diff options
Diffstat (limited to 'source/blender/editors/space_view3d')
36 files changed, 9282 insertions, 21594 deletions
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index e25a9c04f15..44089734e83 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -25,6 +25,7 @@ set(INC ../../blenlib ../../blentranslation ../../bmesh + ../../draw ../../gpu ../../imbuf ../../makesdna @@ -42,24 +43,29 @@ set(INC_SYS ) set(SRC - drawanimviz.c - drawarmature.c - drawmesh.c drawobject.c - drawsimdebug.c - drawvolume.c space_view3d.c view3d_buttons.c view3d_camera_control.c view3d_draw.c + view3d_draw_legacy.c view3d_edit.c view3d_fly.c view3d_walk.c view3d_header.c view3d_iterators.c + view3d_gizmo_armature.c + view3d_gizmo_camera.c + view3d_gizmo_empty.c + view3d_gizmo_forcefield.c + view3d_gizmo_lamp.c + view3d_gizmo_navigate.c + view3d_gizmo_navigate_type.c + view3d_gizmo_ruler.c + view3d_gizmo_preselect.c + view3d_gizmo_preselect_type.c view3d_ops.c view3d_project.c - view3d_ruler.c view3d_select.c view3d_snap.c view3d_toolbar.c @@ -74,13 +80,6 @@ if(WITH_PYTHON) add_definitions(-DWITH_PYTHON) endif() -if(WITH_GAMEENGINE) - list(APPEND INC - ../../../gameengine/BlenderRoutines - ) - add_definitions(-DWITH_GAMEENGINE) -endif() - add_definitions(${GL_DEFINITIONS}) if(WITH_INTERNATIONAL) @@ -95,8 +94,4 @@ if(WITH_MOD_SMOKE) add_definitions(-DWITH_SMOKE) endif() -if(WITH_LEGACY_DEPSGRAPH) - add_definitions(-DWITH_LEGACY_DEPSGRAPH) -endif() - blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c deleted file mode 100644 index e2e71207738..00000000000 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2009 by the Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Joshua Leung - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/drawanimviz.c - * \ingroup spview3d - */ - - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "BLI_sys_types.h" - -#include "DNA_anim_types.h" -#include "DNA_armature_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_view3d_types.h" -#include "DNA_object_types.h" - -#include "BLI_math.h" -#include "BLI_dlrbTree.h" - -#include "BKE_animsys.h" -#include "BKE_action.h" - -#include "BIF_gl.h" - -#include "ED_keyframes_draw.h" - - -#include "UI_resources.h" - -#include "view3d_intern.h" - -/* ************************************ Motion Paths ************************************* */ - -/* TODO: - * - options to draw paths with lines - * - include support for editing the path verts */ - -/* Set up drawing environment for drawing motion paths */ -void draw_motion_paths_init(View3D *v3d, ARegion *ar) -{ - RegionView3D *rv3d = ar->regiondata; - - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); -} - -/* set color - * - more intense for active/selected bones, less intense for unselected bones - * - black for before current frame, green for current frame, blue for after current frame - * - intensity decreases as distance from current frame increases - * - * If the user select custom color, the color is replaced for the color selected in UI panel - * - 75% Darker color is used for previous frames - * - 50% Darker color for current frame - * - User selected color for next frames - */ -static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra, - float prev_color[3], float frame_color[3], float next_color[3]) -{ - int frame = sfra + i; - int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */ - -#define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min) - float intensity; /* how faint */ - - if (frame < CFRA) { - if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { - /* Custom color: previous frames color is darker than current frame */ - glColor3fv(prev_color); - } - else { - /* black - before cfra */ - if (sel) { - /* intensity = 0.5f; */ - intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f); - } - else { - /* intensity = 0.8f; */ - intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f); - } - UI_ThemeColorBlend(TH_WIRE, blend_base, intensity); - } - } - else if (frame > CFRA) { - if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { - /* Custom color: next frames color is equal to user selected color */ - glColor3fv(next_color); - } - else { - /* blue - after cfra */ - if (sel) { - /* intensity = 0.5f; */ - intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f); - } - else { - /* intensity = 0.8f; */ - intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f); - } - UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity); - } - } - else { - if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { - /* Custom color: current frame color is slightly darker than user selected color */ - glColor3fv(frame_color); - } - else { - /* green - on cfra */ - if (sel) { - intensity = 0.5f; - } - else { - intensity = 0.99f; - } - UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10); - } - } -#undef SET_INTENSITY -} - -/* Draw the given motion path for an Object or a Bone - * - assumes that the viewport has already been initialized properly - * i.e. draw_motion_paths_init() has been called - */ -void draw_motion_path_instance(Scene *scene, - Object *ob, bPoseChannel *pchan, bAnimVizSettings *avs, bMotionPath *mpath) -{ - //RegionView3D *rv3d = ar->regiondata; - bMotionPathVert *mpv, *mpv_start; - int i, stepsize = avs->path_step; - int sfra, efra, sind, len; - float prev_color[3]; - float frame_color[3]; - float next_color[3]; - - /* Custom color - Previous frames: color is darker than current frame */ - prev_color[0] = mpath->color[0] * 0.25f; - prev_color[1] = mpath->color[1] * 0.25f; - prev_color[2] = mpath->color[2] * 0.25f; - - /* Custom color - Current frame: color is slightly darker than user selected color */ - frame_color[0] = mpath->color[0] * 0.50f; - frame_color[1] = mpath->color[1] * 0.50f; - frame_color[2] = mpath->color[2] * 0.50f; - - /* Custom color - Next frames: color is equal to user selection */ - next_color[0] = mpath->color[0]; - next_color[1] = mpath->color[1]; - next_color[2] = mpath->color[2]; - - /* Save old line width */ - GLfloat old_width; - glGetFloatv(GL_LINE_WIDTH, &old_width); - - /* get frame ranges */ - if (avs->path_type == MOTIONPATH_TYPE_ACFRA) { - /* With "Around Current", we only choose frames from around - * the current frame to draw. - */ - sfra = CFRA - avs->path_bc; - efra = CFRA + avs->path_ac; - } - else { - /* Use the current display range */ - sfra = avs->path_sf; - efra = avs->path_ef; - } - - /* no matter what, we can only show what is in the cache and no more - * - abort if whole range is past ends of path - * - otherwise clamp endpoints to extents of path - */ - if (sfra < mpath->start_frame) { - /* start clamp */ - sfra = mpath->start_frame; - } - if (efra > mpath->end_frame) { - /* end clamp */ - efra = mpath->end_frame; - } - - if ((sfra > mpath->end_frame) || (efra < mpath->start_frame)) { - /* whole path is out of bounds */ - return; - } - - len = efra - sfra; - - if ((len <= 0) || (mpath->points == NULL)) { - return; - } - - /* get pointers to parts of path */ - sind = sfra - mpath->start_frame; - mpv_start = (mpath->points + sind); - - /* draw curve-line of path */ - /* Draw lines only if line drawing option is enabled */ - if (mpath->flag & MOTIONPATH_FLAG_LINES) { - /* set line thickness */ - glLineWidth(mpath->line_thickness); - - glBegin(GL_LINE_STRIP); - for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { - short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT); - /* Set color */ - set_motion_path_color(scene, mpath, i, sel, sfra, efra, prev_color, frame_color, next_color); - /* draw a vertex with this color */ - glVertex3fv(mpv->co); - } - - glEnd(); - /* back to old line thickness */ - glLineWidth(old_width); - } - - /* Point must be bigger than line thickness */ - glPointSize(mpath->line_thickness + 1.0); - - /* draw little black point at each frame - * NOTE: this is not really visible/noticeable - */ - glBegin(GL_POINTS); - for (i = 0, mpv = mpv_start; i < len; i++, mpv++) - glVertex3fv(mpv->co); - glEnd(); - - /* Draw little white dots at each framestep value or replace with custom color */ - if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { - glColor4fv(mpath->color); - } - else { - UI_ThemeColor(TH_TEXT_HI); - } - glBegin(GL_POINTS); - for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) - glVertex3fv(mpv->co); - glEnd(); - - /* Draw big green dot where the current frame is - * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter - */ - if ((avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) && - (sfra < CFRA) && (CFRA <= efra)) - { - UI_ThemeColor(TH_CFRAME); - - glPointSize(mpath->line_thickness + 5.0); - glBegin(GL_POINTS); - mpv = mpv_start + (CFRA - sfra); - glVertex3fv(mpv->co); - glEnd(); - - UI_ThemeColor(TH_TEXT_HI); - } - - /* XXX, this isn't up to date but probably should be kept so. */ - invert_m4_m4(ob->imat, ob->obmat); - - /* Draw frame numbers at each framestep value */ - if (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) { - unsigned char col[4]; - UI_GetThemeColor3ubv(TH_TEXT_HI, col); - col[3] = 255; - - for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) { - int frame = sfra + i; - char numstr[32]; - size_t numstr_len; - float co[3]; - - /* only draw framenum if several consecutive highlighted points don't occur on same point */ - if (i == 0) { - numstr_len = sprintf(numstr, " %d", frame); - mul_v3_m4v3(co, ob->imat, mpv->co); - view3d_cached_text_draw_add(co, numstr, numstr_len, - 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col); - } - else if ((i >= stepsize) && (i < len - stepsize)) { - bMotionPathVert *mpvP = (mpv - stepsize); - bMotionPathVert *mpvN = (mpv + stepsize); - - if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) { - numstr_len = sprintf(numstr, " %d", frame); - mul_v3_m4v3(co, ob->imat, mpv->co); - view3d_cached_text_draw_add(co, numstr, numstr_len, - 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col); - } - } - } - } - - /* Keyframes - dots and numbers */ - if (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) { - unsigned char col[4]; - - AnimData *adt = BKE_animdata_from_id(&ob->id); - DLRBT_Tree keys; - - /* build list of all keyframes in active action for object or pchan */ - BLI_dlrbTree_init(&keys); - - if (adt) { - /* it is assumed that keyframes for bones are all grouped in a single group - * unless an option is set to always use the whole action - */ - if ((pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) { - bActionGroup *agrp = BKE_action_group_find_name(adt->action, pchan->name); - - if (agrp) { - agroup_to_keylist(adt, agrp, &keys, NULL); - BLI_dlrbTree_linkedlist_sync(&keys); - } - } - else { - action_to_keylist(adt, adt->action, &keys, NULL); - BLI_dlrbTree_linkedlist_sync(&keys); - } - } - - /* Draw slightly-larger yellow dots at each keyframe */ - UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col); - col[3] = 255; - - /* if custom, point must be bigger than line */ - if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { - glPointSize(mpath->line_thickness + 3.0); - } - else { - glPointSize(4.0f); - } - glColor3ubv(col); - - glBegin(GL_POINTS); - for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { - int frame = sfra + i; - float mframe = (float)(frame); - - if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) - glVertex3fv(mpv->co); - } - glEnd(); - - /* Draw frame numbers of keyframes */ - if (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) { - float co[3]; - for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { - float mframe = (float)(sfra + i); - - if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) { - char numstr[32]; - size_t numstr_len; - - numstr_len = sprintf(numstr, " %d", (sfra + i)); - mul_v3_m4v3(co, ob->imat, mpv->co); - view3d_cached_text_draw_add(co, numstr, numstr_len, - 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col); - } - } - } - - BLI_dlrbTree_free(&keys); - } -} - -/* Clean up drawing environment after drawing motion paths */ -void draw_motion_paths_cleanup(View3D *v3d) -{ - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - glPopMatrix(); -} diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c deleted file mode 100644 index 0c3b1a21f71..00000000000 --- a/source/blender/editors/space_view3d/drawarmature.c +++ /dev/null @@ -1,2793 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2005 by the Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/drawarmature.c - * \ingroup spview3d - */ - - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "DNA_anim_types.h" -#include "DNA_armature_types.h" -#include "DNA_constraint_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_view3d_types.h" -#include "DNA_object_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_dlrbTree.h" -#include "BLI_utildefines.h" - -#include "BKE_animsys.h" -#include "BKE_action.h" -#include "BKE_armature.h" -#include "BKE_global.h" -#include "BKE_modifier.h" -#include "BKE_nla.h" -#include "BKE_curve.h" - - -#include "BIF_gl.h" -#include "BIF_glutil.h" - -#include "ED_armature.h" -#include "ED_keyframes_draw.h" - -#include "GPU_basic_shader.h" - -#include "UI_resources.h" - -#include "view3d_intern.h" - -#include "GPU_select.h" - -/* *************** Armature Drawing - Coloring API ***************************** */ - -/* global here is reset before drawing each bone */ -static ThemeWireColor *bcolor = NULL; - -/* values of colCode for set_pchan_glcolor */ -enum { - PCHAN_COLOR_NORMAL = 0, /* normal drawing */ - PCHAN_COLOR_SOLID, /* specific case where "solid" color is needed */ - PCHAN_COLOR_CONSTS, /* "constraint" colors (which may/may-not be suppressed) */ - - PCHAN_COLOR_SPHEREBONE_BASE, /* for the 'stick' of sphere (envelope) bones */ - PCHAN_COLOR_SPHEREBONE_END, /* for the ends of sphere (envelope) bones */ - PCHAN_COLOR_LINEBONE /* for the middle of line-bones */ -}; - -/* This function sets the color-set for coloring a certain bone */ -static void set_pchan_colorset(Object *ob, bPoseChannel *pchan) -{ - bPose *pose = (ob) ? ob->pose : NULL; - bArmature *arm = (ob) ? ob->data : NULL; - bActionGroup *grp = NULL; - short color_index = 0; - - /* sanity check */ - if (ELEM(NULL, ob, arm, pose, pchan)) { - bcolor = NULL; - return; - } - - /* only try to set custom color if enabled for armature */ - if (arm->flag & ARM_COL_CUSTOM) { - /* currently, a bone can only use a custom color set if it's group (if it has one), - * has been set to use one - */ - if (pchan->agrp_index) { - grp = (bActionGroup *)BLI_findlink(&pose->agroups, (pchan->agrp_index - 1)); - if (grp) - color_index = grp->customCol; - } - } - - /* bcolor is a pointer to the color set to use. If NULL, then the default - * color set (based on the theme colors for 3d-view) is used. - */ - if (color_index > 0) { - bTheme *btheme = UI_GetTheme(); - bcolor = &btheme->tarm[(color_index - 1)]; - } - else if (color_index == -1) { - /* use the group's own custom color set (grp is always != NULL here) */ - bcolor = &grp->cs; - } - else { - bcolor = NULL; - } -} - -/* This function is for brightening/darkening a given color (like UI_ThemeColorShade()) */ -static void cp_shade_color3ub(unsigned char cp[3], const int offset) -{ - int r, g, b; - - r = offset + (int) cp[0]; - CLAMP(r, 0, 255); - g = offset + (int) cp[1]; - CLAMP(g, 0, 255); - b = offset + (int) cp[2]; - CLAMP(b, 0, 255); - - cp[0] = r; - cp[1] = g; - cp[2] = b; -} - -/* This function sets the gl-color for coloring a certain bone (based on bcolor) */ -static bool set_pchan_glColor(short colCode, int boneflag, short constflag) -{ - switch (colCode) { - case PCHAN_COLOR_NORMAL: - { - if (bcolor) { - unsigned char cp[3]; - - if (boneflag & BONE_DRAW_ACTIVE) { - copy_v3_v3_char((char *)cp, bcolor->active); - if (!(boneflag & BONE_SELECTED)) { - cp_shade_color3ub(cp, -80); - } - } - else if (boneflag & BONE_SELECTED) { - copy_v3_v3_char((char *)cp, bcolor->select); - } - else { - /* a bit darker than solid */ - copy_v3_v3_char((char *)cp, bcolor->solid); - cp_shade_color3ub(cp, -50); - } - - glColor3ubv(cp); - } - else { - if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) { - UI_ThemeColor(TH_BONE_POSE_ACTIVE); - } - else if (boneflag & BONE_DRAW_ACTIVE) { - UI_ThemeColorBlend(TH_WIRE, TH_BONE_POSE, 0.15f); /* unselected active */ - } - else if (boneflag & BONE_SELECTED) { - UI_ThemeColor(TH_BONE_POSE); - } - else { - UI_ThemeColor(TH_WIRE); - } - } - - return true; - } - case PCHAN_COLOR_SOLID: - { - if (bcolor) { - glColor3ubv((unsigned char *)bcolor->solid); - } - else - UI_ThemeColor(TH_BONE_SOLID); - - return true; - } - case PCHAN_COLOR_CONSTS: - { - if ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS)) { - if (constflag & PCHAN_HAS_TARGET) glColor4ub(255, 150, 0, 80); - else if (constflag & PCHAN_HAS_IK) glColor4ub(255, 255, 0, 80); - else if (constflag & PCHAN_HAS_SPLINEIK) glColor4ub(200, 255, 0, 80); - else if (constflag & PCHAN_HAS_CONST) glColor4ub(0, 255, 120, 80); - - return true; - } - return false; - } - case PCHAN_COLOR_SPHEREBONE_BASE: - { - if (bcolor) { - unsigned char cp[3]; - - if (boneflag & BONE_DRAW_ACTIVE) { - copy_v3_v3_char((char *)cp, bcolor->active); - } - else if (boneflag & BONE_SELECTED) { - copy_v3_v3_char((char *)cp, bcolor->select); - } - else { - copy_v3_v3_char((char *)cp, bcolor->solid); - } - - glColor3ubv(cp); - } - else { - if (boneflag & BONE_DRAW_ACTIVE) UI_ThemeColorShade(TH_BONE_POSE, 40); - else if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_BONE_POSE); - else UI_ThemeColor(TH_BONE_SOLID); - } - - return true; - } - case PCHAN_COLOR_SPHEREBONE_END: - { - if (bcolor) { - unsigned char cp[3]; - - if (boneflag & BONE_DRAW_ACTIVE) { - copy_v3_v3_char((char *)cp, bcolor->active); - cp_shade_color3ub(cp, 10); - } - else if (boneflag & BONE_SELECTED) { - copy_v3_v3_char((char *)cp, bcolor->select); - cp_shade_color3ub(cp, -30); - } - else { - copy_v3_v3_char((char *)cp, bcolor->solid); - cp_shade_color3ub(cp, -30); - } - - glColor3ubv(cp); - } - else { - if (boneflag & BONE_DRAW_ACTIVE) UI_ThemeColorShade(TH_BONE_POSE, 10); - else if (boneflag & BONE_SELECTED) UI_ThemeColorShade(TH_BONE_POSE, -30); - else UI_ThemeColorShade(TH_BONE_SOLID, -30); - } - break; - } - case PCHAN_COLOR_LINEBONE: - { - /* inner part in background color or constraint */ - if ((constflag) && ((bcolor == NULL) || (bcolor->flag & TH_WIRECOLOR_CONSTCOLS))) { - if (constflag & PCHAN_HAS_TARGET) glColor3ub(255, 150, 0); - else if (constflag & PCHAN_HAS_IK) glColor3ub(255, 255, 0); - else if (constflag & PCHAN_HAS_SPLINEIK) glColor3ub(200, 255, 0); - else if (constflag & PCHAN_HAS_CONST) glColor3ub(0, 255, 120); - else if (constflag) UI_ThemeColor(TH_BONE_POSE); /* PCHAN_HAS_ACTION */ - } - else { - if (bcolor) { - const char *cp = bcolor->solid; - glColor4ub(cp[0], cp[1], cp[2], 204); - } - else - UI_ThemeColorShade(TH_BACK, -30); - } - - return true; - } - } - - return false; -} - -static void set_ebone_glColor(const unsigned int boneflag) -{ - if ((boneflag & BONE_DRAW_ACTIVE) && (boneflag & BONE_SELECTED)) { - UI_ThemeColor(TH_EDGE_SELECT); - } - else if (boneflag & BONE_DRAW_ACTIVE) { - UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_SELECT, 0.15f); /* unselected active */ - } - else if (boneflag & BONE_SELECTED) { - UI_ThemeColorShade(TH_EDGE_SELECT, -20); - } - else { - UI_ThemeColor(TH_WIRE_EDIT); - } -} - -/* *************** Armature drawing, helper calls for parts ******************* */ - -/* half the cube, in Y */ -static const float cube[8][3] = { - {-1.0, 0.0, -1.0}, - {-1.0, 0.0, 1.0}, - {-1.0, 1.0, 1.0}, - {-1.0, 1.0, -1.0}, - { 1.0, 0.0, -1.0}, - { 1.0, 0.0, 1.0}, - { 1.0, 1.0, 1.0}, - { 1.0, 1.0, -1.0}, -}; - -static void drawsolidcube_size(float xsize, float ysize, float zsize) -{ - static GLuint displist = 0; - float n[3] = {0.0f}; - - glScalef(xsize, ysize, zsize); - - if (displist == 0) { - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - glBegin(GL_QUADS); - n[0] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); - n[0] = 0; - n[1] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]); - n[1] = 0; - n[0] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]); - n[0] = 0; - n[1] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]); - n[1] = 0; - n[2] = 1.0; - glNormal3fv(n); - glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]); - n[2] = -1.0; - glNormal3fv(n); - glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]); - glEnd(); - - glEndList(); - } - - glCallList(displist); -} - -static void drawcube_size(float xsize, float ysize, float zsize) -{ - static GLuint displist = 0; - - if (displist == 0) { - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - glBegin(GL_LINE_STRIP); - glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); - glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); - glVertex3fv(cube[7]); glVertex3fv(cube[4]); - glEnd(); - - glBegin(GL_LINES); - glVertex3fv(cube[1]); glVertex3fv(cube[5]); - glVertex3fv(cube[2]); glVertex3fv(cube[6]); - glVertex3fv(cube[3]); glVertex3fv(cube[7]); - glEnd(); - - glEndList(); - } - - glScalef(xsize, ysize, zsize); - glCallList(displist); - -} - - -static void draw_bonevert(void) -{ - static GLuint displist = 0; - - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - glPushMatrix(); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0.0, 0.05, 16, 1); - - glRotatef(90, 0, 1, 0); - gluDisk(qobj, 0.0, 0.05, 16, 1); - - glRotatef(90, 1, 0, 0); - gluDisk(qobj, 0.0, 0.05, 16, 1); - - gluDeleteQuadric(qobj); - - glPopMatrix(); - glEndList(); - } - - glCallList(displist); -} - -static void draw_bonevert_solid(void) -{ - static GLuint displist = 0; - - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); - /* Draw tips of a bone */ - gluSphere(qobj, 0.05, 8, 5); - gluDeleteQuadric(qobj); - - glEndList(); - } - - glCallList(displist); -} - -static const float bone_octahedral_verts[6][3] = { - { 0.0f, 0.0f, 0.0f}, - { 0.1f, 0.1f, 0.1f}, - { 0.1f, 0.1f, -0.1f}, - {-0.1f, 0.1f, -0.1f}, - {-0.1f, 0.1f, 0.1f}, - { 0.0f, 1.0f, 0.0f} -}; - -static const unsigned int bone_octahedral_wire_sides[8] = {0, 1, 5, 3, 0, 4, 5, 2}; -static const unsigned int bone_octahedral_wire_square[8] = {1, 2, 3, 4, 1}; - -static const unsigned int bone_octahedral_solid_tris[8][3] = { - {2, 1, 0}, /* bottom */ - {3, 2, 0}, - {4, 3, 0}, - {1, 4, 0}, - - {5, 1, 2}, /* top */ - {5, 2, 3}, - {5, 3, 4}, - {5, 4, 1} -}; - -/* aligned with bone_octahedral_solid_tris */ -static const float bone_octahedral_solid_normals[8][3] = { - { M_SQRT1_2, -M_SQRT1_2, 0.00000000f}, - {-0.00000000f, -M_SQRT1_2, -M_SQRT1_2}, - {-M_SQRT1_2, -M_SQRT1_2, 0.00000000f}, - { 0.00000000f, -M_SQRT1_2, M_SQRT1_2}, - { 0.99388373f, 0.11043154f, -0.00000000f}, - { 0.00000000f, 0.11043154f, -0.99388373f}, - {-0.99388373f, 0.11043154f, 0.00000000f}, - { 0.00000000f, 0.11043154f, 0.99388373f} -}; - -static void draw_bone_octahedral(void) -{ - static GLuint displist = 0; - - if (displist == 0) { - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - /* Section 1, sides */ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, bone_octahedral_verts); - glDrawElements(GL_LINE_LOOP, - sizeof(bone_octahedral_wire_sides) / sizeof(*bone_octahedral_wire_sides), - GL_UNSIGNED_INT, - bone_octahedral_wire_sides); - - /* Section 1, square */ - glDrawElements(GL_LINE_LOOP, - sizeof(bone_octahedral_wire_square) / sizeof(*bone_octahedral_wire_square), - GL_UNSIGNED_INT, - bone_octahedral_wire_square); - glDisableClientState(GL_VERTEX_ARRAY); - - glEndList(); - } - - glCallList(displist); -} - -static void draw_bone_solid_octahedral(void) -{ - static GLuint displist = 0; - - if (displist == 0) { - int i; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - -#if 1 - glBegin(GL_TRIANGLES); - for (i = 0; i < 8; i++) { - glNormal3fv(bone_octahedral_solid_normals[i]); - glVertex3fv(bone_octahedral_verts[bone_octahedral_solid_tris[i][0]]); - glVertex3fv(bone_octahedral_verts[bone_octahedral_solid_tris[i][1]]); - glVertex3fv(bone_octahedral_verts[bone_octahedral_solid_tris[i][2]]); - } - - glEnd(); - -#else /* not working because each vert needs a different normal */ - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glNormalPointer(GL_FLOAT, 0, bone_octahedral_solid_normals); - glVertexPointer(3, GL_FLOAT, 0, bone_octahedral_verts); - glDrawElements(GL_TRIANGLES, sizeof(bone_octahedral_solid_tris) / sizeof(unsigned int), - GL_UNSIGNED_INT, bone_octahedral_solid_tris); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); -#endif - - glEndList(); - } - - glCallList(displist); -} - -/* *************** Armature drawing, bones ******************* */ - - -static void draw_bone_points(const short dt, int armflag, unsigned int boneflag, int id) -{ - /* Draw root point if we are not connected */ - if ((boneflag & BONE_CONNECTED) == 0) { - if (id != -1) - GPU_select_load_id(id | BONESEL_ROOT); - - if (dt <= OB_WIRE) { - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); - } - } - else { - if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, 0); - else - UI_ThemeColor(TH_BONE_SOLID); - } - - if (dt > OB_WIRE) - draw_bonevert_solid(); - else - draw_bonevert(); - } - - /* Draw tip point */ - if (id != -1) - GPU_select_load_id(id | BONESEL_TIP); - - if (dt <= OB_WIRE) { - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); - } - } - else { - if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, 0); - else - UI_ThemeColor(TH_BONE_SOLID); - } - - glTranslatef(0.0f, 1.0f, 0.0f); - if (dt > OB_WIRE) - draw_bonevert_solid(); - else - draw_bonevert(); - glTranslatef(0.0f, -1.0f, 0.0f); - -} - -/* 16 values of sin function (still same result!) */ -static const float si[16] = { - 0.00000000f, - 0.20129852f, 0.39435585f, - 0.57126821f, 0.72479278f, - 0.84864425f, 0.93775213f, - 0.98846832f, 0.99871650f, - 0.96807711f, 0.89780453f, - 0.79077573f, 0.65137248f, - 0.48530196f, 0.29936312f, - 0.10116832f -}; -/* 16 values of cos function (still same result!) */ -static const float co[16] = { - 1.00000000f, - 0.97952994f, 0.91895781f, - 0.82076344f, 0.68896691f, - 0.52896401f, 0.34730525f, - 0.15142777f, -0.05064916f, - -0.25065253f, -0.44039415f, - -0.61210598f, -0.75875812f, - -0.87434661f, -0.95413925f, - -0.99486932f -}; - - - -/* smat, imat = mat & imat to draw screenaligned */ -static void draw_sphere_bone_dist(float smat[4][4], float imat[4][4], bPoseChannel *pchan, EditBone *ebone) -{ - float head, tail, dist /*, length*/; - float *headvec, *tailvec, dirvec[3]; - - /* figure out the sizes of spheres */ - if (ebone) { - /* this routine doesn't call get_matrix_editbone() that calculates it */ - ebone->length = len_v3v3(ebone->head, ebone->tail); - - /*length = ebone->length;*/ /*UNUSED*/ - tail = ebone->rad_tail; - dist = ebone->dist; - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) - head = ebone->parent->rad_tail; - else - head = ebone->rad_head; - headvec = ebone->head; - tailvec = ebone->tail; - } - else { - /*length = pchan->bone->length;*/ /*UNUSED*/ - tail = pchan->bone->rad_tail; - dist = pchan->bone->dist; - if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) - head = pchan->parent->bone->rad_tail; - else - head = pchan->bone->rad_head; - headvec = pchan->pose_head; - tailvec = pchan->pose_tail; - } - - /* ***** draw it ***** */ - - /* move vector to viewspace */ - sub_v3_v3v3(dirvec, tailvec, headvec); - mul_mat3_m4_v3(smat, dirvec); - /* clear zcomp */ - dirvec[2] = 0.0f; - - if (head != tail) { - /* correction when viewing along the bones axis - * it pops in and out but better then artifacts, [#23841] */ - float view_dist = len_v2(dirvec); - - if (head - view_dist > tail) { - tailvec = headvec; - tail = head; - zero_v3(dirvec); - dirvec[0] = 0.00001; /* XXX. weak but ok */ - } - else if (tail - view_dist > head) { - headvec = tailvec; - head = tail; - zero_v3(dirvec); - dirvec[0] = 0.00001; /* XXX. weak but ok */ - } - } - - /* move vector back */ - mul_mat3_m4_v3(imat, dirvec); - - if (0.0f != normalize_v3(dirvec)) { - float norvec[3], vec1[3], vec2[3], vec[3]; - int a; - - //mul_v3_fl(dirvec, head); - cross_v3_v3v3(norvec, dirvec, imat[2]); - - glBegin(GL_QUAD_STRIP); - - for (a = 0; a < 16; a++) { - vec[0] = -si[a] * dirvec[0] + co[a] * norvec[0]; - vec[1] = -si[a] * dirvec[1] + co[a] * norvec[1]; - vec[2] = -si[a] * dirvec[2] + co[a] * norvec[2]; - - madd_v3_v3v3fl(vec1, headvec, vec, head); - madd_v3_v3v3fl(vec2, headvec, vec, head + dist); - - glColor4ub(255, 255, 255, 50); - glVertex3fv(vec1); - //glColor4ub(255, 255, 255, 0); - glVertex3fv(vec2); - } - - for (a = 15; a >= 0; a--) { - vec[0] = si[a] * dirvec[0] + co[a] * norvec[0]; - vec[1] = si[a] * dirvec[1] + co[a] * norvec[1]; - vec[2] = si[a] * dirvec[2] + co[a] * norvec[2]; - - madd_v3_v3v3fl(vec1, tailvec, vec, tail); - madd_v3_v3v3fl(vec2, tailvec, vec, tail + dist); - - //glColor4ub(255, 255, 255, 50); - glVertex3fv(vec1); - //glColor4ub(255, 255, 255, 0); - glVertex3fv(vec2); - } - /* make it cyclic... */ - - vec[0] = -si[0] * dirvec[0] + co[0] * norvec[0]; - vec[1] = -si[0] * dirvec[1] + co[0] * norvec[1]; - vec[2] = -si[0] * dirvec[2] + co[0] * norvec[2]; - - madd_v3_v3v3fl(vec1, headvec, vec, head); - madd_v3_v3v3fl(vec2, headvec, vec, head + dist); - - //glColor4ub(255, 255, 255, 50); - glVertex3fv(vec1); - //glColor4ub(255, 255, 255, 0); - glVertex3fv(vec2); - - glEnd(); - } -} - - -/* smat, imat = mat & imat to draw screenaligned */ -static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4], - int armflag, int boneflag, short constflag, unsigned int id, - bPoseChannel *pchan, EditBone *ebone) -{ - float head, tail /*, length*/; - float *headvec, *tailvec, dirvec[3]; - - /* figure out the sizes of spheres */ - if (ebone) { - /* this routine doesn't call get_matrix_editbone() that calculates it */ - ebone->length = len_v3v3(ebone->head, ebone->tail); - - /*length = ebone->length;*/ /*UNUSED*/ - tail = ebone->rad_tail; - if (ebone->parent && (boneflag & BONE_CONNECTED)) - head = ebone->parent->rad_tail; - else - head = ebone->rad_head; - headvec = ebone->head; - tailvec = ebone->tail; - } - else { - /*length = pchan->bone->length;*/ /*UNUSED*/ - tail = pchan->bone->rad_tail; - if ((pchan->parent) && (boneflag & BONE_CONNECTED)) - head = pchan->parent->bone->rad_tail; - else - head = pchan->bone->rad_head; - headvec = pchan->pose_head; - tailvec = pchan->pose_tail; - } - - /* sphere root color */ - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); - } - else if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); - - /* Draw root point if we are not connected */ - if ((boneflag & BONE_CONNECTED) == 0) { - if (id != -1) - GPU_select_load_id(id | BONESEL_ROOT); - - drawcircball(GL_LINE_LOOP, headvec, head, imat); - } - - /* Draw tip point */ - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); - } - - if (id != -1) - GPU_select_load_id(id | BONESEL_TIP); - - drawcircball(GL_LINE_LOOP, tailvec, tail, imat); - - /* base */ - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_SELECT); - else UI_ThemeColor(TH_WIRE_EDIT); - } - - sub_v3_v3v3(dirvec, tailvec, headvec); - - /* move vector to viewspace */ - mul_mat3_m4_v3(smat, dirvec); - /* clear zcomp */ - dirvec[2] = 0.0f; - /* move vector back */ - mul_mat3_m4_v3(imat, dirvec); - - if (0.0f != normalize_v3(dirvec)) { - float norvech[3], norvect[3], vec[3]; - - copy_v3_v3(vec, dirvec); - - mul_v3_fl(dirvec, head); - cross_v3_v3v3(norvech, dirvec, imat[2]); - - mul_v3_fl(vec, tail); - cross_v3_v3v3(norvect, vec, imat[2]); - - if (id != -1) - GPU_select_load_id(id | BONESEL_BONE); - - glBegin(GL_LINES); - - add_v3_v3v3(vec, headvec, norvech); - glVertex3fv(vec); - - add_v3_v3v3(vec, tailvec, norvect); - glVertex3fv(vec); - - sub_v3_v3v3(vec, headvec, norvech); - glVertex3fv(vec); - - sub_v3_v3v3(vec, tailvec, norvect); - glVertex3fv(vec); - - glEnd(); - } -} - -/* does wire only for outline selecting */ -static void draw_sphere_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, - bPoseChannel *pchan, EditBone *ebone) -{ - GLUquadricObj *qobj; - float head, tail, length; - float fac1, fac2; - - glPushMatrix(); - qobj = gluNewQuadric(); - - /* figure out the sizes of spheres */ - if (ebone) { - length = ebone->length; - tail = ebone->rad_tail; - if (ebone->parent && (boneflag & BONE_CONNECTED)) - head = ebone->parent->rad_tail; - else - head = ebone->rad_head; - } - else { - length = pchan->bone->length; - tail = pchan->bone->rad_tail; - if (pchan->parent && (boneflag & BONE_CONNECTED)) - head = pchan->parent->bone->rad_tail; - else - head = pchan->bone->rad_head; - } - - /* move to z-axis space */ - glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); - - if (dt == OB_SOLID) { - /* set up solid drawing */ - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - - gluQuadricDrawStyle(qobj, GLU_FILL); - } - else { - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - } - - /* sphere root color */ - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColorShade(TH_BONE_SOLID, -30); - } - else if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SPHEREBONE_END, boneflag, constflag); - else if (dt == OB_SOLID) - UI_ThemeColorShade(TH_BONE_SOLID, -30); - - /* Draw root point if we are not connected */ - if ((boneflag & BONE_CONNECTED) == 0) { - if (id != -1) - GPU_select_load_id(id | BONESEL_ROOT); - gluSphere(qobj, head, 16, 10); - } - - /* Draw tip point */ - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColorShade(TH_BONE_SOLID, -30); - } - - if (id != -1) - GPU_select_load_id(id | BONESEL_TIP); - - glTranslatef(0.0f, 0.0f, length); - gluSphere(qobj, tail, 16, 10); - glTranslatef(0.0f, 0.0f, -length); - - /* base */ - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_SELECT); - else UI_ThemeColor(TH_BONE_SOLID); - } - else if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SPHEREBONE_BASE, boneflag, constflag); - else if (dt == OB_SOLID) - UI_ThemeColor(TH_BONE_SOLID); - - fac1 = (length - head) / length; - fac2 = (length - tail) / length; - - if (length > (head + tail)) { - if (id != -1) - GPU_select_load_id(id | BONESEL_BONE); - - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); - - glTranslatef(0.0f, 0.0f, head); - gluCylinder(qobj, fac1 * head + (1.0f - fac1) * tail, fac2 * tail + (1.0f - fac2) * head, length - head - tail, 16, 1); - glTranslatef(0.0f, 0.0f, -head); - - glDisable(GL_POLYGON_OFFSET_FILL); - - /* draw sphere on extrema */ - glTranslatef(0.0f, 0.0f, length - tail); - gluSphere(qobj, fac2 * tail + (1.0f - fac2) * head, 16, 10); - glTranslatef(0.0f, 0.0f, -length + tail); - - glTranslatef(0.0f, 0.0f, head); - gluSphere(qobj, fac1 * head + (1.0f - fac1) * tail, 16, 10); - } - else { - /* 1 sphere in center */ - glTranslatef(0.0f, 0.0f, (head + length - tail) / 2.0f); - gluSphere(qobj, fac1 * head + (1.0f - fac1) * tail, 16, 10); - } - - /* restore */ - if (dt == OB_SOLID) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - - glPopMatrix(); - gluDeleteQuadric(qobj); -} - -static GLubyte bm_dot6[] = {0x0, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x0}; -static GLubyte bm_dot8[] = {0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C}; - -static GLubyte bm_dot5[] = {0x0, 0x0, 0x10, 0x38, 0x7c, 0x38, 0x10, 0x0}; -static GLubyte bm_dot7[] = {0x0, 0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38}; - - -static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned int id, - bPoseChannel *pchan, EditBone *ebone) -{ - /* call this once, avoid constant changing */ - BLI_assert(glaGetOneInt(GL_UNPACK_ALIGNMENT) == 1); - - float length; - - if (pchan) - length = pchan->bone->length; - else - length = ebone->length; - - glPushMatrix(); - glScalef(length, length, length); - - /* this chunk not in object mode */ - if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) { - glLineWidth(4.0f); - if (G.f & G_PICKSEL) { - /* no bitmap in selection mode, crashes 3d cards... - * instead draw a solid point the same size */ - glPointSize(8.0f); - } - - if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); - else if (armflag & ARM_EDITMODE) { - UI_ThemeColor(TH_WIRE_EDIT); - } - - /* Draw root point if we are not connected */ - if ((boneflag & BONE_CONNECTED) == 0) { - if (G.f & G_PICKSEL) { - GPU_select_load_id(id | BONESEL_ROOT); - glBegin(GL_POINTS); - glVertex3f(0.0f, 0.0f, 0.0f); - glEnd(); - } - else { - glRasterPos3f(0.0f, 0.0f, 0.0f); - glBitmap(8, 8, 4, 4, 0, 0, bm_dot8); - } - } - - if (id != -1) - GPU_select_load_id((GLuint) id | BONESEL_BONE); - - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); - - /* tip */ - if (G.f & G_PICKSEL) { - /* no bitmap in selection mode, crashes 3d cards... */ - GPU_select_load_id(id | BONESEL_TIP); - glBegin(GL_POINTS); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); - } - else { - glRasterPos3f(0.0f, 1.0f, 0.0f); - glBitmap(8, 8, 4, 4, 0, 0, bm_dot7); - } - - /* further we send no names */ - if (id != -1) - GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */ - - if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_LINEBONE, boneflag, constflag); - } - - glLineWidth(2.0); - - /*Draw root point if we are not connected */ - if ((boneflag & BONE_CONNECTED) == 0) { - if ((G.f & G_PICKSEL) == 0) { - /* no bitmap in selection mode, crashes 3d cards... */ - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_ROOTSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); - } - glRasterPos3f(0.0f, 0.0f, 0.0f); - glBitmap(8, 8, 4, 4, 0, 0, bm_dot6); - } - } - - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_SELECTED) UI_ThemeColor(TH_EDGE_SELECT); - else UI_ThemeColorShade(TH_BACK, -30); - } - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(0.0f, 1.0f, 0.0f); - glEnd(); - - /* tip */ - if ((G.f & G_PICKSEL) == 0) { - /* no bitmap in selection mode, crashes 3d cards... */ - if (armflag & ARM_EDITMODE) { - if (boneflag & BONE_TIPSEL) UI_ThemeColor(TH_VERTEX_SELECT); - else UI_ThemeColor(TH_VERTEX); - } - glRasterPos3f(0.0f, 1.0f, 0.0f); - glBitmap(8, 8, 4, 4, 0, 0, bm_dot5); - } - - glPopMatrix(); -} - -/* A partial copy of BKE_pchan_bbone_spline_setup(), with just the parts for previewing editmode curve settings - * - * This assumes that prev/next bones don't have any impact (since they should all still be in the "straight" - * position here anyway), and that we can simply apply the bbone settings to get the desired effect... - */ -static void ebone_spline_preview(EditBone *ebone, Mat4 result_array[MAX_BBONE_SUBDIV]) -{ - float h1[3], h2[3], length, hlength1, hlength2, roll1 = 0.0f, roll2 = 0.0f; - float mat3[3][3]; - float data[MAX_BBONE_SUBDIV + 1][4], *fp; - int a; - - length = ebone->length; - - hlength1 = ebone->ease1 * length * 0.390464f; /* 0.5f * sqrt(2) * kappa, the handle length for near-perfect circles */ - hlength2 = ebone->ease2 * length * 0.390464f; - - /* find the handle points, since this is inside bone space, the - * first point = (0, 0, 0) - * last point = (0, length, 0) - * - * we also just apply all the "extra effects", since they're the whole reason we're doing this... - */ - h1[0] = ebone->curveInX; - h1[1] = hlength1; - h1[2] = ebone->curveInY; - roll1 = ebone->roll1; - - h2[0] = ebone->curveOutX; - h2[1] = -hlength2; - h2[2] = ebone->curveOutY; - roll2 = ebone->roll2; - - /* make curve */ - if (ebone->segments > MAX_BBONE_SUBDIV) - ebone->segments = MAX_BBONE_SUBDIV; - - BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float)); - BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float)); - BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float)); - BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float)); - - equalize_bbone_bezier(data[0], ebone->segments); /* note: does stride 4! */ - - /* make transformation matrices for the segments for drawing */ - for (a = 0, fp = data[0]; a < ebone->segments; a++, fp += 4) { - sub_v3_v3v3(h1, fp + 4, fp); - vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */ - - copy_m4_m3(result_array[a].mat, mat3); - copy_v3_v3(result_array[a].mat[3], fp); - - /* "extra" scale facs... */ - { - const int num_segments = ebone->segments; - - const float scaleFactorIn = 1.0f + (ebone->scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments); - const float scaleFactorOut = 1.0f + (ebone->scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments); - - const float scalefac = scaleFactorIn * scaleFactorOut; - float bscalemat[4][4], bscale[3]; - - bscale[0] = scalefac; - bscale[1] = 1.0f; - bscale[2] = scalefac; - - size_to_mat4(bscalemat, bscale); - - /* Note: don't multiply by inverse scale mat here, as it causes problems with scaling shearing and breaking segment chains */ - mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat); - } - } -} - -static void draw_b_bone_boxes(const short dt, bPoseChannel *pchan, EditBone *ebone, float xwidth, float length, float zwidth) -{ - int segments = 0; - - if (pchan) - segments = pchan->bone->segments; - else if (ebone) - segments = ebone->segments; - - if (segments > 1) { - float dlen = length / (float)segments; - Mat4 bbone[MAX_BBONE_SUBDIV]; - int a; - - if (pchan) { - BKE_pchan_bbone_spline_setup(pchan, 0, bbone); - } - else if (ebone) { - ebone_spline_preview(ebone, bbone); - } - - for (a = 0; a < segments; a++) { - glPushMatrix(); - glMultMatrixf(bbone[a].mat); - if (dt == OB_SOLID) drawsolidcube_size(xwidth, dlen, zwidth); - else drawcube_size(xwidth, dlen, zwidth); - glPopMatrix(); - } - } - else { - glPushMatrix(); - if (dt == OB_SOLID) drawsolidcube_size(xwidth, length, zwidth); - else drawcube_size(xwidth, length, zwidth); - glPopMatrix(); - } -} - -static void draw_b_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, - bPoseChannel *pchan, EditBone *ebone) -{ - float xwidth, length, zwidth; - - if (pchan) { - xwidth = pchan->bone->xwidth; - length = pchan->bone->length; - zwidth = pchan->bone->zwidth; - } - else { - xwidth = ebone->xwidth; - length = ebone->length; - zwidth = ebone->zwidth; - } - - /* draw points only if... */ - if (armflag & ARM_EDITMODE) { - /* move to unitspace */ - glPushMatrix(); - glScalef(length, length, length); - draw_bone_points(dt, armflag, boneflag, id); - glPopMatrix(); - length *= 0.95f; /* make vertices visible */ - } - - /* colors for modes */ - if (armflag & ARM_POSEMODE) { - if (dt <= OB_WIRE) - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); - else - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag); - } - else if (armflag & ARM_EDITMODE) { - if (dt == OB_WIRE) { - set_ebone_glColor(boneflag); - } - else - UI_ThemeColor(TH_BONE_SOLID); - } - - if (id != -1) { - GPU_select_load_id((GLuint) id | BONESEL_BONE); - } - - /* set up solid drawing */ - if (dt > OB_WIRE) { - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - - if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag); - else - UI_ThemeColor(TH_BONE_SOLID); - - draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth); - - /* disable solid drawing */ - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - else { - /* wire */ - if (armflag & ARM_POSEMODE) { - if (constflag && ((G.f & G_PICKSEL) == 0)) { - /* set constraint colors */ - if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) { - glEnable(GL_BLEND); - - draw_b_bone_boxes(OB_SOLID, pchan, ebone, xwidth, length, zwidth); - - glDisable(GL_BLEND); - } - - /* restore colors */ - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); - } - } - - draw_b_bone_boxes(OB_WIRE, pchan, ebone, xwidth, length, zwidth); - } -} - -static void draw_wire_bone_segments(bPoseChannel *pchan, Mat4 *bbones, float length, int segments) -{ - if ((segments > 1) && (pchan)) { - float dlen = length / (float)segments; - Mat4 *bbone = bbones; - int a; - - for (a = 0; a < segments; a++, bbone++) { - glPushMatrix(); - glMultMatrixf(bbone->mat); - - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(0.0f, dlen, 0.0f); - glEnd(); /* GL_LINES */ - - glPopMatrix(); - } - } - else { - glPushMatrix(); - - glBegin(GL_LINES); - glVertex3f(0.0f, 0.0f, 0.0f); - glVertex3f(0.0f, length, 0.0f); - glEnd(); - - glPopMatrix(); - } -} - -static void draw_wire_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, - bPoseChannel *pchan, EditBone *ebone) -{ - Mat4 bbones_array[MAX_BBONE_SUBDIV]; - Mat4 *bbones = NULL; - int segments = 0; - float length; - - if (pchan) { - segments = pchan->bone->segments; - length = pchan->bone->length; - - if (segments > 1) { - BKE_pchan_bbone_spline_setup(pchan, 0, bbones_array); - bbones = bbones_array; - } - } - else - length = ebone->length; - - /* draw points only if... */ - if (armflag & ARM_EDITMODE) { - /* move to unitspace */ - glPushMatrix(); - glScalef(length, length, length); - draw_bone_points(dt, armflag, boneflag, id); - glPopMatrix(); - length *= 0.95f; /* make vertices visible */ - } - - /* this chunk not in object mode */ - if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) { - if (id != -1) - GPU_select_load_id((GLuint) id | BONESEL_BONE); - - draw_wire_bone_segments(pchan, bbones, length, segments); - - /* further we send no names */ - if (id != -1) - GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */ - } - - /* colors for modes */ - if (armflag & ARM_POSEMODE) { - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); - } - else if (armflag & ARM_EDITMODE) { - set_ebone_glColor(boneflag); - } - - /* draw normal */ - draw_wire_bone_segments(pchan, bbones, length, segments); -} - -static void draw_bone(const short dt, int armflag, int boneflag, short constflag, unsigned int id, float length) -{ - - /* Draw a 3d octahedral bone, we use normalized space based on length, - * for display-lists */ - - glScalef(length, length, length); - - /* set up solid drawing */ - if (dt > OB_WIRE) { - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - UI_ThemeColor(TH_BONE_SOLID); - } - - /* colors for posemode */ - if (armflag & ARM_POSEMODE) { - if (dt <= OB_WIRE) - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); - else - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag); - } - - - draw_bone_points(dt, armflag, boneflag, id); - - /* now draw the bone itself */ - if (id != -1) { - GPU_select_load_id((GLuint) id | BONESEL_BONE); - } - - /* wire? */ - if (dt <= OB_WIRE) { - /* colors */ - if (armflag & ARM_EDITMODE) { - set_ebone_glColor(boneflag); - } - else if (armflag & ARM_POSEMODE) { - if (constflag && ((G.f & G_PICKSEL) == 0)) { - /* draw constraint colors */ - if (set_pchan_glColor(PCHAN_COLOR_CONSTS, boneflag, constflag)) { - glEnable(GL_BLEND); - - draw_bone_solid_octahedral(); - - glDisable(GL_BLEND); - } - - /* restore colors */ - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, constflag); - } - } - draw_bone_octahedral(); - } - else { - /* solid */ - if (armflag & ARM_POSEMODE) - set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag); - else - UI_ThemeColor(TH_BONE_SOLID); - draw_bone_solid_octahedral(); - } - - /* disable solid drawing */ - if (dt > OB_WIRE) { - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } -} - -static void draw_custom_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, - const short dt, int armflag, int boneflag, unsigned int id, float length) -{ - if (ob == NULL) return; - - glScalef(length, length, length); - - /* colors for posemode */ - if (armflag & ARM_POSEMODE) { - set_pchan_glColor(PCHAN_COLOR_NORMAL, boneflag, 0); - } - - if (id != -1) { - GPU_select_load_id((GLuint) id | BONESEL_BONE); - } - - draw_object_instance(scene, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE); -} - - -static void pchan_draw_IK_root_lines(bPoseChannel *pchan, short only_temp) -{ - bConstraint *con; - bPoseChannel *parchan; - - for (con = pchan->constraints.first; con; con = con->next) { - if (con->enforce == 0.0f) - continue; - - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - { - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - int segcount = 0; - - /* if only_temp, only draw if it is a temporary ik-chain */ - if ((only_temp) && !(data->flag & CONSTRAINT_IK_TEMP)) - continue; - - setlinestyle(3); - glBegin(GL_LINES); - - /* exclude tip from chain? */ - if ((data->flag & CONSTRAINT_IK_TIP) == 0) - parchan = pchan->parent; - else - parchan = pchan; - - glVertex3fv(parchan->pose_tail); - - /* Find the chain's root */ - while (parchan->parent) { - segcount++; - if (segcount == data->rootbone || segcount > 255) { - break; /* 255 is weak */ - } - parchan = parchan->parent; - } - if (parchan) - glVertex3fv(parchan->pose_head); - - glEnd(); - setlinestyle(0); - break; - } - case CONSTRAINT_TYPE_SPLINEIK: - { - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - int segcount = 0; - - setlinestyle(3); - glBegin(GL_LINES); - - parchan = pchan; - glVertex3fv(parchan->pose_tail); - - /* Find the chain's root */ - while (parchan->parent) { - segcount++; - /* FIXME: revise the breaking conditions */ - if (segcount == data->chainlen || segcount > 255) break; /* 255 is weak */ - parchan = parchan->parent; - } - /* Only draw line in case our chain is more than one bone long! */ - if (parchan != pchan) /* XXX revise the breaking conditions to only stop at the tail? */ - glVertex3fv(parchan->pose_head); - - glEnd(); - setlinestyle(0); - break; - } - } - } -} - -static void bgl_sphere_project(float ax, float az) -{ - float dir[3], sine, q3; - - sine = 1.0f - ax * ax - az * az; - q3 = (sine < 0.0f) ? 0.0f : (2.0f * sqrtf(sine)); - - dir[0] = -az * q3; - dir[1] = 1.0f - 2.0f * sine; - dir[2] = ax * q3; - - glVertex3fv(dir); -} - -static void draw_dof_ellipse(float ax, float az) -{ - const float staticSine[16] = { - 0.0f, 0.104528463268f, 0.207911690818f, 0.309016994375f, - 0.406736643076f, 0.5f, 0.587785252292f, 0.669130606359f, - 0.743144825477f, 0.809016994375f, 0.866025403784f, - 0.913545457643f, 0.951056516295f, 0.978147600734f, - 0.994521895368f, 1.0f - }; - - int i, j, n = 16; - float x, z, px, pz; - - glEnable(GL_BLEND); - glDepthMask(0); - - glColor4ub(70, 70, 70, 50); - - glBegin(GL_QUADS); - pz = 0.0f; - for (i = 1; i < n; i++) { - z = staticSine[i]; - - px = 0.0f; - for (j = 1; j <= (n - i); j++) { - x = staticSine[j]; - - if (j == n - i) { - glEnd(); - glBegin(GL_TRIANGLES); - bgl_sphere_project(ax * px, az * z); - bgl_sphere_project(ax * px, az * pz); - bgl_sphere_project(ax * x, az * pz); - glEnd(); - glBegin(GL_QUADS); - } - else { - bgl_sphere_project(ax * x, az * z); - bgl_sphere_project(ax * x, az * pz); - bgl_sphere_project(ax * px, az * pz); - bgl_sphere_project(ax * px, az * z); - } - - px = x; - } - pz = z; - } - glEnd(); - - glDisable(GL_BLEND); - glDepthMask(1); - - glColor3ub(0, 0, 0); - - glBegin(GL_LINE_STRIP); - for (i = 0; i < n; i++) - bgl_sphere_project(staticSine[n - i - 1] * ax, staticSine[i] * az); - glEnd(); -} - -static void draw_pose_dofs(Object *ob) -{ - bArmature *arm = ob->data; - bPoseChannel *pchan; - Bone *bone; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - bone = pchan->bone; - - if ((bone != NULL) && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { - if (bone->flag & BONE_SELECTED) { - if (bone->layer & arm->layer) { - if (pchan->ikflag & (BONE_IK_XLIMIT | BONE_IK_ZLIMIT)) { - if (BKE_pose_channel_in_IK_chain(ob, pchan)) { - float corner[4][3], posetrans[3], mat[4][4]; - float phi = 0.0f, theta = 0.0f, scale; - int a, i; - - /* in parent-bone pose, but own restspace */ - glPushMatrix(); - - copy_v3_v3(posetrans, pchan->pose_mat[3]); - glTranslate3fv(posetrans); - - if (pchan->parent) { - copy_m4_m4(mat, pchan->parent->pose_mat); - mat[3][0] = mat[3][1] = mat[3][2] = 0.0f; - glMultMatrixf(mat); - } - - copy_m4_m3(mat, pchan->bone->bone_mat); - glMultMatrixf(mat); - - scale = bone->length * pchan->size[1]; - glScalef(scale, scale, scale); - - if (pchan->ikflag & BONE_IK_XLIMIT) { - if (pchan->ikflag & BONE_IK_ZLIMIT) { - float amin[3], amax[3]; - - for (i = 0; i < 3; i++) { - /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */ - amin[i] = sinf(pchan->limitmin[i] * 0.5f); - amax[i] = sinf(pchan->limitmax[i] * 0.5f); - } - - glScalef(1.0f, -1.0f, 1.0f); - if ((amin[0] != 0.0f) && (amin[2] != 0.0f)) - draw_dof_ellipse(amin[0], amin[2]); - if ((amin[0] != 0.0f) && (amax[2] != 0.0f)) - draw_dof_ellipse(amin[0], amax[2]); - if ((amax[0] != 0.0f) && (amin[2] != 0.0f)) - draw_dof_ellipse(amax[0], amin[2]); - if ((amax[0] != 0.0f) && (amax[2] != 0.0f)) - draw_dof_ellipse(amax[0], amax[2]); - glScalef(1.0f, -1.0f, 1.0f); - } - } - - /* arcs */ - if (pchan->ikflag & BONE_IK_ZLIMIT) { - /* OpenGL requires rotations in degrees; so we're taking the average angle here */ - theta = RAD2DEGF(0.5f * (pchan->limitmin[2] + pchan->limitmax[2])); - glRotatef(theta, 0.0f, 0.0f, 1.0f); - - glColor3ub(50, 50, 255); /* blue, Z axis limit */ - glBegin(GL_LINE_STRIP); - for (a = -16; a <= 16; a++) { - /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */ - float fac = ((float)a) / 16.0f * 0.5f; - - phi = fac * (pchan->limitmax[2] - pchan->limitmin[2]); - - i = (a == -16) ? 0 : 1; - corner[i][0] = sinf(phi); - corner[i][1] = cosf(phi); - corner[i][2] = 0.0f; - glVertex3fv(corner[i]); - } - glEnd(); - - glRotatef(-theta, 0.0f, 0.0f, 1.0f); - } - - if (pchan->ikflag & BONE_IK_XLIMIT) { - /* OpenGL requires rotations in degrees; so we're taking the average angle here */ - theta = RAD2DEGF(0.5f * (pchan->limitmin[0] + pchan->limitmax[0])); - glRotatef(theta, 1.0f, 0.0f, 0.0f); - - glColor3ub(255, 50, 50); /* Red, X axis limit */ - glBegin(GL_LINE_STRIP); - for (a = -16; a <= 16; a++) { - /* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */ - float fac = ((float)a) / 16.0f * 0.5f; - phi = (float)M_PI_2 + fac * (pchan->limitmax[0] - pchan->limitmin[0]); - - i = (a == -16) ? 2 : 3; - corner[i][0] = 0.0f; - corner[i][1] = sinf(phi); - corner[i][2] = cosf(phi); - glVertex3fv(corner[i]); - } - glEnd(); - - glRotatef(-theta, 1.0f, 0.0f, 0.0f); - } - - /* out of cone, out of bone */ - glPopMatrix(); - } - } - } - } - } - } -} - -static void bone_matrix_translate_y(float mat[4][4], float y) -{ - float trans[3]; - - copy_v3_v3(trans, mat[1]); - mul_v3_fl(trans, y); - add_v3_v3(mat[3], trans); -} - -/* assumes object is Armature with pose */ -static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base, - const short dt, const unsigned char ob_wire_col[4], - const bool do_const_color, const bool is_outline) -{ - RegionView3D *rv3d = ar->regiondata; - Object *ob = base->object; - bArmature *arm = ob->data; - bPoseChannel *pchan; - Bone *bone; - float smat[4][4], imat[4][4], bmat[4][4]; - int index = -1; - const enum { - DASH_RELATIONSHIP_LINES = 1, - DASH_HELP_LINES = 2, - } do_dashed = ( - (is_outline ? 0 : DASH_RELATIONSHIP_LINES) | - ((v3d->flag & V3D_HIDE_HELPLINES) ? 0 : DASH_HELP_LINES)); - bool draw_wire = false; - int flag; - bool is_cull_enabled; - - /* being set below */ - arm->layer_used = 0; - - /* precalc inverse matrix for drawing screen aligned */ - if (arm->drawtype == ARM_ENVELOPE) { - /* precalc inverse matrix for drawing screen aligned */ - copy_m4_m4(smat, rv3d->viewmatob); - mul_mat3_m4_fl(smat, 1.0f / len_v3(ob->obmat[0])); - invert_m4_m4(imat, smat); - - /* and draw blended distances */ - if (arm->flag & ARM_POSEMODE) { - glEnable(GL_BLEND); - - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - bone = pchan->bone; - if (bone) { - /* 1) bone must be visible, 2) for OpenGL select-drawing cannot have unselectable [#27194] - * NOTE: this is the only case with (NO_DEFORM == 0) flag, as this is for envelope influence drawing - */ - if (((bone->flag & (BONE_HIDDEN_P | BONE_NO_DEFORM | BONE_HIDDEN_PG)) == 0) && - ((G.f & G_PICKSEL) == 0 || (bone->flag & BONE_UNSELECTABLE) == 0)) - { - if (bone->flag & (BONE_SELECTED)) { - if (bone->layer & arm->layer) - draw_sphere_bone_dist(smat, imat, pchan, NULL); - } - } - } - } - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - } - } - - /* little speedup, also make sure transparent only draws once */ - glCullFace(GL_BACK); - if (v3d->flag2 & V3D_BACKFACE_CULLING) { - glEnable(GL_CULL_FACE); - is_cull_enabled = true; - } - else { - is_cull_enabled = false; - } - - /* if solid we draw that first, with selection codes, but without names, axes etc */ - if (dt > OB_WIRE) { - if (arm->flag & ARM_POSEMODE) - index = base->selcol; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - bone = pchan->bone; - arm->layer_used |= bone->layer; - - /* 1) bone must be visible, 2) for OpenGL select-drawing cannot have unselectable [#27194] */ - if (((bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) && - ((G.f & G_PICKSEL) == 0 || (bone->flag & BONE_UNSELECTABLE) == 0)) - { - if (bone->layer & arm->layer) { - const bool use_custom = (pchan->custom) && !(arm->flag & ARM_NO_CUSTOM); - glPushMatrix(); - - if (use_custom && pchan->custom_tx) { - glMultMatrixf(pchan->custom_tx->pose_mat); - } - else { - glMultMatrixf(pchan->pose_mat); - } - - /* catch exception for bone with hidden parent */ - flag = bone->flag; - if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { - flag &= ~BONE_CONNECTED; - } - - /* set temporary flag for drawing bone as active, but only if selected */ - if (bone == arm->act_bone) - flag |= BONE_DRAW_ACTIVE; - - if (do_const_color) { - /* keep color */ - } - else { - /* set color-set to use */ - set_pchan_colorset(ob, pchan); - } - - /* may be 2x width from custom bone's outline option */ - glLineWidth(1.0f); - - if (use_custom) { - /* if drawwire, don't try to draw in solid */ - if (pchan->bone->flag & BONE_DRAWWIRE) { - draw_wire = true; - } - else { - if (is_cull_enabled && (v3d->flag2 & V3D_BACKFACE_CULLING) == 0) { - is_cull_enabled = false; - glDisable(GL_CULL_FACE); - } - - draw_custom_bone(scene, v3d, rv3d, pchan->custom, - OB_SOLID, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan)); - } - } - else { - if (is_cull_enabled == false) { - is_cull_enabled = true; - glEnable(GL_CULL_FACE); - } - - if (arm->drawtype == ARM_LINE) { - /* nothing in solid */ - } - else if (arm->drawtype == ARM_WIRE) { - /* nothing in solid */ - } - else if (arm->drawtype == ARM_ENVELOPE) { - draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, pchan, NULL); - } - else if (arm->drawtype == ARM_B_BONE) { - draw_b_bone(OB_SOLID, arm->flag, flag, 0, index, pchan, NULL); - } - else { - draw_bone(OB_SOLID, arm->flag, flag, 0, index, bone->length); - } - } - - glPopMatrix(); - } - } - - if (index != -1) - index += 0x10000; /* pose bones count in higher 2 bytes only */ - } - - /* very very confusing... but in object mode, solid draw, we cannot do GPU_select_load_id yet, - * stick bones and/or wire custom-shapes are drawn in next loop - */ - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false) && index != -1) { - /* object tag, for bordersel optim */ - GPU_select_load_id(index & 0xFFFF); - index = -1; - } - } - - /* custom bone may draw outline double-width */ - if (arm->flag & ARM_POSEMODE) { - glLineWidth(1.0f); - } - - /* draw custom bone shapes as wireframes */ - if (!(arm->flag & ARM_NO_CUSTOM) && - (draw_wire || (dt <= OB_WIRE)) ) - { - if (arm->flag & ARM_POSEMODE) - index = base->selcol; - - /* only draw custom bone shapes that need to be drawn as wires */ - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - bone = pchan->bone; - - /* 1) bone must be visible, 2) for OpenGL select-drawing cannot have unselectable [#27194] */ - if (((bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) && - ((G.f & G_PICKSEL) == 0 || (bone->flag & BONE_UNSELECTABLE) == 0) ) - { - if (bone->layer & arm->layer) { - if (pchan->custom) { - if ((dt < OB_SOLID) || (bone->flag & BONE_DRAWWIRE)) { - glPushMatrix(); - - if (pchan->custom_tx) { - glMultMatrixf(pchan->custom_tx->pose_mat); - } - else { - glMultMatrixf(pchan->pose_mat); - } - - /* prepare colors */ - if (do_const_color) { - /* 13 October 2009, Disabled this to make ghosting show the right colors (Aligorith) */ - } - else if (arm->flag & ARM_POSEMODE) - set_pchan_colorset(ob, pchan); - else { - glColor3ubv(ob_wire_col); - } - - /* catch exception for bone with hidden parent */ - flag = bone->flag; - if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) - flag &= ~BONE_CONNECTED; - - /* set temporary flag for drawing bone as active, but only if selected */ - if (bone == arm->act_bone) - flag |= BONE_DRAW_ACTIVE; - - draw_custom_bone(scene, v3d, rv3d, pchan->custom, - OB_WIRE, arm->flag, flag, index, PCHAN_CUSTOM_DRAW_SIZE(pchan)); - - glPopMatrix(); - } - } - } - } - - if (index != -1) - index += 0x10000; /* pose bones count in higher 2 bytes only */ - } - /* stick or wire bones have not been drawn yet so don't clear object selection in this case */ - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire && index != -1) { - /* object tag, for bordersel optim */ - GPU_select_load_id(index & 0xFFFF); - index = -1; - } - } - - /* wire draw over solid only in posemode */ - if ((dt <= OB_WIRE) || (arm->flag & ARM_POSEMODE) || ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { - /* draw line check first. we do selection indices */ - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { - if (arm->flag & ARM_POSEMODE) - index = base->selcol; - } - /* if solid && posemode, we draw again with polygonoffset */ - else if ((dt > OB_WIRE) && (arm->flag & ARM_POSEMODE)) { - ED_view3d_polygon_offset(rv3d, 1.0); - } - else { - /* and we use selection indices if not done yet */ - if (arm->flag & ARM_POSEMODE) - index = base->selcol; - } - - if (is_cull_enabled == false) { - is_cull_enabled = true; - glEnable(GL_CULL_FACE); - } - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - bone = pchan->bone; - arm->layer_used |= bone->layer; - - /* 1) bone must be visible, 2) for OpenGL select-drawing cannot have unselectable [#27194] */ - if (((bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) && - ((G.f & G_PICKSEL) == 0 || (bone->flag & BONE_UNSELECTABLE) == 0)) - { - if (bone->layer & arm->layer) { - const short constflag = pchan->constflag; - if ((do_dashed & DASH_RELATIONSHIP_LINES) && (pchan->parent)) { - /* Draw a line from our root to the parent's tip - * - only if V3D_HIDE_HELPLINES is enabled... - */ - if ((do_dashed & DASH_HELP_LINES) && ((bone->flag & BONE_CONNECTED) == 0)) { - if (arm->flag & ARM_POSEMODE) { - GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */ - UI_ThemeColor(TH_WIRE); - } - setlinestyle(3); - glBegin(GL_LINES); - glVertex3fv(pchan->pose_head); - glVertex3fv(pchan->parent->pose_tail); - glEnd(); - setlinestyle(0); - } - - /* Draw a line to IK root bone - * - only if temporary chain (i.e. "autoik") - */ - if (arm->flag & ARM_POSEMODE) { - if (constflag & PCHAN_HAS_IK) { - if (bone->flag & BONE_SELECTED) { - if (constflag & PCHAN_HAS_TARGET) glColor3ub(200, 120, 0); - else glColor3ub(200, 200, 50); /* add theme! */ - - GPU_select_load_id(index & 0xFFFF); - pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES)); - } - } - else if (constflag & PCHAN_HAS_SPLINEIK) { - if (bone->flag & BONE_SELECTED) { - glColor3ub(150, 200, 50); /* add theme! */ - - GPU_select_load_id(index & 0xFFFF); - pchan_draw_IK_root_lines(pchan, !(do_dashed & DASH_HELP_LINES)); - } - } - } - } - - glPushMatrix(); - if (arm->drawtype != ARM_ENVELOPE) - glMultMatrixf(pchan->pose_mat); - - /* catch exception for bone with hidden parent */ - flag = bone->flag; - if ((bone->parent) && (bone->parent->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) - flag &= ~BONE_CONNECTED; - - /* set temporary flag for drawing bone as active, but only if selected */ - if (bone == arm->act_bone) - flag |= BONE_DRAW_ACTIVE; - - /* extra draw service for pose mode */ - - /* set color-set to use */ - if (do_const_color) { - /* keep color */ - } - else { - set_pchan_colorset(ob, pchan); - } - - if ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) { - /* custom bone shapes should not be drawn here! */ - } - else if (arm->drawtype == ARM_ENVELOPE) { - if (dt < OB_SOLID) - draw_sphere_bone_wire(smat, imat, arm->flag, flag, constflag, index, pchan, NULL); - } - else if (arm->drawtype == ARM_LINE) - draw_line_bone(arm->flag, flag, constflag, index, pchan, NULL); - else if (arm->drawtype == ARM_WIRE) - draw_wire_bone(dt, arm->flag, flag, constflag, index, pchan, NULL); - else if (arm->drawtype == ARM_B_BONE) - draw_b_bone(OB_WIRE, arm->flag, flag, constflag, index, pchan, NULL); - else - draw_bone(OB_WIRE, arm->flag, flag, constflag, index, bone->length); - - glPopMatrix(); - } - } - - /* pose bones count in higher 2 bytes only */ - if (index != -1) - index += 0x10000; - } - /* restore things */ - if (!ELEM(arm->drawtype, ARM_WIRE, ARM_LINE) && (dt > OB_WIRE) && (arm->flag & ARM_POSEMODE)) - ED_view3d_polygon_offset(rv3d, 0.0); - } - - /* restore */ - if (is_cull_enabled) { - glDisable(GL_CULL_FACE); - } - - /* draw DoFs */ - if (arm->flag & ARM_POSEMODE) { - if (((base->flag & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) { - draw_pose_dofs(ob); - } - } - - /* finally names and axes */ - if ((arm->flag & (ARM_DRAWNAMES | ARM_DRAWAXES)) && - (is_outline == 0) && - ((base->flag & OB_FROMDUPLI) == 0)) - { - /* patch for several 3d cards (IBM mostly) that crash on GL_SELECT with text drawing */ - if ((G.f & G_PICKSEL) == 0) { - float vec[3]; - - unsigned char col[4]; - if (do_const_color) { - /* so we can draw bone names in current const color */ - float tcol[4]; - glGetFloatv(GL_CURRENT_COLOR, tcol); - rgb_float_to_uchar(col, tcol); - col[3] = 255; - } - else { - col[0] = ob_wire_col[0]; - col[1] = ob_wire_col[1]; - col[2] = ob_wire_col[2]; - col[3] = 255; - } - - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if ((pchan->bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG)) == 0) { - if (pchan->bone->layer & arm->layer) { - if (arm->flag & (ARM_EDITMODE | ARM_POSEMODE)) { - bone = pchan->bone; - UI_GetThemeColor3ubv((bone->flag & BONE_SELECTED) ? TH_TEXT_HI : TH_TEXT, col); - } - else if (dt > OB_WIRE) { - UI_GetThemeColor3ubv(TH_TEXT, col); - } - - /* Draw names of bone */ - if (arm->flag & ARM_DRAWNAMES) { - mid_v3_v3v3(vec, pchan->pose_head, pchan->pose_tail); - view3d_cached_text_draw_add(vec, pchan->name, strlen(pchan->name), 10, 0, col); - } - - /* Draw additional axes on the bone tail */ - if ((arm->flag & ARM_DRAWAXES) && (arm->flag & ARM_POSEMODE)) { - glPushMatrix(); - copy_m4_m4(bmat, pchan->pose_mat); - bone_matrix_translate_y(bmat, pchan->bone->length); - glMultMatrixf(bmat); - - glColor3ubv(col); - - float viewmat_pchan[4][4]; - mul_m4_m4m4(viewmat_pchan, rv3d->viewmatob, bmat); - drawaxes(viewmat_pchan, pchan->bone->length * 0.25f, OB_ARROWS); - - glPopMatrix(); - } - } - } - } - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - } - } - - if (index != -1) { - GPU_select_load_id(-1); - } -} - -/* in editmode, we don't store the bone matrix... */ -static void get_matrix_editbone(EditBone *ebone, float bmat[4][4]) -{ - ebone->length = len_v3v3(ebone->tail, ebone->head); - ED_armature_ebone_to_mat4(ebone, bmat); -} - -static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt) -{ - RegionView3D *rv3d = ar->regiondata; - EditBone *eBone; - bArmature *arm = ob->data; - float smat[4][4], imat[4][4], bmat[4][4]; - unsigned int index; - int flag; - - /* being set in code below */ - arm->layer_used = 0; - - ED_view3d_check_mats_rv3d(rv3d); - - /* envelope (deform distance) */ - if (arm->drawtype == ARM_ENVELOPE) { - /* precalc inverse matrix for drawing screen aligned */ - copy_m4_m4(smat, rv3d->viewmatob); - mul_mat3_m4_fl(smat, 1.0f / len_v3(ob->obmat[0])); - invert_m4_m4(imat, smat); - - /* and draw blended distances */ - glEnable(GL_BLEND); - - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - if (eBone->layer & arm->layer) { - if ((eBone->flag & (BONE_HIDDEN_A | BONE_NO_DEFORM)) == 0) { - if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) - draw_sphere_bone_dist(smat, imat, NULL, eBone); - } - } - } - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - } - - /* if solid we draw it first */ - if ((dt > OB_WIRE) && (arm->drawtype != ARM_LINE)) { - for (eBone = arm->edbo->first, index = 0; eBone; eBone = eBone->next, index++) { - if (eBone->layer & arm->layer) { - if ((eBone->flag & BONE_HIDDEN_A) == 0) { - glPushMatrix(); - get_matrix_editbone(eBone, bmat); - glMultMatrixf(bmat); - - /* catch exception for bone with hidden parent */ - flag = eBone->flag; - if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) { - flag &= ~BONE_CONNECTED; - } - - /* set temporary flag for drawing bone as active, but only if selected */ - if (eBone == arm->act_edbone) - flag |= BONE_DRAW_ACTIVE; - - if (arm->drawtype == ARM_ENVELOPE) - draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone); - else if (arm->drawtype == ARM_B_BONE) - draw_b_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone); - else if (arm->drawtype == ARM_WIRE) - draw_wire_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone); - else { - draw_bone(OB_SOLID, arm->flag, flag, 0, index, eBone->length); - } - - glPopMatrix(); - } - } - } - } - - /* if wire over solid, set offset */ - index = -1; - GPU_select_load_id(-1); - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { - if (G.f & G_PICKSEL) - index = 0; - } - else if (dt > OB_WIRE) - ED_view3d_polygon_offset(rv3d, 1.0); - else if (arm->flag & ARM_EDITMODE) - index = 0; /* do selection codes */ - - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - arm->layer_used |= eBone->layer; - if (eBone->layer & arm->layer) { - if ((eBone->flag & BONE_HIDDEN_A) == 0) { - - /* catch exception for bone with hidden parent */ - flag = eBone->flag; - if ((eBone->parent) && !EBONE_VISIBLE(arm, eBone->parent)) { - flag &= ~BONE_CONNECTED; - } - - /* set temporary flag for drawing bone as active, but only if selected */ - if (eBone == arm->act_edbone) - flag |= BONE_DRAW_ACTIVE; - - if (arm->drawtype == ARM_ENVELOPE) { - if (dt < OB_SOLID) - draw_sphere_bone_wire(smat, imat, arm->flag, flag, 0, index, NULL, eBone); - } - else { - glPushMatrix(); - get_matrix_editbone(eBone, bmat); - glMultMatrixf(bmat); - - if (arm->drawtype == ARM_LINE) - draw_line_bone(arm->flag, flag, 0, index, NULL, eBone); - else if (arm->drawtype == ARM_WIRE) - draw_wire_bone(OB_WIRE, arm->flag, flag, 0, index, NULL, eBone); - else if (arm->drawtype == ARM_B_BONE) - draw_b_bone(OB_WIRE, arm->flag, flag, 0, index, NULL, eBone); - else - draw_bone(OB_WIRE, arm->flag, flag, 0, index, eBone->length); - - glPopMatrix(); - } - - /* offset to parent */ - if (eBone->parent) { - UI_ThemeColor(TH_WIRE_EDIT); - GPU_select_load_id(-1); /* -1 here is OK! */ - setlinestyle(3); - - glBegin(GL_LINES); - glVertex3fv(eBone->parent->tail); - glVertex3fv(eBone->head); - glEnd(); - - setlinestyle(0); - } - } - } - if (index != -1) index++; - } - - /* restore */ - if (index != -1) { - GPU_select_load_id(-1); - } - - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { - /* pass */ - } - else if (dt > OB_WIRE) { - ED_view3d_polygon_offset(rv3d, 0.0); - } - - /* finally names and axes */ - if (arm->flag & (ARM_DRAWNAMES | ARM_DRAWAXES)) { - /* patch for several 3d cards (IBM mostly) that crash on GL_SELECT with text drawing */ - if ((G.f & G_PICKSEL) == 0) { - float vec[3]; - unsigned char col[4]; - col[3] = 255; - - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { - if (eBone->layer & arm->layer) { - if ((eBone->flag & BONE_HIDDEN_A) == 0) { - - UI_GetThemeColor3ubv((eBone->flag & BONE_SELECTED) ? TH_TEXT_HI : TH_TEXT, col); - - /* Draw name */ - if (arm->flag & ARM_DRAWNAMES) { - mid_v3_v3v3(vec, eBone->head, eBone->tail); - view3d_cached_text_draw_add(vec, eBone->name, strlen(eBone->name), 10, 0, col); - } - /* Draw additional axes */ - if (arm->flag & ARM_DRAWAXES) { - glPushMatrix(); - get_matrix_editbone(eBone, bmat); - bone_matrix_translate_y(bmat, eBone->length); - glMultMatrixf(bmat); - - glColor3ubv(col); - - float viewmat_ebone[4][4]; - mul_m4_m4m4(viewmat_ebone, rv3d->viewmatob, bmat); - drawaxes(viewmat_ebone, eBone->length * 0.25f, OB_ARROWS); - - glPopMatrix(); - } - - } - } - } - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - } - } -} - -/* ****************************** Armature Visualization ******************************** */ - -/* ---------- Paths --------- */ - -/* draw bone paths - * - in view space - */ -static void draw_pose_paths(Scene *scene, View3D *v3d, ARegion *ar, Object *ob) -{ - bAnimVizSettings *avs = &ob->pose->avs; - bArmature *arm = ob->data; - bPoseChannel *pchan; - - /* setup drawing environment for paths */ - draw_motion_paths_init(v3d, ar); - - /* draw paths where they exist and they releated bone is visible */ - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if ((pchan->bone->layer & arm->layer) && (pchan->mpath)) - draw_motion_path_instance(scene, ob, pchan, avs, pchan->mpath); - } - - /* cleanup after drawing */ - draw_motion_paths_cleanup(v3d); -} - - -/* ---------- Ghosts --------- */ - -/* helper function for ghost drawing - sets/removes flags for temporarily - * hiding unselected bones while drawing ghosts - */ -static void ghost_poses_tag_unselected(Object *ob, short unset) -{ - bArmature *arm = ob->data; - bPose *pose = ob->pose; - bPoseChannel *pchan; - - /* don't do anything if no hiding any bones */ - if ((arm->flag & ARM_GHOST_ONLYSEL) == 0) - return; - - /* loop over all pchans, adding/removing tags as appropriate */ - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if ((pchan->bone) && (arm->layer & pchan->bone->layer)) { - if (unset) { - /* remove tags from all pchans if cleaning up */ - pchan->bone->flag &= ~BONE_HIDDEN_PG; - } - else { - /* set tags on unselected pchans only */ - if ((pchan->bone->flag & BONE_SELECTED) == 0) - pchan->bone->flag |= BONE_HIDDEN_PG; - } - } - } -} - -/* draw ghosts that occur within a frame range - * note: object should be in posemode - */ -static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base *base) -{ - Object *ob = base->object; - AnimData *adt = BKE_animdata_from_id(&ob->id); - bArmature *arm = ob->data; - bPose *posen, *poseo; - float start, end, stepsize, range, colfac; - int cfrao, flago; - - start = (float)arm->ghostsf; - end = (float)arm->ghostef; - if (end <= start) - return; - - /* prevent infinite loops if this is set to 0 - T49527 */ - if (arm->ghostsize < 1) - arm->ghostsize = 1; - - stepsize = (float)(arm->ghostsize); - range = (float)(end - start); - - /* store values */ - ob->mode &= ~OB_MODE_POSE; - cfrao = CFRA; - flago = arm->flag; - arm->flag &= ~(ARM_DRAWNAMES | ARM_DRAWAXES); - - /* copy the pose */ - poseo = ob->pose; - BKE_pose_copy_data(&posen, ob->pose, 1); - ob->pose = posen; - BKE_pose_rebuild(ob, ob->data); /* child pointers for IK */ - ghost_poses_tag_unselected(ob, 0); /* hide unselected bones if need be */ - - glEnable(GL_BLEND); - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - /* draw from first frame of range to last */ - for (CFRA = (int)start; CFRA <= end; CFRA += (int)stepsize) { - colfac = (end - (float)CFRA) / range; - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac))); - - BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL); - BKE_pose_where_is(scene, ob); - draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false); - } - glDisable(GL_BLEND); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - - /* before disposing of temp pose, use it to restore object to a sane state */ - BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)cfrao, ADT_RECALC_ALL); - - /* clean up temporary pose */ - ghost_poses_tag_unselected(ob, 1); /* unhide unselected bones if need be */ - BKE_pose_free(posen); - - /* restore */ - CFRA = cfrao; - ob->pose = poseo; - arm->flag = flago; - ob->mode |= OB_MODE_POSE; -} - -/* draw ghosts on keyframes in action within range - * - object should be in posemode - */ -static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, ARegion *ar, Base *base) -{ - Object *ob = base->object; - AnimData *adt = BKE_animdata_from_id(&ob->id); - bAction *act = (adt) ? adt->action : NULL; - bArmature *arm = ob->data; - bPose *posen, *poseo; - DLRBT_Tree keys; - ActKeyColumn *ak, *akn; - float start, end, range, colfac, i; - int cfrao, flago; - - start = (float)arm->ghostsf; - end = (float)arm->ghostef; - if (end <= start) - return; - - /* get keyframes - then clip to only within range */ - BLI_dlrbTree_init(&keys); - action_to_keylist(adt, act, &keys, NULL); - BLI_dlrbTree_linkedlist_sync(&keys); - - range = 0; - for (ak = keys.first; ak; ak = akn) { - akn = ak->next; - - if ((ak->cfra < start) || (ak->cfra > end)) - BLI_freelinkN((ListBase *)&keys, ak); - else - range++; - } - if (range == 0) return; - - /* store values */ - ob->mode &= ~OB_MODE_POSE; - cfrao = CFRA; - flago = arm->flag; - arm->flag &= ~(ARM_DRAWNAMES | ARM_DRAWAXES); - - /* copy the pose */ - poseo = ob->pose; - BKE_pose_copy_data(&posen, ob->pose, 1); - ob->pose = posen; - BKE_pose_rebuild(ob, ob->data); /* child pointers for IK */ - ghost_poses_tag_unselected(ob, 0); /* hide unselected bones if need be */ - - glEnable(GL_BLEND); - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - /* draw from first frame of range to last */ - for (ak = keys.first, i = 0; ak; ak = ak->next, i++) { - colfac = i / range; - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac))); - - CFRA = (int)ak->cfra; - - BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL); - BKE_pose_where_is(scene, ob); - draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false); - } - glDisable(GL_BLEND); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - - /* before disposing of temp pose, use it to restore object to a sane state */ - BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)cfrao, ADT_RECALC_ALL); - - /* clean up temporary pose */ - ghost_poses_tag_unselected(ob, 1); /* unhide unselected bones if need be */ - BLI_dlrbTree_free(&keys); - BKE_pose_free(posen); - - /* restore */ - CFRA = cfrao; - ob->pose = poseo; - arm->flag = flago; - ob->mode |= OB_MODE_POSE; -} - -/* draw ghosts around current frame - * - object is supposed to be armature in posemode - */ -static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) -{ - Object *ob = base->object; - AnimData *adt = BKE_animdata_from_id(&ob->id); - bArmature *arm = ob->data; - bPose *posen, *poseo; - float cur, start, end, stepsize, range, colfac, actframe, ctime; - int cfrao, flago; - - /* pre conditions, get an action with sufficient frames */ - if (ELEM(NULL, adt, adt->action)) - return; - - calc_action_range(adt->action, &start, &end, 0); - if (start == end) - return; - - /* prevent infinite loops if this is set to 0 - T49527 */ - if (arm->ghostsize < 1) - arm->ghostsize = 1; - - stepsize = (float)(arm->ghostsize); - range = (float)(arm->ghostep) * stepsize + 0.5f; /* plus half to make the for loop end correct */ - - /* store values */ - ob->mode &= ~OB_MODE_POSE; - cfrao = CFRA; - actframe = BKE_nla_tweakedit_remap(adt, (float)CFRA, 0); - flago = arm->flag; - arm->flag &= ~(ARM_DRAWNAMES | ARM_DRAWAXES); - - /* copy the pose */ - poseo = ob->pose; - BKE_pose_copy_data(&posen, ob->pose, 1); - ob->pose = posen; - BKE_pose_rebuild(ob, ob->data); /* child pointers for IK */ - ghost_poses_tag_unselected(ob, 0); /* hide unselected bones if need be */ - - glEnable(GL_BLEND); - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - /* draw from darkest blend to lowest */ - for (cur = stepsize; cur < range; cur += stepsize) { - ctime = cur - (float)fmod(cfrao, stepsize); /* ensures consistent stepping */ - colfac = ctime / range; - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac))); - - /* only within action range */ - if (actframe + ctime >= start && actframe + ctime <= end) { - CFRA = (int)BKE_nla_tweakedit_remap(adt, actframe + ctime, NLATIME_CONVERT_MAP); - - if (CFRA != cfrao) { - BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL); - BKE_pose_where_is(scene, ob); - draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false); - } - } - - ctime = cur + (float)fmod((float)cfrao, stepsize) - stepsize + 1.0f; /* ensures consistent stepping */ - colfac = ctime / range; - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128 - (int)(120.0f * sqrtf(colfac))); - - /* only within action range */ - if ((actframe - ctime >= start) && (actframe - ctime <= end)) { - CFRA = (int)BKE_nla_tweakedit_remap(adt, actframe - ctime, NLATIME_CONVERT_MAP); - - if (CFRA != cfrao) { - BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)CFRA, ADT_RECALC_ALL); - BKE_pose_where_is(scene, ob); - draw_pose_bones(scene, v3d, ar, base, OB_WIRE, NULL, true, false); - } - } - } - glDisable(GL_BLEND); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - - /* before disposing of temp pose, use it to restore object to a sane state */ - BKE_animsys_evaluate_animdata(scene, &ob->id, adt, (float)cfrao, ADT_RECALC_ALL); - - /* clean up temporary pose */ - ghost_poses_tag_unselected(ob, 1); /* unhide unselected bones if need be */ - BKE_pose_free(posen); - - /* restore */ - CFRA = cfrao; - ob->pose = poseo; - arm->flag = flago; - ob->mode |= OB_MODE_POSE; -} - -/* ********************************** Armature Drawing - Main ************************* */ - -/* called from drawobject.c, return true if nothing was drawn - * (ob_wire_col == NULL) when drawing ghost */ -bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, - const short dt, const short dflag, const unsigned char ob_wire_col[4], - const bool is_outline) -{ - Object *ob = base->object; - bArmature *arm = ob->data; - bool retval = false; - - if (v3d->flag2 & V3D_RENDER_OVERRIDE) - return true; - - /* needed for 'draw_line_bone' which draws pixel. */ - if (arm->drawtype == ARM_LINE) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - } - - if (dt > OB_WIRE) { - /* we use color for solid lighting */ - if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { - const float diffuse[3] = {0.64f, 0.64f, 0.64f}; - const float specular[3] = {0.5f, 0.5f, 0.5f}; - GPU_basic_shader_colors(diffuse, specular, 35, 1.0f); - } - else { - const float diffuse[3] = {1.0f, 1.0f, 1.0f}; - const float specular[3] = {1.0f, 1.0f, 1.0f}; - GPU_basic_shader_colors(diffuse, specular, 35, 1.0f); - glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); /* only for lighting... */ - } - } - - /* arm->flag is being used to detect mode... */ - /* editmode? */ - if (arm->edbo) { - arm->flag |= ARM_EDITMODE; - draw_ebones(v3d, ar, ob, dt); - arm->flag &= ~ARM_EDITMODE; - } - else { - /* Draw Pose */ - if (ob->pose && ob->pose->chanbase.first) { - /* We can't safely draw non-updated pose, might contain NULL bone pointers... */ - if (ob->pose->flag & POSE_RECALC) { - BKE_pose_rebuild(ob, arm); - } - - /* drawing posemode selection indices or colors only in these cases */ - if (!(base->flag & OB_FROMDUPLI)) { - if (G.f & G_PICKSEL) { -#if 0 - /* nifty but actually confusing to allow bone selection out of posemode */ - if (OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) { - if (ob == modifiers_isDeformedByArmature(OBACT)) - arm->flag |= ARM_POSEMODE; - } - else -#endif - if (ob->mode & OB_MODE_POSE) { - arm->flag |= ARM_POSEMODE; - } - } - else if (ob->mode & OB_MODE_POSE) { - if (arm->ghosttype == ARM_GHOST_RANGE) { - draw_ghost_poses_range(scene, v3d, ar, base); - } - else if (arm->ghosttype == ARM_GHOST_KEYS) { - draw_ghost_poses_keys(scene, v3d, ar, base); - } - else if (arm->ghosttype == ARM_GHOST_CUR) { - if (arm->ghostep) - draw_ghost_poses(scene, v3d, ar, base); - } - if ((dflag & DRAW_SCENESET) == 0) { - if (ob == OBACT) - arm->flag |= ARM_POSEMODE; - else if (OBACT && (OBACT->mode & OB_MODE_WEIGHT_PAINT)) { - if (ob == modifiers_isDeformedByArmature(OBACT)) - arm->flag |= ARM_POSEMODE; - } - draw_pose_paths(scene, v3d, ar, ob); - } - } - } - draw_pose_bones(scene, v3d, ar, base, dt, ob_wire_col, (dflag & DRAW_CONSTCOLOR), is_outline); - arm->flag &= ~ARM_POSEMODE; - - if (ob->mode & OB_MODE_POSE) - UI_ThemeColor(TH_WIRE); /* restore, for extra draw stuff */ - } - else { - retval = true; - } - } - /* restore */ - glFrontFace(GL_CCW); - - if (arm->drawtype == ARM_LINE) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - } - - return retval; -} diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c deleted file mode 100644 index 20dbb8df69e..00000000000 --- a/source/blender/editors/space_view3d/drawmesh.c +++ /dev/null @@ -1,1405 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * Contributor(s): Blender Foundation, full update, glsl support - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/drawmesh.c - * \ingroup spview3d - */ - -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "BLI_utildefines.h" -#include "BLI_bitmap.h" -#include "BLI_math.h" - -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_node_types.h" -#include "DNA_object_types.h" -#include "DNA_property_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_view3d_types.h" - -#include "BKE_DerivedMesh.h" -#include "BKE_global.h" -#include "BKE_image.h" -#include "BKE_material.h" -#include "BKE_paint.h" -#include "BKE_property.h" -#include "BKE_editmesh.h" -#include "BKE_scene.h" - -#include "BIF_gl.h" -#include "BIF_glutil.h" - -#include "UI_resources.h" - -#include "GPU_draw.h" -#include "GPU_material.h" -#include "GPU_basic_shader.h" -#include "GPU_shader.h" - -#include "RE_engine.h" - -#include "ED_uvedit.h" - -#include "view3d_intern.h" /* own include */ - -/* user data structures for derived mesh callbacks */ -typedef struct drawMeshFaceSelect_userData { - Mesh *me; - BLI_bitmap *edge_flags; /* pairs of edge options (visible, select) */ -} drawMeshFaceSelect_userData; - -typedef struct drawEMTFMapped_userData { - BMEditMesh *em; - bool has_mcol; - int cd_poly_tex_offset; - const MPoly *mpoly; - const MTexPoly *mtexpoly; -} drawEMTFMapped_userData; - -typedef struct drawTFace_userData { - const Mesh *me; - const MPoly *mpoly; - const MTexPoly *mtexpoly; -} drawTFace_userData; - -/**************************** Face Select Mode *******************************/ - -/* mainly to be less confusing */ -BLI_INLINE int edge_vis_index(const int index) { return index * 2; } -BLI_INLINE int edge_sel_index(const int index) { return index * 2 + 1; } - -static BLI_bitmap *get_tface_mesh_marked_edge_info(Mesh *me, bool draw_select_edges) -{ - BLI_bitmap *bitmap_edge_flags = BLI_BITMAP_NEW(me->totedge * 2, __func__); - MPoly *mp; - MLoop *ml; - int i, j; - bool select_set; - - for (i = 0; i < me->totpoly; i++) { - mp = &me->mpoly[i]; - - if (!(mp->flag & ME_HIDE)) { - select_set = (mp->flag & ME_FACE_SEL) != 0; - - ml = me->mloop + mp->loopstart; - for (j = 0; j < mp->totloop; j++, ml++) { - if ((draw_select_edges == false) && - (select_set && BLI_BITMAP_TEST(bitmap_edge_flags, edge_sel_index(ml->e)))) - { - BLI_BITMAP_DISABLE(bitmap_edge_flags, edge_vis_index(ml->e)); - } - else { - BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_vis_index(ml->e)); - if (select_set) { - BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_sel_index(ml->e)); - } - } - } - } - } - - return bitmap_edge_flags; -} - - -static DMDrawOption draw_mesh_face_select__setHiddenOpts(void *userData, int index) -{ - drawMeshFaceSelect_userData *data = userData; - Mesh *me = data->me; - - if (me->drawflag & ME_DRAWEDGES) { - if ((BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index)))) - return DM_DRAW_OPTION_NORMAL; - else - return DM_DRAW_OPTION_SKIP; - } - else if (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)) && - BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))) - { - return DM_DRAW_OPTION_NORMAL; - } - else { - return DM_DRAW_OPTION_SKIP; - } -} - -static DMDrawOption draw_mesh_face_select__setSelectOpts(void *userData, int index) -{ - drawMeshFaceSelect_userData *data = userData; - return (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)) && - BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP; -} - -/* draws unselected */ -static DMDrawOption draw_mesh_face_select__drawFaceOptsInv(void *userData, int index) -{ - Mesh *me = (Mesh *)userData; - - MPoly *mpoly = &me->mpoly[index]; - if (!(mpoly->flag & ME_HIDE) && !(mpoly->flag & ME_FACE_SEL)) - return DM_DRAW_OPTION_NORMAL; - else - return DM_DRAW_OPTION_SKIP; -} - -void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm, bool draw_select_edges) -{ - drawMeshFaceSelect_userData data; - - data.me = me; - data.edge_flags = get_tface_mesh_marked_edge_info(me, draw_select_edges); - - glEnable(GL_DEPTH_TEST); - ED_view3d_polygon_offset(rv3d, 1.0); - - /* Draw (Hidden) Edges */ - setlinestyle(1); - UI_ThemeColor(TH_EDGE_FACESEL); - dm->drawMappedEdges(dm, draw_mesh_face_select__setHiddenOpts, &data); - setlinestyle(0); - - /* Draw Selected Faces */ - if (me->drawflag & ME_DRAWFACES) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - /* dull unselected faces so as not to get in the way of seeing color */ - glColor4ub(96, 96, 96, 64); - dm->drawMappedFaces(dm, draw_mesh_face_select__drawFaceOptsInv, NULL, NULL, (void *)me, DM_DRAW_SKIP_HIDDEN); - glDisable(GL_BLEND); - } - - ED_view3d_polygon_offset(rv3d, 1.0); - - /* Draw Stippled Outline for selected faces */ - glColor3ub(255, 255, 255); - setlinestyle(1); - dm->drawMappedEdges(dm, draw_mesh_face_select__setSelectOpts, &data); - setlinestyle(0); - - ED_view3d_polygon_offset(rv3d, 0.0); /* resets correctly now, even after calling accumulated offsets */ - - MEM_freeN(data.edge_flags); -} - -/***************************** Texture Drawing ******************************/ - -static Material *give_current_material_or_def(Object *ob, int matnr) -{ - extern Material defmaterial; /* render module abuse... */ - Material *ma = give_current_material(ob, matnr); - - return ma ? ma : &defmaterial; -} - -/* Icky globals, fix with userdata parameter */ - -static struct TextureDrawState { - Object *ob; - Image *stencil; /* texture painting stencil */ - Image *canvas; /* texture painting canvas, for image mode */ - bool use_game_mat; - int is_lit, is_tex; - int color_profile; - bool use_backface_culling; - bool two_sided_lighting; - unsigned char obcol[4]; - bool is_texpaint; - bool texpaint_material; /* use material slots for texture painting */ -} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, false, {0, 0, 0, 0}, false, false}; - -static bool set_draw_settings_cached( - int clearcache, MTexPoly *texface, Material *ma, - const struct TextureDrawState *gtexdraw) -{ - static Material *c_ma; - static int c_textured; - static MTexPoly c_texface; - static int c_backculled; - static bool c_badtex; - static int c_lit; - static int c_has_texface; - - int backculled = 1; - int alphablend = GPU_BLEND_SOLID; - int textured = 0; - int lit = 0; - int has_texface = texface != NULL; - bool need_set_tpage = false; - bool texpaint = ((gtexdraw->ob->mode & OB_MODE_TEXTURE_PAINT) != 0); - - Image *ima = NULL; - - if (ma != NULL) { - if (ma->mode & MA_TRANSP) { - alphablend = GPU_BLEND_ALPHA; - } - } - - if (clearcache) { - c_textured = c_lit = c_backculled = -1; - memset(&c_texface, 0, sizeof(c_texface)); - c_badtex = false; - c_has_texface = -1; - c_ma = NULL; - } - else { - textured = gtexdraw->is_tex; - } - - /* convert number of lights into boolean */ - if (gtexdraw->is_lit) { - lit = 1; - } - - backculled = gtexdraw->use_backface_culling; - if (ma) { - if (ma->mode & MA_SHLESS) lit = 0; - if (gtexdraw->use_game_mat) { - backculled = backculled || (ma->game.flag & GEMAT_BACKCULL); - alphablend = ma->game.alpha_blend; - } - } - - if (texface && !texpaint) { - textured = textured && (texface->tpage); - - /* no material, render alpha if texture has depth=32 */ - if (!ma && BKE_image_has_alpha(texface->tpage)) - alphablend = GPU_BLEND_ALPHA; - } - else if (texpaint) { - if (gtexdraw->texpaint_material) - ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL; - else - ima = gtexdraw->canvas; - } - else - textured = 0; - - if (backculled != c_backculled) { - if (backculled) glEnable(GL_CULL_FACE); - else glDisable(GL_CULL_FACE); - - c_backculled = backculled; - } - - /* need to re-set tpage if textured flag changed or existsment of texface changed.. */ - need_set_tpage = textured != c_textured || has_texface != c_has_texface; - /* ..or if settings inside texface were changed (if texface was used) */ - need_set_tpage |= (texpaint && c_ma != ma) || (texface && memcmp(&c_texface, texface, sizeof(c_texface))); - - if (need_set_tpage) { - if (textured) { - if (texpaint) { - c_badtex = false; - if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, 0, 1, 0, false)) { - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); - - glActiveTexture(GL_TEXTURE1); - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); - glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]); - glActiveTexture(GL_TEXTURE0); - } - else { - glActiveTexture(GL_TEXTURE1); - glDisable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glActiveTexture(GL_TEXTURE0); - - c_badtex = true; - GPU_clear_tpage(true); - glDisable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - } - else { - c_badtex = !GPU_set_tpage(texface, !texpaint, alphablend); - } - } - else { - GPU_set_tpage(NULL, 0, 0); - c_badtex = false; - } - c_textured = textured; - c_has_texface = has_texface; - if (texface) - memcpy(&c_texface, texface, sizeof(c_texface)); - } - - if (c_badtex) lit = 0; - if (lit != c_lit || ma != c_ma || textured != c_textured) { - int options = GPU_SHADER_USE_COLOR; - - if (c_textured && !c_badtex) { - options |= GPU_SHADER_TEXTURE_2D; - } - if (gtexdraw->two_sided_lighting) { - options |= GPU_SHADER_TWO_SIDED; - } - - if (lit) { - options |= GPU_SHADER_LIGHTING; - if (!ma) - ma = give_current_material_or_def(NULL, 0); /* default material */ - - float specular[3]; - mul_v3_v3fl(specular, &ma->specr, ma->spec); - - GPU_basic_shader_colors(NULL, specular, ma->har, 1.0f); - } - - GPU_basic_shader_bind(options); - - c_lit = lit; - c_ma = ma; - } - - return c_badtex; -} - -static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob) -{ - unsigned char obcol[4]; - bool is_tex, solidtex; - Mesh *me = ob->data; - ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - - /* XXX scene->obedit warning */ - - /* texture draw is abused for mask selection mode, do this so wire draw - * with face selection in weight paint is not lit. */ - if ((v3d->drawtype <= OB_WIRE) && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT))) { - solidtex = false; - Gtexdraw.is_lit = 0; - } - else if ((ob->mode & OB_MODE_TEXTURE_PAINT) && BKE_scene_use_new_shading_nodes(scene)) { - solidtex = true; - if (v3d->flag2 & V3D_SHADELESS_TEX) - Gtexdraw.is_lit = 0; - else - Gtexdraw.is_lit = -1; - } - else if ((v3d->drawtype == OB_SOLID) || - ((ob->mode & OB_MODE_EDIT) && (v3d->drawtype != OB_TEXTURE))) - { - /* draw with default lights in solid draw mode and edit mode */ - solidtex = true; - Gtexdraw.is_lit = -1; - } - else { - /* draw with lights in the scene otherwise */ - solidtex = false; - if (v3d->flag2 & V3D_SHADELESS_TEX) { - Gtexdraw.is_lit = 0; - } - else { - Gtexdraw.is_lit = GPU_scene_object_lights( - scene, ob, v3d->localvd ? v3d->localvd->lay : v3d->lay, - rv3d->viewmat, !rv3d->is_persp); - } - } - - rgba_float_to_uchar(obcol, ob->col); - - if (solidtex || v3d->drawtype == OB_TEXTURE) is_tex = true; - else is_tex = false; - - Gtexdraw.ob = ob; - Gtexdraw.stencil = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? imapaint->stencil : NULL; - Gtexdraw.is_texpaint = (ob->mode == OB_MODE_TEXTURE_PAINT); - Gtexdraw.texpaint_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL); - Gtexdraw.canvas = (Gtexdraw.texpaint_material) ? NULL : imapaint->canvas; - Gtexdraw.is_tex = is_tex; - - /* naughty multitexturing hacks to quickly support stencil + shading + alpha blending - * in new texpaint code. The better solution here would be to support GLSL */ - if (Gtexdraw.is_texpaint) { - glActiveTexture(GL_TEXTURE1); - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); - - /* load the stencil texture here */ - if (Gtexdraw.stencil != NULL) { - glActiveTexture(GL_TEXTURE2); - if (GPU_verify_image(Gtexdraw.stencil, NULL, GL_TEXTURE_2D, false, false, false, false)) { - float col[4] = {imapaint->stencil_col[0], imapaint->stencil_col[1], imapaint->stencil_col[2], 1.0f}; - glEnable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, col); - if ((imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) == 0) { - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_ONE_MINUS_SRC_COLOR); - } - else { - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); - } - } - } - glActiveTexture(GL_TEXTURE0); - } - - Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene); - Gtexdraw.use_game_mat = (RE_engines_find(scene->r.engine)->flag & RE_GAME) != 0; - Gtexdraw.use_backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0; - Gtexdraw.two_sided_lighting = (me->flag & ME_TWOSIDED); - - memcpy(Gtexdraw.obcol, obcol, sizeof(obcol)); - set_draw_settings_cached(1, NULL, NULL, &Gtexdraw); - glCullFace(GL_BACK); -} - -static void draw_textured_end(void) -{ - if (Gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) { - glActiveTexture(GL_TEXTURE1); - glDisable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBindTexture(GL_TEXTURE_2D, 0); - - if (Gtexdraw.stencil != NULL) { - glActiveTexture(GL_TEXTURE2); - glDisable(GL_TEXTURE_2D); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - glBindTexture(GL_TEXTURE_2D, 0); - } - glActiveTexture(GL_TEXTURE0); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - /* manual reset, since we don't use tpage */ - glBindTexture(GL_TEXTURE_2D, 0); - /* force switch off textures */ - GPU_clear_tpage(true); - } - else { - /* switch off textures */ - GPU_set_tpage(NULL, 0, 0); - } - - glDisable(GL_CULL_FACE); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - - /* XXX, bad patch - GPU_default_lights() calls - * glLightfv(GL_POSITION, ...) which - * is transformed by the current matrix... we - * need to make sure that matrix is identity. - * - * It would be better if drawmesh.c kept track - * of and restored the light settings it changed. - * - zr - */ - glPushMatrix(); - glLoadIdentity(); - GPU_default_lights(); - glPopMatrix(); -} - -static DMDrawOption draw_tface__set_draw_legacy(MTexPoly *mtexpoly, const bool has_mcol, int matnr) -{ - Material *ma = give_current_material(Gtexdraw.ob, matnr + 1); - bool invalidtexture = false; - - if (ma && (ma->game.flag & GEMAT_INVISIBLE)) - return DM_DRAW_OPTION_SKIP; - - invalidtexture = set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw); - - if (mtexpoly && invalidtexture) { - glColor3ub(0xFF, 0x00, 0xFF); - return DM_DRAW_OPTION_NO_MCOL; /* Don't set color */ - } - else if (!has_mcol) { - if (mtexpoly) { - glColor3f(1.0, 1.0, 1.0); - } - else { - if (ma) { - if (ma->shade_flag & MA_OBCOLOR) { - glColor3ubv(Gtexdraw.obcol); - } - else { - float col[3]; - if (Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r); - else copy_v3_v3(col, &ma->r); - - glColor3fv(col); - } - } - else { - glColor3f(1.0, 1.0, 1.0); - } - } - return DM_DRAW_OPTION_NORMAL; /* normal drawing (no mcols anyway, no need to turn off) */ - } - else { - return DM_DRAW_OPTION_NORMAL; /* Set color from mcol */ - } -} - -static DMDrawOption draw_tface__set_draw(MTexPoly *mtexpoly, const bool UNUSED(has_mcol), int matnr) -{ - Material *ma = give_current_material(Gtexdraw.ob, matnr + 1); - - if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return DM_DRAW_OPTION_SKIP; - - if (mtexpoly || Gtexdraw.is_texpaint) - set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw); - - /* always use color from mcol, as set in update_tface_color_layer */ - return DM_DRAW_OPTION_NORMAL; -} - -static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol) -{ - const MPoly *mp = dm->getPolyArray(dm); - const int mpoly_num = dm->getNumPolys(dm); - MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY); - MLoopCol *finalCol; - int i, j; - MLoopCol *mloopcol = NULL; - - /* cache material values to avoid a lot of lookups */ - Material *ma = NULL; - short mat_nr_prev = -1; - enum { - COPY_CALC, - COPY_ORIG, - COPY_PREV, - } copy_mode = COPY_CALC; - - if (use_mcol) { - mloopcol = dm->getLoopDataArray(dm, CD_PREVIEW_MLOOPCOL); - if (!mloopcol) - mloopcol = dm->getLoopDataArray(dm, CD_MLOOPCOL); - } - - if (CustomData_has_layer(&dm->loopData, CD_TEXTURE_MLOOPCOL)) { - finalCol = CustomData_get_layer(&dm->loopData, CD_TEXTURE_MLOOPCOL); - } - else { - finalCol = MEM_mallocN(sizeof(MLoopCol) * dm->numLoopData, "add_tface_color_layer"); - CustomData_add_layer(&dm->loopData, CD_TEXTURE_MLOOPCOL, CD_ASSIGN, finalCol, dm->numLoopData); - } - - for (i = mpoly_num; i--; mp++) { - const short mat_nr = mp->mat_nr; - - if (UNLIKELY(mat_nr_prev != mat_nr)) { - ma = give_current_material(Gtexdraw.ob, mat_nr + 1); - copy_mode = COPY_CALC; - mat_nr_prev = mat_nr; - } - - /* avoid lookups */ - if (copy_mode == COPY_ORIG) { - memcpy(&finalCol[mp->loopstart], &mloopcol[mp->loopstart], sizeof(*finalCol) * mp->totloop); - } - else if (copy_mode == COPY_PREV) { - int loop_index = mp->loopstart; - const MLoopCol *lcol_prev = &finalCol[(mp - 1)->loopstart]; - for (j = 0; j < mp->totloop; j++, loop_index++) { - finalCol[loop_index] = *lcol_prev; - } - } - - /* (copy_mode == COPY_CALC) */ - else if (ma && (ma->game.flag & GEMAT_INVISIBLE)) { - if (mloopcol) { - memcpy(&finalCol[mp->loopstart], &mloopcol[mp->loopstart], sizeof(*finalCol) * mp->totloop); - copy_mode = COPY_ORIG; - } - else { - memset(&finalCol[mp->loopstart], 0xff, sizeof(*finalCol) * mp->totloop); - copy_mode = COPY_PREV; - } - } - else if (mtexpoly && set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw)) { - int loop_index = mp->loopstart; - for (j = 0; j < mp->totloop; j++, loop_index++) { - finalCol[loop_index].r = 255; - finalCol[loop_index].g = 0; - finalCol[loop_index].b = 255; - finalCol[loop_index].a = 255; - } - copy_mode = COPY_PREV; - } - else if (ma && (ma->shade_flag & MA_OBCOLOR)) { - int loop_index = mp->loopstart; - for (j = 0; j < mp->totloop; j++, loop_index++) { - copy_v3_v3_uchar(&finalCol[loop_index].r, Gtexdraw.obcol); - finalCol[loop_index].a = 255; - } - copy_mode = COPY_PREV; - } - else { - if (mloopcol) { - memcpy(&finalCol[mp->loopstart], &mloopcol[mp->loopstart], sizeof(*finalCol) * mp->totloop); - copy_mode = COPY_ORIG; - } - else if (mtexpoly) { - memset(&finalCol[mp->loopstart], 0xff, sizeof(*finalCol) * mp->totloop); - copy_mode = COPY_PREV; - } - else { - float col[3]; - - if (ma) { - int loop_index = mp->loopstart; - MLoopCol lcol; - - if (Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r); - else copy_v3_v3(col, &ma->r); - rgb_float_to_uchar((unsigned char *)&lcol.r, col); - lcol.a = 255; - - for (j = 0; j < mp->totloop; j++, loop_index++) { - finalCol[loop_index] = lcol; - } - } - else { - memset(&finalCol[mp->loopstart], 0xff, sizeof(*finalCol) * mp->totloop); - } - copy_mode = COPY_PREV; - } - } - } - - dm->dirty |= DM_DIRTY_MCOL_UPDATE_DRAW; -} - -static DMDrawOption draw_tface_mapped__set_draw(void *userData, int origindex, int UNUSED(mat_nr)) -{ - const Mesh *me = ((drawTFace_userData *)userData)->me; - - /* array checked for NULL before calling */ - MPoly *mpoly = &me->mpoly[origindex]; - - BLI_assert(origindex >= 0 && origindex < me->totpoly); - - if (mpoly->flag & ME_HIDE) { - return DM_DRAW_OPTION_SKIP; - } - else { - MTexPoly *tpoly = (me->mtpoly) ? &me->mtpoly[origindex] : NULL; - int matnr = mpoly->mat_nr; - - return draw_tface__set_draw(tpoly, (me->mloopcol != NULL), matnr); - } -} - -static DMDrawOption draw_em_tf_mapped__set_draw(void *userData, int origindex, int mat_nr) -{ - drawEMTFMapped_userData *data = userData; - BMEditMesh *em = data->em; - BMFace *efa; - - if (UNLIKELY(origindex >= em->bm->totface)) - return DM_DRAW_OPTION_NORMAL; - - efa = BM_face_at_index(em->bm, origindex); - - if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - return DM_DRAW_OPTION_SKIP; - } - else { - MTexPoly *mtexpoly = (data->cd_poly_tex_offset != -1) ? - BM_ELEM_CD_GET_VOID_P(efa, data->cd_poly_tex_offset) : NULL; - int matnr = (mat_nr != -1) ? mat_nr : efa->mat_nr; - - return draw_tface__set_draw_legacy(mtexpoly, data->has_mcol, matnr); - } -} - -/* when face select is on, use face hidden flag */ -static DMDrawOption wpaint__setSolidDrawOptions_facemask(void *userData, int index) -{ - Mesh *me = (Mesh *)userData; - MPoly *mp = &me->mpoly[index]; - if (mp->flag & ME_HIDE) - return DM_DRAW_OPTION_SKIP; - return DM_DRAW_OPTION_NORMAL; -} - -static void draw_mesh_text(Scene *scene, Object *ob, int glsl) -{ - Mesh *me = ob->data; - DerivedMesh *ddm; - MPoly *mp, *mface = me->mpoly; - MTexPoly *mtpoly = me->mtpoly; - MLoopUV *mloopuv = me->mloopuv; - MLoopUV *luv; - MLoopCol *mloopcol = me->mloopcol; /* why does mcol exist? */ - MLoopCol *lcol; - - bProperty *prop = BKE_bproperty_object_get(ob, "Text"); - GPUVertexAttribs gattribs; - int a, totpoly = me->totpoly; - - /* fake values to pass to GPU_render_text() */ - MCol tmp_mcol[4] = {{0}}; - MCol *tmp_mcol_pt = mloopcol ? tmp_mcol : NULL; - - /* don't draw without tfaces */ - if (!mtpoly || !mloopuv) - return; - - /* don't draw when editing */ - if (ob->mode & OB_MODE_EDIT) - return; - else if (ob == OBACT) - if (BKE_paint_select_elem_test(ob)) - return; - - ddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); - - for (a = 0, mp = mface; a < totpoly; a++, mtpoly++, mp++) { - short matnr = mp->mat_nr; - const bool mf_smooth = (mp->flag & ME_SMOOTH) != 0; - Material *mat = (me->mat) ? me->mat[matnr] : NULL; - int mode = mat ? mat->game.flag : GEMAT_INVISIBLE; - - - if (!(mode & GEMAT_INVISIBLE) && (mode & GEMAT_TEXT) && mp->totloop >= 3) { - /* get the polygon as a tri/quad */ - int mp_vi[4]; - float v_quad_data[4][3]; - const float *v_quad[4]; - const float *uv_quad[4]; - char string[MAX_PROPSTRING]; - int characters, i, glattrib = -1, badtex = 0; - - - /* TEXFACE */ - if (glsl) { - GPU_object_material_bind(matnr + 1, &gattribs); - - for (i = 0; i < gattribs.totlayer; i++) { - if (gattribs.layer[i].type == CD_MTFACE) { - glattrib = gattribs.layer[i].glindex; - break; - } - } - } - else { - badtex = set_draw_settings_cached(0, mtpoly, mat, &Gtexdraw); - if (badtex) { - continue; - } - } - - mp_vi[0] = me->mloop[mp->loopstart + 0].v; - mp_vi[1] = me->mloop[mp->loopstart + 1].v; - mp_vi[2] = me->mloop[mp->loopstart + 2].v; - mp_vi[3] = (mp->totloop >= 4) ? me->mloop[mp->loopstart + 3].v : 0; - - /* UV */ - luv = &mloopuv[mp->loopstart]; - uv_quad[0] = luv->uv; luv++; - uv_quad[1] = luv->uv; luv++; - uv_quad[2] = luv->uv; luv++; - if (mp->totloop >= 4) { - uv_quad[3] = luv->uv; - } - else { - uv_quad[3] = NULL; - } - - - /* COLOR */ - if (mloopcol) { - unsigned int totloop_clamp = min_ii(4, mp->totloop); - unsigned int j; - lcol = &mloopcol[mp->loopstart]; - - for (j = 0; j < totloop_clamp; j++, lcol++) { - MESH_MLOOPCOL_TO_MCOL(lcol, &tmp_mcol[j]); - } - } - - /* LOCATION */ - ddm->getVertCo(ddm, mp_vi[0], v_quad_data[0]); - ddm->getVertCo(ddm, mp_vi[1], v_quad_data[1]); - ddm->getVertCo(ddm, mp_vi[2], v_quad_data[2]); - if (mp->totloop >= 4) { - ddm->getVertCo(ddm, mp_vi[3], v_quad_data[3]); - } - - v_quad[0] = v_quad_data[0]; - v_quad[1] = v_quad_data[1]; - v_quad[2] = v_quad_data[2]; - if (mp->totloop >= 4) { - v_quad[3] = v_quad_data[2]; - } - else { - v_quad[3] = NULL; - } - - - /* The BM_FONT handling is in the gpu module, shared with the - * game engine, was duplicated previously */ - - BKE_bproperty_set_valstr(prop, string); - characters = strlen(string); - - if (!BKE_image_has_ibuf(mtpoly->tpage, NULL)) - characters = 0; - - if (!mf_smooth) { - float nor[3]; - - normal_tri_v3(nor, v_quad[0], v_quad[1], v_quad[2]); - - glNormal3fv(nor); - } - - GPU_render_text( - mtpoly, mode, string, characters, - (unsigned int *)tmp_mcol_pt, - v_quad, uv_quad, - glattrib); - } - } - - ddm->release(ddm); -} - -static int compareDrawOptions(void *userData, int cur_index, int next_index) -{ - drawTFace_userData *data = userData; - - if (data->mpoly && data->mpoly[cur_index].mat_nr != data->mpoly[next_index].mat_nr) - return 0; - - if (data->mtexpoly && data->mtexpoly[cur_index].tpage != data->mtexpoly[next_index].tpage) - return 0; - - return 1; -} - - -static int compareDrawOptionsEm(void *userData, int cur_index, int next_index) -{ - drawEMTFMapped_userData *data = userData; - - if (data->mpoly && data->mpoly[cur_index].mat_nr != data->mpoly[next_index].mat_nr) - return 0; - - if (data->mtexpoly && data->mtexpoly[cur_index].tpage != data->mtexpoly[next_index].tpage) - return 0; - - return 1; -} - -static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d, - Object *ob, DerivedMesh *dm, const int draw_flags) -{ - Mesh *me = ob->data; - - /* correct for negative scale */ - if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); - else glFrontFace(GL_CCW); - - /* draw the textured mesh */ - draw_textured_begin(scene, v3d, rv3d, ob); - - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - - if (ob->mode & OB_MODE_EDIT) { - drawEMTFMapped_userData data; - - data.em = me->edit_btmesh; - data.has_mcol = CustomData_has_layer(&me->edit_btmesh->bm->ldata, CD_MLOOPCOL); - data.cd_poly_tex_offset = CustomData_get_offset(&me->edit_btmesh->bm->pdata, CD_MTEXPOLY); - - data.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY); - data.mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY); - - dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data, 0); - } - else { - DMDrawFlag dm_draw_flag; - drawTFace_userData userData; - - if (ob->mode & OB_MODE_TEXTURE_PAINT) { - dm_draw_flag = DM_DRAW_USE_TEXPAINT_UV; - } - else { - dm_draw_flag = DM_DRAW_USE_ACTIVE_UV; - } - - if (ob == OBACT) { - if (ob->mode & OB_MODE_WEIGHT_PAINT) { - dm_draw_flag |= DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN; - } - else if (ob->mode & OB_MODE_SCULPT) { - dm_draw_flag |= DM_DRAW_SKIP_HIDDEN | DM_DRAW_USE_COLORS; - } - else if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) { - dm_draw_flag |= DM_DRAW_USE_COLORS; - } - } - else { - if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) { - dm_draw_flag |= DM_DRAW_USE_COLORS; - } - } - - - userData.mpoly = DM_get_poly_data_layer(dm, CD_MPOLY); - userData.mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY); - - if (draw_flags & DRAW_FACE_SELECT) { - userData.me = me; - - dm->drawMappedFacesTex( - dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, - &userData, dm_draw_flag); - } - else { - userData.me = NULL; - - /* if ((ob->mode & OB_MODE_ALL_PAINT) == 0) */ { - - /* Note: this isn't efficient and runs on every redraw, - * its needed so material colors are used for vertex colors. - * In the future we will likely remove 'texface' so, just avoid running this where possible, - * (when vertex paint or weight paint are used). - * - * Note 2: We disable optimization for now since it causes T48788 - * and it is now too close to release to do something smarter. - * - * TODO(sergey): Find some real solution here. - */ - - update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT)); - } - - dm->drawFacesTex( - dm, draw_tface__set_draw, compareDrawOptions, - &userData, dm_draw_flag); - } - } - - /* draw game engine text hack */ - if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { - if (BKE_bproperty_object_get(ob, "Text")) { - draw_mesh_text(scene, ob, 0); - } - } - - draw_textured_end(); - - /* draw edges and selected faces over textured mesh */ - if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) { - bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0; - draw_mesh_face_select(rv3d, me, dm, draw_select_edges); - } - - /* reset from negative scale correction */ - glFrontFace(GL_CCW); - - /* in editmode, the blend mode needs to be set in case it was ADD */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -} - -/************************** NEW SHADING NODES ********************************/ - -typedef struct TexMatCallback { - Scene *scene; - Object *ob; - Mesh *me; - DerivedMesh *dm; - bool shadeless; - bool two_sided_lighting; -} TexMatCallback; - -static void tex_mat_set_material_cb(void *UNUSED(userData), int mat_nr, void *attribs) -{ - /* all we have to do here is simply enable the GLSL material, but note - * that the GLSL code will give different result depending on the drawtype, - * in texture draw mode it will output the active texture node, in material - * draw mode it will show the full material. */ - GPU_object_material_bind(mat_nr, attribs); -} - -static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs) -{ - /* texture draw mode without GLSL */ - TexMatCallback *data = (TexMatCallback *)userData; - GPUVertexAttribs *gattribs = attribs; - Image *ima; - ImageUser *iuser; - bNode *node; - - /* draw image texture if we find one */ - if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node, NULL)) { - /* get openl texture */ - int mipmap = 1; - int bindcode = (ima) ? GPU_verify_image(ima, iuser, GL_TEXTURE_2D, 0, 0, mipmap, false) : 0; - - if (bindcode) { - NodeTexBase *texbase = node->storage; - - /* disable existing material */ - GPU_object_material_unbind(); - - /* bind texture */ - glBindTexture(GL_TEXTURE_2D, ima->bindcode[TEXTARGET_TEXTURE_2D]); - - glMatrixMode(GL_TEXTURE); - glLoadMatrixf(texbase->tex_mapping.mat); - glMatrixMode(GL_MODELVIEW); - - /* use active UV texture layer */ - memset(gattribs, 0, sizeof(*gattribs)); - - gattribs->layer[0].type = CD_MTFACE; - gattribs->layer[0].name[0] = '\0'; - gattribs->layer[0].gltexco = 1; - gattribs->layer[0].glinfoindoex = -1; - gattribs->totlayer = 1; - - /* bind material */ - float diffuse[3] = {1.0f, 1.0f, 1.0f}; - - int options = GPU_SHADER_TEXTURE_2D; - if (!data->shadeless) - options |= GPU_SHADER_LIGHTING; - if (data->two_sided_lighting) - options |= GPU_SHADER_TWO_SIDED; - - GPU_basic_shader_colors(diffuse, NULL, 0, 1.0f); - GPU_basic_shader_bind(options); - - return; - } - } - - /* disable texture material */ - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - - if (data->shadeless) { - glColor3f(1.0f, 1.0f, 1.0f); - memset(gattribs, 0, sizeof(*gattribs)); - } - else { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - - /* enable solid material */ - GPU_object_material_bind(mat_nr, attribs); - } -} - -static bool tex_mat_set_face_mesh_cb(void *userData, int index) -{ - /* faceselect mode face hiding */ - TexMatCallback *data = (TexMatCallback *)userData; - Mesh *me = (Mesh *)data->me; - MPoly *mp = &me->mpoly[index]; - - return !(mp->flag & ME_HIDE); -} - -static bool tex_mat_set_face_editmesh_cb(void *userData, int index) -{ - /* editmode face hiding */ - TexMatCallback *data = (TexMatCallback *)userData; - Mesh *me = (Mesh *)data->me; - BMEditMesh *em = me->edit_btmesh; - BMFace *efa; - - if (UNLIKELY(index >= em->bm->totface)) - return DM_DRAW_OPTION_NORMAL; - - efa = BM_face_at_index(em->bm, index); - - return !BM_elem_flag_test(efa, BM_ELEM_HIDDEN); -} - -void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, - Object *ob, DerivedMesh *dm, const int draw_flags) -{ - /* if not cycles, or preview-modifiers, or drawing matcaps */ - if ((draw_flags & DRAW_MODIFIERS_PREVIEW) || - (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) || - (BKE_scene_use_new_shading_nodes(scene) == false) || - ((ob->mode & OB_MODE_TEXTURE_PAINT) && ELEM(v3d->drawtype, OB_TEXTURE, OB_SOLID))) - { - draw_mesh_textured_old(scene, v3d, rv3d, ob, dm, draw_flags); - return; - } - else if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { - draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags); - return; - } - - /* set opengl state for negative scale & color */ - if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); - else glFrontFace(GL_CCW); - - Mesh *me = ob->data; - - bool shadeless = ((v3d->flag2 & V3D_SHADELESS_TEX) && - ((v3d->drawtype == OB_TEXTURE) || (ob->mode & OB_MODE_TEXTURE_PAINT))); - bool two_sided_lighting = (me->flag & ME_TWOSIDED) != 0; - - TexMatCallback data = {scene, ob, me, dm, shadeless, two_sided_lighting}; - bool (*set_face_cb)(void *, int); - bool picking = (G.f & G_PICKSEL) != 0; - - /* face hiding callback depending on mode */ - if (ob == scene->obedit) - set_face_cb = tex_mat_set_face_editmesh_cb; - else if (draw_flags & DRAW_FACE_SELECT) - set_face_cb = tex_mat_set_face_mesh_cb; - else - set_face_cb = NULL; - - /* test if we can use glsl */ - const int drawtype = view3d_effective_drawtype(v3d); - bool glsl = (drawtype == OB_MATERIAL) && !picking; - - GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); - - if (glsl || picking) { - /* draw glsl or solid */ - dm->drawMappedFacesMat(dm, - tex_mat_set_material_cb, - set_face_cb, &data); - } - else { - /* draw textured */ - dm->drawMappedFacesMat(dm, - tex_mat_set_texture_cb, - set_face_cb, &data); - } - - GPU_end_object_materials(); - - /* reset opengl state */ - GPU_end_object_materials(); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - - glBindTexture(GL_TEXTURE_2D, 0); - - glFrontFace(GL_CCW); - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - - /* faceselect mode drawing over textured mesh */ - if (!(ob == scene->obedit) && (draw_flags & DRAW_FACE_SELECT)) { - bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0; - draw_mesh_face_select(rv3d, ob->data, dm, draw_select_edges); - } -} - -/* Vertex Paint and Weight Paint */ -static void draw_mesh_paint_light_begin(void) -{ - /* get material diffuse color from vertex colors but set default spec */ - const float specular[3] = {0.47f, 0.47f, 0.47f}; - GPU_basic_shader_colors(NULL, specular, 35, 1.0f); - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); -} - -static void draw_mesh_paint_light_end(void) -{ - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); -} - -void draw_mesh_paint_weight_faces(DerivedMesh *dm, const bool use_light, - void *facemask_cb, void *user_data) -{ - DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_object_material_bind : NULL; - int flags = DM_DRAW_USE_COLORS; - - if (use_light) { - draw_mesh_paint_light_begin(); - flags |= DM_DRAW_NEED_NORMALS; - } - - dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, setMaterial, NULL, user_data, flags); - - if (use_light) { - draw_mesh_paint_light_end(); - } -} - -void draw_mesh_paint_vcolor_faces(DerivedMesh *dm, const bool use_light, - void *facemask_cb, void *user_data, - const Mesh *me) -{ - DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_object_material_bind : NULL; - int flags = 0; - - if (use_light) { - draw_mesh_paint_light_begin(); - flags |= DM_DRAW_NEED_NORMALS; - } - - /* Don't show alpha in wire mode. */ - const bool show_alpha = use_light; - if (show_alpha) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - if (me->mloopcol) { - dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, - DM_DRAW_USE_COLORS | flags); - } - else { - glColor3f(1.0f, 1.0f, 1.0f); - dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, flags); - } - - if (show_alpha) { - glDisable(GL_BLEND); - } - - if (use_light) { - draw_mesh_paint_light_end(); - } -} - -void draw_mesh_paint_weight_edges(RegionView3D *rv3d, DerivedMesh *dm, - const bool use_depth, const bool use_alpha, - void *edgemask_cb, void *user_data) -{ - /* weight paint in solid mode, special case. focus on making the weights clear - * rather than the shading, this is also forced in wire view */ - - if (use_depth) { - ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ - } - else { - glDisable(GL_DEPTH_TEST); - } - - if (use_alpha) { - glEnable(GL_BLEND); - } - - glColor4ub(255, 255, 255, 96); - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(1, 0xAAAA); - - dm->drawMappedEdges(dm, (DMSetDrawOptions)edgemask_cb, user_data); - - if (use_depth) { - ED_view3d_polygon_offset(rv3d, 0.0); - glDepthMask(1); - } - else { - glEnable(GL_DEPTH_TEST); - } - - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - - if (use_alpha) { - glDisable(GL_BLEND); - } -} - -void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, - Object *ob, DerivedMesh *dm, const int draw_flags) -{ - DMSetDrawOptions facemask = NULL; - Mesh *me = ob->data; - const bool use_light = (v3d->drawtype >= OB_SOLID); - - /* hide faces in face select mode */ - if (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL)) - facemask = wpaint__setSolidDrawOptions_facemask; - - if (ob->mode & OB_MODE_WEIGHT_PAINT) { - draw_mesh_paint_weight_faces(dm, use_light, facemask, me); - } - else if (ob->mode & OB_MODE_VERTEX_PAINT) { - draw_mesh_paint_vcolor_faces(dm, use_light, facemask, me, me); - } - - /* draw face selection on top */ - if (draw_flags & DRAW_FACE_SELECT) { - bool draw_select_edges = (ob->mode & OB_MODE_TEXTURE_PAINT) == 0; - draw_mesh_face_select(rv3d, me, dm, draw_select_edges); - } - else if ((use_light == false) || (ob->dtx & OB_DRAWWIRE)) { - const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) || !(ob->mode & OB_MODE_WEIGHT_PAINT); - const bool use_alpha = (ob->mode & OB_MODE_VERTEX_PAINT) == 0; - - if (use_alpha == false) { - set_inverted_drawing(1); - } - - draw_mesh_paint_weight_edges(rv3d, dm, use_depth, use_alpha, NULL, NULL); - - if (use_alpha == false) { - set_inverted_drawing(0); - } - } -} diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index dd174c7fd7a..bb574874cad 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -27,248 +27,42 @@ * \ingroup spview3d */ -#include "MEM_guardedalloc.h" - -#include "DNA_camera_types.h" -#include "DNA_curve_types.h" -#include "DNA_constraint_types.h" /* for drawing constraint */ -#include "DNA_lamp_types.h" -#include "DNA_lattice_types.h" -#include "DNA_material_types.h" #include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" -#include "DNA_smoke_types.h" -#include "DNA_world_types.h" #include "DNA_object_types.h" -#include "BLI_listbase.h" -#include "BLI_link_utils.h" -#include "BLI_string.h" #include "BLI_math.h" -#include "BLI_memarena.h" -#include "BKE_anim.h" /* for the where_on_path function */ -#include "BKE_armature.h" -#include "BKE_camera.h" -#include "BKE_colortools.h" -#include "BKE_constraint.h" /* for the get_constraint_target function */ -#include "BKE_curve.h" #include "BKE_DerivedMesh.h" -#include "BKE_deform.h" -#include "BKE_displist.h" -#include "BKE_font.h" #include "BKE_global.h" -#include "BKE_image.h" -#include "BKE_key.h" -#include "BKE_lattice.h" -#include "BKE_main.h" -#include "BKE_mesh.h" -#include "BKE_material.h" -#include "BKE_mball.h" -#include "BKE_modifier.h" -#include "BKE_movieclip.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" -#include "BKE_pointcache.h" -#include "BKE_scene.h" -#include "BKE_subsurf.h" -#include "BKE_unit.h" -#include "BKE_tracking.h" #include "BKE_editmesh.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "GPU_draw.h" -#include "GPU_select.h" -#include "GPU_basic_shader.h" #include "GPU_shader.h" +#include "GPU_immediate.h" +#include "GPU_batch.h" +#include "GPU_matrix.h" +#include "GPU_state.h" +#include "GPU_framebuffer.h" #include "ED_mesh.h" -#include "ED_particle.h" -#include "ED_screen.h" -#include "ED_sculpt.h" -#include "ED_types.h" #include "UI_resources.h" -#include "UI_interface_icons.h" - -#include "WM_api.h" -#include "BLF_api.h" #include "view3d_intern.h" /* bad level include */ -/* Workaround for sequencer scene render mode. - * - * Strips doesn't use DAG to update objects or so, which - * might lead to situations when object is drawing without - * curve cache ready. - * - * Ideally we don't want to evaluate objects from drawing, - * but it'll require some major sequencer re-design. So - * for now just fallback to legacy behavior with calling - * display ist creating from draw(). - */ -#define SEQUENCER_DAG_WORKAROUND - -typedef enum eWireDrawMode { - OBDRAW_WIRE_OFF = 0, - OBDRAW_WIRE_ON = 1, - OBDRAW_WIRE_ON_DEPTH = 2 -} eWireDrawMode; - -typedef struct drawDMVerts_userData { - BMesh *bm; - - BMVert *eve_act; - char sel; - - /* cached theme values */ - unsigned char th_editmesh_active[4]; - unsigned char th_vertex_select[4]; - unsigned char th_vertex[4]; - unsigned char th_skin_root[4]; - - /* for skin node drawing */ - int cd_vskin_offset; - float imat[4][4]; -} drawDMVerts_userData; - -typedef struct drawDMEdgesSel_userData { - BMesh *bm; - - unsigned char *baseCol, *selCol, *actCol; - BMEdge *eed_act; -} drawDMEdgesSel_userData; - -typedef struct drawDMEdgesSelInterp_userData { - BMesh *bm; - - unsigned char *baseCol, *selCol; - unsigned char *lastCol; -} drawDMEdgesSelInterp_userData; - -typedef struct drawDMEdgesWeightInterp_userData { - BMesh *bm; - - int cd_dvert_offset; - int defgroup_tot; - int vgroup_index; - char weight_user; - float alert_color[3]; - -} drawDMEdgesWeightInterp_userData; - -typedef struct drawDMFacesSel_userData { -#ifdef WITH_FREESTYLE - unsigned char *cols[4]; -#else - unsigned char *cols[3]; -#endif - - DerivedMesh *dm; - BMesh *bm; - - BMFace *efa_act; - const int *orig_index_mp_to_orig; -} drawDMFacesSel_userData; - -typedef struct drawDMNormal_userData { - BMesh *bm; - int uniform_scale; - float normalsize; - float tmat[3][3]; - float imat[3][3]; -} drawDMNormal_userData; - -typedef struct drawMVertOffset_userData { - MVert *mvert; - int offset; -} drawMVertOffset_userData; - -typedef struct drawDMLayer_userData { - BMesh *bm; - int cd_layer_offset; -} drawDMLayer_userData; - -typedef struct drawBMOffset_userData { - BMesh *bm; - int offset; -} drawBMOffset_userData; - -typedef struct drawBMSelect_userData { - BMesh *bm; - bool select; -} drawBMSelect_userData; - -static void draw_bounding_volume(Object *ob, char type); - -static void drawcube_size(float size); -static void drawcircle_size(float size); -static void draw_empty_sphere(float size); -static void draw_empty_cone(float size); -static void draw_box(const float vec[8][3], bool solid); - -static void ob_wire_color_blend_theme_id(const unsigned char ob_wire_col[4], const int theme_id, float fac) -{ - float col_wire[3], col_bg[3], col[3]; - - rgb_uchar_to_float(col_wire, ob_wire_col); - - UI_GetThemeColor3fv(theme_id, col_bg); - interp_v3_v3v3(col, col_bg, col_wire, fac); - glColor3fv(col); -} +#include "../../draw/intern/draw_cache_impl.h" /* bad level include (temporary) */ int view3d_effective_drawtype(const struct View3D *v3d) { - if (v3d->drawtype == OB_RENDER) { - return v3d->prev_drawtype; + if (v3d->shading.type == OB_RENDER) { + return v3d->shading.prev_type; } - return v3d->drawtype; -} - -/* this condition has been made more complex since editmode can draw textures */ -bool check_object_draw_texture(Scene *scene, View3D *v3d, const char drawtype) -{ - const int v3d_drawtype = view3d_effective_drawtype(v3d); - /* texture and material draw modes */ - if (ELEM(v3d_drawtype, OB_TEXTURE, OB_MATERIAL) && drawtype > OB_SOLID) { - return true; - } - - /* textured solid */ - if ((v3d_drawtype == OB_SOLID) && - (v3d->flag2 & V3D_SOLID_TEX) && - (BKE_scene_use_new_shading_nodes(scene) == false)) - { - return true; - } - - if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) { - return true; - } - - return false; -} - -static bool check_object_draw_editweight(Mesh *me, DerivedMesh *finalDM) -{ - if (me->drawflag & ME_DRAWEIGHT) { - /* editmesh handles its own weight drawing */ - if (finalDM->type != DM_TYPE_EDITBMESH) { - return true; - } - } - - return false; + return v3d->shading.type; } static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt) @@ -283,58 +77,15 @@ static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt) return true; /* if its drawing textures with zbuf sel, then don't draw dots */ - if (dt == OB_TEXTURE && vd->drawtype == OB_TEXTURE) + if (dt == OB_TEXTURE && vd->shading.type == OB_TEXTURE) return false; - if ((vd->drawtype >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX)) + if ((vd->shading.type >= OB_SOLID) && (vd->flag2 & V3D_SOLID_TEX)) return false; return true; } -/* ************************ */ - -/* check for glsl drawing */ - -bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt) -{ - if (G.f & G_PICKSEL) - return false; - if (!check_object_draw_texture(scene, v3d, dt)) - return false; - if (ob == OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT)) - return false; - - if (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) - return true; - - if (v3d->drawtype == OB_TEXTURE) - return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene)); - else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID) - return true; - else - return false; -} - -static bool check_alpha_pass(Base *base) -{ - if (base->flag & OB_FROMDUPLI) - return false; - - if (G.f & G_PICKSEL) - return false; - - if (base->object->mode & OB_MODE_ALL_PAINT) - return false; - - return (base->object->dtx & OB_DRAWTRANSP); -} - -/***/ -static const unsigned int colortab[] = { - 0x0, 0x403000, 0xFFFF88 -}; - /* ----------------- OpenGL Circle Drawing - Tables for Optimized Drawing Speed ------------------ */ /* 32 values of sin function (still same result!) */ #define CIRCLE_RESOL 32 @@ -410,328 +161,6 @@ static const float cosval[CIRCLE_RESOL] = { 1.00000000 }; -/** - * \param viewmat_local_unit: is typically the 'rv3d->viewmatob' - * copied into a 3x3 matrix and normalized. - */ -static void draw_xyz_wire(const float viewmat_local_unit[3][3], const float c[3], float size, int axis) -{ - int line_type; - float buffer[4][3]; - int n = 0; - - float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f}; - float dim = size * 0.1f; - float dx[3], dy[3]; - - dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f; - dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f; - - switch (axis) { - case 0: /* x axis */ - line_type = GL_LINES; - - /* bottom left to top right */ - negate_v3_v3(v1, dx); - sub_v3_v3(v1, dy); - copy_v3_v3(v2, dx); - add_v3_v3(v2, dy); - - copy_v3_v3(buffer[n++], v1); - copy_v3_v3(buffer[n++], v2); - - /* top left to bottom right */ - mul_v3_fl(dy, 2.0f); - add_v3_v3(v1, dy); - sub_v3_v3(v2, dy); - - copy_v3_v3(buffer[n++], v1); - copy_v3_v3(buffer[n++], v2); - - break; - case 1: /* y axis */ - line_type = GL_LINES; - - /* bottom left to top right */ - mul_v3_fl(dx, 0.75f); - negate_v3_v3(v1, dx); - sub_v3_v3(v1, dy); - copy_v3_v3(v2, dx); - add_v3_v3(v2, dy); - - copy_v3_v3(buffer[n++], v1); - copy_v3_v3(buffer[n++], v2); - - /* top left to center */ - mul_v3_fl(dy, 2.0f); - add_v3_v3(v1, dy); - zero_v3(v2); - - copy_v3_v3(buffer[n++], v1); - copy_v3_v3(buffer[n++], v2); - - break; - case 2: /* z axis */ - line_type = GL_LINE_STRIP; - - /* start at top left */ - negate_v3_v3(v1, dx); - add_v3_v3(v1, dy); - - copy_v3_v3(buffer[n++], v1); - - mul_v3_fl(dx, 2.0f); - add_v3_v3(v1, dx); - - copy_v3_v3(buffer[n++], v1); - - mul_v3_fl(dy, 2.0f); - sub_v3_v3(v1, dx); - sub_v3_v3(v1, dy); - - copy_v3_v3(buffer[n++], v1); - - add_v3_v3(v1, dx); - - copy_v3_v3(buffer[n++], v1); - - break; - default: - BLI_assert(0); - return; - } - - for (int i = 0; i < n; i++) { - mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]); - add_v3_v3(buffer[i], c); - } - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, buffer); - glDrawArrays(line_type, 0, n); - glDisableClientState(GL_VERTEX_ARRAY); -} - -void drawaxes(const float viewmat_local[4][4], float size, char drawtype) -{ - int axis; - float v1[3] = {0.0, 0.0, 0.0}; - float v2[3] = {0.0, 0.0, 0.0}; - float v3[3] = {0.0, 0.0, 0.0}; - - glLineWidth(1); - - switch (drawtype) { - - case OB_PLAINAXES: - for (axis = 0; axis < 3; axis++) { - glBegin(GL_LINES); - - v1[axis] = size; - v2[axis] = -size; - glVertex3fv(v1); - glVertex3fv(v2); - - /* reset v1 & v2 to zero */ - v1[axis] = v2[axis] = 0.0f; - - glEnd(); - } - break; - case OB_SINGLE_ARROW: - - glBegin(GL_LINES); - /* in positive z direction only */ - v1[2] = size; - glVertex3fv(v1); - glVertex3fv(v2); - glEnd(); - - /* square pyramid */ - glBegin(GL_TRIANGLES); - - v2[0] = size * 0.035f; v2[1] = size * 0.035f; - v3[0] = size * -0.035f; v3[1] = size * 0.035f; - v2[2] = v3[2] = size * 0.75f; - - for (axis = 0; axis < 4; axis++) { - if (axis % 2 == 1) { - v2[0] = -v2[0]; - v3[1] = -v3[1]; - } - else { - v2[1] = -v2[1]; - v3[0] = -v3[0]; - } - - glVertex3fv(v1); - glVertex3fv(v2); - glVertex3fv(v3); - - } - glEnd(); - - break; - case OB_CUBE: - drawcube_size(size); - break; - - case OB_CIRCLE: - drawcircle_size(size); - break; - - case OB_EMPTY_SPHERE: - draw_empty_sphere(size); - break; - - case OB_EMPTY_CONE: - draw_empty_cone(size); - break; - - case OB_ARROWS: - default: - { - float viewmat_local_unit[3][3]; - - copy_m3_m4(viewmat_local_unit, (float (*)[4])viewmat_local); - normalize_m3(viewmat_local_unit); - - for (axis = 0; axis < 3; axis++) { - const int arrow_axis = (axis == 0) ? 1 : 0; - - glBegin(GL_LINES); - - v2[axis] = size; - glVertex3fv(v1); - glVertex3fv(v2); - - v1[axis] = size * 0.85f; - v1[arrow_axis] = -size * 0.08f; - glVertex3fv(v1); - glVertex3fv(v2); - - v1[arrow_axis] = size * 0.08f; - glVertex3fv(v1); - glVertex3fv(v2); - - glEnd(); - - v2[axis] += size * 0.125f; - - draw_xyz_wire(viewmat_local_unit, v2, size, axis); - - - /* reset v1 & v2 to zero */ - v1[arrow_axis] = v1[axis] = v2[axis] = 0.0f; - } - break; - } - } -} - - -/* Function to draw an Image on an empty Object */ -static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], eStereoViews sview) -{ - Image *ima = ob->data; - ImBuf *ibuf; - ImageUser iuser = *ob->iuser; - - /* Support multi-view */ - if (ima && (sview == STEREO_RIGHT_ID)) { - iuser.multiview_eye = sview; - iuser.flag |= IMA_SHOW_STEREO; - BKE_image_multiview_index(ima, &iuser); - } - - ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); - - if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) { - IMB_rect_from_float(ibuf); - } - - int ima_x, ima_y; - - /* Get the buffer dimensions so we can fallback to fake ones */ - if (ibuf && ibuf->rect) { - ima_x = ibuf->x; - ima_y = ibuf->y; - } - else { - ima_x = 1; - ima_y = 1; - } - - float sca_x = 1.0f; - float sca_y = 1.0f; - - /* Get the image aspect even if the buffer is invalid */ - if (ima) { - if (ima->aspx > ima->aspy) { - sca_y = ima->aspy / ima->aspx; - } - else if (ima->aspx < ima->aspy) { - sca_x = ima->aspx / ima->aspy; - } - } - - /* Calculate the scale center based on object's origin */ - float ofs_x = ob->ima_ofs[0] * ima_x; - float ofs_y = ob->ima_ofs[1] * ima_y; - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - - /* Calculate Image scale */ - float scale = ob->empty_drawsize / max_ff((float)ima_x * sca_x, (float)ima_y * sca_y); - - /* Set the object scale */ - glScalef(scale * sca_x, scale * sca_y, 1.0f); - - if (ibuf && ibuf->rect) { - const bool use_clip = (U.glalphaclip != 1.0f); - int zoomfilter = (U.gameflags & USER_DISABLE_MIPMAP) ? GL_NEAREST : GL_LINEAR; - /* Setup GL params */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - if (use_clip) { - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, U.glalphaclip); - } - - /* Use the object color and alpha */ - glColor4fv(ob->col); - - /* Draw the Image on the screen */ - glaDrawPixelsTex(ofs_x, ofs_y, ima_x, ima_y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect); - - glDisable(GL_BLEND); - - if (use_clip) { - glDisable(GL_ALPHA_TEST); - glAlphaFunc(GL_ALWAYS, 0.0f); - } - } - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(ob_wire_col); - } - - /* Calculate the outline vertex positions */ - glBegin(GL_LINE_LOOP); - glVertex2f(ofs_x, ofs_y); - glVertex2f(ofs_x + ima_x, ofs_y); - glVertex2f(ofs_x + ima_x, ofs_y + ima_y); - glVertex2f(ofs_x, ofs_y + ima_y); - glEnd(); - - /* Reset GL settings */ - glPopMatrix(); - - BKE_image_release_ibuf(ima, ibuf, NULL); -} - static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3], float rad, const float tmat[4][4]) { float vx[3], vy[3]; @@ -747,838 +176,17 @@ static void circball_array_fill(float verts[CIRCLE_RESOL][3], const float cent[3 } } -void drawcircball(int mode, const float cent[3], float rad, const float tmat[4][4]) +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned pos) { float verts[CIRCLE_RESOL][3]; circball_array_fill(verts, cent, rad, tmat); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, verts); - glDrawArrays(mode, 0, CIRCLE_RESOL); - glDisableClientState(GL_VERTEX_ARRAY); -} - -/* circle for object centers, special_color is for library or ob users */ -static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color) -{ - const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f; - float verts[CIRCLE_RESOL][3]; - - /* using glDepthFunc guarantees that it does write z values, - * but not checks for it, so centers remain visible independent of draw order */ - if (v3d->zbuf) glDepthFunc(GL_ALWAYS); - /* write to near buffer always */ - glDepthRange(0.0, 0.0); - glEnable(GL_BLEND); - - if (special_color) { - if (selstate == ACTIVE || selstate == SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155); - else glColor4ub(0x55, 0xCC, 0xCC, 155); - } - else { - if (selstate == ACTIVE) UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80); - else if (selstate == SELECT) UI_ThemeColorShadeAlpha(TH_SELECT, 0, -80); - else if (selstate == DESELECT) UI_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80); - } - - circball_array_fill(verts, co, size, rv3d->viewinv); - - /* enable vertex array */ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, verts); - - /* 1. draw filled, blended polygon */ - glDrawArrays(GL_POLYGON, 0, CIRCLE_RESOL); - - /* 2. draw outline */ - glLineWidth(1); - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -30); - glDrawArrays(GL_LINE_LOOP, 0, CIRCLE_RESOL); - - /* finish up */ - glDisableClientState(GL_VERTEX_ARRAY); - - glDepthRange(0.0, 1.0); - glDisable(GL_BLEND); - - if (v3d->zbuf) glDepthFunc(GL_LEQUAL); -} - -/* *********** text drawing for object/particles/armature ************* */ - -typedef struct ViewCachedString { - struct ViewCachedString *next; - float vec[3]; - union { - unsigned char ub[4]; - int pack; - } col; - short sco[2]; - short xoffs; - short flag; - int str_len; - - /* str is allocated past the end */ - char str[0]; -} ViewCachedString; - -/* one arena for all 3 string lists */ -static MemArena *g_v3d_strings_arena = NULL; -static ViewCachedString *g_v3d_strings[3] = {NULL, NULL, NULL}; -static int g_v3d_string_level = -1; - -void view3d_cached_text_draw_begin(void) -{ - g_v3d_string_level++; - - BLI_assert(g_v3d_string_level >= 0); - - if (g_v3d_string_level == 0) { - BLI_assert(g_v3d_strings_arena == NULL); - } -} - -void view3d_cached_text_draw_add(const float co[3], - const char *str, const size_t str_len, - short xoffs, short flag, - const unsigned char col[4]) -{ - int alloc_len = str_len + 1; - ViewCachedString *vos; - - BLI_assert(str_len == strlen(str)); - - if (g_v3d_strings_arena == NULL) { - g_v3d_strings_arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 14), __func__); - } - - vos = BLI_memarena_alloc(g_v3d_strings_arena, sizeof(ViewCachedString) + alloc_len); - - BLI_LINKS_PREPEND(g_v3d_strings[g_v3d_string_level], vos); - - copy_v3_v3(vos->vec, co); - copy_v4_v4_uchar(vos->col.ub, col); - vos->xoffs = xoffs; - vos->flag = flag; - vos->str_len = str_len; - - /* allocate past the end */ - memcpy(vos->str, str, alloc_len); -} - -void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write) -{ - RegionView3D *rv3d = ar->regiondata; - ViewCachedString *vos; - int tot = 0; - - BLI_assert(g_v3d_string_level >= 0 && g_v3d_string_level <= 2); - - /* project first and test */ - for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) { - if (ED_view3d_project_short_ex(ar, - (vos->flag & V3D_CACHE_TEXT_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob, - (vos->flag & V3D_CACHE_TEXT_LOCALCLIP) != 0, - vos->vec, vos->sco, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) - { - tot++; - } - else { - vos->sco[0] = IS_CLIPPED; - } - } - - if (tot) { - int col_pack_prev = 0; - -#if 0 - bglMats mats; /* ZBuffer depth vars */ - double ux, uy, uz; - float depth; - - if (v3d->zbuf) - bgl_get_mats(&mats); -#endif - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_disable(); - } - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - wmOrtho2_region_pixelspace(ar); - glLoadIdentity(); - - if (depth_write) { - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - } - else { - glDepthMask(0); - } - - for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) { - if (vos->sco[0] != IS_CLIPPED) { - if (col_pack_prev != vos->col.pack) { - glColor3ubv(vos->col.ub); - col_pack_prev = vos->col.pack; - } - - ((vos->flag & V3D_CACHE_TEXT_ASCII) ? BLF_draw_default_ascii : BLF_draw_default)( - (float)(vos->sco[0] + vos->xoffs), - (float)(vos->sco[1]), - (depth_write) ? 0.0f : 2.0f, - vos->str, - vos->str_len); - } - } - - if (depth_write) { - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - } - else { - glDepthMask(1); - } - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_enable(); - } - } - - g_v3d_strings[g_v3d_string_level] = NULL; - - if (g_v3d_string_level == 0) { - if (g_v3d_strings_arena) { - BLI_memarena_free(g_v3d_strings_arena); - g_v3d_strings_arena = NULL; - } - } - - g_v3d_string_level--; -} - -/* ******************** primitive drawing ******************* */ - -/* draws a cube given the scaling of the cube, assuming that - * all required matrices have been set (used for drawing empties) - */ -static void drawcube_size(float size) -{ - const GLfloat pos[8][3] = { - {-size, -size, -size}, - {-size, -size, size}, - {-size, size, -size}, - {-size, size, size}, - { size, -size, -size}, - { size, -size, size}, - { size, size, -size}, - { size, size, size} - }; - - const GLubyte indices[24] = {0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6}; - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, pos); - glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices); - glDisableClientState(GL_VERTEX_ARRAY); -} - -static void drawshadbuflimits(Lamp *la, float mat[4][4]) -{ - float sta[3], end[3], lavec[3]; - - negate_v3_v3(lavec, mat[2]); - normalize_v3(lavec); - - madd_v3_v3v3fl(sta, mat[3], lavec, la->clipsta); - madd_v3_v3v3fl(end, mat[3], lavec, la->clipend); - - glBegin(GL_LINES); - glVertex3fv(sta); - glVertex3fv(end); - glEnd(); - - glPointSize(3.0); - glBegin(GL_POINTS); - glVertex3fv(sta); - glVertex3fv(end); - glEnd(); -} - -static void spotvolume(float lvec[3], float vvec[3], const float inp) -{ - /* camera is at 0,0,0 */ - float temp[3], plane[3], mat1[3][3], mat2[3][3], mat3[3][3], mat4[3][3], q[4], co, si, angle; - - normalize_v3(lvec); - normalize_v3(vvec); /* is this the correct vector ? */ - - cross_v3_v3v3(temp, vvec, lvec); /* equation for a plane through vvec and lvec */ - cross_v3_v3v3(plane, lvec, temp); /* a plane perpendicular to this, parallel with lvec */ - - /* vectors are exactly aligned, use the X axis, this is arbitrary */ - if (normalize_v3(plane) == 0.0f) - plane[1] = 1.0f; - - /* now we've got two equations: one of a cone and one of a plane, but we have - * three unknowns. We remove one unknown by rotating the plane to z=0 (the plane normal) */ - - /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */ - /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/ - - /* translating this comment to english didnt really help me understanding the math! :-) (ton) */ - - q[1] = plane[1]; - q[2] = -plane[0]; - q[3] = 0; - normalize_v3(&q[1]); - - angle = saacos(plane[2]) / 2.0f; - co = cosf(angle); - si = sqrtf(1 - co * co); - - q[0] = co; - q[1] *= si; - q[2] *= si; - q[3] = 0; - - quat_to_mat3(mat1, q); - - /* rotate lamp vector now over acos(inp) degrees */ - copy_v3_v3(vvec, lvec); - - unit_m3(mat2); - co = inp; - si = sqrtf(1.0f - inp * inp); - - mat2[0][0] = co; - mat2[1][0] = -si; - mat2[0][1] = si; - mat2[1][1] = co; - mul_m3_m3m3(mat3, mat2, mat1); - - mat2[1][0] = si; - mat2[0][1] = -si; - mul_m3_m3m3(mat4, mat2, mat1); - transpose_m3(mat1); - - mul_m3_m3m3(mat2, mat1, mat3); - mul_m3_v3(mat2, lvec); - mul_m3_m3m3(mat2, mat1, mat4); - mul_m3_v3(mat2, vvec); -} - -static void draw_spot_cone(Lamp *la, float x, float z) -{ - z = fabsf(z); - - glBegin(GL_TRIANGLE_FAN); - glVertex3f(0.0f, 0.0f, -x); - - if (la->mode & LA_SQUARE) { - glVertex3f(z, z, 0); - glVertex3f(-z, z, 0); - glVertex3f(-z, -z, 0); - glVertex3f(z, -z, 0); - glVertex3f(z, z, 0); - } - else { - for (int a = 0; a < 33; a++) { - float angle = a * M_PI * 2 / (33 - 1); - glVertex3f(z * cosf(angle), z * sinf(angle), 0); - } - } - - glEnd(); -} - -static void draw_transp_spot_volume(Lamp *la, float x, float z) -{ - glEnable(GL_CULL_FACE); - glEnable(GL_BLEND); - glDepthMask(0); - - /* draw backside darkening */ - glCullFace(GL_FRONT); - - glBlendFunc(GL_ZERO, GL_SRC_ALPHA); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - - draw_spot_cone(la, x, z); - - /* draw front side lighting */ - glCullFace(GL_BACK); - - glBlendFunc(GL_ONE, GL_ONE); - glColor4f(0.2f, 0.2f, 0.2f, 1.0f); - - draw_spot_cone(la, x, z); - - /* restore state */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_BLEND); - glDepthMask(1); - glDisable(GL_CULL_FACE); - glCullFace(GL_BACK); -} - -#ifdef WITH_GAMEENGINE -static void draw_transp_sun_volume(Lamp *la) -{ - float box[8][3]; - - /* construct box */ - box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size; - box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size; - box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size; - box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size; - box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend; - box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta; - - /* draw edges */ - draw_box(box, false); - - /* draw faces */ - glEnable(GL_CULL_FACE); - glEnable(GL_BLEND); - glDepthMask(0); - - /* draw backside darkening */ - glCullFace(GL_FRONT); - - glBlendFunc(GL_ZERO, GL_SRC_ALPHA); - glColor4f(0.0f, 0.0f, 0.0f, 0.4f); - - draw_box(box, true); - - /* draw front side lighting */ - glCullFace(GL_BACK); - - glBlendFunc(GL_ONE, GL_ONE); - glColor4f(0.2f, 0.2f, 0.2f, 1.0f); - - draw_box(box, true); - - /* restore state */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_BLEND); - glDepthMask(1); - glDisable(GL_CULL_FACE); - glCullFace(GL_BACK); -} -#endif - -static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const short dflag, const unsigned char ob_wire_col[4], const bool is_obact) -{ - Object *ob = base->object; - const float pixsize = ED_view3d_pixel_size(rv3d, ob->obmat[3]); - Lamp *la = ob->data; - float vec[3], lvec[3], vvec[3], circrad; - float lampsize; - float imat[4][4]; - - unsigned char curcol[4]; - unsigned char col[4]; - /* cone can't be drawn for duplicated lamps, because duplilist would be freed */ - /* the moment of view3d_draw_transp() call */ - const bool is_view = (rv3d->persp == RV3D_CAMOB && v3d->camera == base->object); - const bool drawcone = ((dt > OB_WIRE) && - !(G.f & G_PICKSEL) && - (la->type == LA_SPOT) && - (la->mode & LA_SHOW_CONE) && - !(base->flag & OB_FROMDUPLI) && - !is_view); - -#ifdef WITH_GAMEENGINE - const bool drawshadowbox = ( - (rv3d->rflag & RV3D_IS_GAME_ENGINE) && - (dt > OB_WIRE) && - !(G.f & G_PICKSEL) && - (la->type == LA_SUN) && - ((la->mode & LA_SHAD_BUF) || - (la->mode & LA_SHAD_RAY)) && - (la->mode & LA_SHOW_SHADOW_BOX) && - !(base->flag & OB_FROMDUPLI) && - !is_view); -#else - const bool drawshadowbox = false; -#endif - - if ((drawcone || drawshadowbox) && !v3d->transp) { - /* in this case we need to draw delayed */ - ED_view3d_after_add(v3d->xray ? &v3d->afterdraw_xraytransp : &v3d->afterdraw_transp, base, dflag); - return; - } - - /* we first draw only the screen aligned & fixed scale stuff */ - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); - - /* lets calculate the scale: */ - lampsize = pixsize * ((float)U.obcenter_dia * 0.5f); - - /* and view aligned matrix: */ - copy_m4_m4(imat, rv3d->viewinv); - normalize_v3(imat[0]); - normalize_v3(imat[1]); - - /* lamp center */ - copy_v3_v3(vec, ob->obmat[3]); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - /* for AA effects */ - curcol[0] = ob_wire_col[0]; - curcol[1] = ob_wire_col[1]; - curcol[2] = ob_wire_col[2]; - curcol[3] = 154; - glColor4ubv(curcol); - } - - glLineWidth(1); - - if (lampsize > 0.0f) { - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (ob->id.us > 1) { - if (is_obact || (ob->flag & SELECT)) { - glColor4ub(0x88, 0xFF, 0xFF, 155); - } - else { - glColor4ub(0x77, 0xCC, 0xCC, 155); - } - } - } - - /* Inner Circle */ - glEnable(GL_BLEND); - drawcircball(GL_LINE_LOOP, vec, lampsize, imat); - glDisable(GL_BLEND); - drawcircball(GL_POLYGON, vec, lampsize, imat); - - /* restore */ - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (ob->id.us > 1) - glColor4ubv(curcol); - } - - /* Outer circle */ - circrad = 3.0f * lampsize; - setlinestyle(3); - - drawcircball(GL_LINE_LOOP, vec, circrad, imat); - - /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */ - if (la->type != LA_HEMI) { - if ((la->mode & LA_SHAD_RAY) || ((la->mode & LA_SHAD_BUF) && (la->type == LA_SPOT))) { - drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f * pixsize, imat); - } - } + immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL); + for (int i = 0; i < CIRCLE_RESOL; ++i) { + immVertex3fv(pos, verts[i]); } - else { - setlinestyle(3); - circrad = 0.0f; - } - - /* draw the pretty sun rays */ - if (la->type == LA_SUN) { - float v1[3], v2[3], mat[3][3]; - short axis; - - /* setup a 45 degree rotation matrix */ - axis_angle_normalized_to_mat3_ex(mat, imat[2], M_SQRT1_2, M_SQRT1_2); - - /* vectors */ - mul_v3_v3fl(v1, imat[0], circrad * 1.2f); - mul_v3_v3fl(v2, imat[0], circrad * 2.5f); - - /* center */ - glTranslate3fv(vec); - - setlinestyle(3); - - glBegin(GL_LINES); - for (axis = 0; axis < 8; axis++) { - glVertex3fv(v1); - glVertex3fv(v2); - mul_m3_v3(mat, v1); - mul_m3_v3(mat, v2); - } - glEnd(); - - glTranslatef(-vec[0], -vec[1], -vec[2]); - - } - - if (la->type == LA_LOCAL) { - if (la->mode & LA_SPHERE) { - drawcircball(GL_LINE_LOOP, vec, la->dist, imat); - } - } - - glPopMatrix(); /* back in object space */ - zero_v3(vec); - - if (is_view) { - /* skip drawing extra info */ - } - else if (la->type == LA_SPOT) { - float x, y, z, z_abs; - copy_v3_fl3(lvec, 0.0f, 0.0f, 1.0f); - copy_v3_fl3(vvec, rv3d->persmat[0][2], rv3d->persmat[1][2], rv3d->persmat[2][2]); - mul_transposed_mat3_m4_v3(ob->obmat, vvec); - - x = -la->dist; - y = cosf(la->spotsize * 0.5f); - z = x * sqrtf(1.0f - y * y); - - spotvolume(lvec, vvec, y); - mul_v3_fl(lvec, x); - mul_v3_fl(vvec, x); - - x *= y; - - z_abs = fabsf(z); - - if (la->mode & LA_SQUARE) { - /* draw pyramid */ - const float vertices[5][3] = { - /* 5 of vertex coords of pyramid */ - {0.0f, 0.0f, 0.0f}, - {z_abs, z_abs, x}, - {-z_abs, -z_abs, x}, - {z_abs, -z_abs, x}, - {-z_abs, z_abs, x}, - }; - const unsigned char indices[] = { - 0, 1, 3, - 0, 3, 2, - 0, 2, 4, - 0, 1, 4, - }; - - /* Draw call: - * activate and specify pointer to vertex array */ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vertices); - /* draw the pyramid */ - glDrawElements(GL_LINE_STRIP, 12, GL_UNSIGNED_BYTE, indices); - - /* deactivate vertex arrays after drawing */ - glDisableClientState(GL_VERTEX_ARRAY); - - glTranslatef(0.0f, 0.0f, x); - - /* draw the square representing spotbl */ - if (la->type == LA_SPOT) { - float blend = z_abs * (1.0f - pow2f(la->spotblend)); - - /* hide line if it is zero size or overlaps with outer border, - * previously it adjusted to always to show it but that seems - * confusing because it doesn't show the actual blend size */ - if (blend != 0.0f && blend != z_abs) { - fdrawbox(blend, -blend, -blend, blend); - } - } - } - else { - - /* draw the angled sides of the cone */ - glBegin(GL_LINE_STRIP); - glVertex3fv(vvec); - glVertex3fv(vec); - glVertex3fv(lvec); - glEnd(); - - /* draw the circle at the end of the cone */ - glTranslatef(0.0f, 0.0f, x); - circ(0.0f, 0.0f, z_abs); - - /* draw the circle representing spotbl */ - if (la->type == LA_SPOT) { - float blend = z_abs * (1.0f - pow2f(la->spotblend)); - - /* hide line if it is zero size or overlaps with outer border, - * previously it adjusted to always to show it but that seems - * confusing because it doesn't show the actual blend size */ - if (blend != 0.0f && blend != z_abs) { - circ(0.0f, 0.0f, blend); - } - } - } - - if (drawcone) - draw_transp_spot_volume(la, x, z); - - /* draw clip start, useful for wide cones where its not obvious where the start is */ - glTranslatef(0.0, 0.0, -x); /* reverse translation above */ - glBegin(GL_LINES); - if (la->type == LA_SPOT && (la->mode & LA_SHAD_BUF)) { - float lvec_clip[3]; - float vvec_clip[3]; - float clipsta_fac = la->clipsta / -x; - - interp_v3_v3v3(lvec_clip, vec, lvec, clipsta_fac); - interp_v3_v3v3(vvec_clip, vec, vvec, clipsta_fac); - - glVertex3fv(lvec_clip); - glVertex3fv(vvec_clip); - } - /* Else, draw spot direction (using distance as end limit, same as for Area lamp). */ - else { - glVertex3f(0.0, 0.0, -circrad); - glVertex3f(0.0, 0.0, -la->dist); - } - glEnd(); - } - else if (ELEM(la->type, LA_HEMI, LA_SUN)) { - - /* draw the line from the circle along the dist */ - glBegin(GL_LINES); - vec[2] = -circrad; - glVertex3fv(vec); - vec[2] = -la->dist; - glVertex3fv(vec); - glEnd(); - - if (la->type == LA_HEMI) { - /* draw the hemisphere curves */ - short axis, steps, dir; - float outdist, zdist, mul; - zero_v3(vec); - outdist = 0.14; mul = 1.4; dir = 1; - - setlinestyle(4); - /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */ - for (axis = 0; axis < 4; axis++) { - float v[3] = {0.0, 0.0, 0.0}; - zdist = 0.02; - - glBegin(GL_LINE_STRIP); - - for (steps = 0; steps < 6; steps++) { - if (axis == 0 || axis == 1) { /* x axis up, x axis down */ - /* make the arcs start at the edge of the energy circle */ - if (steps == 0) v[0] = dir * circrad; - else v[0] = v[0] + dir * (steps * outdist); - } - else if (axis == 2 || axis == 3) { /* y axis up, y axis down */ - /* make the arcs start at the edge of the energy circle */ - v[1] = (steps == 0) ? (dir * circrad) : (v[1] + dir * (steps * outdist)); - } - - v[2] = v[2] - steps * zdist; - - glVertex3fv(v); - - zdist = zdist * mul; - } - - glEnd(); - /* flip the direction */ - dir = -dir; - } - } - -#ifdef WITH_GAMEENGINE - if (drawshadowbox) { - draw_transp_sun_volume(la); - } -#endif - - } - else if (la->type == LA_AREA) { - setlinestyle(3); - if (la->area_shape == LA_AREA_SQUARE) - fdrawbox(-la->area_size * 0.5f, -la->area_size * 0.5f, la->area_size * 0.5f, la->area_size * 0.5f); - else if (la->area_shape == LA_AREA_RECT) - fdrawbox(-la->area_size * 0.5f, -la->area_sizey * 0.5f, la->area_size * 0.5f, la->area_sizey * 0.5f); - - glBegin(GL_LINES); - glVertex3f(0.0, 0.0, -circrad); - glVertex3f(0.0, 0.0, -la->dist); - glEnd(); - } - - /* and back to viewspace */ - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); - copy_v3_v3(vec, ob->obmat[3]); - - setlinestyle(0); - - if ((la->type == LA_SPOT) && (la->mode & LA_SHAD_BUF) && (is_view == false)) { - drawshadbuflimits(la, ob->obmat); - } - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - UI_GetThemeColor4ubv(TH_LAMP, col); - glColor4ubv(col); - } - - glEnable(GL_BLEND); - - if (vec[2] > 0) vec[2] -= circrad; - else vec[2] += circrad; - - glBegin(GL_LINES); - glVertex3fv(vec); - vec[2] = 0; - glVertex3fv(vec); - glEnd(); - - glPointSize(2.0); - glBegin(GL_POINTS); - glVertex3fv(vec); - glEnd(); - - glDisable(GL_BLEND); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - /* restore for drawing extra stuff */ - glColor3ubv(ob_wire_col); - } - /* and finally back to org object space! */ - glPopMatrix(); -} - -static void draw_limit_line(float sta, float end, const short dflag, const unsigned char col[3]) -{ - glBegin(GL_LINES); - glVertex3f(0.0, 0.0, -sta); - glVertex3f(0.0, 0.0, -end); - glEnd(); - - if (!(dflag & DRAW_PICKING)) { - glPointSize(3.0); - glBegin(GL_POINTS); - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(col); - } - glVertex3f(0.0, 0.0, -sta); - glVertex3f(0.0, 0.0, -end); - glEnd(); - } -} - - -/* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */ -/* qdn: now also enabled for Blender to set focus point for defocus composite node */ -static void draw_focus_cross(float dist, float size) -{ - glBegin(GL_LINES); - glVertex3f(-size, 0.0f, -dist); - glVertex3f(size, 0.0f, -dist); - glVertex3f(0.0f, -size, -dist); - glVertex3f(0.0f, size, -dist); - glEnd(); + immEnd(); } #ifdef VIEW3D_CAMERA_BORDER_HACK @@ -1586,6840 +194,132 @@ unsigned char view3d_camera_border_hack_col[3]; bool view3d_camera_border_hack_test = false; #endif -/* ****************** draw clip data *************** */ - -static void draw_bundle_sphere(void) -{ - static GLuint displist = 0; - - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_FILL); - gluSphere(qobj, 0.05, 8, 8); - gluDeleteQuadric(qobj); - - glEndList(); - } - - glCallList(displist); -} - -static void draw_viewport_object_reconstruction( - Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d, - MovieClip *clip, MovieTrackingObject *tracking_object, - const short dflag, const unsigned char ob_wire_col[4], - int *global_track_index, bool draw_selected) -{ - MovieTracking *tracking = &clip->tracking; - MovieTrackingTrack *track; - float mat[4][4], imat[4][4]; - unsigned char col_unsel[4], col_sel[4]; - int tracknr = *global_track_index; - ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object); - float camera_size[3]; - - UI_GetThemeColor4ubv(TH_TEXT, col_unsel); - UI_GetThemeColor4ubv(TH_SELECT, col_sel); - - BKE_tracking_get_camera_object_matrix(scene, base->object, mat); - - /* we're compensating camera size for bundles size, - * to make it so bundles are always displayed with the same size */ - copy_v3_v3(camera_size, base->object->size); - if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) - mul_v3_fl(camera_size, tracking_object->scale); - - glPushMatrix(); - - if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { - /* current ogl matrix is translated in camera space, bundles should - * be rendered in world space, so camera matrix should be "removed" - * from current ogl matrix */ - invert_m4_m4(imat, base->object->obmat); - - glMultMatrixf(imat); - glMultMatrixf(mat); - } - else { - float obmat[4][4]; - int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, scene->r.cfra); - - BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, obmat); - - invert_m4_m4(imat, obmat); - glMultMatrixf(imat); - } - - for (track = tracksbase->first; track; track = track->next) { - bool selected = TRACK_SELECTED(track); - - if (draw_selected && !selected) - continue; - - if ((track->flag & TRACK_HAS_BUNDLE) == 0) - continue; - - if (dflag & DRAW_PICKING) - GPU_select_load_id(base->selcol + (tracknr << 16)); - - glPushMatrix(); - glTranslate3fv(track->bundle_pos); - glScalef(v3d->bundle_size / 0.05f / camera_size[0], - v3d->bundle_size / 0.05f / camera_size[1], - v3d->bundle_size / 0.05f / camera_size[2]); - - const int v3d_drawtype = view3d_effective_drawtype(v3d); - if (v3d_drawtype == OB_WIRE) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) { - glColor3ubv(ob_wire_col); - } - else { - glColor3fv(track->color); - } - } - - drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype); - } - else if (v3d_drawtype > OB_WIRE) { - if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) { - /* selection outline */ - if (selected) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(ob_wire_col); - } - - glLineWidth(2.0f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - draw_bundle_sphere(); - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color); - else UI_ThemeColor(TH_BUNDLE_SOLID); - } - - draw_bundle_sphere(); - } - else { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (selected) { - glColor3ubv(ob_wire_col); - } - else { - if (track->flag & TRACK_CUSTOMCOLOR) glColor3fv(track->color); - else UI_ThemeColor(TH_WIRE); - } - } - - drawaxes(rv3d->viewmatob, 0.05f, v3d->bundle_drawtype); - } - } - - glPopMatrix(); - - if ((dflag & DRAW_PICKING) == 0 && (v3d->flag2 & V3D_SHOW_BUNDLENAME)) { - float pos[3]; - - mul_v3_m4v3(pos, mat, track->bundle_pos); - view3d_cached_text_draw_add(pos, - track->name, strlen(track->name), - 10, V3D_CACHE_TEXT_GLOBALSPACE, - selected ? col_sel : col_unsel); - } - - tracknr++; - } - - if ((dflag & DRAW_PICKING) == 0) { - if ((v3d->flag2 & V3D_SHOW_CAMERAPATH) && (tracking_object->flag & TRACKING_OBJECT_CAMERA)) { - MovieTrackingReconstruction *reconstruction; - reconstruction = BKE_tracking_object_get_reconstruction(tracking, tracking_object); - - if (reconstruction->camnr) { - MovieReconstructedCamera *camera = reconstruction->cameras; - - UI_ThemeColor(TH_CAMERA_PATH); - glLineWidth(2.0f); - - glBegin(GL_LINE_STRIP); - for (int a = 0; a < reconstruction->camnr; a++, camera++) { - glVertex3fv(camera->mat[3]); - } - glEnd(); - } - } - } - - glPopMatrix(); - - *global_track_index = tracknr; -} - -static void draw_viewport_reconstruction( - Scene *scene, Base *base, const View3D *v3d, const RegionView3D *rv3d, MovieClip *clip, - const short dflag, const unsigned char ob_wire_col[4], - const bool draw_selected) -{ - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *tracking_object; - int global_track_index = 1; - - if ((v3d->flag2 & V3D_SHOW_RECONSTRUCTION) == 0) - return; - - if (v3d->flag2 & V3D_RENDER_OVERRIDE) - return; - - GPU_basic_shader_colors(NULL, NULL, 0, 1.0f); - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - - tracking_object = tracking->objects.first; - while (tracking_object) { - draw_viewport_object_reconstruction( - scene, base, v3d, rv3d, clip, tracking_object, - dflag, ob_wire_col, &global_track_index, draw_selected); - - tracking_object = tracking_object->next; - } - - /* restore */ - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(ob_wire_col); - } - - if (dflag & DRAW_PICKING) - GPU_select_load_id(base->selcol); -} - -static void drawcamera_volume(float near_plane[4][3], float far_plane[4][3], const GLenum mode) -{ - glBegin(mode); - glVertex3fv(near_plane[0]); - glVertex3fv(far_plane[0]); - glVertex3fv(far_plane[1]); - glVertex3fv(near_plane[1]); - glEnd(); - - glBegin(mode); - glVertex3fv(near_plane[1]); - glVertex3fv(far_plane[1]); - glVertex3fv(far_plane[2]); - glVertex3fv(near_plane[2]); - glEnd(); - - glBegin(mode); - glVertex3fv(near_plane[2]); - glVertex3fv(far_plane[2]); - glVertex3fv(far_plane[3]); - glVertex3fv(near_plane[3]); - glEnd(); - - glBegin(mode); - glVertex3fv(far_plane[3]); - glVertex3fv(near_plane[3]); - glVertex3fv(near_plane[0]); - glVertex3fv(far_plane[0]); - glEnd(); -} - -/* camera frame */ -static void drawcamera_frame(float vec[4][3], const GLenum mode) -{ - glBegin(mode); - glVertex3fv(vec[0]); - glVertex3fv(vec[1]); - glVertex3fv(vec[2]); - glVertex3fv(vec[3]); - glEnd(); -} - -/* center point to camera frame */ -static void drawcamera_framelines(float vec[4][3], float origin[3]) -{ - glBegin(GL_LINE_STRIP); - glVertex3fv(vec[1]); - glVertex3fv(origin); - glVertex3fv(vec[0]); - glVertex3fv(vec[3]); - glVertex3fv(origin); - glVertex3fv(vec[2]); - glEnd(); -} - -static bool drawcamera_is_stereo3d(Scene *scene, View3D *v3d, Object *ob) -{ - return (ob == v3d->camera) && - (scene->r.scemode & R_MULTIVIEW) != 0 && - (v3d->stereo3d_flag); -} - -static void drawcamera_stereo3d( - Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const Camera *cam, - float vec[4][3], float drawsize, const float scale[3]) -{ - float obmat[4][4]; - float vec_lr[2][4][3]; - const float fac = (cam->stereo.pivot == CAM_S3D_PIVOT_CENTER) ? 2.0f : 1.0f; - float origin[2][3] = {{0}}; - float tvec[3]; - const Camera *cam_lr[2]; - const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - - const bool is_stereo3d_cameras = (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D); - const bool is_stereo3d_plane = (v3d->stereo3d_flag & V3D_S3D_DISPPLANE) && (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D); - const bool is_stereo3d_volume = (v3d->stereo3d_flag & V3D_S3D_DISPVOLUME); - - zero_v3(tvec); - - glPushMatrix(); - - for (int i = 0; i < 2; i++) { - ob = BKE_camera_multiview_render(scene, ob, names[i]); - cam_lr[i] = ob->data; - - glLoadMatrixf(rv3d->viewmat); - BKE_camera_multiview_model_matrix(&scene->r, ob, names[i], obmat); - glMultMatrixf(obmat); - - copy_m3_m3(vec_lr[i], vec); - copy_v3_v3(vec_lr[i][3], vec[3]); - - if (cam->stereo.convergence_mode == CAM_S3D_OFFAXIS) { - const float shift_x = - ((BKE_camera_multiview_shift_x(&scene->r, ob, names[i]) - cam->shiftx) * - (drawsize * scale[0] * fac)); - - for (int j = 0; j < 4; j++) { - vec_lr[i][j][0] += shift_x; - } - } - - if (is_stereo3d_cameras) { - /* camera frame */ - drawcamera_frame(vec_lr[i], GL_LINE_LOOP); - - /* center point to camera frame */ - drawcamera_framelines(vec_lr[i], tvec); - } - - /* connecting line */ - mul_m4_v3(obmat, origin[i]); - - /* convergence plane */ - if (is_stereo3d_plane || is_stereo3d_volume) { - for (int j = 0; j < 4; j++) { - mul_m4_v3(obmat, vec_lr[i][j]); - } - } - } - - - /* the remaining drawing takes place in the view space */ - glLoadMatrixf(rv3d->viewmat); - - if (is_stereo3d_cameras) { - /* draw connecting lines */ - GPU_basic_shader_bind_enable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - GPU_basic_shader_line_stipple(2, 0xAAAA); - - glBegin(GL_LINES); - glVertex3fv(origin[0]); - glVertex3fv(origin[1]); - glEnd(); - - GPU_basic_shader_bind_disable(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - } - - /* draw convergence plane */ - if (is_stereo3d_plane) { - float axis_center[3], screen_center[3]; - float world_plane[4][3]; - float local_plane[4][3]; - float offset; - - mid_v3_v3v3(axis_center, origin[0], origin[1]); - - for (int i = 0; i < 4; i++) { - mid_v3_v3v3(world_plane[i], vec_lr[0][i], vec_lr[1][i]); - sub_v3_v3v3(local_plane[i], world_plane[i], axis_center); - } - - mid_v3_v3v3(screen_center, world_plane[0], world_plane[2]); - offset = cam->stereo.convergence_distance / len_v3v3(screen_center, axis_center); - - for (int i = 0; i < 4; i++) { - mul_v3_fl(local_plane[i], offset); - add_v3_v3(local_plane[i], axis_center); - } - - glColor3f(0.0f, 0.0f, 0.0f); - - /* camera frame */ - drawcamera_frame(local_plane, GL_LINE_LOOP); - - if (v3d->stereo3d_convergence_alpha > 0.0f) { - glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ - - glColor4f(0.0f, 0.0f, 0.0f, v3d->stereo3d_convergence_alpha); - - drawcamera_frame(local_plane, GL_QUADS); - - glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ - } - } - - /* draw convergence plane */ - if (is_stereo3d_volume) { - float screen_center[3]; - float near_plane[4][3], far_plane[4][3]; - - for (int i = 0; i < 2; i++) { - mid_v3_v3v3(screen_center, vec_lr[i][0], vec_lr[i][2]); - - float offset = len_v3v3(screen_center, origin[i]); - - for (int j = 0; j < 4; j++) { - sub_v3_v3v3(near_plane[j], vec_lr[i][j], origin[i]); - mul_v3_fl(near_plane[j], cam_lr[i]->clipsta / offset); - add_v3_v3(near_plane[j], origin[i]); - - sub_v3_v3v3(far_plane[j], vec_lr[i][j], origin[i]); - mul_v3_fl(far_plane[j], cam_lr[i]->clipend / offset); - add_v3_v3(far_plane[j], origin[i]); - } - - /* camera frame */ - glColor3f(0.0f, 0.0f, 0.0f); - - drawcamera_frame(near_plane, GL_LINE_LOOP); - drawcamera_frame(far_plane, GL_LINE_LOOP); - drawcamera_volume(near_plane, far_plane, GL_LINE_LOOP); - - if (v3d->stereo3d_volume_alpha > 0.0f) { - glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ - - if (i == 0) - glColor4f(0.0f, 1.0f, 1.0f, v3d->stereo3d_volume_alpha); - else - glColor4f(1.0f, 0.0f, 0.0f, v3d->stereo3d_volume_alpha); - - drawcamera_frame(near_plane, GL_QUADS); - drawcamera_frame(far_plane, GL_QUADS); - drawcamera_volume(near_plane, far_plane, GL_QUADS); - - glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ - } - } - } - - glPopMatrix(); -} - -/* flag similar to draw_object() */ -static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, - const short dflag, const unsigned char ob_wire_col[4]) -{ - /* a standing up pyramid with (0,0,0) as top */ - Camera *cam; - Object *ob = base->object; - float tvec[3]; - float vec[4][3], asp[2], shift[2], scale[3]; - MovieClip *clip = BKE_object_movieclip_get(scene, base->object, false); - - const bool is_active = (ob == v3d->camera); - const bool is_view = (rv3d->persp == RV3D_CAMOB && is_active); - const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0; - const bool is_stereo3d = drawcamera_is_stereo3d(scene, v3d, ob); - const bool is_stereo3d_view = (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D); - const bool is_stereo3d_cameras = (ob == scene->camera) && - is_multiview && - is_stereo3d_view && - (v3d->stereo3d_flag & V3D_S3D_DISPCAMERAS); - const bool is_selection_camera_stereo = (G.f & G_PICKSEL) && - is_view && is_multiview && - is_stereo3d_view; - - /* draw data for movie clip set as active for scene */ - if (clip) { - draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, false); - draw_viewport_reconstruction(scene, base, v3d, rv3d, clip, dflag, ob_wire_col, true); - } - -#ifdef VIEW3D_CAMERA_BORDER_HACK - if (is_view && !(G.f & G_PICKSEL)) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - view3d_camera_border_hack_col[0] = ob_wire_col[0]; - view3d_camera_border_hack_col[1] = ob_wire_col[1]; - view3d_camera_border_hack_col[2] = ob_wire_col[2]; - } - else { - float col[4]; - glGetFloatv(GL_CURRENT_COLOR, col); - rgb_float_to_uchar(view3d_camera_border_hack_col, col); - } - view3d_camera_border_hack_test = true; - return; - } -#endif - - cam = ob->data; - - /* BKE_camera_multiview_model_matrix already accounts for scale, don't do it here */ - if (is_selection_camera_stereo) { - scale[0] = 1.0f; - scale[1] = 1.0f; - scale[2] = 1.0f; - } - else { - scale[0] = 1.0f / len_v3(ob->obmat[0]); - scale[1] = 1.0f / len_v3(ob->obmat[1]); - scale[2] = 1.0f / len_v3(ob->obmat[2]); - } - - float drawsize; - BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale, - asp, shift, &drawsize, vec); - - glDisable(GL_CULL_FACE); - glLineWidth(1); - - /* camera frame */ - if (!is_stereo3d_cameras) { - /* make sure selection uses the same matrix for camera as the one used while viewing */ - if (is_selection_camera_stereo) { - float obmat[4][4]; - bool is_left = v3d->multiview_eye == STEREO_LEFT_ID; - - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); - BKE_camera_multiview_model_matrix(&scene->r, ob, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, obmat); - glMultMatrixf(obmat); - - drawcamera_frame(vec, GL_LINE_LOOP); - glPopMatrix(); - } - else { - drawcamera_frame(vec, GL_LINE_LOOP); - } - } - - if (is_view) - return; - - zero_v3(tvec); - - /* center point to camera frame */ - if (!is_stereo3d_cameras) - drawcamera_framelines(vec, tvec); - - /* arrow on top */ - tvec[2] = vec[1][2]; /* copy the depth */ - - /* draw an outline arrow for inactive cameras and filled - * for active cameras. We actually draw both outline+filled - * for active cameras so the wire can be seen side-on */ - for (int i = 0; i < 2; i++) { - if (i == 0) glBegin(GL_LINE_LOOP); - else if (i == 1 && is_active) glBegin(GL_TRIANGLES); - else break; - - tvec[0] = shift[0] + ((-0.7f * drawsize) * scale[0]); - tvec[1] = shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]); - glVertex3fv(tvec); /* left */ - - tvec[0] = shift[0] + ((0.7f * drawsize) * scale[0]); - glVertex3fv(tvec); /* right */ - - tvec[0] = shift[0]; - tvec[1] = shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]); - glVertex3fv(tvec); /* top */ - - glEnd(); - } - - if ((dflag & DRAW_SCENESET) == 0) { - if (cam->flag & (CAM_SHOWLIMITS | CAM_SHOWMIST)) { - float nobmat[4][4]; - - /* draw in normalized object matrix space */ - copy_m4_m4(nobmat, ob->obmat); - normalize_m4(nobmat); - - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); - glMultMatrixf(nobmat); - - if (cam->flag & CAM_SHOWLIMITS) { - const unsigned char col[3] = {128, 128, 60}, col_hi[3] = {255, 255, 120}; - - draw_limit_line(cam->clipsta, cam->clipend, dflag, (is_active ? col_hi : col)); - /* qdn: was yafray only, now also enabled for Blender to be used with defocus composite node */ - draw_focus_cross(BKE_camera_object_dof_distance(ob), cam->drawsize); - } - - if (cam->flag & CAM_SHOWMIST) { - World *world = scene->world; - const unsigned char col[3] = {128, 128, 128}, col_hi[3] = {255, 255, 255}; - - if (world) { - draw_limit_line(world->miststa, world->miststa + world->mistdist, - dflag, (is_active ? col_hi : col)); - } - } - glPopMatrix(); - } - } - - /* stereo cameras drawing */ - if (is_stereo3d) { - drawcamera_stereo3d(scene, v3d, rv3d, ob, cam, vec, drawsize, scale); - } -} - -/* flag similar to draw_object() */ -static void drawspeaker(Scene *UNUSED(scene), View3D *UNUSED(v3d), RegionView3D *UNUSED(rv3d), - Object *UNUSED(ob), int UNUSED(flag)) -{ - float vec[3]; - - glEnable(GL_BLEND); - glLineWidth(1); - - for (int j = 0; j < 3; j++) { - vec[2] = 0.25f * j - 0.125f; - - glBegin(GL_LINE_LOOP); - for (int i = 0; i < 16; i++) { - vec[0] = cosf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); - vec[1] = sinf((float)M_PI * i / 8.0f) * (j == 0 ? 0.5f : 0.25f); - glVertex3fv(vec); - } - glEnd(); - } - - for (int j = 0; j < 4; j++) { - vec[0] = (((j + 1) % 2) * (j - 1)) * 0.5f; - vec[1] = ((j % 2) * (j - 2)) * 0.5f; - glBegin(GL_LINE_STRIP); - for (int i = 0; i < 3; i++) { - if (i == 1) { - vec[0] *= 0.5f; - vec[1] *= 0.5f; - } - - vec[2] = 0.25f * i - 0.125f; - glVertex3fv(vec); - } - glEnd(); - } - - glDisable(GL_BLEND); -} - -static void lattice_draw_verts(Lattice *lt, DispList *dl, BPoint *actbp, short sel) -{ - BPoint *bp = lt->def; - const float *co = dl ? dl->verts : NULL; - - const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX; - UI_ThemeColor(color); - - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - glBegin(GL_POINTS); - - for (int w = 0; w < lt->pntsw; w++) { - int wxt = (w == 0 || w == lt->pntsw - 1); - for (int v = 0; v < lt->pntsv; v++) { - int vxt = (v == 0 || v == lt->pntsv - 1); - for (int u = 0; u < lt->pntsu; u++, bp++, co += 3) { - int uxt = (u == 0 || u == lt->pntsu - 1); - if (!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) { - if (bp->hide == 0) { - /* check for active BPoint and ensure selected */ - if ((bp == actbp) && (bp->f1 & SELECT)) { - UI_ThemeColor(TH_ACTIVE_VERT); - glVertex3fv(dl ? co : bp->vec); - UI_ThemeColor(color); - } - else if ((bp->f1 & SELECT) == sel) { - glVertex3fv(dl ? co : bp->vec); - } - } - } - } - } - } - - glEnd(); -} - -static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int actdef_wcol) -{ - int index = ((w * lt->pntsv + v) * lt->pntsu) + u; - - if (actdef_wcol) { - float col[3]; - MDeformWeight *mdw = defvert_find_index(lt->dvert + index, actdef_wcol - 1); - - weight_to_rgb(col, mdw ? mdw->weight : 0.0f); - glColor3fv(col); - - } - - if (dl) { - glVertex3fv(&dl->verts[index * 3]); - } - else { - glVertex3fv(lt->def[index].vec); - } -} - -#ifdef SEQUENCER_DAG_WORKAROUND -static void ensure_curve_cache(Main *bmain, Scene *scene, Object *object) -{ - bool need_recalc = object->curve_cache == NULL; - /* Render thread might have freed the curve cache if the - * object is not visible. If the object is also used for - * particles duplication, then render thread might have - * also created curve_cache with only bevel and path - * filled in. - * - * So check for curve_cache != NULL is not fully correct - * here, we also need to check whether display list is - * empty or not. - * - * The trick below tries to optimize calls to displist - * creation for cases curve is empty. Meaning, if the curve - * is empty (without splines) bevel list would also be empty. - * And the thing is, render thread always leaves bevel list - * in a proper state. So if bevel list is here and display - * list is not we need to make display list. - */ - if (need_recalc == false) { - need_recalc = object->curve_cache->disp.first == NULL && - object->curve_cache->bev.first != NULL; - } - if (need_recalc) { - switch (object->type) { - case OB_CURVE: - case OB_SURF: - case OB_FONT: - BKE_displist_make_curveTypes(scene, object, false); - break; - case OB_MBALL: - BKE_displist_make_mball(bmain, bmain->eval_ctx, scene, object); - break; - case OB_LATTICE: - BKE_lattice_modifiers_calc(scene, object); - break; - } - } -} -#endif - -/* lattice color is hardcoded, now also shows weightgroup values in edit mode */ -static void drawlattice(View3D *v3d, Object *ob) -{ - Lattice *lt = ob->data; - DispList *dl; - int u, v, w; - int actdef_wcol = 0; - const bool is_edit = (lt->editlatt != NULL); - - dl = BKE_displist_find(&ob->curve_cache->disp, DL_VERTS); - - if (is_edit) { - lt = lt->editlatt->latt; - - UI_ThemeColor(TH_WIRE_EDIT); - - if (ob->defbase.first && lt->dvert) { - actdef_wcol = ob->actdef; - } - } - - glLineWidth(1); - glBegin(GL_LINES); - for (w = 0; w < lt->pntsw; w++) { - int wxt = (w == 0 || w == lt->pntsw - 1); - for (v = 0; v < lt->pntsv; v++) { - int vxt = (v == 0 || v == lt->pntsv - 1); - for (u = 0; u < lt->pntsu; u++) { - int uxt = (u == 0 || u == lt->pntsu - 1); - - if (w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) { - drawlattice__point(lt, dl, u, v, w - 1, actdef_wcol); - drawlattice__point(lt, dl, u, v, w, actdef_wcol); - } - if (v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) { - drawlattice__point(lt, dl, u, v - 1, w, actdef_wcol); - drawlattice__point(lt, dl, u, v, w, actdef_wcol); - } - if (u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) { - drawlattice__point(lt, dl, u - 1, v, w, actdef_wcol); - drawlattice__point(lt, dl, u, v, w, actdef_wcol); - } - } - } - } - glEnd(); - - if (is_edit) { - BPoint *actbp = BKE_lattice_active_point_get(lt); - - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - - lattice_draw_verts(lt, dl, actbp, 0); - lattice_draw_verts(lt, dl, actbp, 1); - - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - } -} - -/* ***************** ******************** */ - -/* draw callback */ - -typedef struct drawDMVertSel_userData { - MVert *mvert; - int active; - unsigned char *col[3]; /* (base, sel, act) */ - char sel_prev; -} drawDMVertSel_userData; - -static void drawSelectedVertices__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - drawDMVertSel_userData *data = userData; - MVert *mv = &data->mvert[index]; - - if (!(mv->flag & ME_HIDE)) { - const char sel = (index == data->active) ? 2 : (mv->flag & SELECT); - if (sel != data->sel_prev) { - glColor3ubv(data->col[sel]); - data->sel_prev = sel; - } - - glVertex3fv(co); - } -} - -static void drawSelectedVertices(DerivedMesh *dm, Mesh *me) -{ - drawDMVertSel_userData data; - - /* TODO define selected color */ - unsigned char base_col[3] = {0x0, 0x0, 0x0}; - unsigned char sel_col[3] = {0xd8, 0xb8, 0x0}; - unsigned char act_col[3] = {0xff, 0xff, 0xff}; - - data.mvert = me->mvert; - data.active = BKE_mesh_mselect_active_get(me, ME_VSEL); - data.sel_prev = 0xff; - - data.col[0] = base_col; - data.col[1] = sel_col; - data.col[2] = act_col; - - glBegin(GL_POINTS); - dm->foreachMappedVert(dm, drawSelectedVertices__mapFunc, &data, DM_FOREACH_NOP); - glEnd(); -} - -/* ************** DRAW MESH ****************** */ - -/* First section is all the "simple" draw routines, - * ones that just pass some sort of primitive to GL, - * with perhaps various options to control lighting, - * color, etc. - * - * These routines should not have user interface related - * logic!!! - */ - -static void calcDrawDMNormalScale(Object *ob, drawDMNormal_userData *data) -{ - float obmat[3][3]; - - copy_m3_m4(obmat, ob->obmat); - - data->uniform_scale = is_uniform_scaled_m3(obmat); - - if (!data->uniform_scale) { - /* inverted matrix */ - invert_m3_m3(data->imat, obmat); - - /* transposed inverted matrix */ - transpose_m3_m3(data->tmat, data->imat); - } -} - -static void draw_dm_face_normals__mapFunc(void *userData, int index, const float cent[3], const float no[3]) -{ - drawDMNormal_userData *data = userData; - BMFace *efa = BM_face_at_index(data->bm, index); - float n[3]; - - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - if (!data->uniform_scale) { - mul_v3_m3v3(n, data->tmat, no); - normalize_v3(n); - mul_m3_v3(data->imat, n); - } - else { - copy_v3_v3(n, no); - } - - glVertex3fv(cent); - glVertex3f(cent[0] + n[0] * data->normalsize, - cent[1] + n[1] * data->normalsize, - cent[2] + n[2] * data->normalsize); - } -} - -static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm) -{ - drawDMNormal_userData data; - - data.bm = em->bm; - data.normalsize = scene->toolsettings->normalsize; - - calcDrawDMNormalScale(ob, &data); - - glBegin(GL_LINES); - dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL); - glEnd(); -} - -static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3])) -{ - drawBMSelect_userData *data = userData; - BMFace *efa = BM_face_at_index(data->bm, index); - - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && - (BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select)) - { - glVertex3fv(cent); - } -} -static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select) -{ - drawBMSelect_userData data = {em->bm, select}; - - glBegin(GL_POINTS); - dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP); - glEnd(); -} - -static void draw_dm_vert_normals__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]) -{ - drawDMNormal_userData *data = userData; - BMVert *eve = BM_vert_at_index(data->bm, index); - - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - float no[3], n[3]; - - if (no_f) { - copy_v3_v3(no, no_f); - } - else { - normal_short_to_float_v3(no, no_s); - } - - if (!data->uniform_scale) { - mul_v3_m3v3(n, data->tmat, no); - normalize_v3(n); - mul_m3_v3(data->imat, n); - } - else { - copy_v3_v3(n, no); - } - - glVertex3fv(co); - glVertex3f(co[0] + n[0] * data->normalsize, - co[1] + n[1] * data->normalsize, - co[2] + n[2] * data->normalsize); - } -} - -static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm) -{ - drawDMNormal_userData data; - - data.bm = em->bm; - data.normalsize = scene->toolsettings->normalsize; - - calcDrawDMNormalScale(ob, &data); - - glBegin(GL_LINES); - dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL); - glEnd(); -} - -/* Draw verts with color set based on selection */ -static void draw_dm_verts__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - drawDMVerts_userData *data = userData; - BMVert *eve = BM_vert_at_index(data->bm, index); - - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT) == data->sel) { - /* skin nodes: draw a red circle around the root node(s) */ - if (data->cd_vskin_offset != -1) { - const MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, data->cd_vskin_offset); - if (vs->flag & MVERT_SKIN_ROOT) { - float radius = (vs->radius[0] + vs->radius[1]) * 0.5f; - glEnd(); - - glColor4ubv(data->th_skin_root); - drawcircball(GL_LINES, co, radius, data->imat); - - glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex); - glBegin(GL_POINTS); - } - } - - /* draw active in a different color - no need to stop/start point drawing for this :D */ - if (eve == data->eve_act) { - glColor4ubv(data->th_editmesh_active); - glVertex3fv(co); - - /* back to regular vertex color */ - glColor4ubv(data->sel ? data->th_vertex_select : data->th_vertex); - } - else { - glVertex3fv(co); - } - } -} - -static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, const char sel, BMVert *eve_act, - RegionView3D *rv3d) -{ - drawDMVerts_userData data; - data.sel = sel; - data.eve_act = eve_act; - data.bm = em->bm; - - /* Cache theme values */ - UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, data.th_editmesh_active); - UI_GetThemeColor4ubv(TH_VERTEX_SELECT, data.th_vertex_select); - UI_GetThemeColor4ubv(TH_VERTEX, data.th_vertex); - UI_GetThemeColor4ubv(TH_SKIN_ROOT, data.th_skin_root); - - /* For skin root drawing */ - data.cd_vskin_offset = CustomData_get_offset(&em->bm->vdata, CD_MVERT_SKIN); - /* view-aligned matrix */ - mul_m4_m4m4(data.imat, rv3d->viewmat, em->ob->obmat); - invert_m4(data.imat); - - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - glBegin(GL_POINTS); - dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data, DM_FOREACH_NOP); - glEnd(); -} - -/* Draw edges with color set based on selection */ -static DMDrawOption draw_dm_edges_sel__setDrawOptions(void *userData, int index) -{ - BMEdge *eed; - drawDMEdgesSel_userData *data = userData; - unsigned char *col; - - eed = BM_edge_at_index(data->bm, index); - - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - if (eed == data->eed_act) { - glColor4ubv(data->actCol); - } - else { - if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - col = data->selCol; - } - else { - col = data->baseCol; - } - /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */ - if (col[3] == 0) - return DM_DRAW_OPTION_SKIP; - - glColor4ubv(col); - } - return DM_DRAW_OPTION_NORMAL; - } - else { - return DM_DRAW_OPTION_SKIP; - } -} - -static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, - unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act) -{ - drawDMEdgesSel_userData data; - - data.baseCol = baseCol; - data.selCol = selCol; - data.actCol = actCol; - data.bm = em->bm; - data.eed_act = eed_act; - dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data); -} - -/* Draw edges */ -static DMDrawOption draw_dm_edges__setDrawOptions(void *userData, int index) -{ - if (BM_elem_flag_test(BM_edge_at_index(userData, index), BM_ELEM_HIDDEN)) - return DM_DRAW_OPTION_SKIP; - else - return DM_DRAW_OPTION_NORMAL; -} - -static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm) -{ - dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em->bm); -} - -/* Draw edges with color interpolated based on selection */ -static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index) -{ - drawDMEdgesSelInterp_userData *data = userData; - if (BM_elem_flag_test(BM_edge_at_index(data->bm, index), BM_ELEM_HIDDEN)) - return DM_DRAW_OPTION_SKIP; - else - return DM_DRAW_OPTION_NORMAL; -} -static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t) -{ - drawDMEdgesSelInterp_userData *data = userData; - BMEdge *eed = BM_edge_at_index(data->bm, index); - unsigned char **cols = userData; - unsigned int col0_id = (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1; - unsigned int col1_id = (BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1; - unsigned char *col0 = cols[col0_id]; - unsigned char *col1 = cols[col1_id]; - unsigned char *col_pt; - - if (col0_id == col1_id) { - col_pt = col0; - } - else if (t == 0.0f) { - col_pt = col0; - } - else if (t == 1.0f) { - col_pt = col1; - } - else { - unsigned char col_blend[4]; - interp_v4_v4v4_uchar(col_blend, col0, col1, t); - glColor4ubv(col_blend); - data->lastCol = NULL; - return; - } - - if (data->lastCol != col_pt) { - data->lastCol = col_pt; - glColor4ubv(col_pt); - } -} - -static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol) -{ - drawDMEdgesSelInterp_userData data; - data.bm = em->bm; - data.baseCol = baseCol; - data.selCol = selCol; - data.lastCol = NULL; - - dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, &data); -} - -static void bm_color_from_weight(float col[3], BMVert *vert, drawDMEdgesWeightInterp_userData *data) -{ - MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, data->cd_dvert_offset); - float weight = defvert_find_weight(dvert, data->vgroup_index); - - if ((weight == 0.0f) && - ((data->weight_user == OB_DRAW_GROUPUSER_ACTIVE) || - ((data->weight_user == OB_DRAW_GROUPUSER_ALL) && defvert_is_weight_zero(dvert, data->defgroup_tot)))) - { - copy_v3_v3(col, data->alert_color); - } - else { - weight_to_rgb(col, weight); - } -} - -static void draw_dm_edges_nop_interp__setDrawInterpOptions(void *UNUSED(userData), int UNUSED(index), float UNUSED(t)) -{ - /* pass */ -} - -static void draw_dm_edges_weight_interp__setDrawInterpOptions(void *userData, int index, float t) -{ - drawDMEdgesWeightInterp_userData *data = userData; - BMEdge *eed = BM_edge_at_index(data->bm, index); - float col[3]; - - if (t == 0.0f) { - bm_color_from_weight(col, eed->v1, data); - } - else if (t == 1.0f) { - bm_color_from_weight(col, eed->v2, data); - } - else { - float col_v1[3]; - float col_v2[3]; - - bm_color_from_weight(col_v1, eed->v1, data); - bm_color_from_weight(col_v2, eed->v2, data); - interp_v3_v3v3(col, col_v1, col_v2, t); - } - - glColor3fv(col); -} - -static void draw_dm_edges_weight_interp(BMEditMesh *em, DerivedMesh *dm, const char weight_user) -{ - drawDMEdgesWeightInterp_userData data; - Object *ob = em->ob; - - data.bm = em->bm; - data.cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); - data.defgroup_tot = BLI_listbase_count(&ob->defbase); - data.vgroup_index = ob->actdef - 1; - data.weight_user = weight_user; - UI_GetThemeColor3fv(TH_VERTEX_UNREFERENCED, data.alert_color); - - if ((data.vgroup_index != -1) && (data.cd_dvert_offset != -1)) { - glEnable(GL_BLEND); - dm->drawMappedEdgesInterp( - dm, - draw_dm_edges_sel_interp__setDrawOptions, - draw_dm_edges_weight_interp__setDrawInterpOptions, - &data); - glDisable(GL_BLEND); - } - else { - float col[3]; - - if (data.weight_user == OB_DRAW_GROUPUSER_NONE) { - weight_to_rgb(col, 0.0f); - } - else { - copy_v3_v3(col, data.alert_color); - } - glColor3fv(col); - - dm->drawMappedEdgesInterp( - dm, - draw_dm_edges_sel_interp__setDrawOptions, - draw_dm_edges_nop_interp__setDrawInterpOptions, - &data); - } - -} - -static bool draw_dm_edges_weight_check(Mesh *me, View3D *v3d) -{ - if (me->drawflag & ME_DRAWEIGHT) { - if ((v3d->drawtype == OB_WIRE) || - (v3d->flag2 & V3D_SOLID_MATCAP) || - ((v3d->flag2 & V3D_OCCLUDE_WIRE) && (v3d->drawtype > OB_WIRE))) - { - return true; - } - } - - return false; -} - -/* Draw only seam edges */ -static DMDrawOption draw_dm_edges_seams__setDrawOptions(void *userData, int index) -{ - BMEdge *eed = BM_edge_at_index(userData, index); - - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SEAM)) - return DM_DRAW_OPTION_NORMAL; - else - return DM_DRAW_OPTION_SKIP; -} - -static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm) -{ - dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em->bm); -} - -/* Draw only sharp edges */ -static DMDrawOption draw_dm_edges_sharp__setDrawOptions(void *userData, int index) -{ - BMEdge *eed = BM_edge_at_index(userData, index); - - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) - return DM_DRAW_OPTION_NORMAL; - else - return DM_DRAW_OPTION_SKIP; -} - -static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm) -{ - dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em->bm); -} - -#ifdef WITH_FREESTYLE - -static bool draw_dm_test_freestyle_edge_mark(BMesh *bm, BMEdge *eed) -{ - FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, eed->head.data, CD_FREESTYLE_EDGE); - if (!fed) - return false; - return (fed->flag & FREESTYLE_EDGE_MARK) != 0; -} - -/* Draw only Freestyle feature edges */ -static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index) -{ - BMEdge *eed = BM_edge_at_index(userData, index); - - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && draw_dm_test_freestyle_edge_mark(userData, eed)) - return DM_DRAW_OPTION_NORMAL; - else - return DM_DRAW_OPTION_SKIP; -} - -static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm) -{ - dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em->bm); -} - -static bool draw_dm_test_freestyle_face_mark(BMesh *bm, BMFace *efa) -{ - FreestyleFace *ffa = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_FREESTYLE_FACE); - if (!ffa) - return false; - return (ffa->flag & FREESTYLE_FACE_MARK) != 0; -} - -#endif - -/* Draw loop normals. */ -static void draw_dm_loop_normals__mapFunc(void *userData, int vertex_index, int face_index, - const float co[3], const float no[3]) -{ - if (no) { - const drawDMNormal_userData *data = userData; - const BMVert *eve = BM_vert_at_index(data->bm, vertex_index); - const BMFace *efa = BM_face_at_index(data->bm, face_index); - float vec[3]; - - if (!(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) || BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) { - if (!data->uniform_scale) { - mul_v3_m3v3(vec, (float(*)[3])data->tmat, no); - normalize_v3(vec); - mul_m3_v3((float(*)[3])data->imat, vec); - } - else { - copy_v3_v3(vec, no); - } - mul_v3_fl(vec, data->normalsize); - add_v3_v3(vec, co); - glVertex3fv(co); - glVertex3fv(vec); - } - } -} - -static void draw_dm_loop_normals(BMEditMesh *em, Scene *scene, Object *ob, DerivedMesh *dm) -{ - drawDMNormal_userData data; - - data.bm = em->bm; - data.normalsize = scene->toolsettings->normalsize; - - calcDrawDMNormalScale(ob, &data); - - glBegin(GL_LINES); - dm->foreachMappedLoop(dm, draw_dm_loop_normals__mapFunc, &data, DM_FOREACH_USE_NORMAL); - glEnd(); -} - -/* Draw faces with color set based on selection - * return 2 for the active face so it renders with stipple enabled */ -static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index) -{ - drawDMFacesSel_userData *data = userData; - BMFace *efa = BM_face_at_index(data->bm, index); - unsigned char *col; - - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - if (efa == data->efa_act) { - glColor4ubv(data->cols[2]); - return DM_DRAW_OPTION_STIPPLE; - } - else { -#ifdef WITH_FREESTYLE - col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0]; -#else - col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0]; -#endif - if (col[3] == 0) - return DM_DRAW_OPTION_SKIP; - glColor4ubv(col); - return DM_DRAW_OPTION_NORMAL; - } - } - return DM_DRAW_OPTION_SKIP; -} - -static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index) -{ - - drawDMFacesSel_userData *data = userData; - int i; - BMFace *efa; - BMFace *next_efa; - - unsigned char *col, *next_col; - - i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[index] : index; - efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL; - i = data->orig_index_mp_to_orig ? data->orig_index_mp_to_orig[next_index] : next_index; - next_efa = (i != ORIGINDEX_NONE) ? BM_face_at_index(data->bm, i) : NULL; - - if (ELEM(NULL, efa, next_efa)) - return 0; - - if (efa == next_efa) - return 1; - - if (efa == data->efa_act || next_efa == data->efa_act) - return 0; - -#ifdef WITH_FREESTYLE - col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0]; - next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : draw_dm_test_freestyle_face_mark(data->bm, efa) ? 3 : 0]; -#else - col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0]; - next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0]; -#endif - - if (col[3] == 0 || next_col[3] == 0) - return 0; - - return col == next_col; -} - -/* also draws the active face */ -#ifdef WITH_FREESTYLE -static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, - unsigned char *selCol, unsigned char *actCol, unsigned char *markCol, BMFace *efa_act) -#else -static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, - unsigned char *selCol, unsigned char *actCol, BMFace *efa_act) -#endif -{ - drawDMFacesSel_userData data; - data.dm = dm; - data.cols[0] = baseCol; - data.bm = em->bm; - data.cols[1] = selCol; - data.cols[2] = actCol; -#ifdef WITH_FREESTYLE - data.cols[3] = markCol; -#endif - data.efa_act = efa_act; - /* double lookup */ - data.orig_index_mp_to_orig = DM_get_poly_data_layer(dm, CD_ORIGINDEX); - - dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, NULL, draw_dm_faces_sel__compareDrawOptions, &data, DM_DRAW_SKIP_HIDDEN); -} - -static DMDrawOption draw_dm_creases__setDrawOptions(void *userData, int index) -{ - drawDMLayer_userData *data = userData; - BMesh *bm = data->bm; - BMEdge *eed = BM_edge_at_index(bm, index); - - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - const float crease = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset); - if (crease != 0.0f) { - UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_CREASE, crease); - return DM_DRAW_OPTION_NORMAL; - } - } - return DM_DRAW_OPTION_SKIP; -} -static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm) -{ - drawDMLayer_userData data; - - data.bm = em->bm; - data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE); - - if (data.cd_layer_offset != -1) { - glLineWidth(3.0); - dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, &data); - } -} - -static DMDrawOption draw_dm_bweights__setDrawOptions(void *userData, int index) -{ - drawDMLayer_userData *data = userData; - BMesh *bm = data->bm; - BMEdge *eed = BM_edge_at_index(bm, index); - - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - const float bweight = BM_ELEM_CD_GET_FLOAT(eed, data->cd_layer_offset); - if (bweight != 0.0f) { - UI_ThemeColorBlend(TH_WIRE_EDIT, TH_EDGE_BEVEL, bweight); - return DM_DRAW_OPTION_NORMAL; - } - } - return DM_DRAW_OPTION_SKIP; -} -static void draw_dm_bweights__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - drawDMLayer_userData *data = userData; - BMesh *bm = data->bm; - BMVert *eve = BM_vert_at_index(bm, index); - - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - const float bweight = BM_ELEM_CD_GET_FLOAT(eve, data->cd_layer_offset); - if (bweight != 0.0f) { - UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_BEVEL, bweight); - glVertex3fv(co); - } - } -} -static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm) -{ - ToolSettings *ts = scene->toolsettings; - - if (ts->selectmode & SCE_SELECT_VERTEX) { - drawDMLayer_userData data; - - data.bm = em->bm; - data.cd_layer_offset = CustomData_get_offset(&em->bm->vdata, CD_BWEIGHT); - - if (data.cd_layer_offset != -1) { - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2); - glBegin(GL_POINTS); - dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, &data, DM_FOREACH_NOP); - glEnd(); - } - } - else { - drawDMLayer_userData data; - - data.bm = em->bm; - data.cd_layer_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT); - - if (data.cd_layer_offset != -1) { - glLineWidth(3.0); - dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, &data); - } - } -} - -/* Second section of routines: Combine first sets to form fancy - * drawing routines (for example rendering twice to get overlays). - * - * Also includes routines that are basic drawing but are too - * specialized to be split out (like drawing creases or measurements). - */ - -/* EditMesh drawing routines */ - -static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, - BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act, - RegionView3D *rv3d) -{ - ToolSettings *ts = scene->toolsettings; - - if (v3d->zbuf) glDepthMask(0); /* disable write in zbuffer, zbuf select */ - - for (int sel = 0; sel < 2; sel++) { - unsigned char col[4], fcol[4]; - - UI_GetThemeColor3ubv(sel ? TH_VERTEX_SELECT : TH_VERTEX, col); - UI_GetThemeColor3ubv(sel ? TH_FACE_DOT : TH_WIRE_EDIT, fcol); - - for (int pass = 0; pass < 2; pass++) { - float size = UI_GetThemeValuef(TH_VERTEX_SIZE); - float fsize = UI_GetThemeValuef(TH_FACEDOT_SIZE); - - if (pass == 0) { - if (v3d->zbuf && !(v3d->flag & V3D_ZBUF_SELECT)) { - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - } - else { - continue; - } - - size = (size > 2.1f ? size / 2.0f : size); - fsize = (fsize > 2.1f ? fsize / 2.0f : fsize); - col[3] = fcol[3] = 100; - } - else { - col[3] = fcol[3] = 255; - } - - if (ts->selectmode & SCE_SELECT_VERTEX) { - glPointSize(size); - glColor4ubv(col); - draw_dm_verts(em, cageDM, sel, eve_act, rv3d); - } - - if (check_ob_drawface_dot(scene, v3d, obedit->dt)) { - glPointSize(fsize); - glColor4ubv(fcol); - draw_dm_face_centers(em, cageDM, sel); - } - - if (pass == 0) { - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - } - } - } - - if (v3d->zbuf) glDepthMask(1); -} - -static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d, - Mesh *me, DerivedMesh *cageDM, short sel_only, - BMEdge *eed_act) -{ - ToolSettings *ts = scene->toolsettings; - unsigned char wireCol[4], selCol[4], actCol[4]; - - /* since this function does transparent... */ - UI_GetThemeColor4ubv(TH_EDGE_SELECT, selCol); - UI_GetThemeColor4ubv(TH_WIRE_EDIT, wireCol); - UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, actCol); - - /* when sel only is used, don't render wire, only selected, this is used for - * textured draw mode when the 'edges' option is disabled */ - if (sel_only) - wireCol[3] = 0; - - for (int pass = 0; pass < 2; pass++) { - /* show wires in transparent when no zbuf clipping for select */ - if (pass == 0) { - if (v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT) == 0) { - glEnable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - selCol[3] = 85; - if (!sel_only) wireCol[3] = 85; - } - else { - continue; - } - } - else { - selCol[3] = 255; - if (!sel_only) wireCol[3] = 255; - } - - if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) { - if (cageDM->drawMappedEdgesInterp && - ((ts->selectmode & SCE_SELECT_VERTEX) || (me->drawflag & ME_DRAWEIGHT))) - { - if (draw_dm_edges_weight_check(me, v3d)) { - // Interpolate vertex weights - draw_dm_edges_weight_interp(em, cageDM, ts->weightuser); - } - else if (ts->selectmode == SCE_SELECT_FACE) { - draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); - } - else { - // Interpolate vertex selection - draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol); - } - } - else { - draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); - } - } - else { - if (!sel_only) { - glColor4ubv(wireCol); - draw_dm_edges(em, cageDM); - } - } - - if (pass == 0) { - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - } - } -} - -static void draw_em_measure_stats(ARegion *ar, View3D *v3d, Object *ob, BMEditMesh *em, UnitSettings *unit) -{ - /* Do not use ascii when using non-default unit system, some unit chars are utf8 (micro, square, etc.). - * See bug #36090. - */ - const short txt_flag = V3D_CACHE_TEXT_LOCALCLIP | (unit->system ? 0 : V3D_CACHE_TEXT_ASCII); - Mesh *me = ob->data; - float v1[3], v2[3], v3[3], vmid[3], fvec[3]; - char numstr[32]; /* Stores the measurement display text here */ - size_t numstr_len; - const char *conv_float; /* Use a float conversion matching the grid size */ - unsigned char col[4] = {0, 0, 0, 255}; /* color of the text to draw */ - float area; /* area of the face */ - float grid = unit->system ? unit->scale_length : v3d->grid; - const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0; - const bool do_global = (v3d->flag & V3D_GLOBAL_STATS) != 0; - const bool do_moving = (G.moving & G_TRANSFORM_EDIT) != 0; - /* when 2 edge-info options are enabled, space apart */ - const bool do_edge_textpair = (me->drawflag & ME_DRAWEXTRA_EDGELEN) && (me->drawflag & ME_DRAWEXTRA_EDGEANG); - const float edge_texpair_sep = 0.4f; - float clip_planes[4][4]; - /* allow for displaying shape keys and deform mods */ - DerivedMesh *dm = EDBM_mesh_deform_dm_get(em); - BMIter iter; - - /* make the precision of the display value proportionate to the gridsize */ - - if (grid <= 0.01f) conv_float = "%.6g"; - else if (grid <= 0.1f) conv_float = "%.5g"; - else if (grid <= 1.0f) conv_float = "%.4g"; - else if (grid <= 10.0f) conv_float = "%.3g"; - else conv_float = "%.2g"; - - if (me->drawflag & (ME_DRAWEXTRA_EDGELEN | ME_DRAWEXTRA_EDGEANG)) { - BoundBox bb; - bglMats mats = {{0}}; - const rcti rect = {0, ar->winx, 0, ar->winy}; - - view3d_get_transformation(ar, ar->regiondata, em->ob, &mats); - ED_view3d_clipping_calc(&bb, clip_planes, &mats, &rect); - } - - if (me->drawflag & ME_DRAWEXTRA_EDGELEN) { - BMEdge *eed; - - UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col); - - if (dm) { - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - } - - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - /* draw selected edges, or edges next to selected verts while dragging */ - if (BM_elem_flag_test(eed, BM_ELEM_SELECT) || - (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || - BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))) - { - float v1_clip[3], v2_clip[3]; - - if (dm) { - dm->getVertCo(dm, BM_elem_index_get(eed->v1), v1); - dm->getVertCo(dm, BM_elem_index_get(eed->v2), v2); - } - else { - copy_v3_v3(v1, eed->v1->co); - copy_v3_v3(v2, eed->v2->co); - } - - if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) { - - if (do_edge_textpair) { - interp_v3_v3v3(vmid, v1, v2, edge_texpair_sep); - } - else { - mid_v3_v3v3(vmid, v1_clip, v2_clip); - } - - if (do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); - } - - if (unit->system) { - numstr_len = bUnit_AsString(numstr, sizeof(numstr), len_v3v3(v1, v2) * unit->scale_length, 3, - unit->system, B_UNIT_LENGTH, do_split, false); - } - else { - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, len_v3v3(v1, v2)); - } - - view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col); - } - } - } - } - - if (me->drawflag & ME_DRAWEXTRA_EDGEANG) { - const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS); - BMEdge *eed; - - UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col); - - if (dm) { - BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); - } - - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - BMLoop *l_a, *l_b; - if (BM_edge_loop_pair(eed, &l_a, &l_b)) { - /* draw selected edges, or edges next to selected verts while dragging */ - if (BM_elem_flag_test(eed, BM_ELEM_SELECT) || - (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || - BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) || - /* special case, this is useful to show when verts connected to - * this edge via a face are being transformed */ - BM_elem_flag_test(l_a->next->next->v, BM_ELEM_SELECT) || - BM_elem_flag_test(l_a->prev->v, BM_ELEM_SELECT) || - BM_elem_flag_test(l_b->next->next->v, BM_ELEM_SELECT) || - BM_elem_flag_test(l_b->prev->v, BM_ELEM_SELECT) - ))) - { - float v1_clip[3], v2_clip[3]; - - if (dm) { - dm->getVertCo(dm, BM_elem_index_get(eed->v1), v1); - dm->getVertCo(dm, BM_elem_index_get(eed->v2), v2); - } - else { - copy_v3_v3(v1, eed->v1->co); - copy_v3_v3(v2, eed->v2->co); - } - - if (clip_segment_v3_plane_n(v1, v2, clip_planes, 4, v1_clip, v2_clip)) { - float no_a[3], no_b[3]; - float angle; - - if (do_edge_textpair) { - interp_v3_v3v3(vmid, v2_clip, v1_clip, edge_texpair_sep); - } - else { - mid_v3_v3v3(vmid, v1_clip, v2_clip); - } - - if (dm) { - dm->getPolyNo(dm, BM_elem_index_get(l_a->f), no_a); - dm->getPolyNo(dm, BM_elem_index_get(l_b->f), no_b); - } - else { - copy_v3_v3(no_a, l_a->f->no); - copy_v3_v3(no_b, l_b->f->no); - } - - if (do_global) { - mul_mat3_m4_v3(ob->imat, no_a); - mul_mat3_m4_v3(ob->imat, no_b); - normalize_v3(no_a); - normalize_v3(no_b); - } - - angle = angle_normalized_v3v3(no_a, no_b); - - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle)); - - view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col); - } - } - } - } - } - - if (me->drawflag & ME_DRAWEXTRA_FACEAREA) { - /* would be nice to use BM_face_calc_area, but that is for 2d faces - * so instead add up tessellation triangle areas */ - BMFace *f = NULL; - -#define DRAW_EM_MEASURE_STATS_FACEAREA() \ - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \ - mul_v3_fl(vmid, 1.0f / (float)n); \ - if (unit->system) { \ - numstr_len = bUnit_AsString( \ - numstr, sizeof(numstr), \ - (double)(area * unit->scale_length * unit->scale_length), \ - 3, unit->system, B_UNIT_AREA, do_split, false); \ - } \ - else { \ - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), conv_float, area); \ - } \ - view3d_cached_text_draw_add(vmid, numstr, numstr_len, 0, txt_flag, col); \ - } (void)0 - - UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col); - - if (dm) { - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - } - - area = 0.0; - zero_v3(vmid); - int n = 0; - for (int i = 0; i < em->tottri; i++) { - BMLoop **l = em->looptris[i]; - if (f && l[0]->f != f) { - DRAW_EM_MEASURE_STATS_FACEAREA(); - zero_v3(vmid); - area = 0.0; - n = 0; - } - - f = l[0]->f; - - if (dm) { - dm->getVertCo(dm, BM_elem_index_get(l[0]->v), v1); - dm->getVertCo(dm, BM_elem_index_get(l[1]->v), v2); - dm->getVertCo(dm, BM_elem_index_get(l[2]->v), v3); - } - else { - copy_v3_v3(v1, l[0]->v->co); - copy_v3_v3(v2, l[1]->v->co); - copy_v3_v3(v3, l[2]->v->co); - } - - add_v3_v3(vmid, v1); - add_v3_v3(vmid, v2); - add_v3_v3(vmid, v3); - n += 3; - if (do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); - mul_mat3_m4_v3(ob->obmat, v3); - } - area += area_tri_v3(v1, v2, v3); - } - - if (f) { - DRAW_EM_MEASURE_STATS_FACEAREA(); - } -#undef DRAW_EM_MEASURE_STATS_FACEAREA - } - - if (me->drawflag & ME_DRAWEXTRA_FACEANG) { - BMFace *efa; - const bool is_rad = (unit->system_rotation == USER_UNIT_ROT_RADIANS); - - UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col); - - if (dm) { - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - } - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - const bool is_face_sel = BM_elem_flag_test_bool(efa, BM_ELEM_SELECT); - - if (is_face_sel || do_moving) { - BMIter liter; - BMLoop *loop; - bool is_first = true; - - BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) { - if (is_face_sel || - (do_moving && - (BM_elem_flag_test(loop->v, BM_ELEM_SELECT) || - BM_elem_flag_test(loop->prev->v, BM_ELEM_SELECT) || - BM_elem_flag_test(loop->next->v, BM_ELEM_SELECT)))) - { - float v2_local[3]; - - /* lazy init center calc */ - if (is_first) { - if (dm) { - BMLoop *l_iter, *l_first; - float tvec[3]; - zero_v3(vmid); - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - dm->getVertCo(dm, BM_elem_index_get(l_iter->v), tvec); - add_v3_v3(vmid, tvec); - } while ((l_iter = l_iter->next) != l_first); - mul_v3_fl(vmid, 1.0f / (float)efa->len); - } - else { - BM_face_calc_center_bounds(efa, vmid); - } - is_first = false; - } - - if (dm) { - dm->getVertCo(dm, BM_elem_index_get(loop->prev->v), v1); - dm->getVertCo(dm, BM_elem_index_get(loop->v), v2); - dm->getVertCo(dm, BM_elem_index_get(loop->next->v), v3); - } - else { - copy_v3_v3(v1, loop->prev->v->co); - copy_v3_v3(v2, loop->v->co); - copy_v3_v3(v3, loop->next->v->co); - } - - copy_v3_v3(v2_local, v2); - - if (do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); - mul_mat3_m4_v3(ob->obmat, v3); - } - - float angle = angle_v3v3v3(v1, v2, v3); - - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%.3f", is_rad ? angle : RAD2DEGF(angle)); - interp_v3_v3v3(fvec, vmid, v2_local, 0.8f); - view3d_cached_text_draw_add(fvec, numstr, numstr_len, 0, txt_flag, col); - } - } - } - } - } -} - -static void draw_em_indices(BMEditMesh *em) -{ - const short txt_flag = V3D_CACHE_TEXT_ASCII | V3D_CACHE_TEXT_LOCALCLIP; - BMEdge *e; - BMFace *f; - BMVert *v; - char numstr[32]; - size_t numstr_len; - float pos[3]; - unsigned char col[4]; - - BMIter iter; - BMesh *bm = em->bm; - - /* For now, reuse appropriate theme colors from stats text colors */ - int i = 0; - if (em->selectmode & SCE_SELECT_VERTEX) { - UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col); - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); - view3d_cached_text_draw_add(v->co, numstr, numstr_len, 0, txt_flag, col); - } - i++; - } - } - - if (em->selectmode & SCE_SELECT_EDGE) { - i = 0; - UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col); - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); - mid_v3_v3v3(pos, e->v1->co, e->v2->co); - view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col); - } - i++; - } - } - - if (em->selectmode & SCE_SELECT_FACE) { - i = 0; - UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col); - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - BM_face_calc_center_mean(f, pos); - numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", i); - view3d_cached_text_draw_add(pos, numstr, numstr_len, 0, txt_flag, col); - } - i++; - } - } -} - -static DMDrawOption draw_em_fancy__setFaceOpts(void *userData, int index) -{ - BMEditMesh *em = userData; - - if (UNLIKELY(index >= em->bm->totface)) - return DM_DRAW_OPTION_NORMAL; - - BMFace *efa = BM_face_at_index(em->bm, index); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - return DM_DRAW_OPTION_NORMAL; - } - else { - return DM_DRAW_OPTION_SKIP; - } -} - -static DMDrawOption draw_em_fancy__setGLSLFaceOpts(void *userData, int index) -{ - BMEditMesh *em = userData; - - if (UNLIKELY(index >= em->bm->totface)) - return DM_DRAW_OPTION_NORMAL; - - BMFace *efa = BM_face_at_index(em->bm, index); - - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - return DM_DRAW_OPTION_NORMAL; - } - else { - return DM_DRAW_OPTION_SKIP; - } -} - -static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, - Object *ob, BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, const char dt) - -{ - RegionView3D *rv3d = ar->regiondata; - Mesh *me = ob->data; - const bool use_occlude_wire = (dt > OB_WIRE) && (v3d->flag2 & V3D_OCCLUDE_WIRE); - bool use_depth_offset = false; - - glLineWidth(1); - - BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); - - if (check_object_draw_editweight(me, finalDM)) { - if (dt > OB_WIRE) { - draw_mesh_paint_weight_faces(finalDM, true, draw_em_fancy__setFaceOpts, me->edit_btmesh); - - ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); - use_depth_offset = true; - } - else { - glEnable(GL_DEPTH_TEST); - draw_mesh_paint_weight_faces(finalDM, false, draw_em_fancy__setFaceOpts, me->edit_btmesh); - draw_mesh_paint_weight_edges(rv3d, finalDM, true, true, draw_dm_edges__setDrawOptions, me->edit_btmesh->bm); - glDisable(GL_DEPTH_TEST); - } - } - else if (dt > OB_WIRE) { - if (use_occlude_wire) { - /* use the cageDM since it always overlaps the editmesh faces */ - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - cageDM->drawMappedFaces(cageDM, draw_em_fancy__setFaceOpts, - GPU_object_material_bind, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN | DM_DRAW_NEED_NORMALS); - GPU_object_material_unbind(); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - } - else if (check_object_draw_texture(scene, v3d, dt)) { - if (draw_glsl_material(scene, ob, v3d, dt)) { - glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - - finalDM->drawMappedFacesGLSL(finalDM, GPU_object_material_bind, - draw_em_fancy__setGLSLFaceOpts, em); - GPU_object_material_unbind(); - - glFrontFace(GL_CCW); - } - else { - draw_mesh_textured(scene, v3d, rv3d, ob, finalDM, 0); - } - } - else { - glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_object_material_bind, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN | DM_DRAW_NEED_NORMALS); - - glFrontFace(GL_CCW); - - GPU_object_material_unbind(); - } - - /* Setup for drawing wire over, disable zbuffer - * write to show selected edge wires better */ - UI_ThemeColor(TH_WIRE_EDIT); - - ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); - use_depth_offset = true; - } - else { - if (cageDM != finalDM) { - UI_ThemeColorBlend(TH_WIRE_EDIT, TH_BACK, 0.7); - finalDM->drawEdges(finalDM, 1, 0); - } - } - - if ((dt > OB_WIRE) && (v3d->flag2 & V3D_RENDER_SHADOW)) { - /* pass */ - } - else { - /* annoying but active faces is stored differently */ - BMFace *efa_act = BM_mesh_active_face_get(em->bm, false, true); - BMEdge *eed_act = NULL; - BMVert *eve_act = NULL; - - if (em->bm->selected.last) { - BMEditSelection *ese = em->bm->selected.last; - /* face is handled above */ -#if 0 - if (ese->type == BM_FACE) { - efa_act = (BMFace *)ese->data; - } - else -#endif - if (ese->htype == BM_EDGE) { - eed_act = (BMEdge *)ese->ele; - } - else if (ese->htype == BM_VERT) { - eve_act = (BMVert *)ese->ele; - } - } - - if ((me->drawflag & ME_DRAWFACES) && (use_occlude_wire == false)) { /* transp faces */ - unsigned char col1[4], col2[4], col3[4]; -#ifdef WITH_FREESTYLE - unsigned char col4[4]; -#endif - - UI_GetThemeColor4ubv(TH_FACE, col1); - UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); - UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3); -#ifdef WITH_FREESTYLE - UI_GetThemeColor4ubv(TH_FREESTYLE_FACE_MARK, col4); -#endif - - glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ - - /* don't draw unselected faces, only selected, this is MUCH nicer when texturing */ - if (check_object_draw_texture(scene, v3d, dt)) - col1[3] = 0; - -#ifdef WITH_FREESTYLE - if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE) || !CustomData_has_layer(&em->bm->pdata, CD_FREESTYLE_FACE)) - col4[3] = 0; - - draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act); -#else - draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act); -#endif - - glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ - } - else if (efa_act) { - /* even if draw faces is off it would be nice to draw the stipple face - * Make all other faces zero alpha except for the active */ - unsigned char col1[4], col2[4], col3[4]; -#ifdef WITH_FREESTYLE - unsigned char col4[4]; - col4[3] = 0; /* don't draw */ -#endif - col1[3] = col2[3] = 0; /* don't draw */ - - UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3); - - glEnable(GL_BLEND); - glDepthMask(0); /* disable write in zbuffer, needed for nice transp */ - -#ifdef WITH_FREESTYLE - draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act); -#else - draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act); -#endif - - glDisable(GL_BLEND); - glDepthMask(1); /* restore write in zbuffer */ - } - - /* here starts all fancy draw-extra over */ - if ((me->drawflag & ME_DRAWEDGES) == 0 && check_object_draw_texture(scene, v3d, dt)) { - /* we are drawing textures and 'ME_DRAWEDGES' is disabled, don't draw any edges */ - - /* only draw selected edges otherwise there is no way of telling if a face is selected */ - draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act); - - } - else { - if (me->drawflag & ME_DRAWSEAMS) { - UI_ThemeColor(TH_EDGE_SEAM); - glLineWidth(2); - - draw_dm_edges_seams(em, cageDM); - - glColor3ub(0, 0, 0); - } - - if (me->drawflag & ME_DRAWSHARP) { - UI_ThemeColor(TH_EDGE_SHARP); - glLineWidth(2); - - draw_dm_edges_sharp(em, cageDM); - - glColor3ub(0, 0, 0); - } - -#ifdef WITH_FREESTYLE - if (me->drawflag & ME_DRAW_FREESTYLE_EDGE && CustomData_has_layer(&em->bm->edata, CD_FREESTYLE_EDGE)) { - UI_ThemeColor(TH_FREESTYLE_EDGE_MARK); - glLineWidth(2); - - draw_dm_edges_freestyle(em, cageDM); - - glColor3ub(0, 0, 0); - } -#endif - - if (me->drawflag & ME_DRAWCREASES) { - draw_dm_creases(em, cageDM); - } - if (me->drawflag & ME_DRAWBWEIGHTS) { - draw_dm_bweights(em, scene, cageDM); - } - - glLineWidth(1); - draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act); - } - - { - draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act, rv3d); - - if (me->drawflag & ME_DRAWNORMALS) { - UI_ThemeColor(TH_NORMAL); - draw_dm_face_normals(em, scene, ob, cageDM); - } - if (me->drawflag & ME_DRAW_VNORMALS) { - UI_ThemeColor(TH_VNORMAL); - draw_dm_vert_normals(em, scene, ob, cageDM); - } - if (me->drawflag & ME_DRAW_LNORMALS) { - UI_ThemeColor(TH_LNORMAL); - draw_dm_loop_normals(em, scene, ob, cageDM); - } - - if ((me->drawflag & (ME_DRAWEXTRA_EDGELEN | - ME_DRAWEXTRA_FACEAREA | - ME_DRAWEXTRA_FACEANG | - ME_DRAWEXTRA_EDGEANG)) && - !(v3d->flag2 & V3D_RENDER_OVERRIDE)) - { - draw_em_measure_stats(ar, v3d, ob, em, &scene->unit); - } - - if ((G.debug & G_DEBUG) && (me->drawflag & ME_DRAWEXTRA_INDICES) && - !(v3d->flag2 & V3D_RENDER_OVERRIDE)) - { - draw_em_indices(em); - } - } - } - - if (use_depth_offset) { - glDepthMask(1); - ED_view3d_polygon_offset(rv3d, 0.0); - GPU_object_material_unbind(); - } -#if 0 /* currently not needed */ - else if (use_occlude_wire) { - ED_view3d_polygon_offset(rv3d, 0.0); - } -#endif -} - -/* Mesh drawing routines */ - -static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) -{ - if ((v3d->transp == false) && /* not when we draw the transparent pass */ - (ob->mode & OB_MODE_ALL_PAINT) == false) /* not when painting (its distracting) - campbell */ - { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - glDepthMask(0); - - /* if transparent, we cannot draw the edges for solid select... edges - * have no material info. GPU_object_material_visible will skip the - * transparent faces */ - if (ob->dtx & OB_DRAWTRANSP) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_visible); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - else { - dm->drawEdges(dm, 0, 1); - } - - glDepthMask(1); - } -} - -static bool object_is_halo(Scene *scene, Object *ob) -{ - const Material *ma = give_current_material(ob, 1); - return (ma && (ma->material_type == MA_TYPE_HALO) && !BKE_scene_use_new_shading_nodes(scene)); -} - -static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const unsigned char ob_wire_col[4], const short dflag) -{ -#ifdef WITH_GAMEENGINE - Object *ob = (rv3d->rflag & RV3D_IS_GAME_ENGINE) ? BKE_object_lod_meshob_get(base->object, scene) : base->object; -#else - Object *ob = base->object; -#endif - Mesh *me = ob->data; - eWireDrawMode draw_wire = OBDRAW_WIRE_OFF; - bool /* no_verts,*/ no_edges, no_faces; - DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); - const bool is_obact = (ob == OBACT); - int draw_flags = (is_obact && BKE_paint_select_face_test(ob)) ? DRAW_FACE_SELECT : 0; - - if (!dm) - return; - - DM_update_materials(dm, ob); - - /* Check to draw dynamic paint colors (or weights from WeightVG modifiers). - * Note: Last "preview-active" modifier in stack will win! */ - if (DM_get_loop_data_layer(dm, CD_PREVIEW_MLOOPCOL) && modifiers_isPreview(ob)) - draw_flags |= DRAW_MODIFIERS_PREVIEW; - - /* Unwanted combination */ - if (draw_flags & DRAW_FACE_SELECT) { - draw_wire = OBDRAW_WIRE_OFF; - } - else if (ob->dtx & OB_DRAWWIRE) { - draw_wire = OBDRAW_WIRE_ON_DEPTH; /* draw wire after solid using zoffset and depth buffer adjusment */ - } - - /* check polys instead of tessfaces because of dyntopo where tessfaces don't exist */ - if (dm->type == DM_TYPE_CCGDM) { - no_edges = !subsurf_has_edges(dm); - no_faces = !subsurf_has_faces(dm); - } - else { - no_edges = (dm->getNumEdges(dm) == 0); - no_faces = (dm->getNumPolys(dm) == 0); - } - - /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */ - glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - - if (dt == OB_BOUNDBOX) { - if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_WIRE) == 0) - draw_bounding_volume(ob, ob->boundtype); - } - else if ((no_faces && no_edges) || - ((!is_obact || (ob->mode == OB_MODE_OBJECT)) && object_is_halo(scene, ob))) - { - glPointSize(1.5); - dm->drawVerts(dm); - } - else if ((dt == OB_WIRE) || no_faces) { - draw_wire = OBDRAW_WIRE_ON; /* draw wire only, no depth buffer stuff */ - } - else if (((is_obact && ob->mode & OB_MODE_TEXTURE_PAINT)) || - check_object_draw_texture(scene, v3d, dt)) - { - bool draw_loose = true; - - if ((v3d->flag & V3D_SELECT_OUTLINE) && - ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (base->flag & SELECT) && - !(G.f & G_PICKSEL || (draw_flags & DRAW_FACE_SELECT)) && - (draw_wire == OBDRAW_WIRE_OFF)) - { - draw_mesh_object_outline(v3d, ob, dm); - } - - if (draw_glsl_material(scene, ob, v3d, dt) && !(draw_flags & DRAW_MODIFIERS_PREVIEW)) { - Paint *p; - - glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - - if ((v3d->flag2 & V3D_SHOW_SOLID_MATCAP) && ob->sculpt && (p = BKE_paint_get_active(scene))) { - GPUVertexAttribs gattribs; - float planes[4][4]; - float (*fpl)[4] = NULL; - const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING); - - if (ob->sculpt->partial_redraw) { - if (ar->do_draw & RGN_DRAW_PARTIAL) { - ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob); - fpl = planes; - ob->sculpt->partial_redraw = 0; - } - } - - GPU_object_material_bind(1, &gattribs); - dm->drawFacesSolid(dm, fpl, fast, NULL); - draw_loose = false; - } - else - dm->drawFacesGLSL(dm, GPU_object_material_bind); - -#if 0 /* XXX */ - if (BKE_bproperty_object_get(ob, "Text")) - draw_mesh_text(ob, 1); -#endif - GPU_object_material_unbind(); - - glFrontFace(GL_CCW); - - if (draw_flags & DRAW_FACE_SELECT) - draw_mesh_face_select(rv3d, me, dm, false); - } - else { - draw_mesh_textured(scene, v3d, rv3d, ob, dm, draw_flags); - } - - if (draw_loose && !(draw_flags & DRAW_FACE_SELECT)) { - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(ob_wire_col); - } - glLineWidth(1.0f); - dm->drawLooseEdges(dm); - } - } - } - else if (dt == OB_SOLID) { - if (draw_flags & DRAW_MODIFIERS_PREVIEW) { - /* for object selection draws no shade */ - if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) { - dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); - GPU_object_material_unbind(); - } - else { - const float specular[3] = {0.47f, 0.47f, 0.47f}; - - /* draw outline */ - if ((v3d->flag & V3D_SELECT_OUTLINE) && - ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (base->flag & SELECT) && - (draw_wire == OBDRAW_WIRE_OFF) && - (ob->sculpt == NULL)) - { - draw_mesh_object_outline(v3d, ob, dm); - } - - /* materials arent compatible with vertex colors */ - GPU_end_object_materials(); - - /* set default specular */ - GPU_basic_shader_colors(NULL, specular, 35, 1.0f); - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - - dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS); - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - } - else { - Paint *p; - - if ((v3d->flag & V3D_SELECT_OUTLINE) && - ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (base->flag & SELECT) && - (draw_wire == OBDRAW_WIRE_OFF) && - (ob->sculpt == NULL)) - { - draw_mesh_object_outline(v3d, ob, dm); - } - - glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - - if (ob->sculpt && (p = BKE_paint_get_active(scene))) { - float planes[4][4]; - float (*fpl)[4] = NULL; - const bool fast = (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING); - - if (ob->sculpt->partial_redraw) { - if (ar->do_draw & RGN_DRAW_PARTIAL) { - ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob); - fpl = planes; - ob->sculpt->partial_redraw = 0; - } - } - - dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind); - } - else - dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); - - glFrontFace(GL_CCW); - - GPU_object_material_unbind(); - - if (!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(ob_wire_col); - } - glLineWidth(1.0f); - dm->drawLooseEdges(dm); - } - } - } - else if (dt == OB_PAINT) { - draw_mesh_paint(v3d, rv3d, ob, dm, draw_flags); - - /* since we already draw wire as wp guide, don't draw over the top */ - draw_wire = OBDRAW_WIRE_OFF; - } - - if ((draw_wire != OBDRAW_WIRE_OFF) && /* draw extra wire */ - /* when overriding with render only, don't bother */ - (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0)) - { - /* When using wireframe object draw in particle edit mode - * the mesh gets in the way of seeing the particles, fade the wire color - * with the background. */ - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (is_obact && (ob->mode & OB_MODE_PARTICLE_EDIT)) { - ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f); - } - else { - glColor3ubv(ob_wire_col); - } - } - - /* If drawing wire and drawtype is not OB_WIRE then we are - * overlaying the wires. - * - * UPDATE bug #10290 - With this wire-only objects can draw - * behind other objects depending on their order in the scene. 2x if 0's below. undo'ing zr's commit: r4059 - * - * if draw wire is 1 then just drawing wire, no need for depth buffer stuff, - * otherwise this wire is to overlay solid mode faces so do some depth buffer tricks. - */ - if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) { - ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ - } - - glLineWidth(1.0f); - dm->drawEdges(dm, ((dt == OB_WIRE) || no_faces), (ob->dtx & OB_DRAW_ALL_EDGES) != 0); - - if (dt != OB_WIRE && (draw_wire == OBDRAW_WIRE_ON_DEPTH)) { - glDepthMask(1); - ED_view3d_polygon_offset(rv3d, 0.0); - } - } - - if (is_obact && BKE_paint_select_vert_test(ob)) { - const bool use_depth = (v3d->flag & V3D_ZBUF_SELECT) != 0; - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - - if (!use_depth) glDisable(GL_DEPTH_TEST); - else ED_view3d_polygon_offset(rv3d, 1.0); - drawSelectedVertices(dm, ob->data); - if (!use_depth) glEnable(GL_DEPTH_TEST); - else ED_view3d_polygon_offset(rv3d, 0.0); - } - dm->release(dm); -} - -/* returns true if nothing was drawn, for detecting to draw an object center */ -static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const unsigned char ob_wire_col[4], const short dflag) -{ - Object *ob = base->object; - Object *obedit = scene->obedit; - Mesh *me = ob->data; - BMEditMesh *em = me->edit_btmesh; - bool do_alpha_after = false, drawlinked = false, retval = false; - - /* If we are drawing shadows and any of the materials don't cast a shadow, - * then don't draw the object */ - if (v3d->flag2 & V3D_RENDER_SHADOW) { - for (int i = 1; i <= ob->totcol; ++i) { - Material *ma = give_current_material(ob, i); - if (ma && !(ma->mode2 & MA_CASTSHADOW)) { - return true; - } - } - } - - if (obedit && ob != obedit && ob->data == obedit->data) { - if (BKE_key_from_object(ob) || BKE_key_from_object(obedit)) {} - else if (ob->modifiers.first || obedit->modifiers.first) {} - else drawlinked = true; - } - - /* backface culling */ - if (v3d->flag2 & V3D_BACKFACE_CULLING) { - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - } - - if (ob == obedit || drawlinked) { - DerivedMesh *finalDM, *cageDM; - - if (obedit != ob) { - finalDM = cageDM = editbmesh_get_derived_base( - ob, em, scene->customdata_mask); - } - else { - cageDM = editbmesh_get_derived_cage_and_final( - scene, ob, em, scene->customdata_mask, - &finalDM); - } - - const bool use_material = ((me->drawflag & ME_DRAWEIGHT) == 0); - - DM_update_materials(finalDM, ob); - if (cageDM != finalDM) { - DM_update_materials(cageDM, ob); - } - - if (use_material) { - if (dt > OB_WIRE) { - const bool glsl = draw_glsl_material(scene, ob, v3d, dt); - - GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); - } - } - - draw_em_fancy(scene, ar, v3d, ob, em, cageDM, finalDM, dt); - - if (use_material) { - GPU_end_object_materials(); - } - - if (obedit != ob) - finalDM->release(finalDM); - } - else { - /* ob->bb was set by derived mesh system, do NULL check just to be sure */ - if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) { - if (dt > OB_WIRE) { - const bool glsl = draw_glsl_material(scene, ob, v3d, dt); - - if (dt == OB_SOLID || glsl) { - const bool check_alpha = check_alpha_pass(base); - GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, - (check_alpha) ? &do_alpha_after : NULL); - } - } - - draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); - - GPU_end_object_materials(); - - if (me->totvert == 0) retval = true; - } - } - - if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - /* GPU_begin_object_materials checked if this is needed */ - if (do_alpha_after) { - if (ob->dtx & OB_DRAWXRAY) { - ED_view3d_after_add(&v3d->afterdraw_xraytransp, base, dflag); - } - else { - ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag); - } - } - else if (ob->dtx & OB_DRAWXRAY && ob->dtx & OB_DRAWTRANSP) { - /* special case xray+transp when alpha is 1.0, without this the object vanishes */ - if (v3d->xray == 0 && v3d->transp == 0) { - ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag); - } - } - } - - if (v3d->flag2 & V3D_BACKFACE_CULLING) - glDisable(GL_CULL_FACE); - - return retval; -} - -/* ************** DRAW DISPLIST ****************** */ - - -/** - * \param dl_type_mask: Only draw types matching this mask. - * \return true when nothing was drawn - */ -static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask) -{ - if (dlbase == NULL) return true; - - glEnableClientState(GL_VERTEX_ARRAY); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - for (DispList *dl = dlbase->first; dl; dl = dl->next) { - if (dl->parts == 0 || dl->nr == 0) { - continue; - } - - if ((dl_type_mask & (1 << dl->type)) == 0) { - continue; - } - - const float *data = dl->verts; - int parts; - - switch (dl->type) { - case DL_SEGM: - - glVertexPointer(3, GL_FLOAT, 0, data); - - for (parts = 0; parts < dl->parts; parts++) - glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr); - - break; - case DL_POLY: - - glVertexPointer(3, GL_FLOAT, 0, data); - - for (parts = 0; parts < dl->parts; parts++) - glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr); - - break; - case DL_SURF: - - glVertexPointer(3, GL_FLOAT, 0, data); - - for (parts = 0; parts < dl->parts; parts++) { - if (dl->flag & DL_CYCL_U) - glDrawArrays(GL_LINE_LOOP, parts * dl->nr, dl->nr); - else - glDrawArrays(GL_LINE_STRIP, parts * dl->nr, dl->nr); - } - - for (int nr = 0; nr < dl->nr; nr++) { - int ofs = 3 * dl->nr; - - data = (dl->verts) + 3 * nr; - parts = dl->parts; - - if (dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP); - else glBegin(GL_LINE_STRIP); - - while (parts--) { - glVertex3fv(data); - data += ofs; - } - glEnd(); - -#if 0 - /* (ton) this code crashes for me when resolv is 86 or higher... no clue */ - glVertexPointer(3, GL_FLOAT, sizeof(float) * 3 * dl->nr, data + 3 * nr); - if (dl->flag & DL_CYCL_V) - glDrawArrays(GL_LINE_LOOP, 0, dl->parts); - else - glDrawArrays(GL_LINE_STRIP, 0, dl->parts); -#endif - } - break; - - case DL_INDEX3: - glVertexPointer(3, GL_FLOAT, 0, dl->verts); - glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index); - break; - - case DL_INDEX4: - glVertexPointer(3, GL_FLOAT, 0, dl->verts); - glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index); - break; - } - } - - glDisableClientState(GL_VERTEX_ARRAY); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - return false; -} - -static bool drawDispListwire(ListBase *dlbase, const short ob_type) -{ - unsigned int dl_mask = 0xffffffff; - - /* skip fill-faces for curves & fonts */ - if (ELEM(ob_type, OB_FONT, OB_CURVE)) { - dl_mask &= ~((1 << DL_INDEX3) | (1 << DL_INDEX4)); - } - - return drawDispListwire_ex(dlbase, dl_mask); -} - -static bool index3_nors_incr = true; - -static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, - const unsigned char ob_wire_col[4], const bool use_glsl) -{ - GPUVertexAttribs gattribs; - - if (lb == NULL) return; - - glEnableClientState(GL_VERTEX_ARRAY); - - /* track current material, -1 for none (needed for lines) */ - short col = -1; - - DispList *dl = lb->first; - while (dl) { - const float *data = dl->verts; - const float *ndata = dl->nors; - - switch (dl->type) { - case DL_SEGM: - if (ob->type == OB_SURF) { - if (col != -1) { - GPU_object_material_unbind(); - col = -1; - } - - if ((dflag & DRAW_CONSTCOLOR) == 0) - glColor3ubv(ob_wire_col); - - // glVertexPointer(3, GL_FLOAT, 0, dl->verts); - // glDrawArrays(GL_LINE_STRIP, 0, dl->nr); - glBegin(GL_LINE_STRIP); - for (int nr = dl->nr; nr; nr--, data += 3) - glVertex3fv(data); - glEnd(); - } - break; - case DL_POLY: - if (ob->type == OB_SURF) { - if (col != -1) { - GPU_object_material_unbind(); - col = -1; - } - - /* for some reason glDrawArrays crashes here in half of the platforms (not osx) */ - //glVertexPointer(3, GL_FLOAT, 0, dl->verts); - //glDrawArrays(GL_LINE_LOOP, 0, dl->nr); - - glBegin(GL_LINE_LOOP); - for (int nr = dl->nr; nr; nr--, data += 3) - glVertex3fv(data); - glEnd(); - } - break; - case DL_SURF: - - if (dl->index) { - if (col != dl->col) { - GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL); - col = dl->col; - } - /* FLAT/SMOOTH shading for surfaces */ - glShadeModel((dl->rt & CU_SMOOTH) ? GL_SMOOTH : GL_FLAT); - - glEnableClientState(GL_NORMAL_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, dl->verts); - glNormalPointer(GL_FLOAT, 0, dl->nors); - glDrawElements(GL_QUADS, 4 * dl->totindex, GL_UNSIGNED_INT, dl->index); - glDisableClientState(GL_NORMAL_ARRAY); - glShadeModel(GL_SMOOTH); - } - break; - - case DL_INDEX3: - if (col != dl->col) { - GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL); - col = dl->col; - } - - glVertexPointer(3, GL_FLOAT, 0, dl->verts); - - /* for polys only one normal needed */ - if (index3_nors_incr) { - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, 0, dl->nors); - } - else - glNormal3fv(ndata); - - glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index); - - if (index3_nors_incr) - glDisableClientState(GL_NORMAL_ARRAY); - - break; - - case DL_INDEX4: - if (col != dl->col) { - GPU_object_material_bind(dl->col + 1, use_glsl ? &gattribs : NULL); - col = dl->col; - } - - glEnableClientState(GL_NORMAL_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, dl->verts); - glNormalPointer(GL_FLOAT, 0, dl->nors); - glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index); - glDisableClientState(GL_NORMAL_ARRAY); - - break; - } - dl = dl->next; - } - - glDisableClientState(GL_VERTEX_ARRAY); - glFrontFace(GL_CCW); - - if (col != -1) { - GPU_object_material_unbind(); - } -} - -static void drawCurveDMWired(Object *ob) -{ - DerivedMesh *dm = ob->derivedFinal; - dm->drawEdges(dm, 1, 0); -} - -/* return true when nothing was drawn */ -static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, const char dt) -{ - Object *ob = base->object; - DerivedMesh *dm = ob->derivedFinal; - - if (!dm) { - return true; - } - - DM_update_materials(dm, ob); - - glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - - if (dt > OB_WIRE && dm->getNumPolys(dm)) { - bool glsl = draw_glsl_material(scene, ob, v3d, dt); - GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); - - if (!glsl) - dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); - else - dm->drawFacesGLSL(dm, GPU_object_material_bind); - - GPU_end_object_materials(); - } - else { - if (((v3d->flag2 & V3D_RENDER_OVERRIDE) && v3d->drawtype >= OB_SOLID) == 0) - drawCurveDMWired(ob); - } - - return false; -} - -/** - * Only called by #drawDispList - * \return true when nothing was drawn - */ -static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const short dflag, const unsigned char ob_wire_col[4]) -{ - Object *ob = base->object; - ListBase *lb = NULL; - DispList *dl; - Curve *cu; - const bool render_only = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0; - const bool solid = (dt > OB_WIRE); - - switch (ob->type) { - case OB_FONT: - case OB_CURVE: - cu = ob->data; - - lb = &ob->curve_cache->disp; - - if (solid) { - const bool has_faces = BKE_displist_has_faces(lb); - dl = lb->first; - if (dl == NULL) { - return true; - } - - if (dl->nors == NULL) BKE_displist_normals_add(lb); - index3_nors_incr = false; - - if (!render_only) { - /* when we have faces, only draw loose-wire */ - if (has_faces) { - drawDispListwire_ex(lb, (1 << DL_SEGM)); - } - else { - drawDispListwire(lb, ob->type); - } - } - - if (has_faces == false) { - /* pass */ - } - else { - if (draw_glsl_material(scene, ob, v3d, dt)) { - GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL); - drawDispListsolid(lb, ob, dflag, ob_wire_col, true); - GPU_end_object_materials(); - } - else { - GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL); - drawDispListsolid(lb, ob, dflag, ob_wire_col, false); - GPU_end_object_materials(); - } - if (cu->editnurb && cu->bevobj == NULL && cu->taperobj == NULL && cu->ext1 == 0.0f && cu->ext2 == 0.0f) { - cpack(0); - drawDispListwire(lb, ob->type); - } - } - index3_nors_incr = true; - } - else { - if (!render_only || BKE_displist_has_faces(lb)) { - return drawDispListwire(lb, ob->type); - } - } - break; - case OB_SURF: - - lb = &ob->curve_cache->disp; - - if (solid) { - dl = lb->first; - if (dl == NULL) { - return true; - } - - if (dl->nors == NULL) BKE_displist_normals_add(lb); - - if (draw_glsl_material(scene, ob, v3d, dt)) { - GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL); - drawDispListsolid(lb, ob, dflag, ob_wire_col, true); - GPU_end_object_materials(); - } - else { - GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL); - drawDispListsolid(lb, ob, dflag, ob_wire_col, false); - GPU_end_object_materials(); - } - } - else { - return drawDispListwire(lb, ob->type); - } - break; - case OB_MBALL: - - if (BKE_mball_is_basis(ob)) { - lb = &ob->curve_cache->disp; - if (BLI_listbase_is_empty(lb)) { - return true; - } - - if (solid) { - - if (draw_glsl_material(scene, ob, v3d, dt)) { - GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL); - drawDispListsolid(lb, ob, dflag, ob_wire_col, true); - GPU_end_object_materials(); - } - else { - GPU_begin_object_materials(v3d, rv3d, scene, ob, 0, NULL); - drawDispListsolid(lb, ob, dflag, ob_wire_col, false); - GPU_end_object_materials(); - } - } - else { - return drawDispListwire(lb, ob->type); - } - } - break; - } - - return false; -} -static bool drawDispList(Main *bmain, Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const short dflag, const unsigned char ob_wire_col[4]) -{ - bool retval; - - /* backface culling */ - if (v3d->flag2 & V3D_BACKFACE_CULLING) { - /* not all displists use same in/out normal direction convention */ - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - } - -#ifdef SEQUENCER_DAG_WORKAROUND - ensure_curve_cache(bmain, scene, base->object); -#endif - - if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) { - retval = false; - } - else { - Object *ob = base->object; - GLenum mode; - - if (ob->type == OB_MBALL) { - mode = (ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW; - } - else { - mode = (ob->transflag & OB_NEG_SCALE) ? GL_CCW : GL_CW; - } - - glFrontFace(mode); - - retval = drawDispList_nobackface(scene, v3d, rv3d, base, dt, dflag, ob_wire_col); - - if (mode != GL_CCW) { - glFrontFace(GL_CCW); - } - } - - if (v3d->flag2 & V3D_BACKFACE_CULLING) { - glDisable(GL_CULL_FACE); - } - - return retval; -} - -/* *********** drawing for particles ************* */ -static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int select) -{ - /* draw created data arrays */ - switch (draw_as) { - case PART_DRAW_AXIS: - case PART_DRAW_CROSS: - glDrawArrays(GL_LINES, 0, 6 * totpoint); - break; - case PART_DRAW_LINE: - glDrawArrays(GL_LINES, 0, 2 * totpoint); - break; - case PART_DRAW_BB: - if (ob_dt <= OB_WIRE || select) - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - else - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - glDrawArrays(GL_QUADS, 0, 4 * totpoint); - break; - default: - glDrawArrays(GL_POINTS, 0, totpoint); - break; - } -} -static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, - float imat[4][4], const float draw_line[2], ParticleBillboardData *bb, ParticleDrawData *pdd) -{ - float vec[3], vec2[3]; - float *vd = NULL; - float *cd = NULL; - float ma_col[3] = {0.0f, 0.0f, 0.0f}; - - /* null only for PART_DRAW_CIRC */ - if (pdd) { - vd = pdd->vd; - cd = pdd->cd; - - if (pdd->ma_col) { - copy_v3_v3(ma_col, pdd->ma_col); - } - } - - switch (draw_as) { - case PART_DRAW_DOT: - { - if (vd) { - copy_v3_v3(vd, state->co); pdd->vd += 3; - } - if (cd) { - copy_v3_v3(cd, pdd->ma_col); - pdd->cd += 3; - } - break; - } - case PART_DRAW_CROSS: - case PART_DRAW_AXIS: - { - vec[0] = 2.0f * pixsize; - vec[1] = vec[2] = 0.0; - mul_qt_v3(state->rot, vec); - if (draw_as == PART_DRAW_AXIS) { - if (cd) { - cd[1] = cd[2] = cd[4] = cd[5] = 0.0; - cd[0] = cd[3] = 1.0; - cd[6] = cd[8] = cd[9] = cd[11] = 0.0; - cd[7] = cd[10] = 1.0; - cd[13] = cd[12] = cd[15] = cd[16] = 0.0; - cd[14] = cd[17] = 1.0; - pdd->cd += 18; - } - - copy_v3_v3(vec2, state->co); - } - else { - if (cd) { - cd[0] = cd[3] = cd[6] = cd[9] = cd[12] = cd[15] = ma_col[0]; - cd[1] = cd[4] = cd[7] = cd[10] = cd[13] = cd[16] = ma_col[1]; - cd[2] = cd[5] = cd[8] = cd[11] = cd[14] = cd[17] = ma_col[2]; - pdd->cd += 18; - } - sub_v3_v3v3(vec2, state->co, vec); - } - - add_v3_v3(vec, state->co); - copy_v3_v3(pdd->vd, vec); pdd->vd += 3; - copy_v3_v3(pdd->vd, vec2); pdd->vd += 3; - - vec[1] = 2.0f * pixsize; - vec[0] = vec[2] = 0.0; - mul_qt_v3(state->rot, vec); - if (draw_as == PART_DRAW_AXIS) { - copy_v3_v3(vec2, state->co); - } - else { - sub_v3_v3v3(vec2, state->co, vec); - } - - add_v3_v3(vec, state->co); - copy_v3_v3(pdd->vd, vec); pdd->vd += 3; - copy_v3_v3(pdd->vd, vec2); pdd->vd += 3; - - vec[2] = 2.0f * pixsize; - vec[0] = vec[1] = 0.0f; - mul_qt_v3(state->rot, vec); - if (draw_as == PART_DRAW_AXIS) { - copy_v3_v3(vec2, state->co); - } - else { - sub_v3_v3v3(vec2, state->co, vec); - } - - add_v3_v3(vec, state->co); - - copy_v3_v3(pdd->vd, vec); pdd->vd += 3; - copy_v3_v3(pdd->vd, vec2); pdd->vd += 3; - break; - } - case PART_DRAW_LINE: - { - copy_v3_v3(vec, state->vel); - normalize_v3(vec); - if (draw & PART_DRAW_VEL_LENGTH) - mul_v3_fl(vec, len_v3(state->vel)); - madd_v3_v3v3fl(pdd->vd, state->co, vec, -draw_line[0]); pdd->vd += 3; - madd_v3_v3v3fl(pdd->vd, state->co, vec, draw_line[1]); pdd->vd += 3; - if (cd) { - cd[0] = cd[3] = ma_col[0]; - cd[1] = cd[4] = ma_col[1]; - cd[2] = cd[5] = ma_col[2]; - pdd->cd += 6; - } - break; - } - case PART_DRAW_CIRC: - { - drawcircball(GL_LINE_LOOP, state->co, pixsize, imat); - break; - } - case PART_DRAW_BB: - { - float xvec[3], yvec[3], zvec[3], bb_center[3]; - if (cd) { - cd[0] = cd[3] = cd[6] = cd[9] = ma_col[0]; - cd[1] = cd[4] = cd[7] = cd[10] = ma_col[1]; - cd[2] = cd[5] = cd[8] = cd[11] = ma_col[2]; - pdd->cd += 12; - } - - copy_v3_v3(bb->vec, state->co); - copy_v3_v3(bb->vel, state->vel); - - psys_make_billboard(bb, xvec, yvec, zvec, bb_center); - - add_v3_v3v3(pdd->vd, bb_center, xvec); - add_v3_v3(pdd->vd, yvec); pdd->vd += 3; - - sub_v3_v3v3(pdd->vd, bb_center, xvec); - add_v3_v3(pdd->vd, yvec); pdd->vd += 3; - - sub_v3_v3v3(pdd->vd, bb_center, xvec); - sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3; - - add_v3_v3v3(pdd->vd, bb_center, xvec); - sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3; - - copy_v3_v3(pdd->nd, zvec); pdd->nd += 3; - copy_v3_v3(pdd->nd, zvec); pdd->nd += 3; - copy_v3_v3(pdd->nd, zvec); pdd->nd += 3; - copy_v3_v3(pdd->nd, zvec); pdd->nd += 3; - break; - } - } -} -static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d, - ParticleKey *state, int draw_as, - float imat[4][4], ParticleBillboardData *bb, ParticleDrawData *pdd, - const float ct, const float pa_size, const float r_tilt, const float pixsize_scale) -{ - ParticleSettings *part = psys->part; - float pixsize; - - if (psys->parent) - mul_m4_v3(psys->parent->obmat, state->co); - - /* create actual particle data */ - if (draw_as == PART_DRAW_BB) { - bb->offset[0] = part->bb_offset[0]; - bb->offset[1] = part->bb_offset[1]; - bb->size[0] = part->bb_size[0] * pa_size; - if (part->bb_align == PART_BB_VEL) { - float pa_vel = len_v3(state->vel); - float head = part->bb_vel_head * pa_vel; - float tail = part->bb_vel_tail * pa_vel; - bb->size[1] = part->bb_size[1] * pa_size + head + tail; - /* use offset to adjust the particle center. this is relative to size, so need to divide! */ - if (bb->size[1] > 0.0f) - bb->offset[1] += (head - tail) / bb->size[1]; - } - else { - bb->size[1] = part->bb_size[1] * pa_size; - } - bb->tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); - bb->time = ct; - } - - pixsize = ED_view3d_pixel_size(rv3d, state->co) * pixsize_scale; - - draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd); -} -/* unified drawing of all new particle systems draw types except dupli ob & group - * mostly tries to use vertex arrays for speed - * - * 1. check that everything is ok & updated - * 2. start initializing things - * 3. initialize according to draw type - * 4. allocate drawing data arrays - * 5. start filling the arrays - * 6. draw the arrays - * 7. clean up - */ -static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d, - Base *base, ParticleSystem *psys, - const char ob_dt, const short dflag) -{ - Object *ob = base->object; - ParticleEditSettings *pset = PE_settings(scene); - ParticleSettings *part = psys->part; - ParticleData *pars = psys->particles; - ParticleData *pa; - ParticleKey state, *states = NULL; - ParticleBillboardData bb; - ParticleSimulationData sim = {NULL}; - ParticleDrawData *pdd = psys->pdd; - Material *ma; - float vel[3], imat[4][4]; - float timestep, pixsize_scale = 1.0f, pa_size, r_tilt, r_length; - float pa_time, pa_birthtime, pa_dietime, pa_health, intensity; - float cfra; - float ma_col[3] = {0.0f, 0.0f, 0.0f}; - int a, totpart, totpoint = 0, totve = 0, drawn, draw_as, totchild = 0; - bool select = (ob->flag & SELECT) != 0, create_cdata = false, need_v = false; - GLint polygonmode[2]; - char numstr[32]; - unsigned char tcol[4] = {0, 0, 0, 255}; - -/* 1. */ - if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering)) - return; - - if (pars == NULL) return; - - /* don't draw normal paths in edit mode */ - if (psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART) == 0) - return; - - if (part->draw_as == PART_DRAW_REND) - draw_as = part->ren_as; - else - draw_as = part->draw_as; - - if (draw_as == PART_DRAW_NOT) - return; - - /* prepare curvemapping tables */ - if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) - curvemapping_changed_all(psys->part->clumpcurve); - if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) - curvemapping_changed_all(psys->part->roughcurve); - if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) - curvemapping_changed_all(psys->part->twistcurve); - -/* 2. */ - sim.scene = scene; - sim.ob = ob; - sim.psys = psys; - sim.psmd = psys_get_modifier(ob, psys); - - if (part->phystype == PART_PHYS_KEYED) { - if (psys->flag & PSYS_KEYED) { - psys_count_keyed_targets(&sim); - if (psys->totkeyed == 0) - return; - } - } - - if (select) { - select = false; - if (psys_get_current(ob) == psys) - select = true; - } - - psys->flag |= PSYS_DRAWING; - - if (part->type == PART_HAIR && !psys->childcache) - totchild = 0; - else - totchild = psys->totchild * part->disp / 100; - - ma = give_current_material(ob, part->omat); - - if (v3d->zbuf) glDepthMask(1); - - if ((ma) && (part->draw_col == PART_DRAW_COL_MAT)) { - rgb_float_to_uchar(tcol, &(ma->r)); - copy_v3_v3(ma_col, &ma->r); - } - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(tcol); - } - - timestep = psys_get_timestep(&sim); - - if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) { - float mat[4][4]; - mul_m4_m4m4(mat, ob->obmat, psys->imat); - glMultMatrixf(mat); - } - - /* needed for text display */ - invert_m4_m4(ob->imat, ob->obmat); - - totpart = psys->totpart; - - cfra = BKE_scene_frame_get(scene); - - if (draw_as == PART_DRAW_PATH && psys->pathcache == NULL && psys->childcache == NULL) - draw_as = PART_DRAW_DOT; - -/* 3. */ - glLineWidth(1.0f); - - switch (draw_as) { - case PART_DRAW_DOT: - if (part->draw_size) - glPointSize(part->draw_size); - else - glPointSize(2.0); /* default dot size */ - break; - case PART_DRAW_CIRC: - /* calculate view aligned matrix: */ - copy_m4_m4(imat, rv3d->viewinv); - normalize_v3(imat[0]); - normalize_v3(imat[1]); - ATTR_FALLTHROUGH; - case PART_DRAW_CROSS: - case PART_DRAW_AXIS: - /* lets calculate the scale: */ - - if (part->draw_size == 0.0) - pixsize_scale = 2.0f; - else - pixsize_scale = part->draw_size; - - if (draw_as == PART_DRAW_AXIS) - create_cdata = 1; - break; - case PART_DRAW_OB: - if (part->dup_ob == NULL) - draw_as = PART_DRAW_DOT; - else - draw_as = 0; - break; - case PART_DRAW_GR: - if (part->dup_group == NULL) - draw_as = PART_DRAW_DOT; - else - draw_as = 0; - break; - case PART_DRAW_BB: - if (v3d->camera == NULL && part->bb_ob == NULL) { - printf("Billboards need an active camera or a target object!\n"); - - draw_as = part->draw_as = PART_DRAW_DOT; - - if (part->draw_size) - glPointSize(part->draw_size); - else - glPointSize(2.0); /* default dot size */ - } - else if (part->bb_ob) - bb.ob = part->bb_ob; - else - bb.ob = v3d->camera; - - bb.align = part->bb_align; - bb.anim = part->bb_anim; - bb.lock = part->draw & PART_DRAW_BB_LOCK; - break; - case PART_DRAW_PATH: - break; - case PART_DRAW_LINE: - need_v = 1; - break; - } - if (part->draw & PART_DRAW_SIZE && part->draw_as != PART_DRAW_CIRC) { - copy_m4_m4(imat, rv3d->viewinv); - normalize_v3(imat[0]); - normalize_v3(imat[1]); - } - - if (ELEM(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) && - (part->draw_col > PART_DRAW_COL_MAT)) - { - create_cdata = 1; - } - - if (!create_cdata && pdd && pdd->cdata) { - MEM_freeN(pdd->cdata); - pdd->cdata = pdd->cd = NULL; - } - -/* 4. */ - if (draw_as && ELEM(draw_as, PART_DRAW_PATH, PART_DRAW_CIRC) == 0) { - int partsize = 3 * sizeof(float); - int create_ndata = 0; - - if (!pdd) - pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData"); - - if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) { - partsize *= part->trail_count; - psys_make_temp_pointcache(ob, psys); - } - - switch (draw_as) { - case PART_DRAW_AXIS: - case PART_DRAW_CROSS: - partsize *= 6; - if (draw_as != PART_DRAW_CROSS) - create_cdata = 1; - break; - case PART_DRAW_LINE: - partsize *= 2; - break; - case PART_DRAW_BB: - partsize *= 4; - create_ndata = 1; - break; - } - - if (pdd->totpart != totpart + totchild || pdd->partsize != partsize) - psys_free_pdd(psys); - - if (!pdd->vdata) - pdd->vdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_vdata"); - if (create_cdata && !pdd->cdata) - pdd->cdata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_cdata"); - if (create_ndata && !pdd->ndata) - pdd->ndata = MEM_calloc_arrayN(totpart + totchild, partsize, "particle_ndata"); - - if (part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) { - if (!pdd->vedata) - pdd->vedata = MEM_calloc_arrayN(totpart + totchild, 2 * 3 * sizeof(float), "particle_vedata"); - - need_v = 1; - } - else if (pdd->vedata) { - /* velocity data not needed, so free it */ - MEM_freeN(pdd->vedata); - pdd->vedata = NULL; - } - - pdd->vd = pdd->vdata; - pdd->ved = pdd->vedata; - pdd->cd = pdd->cdata; - pdd->nd = pdd->ndata; - pdd->totpart = totpart + totchild; - pdd->partsize = partsize; - } - else if (psys->pdd) { - psys_free_pdd(psys); - MEM_freeN(psys->pdd); - pdd = psys->pdd = NULL; - } - - if (pdd) { - pdd->ma_col = ma_col; - } - - psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - - /* circles don't use drawdata, so have to add a special case here */ - if ((pdd || draw_as == PART_DRAW_CIRC) && draw_as != PART_DRAW_PATH) { - /* 5. */ - if (pdd && (pdd->flag & PARTICLE_DRAW_DATA_UPDATED) && - (pdd->vedata || part->draw & (PART_DRAW_SIZE | PART_DRAW_NUM | PART_DRAW_HEALTH)) == 0) - { - totpoint = pdd->totpoint; /* draw data is up to date */ - } - else { - for (a = 0, pa = pars; a < totpart + totchild; a++, pa++) { - /* setup per particle individual stuff */ - if (a < totpart) { - if (totchild && (part->draw & PART_DRAW_PARENT) == 0) continue; - if (pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue; - - pa_time = (cfra - pa->time) / pa->lifetime; - pa_birthtime = pa->time; - pa_dietime = pa->dietime; - pa_size = pa->size; - if (part->phystype == PART_PHYS_BOIDS) - pa_health = pa->boid->data.health; - else - pa_health = -1.0; - - r_tilt = 2.0f * (psys_frand(psys, a + 21) - 0.5f); - r_length = psys_frand(psys, a + 22); - - if (part->draw_col > PART_DRAW_COL_MAT) { - switch (part->draw_col) { - case PART_DRAW_COL_VEL: - intensity = len_v3(pa->state.vel) / part->color_vec_max; - break; - case PART_DRAW_COL_ACC: - intensity = len_v3v3(pa->state.vel, pa->prev_state.vel) / ((pa->state.time - pa->prev_state.time) * part->color_vec_max); - break; - default: - intensity = 1.0f; /* should never happen */ - BLI_assert(0); - break; - } - CLAMP(intensity, 0.0f, 1.0f); - weight_to_rgb(ma_col, intensity); - } - } - else { - ChildParticle *cpa = &psys->child[a - totpart]; - - pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); - pa_size = psys_get_child_size(psys, cpa, cfra, NULL); - - pa_health = -1.0; - - r_tilt = 2.0f * (psys_frand(psys, a + 21) - 0.5f); - r_length = psys_frand(psys, a + 22); - } - - drawn = 0; - if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) { - float length = part->path_end * (1.0f - part->randlength * r_length); - int trail_count = part->trail_count * (1.0f - part->randlength * r_length); - float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length; - float dt = length / (trail_count ? (float)trail_count : 1.0f); - int i = 0; - - ct += dt; - for (i = 0; i < trail_count; i++, ct += dt) { - - if (part->draw & PART_ABS_PATH_TIME) { - if (ct < pa_birthtime || ct > pa_dietime) - continue; - } - else if (ct < 0.0f || ct > 1.0f) - continue; - - state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime)); - psys_get_particle_on_path(&sim, a, &state, need_v); - - draw_particle_data(psys, rv3d, - &state, draw_as, imat, &bb, psys->pdd, - ct, pa_size, r_tilt, pixsize_scale); - - totpoint++; - drawn = 1; - } - } - else { - state.time = cfra; - if (psys_get_particle_state(&sim, a, &state, 0)) { - - draw_particle_data(psys, rv3d, - &state, draw_as, imat, &bb, psys->pdd, - pa_time, pa_size, r_tilt, pixsize_scale); - - totpoint++; - drawn = 1; - } - } - - if (drawn) { - /* additional things to draw for each particle - * (velocity, size and number) */ - if ((part->draw & PART_DRAW_VEL) && pdd && pdd->vedata) { - copy_v3_v3(pdd->ved, state.co); - pdd->ved += 3; - mul_v3_v3fl(vel, state.vel, timestep); - add_v3_v3v3(pdd->ved, state.co, vel); - pdd->ved += 3; - - totve++; - } - - if (part->draw & PART_DRAW_SIZE) { - setlinestyle(3); - drawcircball(GL_LINE_LOOP, state.co, pa_size, imat); - setlinestyle(0); - } - - - if ((part->draw & PART_DRAW_NUM || part->draw & PART_DRAW_HEALTH) && - (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) - { - size_t numstr_len; - float vec_txt[3]; - char *val_pos = numstr; - numstr[0] = '\0'; - - if (part->draw & PART_DRAW_NUM) { - if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) { - numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health); - } - else { - numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d", a); - } - } - else { - if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) { - numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%.2f", pa_health); - } - } - - if (numstr[0]) { - /* in path drawing state.co is the end point - * use worldspace because object matrix is already applied */ - mul_v3_m4v3(vec_txt, ob->imat, state.co); - view3d_cached_text_draw_add(vec_txt, numstr, numstr_len, - 10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol); - } - } - } - } - } - } -/* 6. */ - - glGetIntegerv(GL_POLYGON_MODE, polygonmode); - glEnableClientState(GL_VERTEX_ARRAY); - - if (draw_as == PART_DRAW_PATH) { - ParticleCacheKey **cache, *path; - float *cdata2 = NULL; - - /* setup gl flags */ - if (1) { //ob_dt > OB_WIRE) { - glEnableClientState(GL_NORMAL_ARRAY); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (part->draw_col == PART_DRAW_COL_MAT) - glEnableClientState(GL_COLOR_ARRAY); - } - - // XXX test - GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f); - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - } - - if (totchild && (part->draw & PART_DRAW_PARENT) == 0) - totpart = 0; - else if (psys->pathcache == NULL) - totpart = 0; - - /* draw actual/parent particles */ - cache = psys->pathcache; - for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { - path = cache[a]; - if (path->segments > 0) { - glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); - - if (1) { //ob_dt > OB_WIRE) { - glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (part->draw_col == PART_DRAW_COL_MAT) { - glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); - } - } - } - - glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1); - } - } - - if (part->type == PART_HAIR) { - if (part->draw & PART_DRAW_GUIDE_HAIRS) { - DerivedMesh *hair_dm = psys->hair_out_dm; - - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { - if (pa->totkey > 1) { - HairKey *hkey = pa->hair; - - glVertexPointer(3, GL_FLOAT, sizeof(HairKey), hkey->world_co); - -#if 0 /* XXX use proper theme color here */ - UI_ThemeColor(TH_NORMAL); -#else - glColor3f(0.58f, 0.67f, 1.0f); -#endif - - glDrawArrays(GL_LINE_STRIP, 0, pa->totkey); - } - } - - if (hair_dm) { - MVert *mvert = hair_dm->getVertArray(hair_dm); - int i; - - glColor3f(0.9f, 0.4f, 0.4f); - - glBegin(GL_LINES); - for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { - for (i = 1; i < pa->totkey; ++i) { - float v1[3], v2[3]; - - copy_v3_v3(v1, mvert[pa->hair_index + i - 1].co); - copy_v3_v3(v2, mvert[pa->hair_index + i].co); - - mul_m4_v3(ob->obmat, v1); - mul_m4_v3(ob->obmat, v2); - - glVertex3fv(v1); - glVertex3fv(v2); - } - } - glEnd(); - } - - glEnableClientState(GL_NORMAL_ARRAY); - if ((dflag & DRAW_CONSTCOLOR) == 0) - if (part->draw_col == PART_DRAW_COL_MAT) - glEnableClientState(GL_COLOR_ARRAY); - } - - if (part->draw & PART_DRAW_HAIR_GRID) { - ClothModifierData *clmd = psys->clmd; - if (clmd) { - float *gmin = clmd->hair_grid_min; - float *gmax = clmd->hair_grid_max; - int *res = clmd->hair_grid_res; - int i; - - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - if (select) - UI_ThemeColor(TH_ACTIVE); - else - UI_ThemeColor(TH_WIRE); - glBegin(GL_LINES); - glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmin[2]); - glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmin[2]); - glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmin[2]); - glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmin[2]); - - glVertex3f(gmin[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmin[1], gmax[2]); - glVertex3f(gmax[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmax[1], gmax[2]); - glVertex3f(gmax[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmax[1], gmax[2]); - glVertex3f(gmin[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmin[1], gmax[2]); - - glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmax[2]); - glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmax[2]); - glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmax[2]); - glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmax[2]); - glEnd(); - - if (select) - UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -100); - else - UI_ThemeColorShadeAlpha(TH_WIRE, 0, -100); - glEnable(GL_BLEND); - glBegin(GL_LINES); - for (i = 1; i < res[0] - 1; ++i) { - float f = interpf(gmax[0], gmin[0], (float)i / (float)(res[0] - 1)); - glVertex3f(f, gmin[1], gmin[2]); glVertex3f(f, gmax[1], gmin[2]); - glVertex3f(f, gmax[1], gmin[2]); glVertex3f(f, gmax[1], gmax[2]); - glVertex3f(f, gmax[1], gmax[2]); glVertex3f(f, gmin[1], gmax[2]); - glVertex3f(f, gmin[1], gmax[2]); glVertex3f(f, gmin[1], gmin[2]); - } - for (i = 1; i < res[1] - 1; ++i) { - float f = interpf(gmax[1], gmin[1], (float)i / (float)(res[1] - 1)); - glVertex3f(gmin[0], f, gmin[2]); glVertex3f(gmax[0], f, gmin[2]); - glVertex3f(gmax[0], f, gmin[2]); glVertex3f(gmax[0], f, gmax[2]); - glVertex3f(gmax[0], f, gmax[2]); glVertex3f(gmin[0], f, gmax[2]); - glVertex3f(gmin[0], f, gmax[2]); glVertex3f(gmin[0], f, gmin[2]); - } - for (i = 1; i < res[2] - 1; ++i) { - float f = interpf(gmax[2], gmin[2], (float)i / (float)(res[2] - 1)); - glVertex3f(gmin[0], gmin[1], f); glVertex3f(gmax[0], gmin[1], f); - glVertex3f(gmax[0], gmin[1], f); glVertex3f(gmax[0], gmax[1], f); - glVertex3f(gmax[0], gmax[1], f); glVertex3f(gmin[0], gmax[1], f); - glVertex3f(gmin[0], gmax[1], f); glVertex3f(gmin[0], gmin[1], f); - } - glEnd(); - glDisable(GL_BLEND); - - glEnableClientState(GL_NORMAL_ARRAY); - if ((dflag & DRAW_CONSTCOLOR) == 0) - if (part->draw_col == PART_DRAW_COL_MAT) - glEnableClientState(GL_COLOR_ARRAY); - } - } - } - - /* draw child particles */ - cache = psys->childcache; - for (a = 0; a < totchild; a++) { - path = cache[a]; - glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); - - if (1) { //ob_dt > OB_WIRE) { - glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (part->draw_col == PART_DRAW_COL_MAT) { - glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); - } - } - } - - glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1); - } - - /* restore & clean up */ - if (1) { //ob_dt > OB_WIRE) { - if (part->draw_col == PART_DRAW_COL_MAT) - glDisableClientState(GL_COLOR_ARRAY); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - } - - if (cdata2) { - MEM_freeN(cdata2); - cdata2 = NULL; - } - - if ((part->draw & PART_DRAW_NUM) && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - cache = psys->pathcache; - - for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { - float vec_txt[3]; - size_t numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%i", a); - /* use worldspace because object matrix is already applied */ - mul_v3_m4v3(vec_txt, ob->imat, cache[a]->co); - view3d_cached_text_draw_add(vec_txt, numstr, numstr_len, - 10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol); - } - } - } - else if (pdd && ELEM(draw_as, 0, PART_DRAW_CIRC) == 0) { - glDisableClientState(GL_COLOR_ARRAY); - - /* enable point data array */ - if (pdd->vdata) { - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, pdd->vdata); - } - else - glDisableClientState(GL_VERTEX_ARRAY); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (select) { - UI_ThemeColor(TH_ACTIVE); - - if (part->draw_size) - glPointSize(part->draw_size + 2); - else - glPointSize(4.0); - - glLineWidth(3.0); - - draw_particle_arrays(draw_as, totpoint, ob_dt, 1); - } - - /* restore from select */ - glColor3fv(ma_col); - } - - glPointSize(part->draw_size ? part->draw_size : 2.0); - glLineWidth(1.0); - - /* enable other data arrays */ - - /* billboards are drawn this way */ - if (pdd->ndata && ob_dt > OB_WIRE) { - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, 0, pdd->ndata); - GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f); - GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - } - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if (pdd->cdata) { - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(3, GL_FLOAT, 0, pdd->cdata); - } - } - - draw_particle_arrays(draw_as, totpoint, ob_dt, 0); - - pdd->flag |= PARTICLE_DRAW_DATA_UPDATED; - pdd->totpoint = totpoint; - } - - if (pdd && pdd->vedata) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glDisableClientState(GL_COLOR_ARRAY); - cpack(0xC0C0C0); - } - - glVertexPointer(3, GL_FLOAT, 0, pdd->vedata); - - glDrawArrays(GL_LINES, 0, 2 * totve); - } - - glPolygonMode(GL_FRONT, polygonmode[0]); - glPolygonMode(GL_BACK, polygonmode[1]); - -/* 7. */ - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - - if (states) - MEM_freeN(states); - - psys->flag &= ~PSYS_DRAWING; - - /* draw data can't be saved for billboards as they must update to target changes */ - if (draw_as == PART_DRAW_BB) { - psys_free_pdd(psys); - pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; - } - - if (psys->lattice_deform_data) { - end_latt_deform(psys->lattice_deform_data); - psys->lattice_deform_data = NULL; - } - - if (pdd) { - /* drop references to stack memory */ - pdd->ma_col = NULL; - } - - if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) { - glLoadMatrixf(rv3d->viewmat); - } -} - -static void draw_update_ptcache_edit(Main *bmain, Scene *scene, Object *ob, PTCacheEdit *edit) -{ - if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED) - PE_update_object(bmain, scene, ob, 0); - - /* create path and child path cache if it doesn't exist already */ - if (edit->pathcache == NULL) - psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering); -} - -static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) -{ - ParticleCacheKey **cache, *path, *pkey; - PTCacheEditPoint *point; - PTCacheEditKey *key; - ParticleEditSettings *pset = PE_settings(scene); - int i, k, totpoint = edit->totpoint, timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : 0; - int totkeys = 1; - float sel_col[3]; - float nosel_col[3]; - float *pathcol = NULL, *pcol; - - if (edit->pathcache == NULL) - return; - - PE_hide_keys_time(scene, edit, CFRA); - - /* opengl setup */ - if ((v3d->flag & V3D_ZBUF_SELECT) == 0) - glDisable(GL_DEPTH_TEST); - - /* get selection theme colors */ - UI_GetThemeColor3fv(TH_VERTEX_SELECT, sel_col); - UI_GetThemeColor3fv(TH_VERTEX, nosel_col); - - /* draw paths */ - totkeys = (*edit->pathcache)->segments + 1; - - glEnable(GL_BLEND); - pathcol = MEM_calloc_arrayN(totkeys, 4 * sizeof(float), "particle path color data"); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - if (pset->brushtype == PE_BRUSH_WEIGHT) - glLineWidth(2.0f); - - cache = edit->pathcache; - for (i = 0, point = edit->points; i < totpoint; i++, point++) { - path = cache[i]; - glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); - - if (point->flag & PEP_HIDE) { - for (k = 0, pcol = pathcol; k < totkeys; k++, pcol += 4) { - copy_v3_v3(pcol, path->col); - pcol[3] = 0.25f; - } - - glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol); - } - else if (timed) { - for (k = 0, pcol = pathcol, pkey = path; k < totkeys; k++, pkey++, pcol += 4) { - copy_v3_v3(pcol, pkey->col); - pcol[3] = 1.0f - fabsf((float)(CFRA) -pkey->time) / (float)pset->fade_frames; - } - - glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol); - } - else - glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); - - glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1); - } - - if (pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; } - - - /* draw edit vertices */ - if (pset->selectmode != SCE_SELECT_PATH) { - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - - if (pset->selectmode == SCE_SELECT_POINT) { - float *pd = NULL, *pdata = NULL; - float *cd = NULL, *cdata = NULL; - int totkeys_visible = 0; - - for (i = 0, point = edit->points; i < totpoint; i++, point++) - if (!(point->flag & PEP_HIDE)) - totkeys_visible += point->totkey; - - if (totkeys_visible) { - if (edit->points && !(edit->points->keys->flag & PEK_USE_WCO)) - pd = pdata = MEM_calloc_arrayN(totkeys_visible, 3 * sizeof(float), "particle edit point data"); - cd = cdata = MEM_calloc_arrayN(totkeys_visible, (timed ? 4 : 3) * sizeof(float), "particle edit color data"); - } - - for (i = 0, point = edit->points; i < totpoint; i++, point++) { - if (point->flag & PEP_HIDE) - continue; - - for (k = 0, key = point->keys; k < point->totkey; k++, key++) { - if (pd) { - copy_v3_v3(pd, key->co); - pd += 3; - } - - if (key->flag & PEK_SELECT) { - copy_v3_v3(cd, sel_col); - } - else { - copy_v3_v3(cd, nosel_col); - } - - if (timed) - *(cd + 3) = 1.0f - fabsf((float)CFRA - *key->time) / (float)pset->fade_frames; - - cd += (timed ? 4 : 3); - } - } - cd = cdata; - pd = pdata; - for (i = 0, point = edit->points; i < totpoint; i++, point++) { - if (point->flag & PEP_HIDE || point->totkey == 0) - continue; - - if (point->keys->flag & PEK_USE_WCO) - glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co); - else - glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), pd); - - glColorPointer((timed ? 4 : 3), GL_FLOAT, (timed ? 4 : 3) * sizeof(float), cd); - - glDrawArrays(GL_POINTS, 0, point->totkey); - - pd += pd ? 3 * point->totkey : 0; - cd += (timed ? 4 : 3) * point->totkey; - } - if (pdata) { MEM_freeN(pdata); pd = pdata = NULL; } - if (cdata) { MEM_freeN(cdata); cd = cdata = NULL; } - } - else if (pset->selectmode == SCE_SELECT_END) { - glBegin(GL_POINTS); - for (i = 0, point = edit->points; i < totpoint; i++, point++) { - if ((point->flag & PEP_HIDE) == 0 && point->totkey) { - key = point->keys + point->totkey - 1; - glColor3fv((key->flag & PEK_SELECT) ? sel_col : nosel_col); - /* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/ - glVertex3fv((key->flag & PEK_USE_WCO) ? key->world_co : key->co); - } - } - glEnd(); - } - } - - glDisable(GL_BLEND); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); -} - -static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, float ith, float drw_size) -{ - float tr[3][3]; - float root[3], tip[3]; - /* take a copy for not spoiling original */ - copy_m3_m3(tr, rotscale); - float tw = itw * drw_size; - float th = ith * drw_size; - - glBegin(GL_LINES); - - glColor4ub(0x7F, 0x00, 0x00, 155); - root[1] = root[2] = 0.0f; - root[0] = -drw_size; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - tip[1] = tip[2] = 0.0f; - tip[0] = drw_size; - mul_m3_v3(tr, tip); - add_v3_v3(tip, com); - glVertex3fv(tip); - - root[1] = 0.0f; root[2] = tw; - root[0] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - root[1] = 0.0f; root[2] = -tw; - root[0] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - root[1] = tw; root[2] = 0.0f; - root[0] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - root[1] = -tw; root[2] = 0.0f; - root[0] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - glColor4ub(0x00, 0x7F, 0x00, 155); - - root[0] = root[2] = 0.0f; - root[1] = -drw_size; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - tip[0] = tip[2] = 0.0f; - tip[1] = drw_size; - mul_m3_v3(tr, tip); - add_v3_v3(tip, com); - glVertex3fv(tip); - - root[0] = 0.0f; root[2] = tw; - root[1] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - root[0] = 0.0f; root[2] = -tw; - root[1] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - root[0] = tw; root[2] = 0.0f; - root[1] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - root[0] = -tw; root[2] = 0.0f; - root[1] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - glColor4ub(0x00, 0x00, 0x7F, 155); - root[0] = root[1] = 0.0f; - root[2] = -drw_size; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - tip[0] = tip[1] = 0.0f; - tip[2] = drw_size; - mul_m3_v3(tr, tip); - add_v3_v3(tip, com); - glVertex3fv(tip); - - root[0] = 0.0f; root[1] = tw; - root[2] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - root[0] = 0.0f; root[1] = -tw; - root[2] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - root[0] = tw; root[1] = 0.0f; - root[2] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - root[0] = -tw; root[1] = 0.0f; - root[2] = th; - mul_m3_v3(tr, root); - add_v3_v3(root, com); - glVertex3fv(root); - glVertex3fv(tip); - - glEnd(); -} - -/* place to add drawers */ - -static void drawhandlesN(Nurb *nu, const char sel, const bool hide_handles) -{ - if (nu->hide || hide_handles) return; - - if (nu->type == CU_BEZIER) { - - const float *fp; - -#define TH_HANDLE_COL_TOT ((TH_HANDLE_SEL_FREE - TH_HANDLE_FREE) + 1) - /* use MIN2 when indexing to ensure newer files don't read outside the array */ - unsigned char handle_cols[TH_HANDLE_COL_TOT][3]; - const int basecol = sel ? TH_HANDLE_SEL_FREE : TH_HANDLE_FREE; - - for (int a = 0; a < TH_HANDLE_COL_TOT; a++) { - UI_GetThemeColor3ubv(basecol + a, handle_cols[a]); - } - - glLineWidth(1.0f); - - glBegin(GL_LINES); - - BezTriple *bezt = nu->bezt; - int a = nu->pntsu; - while (a--) { - if (bezt->hide == 0) { - if ((bezt->f2 & SELECT) == sel) { - fp = bezt->vec[0]; - - glColor3ubv(handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]); - glVertex3fv(fp); - glVertex3fv(fp + 3); - - glColor3ubv(handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]); - glVertex3fv(fp + 3); - glVertex3fv(fp + 6); - } - else if ((bezt->f1 & SELECT) == sel) { - fp = bezt->vec[0]; - - glColor3ubv(handle_cols[MIN2(bezt->h1, TH_HANDLE_COL_TOT - 1)]); - glVertex3fv(fp); - glVertex3fv(fp + 3); - } - else if ((bezt->f3 & SELECT) == sel) { - fp = bezt->vec[1]; - - glColor3ubv(handle_cols[MIN2(bezt->h2, TH_HANDLE_COL_TOT - 1)]); - glVertex3fv(fp); - glVertex3fv(fp + 3); - } - } - bezt++; - } - - glEnd(); - -#undef TH_HANDLE_COL_TOT - - } -} - -static void drawhandlesN_active(Nurb *nu) -{ - if (nu->hide) return; - - UI_ThemeColor(TH_ACTIVE_SPLINE); - glLineWidth(2); - - glBegin(GL_LINES); - - if (nu->type == CU_BEZIER) { - BezTriple *bezt = nu->bezt; - int a = nu->pntsu; - while (a--) { - if (bezt->hide == 0) { - const float *fp = bezt->vec[0]; - - glVertex3fv(fp); - glVertex3fv(fp + 3); - - glVertex3fv(fp + 3); - glVertex3fv(fp + 6); - } - bezt++; - } - } - glEnd(); - - glColor3ub(0, 0, 0); -} - -static void drawvertsN(Nurb *nu, const char sel, const bool hide_handles, const void *vert) -{ - if (nu->hide) return; - - const int color = sel ? TH_VERTEX_SELECT : TH_VERTEX; - - UI_ThemeColor(color); - - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - - glBegin(GL_POINTS); - - if (nu->type == CU_BEZIER) { - - BezTriple *bezt = nu->bezt; - int a = nu->pntsu; - while (a--) { - if (bezt->hide == 0) { - if (sel == 1 && bezt == vert) { - UI_ThemeColor(TH_ACTIVE_VERT); - - if (bezt->f2 & SELECT) glVertex3fv(bezt->vec[1]); - if (!hide_handles) { - if (bezt->f1 & SELECT) glVertex3fv(bezt->vec[0]); - if (bezt->f3 & SELECT) glVertex3fv(bezt->vec[2]); - } - - UI_ThemeColor(color); - } - else if (hide_handles) { - if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]); - } - else { - if ((bezt->f1 & SELECT) == sel) glVertex3fv(bezt->vec[0]); - if ((bezt->f2 & SELECT) == sel) glVertex3fv(bezt->vec[1]); - if ((bezt->f3 & SELECT) == sel) glVertex3fv(bezt->vec[2]); - } - } - bezt++; - } - } - else { - BPoint *bp = nu->bp; - int a = nu->pntsu * nu->pntsv; - while (a--) { - if (bp->hide == 0) { - if (bp == vert) { - UI_ThemeColor(TH_ACTIVE_VERT); - glVertex3fv(bp->vec); - UI_ThemeColor(color); - } - else { - if ((bp->f1 & SELECT) == sel) glVertex3fv(bp->vec); - } - } - bp++; - } - } - - glEnd(); -} - -static void editnurb_draw_active_poly(Nurb *nu) -{ - UI_ThemeColor(TH_ACTIVE_SPLINE); - glLineWidth(2); - - BPoint *bp = nu->bp; - for (int b = 0; b < nu->pntsv; b++) { - if (nu->flagu & 1) glBegin(GL_LINE_LOOP); - else glBegin(GL_LINE_STRIP); - - for (int a = 0; a < nu->pntsu; a++, bp++) { - glVertex3fv(bp->vec); - } - - glEnd(); - } - - glColor3ub(0, 0, 0); -} - -static void editnurb_draw_active_nurbs(Nurb *nu) -{ - UI_ThemeColor(TH_ACTIVE_SPLINE); - glLineWidth(2); - - glBegin(GL_LINES); - BPoint *bp = nu->bp; - for (int b = 0; b < nu->pntsv; b++) { - BPoint *bp1 = bp; - bp++; - - for (int a = nu->pntsu - 1; a > 0; a--, bp++) { - if (bp->hide == 0 && bp1->hide == 0) { - glVertex3fv(bp->vec); - glVertex3fv(bp1->vec); - } - bp1 = bp; - } - } - - if (nu->pntsv > 1) { /* surface */ - - int ofs = nu->pntsu; - for (int b = 0; b < nu->pntsu; b++) { - BPoint *bp1 = nu->bp + b; - bp = bp1 + ofs; - for (int a = nu->pntsv - 1; a > 0; a--, bp += ofs) { - if (bp->hide == 0 && bp1->hide == 0) { - glVertex3fv(bp->vec); - glVertex3fv(bp1->vec); - } - bp1 = bp; - } - } - } - - glEnd(); - - glColor3ub(0, 0, 0); -} - -static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel) -{ - BPoint *bp, *bp1; - int a, b; - Curve *cu = ob->data; - - int index = 0; - Nurb *nu = nurb; - while (nu) { - if (nu->hide == 0) { - switch (nu->type) { - case CU_POLY: - if (!sel && index == cu->actnu) { - /* we should draw active spline highlight below everything */ - editnurb_draw_active_poly(nu); - } - - glLineWidth(1); - - UI_ThemeColor(TH_NURB_ULINE); - bp = nu->bp; - for (b = 0; b < nu->pntsv; b++) { - if (nu->flagu & 1) glBegin(GL_LINE_LOOP); - else glBegin(GL_LINE_STRIP); - - for (a = 0; a < nu->pntsu; a++, bp++) { - glVertex3fv(bp->vec); - } - - glEnd(); - } - break; - case CU_NURBS: - if (!sel && index == cu->actnu) { - /* we should draw active spline highlight below everything */ - editnurb_draw_active_nurbs(nu); - } - - glLineWidth(1); - - glBegin(GL_LINES); - - bp = nu->bp; - for (b = 0; b < nu->pntsv; b++) { - bp1 = bp; - bp++; - for (a = nu->pntsu - 1; a > 0; a--, bp++) { - if (bp->hide == 0 && bp1->hide == 0) { - if (sel) { - if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) { - UI_ThemeColor(TH_NURB_SEL_ULINE); - - glVertex3fv(bp->vec); - glVertex3fv(bp1->vec); - } - } - else { - if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) { - /* pass */ - } - else { - UI_ThemeColor(TH_NURB_ULINE); - - glVertex3fv(bp->vec); - glVertex3fv(bp1->vec); - } - } - } - bp1 = bp; - } - } - - if (nu->pntsv > 1) { /* surface */ - int ofs = nu->pntsu; - for (b = 0; b < nu->pntsu; b++) { - bp1 = nu->bp + b; - bp = bp1 + ofs; - for (a = nu->pntsv - 1; a > 0; a--, bp += ofs) { - if (bp->hide == 0 && bp1->hide == 0) { - if (sel) { - if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) { - UI_ThemeColor(TH_NURB_SEL_VLINE); - - glVertex3fv(bp->vec); - glVertex3fv(bp1->vec); - } - } - else { - if ((bp->f1 & SELECT) && (bp1->f1 & SELECT)) { - /* pass */ - } - else { - UI_ThemeColor(TH_NURB_VLINE); - - glVertex3fv(bp->vec); - glVertex3fv(bp1->vec); - } - } - } - bp1 = bp; - } - } - } - - glEnd(); - break; - } - } - - index++; - nu = nu->next; - } -} - -static void draw_editnurb( - Main *bmain, Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb, - const char dt, const short dflag, const unsigned char ob_wire_col[4]) -{ - ToolSettings *ts = scene->toolsettings; - Object *ob = base->object; - Curve *cu = ob->data; - Nurb *nu; - const void *vert = BKE_curve_vert_active_get(cu); - const bool hide_handles = (cu->drawflag & CU_HIDE_HANDLES) != 0; - unsigned char wire_col[3]; - - /* DispList */ - UI_GetThemeColor3ubv(TH_WIRE_EDIT, wire_col); - glColor3ubv(wire_col); - - drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col); - - /* for shadows only show solid faces */ - if (v3d->flag2 & V3D_RENDER_SHADOW) - return; - - if (v3d->zbuf) glDepthFunc(GL_ALWAYS); - - /* first non-selected and active handles */ - int index = 0; - for (nu = nurb; nu; nu = nu->next) { - if (nu->type == CU_BEZIER) { - if (index == cu->actnu && !hide_handles) - drawhandlesN_active(nu); - drawhandlesN(nu, 0, hide_handles); - } - index++; - } - draw_editnurb_splines(ob, nurb, false); - draw_editnurb_splines(ob, nurb, true); - /* selected handles */ - for (nu = nurb; nu; nu = nu->next) { - if (nu->type == CU_BEZIER && (cu->drawflag & CU_HIDE_HANDLES) == 0) - drawhandlesN(nu, 1, hide_handles); - drawvertsN(nu, 0, hide_handles, NULL); - } - - if (v3d->zbuf) glDepthFunc(GL_LEQUAL); - - glColor3ubv(wire_col); - - /* direction vectors for 3d curve paths - * when at its lowest, don't render normals */ - if ((cu->flag & CU_3D) && (ts->normalsize > 0.0015f) && (cu->drawflag & CU_HIDE_NORMALS) == 0) { - BevList *bl; - glLineWidth(1.0f); - for (bl = ob->curve_cache->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) { - BevPoint *bevp = bl->bevpoints; - int nr = bl->nr; - int skip = nu->resolu / 16; - - while (nr-- > 0) { /* accounts for empty bevel lists */ - const float fac = bevp->radius * ts->normalsize; - float vec_a[3]; /* Offset perpendicular to the curve */ - float vec_b[3]; /* Delta along the curve */ - - vec_a[0] = fac; - vec_a[1] = 0.0f; - vec_a[2] = 0.0f; - - mul_qt_v3(bevp->quat, vec_a); - madd_v3_v3fl(vec_a, bevp->dir, -fac); - - reflect_v3_v3v3(vec_b, vec_a, bevp->dir); - negate_v3(vec_b); - - add_v3_v3(vec_a, bevp->vec); - add_v3_v3(vec_b, bevp->vec); - - glBegin(GL_LINE_STRIP); - glVertex3fv(vec_a); - glVertex3fv(bevp->vec); - glVertex3fv(vec_b); - glEnd(); - - bevp += skip + 1; - nr -= skip; - } - } - } - - if (v3d->zbuf) glDepthFunc(GL_ALWAYS); - - for (nu = nurb; nu; nu = nu->next) { - drawvertsN(nu, 1, hide_handles, vert); - } - - if (v3d->zbuf) glDepthFunc(GL_LEQUAL); -} - -static void draw_editfont_textcurs(RegionView3D *rv3d, float textcurs[4][2]) -{ - cpack(0); - ED_view3d_polygon_offset(rv3d, -1.0); - set_inverted_drawing(1); - glBegin(GL_QUADS); - glVertex2fv(textcurs[0]); - glVertex2fv(textcurs[1]); - glVertex2fv(textcurs[2]); - glVertex2fv(textcurs[3]); - glEnd(); - set_inverted_drawing(0); - ED_view3d_polygon_offset(rv3d, 0.0); -} - -static void draw_editfont( - Main *bmain, Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const short dflag, const unsigned char ob_wire_col[4]) -{ - Object *ob = base->object; - Curve *cu = ob->data; - EditFont *ef = cu->editfont; - float vec1[3], vec2[3]; - - draw_editfont_textcurs(rv3d, ef->textcurs); - - if (cu->flag & CU_FAST) { - cpack(0xFFFFFF); - set_inverted_drawing(1); - drawDispList(bmain, scene, v3d, rv3d, base, OB_WIRE, dflag, ob_wire_col); - set_inverted_drawing(0); - } - else { - drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col); - } - - if (cu->linewidth != 0.0f) { - UI_ThemeColor(TH_WIRE_EDIT); - copy_v3_v3(vec1, ob->orig); - copy_v3_v3(vec2, ob->orig); - vec1[0] += cu->linewidth; - vec2[0] += cu->linewidth; - vec1[1] += cu->linedist * cu->fsize; - vec2[1] -= cu->lines * cu->linedist * cu->fsize; - setlinestyle(3); - glBegin(GL_LINES); - glVertex2fv(vec1); - glVertex2fv(vec2); - glEnd(); - setlinestyle(0); - } - - setlinestyle(3); - for (int i = 0; i < cu->totbox; i++) { - if (cu->tb[i].w != 0.0f) { - UI_ThemeColor(i == (cu->actbox - 1) ? TH_ACTIVE : TH_WIRE); - vec1[0] = cu->xof + cu->tb[i].x; - vec1[1] = cu->yof + cu->tb[i].y + cu->fsize; - vec1[2] = 0.001; - glBegin(GL_LINE_STRIP); - glVertex3fv(vec1); - vec1[0] += cu->tb[i].w; - glVertex3fv(vec1); - vec1[1] -= cu->tb[i].h; - glVertex3fv(vec1); - vec1[0] -= cu->tb[i].w; - glVertex3fv(vec1); - vec1[1] += cu->tb[i].h; - glVertex3fv(vec1); - glEnd(); - } - } - setlinestyle(0); - - - if (ef->selboxes && ef->selboxes_len) { - float selboxw; - - cpack(0xffffff); - set_inverted_drawing(1); - for (int i = 0; i < ef->selboxes_len; i++) { - EditFontSelBox *sb = &ef->selboxes[i]; - float tvec[3]; - - if (i + 1 != ef->selboxes_len) { - if (ef->selboxes[i + 1].y == sb->y) - selboxw = ef->selboxes[i + 1].x - sb->x; - else - selboxw = sb->w; - } - else { - selboxw = sb->w; - } - - /* fill in xy below */ - tvec[2] = 0.001; - - glBegin(GL_QUADS); - - if (sb->rot == 0.0f) { - copy_v2_fl2(tvec, sb->x, sb->y); - glVertex3fv(tvec); - - copy_v2_fl2(tvec, sb->x + selboxw, sb->y); - glVertex3fv(tvec); - - copy_v2_fl2(tvec, sb->x + selboxw, sb->y + sb->h); - glVertex3fv(tvec); - - copy_v2_fl2(tvec, sb->x, sb->y + sb->h); - glVertex3fv(tvec); - } - else { - float mat[2][2]; - - angle_to_mat2(mat, sb->rot); - - copy_v2_fl2(tvec, sb->x, sb->y); - glVertex3fv(tvec); - - copy_v2_fl2(tvec, selboxw, 0.0f); - mul_m2v2(mat, tvec); - add_v2_v2(tvec, &sb->x); - glVertex3fv(tvec); - - copy_v2_fl2(tvec, selboxw, sb->h); - mul_m2v2(mat, tvec); - add_v2_v2(tvec, &sb->x); - glVertex3fv(tvec); - - copy_v2_fl2(tvec, 0.0f, sb->h); - mul_m2v2(mat, tvec); - add_v2_v2(tvec, &sb->x); - glVertex3fv(tvec); - } - - glEnd(); - } - set_inverted_drawing(0); - } -} - -/* draw a sphere for use as an empty drawtype */ -static void draw_empty_sphere(float size) -{ - static GLuint displist = 0; - - if (displist == 0) { - GLUquadricObj *qobj; - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - - glPushMatrix(); - - qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0.0, 1, 16, 1); - - glRotatef(90, 0, 1, 0); - gluDisk(qobj, 0.0, 1, 16, 1); - - glRotatef(90, 1, 0, 0); - gluDisk(qobj, 0.0, 1, 16, 1); - - gluDeleteQuadric(qobj); - - glPopMatrix(); - glEndList(); - } - - glScalef(size, size, size); - glCallList(displist); - glScalef(1.0f / size, 1.0f / size, 1.0f / size); -} - -/* draw a cone for use as an empty drawtype */ -static void draw_empty_cone(float size) -{ - const float radius = size; - - GLUquadricObj *qobj = gluNewQuadric(); - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - - glPushMatrix(); - - glScalef(radius, size * 2.0f, radius); - glRotatef(-90.0, 1.0, 0.0, 0.0); - gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1); - - glPopMatrix(); - - gluDeleteQuadric(qobj); -} - -static void drawspiral(const float cent[3], float rad, float tmat[4][4], int start) -{ - float vec[3], vx[3], vy[3]; - const float tot_inv = 1.0f / (float)CIRCLE_RESOL; - int a; - bool inverse = false; - float x, y, fac; - - if (start < 0) { - inverse = true; - start = -start; - } - - mul_v3_v3fl(vx, tmat[0], rad); - mul_v3_v3fl(vy, tmat[1], rad); - - glBegin(GL_LINE_STRIP); - - if (inverse == 0) { - copy_v3_v3(vec, cent); - glVertex3fv(vec); - - for (a = 0; a < CIRCLE_RESOL; a++) { - if (a + start >= CIRCLE_RESOL) - start = -a + 1; - - fac = (float)a * tot_inv; - x = sinval[a + start] * fac; - y = cosval[a + start] * fac; - - vec[0] = cent[0] + (x * vx[0] + y * vy[0]); - vec[1] = cent[1] + (x * vx[1] + y * vy[1]); - vec[2] = cent[2] + (x * vx[2] + y * vy[2]); - - glVertex3fv(vec); - } - } - else { - fac = (float)(CIRCLE_RESOL - 1) * tot_inv; - x = sinval[start] * fac; - y = cosval[start] * fac; - - vec[0] = cent[0] + (x * vx[0] + y * vy[0]); - vec[1] = cent[1] + (x * vx[1] + y * vy[1]); - vec[2] = cent[2] + (x * vx[2] + y * vy[2]); - - glVertex3fv(vec); - - for (a = 0; a < CIRCLE_RESOL; a++) { - if (a + start >= CIRCLE_RESOL) - start = -a + 1; - - fac = (float)(-a + (CIRCLE_RESOL - 1)) * tot_inv; - x = sinval[a + start] * fac; - y = cosval[a + start] * fac; - - vec[0] = cent[0] + (x * vx[0] + y * vy[0]); - vec[1] = cent[1] + (x * vx[1] + y * vy[1]); - vec[2] = cent[2] + (x * vx[2] + y * vy[2]); - glVertex3fv(vec); - } - } - - glEnd(); -} - -/* draws a circle on x-z plane given the scaling of the circle, assuming that - * all required matrices have been set (used for drawing empties) */ -static void drawcircle_size(float size) -{ - glBegin(GL_LINE_LOOP); - - /* coordinates are: cos(degrees * 11.25) = x, sin(degrees * 11.25) = y, 0.0f = z */ - for (short degrees = 0; degrees < CIRCLE_RESOL; degrees++) { - float x = cosval[degrees]; - float y = sinval[degrees]; - - glVertex3f(x * size, 0.0f, y * size); - } - - glEnd(); - -} - -/* needs fixing if non-identity matrix used */ -static void drawtube(const float vec[3], float radius, float height, float tmat[4][4]) -{ - float cur[3]; - drawcircball(GL_LINE_LOOP, vec, radius, tmat); - - copy_v3_v3(cur, vec); - cur[2] += height; - - drawcircball(GL_LINE_LOOP, cur, radius, tmat); - - glBegin(GL_LINES); - glVertex3f(vec[0] + radius, vec[1], vec[2]); - glVertex3f(cur[0] + radius, cur[1], cur[2]); - glVertex3f(vec[0] - radius, vec[1], vec[2]); - glVertex3f(cur[0] - radius, cur[1], cur[2]); - glVertex3f(vec[0], vec[1] + radius, vec[2]); - glVertex3f(cur[0], cur[1] + radius, cur[2]); - glVertex3f(vec[0], vec[1] - radius, vec[2]); - glVertex3f(cur[0], cur[1] - radius, cur[2]); - glEnd(); -} - -/* needs fixing if non-identity matrix used */ -static void drawcone(const float vec[3], float radius, float height, float tmat[4][4]) -{ - float cur[3]; - - copy_v3_v3(cur, vec); - cur[2] += height; - - drawcircball(GL_LINE_LOOP, cur, radius, tmat); - - glBegin(GL_LINES); - glVertex3f(vec[0], vec[1], vec[2]); - glVertex3f(cur[0] + radius, cur[1], cur[2]); - glVertex3f(vec[0], vec[1], vec[2]); - glVertex3f(cur[0] - radius, cur[1], cur[2]); - glVertex3f(vec[0], vec[1], vec[2]); - glVertex3f(cur[0], cur[1] + radius, cur[2]); - glVertex3f(vec[0], vec[1], vec[2]); - glVertex3f(cur[0], cur[1] - radius, cur[2]); - glEnd(); -} - -/* return true if nothing was drawn */ -static bool drawmball( - Main *bmain, Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, - const char dt, const short dflag, const unsigned char ob_wire_col[4]) -{ - Object *ob = base->object; - MetaElem *ml; - float imat[4][4]; - int code = 1; - - MetaBall *mb = ob->data; - - if (mb->editelems) { - if ((G.f & G_PICKSEL) == 0) { - unsigned char wire_col[4]; - UI_GetThemeColor4ubv(TH_WIRE_EDIT, wire_col); - glColor3ubv(wire_col); - - drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, wire_col); - } - ml = mb->editelems->first; - } - else { - if ((base->flag & OB_FROMDUPLI) == 0) { - drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col); - } - ml = mb->elems.first; - } - - if (ml == NULL) { - return true; - } - - if (v3d->flag2 & V3D_RENDER_OVERRIDE) { - return false; - } - - invert_m4_m4(imat, rv3d->viewmatob); - normalize_v3(imat[0]); - normalize_v3(imat[1]); - - if (mb->editelems == NULL) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(ob_wire_col); - } - } - - glLineWidth(1.0f); - - while (ml) { - /* draw radius */ - if (mb->editelems) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if ((ml->flag & SELECT) && (ml->flag & MB_SCALE_RAD)) cpack(0xA0A0F0); - else cpack(0x3030A0); - } - - if (G.f & G_PICKSEL) { - ml->selcol1 = code; - GPU_select_load_id(code++); - } - } - drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat); - - /* draw stiffness */ - if (mb->editelems) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - if ((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) cpack(0xA0F0A0); - else cpack(0x30A030); - } - - if (G.f & G_PICKSEL) { - ml->selcol2 = code; - GPU_select_load_id(code++); - } - drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad * atanf(ml->s) / (float)M_PI_2, imat); - } - - ml = ml->next; - } - return false; -} - -static void draw_forcefield(Object *ob, RegionView3D *rv3d, - const short dflag, const unsigned char ob_wire_col[4]) -{ - PartDeflect *pd = ob->pd; - float imat[4][4], tmat[4][4]; - float vec[3] = {0.0, 0.0, 0.0}; - /* scale size of circle etc with the empty drawsize */ - const float size = (ob->type == OB_EMPTY) ? ob->empty_drawsize : 1.0f; - - /* calculus here, is reused in PFIELD_FORCE */ - invert_m4_m4(imat, rv3d->viewmatob); -#if 0 - normalize_v3(imat[0]); /* we don't do this because field doesnt scale either... apart from wind! */ - normalize_v3(imat[1]); -#endif - - if (pd->forcefield == PFIELD_WIND) { - float force_val = pd->f_strength; - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f); - } - - unit_m4(tmat); - force_val *= 0.1f; - drawcircball(GL_LINE_LOOP, vec, size, tmat); - vec[2] = 0.5f * force_val; - drawcircball(GL_LINE_LOOP, vec, size, tmat); - vec[2] = 1.0f * force_val; - drawcircball(GL_LINE_LOOP, vec, size, tmat); - vec[2] = 1.5f * force_val; - drawcircball(GL_LINE_LOOP, vec, size, tmat); - vec[2] = 0.0f; /* reset vec for max dist circle */ - - } - else if (pd->forcefield == PFIELD_FORCE) { - float ffall_val = pd->f_power; - - if ((dflag & DRAW_CONSTCOLOR) == 0) ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f); - drawcircball(GL_LINE_LOOP, vec, size, imat); - if ((dflag & DRAW_CONSTCOLOR) == 0) ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.9f - 0.4f / powf(1.5f, ffall_val)); - drawcircball(GL_LINE_LOOP, vec, size * 1.5f, imat); - if ((dflag & DRAW_CONSTCOLOR) == 0) ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.9f - 0.4f / powf(2.0f, ffall_val)); - drawcircball(GL_LINE_LOOP, vec, size * 2.0f, imat); - } - else if (pd->forcefield == PFIELD_VORTEX) { - float force_val = pd->f_strength; - - unit_m4(tmat); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.7f); - } - - if (force_val < 0) { - drawspiral(vec, size, tmat, 1); - drawspiral(vec, size, tmat, 16); - } - else { - drawspiral(vec, size, tmat, -1); - drawspiral(vec, size, tmat, -16); - } - } - else if (pd->forcefield == PFIELD_GUIDE && ob->type == OB_CURVE) { - Curve *cu = ob->data; - if ((cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) { - float guidevec1[4], guidevec2[3]; - float mindist = pd->f_strength; - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f); - } - - /* path end */ - setlinestyle(3); - where_on_path(ob, 1.0f, guidevec1, guidevec2, NULL, NULL, NULL); - drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat); - - /* path beginning */ - setlinestyle(0); - where_on_path(ob, 0.0f, guidevec1, guidevec2, NULL, NULL, NULL); - drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat); - - copy_v3_v3(vec, guidevec1); /* max center */ - } - } - - setlinestyle(3); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.5f); - } - - if (pd->falloff == PFIELD_FALL_SPHERE) { - /* as last, guide curve alters it */ - if (pd->flag & PFIELD_USEMAX) - drawcircball(GL_LINE_LOOP, vec, pd->maxdist, imat); - - if (pd->flag & PFIELD_USEMIN) - drawcircball(GL_LINE_LOOP, vec, pd->mindist, imat); - } - else if (pd->falloff == PFIELD_FALL_TUBE) { - float radius, distance; - - unit_m4(tmat); - - vec[0] = vec[1] = 0.0f; - radius = (pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f; - distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f; - vec[2] = distance; - distance = (pd->flag & PFIELD_POSZ) ? -distance : -2.0f * distance; - - if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) - drawtube(vec, radius, distance, tmat); - - radius = (pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f; - distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f; - vec[2] = distance; - distance = (pd->flag & PFIELD_POSZ) ? -distance : -2.0f * distance; - - if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) - drawtube(vec, radius, distance, tmat); - } - else if (pd->falloff == PFIELD_FALL_CONE) { - float radius, distance; - - unit_m4(tmat); - - radius = DEG2RADF((pd->flag & PFIELD_USEMAXR) ? pd->maxrad : 1.0f); - distance = (pd->flag & PFIELD_USEMAX) ? pd->maxdist : 0.0f; - - if (pd->flag & (PFIELD_USEMAX | PFIELD_USEMAXR)) { - drawcone(vec, distance * sinf(radius), distance * cosf(radius), tmat); - if ((pd->flag & PFIELD_POSZ) == 0) - drawcone(vec, distance * sinf(radius), -distance * cosf(radius), tmat); - } - - radius = DEG2RADF((pd->flag & PFIELD_USEMINR) ? pd->minrad : 1.0f); - distance = (pd->flag & PFIELD_USEMIN) ? pd->mindist : 0.0f; - - if (pd->flag & (PFIELD_USEMIN | PFIELD_USEMINR)) { - drawcone(vec, distance * sinf(radius), distance * cosf(radius), tmat); - if ((pd->flag & PFIELD_POSZ) == 0) - drawcone(vec, distance * sinf(radius), -distance * cosf(radius), tmat); - } - } - setlinestyle(0); -} - -static void draw_box(const float vec[8][3], bool solid) -{ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vec); - - if (solid) { - const GLubyte indices[24] = {0, 1, 2, 3, 7, 6, 5, 4, 4, 5, 1, 0, 3, 2, 6, 7, 3, 7, 4, 0, 1, 5, 6, 2}; - glDrawRangeElements(GL_QUADS, 0, 7, 24, GL_UNSIGNED_BYTE, indices); - } - else { - const GLubyte indices[24] = {0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 4, 5, 5, 6, 6, 7, 7, 4, 1, 5, 2, 6, 3, 7}; - glDrawRangeElements(GL_LINES, 0, 7, 24, GL_UNSIGNED_BYTE, indices); - } - - glDisableClientState(GL_VERTEX_ARRAY); -} - -static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin) -{ - float size[3], cent[3]; - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - - BKE_boundbox_calc_size_aabb(bb, size); - - if (around_origin) { - zero_v3(cent); - } - else { - BKE_boundbox_calc_center_aabb(bb, cent); - } - - glPushMatrix(); - if (type == OB_BOUND_SPHERE) { - float scale = MAX3(size[0], size[1], size[2]); - glTranslate3fv(cent); - glScalef(scale, scale, scale); - gluSphere(qobj, 1.0, 8, 5); - } - else if (type == OB_BOUND_CYLINDER) { - float radius = size[0] > size[1] ? size[0] : size[1]; - glTranslatef(cent[0], cent[1], cent[2] - size[2]); - glScalef(radius, radius, 2.0f * size[2]); - gluCylinder(qobj, 1.0, 1.0, 1.0, 8, 1); - } - else if (type == OB_BOUND_CONE) { - float radius = size[0] > size[1] ? size[0] : size[1]; - glTranslatef(cent[0], cent[1], cent[2] - size[2]); - glScalef(radius, radius, 2.0f * size[2]); - gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1); - } - else if (type == OB_BOUND_CAPSULE) { - float radius = size[0] > size[1] ? size[0] : size[1]; - float length = size[2] > radius ? 2.0f * (size[2] - radius) : 0.0f; - glTranslatef(cent[0], cent[1], cent[2] - length * 0.5f); - gluCylinder(qobj, radius, radius, length, 8, 1); - gluSphere(qobj, radius, 8, 4); - glTranslatef(0.0, 0.0, length); - gluSphere(qobj, radius, 8, 4); - } - glPopMatrix(); - - gluDeleteQuadric(qobj); -} - -static void draw_bounding_volume(Object *ob, char type) -{ - BoundBox bb_local; - BoundBox *bb = NULL; - - if (ob->type == OB_MESH) { - bb = BKE_mesh_boundbox_get(ob); - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - bb = BKE_curve_boundbox_get(ob); - } - else if (ob->type == OB_MBALL) { - if (BKE_mball_is_basis(ob)) { - bb = ob->bb; - } - } - else if (ob->type == OB_ARMATURE) { - bb = BKE_armature_boundbox_get(ob); - } - else if (ob->type == OB_LATTICE) { - bb = BKE_lattice_boundbox_get(ob); - } - else { - const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f}; - bb = &bb_local; - BKE_boundbox_init_from_minmax(bb, min, max); - } - - if (bb == NULL) - return; - - if (ob->gameflag & OB_BOUNDS) { /* bounds need to be drawn around origin for game engine */ - - if (type == OB_BOUND_BOX) { - float vec[8][3], size[3]; - - BKE_boundbox_calc_size_aabb(bb, size); - - vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = -size[0]; - vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = +size[0]; - vec[0][1] = vec[1][1] = vec[4][1] = vec[5][1] = -size[1]; - vec[2][1] = vec[3][1] = vec[6][1] = vec[7][1] = +size[1]; - vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2]; - vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2]; - - draw_box(vec, false); - } - else { - draw_bb_quadric(bb, type, true); - } - } - else { - if (type == OB_BOUND_BOX) - draw_box(bb->vec, false); - else - draw_bb_quadric(bb, type, false); - } -} - -static void drawtexspace(Object *ob) -{ - float vec[8][3], loc[3], size[3]; - - if (ob->type == OB_MESH) { - BKE_mesh_texspace_get(ob->data, loc, NULL, size); - } - else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { - BKE_curve_texspace_get(ob->data, loc, NULL, size); - } - else if (ob->type == OB_MBALL) { - MetaBall *mb = ob->data; - copy_v3_v3(size, mb->size); - copy_v3_v3(loc, mb->loc); - } - else { - return; - } - - vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = loc[0] - size[0]; - vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = loc[0] + size[0]; - - vec[0][1] = vec[1][1] = vec[4][1] = vec[5][1] = loc[1] - size[1]; - vec[2][1] = vec[3][1] = vec[6][1] = vec[7][1] = loc[1] + size[1]; - - vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = loc[2] - size[2]; - vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = loc[2] + size[2]; - - setlinestyle(2); - - draw_box(vec, false); - - setlinestyle(0); -} - -/* draws wire outline */ -static void draw_object_selected_outline( - Main *bmain, Scene *scene, View3D *v3d, ARegion *ar, Base *base, - const unsigned char ob_wire_col[4]) -{ - RegionView3D *rv3d = ar->regiondata; - Object *ob = base->object; - - glDepthMask(0); - - if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - bool has_faces = false; - -#ifdef SEQUENCER_DAG_WORKAROUND - ensure_curve_cache(bmain, scene, ob); -#endif - - DerivedMesh *dm = ob->derivedFinal; - if (dm) { - DM_update_materials(dm, ob); - } - - if (dm) { - has_faces = (dm->getNumPolys(dm) != 0); - } - else { - has_faces = BKE_displist_has_faces(&ob->curve_cache->disp); - } - - if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->bb)) { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - if (dm) { - draw_mesh_object_outline(v3d, ob, dm); - } - else { - /* only draw 'solid' parts of the display list as wire. */ - drawDispListwire_ex(&ob->curve_cache->disp, (DL_INDEX3 | DL_INDEX4 | DL_SURF)); - } - } - } - else if (ob->type == OB_MBALL) { - if (BKE_mball_is_basis(ob)) { - if ((base->flag & OB_FROMDUPLI) == 0) { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - drawDispListwire(&ob->curve_cache->disp, ob->type); - } - } - } - else if (ob->type == OB_ARMATURE) { - if (!(ob->mode & OB_MODE_POSE && base == scene->basact)) { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - draw_armature(scene, v3d, ar, base, OB_WIRE, 0, ob_wire_col, true); - } - } - - glDepthMask(1); -} - -static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const unsigned char ob_wire_col[4]) -{ - if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) { - - if (scene->obedit == ob) { - UI_ThemeColor(TH_WIRE_EDIT); - } - else { - glColor3ubv(ob_wire_col); - } - - ED_view3d_polygon_offset(rv3d, 1.0); - glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */ - glLineWidth(1); - - if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) { - if (ED_view3d_boundbox_clip(rv3d, ob->bb)) { - - if (ob->derivedFinal) { - drawCurveDMWired(ob); - } - else { - drawDispListwire(&ob->curve_cache->disp, ob->type); - } - } - } - else if (ob->type == OB_MBALL) { - if (BKE_mball_is_basis(ob)) { - drawDispListwire(&ob->curve_cache->disp, ob->type); - } - } - - glDepthMask(1); - ED_view3d_polygon_offset(rv3d, 0.0); - } -} - -/* should be called in view space */ -static void draw_hooks(Object *ob) -{ - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData *) md; - float vec[3]; - - mul_v3_m4v3(vec, ob->obmat, hmd->cent); - - if (hmd->object) { - setlinestyle(3); - glBegin(GL_LINES); - glVertex3fv(hmd->object->obmat[3]); - glVertex3fv(vec); - glEnd(); - setlinestyle(0); - } - - glPointSize(3.0); - glBegin(GL_POINTS); - glVertex3fv(vec); - glEnd(); - } - } -} - -static void draw_rigid_body_pivot(bRigidBodyJointConstraint *data, - const short dflag, const unsigned char ob_wire_col[4]) -{ - const char *axis_str[3] = {"px", "py", "pz"}; - float mat[4][4]; - - eul_to_mat4(mat, &data->axX); - glLineWidth(4.0f); - setlinestyle(2); - for (int axis = 0; axis < 3; axis++) { - float dir[3] = {0, 0, 0}; - float v[3]; - - copy_v3_v3(v, &data->pivX); - - dir[axis] = 1.0f; - glBegin(GL_LINES); - mul_m4_v3(mat, dir); - add_v3_v3(v, dir); - glVertex3fv(&data->pivX); - glVertex3fv(v); - glEnd(); - - /* when const color is set wirecolor is NULL - we could get the current color but - * with selection and group instancing its not needed to draw the text */ - if ((dflag & DRAW_CONSTCOLOR) == 0) { - view3d_cached_text_draw_add(v, axis_str[axis], 2, 0, V3D_CACHE_TEXT_ASCII, ob_wire_col); - } - } - - setlinestyle(0); -} - -static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_wire_col[4]) -{ - Object *ob = base->object; - int colindex = 0; - const bool is_edit = (ob->mode & OB_MODE_EDIT) != 0; - /* confusing logic here, there are 2 methods of setting the color - * 'colortab[colindex]' and 'theme_id', colindex overrides theme_id. - * - * note: no theme yet for 'colindex' */ - int theme_id = is_edit ? TH_WIRE_EDIT : TH_WIRE; - int theme_shade = 0; - - if ((scene->obedit == NULL) && - (G.moving & G_TRANSFORM_OBJ) && - (base->flag & (SELECT + BA_WAS_SEL))) - { - theme_id = TH_TRANSFORM; - } - else { - /* Sets the 'colindex' */ - if (ID_IS_LINKED(ob)) { - colindex = (base->flag & (SELECT + BA_WAS_SEL)) ? 2 : 1; - } - /* Sets the 'theme_id' or fallback to wire */ - else { - if (ob->flag & OB_FROMGROUP) { - if (base->flag & (SELECT + BA_WAS_SEL)) { - /* uses darker active color for non-active + selected */ - theme_id = TH_GROUP_ACTIVE; - - if (scene->basact != base) { - theme_shade = -32; - } - } - else { - theme_id = TH_GROUP; - } - } - else { - if (base->flag & (SELECT + BA_WAS_SEL)) { - theme_id = scene->basact == base ? TH_ACTIVE : TH_SELECT; - } - else { - if (ob->type == OB_LAMP) theme_id = TH_LAMP; - else if (ob->type == OB_SPEAKER) theme_id = TH_SPEAKER; - else if (ob->type == OB_CAMERA) theme_id = TH_CAMERA; - else if (ob->type == OB_EMPTY) theme_id = TH_EMPTY; - /* fallback to TH_WIRE */ - } - } - } - } - - /* finally set the color */ - if (colindex == 0) { - if (theme_shade == 0) UI_GetThemeColor3ubv(theme_id, r_ob_wire_col); - else UI_GetThemeColorShade3ubv(theme_id, theme_shade, r_ob_wire_col); - } - else { - cpack_cpy_3ub(r_ob_wire_col, colortab[colindex]); - } - - /* no reason to use this but some functions take col[4] */ - r_ob_wire_col[3] = 255; -} - -static void draw_object_matcap_check(View3D *v3d, Object *ob) -{ - /* fixed rule, active object draws as matcap */ - BLI_assert((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) == 0); - (void)ob; - - if (v3d->defmaterial == NULL) { - extern Material defmaterial; - - v3d->defmaterial = MEM_mallocN(sizeof(Material), "matcap material"); - *(v3d->defmaterial) = defmaterial; - BLI_listbase_clear(&v3d->defmaterial->gpumaterial); - v3d->defmaterial->preview = NULL; - } - /* first time users */ - if (v3d->matcap_icon < ICON_MATCAP_01 || - v3d->matcap_icon > ICON_MATCAP_24) - { - v3d->matcap_icon = ICON_MATCAP_01; - } - - if (v3d->defmaterial->preview == NULL) - v3d->defmaterial->preview = UI_icon_to_preview(v3d->matcap_icon); - - /* signal to all material checks, gets cleared below */ - v3d->flag2 |= V3D_SHOW_SOLID_MATCAP; -} - -static void draw_rigidbody_shape(Object *ob) -{ - BoundBox *bb = NULL; - float size[3], vec[8][3]; - - if (ob->type == OB_MESH) { - bb = BKE_mesh_boundbox_get(ob); - } - - if (bb == NULL) - return; - - switch (ob->rigidbody_object->shape) { - case RB_SHAPE_BOX: - BKE_boundbox_calc_size_aabb(bb, size); - - vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = -size[0]; - vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = +size[0]; - vec[0][1] = vec[1][1] = vec[4][1] = vec[5][1] = -size[1]; - vec[2][1] = vec[3][1] = vec[6][1] = vec[7][1] = +size[1]; - vec[0][2] = vec[3][2] = vec[4][2] = vec[7][2] = -size[2]; - vec[1][2] = vec[2][2] = vec[5][2] = vec[6][2] = +size[2]; - - draw_box(vec, false); - break; - case RB_SHAPE_SPHERE: - draw_bb_quadric(bb, OB_BOUND_SPHERE, true); - break; - case RB_SHAPE_CONE: - draw_bb_quadric(bb, OB_BOUND_CONE, true); - break; - case RB_SHAPE_CYLINDER: - draw_bb_quadric(bb, OB_BOUND_CYLINDER, true); - break; - case RB_SHAPE_CAPSULE: - draw_bb_quadric(bb, OB_BOUND_CAPSULE, true); - break; - } -} - -/** - * main object drawing function, draws in selection - * \param dflag: (draw flag) can be DRAW_PICKING and/or DRAW_CONSTCOLOR, DRAW_SCENESET - */ -void draw_object(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag) -{ - ModifierData *md = NULL; - Object *ob = base->object; - Curve *cu; - RegionView3D *rv3d = ar->regiondata; - unsigned int col = 0; - unsigned char _ob_wire_col[4]; /* dont initialize this */ - const unsigned char *ob_wire_col = NULL; /* dont initialize this, use NULL crashes as a way to find invalid use */ - bool zbufoff = false, is_paint = false, empty_object = false; - const bool is_obact = (ob == OBACT); - const bool render_override = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0; - const bool is_picking = (G.f & G_PICKSEL) != 0; - const bool has_particles = (ob->particlesystem.first != NULL); - bool skip_object = false; /* Draw particles but not their emitter object. */ - SmokeModifierData *smd = NULL; - - if (ob != scene->obedit) { - if (ob->restrictflag & OB_RESTRICT_VIEW) - return; - - if (render_override) { - if (ob->restrictflag & OB_RESTRICT_RENDER) - return; - - if (!has_particles && (ob->transflag & (OB_DUPLI & ~OB_DUPLIFRAMES))) - return; - } - } - - if (has_particles) { - /* XXX particles are not safe for simultaneous threaded render */ - if (G.is_rendering) { - return; - } - - if (ob->mode == OB_MODE_OBJECT) { - ParticleSystem *psys; - - skip_object = render_override; - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - /* Once we have found a psys which renders its emitter object, we are done. */ - if (psys->part->draw & PART_DRAW_EMITTER) { - skip_object = false; - break; - } - } - } - } - - if (((base->flag & OB_FROMDUPLI) == 0) && - (md = modifiers_findByType(ob, eModifierType_Smoke)) && - (modifier_isEnabled(scene, md, eModifierMode_Realtime))) - { - smd = (SmokeModifierData *)md; - - if (smd->domain) { - if (!v3d->transp && (dflag & DRAW_PICKING) == 0) { - if (!v3d->xray && !(ob->dtx & OB_DRAWXRAY)) { - /* object has already been drawn so skip drawing it */ - ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag); - return; - } - else if (v3d->xray) { - /* object has already been drawn so skip drawing it */ - ED_view3d_after_add(&v3d->afterdraw_xraytransp, base, dflag); - return; - } - } - } - } - - - /* xray delay? */ - if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - /* don't do xray in particle mode, need the z-buffer */ - if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) { - /* xray and transp are set when it is drawing the 2nd/3rd pass */ - if (!v3d->xray && !v3d->transp && (ob->dtx & OB_DRAWXRAY) && !(ob->dtx & OB_DRAWTRANSP)) { - ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag); - return; - } - - /* allow transp option for empty images */ - if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) { - if (!v3d->xray && !v3d->transp && !(ob->dtx & OB_DRAWXRAY) && (ob->dtx & OB_DRAWTRANSP)) { - ED_view3d_after_add(&v3d->afterdraw_transp, base, dflag); - return; - } - } - } - } - - - /* -------------------------------------------------------------------- */ - /* no return after this point, otherwise leaks */ - - /* only once set now, will be removed too, should become a global standard */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - /* reset here to avoid having to call all over */ - glLineWidth(1.0f); - - view3d_cached_text_draw_begin(); - - /* draw motion paths (in view space) */ - if (ob->mpath && !render_override) { - bAnimVizSettings *avs = &ob->avs; - - /* setup drawing environment for paths */ - draw_motion_paths_init(v3d, ar); - - /* draw motion path for object */ - draw_motion_path_instance(scene, ob, NULL, avs, ob->mpath); - - /* cleanup after drawing */ - draw_motion_paths_cleanup(v3d); - } - - /* multiply view with object matrix. - * local viewmat and persmat, to calculate projections */ - ED_view3d_init_mats_rv3d_gl(ob, rv3d); - - /* which wire color */ - if ((dflag & DRAW_CONSTCOLOR) == 0) { - - ED_view3d_project_base(ar, base); - - draw_object_wire_color(scene, base, _ob_wire_col); - ob_wire_col = _ob_wire_col; - - glColor3ubv(ob_wire_col); - } - - /* maximum drawtype */ - char dt = v3d->drawtype; - if (dt == OB_RENDER) dt = v3d->prev_drawtype; - dt = MIN2(dt, ob->dt); - if (v3d->zbuf == 0 && dt > OB_WIRE) dt = OB_WIRE; - short dtx = 0; - - - /* faceselect exception: also draw solid when (dt == wire), except in editmode */ - if (is_obact) { - if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) { - if (ob->type == OB_MESH) { - if (dt < OB_SOLID) { - zbufoff = true; - dt = OB_SOLID; - } - - if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { - dt = OB_PAINT; - } - - is_paint = true; - glEnable(GL_DEPTH_TEST); - } - } - } - - /* matcap check - only when not painting color */ - if ((v3d->flag2 & V3D_SOLID_MATCAP) && - (dt == OB_SOLID) && - (is_paint == false && is_picking == false) && - ((v3d->flag2 & V3D_RENDER_SHADOW) == 0)) - { - draw_object_matcap_check(v3d, ob); - } - - /* draw-extra supported for boundbox drawmode too */ - if (dt >= OB_BOUNDBOX) { - dtx = ob->dtx; - if (ob->mode & OB_MODE_EDIT) { - /* the only 2 extra drawtypes alowed in editmode */ - dtx = dtx & (OB_DRAWWIRE | OB_TEXSPACE); - } - } - - if (!skip_object) { - /* draw outline for selected objects, mesh does itself */ - if ((v3d->flag & V3D_SELECT_OUTLINE) && !render_override && ob->type != OB_MESH) { - if (dt > OB_WIRE && (ob->mode & OB_MODE_EDIT) == 0 && (dflag & DRAW_SCENESET) == 0) { - if (!(ob->dtx & OB_DRAWWIRE) && (ob->flag & SELECT) && !(dflag & (DRAW_PICKING | DRAW_CONSTCOLOR))) { - draw_object_selected_outline(bmain, scene, v3d, ar, base, ob_wire_col); - } - } - } - - switch (ob->type) { - case OB_MESH: - empty_object = draw_mesh_object(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag); - if ((dflag & DRAW_CONSTCOLOR) == 0) { - /* mesh draws wire itself */ - dtx &= ~OB_DRAWWIRE; - } - - break; - case OB_FONT: - cu = ob->data; - if (cu->editfont) { - draw_editfont(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col); - } - else if (dt == OB_BOUNDBOX) { - if ((render_override && v3d->drawtype >= OB_WIRE) == 0) { -#ifdef SEQUENCER_DAG_WORKAROUND - ensure_curve_cache(bmain, scene, base->object); -#endif - draw_bounding_volume(ob, ob->boundtype); - } - } - else if (ED_view3d_boundbox_clip(rv3d, ob->bb)) { - empty_object = drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col); - } - - break; - case OB_CURVE: - case OB_SURF: - cu = ob->data; - - if (cu->editnurb) { - ListBase *nurbs = BKE_curve_editNurbs_get(cu); - draw_editnurb(bmain, scene, v3d, rv3d, base, nurbs->first, dt, dflag, ob_wire_col); - } - else if (dt == OB_BOUNDBOX) { - if ((render_override && (v3d->drawtype >= OB_WIRE)) == 0) { -#ifdef SEQUENCER_DAG_WORKAROUND - ensure_curve_cache(bmain, scene, base->object); -#endif - draw_bounding_volume(ob, ob->boundtype); - } - } - else if (ED_view3d_boundbox_clip(rv3d, ob->bb)) { - empty_object = drawDispList(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col); - } - break; - case OB_MBALL: - { - MetaBall *mb = ob->data; - - if (mb->editelems) - drawmball(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col); - else if (dt == OB_BOUNDBOX) { - if ((render_override && (v3d->drawtype >= OB_WIRE)) == 0) { -#ifdef SEQUENCER_DAG_WORKAROUND - ensure_curve_cache(bmain, scene, base->object); -#endif - draw_bounding_volume(ob, ob->boundtype); - } - } - else - empty_object = drawmball(bmain, scene, v3d, rv3d, base, dt, dflag, ob_wire_col); - break; - } - case OB_EMPTY: - if (!render_override) { - if (ob->empty_drawtype == OB_EMPTY_IMAGE) { - draw_empty_image(ob, dflag, ob_wire_col, v3d->multiview_eye); - } - else { - drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); - } - } - break; - case OB_LAMP: - if (!render_override) { - drawlamp(v3d, rv3d, base, dt, dflag, ob_wire_col, is_obact); - } - break; - case OB_CAMERA: - if (!render_override || - (rv3d->persp == RV3D_CAMOB && v3d->camera == ob)) /* special exception for active camera */ - { - drawcamera(scene, v3d, rv3d, base, dflag, ob_wire_col); - } - break; - case OB_SPEAKER: - if (!render_override) - drawspeaker(scene, v3d, rv3d, ob, dflag); - break; - case OB_LATTICE: - if (!render_override) { - /* Do not allow boundbox in edit nor pose mode! */ - if ((dt == OB_BOUNDBOX) && (ob->mode & OB_MODE_EDIT)) - dt = OB_WIRE; - if (dt == OB_BOUNDBOX) { - draw_bounding_volume(ob, ob->boundtype); - } - else { -#ifdef SEQUENCER_DAG_WORKAROUND - ensure_curve_cache(bmain, scene, ob); -#endif - drawlattice(v3d, ob); - } - } - break; - case OB_ARMATURE: - if (!render_override) { - /* Do not allow boundbox in edit nor pose mode! */ - if ((dt == OB_BOUNDBOX) && (ob->mode & (OB_MODE_EDIT | OB_MODE_POSE))) - dt = OB_WIRE; - if (dt == OB_BOUNDBOX) { - draw_bounding_volume(ob, ob->boundtype); - } - else { - glLineWidth(1.0f); - empty_object = draw_armature(scene, v3d, ar, base, dt, dflag, ob_wire_col, false); - } - } - break; - default: - if (!render_override) { - drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS); - } - break; - } - - if (!render_override) { - if (ob->soft /*&& dflag & OB_SBMOTION*/) { - float mrt[3][3], msc[3][3], mtr[3][3]; - SoftBody *sb = NULL; - float tipw = 0.5f, tiph = 0.5f, drawsize = 4.0f; - if ((sb = ob->soft)) { - if (sb->solverflags & SBSO_ESTIMATEIPO) { - - glLoadMatrixf(rv3d->viewmat); - copy_m3_m3(msc, sb->lscale); - copy_m3_m3(mrt, sb->lrot); - mul_m3_m3m3(mtr, mrt, msc); - ob_draw_RE_motion(sb->lcom, mtr, tipw, tiph, drawsize); - glMultMatrixf(ob->obmat); - } - } - } - - if (ob->pd && ob->pd->forcefield) { - draw_forcefield(ob, rv3d, dflag, ob_wire_col); - } - } - } - - /* code for new particle system */ - if ((ob->particlesystem.first) && - (ob != scene->obedit)) - { - ParticleSystem *psys; - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - /* for visibility, also while wpaint */ - if (col || (ob->flag & SELECT)) { - cpack(0xFFFFFF); - } - } - //glDepthMask(GL_FALSE); - - glLoadMatrixf(rv3d->viewmat); - - view3d_cached_text_draw_begin(); - - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - /* run this so that possible child particles get cached */ - if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) { - PTCacheEdit *edit = PE_create_current(bmain, scene, ob); - if (edit && edit->psys == psys) - draw_update_ptcache_edit(bmain, scene, ob, edit); - } - - draw_new_particle_system(scene, v3d, rv3d, base, psys, dt, dflag); - } - invert_m4_m4(ob->imat, ob->obmat); - view3d_cached_text_draw_end(v3d, ar, 0); - - glMultMatrixf(ob->obmat); - - //glDepthMask(GL_TRUE); - if (col) cpack(col); - } - - /* draw edit particles last so that they can draw over child particles */ - if ((dflag & DRAW_PICKING) == 0 && - (!scene->obedit)) - { - - if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) { - PTCacheEdit *edit = PE_create_current(bmain, scene, ob); - if (edit) { - glLoadMatrixf(rv3d->viewmat); - draw_update_ptcache_edit(bmain, scene, ob, edit); - draw_ptcache_edit(scene, v3d, edit); - glMultMatrixf(ob->obmat); - } - } - } - - /* draw code for smoke, only draw domains */ - if (smd && smd->domain) { - SmokeDomainSettings *sds = smd->domain; - float viewnormal[3]; - - glLoadMatrixf(rv3d->viewmat); - glMultMatrixf(ob->obmat); - - if (!render_override) { - BoundBox bb; - float p0[3], p1[3]; - - /* draw max domain bounds */ - if ((sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN)) { - VECSUBFAC(p0, sds->p0, sds->cell_size, sds->adapt_res); - VECADDFAC(p1, sds->p1, sds->cell_size, sds->adapt_res); - BKE_boundbox_init_from_minmax(&bb, p0, p1); - draw_box(bb.vec, false); - } - - /* draw a single voxel to hint the user about the resolution of the fluid */ - copy_v3_v3(p0, sds->p0); - - if (sds->flags & MOD_SMOKE_HIGHRES) { - madd_v3_v3v3fl(p1, p0, sds->cell_size, 1.0f / (sds->amplify + 1)); - } - else { - add_v3_v3v3(p1, p0, sds->cell_size); - } - - BKE_boundbox_init_from_minmax(&bb, p0, p1); - draw_box(bb.vec, false); - } - - /* don't show smoke before simulation starts, this could be made an option in the future */ - if (sds->fluid && CFRA >= sds->point_cache[0]->startframe) { - float p0[3], p1[3]; - - /* get view vector */ - invert_m4_m4(ob->imat, ob->obmat); - mul_v3_mat3_m4v3(viewnormal, ob->imat, rv3d->viewinv[2]); - normalize_v3(viewnormal); - - /* set dynamic boundaries to draw the volume - * also scale cube to global space to equalize volume slicing on all axes - * (it's scaled back before drawing) */ - p0[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_min[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]); - p0[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_min[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]); - p0[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_min[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]); - p1[0] = (sds->p0[0] + sds->cell_size[0] * sds->res_max[0] + sds->obj_shift_f[0]) * fabsf(ob->size[0]); - p1[1] = (sds->p0[1] + sds->cell_size[1] * sds->res_max[1] + sds->obj_shift_f[1]) * fabsf(ob->size[1]); - p1[2] = (sds->p0[2] + sds->cell_size[2] * sds->res_max[2] + sds->obj_shift_f[2]) * fabsf(ob->size[2]); - - if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { - sds->tex = NULL; - GPU_create_smoke(smd, 0); - draw_smoke_volume(sds, ob, p0, p1, viewnormal); - GPU_free_smoke(smd); - } - else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { - sds->tex = NULL; - GPU_create_smoke(smd, 1); - draw_smoke_volume(sds, ob, p0, p1, viewnormal); - GPU_free_smoke(smd); - } - - /* smoke debug render */ - if (!render_override && sds->draw_velocity) { - draw_smoke_velocity(sds, viewnormal); - } - } - } - - if (!render_override) { - bConstraint *con; - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_RIGIDBODYJOINT) { - bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)con->data; - if (data->flag & CONSTRAINT_DRAW_PIVOT) - draw_rigid_body_pivot(data, dflag, ob_wire_col); - } - } - - if ((ob->gameflag & OB_BOUNDS) && (ob->mode == OB_MODE_OBJECT)) { - if (ob->boundtype != ob->collision_boundtype || (dtx & OB_DRAWBOUNDOX) == 0) { - setlinestyle(2); - draw_bounding_volume(ob, ob->collision_boundtype); - setlinestyle(0); - } - } - if (ob->rigidbody_object) { - draw_rigidbody_shape(ob); - } - - /* draw extra: after normal draw because of makeDispList */ - if (dtx && (G.f & G_RENDER_OGL) == 0) { - - if (dtx & OB_AXIS) { - drawaxes(rv3d->viewmatob, 1.0f, OB_ARROWS); - } - if (dtx & OB_DRAWBOUNDOX) { - draw_bounding_volume(ob, ob->boundtype); - } - if (dtx & OB_TEXSPACE) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - /* prevent random colors being used */ - glColor3ubv(ob_wire_col); - } - drawtexspace(ob); - } - if (dtx & OB_DRAWNAME) { - /* patch for several 3d cards (IBM mostly) that crash on GL_SELECT with text drawing */ - /* but, we also don't draw names for sets or duplicators */ - if (dflag == 0) { - const float zero[3] = {0, 0, 0}; - view3d_cached_text_draw_add(zero, ob->id.name + 2, strlen(ob->id.name + 2), 10, 0, ob_wire_col); - } - } - if ((dtx & OB_DRAWWIRE) && dt >= OB_SOLID) { - if ((dflag & DRAW_CONSTCOLOR) == 0) { - draw_wire_extra(scene, rv3d, ob, ob_wire_col); - } - } - } - } - - if ((dt <= OB_SOLID) && !render_override) { - if (((ob->gameflag & OB_DYNAMIC) && - ((ob->gameflag & OB_BOUNDS) == 0)) || - - ((ob->gameflag & OB_BOUNDS) && - (ob->collision_boundtype == OB_BOUND_SPHERE))) - { - float imat[4][4], vec[3] = {0.0f, 0.0f, 0.0f}; - - invert_m4_m4(imat, rv3d->viewmatob); - - if ((dflag & DRAW_CONSTCOLOR) == 0) { - /* prevent random colors being used */ - glColor3ubv(ob_wire_col); - } - - setlinestyle(2); - drawcircball(GL_LINE_LOOP, vec, ob->inertia, imat); - setlinestyle(0); - } - } - - /* return warning, this is cached text draw */ - invert_m4_m4(ob->imat, ob->obmat); - view3d_cached_text_draw_end(v3d, ar, 1); - /* return warning, clear temp flag */ - v3d->flag2 &= ~V3D_SHOW_SOLID_MATCAP; - - glLoadMatrixf(rv3d->viewmat); - - if (zbufoff) { - glDisable(GL_DEPTH_TEST); - } - - if ((base->flag & OB_FROMDUPLI) || render_override) { - ED_view3d_clear_mats_rv3d(rv3d); - return; - } - - /* object centers, need to be drawn in viewmat space for speed, but OK for picking select */ - if (!is_obact || !(ob->mode & OB_MODE_ALL_PAINT)) { - int do_draw_center = -1; /* defines below are zero or positive... */ - - if (render_override) { - /* don't draw */ - } - else if (is_obact) - do_draw_center = ACTIVE; - else if (base->flag & SELECT) - do_draw_center = SELECT; - else if (empty_object || (v3d->flag & V3D_DRAW_CENTERS)) - do_draw_center = DESELECT; - - if (do_draw_center != -1) { - if (dflag & DRAW_PICKING) { - /* draw a single point for opengl selection */ - if ((base->sx != IS_CLIPPED) && - (U.obcenter_dia != 0.0)) - { - glPointSize(U.obcenter_dia); - glBegin(GL_POINTS); - glVertex3fv(ob->obmat[3]); - glEnd(); - } - } - else if ((dflag & DRAW_CONSTCOLOR) == 0) { - /* we don't draw centers for duplicators and sets */ - if ((base->sx != IS_CLIPPED) && - (U.obcenter_dia != 0.0) && - !(G.f & G_RENDER_OGL)) - { - /* check > 0 otherwise grease pencil can draw into the circle select which is annoying. */ - drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ID_IS_LINKED(ob) || ob->id.us > 1); - } - } - } - } - - /* not for sets, duplicators or picking */ - if (dflag == 0 && (v3d->flag & V3D_HIDE_HELPLINES) == 0 && !render_override) { - ListBase *list; - RigidBodyCon *rbc = ob->rigidbody_constraint; - - /* draw hook center and offset line */ - if (ob != scene->obedit) - draw_hooks(ob); - - /* help lines and so */ - if (ob != scene->obedit && ob->parent && (ob->parent->lay & v3d->lay)) { - setlinestyle(3); - glBegin(GL_LINES); - glVertex3fv(ob->obmat[3]); - glVertex3fv(ob->orig); - glEnd(); - setlinestyle(0); - } - - /* Drawing the constraint lines */ - if (ob->constraints.first) { - bConstraint *curcon; - bConstraintOb *cob; - unsigned char col1[4], col2[4]; - - list = &ob->constraints; - - UI_GetThemeColor3ubv(TH_GRID, col1); - UI_make_axis_color(col1, col2, 'Z'); - glColor3ubv(col2); - - cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); - - for (curcon = list->first; curcon; curcon = curcon->next) { - if (ELEM(curcon->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_OBJECTSOLVER)) { - /* special case for object solver and follow track constraints because they don't fill - * constraint targets properly (design limitation -- scene is needed for their target - * but it can't be accessed from get_targets callback) */ - - Object *camob = NULL; - - if (curcon->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *)curcon->data; - - camob = data->camera ? data->camera : scene->camera; - } - else if (curcon->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - bObjectSolverConstraint *data = (bObjectSolverConstraint *)curcon->data; - - camob = data->camera ? data->camera : scene->camera; - } - - if (camob) { - setlinestyle(3); - glBegin(GL_LINES); - glVertex3fv(camob->obmat[3]); - glVertex3fv(ob->obmat[3]); - glEnd(); - setlinestyle(0); - } - } - else { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon); - - if ((cti && cti->get_constraint_targets) && (curcon->flag & CONSTRAINT_EXPAND)) { - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - cti->get_constraint_targets(curcon, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - /* calculate target's matrix */ - if (cti->get_target_matrix) - cti->get_target_matrix(curcon, cob, ct, BKE_scene_frame_get(scene)); - else - unit_m4(ct->matrix); - - setlinestyle(3); - glBegin(GL_LINES); - glVertex3fv(ct->matrix[3]); - glVertex3fv(ob->obmat[3]); - glEnd(); - setlinestyle(0); - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(curcon, &targets, 1); - } - } - } - - BKE_constraints_clear_evalob(cob); - } - /* draw rigid body constraint lines */ - if (rbc) { - UI_ThemeColor(TH_WIRE); - setlinestyle(3); - glBegin(GL_LINES); - if (rbc->ob1) { - glVertex3fv(ob->obmat[3]); - glVertex3fv(rbc->ob1->obmat[3]); - } - if (rbc->ob2) { - glVertex3fv(ob->obmat[3]); - glVertex3fv(rbc->ob2->obmat[3]); - } - glEnd(); - setlinestyle(0); - } - } - - ED_view3d_clear_mats_rv3d(rv3d); -} - - -/** - * Drawing for selection picking, - * caller must have called 'GPU_select_load_id(base->selcode)' first. - */ -void draw_object_select(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short dflag) -{ - BLI_assert(dflag & DRAW_PICKING && dflag & DRAW_CONSTCOLOR); - draw_object(bmain, scene, ar, v3d, base, dflag); - - /* we draw duplicators for selection too */ - if ((base->object->transflag & OB_DUPLI)) { - ListBase *lb; - DupliObject *dob; - Base tbase; - - tbase.flag = OB_FROMDUPLI; - lb = object_duplilist(bmain, bmain->eval_ctx, scene, base->object); - - for (dob = lb->first; dob; dob = dob->next) { - float omat[4][4]; - char dt; - short dtx; - - tbase.object = dob->ob; - copy_m4_m4(omat, dob->ob->obmat); - copy_m4_m4(dob->ob->obmat, dob->mat); - - /* extra service: draw the duplicator in drawtype of parent */ - /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ - dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); - dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx; - - draw_object(bmain, scene, ar, v3d, &tbase, dflag); - - tbase.object->dt = dt; - tbase.object->dtx = dtx; - - copy_m4_m4(dob->ob->obmat, omat); - } - free_object_duplilist(lb); - } -} - /* ***************** BACKBUF SEL (BBS) ********* */ -static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) +static void bbs_obmode_mesh_verts(Object *ob, int offset) { - drawMVertOffset_userData *data = userData; - MVert *mv = &data->mvert[index]; - - if (!(mv->flag & ME_HIDE)) { - GPU_select_index_set(data->offset + index); - glVertex3fv(co); - } -} - -static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset) -{ - drawMVertOffset_userData data; Mesh *me = ob->data; - MVert *mvert = me->mvert; - data.mvert = mvert; - data.offset = offset; - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - glBegin(GL_POINTS); - dm->foreachMappedVert(dm, bbs_obmode_mesh_verts__mapFunc, &data, DM_FOREACH_NOP); - glEnd(); -} - -static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), const short UNUSED(no_s[3])) -{ - drawBMOffset_userData *data = userData; - BMVert *eve = BM_vert_at_index(data->bm, index); - - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - GPU_select_index_set(data->offset + index); - glVertex3fv(co); - } -} -static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset) -{ - drawBMOffset_userData data = {em->bm, offset}; - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); - glBegin(GL_POINTS); - dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, &data, DM_FOREACH_NOP); - glEnd(); + GPUBatch *batch = DRW_mesh_batch_cache_get_verts_with_select_id(me, offset); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); + GPU_batch_draw(batch); } -static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index) +static void bbs_mesh_verts(BMEditMesh *em, int offset) { - drawBMOffset_userData *data = userData; - BMEdge *eed = BM_edge_at_index(data->bm, index); + GPU_point_size(UI_GetThemeValuef(TH_VERTEX_SIZE)); - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - GPU_select_index_set(data->offset + index); - return DM_DRAW_OPTION_NORMAL; - } - else { - return DM_DRAW_OPTION_SKIP; - } -} -static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) -{ - drawBMOffset_userData data = {em->bm, offset}; - glLineWidth(1); - dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, &data); + Mesh *me = em->ob->data; + GPUBatch *batch = DRW_mesh_batch_cache_get_verts_with_select_id(me, offset); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); + GPU_batch_draw(batch); } -/** - * dont set #GPU_framebuffer_index_set. just use to mask other - */ -static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index) +static void bbs_mesh_wire(BMEditMesh *em, int offset) { - BMFace *efa = BM_face_at_index(userData, index); + GPU_line_width(1.0f); - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - return DM_DRAW_OPTION_NORMAL; - } - else { - return DM_DRAW_OPTION_SKIP; - } + Mesh *me = em->ob->data; + GPUBatch *batch = DRW_mesh_batch_cache_get_edges_with_select_id(me, offset); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); + GPU_batch_draw(batch); } -static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int index) +static void bbs_mesh_face(BMEditMesh *em, const bool use_select) { - BMFace *efa = BM_face_at_index(userData, index); + Mesh *me = em->ob->data; + GPUBatch *batch; - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - GPU_select_index_set(index + 1); - return DM_DRAW_OPTION_NORMAL; + if (use_select) { + batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, true, 1); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); + GPU_batch_draw(batch); } else { - return DM_DRAW_OPTION_SKIP; + int selcol; + GPU_select_index_get(0, &selcol); + batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32); + GPU_batch_uniform_1ui(batch, "color", selcol); + GPU_batch_draw(batch); } } -static void bbs_mesh_solid__drawCenter(void *userData, int index, const float cent[3], const float UNUSED(no[3])) +static void bbs_mesh_face_dot(BMEditMesh *em) { - BMFace *efa = BM_face_at_index(userData, index); - - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - GPU_select_index_set(index + 1); - - glVertex3fv(cent); - } + Mesh *me = em->ob->data; + GPUBatch *batch = DRW_mesh_batch_cache_get_facedots_with_select_id(me, 1); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); + GPU_batch_draw(batch); } /* two options, facecolors or black */ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, - Object *ob, DerivedMesh *dm, bool use_faceselect) + Object *ob, bool use_faceselect) { - cpack(0); - if (use_faceselect) { - dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, NULL, NULL, em->bm, DM_DRAW_SKIP_HIDDEN | DM_DRAW_SELECT_USE_EDITMODE); + bbs_mesh_face(em, true); if (check_ob_drawface_dot(scene, v3d, ob->dt)) { - glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE)); - - glBegin(GL_POINTS); - dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, em->bm, DM_FOREACH_NOP); - glEnd(); + bbs_mesh_face_dot(em); } - - } - else { - dm->drawMappedFaces(dm, bbs_mesh_mask__setSolidDrawOptions, NULL, NULL, em->bm, DM_DRAW_SKIP_SELECT | DM_DRAW_SKIP_HIDDEN | DM_DRAW_SELECT_USE_EDITMODE); - } -} - -static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index) -{ - GPU_select_index_set(index + 1); - return DM_DRAW_OPTION_NORMAL; -} - -static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index) -{ - Mesh *me = userData; - - if (!(me->mpoly[index].flag & ME_HIDE)) { - GPU_select_index_set(index + 1); - return DM_DRAW_OPTION_NORMAL; - } - else { - return DM_DRAW_OPTION_SKIP; - } -} - -/* must have called GPU_framebuffer_index_set beforehand */ -static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index) -{ - Mesh *me = userData; - - if (!(me->mpoly[index].flag & ME_HIDE)) { - return DM_DRAW_OPTION_NORMAL; } else { - return DM_DRAW_OPTION_SKIP; + bbs_mesh_face(em, false); } } -static void bbs_mesh_solid_verts(Scene *scene, Object *ob) +static void bbs_mesh_solid_verts(Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *ob) { Mesh *me = ob->data; - DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); - glColor3ub(0, 0, 0); - - DM_update_materials(dm, ob); /* Only draw faces to mask out verts, we don't want their selection ID's. */ const int G_f_orig = G.f; G.f &= ~G_BACKBUFSEL; - dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, NULL, NULL, me, DM_DRAW_SKIP_HIDDEN); + { + int selcol; + GPUBatch *batch; + GPU_select_index_get(0, &selcol); + batch = DRW_mesh_batch_cache_get_triangles_with_select_mask(me, true); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR_U32); + GPU_batch_uniform_1ui(batch, "color", selcol); + GPU_batch_draw(batch); + } G.f |= (G_f_orig & G_BACKBUFSEL); - bbs_obmode_mesh_verts(ob, dm, 1); + bbs_obmode_mesh_verts(ob, 1); bm_vertoffs = me->totvert + 1; - dm->release(dm); } -static void bbs_mesh_solid_faces(Scene *scene, Object *ob) +static void bbs_mesh_solid_faces(Scene *UNUSED(scene), Object *ob) { - DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask); Mesh *me = ob->data; - - glColor3ub(0, 0, 0); - - DM_update_materials(dm, ob); - - if ((me->editflag & ME_EDIT_PAINT_FACE_SEL)) - dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, NULL, NULL, me, DM_DRAW_SKIP_HIDDEN); - else - dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, NULL, NULL, me, 0); - - dm->release(dm); + Mesh *me_orig = DEG_get_original_object(ob)->data; + GPUBatch *batch; + if ((me_orig->editflag & ME_EDIT_PAINT_FACE_SEL)) { + batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, true, 1); + } + else { + batch = DRW_mesh_batch_cache_get_triangles_with_select_id(me, false, 1); + } + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); + GPU_batch_draw(batch); } -void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob) +void draw_object_backbufsel( + Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, + short select_mode) { ToolSettings *ts = scene->toolsettings; + if (select_mode == -1) { + select_mode = ts->selectmode; + } - glMultMatrixf(ob->obmat); + GPU_matrix_mul(ob->obmat); - glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT); - glEnable(GL_DEPTH_TEST); + glClearDepth(1.0); GPU_clear(GPU_DEPTH_BIT); + GPU_depth_test(true); switch (ob->type) { case OB_MESH: @@ -8427,14 +327,10 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec Mesh *me = ob->data; BMEditMesh *em = me->edit_btmesh; - DerivedMesh *dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); - BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); - DM_update_materials(dm, ob); - - bbs_mesh_solid_EM(em, scene, v3d, ob, dm, (ts->selectmode & SCE_SELECT_FACE) != 0); - if (ts->selectmode & SCE_SELECT_FACE) + bbs_mesh_solid_EM(em, scene, v3d, ob, (select_mode & SCE_SELECT_FACE) != 0); + if (select_mode & SCE_SELECT_FACE) bm_solidoffs = 1 + em->bm->totface; else { bm_solidoffs = 1; @@ -8443,8 +339,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec ED_view3d_polygon_offset(rv3d, 1.0); /* we draw edges if edge select mode */ - if (ts->selectmode & SCE_SELECT_EDGE) { - bbs_mesh_wire(em, dm, bm_solidoffs); + if (select_mode & SCE_SELECT_EDGE) { + bbs_mesh_wire(em, bm_solidoffs); bm_wireoffs = bm_solidoffs + em->bm->totedge; } else { @@ -8453,8 +349,8 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec } /* we draw verts if vert select mode. */ - if (ts->selectmode & SCE_SELECT_VERTEX) { - bbs_mesh_verts(em, dm, bm_wireoffs); + if (select_mode & SCE_SELECT_VERTEX) { + bbs_mesh_verts(em, bm_wireoffs); bm_vertoffs = bm_wireoffs + em->bm->totvert; } else { @@ -8462,8 +358,6 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec } ED_view3d_polygon_offset(rv3d, 0.0); - - dm->release(dm); } else { Mesh *me = ob->data; @@ -8471,7 +365,7 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec /* currently vertex select supports weight paint and vertex paint*/ ((ob->mode & OB_MODE_WEIGHT_PAINT) || (ob->mode & OB_MODE_VERTEX_PAINT))) { - bbs_mesh_solid_verts(scene, ob); + bbs_mesh_solid_verts(depsgraph, scene, ob); } else { bbs_mesh_solid_faces(scene, ob); @@ -8483,77 +377,107 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec break; } - glLoadMatrixf(rv3d->viewmat); + GPU_matrix_set(rv3d->viewmat); } -/* ************* draw object instances for bones, for example ****************** */ -/* assumes all matrices/etc set OK */ - -/* helper function for drawing object instances - meshes */ -static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, - Object *ob, const short dt, int outline) +void ED_draw_object_facemap( + Depsgraph *depsgraph, Object *ob, const float col[4], const int facemap) { - Mesh *me = ob->data; - DerivedMesh *dm = NULL, *edm = NULL; - - if (ob->mode & OB_MODE_EDIT) { - edm = editbmesh_get_derived_base(ob, me->edit_btmesh, CD_MASK_BAREMESH); - DM_update_materials(edm, ob); - } - else { - dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - DM_update_materials(dm, ob); + /* happens on undo */ + if (ob->type != OB_MESH || !ob->data) { + return; } - if (dt <= OB_WIRE) { - if (dm) - dm->drawEdges(dm, 1, 0); - else if (edm) - edm->drawEdges(edm, 1, 0); + Mesh *me = ob->data; + { + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + if (ob_eval->runtime.mesh_eval) { + me = ob_eval->runtime.mesh_eval; + } } - else { - if (outline) - draw_mesh_object_outline(v3d, ob, dm ? dm : edm); - if (dm) { - bool glsl = draw_glsl_material(scene, ob, v3d, dt); - GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); - } + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); + /* Just to create the data to pass to immediate mode, grr! */ + const int *facemap_data = CustomData_get_layer(&me->pdata, CD_FACEMAP); + if (facemap_data) { + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); - if (dm) { - dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); - GPU_end_object_materials(); - } - else if (edm) - edm->drawMappedFaces(edm, NULL, GPU_object_material_bind, NULL, NULL, DM_DRAW_NEED_NORMALS); + const MVert *mvert = me->mvert; + const MPoly *mpoly = me->mpoly; + const MLoop *mloop = me->mloop; - GPU_object_material_unbind(); - } + int mpoly_len = me->totpoly; + int mloop_len = me->totloop; - if (edm) edm->release(edm); - if (dm) dm->release(dm); -} + facemap_data = CustomData_get_layer(&me->pdata, CD_FACEMAP); -void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, const char dt, int outline) -{ - if (ob == NULL) - return; + /* use gawain immediate mode fore now */ + const int looptris_len = poly_to_tri_count(mpoly_len, mloop_len); + const int vbo_len_capacity = looptris_len * 3; + int vbo_len_used = 0; - switch (ob->type) { - case OB_MESH: - draw_object_mesh_instance(scene, v3d, rv3d, ob, dt, outline); - break; - case OB_EMPTY: - if (ob->empty_drawtype == OB_EMPTY_IMAGE) { - /* CONSTCOLOR == no wire outline */ - draw_empty_image(ob, DRAW_CONSTCOLOR, NULL, v3d->multiview_eye); + GPUVertFormat format_pos = { 0 }; + const uint pos_id = GPU_vertformat_attr_add(&format_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + GPUVertBuf *vbo_pos = GPU_vertbuf_create_with_format(&format_pos); + GPU_vertbuf_data_alloc(vbo_pos, vbo_len_capacity); + + GPUVertBufRaw pos_step; + GPU_vertbuf_attr_get_raw_data(vbo_pos, pos_id, &pos_step); + + const MPoly *mp; + int i; + if (me->runtime.looptris.array) { + MLoopTri *mlt = me->runtime.looptris.array; + for (mp = mpoly, i = 0; i < mpoly_len; i++, mp++) { + if (facemap_data[i] == facemap) { + for (int j = 2; j < mp->totloop; j++) { + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop[mlt->tri[0]].v].co); + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop[mlt->tri[1]].v].co); + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[mloop[mlt->tri[2]].v].co); + vbo_len_used += 3; + mlt++; + } + } + else { + mlt += mp->totloop - 2; + } } - else { - drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); + } + else { + /* No tessellation data, fan-fill. */ + for (mp = mpoly, i = 0; i < mpoly_len; i++, mp++) { + if (facemap_data[i] == facemap) { + const MLoop *ml_start = &mloop[mp->loopstart]; + const MLoop *ml_a = ml_start + 1; + const MLoop *ml_b = ml_start + 2; + for (int j = 2; j < mp->totloop; j++) { + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[ml_start->v].co); + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[ml_a->v].co); + copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), mvert[ml_b->v].co); + vbo_len_used += 3; + + ml_a++; + ml_b++; + } + } } - break; + } + + if (vbo_len_capacity != vbo_len_used) { + GPU_vertbuf_data_resize(vbo_pos, vbo_len_used); + } + + GPUBatch *draw_batch = GPU_batch_create(GPU_PRIM_TRIS, vbo_pos, NULL); + GPU_batch_program_set_builtin(draw_batch, GPU_SHADER_3D_UNIFORM_COLOR); + GPU_batch_uniform_4fv(draw_batch, "color", col); + GPU_batch_draw(draw_batch); + GPU_batch_discard(draw_batch); + GPU_vertbuf_discard(vbo_pos); + + GPU_blend(false); } } diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c deleted file mode 100644 index 9165147736a..00000000000 --- a/source/blender/editors/space_view3d/drawsimdebug.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2014 by the Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Lukas Toenne - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/drawsimdebug.c - * \ingroup spview3d - */ - -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_view3d_types.h" -#include "DNA_object_types.h" - -#include "BLI_math.h" -#include "BLI_utildefines.h" -#include "BLI_ghash.h" - -#include "BKE_effect.h" - -#include "view3d_intern.h" - -#include "BIF_gl.h" - - -static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4]) -{ - GHashIterator iter; - - /**** dots ****/ - - glPointSize(3.0f); - glBegin(GL_POINTS); - for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); - if (elem->type != SIM_DEBUG_ELEM_DOT) - continue; - - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); - } - glEnd(); - - /**** circles ****/ - - { - float circle[16][2] = { - {0.000000, 1.000000}, {0.382683, 0.923880}, {0.707107, 0.707107}, {0.923880, 0.382683}, - {1.000000, -0.000000}, {0.923880, -0.382683}, {0.707107, -0.707107}, {0.382683, -0.923880}, - {-0.000000, -1.000000}, {-0.382683, -0.923880}, {-0.707107, -0.707107}, {-0.923879, -0.382684}, - {-1.000000, 0.000000}, {-0.923879, 0.382684}, {-0.707107, 0.707107}, {-0.382683, 0.923880} }; - for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); - float radius = elem->v2[0]; - float co[3]; - int i; - - if (elem->type != SIM_DEBUG_ELEM_CIRCLE) - continue; - - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glBegin(GL_LINE_LOOP); - for (i = 0; i < 16; ++i) { - co[0] = radius * circle[i][0]; - co[1] = radius * circle[i][1]; - co[2] = 0.0f; - mul_mat3_m4_v3(imat, co); - add_v3_v3(co, elem->v1); - - glVertex3f(co[0], co[1], co[2]); - } - glEnd(); - } - } - - /**** lines ****/ - - glBegin(GL_LINES); - for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); - if (elem->type != SIM_DEBUG_ELEM_LINE) - continue; - - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); - glVertex3f(elem->v2[0], elem->v2[1], elem->v2[2]); - } - glEnd(); - - /**** vectors ****/ - - glPointSize(2.0f); - glBegin(GL_POINTS); - for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); - if (elem->type != SIM_DEBUG_ELEM_VECTOR) - continue; - - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); - } - glEnd(); - - glBegin(GL_LINES); - for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); - float t[3]; - if (elem->type != SIM_DEBUG_ELEM_VECTOR) - continue; - - glColor3f(elem->color[0], elem->color[1], elem->color[2]); - glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]); - add_v3_v3v3(t, elem->v1, elem->v2); - glVertex3f(t[0], t[1], t[2]); - } - glEnd(); - - /**** strings ****/ - - for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); - if (elem->type != SIM_DEBUG_ELEM_STRING) - continue; - - unsigned char col[4]; - rgb_float_to_uchar(col, elem->color); - col[3] = 255; - view3d_cached_text_draw_add(elem->v1, elem->str, strlen(elem->str), - 0, V3D_CACHE_TEXT_GLOBALSPACE, col); - } -} - -void draw_sim_debug_data(Scene *UNUSED(scene), View3D *v3d, ARegion *ar) -{ - RegionView3D *rv3d = ar->regiondata; - /*Object *ob = base->object;*/ - float imat[4][4]; - - if (!_sim_debug_data) - return; - - invert_m4_m4(imat, rv3d->viewmatob); - -// glDepthMask(GL_FALSE); -// glEnable(GL_BLEND); - - glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); - - view3d_cached_text_draw_begin(); - draw_sim_debug_elements(_sim_debug_data, imat); - view3d_cached_text_draw_end(v3d, ar, false); - - glPopMatrix(); - -// glDepthMask(GL_TRUE); -// glDisable(GL_BLEND); -} diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c deleted file mode 100644 index b230a5e193c..00000000000 --- a/source/blender/editors/space_view3d/drawvolume.c +++ /dev/null @@ -1,853 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * Contributor(s): Daniel Genrich - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/drawvolume.c - * \ingroup spview3d - */ - -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_smoke_types.h" -#include "DNA_view3d_types.h" - -#include "BLI_utildefines.h" -#include "BLI_math.h" - -#include "BKE_DerivedMesh.h" -#include "BKE_colorband.h" -#include "BKE_particle.h" - -#include "smoke_API.h" - -#include "BIF_gl.h" - -#include "GPU_debug.h" -#include "GPU_shader.h" -#include "GPU_texture.h" - -#include "view3d_intern.h" // own include - -struct GPUTexture; - -// #define DEBUG_DRAW_TIME - -#ifdef DEBUG_DRAW_TIME -# include "PIL_time.h" -# include "PIL_time_utildefines.h" -#endif - -/* *************************** Transfer functions *************************** */ - -enum { - TFUNC_FLAME_SPECTRUM = 0, - TFUNC_COLOR_RAMP = 1, -}; - -#define TFUNC_WIDTH 256 - -static void create_flame_spectrum_texture(float *data) -{ -#define FIRE_THRESH 7 -#define MAX_FIRE_ALPHA 0.06f -#define FULL_ON_FIRE 100 - - float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); - - blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000); - - for (int i = 0; i < 16; i++) { - for (int j = 0; j < 16; j++) { - for (int k = 0; k < TFUNC_WIDTH; k++) { - int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4; - if (k >= FIRE_THRESH) { - spec_pixels[index] = (data[k * 4]); - spec_pixels[index + 1] = (data[k * 4 + 1]); - spec_pixels[index + 2] = (data[k * 4 + 2]); - spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( - (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); - } - else { - zero_v4(&spec_pixels[index]); - } - } - } - } - - memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH); - - MEM_freeN(spec_pixels); - -#undef FIRE_THRESH -#undef MAX_FIRE_ALPHA -#undef FULL_ON_FIRE -} - -static void create_color_ramp(const ColorBand *coba, float *data) -{ - for (int i = 0; i < TFUNC_WIDTH; i++) { - BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); - } -} - -static GPUTexture *create_transfer_function(int type, const ColorBand *coba) -{ - float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__); - - switch (type) { - case TFUNC_FLAME_SPECTRUM: - create_flame_spectrum_texture(data); - break; - case TFUNC_COLOR_RAMP: - create_color_ramp(coba, data); - break; - } - - GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, data, NULL); - - MEM_freeN(data); - - return tex; -} - -static GPUTexture *create_field_texture(SmokeDomainSettings *sds) -{ - float *field = NULL; - - switch (sds->coba_field) { -#ifdef WITH_SMOKE - case FLUID_FIELD_DENSITY: field = smoke_get_density(sds->fluid); break; - case FLUID_FIELD_HEAT: field = smoke_get_heat(sds->fluid); break; - case FLUID_FIELD_FUEL: field = smoke_get_fuel(sds->fluid); break; - case FLUID_FIELD_REACT: field = smoke_get_react(sds->fluid); break; - case FLUID_FIELD_FLAME: field = smoke_get_flame(sds->fluid); break; - case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break; - case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break; - case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break; - case FLUID_FIELD_COLOR_R: field = smoke_get_color_r(sds->fluid); break; - case FLUID_FIELD_COLOR_G: field = smoke_get_color_g(sds->fluid); break; - case FLUID_FIELD_COLOR_B: field = smoke_get_color_b(sds->fluid); break; - case FLUID_FIELD_FORCE_X: field = smoke_get_force_x(sds->fluid); break; - case FLUID_FIELD_FORCE_Y: field = smoke_get_force_y(sds->fluid); break; - case FLUID_FIELD_FORCE_Z: field = smoke_get_force_z(sds->fluid); break; -#endif - default: return NULL; - } - - return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field); -} - -typedef struct VolumeSlicer { - float size[3]; - float min[3]; - float max[3]; - float (*verts)[3]; -} VolumeSlicer; - -/* *************************** Axis Aligned Slicing ************************** */ - -static void create_single_slice(VolumeSlicer *slicer, const float depth, - const int axis, const int idx) -{ - const float vertices[3][4][3] = { - { - { depth, slicer->min[1], slicer->min[2] }, - { depth, slicer->max[1], slicer->min[2] }, - { depth, slicer->max[1], slicer->max[2] }, - { depth, slicer->min[1], slicer->max[2] } - }, - { - { slicer->min[0], depth, slicer->min[2] }, - { slicer->min[0], depth, slicer->max[2] }, - { slicer->max[0], depth, slicer->max[2] }, - { slicer->max[0], depth, slicer->min[2] } - }, - { - { slicer->min[0], slicer->min[1], depth }, - { slicer->min[0], slicer->max[1], depth }, - { slicer->max[0], slicer->max[1], depth }, - { slicer->max[0], slicer->min[1], depth } - } - }; - - copy_v3_v3(slicer->verts[idx + 0], vertices[axis][0]); - copy_v3_v3(slicer->verts[idx + 1], vertices[axis][1]); - copy_v3_v3(slicer->verts[idx + 2], vertices[axis][2]); - copy_v3_v3(slicer->verts[idx + 3], vertices[axis][0]); - copy_v3_v3(slicer->verts[idx + 4], vertices[axis][2]); - copy_v3_v3(slicer->verts[idx + 5], vertices[axis][3]); -} - -static void create_axis_aligned_slices(VolumeSlicer *slicer, const int num_slices, - const float view_dir[3], const int axis) -{ - float depth, slice_size = slicer->size[axis] / num_slices; - - /* always process slices in back to front order! */ - if (view_dir[axis] > 0.0f) { - depth = slicer->min[axis]; - } - else { - depth = slicer->max[axis]; - slice_size = -slice_size; - } - - int count = 0; - for (int slice = 0; slice < num_slices; slice++) { - create_single_slice(slicer, depth, axis, count); - - count += 6; - depth += slice_size; - } -} - -/* *************************** View Aligned Slicing ************************** */ - -/* Code adapted from: - * "GPU-based Volume Rendering, Real-time Volume Graphics", AK Peters/CRC Press - */ -static int create_view_aligned_slices(VolumeSlicer *slicer, - const int num_slices, - const float view_dir[3]) -{ - const int indices[] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5 }; - - const float vertices[8][3] = { - { slicer->min[0], slicer->min[1], slicer->min[2] }, - { slicer->max[0], slicer->min[1], slicer->min[2] }, - { slicer->max[0], slicer->max[1], slicer->min[2] }, - { slicer->min[0], slicer->max[1], slicer->min[2] }, - { slicer->min[0], slicer->min[1], slicer->max[2] }, - { slicer->max[0], slicer->min[1], slicer->max[2] }, - { slicer->max[0], slicer->max[1], slicer->max[2] }, - { slicer->min[0], slicer->max[1], slicer->max[2] } - }; - - const int edges[12][2] = { - { 0, 1 }, { 1, 2 }, { 2, 3 }, - { 3, 0 }, { 0, 4 }, { 1, 5 }, - { 2, 6 }, { 3, 7 }, { 4, 5 }, - { 5, 6 }, { 6, 7 }, { 7, 4 } - }; - - const int edge_list[8][12] = { - { 0, 1, 5, 6, 4, 8, 11, 9, 3, 7, 2, 10 }, - { 0, 4, 3, 11, 1, 2, 6, 7, 5, 9, 8, 10 }, - { 1, 5, 0, 8, 2, 3, 7, 4, 6, 10, 9, 11 }, - { 7, 11, 10, 8, 2, 6, 1, 9, 3, 0, 4, 5 }, - { 8, 5, 9, 1, 11, 10, 7, 6, 4, 3, 0, 2 }, - { 9, 6, 10, 2, 8, 11, 4, 7, 5, 0, 1, 3 }, - { 9, 8, 5, 4, 6, 1, 2, 0, 10, 7, 11, 3 }, - { 10, 9, 6, 5, 7, 2, 3, 1, 11, 4, 8, 0 } - }; - - /* find vertex that is the furthest from the view plane */ - int max_index = 0; - float max_dist, min_dist; - min_dist = max_dist = dot_v3v3(view_dir, vertices[0]); - - for (int i = 1; i < 8; i++) { - float dist = dot_v3v3(view_dir, vertices[i]); - - if (dist > max_dist) { - max_dist = dist; - max_index = i; - } - - if (dist < min_dist) { - min_dist = dist; - } - } - - max_dist -= FLT_EPSILON; - min_dist += FLT_EPSILON; - - /* start and direction vectors */ - float vec_start[12][3], vec_dir[12][3]; - /* lambda intersection values */ - float lambda[12], lambda_inc[12]; - float denom = 0.0f; - - float plane_dist = min_dist; - float plane_dist_inc = (max_dist - min_dist) / (float)num_slices; - - /* for all edges */ - for (int i = 0; i < 12; i++) { - copy_v3_v3(vec_start[i], vertices[edges[edge_list[max_index][i]][0]]); - copy_v3_v3(vec_dir[i], vertices[edges[edge_list[max_index][i]][1]]); - sub_v3_v3(vec_dir[i], vec_start[i]); - - denom = dot_v3v3(vec_dir[i], view_dir); - - if (1.0f + denom != 1.0f) { - lambda_inc[i] = plane_dist_inc / denom; - lambda[i] = (plane_dist - dot_v3v3(vec_start[i], view_dir)) / denom; - } - else { - lambda[i] = -1.0f; - lambda_inc[i] = 0.0f; - } - } - - float intersections[6][3]; - float dL[12]; - int num_points = 0; - /* find intersections for each slice, process them in back to front order */ - for (int i = 0; i < num_slices; i++) { - for (int e = 0; e < 12; e++) { - dL[e] = lambda[e] + i * lambda_inc[e]; - } - - if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) { - madd_v3_v3v3fl(intersections[0], vec_start[0], vec_dir[0], dL[0]); - } - else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) { - madd_v3_v3v3fl(intersections[0], vec_start[1], vec_dir[1], dL[1]); - } - else if ((dL[3] >= 0.0f) && (dL[3] < 1.0f)) { - madd_v3_v3v3fl(intersections[0], vec_start[3], vec_dir[3], dL[3]); - } - else continue; - - if ((dL[2] >= 0.0f) && (dL[2] < 1.0f)) { - madd_v3_v3v3fl(intersections[1], vec_start[2], vec_dir[2], dL[2]); - } - else if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) { - madd_v3_v3v3fl(intersections[1], vec_start[0], vec_dir[0], dL[0]); - } - else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) { - madd_v3_v3v3fl(intersections[1], vec_start[1], vec_dir[1], dL[1]); - } - else { - madd_v3_v3v3fl(intersections[1], vec_start[3], vec_dir[3], dL[3]); - } - - if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) { - madd_v3_v3v3fl(intersections[2], vec_start[4], vec_dir[4], dL[4]); - } - else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) { - madd_v3_v3v3fl(intersections[2], vec_start[5], vec_dir[5], dL[5]); - } - else { - madd_v3_v3v3fl(intersections[2], vec_start[7], vec_dir[7], dL[7]); - } - - if ((dL[6] >= 0.0f) && (dL[6] < 1.0f)) { - madd_v3_v3v3fl(intersections[3], vec_start[6], vec_dir[6], dL[6]); - } - else if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) { - madd_v3_v3v3fl(intersections[3], vec_start[4], vec_dir[4], dL[4]); - } - else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) { - madd_v3_v3v3fl(intersections[3], vec_start[5], vec_dir[5], dL[5]); - } - else { - madd_v3_v3v3fl(intersections[3], vec_start[7], vec_dir[7], dL[7]); - } - - if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) { - madd_v3_v3v3fl(intersections[4], vec_start[8], vec_dir[8], dL[8]); - } - else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) { - madd_v3_v3v3fl(intersections[4], vec_start[9], vec_dir[9], dL[9]); - } - else { - madd_v3_v3v3fl(intersections[4], vec_start[11], vec_dir[11], dL[11]); - } - - if ((dL[10] >= 0.0f) && (dL[10] < 1.0f)) { - madd_v3_v3v3fl(intersections[5], vec_start[10], vec_dir[10], dL[10]); - } - else if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) { - madd_v3_v3v3fl(intersections[5], vec_start[8], vec_dir[8], dL[8]); - } - else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) { - madd_v3_v3v3fl(intersections[5], vec_start[9], vec_dir[9], dL[9]); - } - else { - madd_v3_v3v3fl(intersections[5], vec_start[11], vec_dir[11], dL[11]); - } - - for (int e = 0; e < 12; e++) { - copy_v3_v3(slicer->verts[num_points++], intersections[indices[e]]); - } - } - - return num_points; -} - -static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec, - GPUTexture *tex_tfunc, GPUTexture *tex_coba, - bool use_fire, const float min[3], - const float ob_sizei[3], const float invsize[3]) -{ - int invsize_location = GPU_shader_get_uniform(shader, "invsize"); - int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei"); - int min_location = GPU_shader_get_uniform(shader, "min_location"); - - int soot_location; - int stepsize_location; - int densityscale_location; - int spec_location, flame_location; - int shadow_location, actcol_location; - int tfunc_location = 0; - int coba_location = 0; - - if (use_fire) { - spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); - flame_location = GPU_shader_get_uniform(shader, "flame_texture"); - } - else { - shadow_location = GPU_shader_get_uniform(shader, "shadow_texture"); - actcol_location = GPU_shader_get_uniform(shader, "active_color"); - soot_location = GPU_shader_get_uniform(shader, "soot_texture"); - stepsize_location = GPU_shader_get_uniform(shader, "step_size"); - densityscale_location = GPU_shader_get_uniform(shader, "density_scale"); - - if (sds->use_coba) { - tfunc_location = GPU_shader_get_uniform(shader, "transfer_texture"); - coba_location = GPU_shader_get_uniform(shader, "color_band_texture"); - } - } - - GPU_shader_bind(shader); - - if (use_fire) { - GPU_texture_bind(sds->tex_flame, 2); - GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame); - - GPU_texture_bind(tex_spec, 3); - GPU_shader_uniform_texture(shader, spec_location, tex_spec); - } - else { - float density_scale = 10.0f * sds->display_thickness; - - GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx); - GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale); - - GPU_texture_bind(sds->tex, 0); - GPU_shader_uniform_texture(shader, soot_location, sds->tex); - - GPU_texture_bind(sds->tex_shadow, 1); - GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow); - - float active_color[3] = { 0.9, 0.9, 0.9 }; - if ((sds->active_fields & SM_ACTIVE_COLORS) == 0) - mul_v3_v3(active_color, sds->active_color); - GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color); - - if (sds->use_coba) { - GPU_texture_bind(tex_tfunc, 4); - GPU_shader_uniform_texture(shader, tfunc_location, tex_tfunc); - - GPU_texture_bind(tex_coba, 5); - GPU_shader_uniform_texture(shader, coba_location, tex_coba); - } - } - - GPU_shader_uniform_vector(shader, min_location, 3, 1, min); - GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei); - GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); -} - -static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, - GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire) -{ - GPU_shader_unbind(); - - GPU_texture_unbind(sds->tex); - - if (use_fire) { - GPU_texture_unbind(sds->tex_flame); - GPU_texture_unbind(tex_spec); - GPU_texture_free(tex_spec); - } - else { - GPU_texture_unbind(sds->tex_shadow); - - if (sds->use_coba) { - GPU_texture_unbind(tex_tfunc); - GPU_texture_free(tex_tfunc); - - GPU_texture_unbind(tex_coba); - GPU_texture_free(tex_coba); - } - } -} - -static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer, - const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire) -{ - GPUTexture *tex_spec = (do_fire) ? create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL) : NULL; - GPUTexture *tex_tfunc = (sds->use_coba) ? create_transfer_function(TFUNC_COLOR_RAMP, sds->coba) : NULL; - GPUTexture *tex_coba = (sds->use_coba) ? create_field_texture(sds) : NULL; - - GLuint vertex_buffer; - glGenBuffers(1, &vertex_buffer); - glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW); - - bind_shader(sds, shader, tex_spec, tex_tfunc, tex_coba, do_fire, slicer->min, ob_sizei, invsize); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, NULL); - - glDrawArrays(GL_TRIANGLES, 0, num_points); - - glDisableClientState(GL_VERTEX_ARRAY); - - unbind_shader(sds, tex_spec, tex_tfunc, tex_coba, do_fire); - - /* cleanup */ - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glDeleteBuffers(1, &vertex_buffer); -} - -void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, - const float min[3], const float max[3], - const float viewnormal[3]) -{ - if (!sds->tex || !sds->tex_shadow) { - fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n"); - return; - } - - const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame; - - GPUBuiltinShader builtin_shader; - - if (sds->use_coba) { - builtin_shader = GPU_SHADER_SMOKE_COBA; - } - else { - builtin_shader = GPU_SHADER_SMOKE; - } - - GPUShader *shader = GPU_shader_get_builtin_shader(builtin_shader); - - if (!shader) { - fprintf(stderr, "Unable to create GLSL smoke shader.\n"); - return; - } - - GPUShader *fire_shader = NULL; - if (use_fire) { - fire_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE_FIRE); - - if (!fire_shader) { - fprintf(stderr, "Unable to create GLSL fire shader.\n"); - return; - } - } - - const float ob_sizei[3] = { - 1.0f / fabsf(ob->size[0]), - 1.0f / fabsf(ob->size[1]), - 1.0f / fabsf(ob->size[2]) - }; - - const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] }; - const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] }; - -#ifdef DEBUG_DRAW_TIME - TIMEIT_START(draw); -#endif - - /* setup slicing information */ - - const bool view_aligned = (sds->slice_method == MOD_SMOKE_SLICE_VIEW_ALIGNED); - int max_slices, max_points, axis = 0; - - if (view_aligned) { - max_slices = max_iii(sds->res[0], sds->res[1], sds->res[2]) * sds->slice_per_voxel; - max_points = max_slices * 12; - } - else { - if (sds->axis_slice_method == AXIS_SLICE_FULL) { - axis = axis_dominant_v3_single(viewnormal); - max_slices = sds->res[axis] * sds->slice_per_voxel; - } - else { - axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewnormal) : sds->slice_axis - 1; - max_slices = 1; - } - - max_points = max_slices * 6; - } - - VolumeSlicer slicer; - copy_v3_v3(slicer.min, min); - copy_v3_v3(slicer.max, max); - copy_v3_v3(slicer.size, size); - slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices"); - - int num_points; - - if (view_aligned) { - num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal); - } - else { - num_points = max_points; - - if (sds->axis_slice_method == AXIS_SLICE_FULL) { - create_axis_aligned_slices(&slicer, max_slices, viewnormal, axis); - } - else { - const float depth = (sds->slice_depth - 0.5f) * size[axis]; - create_single_slice(&slicer, depth, axis, 0); - } - } - - /* setup buffer and draw */ - - int gl_depth = 0, gl_blend = 0, gl_depth_write = 0; - glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); - glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); - glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&gl_depth_write); - - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false); - - /* Draw fire separately (T47639). */ - if (use_fire && !sds->use_coba) { - glBlendFunc(GL_ONE, GL_ONE); - draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true); - } - -#ifdef DEBUG_DRAW_TIME - printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); - TIMEIT_END(draw); -#endif - - MEM_freeN(slicer.verts); - - glDepthMask(gl_depth_write); - - if (!gl_blend) { - glDisable(GL_BLEND); - } - - if (gl_depth) { - glEnable(GL_DEPTH_TEST); - } -} - -#ifdef WITH_SMOKE -static void add_tri(float (*verts)[3], float(*colors)[3], int *offset, - float p1[3], float p2[3], float p3[3], float rgb[3]) -{ - copy_v3_v3(verts[*offset + 0], p1); - copy_v3_v3(verts[*offset + 1], p2); - copy_v3_v3(verts[*offset + 2], p3); - - copy_v3_v3(colors[*offset + 0], rgb); - copy_v3_v3(colors[*offset + 1], rgb); - copy_v3_v3(colors[*offset + 2], rgb); - - *offset += 3; -} - -static void add_needle(float (*verts)[3], float (*colors)[3], float center[3], - float dir[3], float scale, float voxel_size, int *offset) -{ - float len = len_v3(dir); - - float rgb[3]; - weight_to_rgb(rgb, len); - - if (len != 0.0f) { - mul_v3_fl(dir, 1.0f / len); - len *= scale; - } - - len *= voxel_size; - - float corners[4][3] = { - { 0.0f, 0.2f, -0.5f }, - { -0.2f * 0.866f, -0.2f * 0.5f, -0.5f }, - { 0.2f * 0.866f, -0.2f * 0.5f, -0.5f }, - { 0.0f, 0.0f, 0.5f } - }; - - const float up[3] = { 0.0f, 0.0f, 1.0f }; - float rot[3][3]; - - rotation_between_vecs_to_mat3(rot, up, dir); - transpose_m3(rot); - - for (int i = 0; i < 4; i++) { - mul_m3_v3(rot, corners[i]); - mul_v3_fl(corners[i], len); - add_v3_v3(corners[i], center); - } - - add_tri(verts, colors, offset, corners[0], corners[1], corners[2], rgb); - add_tri(verts, colors, offset, corners[0], corners[1], corners[3], rgb); - add_tri(verts, colors, offset, corners[1], corners[2], corners[3], rgb); - add_tri(verts, colors, offset, corners[2], corners[0], corners[3], rgb); -} - -static void add_streamline(float (*verts)[3], float(*colors)[3], float center[3], - float dir[3], float scale, float voxel_size, int *offset) -{ - const float len = len_v3(dir); - - float rgb[3]; - weight_to_rgb(rgb, len); - - copy_v3_v3(colors[(*offset)], rgb); - copy_v3_v3(verts[(*offset)++], center); - - mul_v3_fl(dir, scale * voxel_size); - add_v3_v3(center, dir); - - copy_v3_v3(colors[(*offset)], rgb); - copy_v3_v3(verts[(*offset)++], center); -} - -typedef void (*vector_draw_func)(float(*)[3], float(*)[3], float *, float *, float, float, int *); -#endif /* WITH_SMOKE */ - -void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3]) -{ -#ifdef WITH_SMOKE - const float *vel_x = smoke_get_velocity_x(domain->fluid); - const float *vel_y = smoke_get_velocity_y(domain->fluid); - const float *vel_z = smoke_get_velocity_z(domain->fluid); - - if (ELEM(NULL, vel_x, vel_y, vel_z)) { - return; - } - - const int *base_res = domain->base_res; - const int *res = domain->res; - const int *res_min = domain->res_min; - - int res_max[3]; - copy_v3_v3_int(res_max, domain->res_max); - - const float *cell_size = domain->cell_size; - const float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.0f; - - /* set first position so that it doesn't jump when domain moves */ - float xyz[3] = { - res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size), - res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size), - res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size) - }; - - if (xyz[0] < res_min[0]) xyz[0] += step_size; - if (xyz[1] < res_min[1]) xyz[1] += step_size; - if (xyz[2] < res_min[2]) xyz[2] += step_size; - - float min[3] = { - domain->p0[0] - domain->cell_size[0] * domain->adapt_res, - domain->p0[1] - domain->cell_size[1] * domain->adapt_res, - domain->p0[2] - domain->cell_size[2] * domain->adapt_res, - }; - - int num_points_v[3] = { - ((float)(res_max[0] - floor(xyz[0])) / step_size) + 0.5f, - ((float)(res_max[1] - floor(xyz[1])) / step_size) + 0.5f, - ((float)(res_max[2] - floor(xyz[2])) / step_size) + 0.5f - }; - - if (domain->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED && - domain->axis_slice_method == AXIS_SLICE_SINGLE) - { - const int axis = (domain->slice_axis == SLICE_AXIS_AUTO) ? - axis_dominant_v3_single(viewnormal) : domain->slice_axis - 1; - - xyz[axis] = (float)base_res[axis] * domain->slice_depth; - num_points_v[axis] = 1; - res_max[axis] = xyz[axis] + 1; - } - - vector_draw_func func; - int max_points; - - if (domain->vector_draw_type == VECTOR_DRAW_NEEDLE) { - func = add_needle; - max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 4 * 3; - } - else { - func = add_streamline; - max_points = (num_points_v[0] * num_points_v[1] * num_points_v[2]) * 2; - } - - float (*verts)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, ""); - float (*colors)[3] = MEM_mallocN(sizeof(float) * 3 * max_points, ""); - - int num_points = 0; - - for (float x = floor(xyz[0]); x < res_max[0]; x += step_size) { - for (float y = floor(xyz[1]); y < res_max[1]; y += step_size) { - for (float z = floor(xyz[2]); z < res_max[2]; z += step_size) { - int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1]; - - float pos[3] = { - min[0] + ((float)x + 0.5f) * cell_size[0], - min[1] + ((float)y + 0.5f) * cell_size[1], - min[2] + ((float)z + 0.5f) * cell_size[2] - }; - - float vel[3] = { - vel_x[index], vel_y[index], vel_z[index] - }; - - func(verts, colors, pos, vel, domain->vector_scale, cell_size[0], &num_points); - } - } - } - - glLineWidth(1.0f); - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, verts); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(3, GL_FLOAT, 0, colors); - - glDrawArrays(GL_LINES, 0, num_points); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - MEM_freeN(verts); - MEM_freeN(colors); -#else - UNUSED_VARS(domain, viewnormal); -#endif -} diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index fed056333c0..0e8e5e1ee22 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -32,9 +32,11 @@ #include <string.h> #include <stdio.h> +#include "DNA_lightprobe_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_gpencil_types.h" #include "MEM_guardedalloc.h" @@ -43,31 +45,39 @@ #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" +#include "BKE_curve.h" #include "BKE_icons.h" -#include "BKE_library.h" +#include "BKE_lattice.h" #include "BKE_main.h" +#include "BKE_mball.h" +#include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_workspace.h" #include "ED_space_api.h" #include "ED_screen.h" +#include "ED_transform.h" -#include "GPU_compositing.h" #include "GPU_framebuffer.h" #include "GPU_material.h" +#include "GPU_viewport.h" +#include "GPU_matrix.h" -#include "BIF_gl.h" +#include "DRW_engine.h" #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" +#include "WM_toolsystem.h" #include "RE_engine.h" #include "RE_pipeline.h" #include "RNA_access.h" +#include "UI_interface.h" #include "UI_resources.h" #ifdef WITH_PYTHON @@ -106,17 +116,17 @@ ARegion *view3d_has_buttons_region(ScrArea *sa) ARegion *view3d_has_tools_region(ScrArea *sa) { - ARegion *ar, *artool = NULL, *arprops = NULL, *arhead; + ARegion *ar, *artool = NULL, *arhead; for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->regiontype == RGN_TYPE_TOOLS) artool = ar; - if (ar->regiontype == RGN_TYPE_TOOL_PROPS) - arprops = ar; } /* tool region hide/unhide also hides props */ - if (arprops && artool) return artool; + if (artool) { + return artool; + } if (artool == NULL) { /* add subdiv level; after header */ @@ -135,15 +145,6 @@ ARegion *view3d_has_tools_region(ScrArea *sa) artool->flag = RGN_FLAG_HIDDEN; } - if (arprops == NULL) { - /* add extra subdivided region for tool properties */ - arprops = MEM_callocN(sizeof(ARegion), "tool props for view3d"); - - BLI_insertlinkafter(&sa->regionbase, artool, arprops); - arprops->regiontype = RGN_TYPE_TOOL_PROPS; - arprops->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - } - return artool; } @@ -250,7 +251,7 @@ void ED_view3d_init_mats_rv3d_gl(struct Object *ob, struct RegionView3D *rv3d) /* we have to multiply instead of loading viewmatob to make * it work with duplis using displists, otherwise it will * override the dupli-matrix */ - glMultMatrixf(ob->obmat); + GPU_matrix_mul(ob->obmat); } #ifdef DEBUG @@ -283,8 +284,6 @@ void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar) BPy_END_ALLOW_THREADS; #endif - if (rv3d->render_engine->re) - RE_Database_Free(rv3d->render_engine->re); RE_engine_free(rv3d->render_engine); rv3d->render_engine = NULL; } @@ -294,50 +293,64 @@ void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa) { wmWindowManager *wm = bmain->wm.first; - if (v3d->drawtype != OB_RENDER) { + if (v3d->shading.type != OB_RENDER) { ARegion *ar; for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiondata) + if ((ar->regiontype == RGN_TYPE_WINDOW) && ar->regiondata) { ED_view3d_stop_render_preview(wm, ar); + break; + } } } } /* ******************** default callbacks for view3d space ***************** */ -static SpaceLink *view3d_new(const bContext *C) +static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene) { - Scene *scene = CTX_data_scene(C); ARegion *ar; View3D *v3d; RegionView3D *rv3d; v3d = MEM_callocN(sizeof(View3D), "initview3d"); v3d->spacetype = SPACE_VIEW3D; - v3d->lay = v3d->layact = 1; if (scene) { - v3d->lay = v3d->layact = scene->lay; v3d->camera = scene->camera; } v3d->scenelock = true; v3d->grid = 1.0f; v3d->gridlines = 16; v3d->gridsubdiv = 10; - v3d->drawtype = OB_SOLID; + BKE_screen_view3d_shading_init(&v3d->shading); + + v3d->overlay.wireframe_threshold = 0.5f; + v3d->overlay.xray_alpha_bone = 0.5f; + v3d->overlay.texture_paint_mode_opacity = 0.8; + v3d->overlay.weight_paint_mode_opacity = 1.0f; + v3d->overlay.vertex_paint_mode_opacity = 0.8; + v3d->overlay.edit_flag = V3D_OVERLAY_EDIT_FACES | + V3D_OVERLAY_EDIT_SEAMS | + V3D_OVERLAY_EDIT_SHARP | + V3D_OVERLAY_EDIT_FREESTYLE_EDGE | + V3D_OVERLAY_EDIT_FREESTYLE_FACE | + V3D_OVERLAY_EDIT_EDGES | + V3D_OVERLAY_EDIT_CREASES | + V3D_OVERLAY_EDIT_BWEIGHTS | + V3D_OVERLAY_EDIT_CU_HANDLES | + V3D_OVERLAY_EDIT_CU_NORMALS; v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR; v3d->flag = V3D_SELECT_OUTLINE; - v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_GPENCIL; + v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION; - v3d->lens = 35.0f; + v3d->lens = 50.0f; v3d->near = 0.01f; v3d->far = 1000.0f; - v3d->twflag |= U.tw_flag & V3D_USE_MANIPULATOR; - v3d->twtype = V3D_MANIP_TRANSLATE; - v3d->around = V3D_AROUND_CENTER_MEAN; + v3d->overlay.gpencil_paper_opacity = 0.5f; + v3d->overlay.gpencil_grid_opacity = 0.9f; v3d->bundle_size = 0.2f; v3d->bundle_drawtype = OB_PLAINAXES; @@ -348,12 +361,16 @@ static SpaceLink *view3d_new(const bContext *C) v3d->stereo3d_convergence_alpha = 0.15f; v3d->stereo3d_volume_alpha = 0.05f; + /* grease pencil settings */ + v3d->vertex_opacity = 1.0f; + v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES; + /* header */ ar = MEM_callocN(sizeof(ARegion), "header for view3d"); BLI_addtail(&v3d->regionbase, ar); ar->regiontype = RGN_TYPE_HEADER; - ar->alignment = RGN_ALIGN_BOTTOM; + ar->alignment = RGN_ALIGN_TOP; /* tool shelf */ ar = MEM_callocN(sizeof(ARegion), "toolshelf for view3d"); @@ -363,14 +380,6 @@ static SpaceLink *view3d_new(const bContext *C) ar->alignment = RGN_ALIGN_LEFT; ar->flag = RGN_FLAG_HIDDEN; - /* tool properties */ - ar = MEM_callocN(sizeof(ARegion), "tool properties for view3d"); - - BLI_addtail(&v3d->regionbase, ar); - ar->regiontype = RGN_TYPE_TOOL_PROPS; - ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - ar->flag = RGN_FLAG_HIDDEN; - /* buttons/list view */ ar = MEM_callocN(sizeof(ARegion), "buttons for view3d"); @@ -399,30 +408,11 @@ static SpaceLink *view3d_new(const bContext *C) static void view3d_free(SpaceLink *sl) { View3D *vd = (View3D *) sl; - BGpic *bgpic; - - for (bgpic = vd->bgpicbase.first; bgpic; bgpic = bgpic->next) { - if (bgpic->source == V3D_BGPIC_IMAGE) { - id_us_min((ID *)bgpic->ima); - } - else if (bgpic->source == V3D_BGPIC_MOVIE) { - id_us_min((ID *)bgpic->clip); - } - } - BLI_freelistN(&vd->bgpicbase); if (vd->localvd) MEM_freeN(vd->localvd); if (vd->properties_storage) MEM_freeN(vd->properties_storage); - /* matcap material, its preview rect gets freed via icons */ - if (vd->defmaterial) { - if (vd->defmaterial->gpumaterial.first) - GPU_material_free(&vd->defmaterial->gpumaterial); - BKE_previewimg_free(&vd->defmaterial->preview); - MEM_freeN(vd->defmaterial); - } - if (vd->fx_settings.ssao) MEM_freeN(vd->fx_settings.ssao); if (vd->fx_settings.dof) @@ -440,33 +430,19 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) { View3D *v3do = (View3D *)sl; View3D *v3dn = MEM_dupallocN(sl); - BGpic *bgpic; /* clear or remove stuff from old */ if (v3dn->localvd) { v3dn->localvd = NULL; v3dn->properties_storage = NULL; - v3dn->lay = v3do->localvd->lay & 0xFFFFFF; } - if (v3dn->drawtype == OB_RENDER) - v3dn->drawtype = OB_SOLID; + if (v3dn->shading.type == OB_RENDER) + v3dn->shading.type = OB_SOLID; /* copy or clear inside new stuff */ - v3dn->defmaterial = NULL; - - BLI_duplicatelist(&v3dn->bgpicbase, &v3do->bgpicbase); - for (bgpic = v3dn->bgpicbase.first; bgpic; bgpic = bgpic->next) { - if (bgpic->source == V3D_BGPIC_IMAGE) { - id_us_plus((ID *)bgpic->ima); - } - else if (bgpic->source == V3D_BGPIC_MOVIE) { - id_us_plus((ID *)bgpic->clip); - } - } - v3dn->properties_storage = NULL; if (v3dn->fx_settings.dof) v3dn->fx_settings.dof = MEM_dupallocN(v3do->fx_settings.dof); @@ -572,101 +548,87 @@ static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar) GPU_offscreen_free(rv3d->gpuoffscreen); rv3d->gpuoffscreen = NULL; } - - if (rv3d->compositor) { - GPU_fx_compositor_destroy(rv3d->compositor); - rv3d->compositor = NULL; - } } -static bool view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) +static bool view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip)) { - if (drag->type == WM_DRAG_ID) { - ID *id = drag->poin; - if (GS(id->name) == ID_OB) - return 1; - } - return 0; + return WM_drag_ID(drag, ID_OB) != NULL; } -static bool view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) +static bool view3d_collection_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip)) { - if (drag->type == WM_DRAG_ID) { - ID *id = drag->poin; - if (GS(id->name) == ID_GR) - return 1; - } - return 0; + return WM_drag_ID(drag, ID_GR) != NULL; } -static bool view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) +static bool view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip)) { - if (drag->type == WM_DRAG_ID) { - ID *id = drag->poin; - if (GS(id->name) == ID_MA) - return 1; - } - return 0; + return WM_drag_ID(drag, ID_MA) != NULL; } -static bool view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) +static bool view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event), const char **UNUSED(tooltip)) { - if (drag->type == WM_DRAG_ID) { - ID *id = drag->poin; - if (GS(id->name) == ID_IM) - return 1; + if (drag->type == WM_DRAG_PATH) { + return (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)); /* rule might not work? */ } - else if (drag->type == WM_DRAG_PATH) { - if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE)) /* rule might not work? */ - return 1; + else { + return WM_drag_ID(drag, ID_IM) != NULL; } - return 0; } -static bool view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) +static bool view3d_ima_bg_is_camera_view(bContext *C) { - if (event->ctrl) - return false; - - if (!ED_view3d_give_base_under_cursor(C, event->mval)) { - return view3d_ima_drop_poll(C, drag, event); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if ((rv3d && (rv3d->persp == RV3D_CAMOB))) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d && v3d->camera && v3d->camera->type == OB_CAMERA) { + return true; + } } - return 0; + return false; } -static bool view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) +static bool view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip) { - Base *base = ED_view3d_give_base_under_cursor(C, event->mval); + if (!view3d_ima_drop_poll(C, drag, event, tooltip)) { + return false; + } - /* either holding and ctrl and no object, or dropping to empty */ - if (((base == NULL) && event->ctrl) || - ((base != NULL) && base->object->type == OB_EMPTY)) - { - return view3d_ima_drop_poll(C, drag, event); + if (ED_view3d_is_object_under_cursor(C, event->mval)) { + return false; } - return 0; + return view3d_ima_bg_is_camera_view(C); } -static bool view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) +static bool view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip) { - Base *base = ED_view3d_give_base_under_cursor(C, event->mval); + if (!view3d_ima_drop_poll(C, drag, event, tooltip)) { + return false; + } + + Object *ob = ED_view3d_give_object_under_cursor(C, event->mval); + + if (ob == NULL) { + return true; + } - if (base && base->object->type == OB_MESH) - return view3d_ima_drop_poll(C, drag, event); - return 0; + if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) { + return true; + } + + return false; } static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = drag->poin; + ID *id = WM_drag_ID(drag, ID_OB); RNA_string_set(drop->ptr, "name", id->name + 2); } -static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop) +static void view3d_collection_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = drag->poin; + ID *id = WM_drag_ID(drag, ID_GR); drop->opcontext = WM_OP_EXEC_DEFAULT; RNA_string_set(drop->ptr, "name", id->name + 2); @@ -674,14 +636,14 @@ static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop) static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = drag->poin; + ID *id = WM_drag_ID(drag, 0); RNA_string_set(drop->ptr, "name", id->name + 2); } static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) { - ID *id = drag->poin; + ID *id = WM_drag_ID(drag, 0); if (id) { RNA_string_set(drop->ptr, "name", id->name + 2); @@ -693,6 +655,25 @@ static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) } } +static void view3d_lightcache_update(bContext *C) +{ + PointerRNA op_ptr; + + Scene *scene = CTX_data_scene(C); + + if (strcmp(scene->r.engine, RE_engine_id_BLENDER_EEVEE) != 0) { + /* Only do auto bake if eevee is the active engine */ + return; + } + + WM_operator_properties_create(&op_ptr, "SCENE_OT_light_cache_bake"); + RNA_int_set(&op_ptr, "delay", 200); + RNA_enum_set_identifier(C, &op_ptr, "subset", "DIRTY"); + + WM_operator_name_call(C, "SCENE_OT_light_cache_bake", WM_OP_INVOKE_DEFAULT, &op_ptr); + + WM_operator_properties_free(&op_ptr); +} /* region dropbox definition */ static void view3d_dropboxes(void) @@ -701,12 +682,38 @@ static void view3d_dropboxes(void) WM_dropbox_add(lb, "OBJECT_OT_add_named", view3d_ob_drop_poll, view3d_ob_drop_copy); WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, view3d_id_drop_copy); - WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy); - WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy); WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy); - WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy); + WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy); + WM_dropbox_add(lb, "OBJECT_OT_collection_instance_add", view3d_collection_drop_poll, view3d_collection_drop_copy); } +static void view3d_widgets(void) +{ + wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure( + &(const struct wmGizmoMapType_Params){SPACE_VIEW3D, RGN_TYPE_WINDOW}); + + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_lamp_spot); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_lamp_area); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_lamp_target); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_force_field); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera_view); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_empty_image); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_armature_spline); + + WM_gizmogrouptype_append(TRANSFORM_GGT_gizmo); + WM_gizmogrouptype_append(VIEW3D_GGT_xform_cage); + WM_gizmogrouptype_append(VIEW3D_GGT_xform_shear); + WM_gizmogrouptype_append(VIEW3D_GGT_xform_extrude); + WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_elem); + WM_gizmogrouptype_append(VIEW3D_GGT_mesh_preselect_edgering); + + WM_gizmogrouptype_append(VIEW3D_GGT_ruler); + WM_gizmotype_append(VIEW3D_GT_ruler_item); + + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_navigate); + WM_gizmotype_append(VIEW3D_GT_navigate_rotate); +} /* type callback, not region itself */ @@ -731,9 +738,6 @@ static void view3d_main_region_free(ARegion *ar) if (rv3d->gpuoffscreen) { GPU_offscreen_free(rv3d->gpuoffscreen); } - if (rv3d->compositor) { - GPU_fx_compositor_destroy(rv3d->compositor); - } MEM_freeN(rv3d); ar->regiondata = NULL; @@ -757,50 +761,27 @@ static void *view3d_main_region_duplicate(void *poin) new->render_engine = NULL; new->sms = NULL; new->smooth_timer = NULL; - new->compositor = NULL; return new; } return NULL; } -static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, Scene *scene) +static void view3d_main_region_listener( + wmWindow *UNUSED(win), ScrArea *sa, ARegion *ar, + wmNotifier *wmn, const Scene *scene) { - wmWindow *win = wmn->wm->winactive; - ScrArea *sa; - unsigned int lay_used = 0; - Base *base; - - if (!win) return; - - base = scene->base.first; - while (base) { - lay_used |= base->lay & ((1 << 20) - 1); /* ignore localview */ - - if (lay_used == (1 << 20) - 1) - break; - - base = base->next; - } - - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_VIEW3D) { - if (BLI_findindex(&sa->regionbase, ar) != -1) { - View3D *v3d = sa->spacedata.first; - v3d->lay_used = lay_used; - break; - } - } - } -} - -static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *wmn) -{ - Scene *scene = sc->scene; View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + wmGizmoMap *gzmap = ar->gizmo_map; /* context changes */ switch (wmn->category) { + case NC_WM: + if (ELEM(wmn->data, ND_UNDO)) { + WM_gizmomap_tag_refresh(gzmap); + } + break; case NC_ANIMATION: switch (wmn->data) { case ND_KEYFRAME_PROP: @@ -820,21 +801,29 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w break; case NC_SCENE: switch (wmn->data) { + case ND_SCENEBROWSE: case ND_LAYER_CONTENT: - if (wmn->reference) - view3d_recalc_used_layers(ar, wmn, wmn->reference); ED_region_tag_redraw(ar); + WM_gizmomap_tag_refresh(gzmap); + break; + case ND_LAYER: + if (wmn->reference) { + BKE_screen_view3d_sync(v3d, wmn->reference); + } + ED_region_tag_redraw(ar); + WM_gizmomap_tag_refresh(gzmap); break; - case ND_FRAME: - case ND_TRANSFORM: case ND_OB_ACTIVE: case ND_OB_SELECT: + ATTR_FALLTHROUGH; + case ND_FRAME: + case ND_TRANSFORM: case ND_OB_VISIBLE: - case ND_LAYER: case ND_RENDER_OPTIONS: case ND_MARKERS: case ND_MODE: ED_region_tag_redraw(ar); + WM_gizmomap_tag_refresh(gzmap); break; case ND_WORLD: /* handled by space_view3d_listener() for v3d access */ @@ -842,7 +831,6 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w case ND_DRAW_RENDER_VIEWPORT: { if (v3d->camera && (scene == wmn->reference)) { - RegionView3D *rv3d = ar->regiondata; if (rv3d->persp == RV3D_CAMOB) { ED_region_tag_redraw(ar); } @@ -867,6 +855,7 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w case ND_POINTCACHE: case ND_LOD: ED_region_tag_redraw(ar); + WM_gizmomap_tag_refresh(gzmap); break; } switch (wmn->action) { @@ -877,9 +866,13 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w break; case NC_GEOM: switch (wmn->data) { + case ND_SELECT: + { + WM_gizmomap_tag_refresh(gzmap); + ATTR_FALLTHROUGH; + } case ND_DATA: case ND_VERTEX_GROUP: - case ND_SELECT: ED_region_tag_redraw(ar); break; } @@ -894,7 +887,6 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w case ND_DRAW_RENDER_VIEWPORT: { if (v3d->camera && (v3d->camera->data == wmn->reference)) { - RegionView3D *rv3d = ar->regiondata; if (rv3d->persp == RV3D_CAMOB) { ED_region_tag_redraw(ar); } @@ -923,21 +915,13 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w switch (wmn->data) { case ND_SHADING: case ND_NODES: - { -#ifdef WITH_LEGACY_DEPSGRAPH - Object *ob = OBACT; - if ((v3d->drawtype == OB_MATERIAL) || - (ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) || - (v3d->drawtype == OB_TEXTURE && - (scene->gm.matmode == GAME_MAT_GLSL || - BKE_scene_use_new_shading_nodes(scene))) || - !DEG_depsgraph_use_legacy()) -#endif - { - ED_region_tag_redraw(ar); - } + /* TODO(sergey) This is a bit too much updates, but needed to + * have proper material drivers update in the viewport. + * + * How to solve? + */ + ED_region_tag_redraw(ar); break; - } case ND_SHADING_DRAW: case ND_SHADING_LINKS: ED_region_tag_redraw(ar); @@ -949,23 +933,29 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w case ND_WORLD_DRAW: /* handled by space_view3d_listener() for v3d access */ break; + case ND_WORLD: + /* Needed for updating world materials */ + ED_region_tag_redraw(ar); + break; } break; case NC_LAMP: switch (wmn->data) { case ND_LIGHTING: - if ((v3d->drawtype == OB_MATERIAL) || - (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)) || - !DEG_depsgraph_use_legacy()) - { - ED_region_tag_redraw(ar); - } + /* TODO(sergey): This is a bit too much, but needed to + * handle updates from new depsgraph. + */ + ED_region_tag_redraw(ar); break; case ND_LIGHTING_DRAW: ED_region_tag_redraw(ar); + WM_gizmomap_tag_refresh(gzmap); break; } break; + case NC_LIGHTPROBE: + ED_area_tag_refresh(sa); + break; case NC_IMAGE: /* this could be more fine grained checks if we had * more context than just the region */ @@ -982,10 +972,10 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w case NC_SPACE: if (wmn->data == ND_SPACE_VIEW3D) { if (wmn->subtype == NS_VIEW3D_GPU) { - RegionView3D *rv3d = ar->regiondata; rv3d->rflag |= RV3D_GPULIGHT_UPDATE; } ED_region_tag_redraw(ar); + WM_gizmomap_tag_refresh(gzmap); } break; case NC_ID: @@ -998,15 +988,13 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w case ND_SKETCH: ED_region_tag_redraw(ar); break; - case ND_SCREENBROWSE: - case ND_SCREENDELETE: - case ND_SCREENSET: - /* screen was changed, need to update used layers due to NC_SCENE|ND_LAYER_CONTENT */ - /* updates used layers only for View3D in active screen */ - if (wmn->reference) { - bScreen *sc_ref = wmn->reference; - view3d_recalc_used_layers(ar, wmn, sc_ref->scene); - } + case ND_LAYOUTBROWSE: + case ND_LAYOUTDELETE: + case ND_LAYOUTSET: + WM_gizmomap_tag_refresh(gzmap); + ED_region_tag_redraw(ar); + break; + case ND_LAYER: ED_region_tag_redraw(ar); break; } @@ -1020,12 +1008,104 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w } } +static void view3d_main_region_message_subscribe( + const struct bContext *C, + struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), + struct bScreen *UNUSED(screen), struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + /* Developer note: there are many properties that impact 3D view drawing, + * so instead of subscribing to individual properties, just subscribe to types + * accepting some redundant redraws. + * + * For other space types we might try avoid this, keep the 3D view as an exceptional case! */ + wmMsgParams_RNA msg_key_params = {{{0}}}; + + /* Only subscribe to types. */ + StructRNA *type_array[] = { + &RNA_Window, + + /* These object have properties that impact drawing. */ + &RNA_AreaLight, + &RNA_Camera, + &RNA_Light, + &RNA_Speaker, + &RNA_SunLight, + + /* General types the 3D view depends on. */ + &RNA_Object, + &RNA_UnitSettings, /* grid-floor */ + + &RNA_View3DOverlay, + &RNA_View3DShading, + &RNA_World, + }; + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + for (int i = 0; i < ARRAY_SIZE(type_array); i++) { + msg_key_params.ptr.type = type_array[i]; + WM_msg_subscribe_rna_params( + mbus, + &msg_key_params, + &msg_sub_value_region_tag_redraw, + __func__); + } + + /* Subscribe to a handful of other properties. */ + RegionView3D *rv3d = ar->regiondata; + + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, engine, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_region_tag_redraw); + if (rv3d->persp == RV3D_CAMOB) { + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, use_border, &msg_sub_value_region_tag_redraw); + } + + WM_msg_subscribe_rna_anon_type(mbus, SceneEEVEE, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_type(mbus, SceneDisplay, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_type(mbus, ObjectDisplay, &msg_sub_value_region_tag_redraw); + + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obact = OBACT(view_layer); + if (obact != NULL) { + switch (obact->mode) { + case OB_MODE_PARTICLE_EDIT: + WM_msg_subscribe_rna_anon_type(mbus, ParticleEdit, &msg_sub_value_region_tag_redraw); + break; + default: + break; + } + } + + { + wmMsgSubscribeValue msg_sub_value_region_tag_refresh = { + .owner = ar, + .user_data = sa, + .notify = WM_toolsystem_do_msg_notify_tag_refresh, + }; + WM_msg_subscribe_rna_anon_prop( + mbus, Object, mode, + &msg_sub_value_region_tag_refresh); + } +} + /* concept is to retrieve cursor type context-less */ -static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar)) +static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) { - Scene *scene = win->screen->scene; + if (WM_cursor_set_from_tool(win, sa, ar)) { + return; + } - if (scene->obedit) { + ViewLayer *view_layer = WM_window_get_active_view_layer(win); + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); + if (obedit) { WM_cursor_set(win, CURSOR_EDIT); } else { @@ -1048,7 +1128,9 @@ static void view3d_header_region_draw(const bContext *C, ARegion *ar) ED_region_header(C, ar); } -static void view3d_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void view3d_header_region_listener( + wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, + wmNotifier *wmn, const Scene *UNUSED(scene)) { /* context changes */ switch (wmn->category) { @@ -1078,6 +1160,36 @@ static void view3d_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(s } } +static void view3d_header_region_message_subscribe( + const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), + struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar, + struct wmMsgBus *mbus) +{ + wmMsgParams_RNA msg_key_params = {{{0}}}; + + /* Only subscribe to types. */ + StructRNA *type_array[] = { + &RNA_View3DShading, + }; + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + for (int i = 0; i < ARRAY_SIZE(type_array); i++) { + msg_key_params.ptr.type = type_array[i]; + WM_msg_subscribe_rna_params( + mbus, + &msg_key_params, + &msg_sub_value_region_tag_redraw, + __func__); + } +} + + /* add handlers, stuff you only do once or on area/region changes */ static void view3d_buttons_region_init(wmWindowManager *wm, ARegion *ar) { @@ -1091,10 +1203,12 @@ static void view3d_buttons_region_init(wmWindowManager *wm, ARegion *ar) static void view3d_buttons_region_draw(const bContext *C, ARegion *ar) { - ED_region_panels(C, ar, NULL, -1, true); + ED_region_panels_ex(C, ar, (const char * []){CTX_data_mode_string(C), NULL}, -1, true); } -static void view3d_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void view3d_buttons_region_listener( + wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, + wmNotifier *wmn, const Scene *UNUSED(scene)) { /* context changes */ switch (wmn->category) { @@ -1197,30 +1311,12 @@ static void view3d_tools_region_init(wmWindowManager *wm, ARegion *ar) static void view3d_tools_region_draw(const bContext *C, ARegion *ar) { - ED_region_panels(C, ar, CTX_data_mode_string(C), -1, true); -} - -static void view3d_props_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) -{ - /* context changes */ - switch (wmn->category) { - case NC_WM: - if (wmn->data == ND_HISTORY) - ED_region_tag_redraw(ar); - break; - case NC_SCENE: - if (wmn->data == ND_MODE) - ED_region_tag_redraw(ar); - break; - case NC_SPACE: - if (wmn->data == ND_SPACE_VIEW3D) - ED_region_tag_redraw(ar); - break; - } + ED_region_panels_ex(C, ar, (const char * []){CTX_data_mode_string(C), NULL}, -1, true); } /* area (not region) level listener */ -static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNotifier *wmn) +static void space_view3d_listener( + wmWindow *UNUSED(win), ScrArea *sa, struct wmNotifier *wmn, Scene *UNUSED(scene)) { View3D *v3d = sa->spacedata.first; @@ -1238,15 +1334,16 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot switch (wmn->data) { case ND_WORLD_DRAW: case ND_WORLD: - if (v3d->flag2 & V3D_SHOW_WORLD) + if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) { ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW); + } break; } break; case NC_MATERIAL: switch (wmn->data) { case ND_NODES: - if (v3d->drawtype == OB_TEXTURE) + if (v3d->shading.type == OB_TEXTURE) ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW); break; } @@ -1254,9 +1351,18 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot } } +static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa)) +{ + Scene *scene = CTX_data_scene(C); + LightCache *lcache = scene->eevee.light_cache; + + if (lcache && (lcache->flag & LIGHTCACHE_UPDATE_AUTO) != 0) { + lcache->flag &= ~LIGHTCACHE_UPDATE_AUTO; + view3d_lightcache_update((bContext *)C); + } +} + const char *view3d_context_dir[] = { - "selected_objects", "selected_bases", "selected_editable_objects", - "selected_editable_bases", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases", "active_base", "active_object", NULL }; @@ -1267,109 +1373,27 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes if (CTX_data_dir(member)) { CTX_data_dir_set(result, view3d_context_dir); } - else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - Base *base; - const bool selected_objects = CTX_data_equals(member, "selected_objects"); - - for (base = scene->base.first; base; base = base->next) { - if ((base->flag & SELECT) && (base->lay & lay)) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) { - if (selected_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - Base *base; - const bool selected_editable_objects = CTX_data_equals(member, "selected_editable_objects"); - - for (base = scene->base.first; base; base = base->next) { - if ((base->flag & SELECT) && (base->lay & lay)) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) { - if (0 == BKE_object_is_libdata(base->object)) { - if (selected_editable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - Base *base; - const bool visible_objects = CTX_data_equals(member, "visible_objects"); - - for (base = scene->base.first; base; base = base->next) { - if (base->lay & lay) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) { - if (visible_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } - else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - Base *base; - const bool selectable_objects = CTX_data_equals(member, "selectable_objects"); - - for (base = scene->base.first; base; base = base->next) { - if (base->lay & lay) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0 && (base->object->restrictflag & OB_RESTRICT_SELECT) == 0) { - if (selectable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } - } - } - CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); - return 1; - } else if (CTX_data_equals(member, "active_base")) { - View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - if (scene->basact && (scene->basact->lay & lay)) { - Object *ob = scene->basact->object; + ViewLayer *view_layer = CTX_data_view_layer(C); + if (view_layer->basact) { + Object *ob = view_layer->basact->object; /* if hidden but in edit mode, we still display, can happen with animation */ - if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0 || (ob->mode & OB_MODE_EDIT)) - CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, scene->basact); + if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT)) { + CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact); + } } return 1; } else if (CTX_data_equals(member, "active_object")) { - View3D *v3d = CTX_wm_view3d(C); - Scene *scene = CTX_data_scene(C); - const unsigned int lay = v3d ? v3d->lay : scene->lay; - if (scene->basact && (scene->basact->lay & lay)) { - Object *ob = scene->basact->object; - if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0 || (ob->mode & OB_MODE_EDIT)) - CTX_data_id_pointer_set(result, &scene->basact->object->id); + ViewLayer *view_layer = CTX_data_view_layer(C); + if (view_layer->basact) { + Object *ob = view_layer->basact->object; + /* if hidden but in edit mode, we still display, can happen with animation */ + if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT) != 0) { + CTX_data_id_pointer_set(result, &ob->id); + } } return 1; @@ -1410,8 +1434,6 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i /* Values in local-view aren't used, see: T52663 */ if (is_local == false) { - /* Skip 'v3d->defmaterial', it's not library data. */ - if ((ID *)v3d->ob_centre == old_id) { v3d->ob_centre = (Object *)new_id; /* Otherwise, bonename may remain valid... We could be smart and check this, too? */ @@ -1419,21 +1441,6 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i v3d->ob_centre_bone[0] = '\0'; } } - - if (ELEM(GS(old_id->name), ID_IM, ID_MC)) { - for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - if ((ID *)bgpic->ima == old_id) { - bgpic->ima = (Image *)new_id; - id_us_min(old_id); - id_us_plus(new_id); - } - if ((ID *)bgpic->clip == old_id) { - bgpic->clip = (MovieClip *)new_id; - id_us_min(old_id); - id_us_plus(new_id); - } - } - } } if (is_local) { @@ -1455,23 +1462,26 @@ void ED_spacetype_view3d(void) st->free = view3d_free; st->init = view3d_init; st->listener = space_view3d_listener; + st->refresh = space_view3d_refresh; st->duplicate = view3d_duplicate; st->operatortypes = view3d_operatortypes; st->keymap = view3d_keymap; st->dropboxes = view3d_dropboxes; + st->gizmos = view3d_widgets; st->context = view3d_context; st->id_remap = view3d_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region"); art->regionid = RGN_TYPE_WINDOW; - art->keymapflag = ED_KEYMAP_GPENCIL; + art->keymapflag = ED_KEYMAP_GIZMO | ED_KEYMAP_GPENCIL; art->draw = view3d_main_region_draw; art->init = view3d_main_region_init; art->exit = view3d_main_region_exit; art->free = view3d_main_region_free; art->duplicate = view3d_main_region_duplicate; art->listener = view3d_main_region_listener; + art->message_subscribe = view3d_main_region_message_subscribe; art->cursor = view3d_main_region_cursor; art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */ BLI_addhead(&st->regiontypes, art); @@ -1491,33 +1501,16 @@ void ED_spacetype_view3d(void) /* regions: tool(bar) */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); art->regionid = RGN_TYPE_TOOLS; - art->prefsizex = 160; /* XXX */ + art->prefsizex = 58; /* XXX */ art->prefsizey = 50; /* XXX */ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = view3d_buttons_region_listener; + art->message_subscribe = ED_region_generic_tools_region_message_subscribe; + art->snap_size = ED_region_generic_tools_region_snap_size; art->init = view3d_tools_region_init; art->draw = view3d_tools_region_draw; BLI_addhead(&st->regiontypes, art); -#if 0 - /* unfinished still */ - view3d_toolshelf_register(art); -#endif - - /* regions: tool properties */ - art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tool properties region"); - art->regionid = RGN_TYPE_TOOL_PROPS; - art->prefsizex = 0; - art->prefsizey = 120; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; - art->listener = view3d_props_region_listener; - art->init = view3d_tools_region_init; - art->draw = view3d_tools_region_draw; - BLI_addhead(&st->regiontypes, art); - - view3d_tool_props_register(art); - - /* regions: header */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d header region"); art->regionid = RGN_TYPE_HEADER; @@ -1526,6 +1519,11 @@ void ED_spacetype_view3d(void) art->listener = view3d_header_region_listener; art->init = view3d_header_region_init; art->draw = view3d_header_region_draw; + art->message_subscribe = view3d_header_region_message_subscribe; + BLI_addhead(&st->regiontypes, art); + + /* regions: hud */ + art = ED_area_type_hud(st->spaceid); BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 05e9a34f492..357d04e0ce9 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -55,12 +55,14 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_customdata.h" -#include "BKE_depsgraph.h" #include "BKE_screen.h" #include "BKE_editmesh.h" #include "BKE_deform.h" #include "BKE_object.h" #include "BKE_object_deform.h" +#include "BKE_report.h" + +#include "DEG_depsgraph.h" #include "WM_api.h" #include "WM_types.h" @@ -68,6 +70,7 @@ #include "RNA_access.h" #include "ED_armature.h" +#include "ED_object.h" #include "ED_mesh.h" #include "ED_screen.h" @@ -776,18 +779,18 @@ static void do_view3d_vgroup_buttons(bContext *C, void *UNUSED(arg), int event) return; } else { - Scene *scene = CTX_data_scene(C); - Object *ob = scene->basact->object; + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = view_layer->basact->object; ED_vgroup_vert_active_mirror(ob, event - B_VGRP_PNL_EDIT_SINGLE); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); } } static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt)) { - Scene *scene = CTX_data_scene(C); - Object *ob = OBACT; + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); if (ob && (BKE_object_is_in_editmode_vgroup(ob) || BKE_object_is_in_wpaint_select_vert(ob))) { @@ -805,7 +808,8 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa) { uiBlock *block = uiLayoutAbsoluteBlock(pa->layout); Scene *scene = CTX_data_scene(C); - Object *ob = scene->basact->object; + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = view_layer->basact->object; MDeformVert *dv; @@ -934,8 +938,9 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr) colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "location", 0, NULL, ICON_NONE); colsub = uiLayoutColumn(split, true); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); uiItemL(colsub, "", ICON_NONE); - uiItemR(colsub, ptr, "lock_location", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(colsub, ptr, "lock_location", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED); split = uiLayoutSplit(layout, 0.8f, false); @@ -944,30 +949,33 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr) colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "rotation_quaternion", 0, IFACE_("Rotation"), ICON_NONE); colsub = uiLayoutColumn(split, true); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE); if (RNA_boolean_get(ptr, "lock_rotations_4d")) - uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE + UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE + UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED); else uiItemL(colsub, "", ICON_NONE); - uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED); break; case ROT_MODE_AXISANGLE: /* axis angle */ colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "rotation_axis_angle", 0, IFACE_("Rotation"), ICON_NONE); colsub = uiLayoutColumn(split, true); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); uiItemR(colsub, ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE); if (RNA_boolean_get(ptr, "lock_rotations_4d")) - uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(colsub, ptr, "lock_rotation_w", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED); else uiItemL(colsub, "", ICON_NONE); - uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED); break; default: /* euler rotations */ colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "rotation_euler", 0, IFACE_("Rotation"), ICON_NONE); colsub = uiLayoutColumn(split, true); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); uiItemL(colsub, "", ICON_NONE); - uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(colsub, ptr, "lock_rotation", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED); break; } uiItemR(layout, ptr, "rotation_mode", 0, "", ICON_NONE); @@ -976,8 +984,9 @@ static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr) colsub = uiLayoutColumn(split, true); uiItemR(colsub, ptr, "scale", 0, NULL, ICON_NONE); colsub = uiLayoutColumn(split, true); + uiLayoutSetEmboss(colsub, UI_EMBOSS_NONE); uiItemL(colsub, "", ICON_NONE); - uiItemR(colsub, ptr, "lock_scale", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(colsub, ptr, "lock_scale", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED); if (ptr->type == &RNA_Object) { Object *ob = ptr->data; @@ -1095,9 +1104,9 @@ static void v3d_editmetaball_buts(uiLayout *layout, Object *ob) static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event) { - Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); - Object *ob = OBACT; + Object *ob = OBACT(view_layer); switch (event) { @@ -1108,7 +1117,7 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event case B_OBJECTPANELMEDIAN: if (ob) { v3d_editvertex_buts(NULL, v3d, ob, 1.0); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } break; } @@ -1119,16 +1128,17 @@ static void do_view3d_region_buttons(bContext *C, void *UNUSED(index), int event static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt)) { - Scene *scene = CTX_data_scene(C); - return (scene->basact != NULL); + ViewLayer *view_layer = CTX_data_view_layer(C); + return (view_layer->basact != NULL); } static void view3d_panel_transform(const bContext *C, Panel *pa) { uiBlock *block; Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); Object *obedit = CTX_data_edit_object(C); - Object *ob = scene->basact->object; + Object *ob = view_layer->basact->object; uiLayout *col; block = uiLayoutGetBlock(pa->layout); @@ -1160,6 +1170,11 @@ static void view3d_panel_transform(const bContext *C, Panel *pa) } } +static void hide_collections_menu_draw(const bContext *C, Menu *menu) +{ + ED_hide_collections_menu_draw(C, menu->layout); +} + void view3d_buttons_register(ARegionType *art) { PanelType *pt; @@ -1167,6 +1182,7 @@ void view3d_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel object"); strcpy(pt->idname, "VIEW3D_PT_transform"); strcpy(pt->label, N_("Transform")); /* XXX C panels not available through RNA (bpy.types)! */ + strcpy(pt->category, "View"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = view3d_panel_transform; pt->poll = view3d_panel_transform_poll; @@ -1175,10 +1191,20 @@ void view3d_buttons_register(ARegionType *art) pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup"); strcpy(pt->idname, "VIEW3D_PT_vgroup"); strcpy(pt->label, N_("Vertex Weights")); /* XXX C panels are not available through RNA (bpy.types)! */ + strcpy(pt->category, "View"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = view3d_panel_vgroup; pt->poll = view3d_panel_vgroup_poll; BLI_addtail(&art->paneltypes, pt); + + MenuType *mt; + + mt = MEM_callocN(sizeof(MenuType), "spacetype view3d menu collections"); + strcpy(mt->idname, "VIEW3D_MT_collection"); + strcpy(mt->label, N_("Collection")); + strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + mt->draw = hide_collections_menu_draw; + WM_menutype_add(mt); } static int view3d_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op)) @@ -1194,7 +1220,7 @@ static int view3d_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op)) void VIEW3D_OT_properties(wmOperatorType *ot) { - ot->name = "Properties"; + ot->name = "Toggle Sidebar"; ot->description = "Toggle the properties region visibility"; ot->idname = "VIEW3D_OT_properties"; @@ -1204,3 +1230,32 @@ void VIEW3D_OT_properties(wmOperatorType *ot) /* flags */ ot->flag = 0; } + +static int view3d_object_mode_menu(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + if (ob == NULL) { + BKE_report(op->reports, RPT_WARNING, "No active object found"); + return OPERATOR_CANCELLED; + } + else if (((ob->mode & OB_MODE_EDIT) == 0) && (ELEM(ob->type, OB_ARMATURE))) { + ED_object_mode_toggle(C, OB_MODE_POSE); + return OPERATOR_CANCELLED; + } + else { + UI_pie_menu_invoke(C, "VIEW3D_MT_object_mode_pie", CTX_wm_window(C)->eventstate); + return OPERATOR_CANCELLED; + } +} + +void VIEW3D_OT_object_mode_pie_or_toggle(wmOperatorType *ot) +{ + ot->name = "Object Mode Menu"; + ot->idname = "VIEW3D_OT_object_mode_pie_or_toggle"; + + ot->exec = view3d_object_mode_menu; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = 0; +} diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c index 5c544ed24df..d8b7d449c36 100644 --- a/source/blender/editors/space_view3d/view3d_camera_control.c +++ b/source/blender/editors/space_view3d/view3d_camera_control.c @@ -54,8 +54,9 @@ #include "BLI_utildefines.h" #include "BKE_object.h" +#include "BKE_context.h" -#include "BKE_depsgraph.h" /* for object updating */ +#include "DEG_depsgraph.h" #include "ED_screen.h" @@ -137,7 +138,7 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl) * the view for first-person style navigation. */ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( - Scene *scene, View3D *v3d, RegionView3D *rv3d, + Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root) { View3DCameraControl *vctrl; @@ -177,7 +178,7 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( /* store the original camera loc and rot */ vctrl->obtfm = BKE_object_tfm_backup(ob_back); - BKE_object_where_is_calc(scene, v3d->camera); + BKE_object_where_is_calc(depsgraph, scene, v3d->camera); negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]); rv3d->dist = 0.0; @@ -242,7 +243,7 @@ void ED_view3d_cameracontrol_update( ob_update = v3d->camera->parent; while (ob_update) { - DAG_id_tag_update(&ob_update->id, OB_RECALC_OB); + DEG_id_tag_update(&ob_update->id, ID_RECALC_TRANSFORM); ob_update = ob_update->parent; } @@ -264,7 +265,7 @@ void ED_view3d_cameracontrol_update( BKE_object_apply_mat4(v3d->camera, view_mat, true, true); - DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); + DEG_id_tag_update(&v3d->camera->id, ID_RECALC_TRANSFORM); copy_v3_v3(v3d->camera->size, size_back); @@ -299,10 +300,10 @@ void ED_view3d_cameracontrol_release( /* store the original camera loc and rot */ BKE_object_tfm_restore(ob_back, vctrl->obtfm); - DAG_id_tag_update(&ob_back->id, OB_RECALC_OB); + DEG_id_tag_update(&ob_back->id, ID_RECALC_TRANSFORM); } else { - /* Non Camera we need to reset the view back to the original location bacause the user canceled*/ + /* Non Camera we need to reset the view back to the original location because the user canceled*/ copy_qt_qt(rv3d->viewquat, vctrl->rot_backup); rv3d->persp = vctrl->persp_backup; } @@ -311,7 +312,7 @@ void ED_view3d_cameracontrol_release( rv3d->dist = vctrl->dist_backup; } else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */ - DAG_id_tag_update((ID *)view3d_cameracontrol_object(vctrl), OB_RECALC_OB); + DEG_id_tag_update((ID *)view3d_cameracontrol_object(vctrl), ID_RECALC_TRANSFORM); /* always, is set to zero otherwise */ copy_v3_v3(rv3d->ofs, vctrl->ofs_backup); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 1cf2e71f2bf..f6b2c79b88b 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -28,958 +28,290 @@ * \ingroup spview3d */ -#include <string.h> -#include <stdio.h> #include <math.h> -#include "DNA_armature_types.h" -#include "DNA_camera_types.h" -#include "DNA_customdata_types.h" -#include "DNA_object_types.h" -#include "DNA_group_types.h" -#include "DNA_mesh_types.h" -#include "DNA_key_types.h" -#include "DNA_lamp_types.h" -#include "DNA_scene_types.h" -#include "DNA_world_types.h" -#include "DNA_brush_types.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" +#include "BLI_listbase.h" #include "BLI_math.h" -#include "BLI_jitter_2d.h" -#include "BLI_utildefines.h" -#include "BLI_endian_switch.h" +#include "BLI_rect.h" +#include "BLI_string.h" #include "BLI_threads.h" +#include "BLI_jitter_2d.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" -#include "BKE_anim.h" #include "BKE_camera.h" +#include "BKE_collection.h" #include "BKE_context.h" -#include "BKE_customdata.h" -#include "BKE_DerivedMesh.h" -#include "BKE_image.h" +#include "BKE_global.h" #include "BKE_key.h" #include "BKE_main.h" +#include "BKE_scene.h" #include "BKE_object.h" -#include "BKE_global.h" #include "BKE_paint.h" -#include "BKE_scene.h" -#include "BKE_screen.h" #include "BKE_unit.h" -#include "BKE_movieclip.h" -#include "RE_engine.h" - -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" -#include "IMB_colormanagement.h" +#include "BLF_api.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "BLT_translation.h" -#include "WM_api.h" +#include "DNA_armature_types.h" +#include "DNA_brush_types.h" +#include "DNA_camera_types.h" +#include "DNA_key_types.h" +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_view3d_types.h" +#include "DNA_windowmanager_types.h" -#include "BLF_api.h" -#include "BLT_translation.h" +#include "DRW_engine.h" #include "ED_armature.h" #include "ED_keyframing.h" #include "ED_gpencil.h" #include "ED_screen.h" -#include "ED_space_api.h" -#include "ED_screen_types.h" #include "ED_transform.h" -#include "UI_interface.h" -#include "UI_interface_icons.h" -#include "UI_resources.h" +#include "DEG_depsgraph_query.h" +#include "GPU_batch.h" +#include "GPU_batch_presets.h" #include "GPU_draw.h" -#include "GPU_framebuffer.h" +#include "GPU_matrix.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" #include "GPU_material.h" -#include "GPU_compositing.h" -#include "GPU_extensions.h" -#include "GPU_select.h" - -#include "view3d_intern.h" /* own include */ - -/* prototypes */ -static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d); -static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect); -static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, - float winmat[4][4], const char *viewname); - -/* handy utility for drawing shapes in the viewport for arbitrary code. - * could add lines and points too */ -// #define DEBUG_DRAW -#ifdef DEBUG_DRAW -static void bl_debug_draw(void); -/* add these locally when using these functions for testing */ -extern void bl_debug_draw_quad_clear(void); -extern void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]); -extern void bl_debug_draw_edge_add(const float v0[3], const float v1[3]); -extern void bl_debug_color_set(const unsigned int col); -#endif - -void circf(float x, float y, float rad) -{ - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_FILL); - - glPushMatrix(); - - glTranslatef(x, y, 0.0); - - gluDisk(qobj, 0.0, rad, 32, 1); - - glPopMatrix(); - - gluDeleteQuadric(qobj); -} - -void circ(float x, float y, float rad) -{ - GLUquadricObj *qobj = gluNewQuadric(); - - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - - glPushMatrix(); - - glTranslatef(x, y, 0.0); - - gluDisk(qobj, 0.0, rad, 32, 1); - - glPopMatrix(); - - gluDeleteQuadric(qobj); -} - - -/* ********* custom clipping *********** */ - -static void view3d_draw_clipping(RegionView3D *rv3d) -{ - BoundBox *bb = rv3d->clipbb; - - if (bb) { - const unsigned int clipping_index[6][4] = { - {0, 1, 2, 3}, - {0, 4, 5, 1}, - {4, 7, 6, 5}, - {7, 3, 2, 6}, - {1, 5, 6, 2}, - {7, 4, 0, 3} - }; - - /* fill in zero alpha for rendering & re-projection [#31530] */ - unsigned char col[4]; - UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col); - glColor4ubv(col); - - glEnable(GL_BLEND); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, bb->vec); - glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index); - glDisableClientState(GL_VERTEX_ARRAY); - glDisable(GL_BLEND); - } -} - -void ED_view3d_clipping_set(RegionView3D *rv3d) -{ - double plane[4]; - const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6; - unsigned int a; - - for (a = 0; a < tot; a++) { - copy_v4db_v4fl(plane, rv3d->clip[a]); - glClipPlane(GL_CLIP_PLANE0 + a, plane); - glEnable(GL_CLIP_PLANE0 + a); - } -} - -/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */ -void ED_view3d_clipping_disable(void) -{ - unsigned int a; - - for (a = 0; a < 6; a++) { - glDisable(GL_CLIP_PLANE0 + a); - } -} -void ED_view3d_clipping_enable(void) -{ - unsigned int a; - - for (a = 0; a < 6; a++) { - glEnable(GL_CLIP_PLANE0 + a); - } -} - -static bool view3d_clipping_test(const float co[3], const float clip[6][4]) -{ - if (plane_point_side_v3(clip[0], co) > 0.0f) - if (plane_point_side_v3(clip[1], co) > 0.0f) - if (plane_point_side_v3(clip[2], co) > 0.0f) - if (plane_point_side_v3(clip[3], co) > 0.0f) - return false; - - return true; -} - -/* for 'local' ED_view3d_clipping_local must run first - * then all comparisons can be done in localspace */ -bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local) -{ - return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip); -} - -/* ********* end custom clipping *********** */ - - -static void drawgrid_draw(ARegion *ar, double wx, double wy, double x, double y, double dx) -{ - double verts[2][2]; +#include "GPU_viewport.h" +#include "GPU_state.h" +#include "GPU_framebuffer.h" - x += (wx); - y += (wy); +#include "MEM_guardedalloc.h" - /* set fixed 'Y' */ - verts[0][1] = 0.0f; - verts[1][1] = (double)ar->winy; +#include "UI_interface.h" +#include "UI_resources.h" - /* iter over 'X' */ - verts[0][0] = verts[1][0] = x - dx * floor(x / dx); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_DOUBLE, 0, verts); +#include "RE_engine.h" - while (verts[0][0] < ar->winx) { - glDrawArrays(GL_LINES, 0, 2); - verts[0][0] = verts[1][0] = verts[0][0] + dx; - } +#include "WM_api.h" +#include "WM_types.h" - /* set fixed 'X' */ - verts[0][0] = 0.0f; - verts[1][0] = (double)ar->winx; +#include "RNA_access.h" - /* iter over 'Y' */ - verts[0][1] = verts[1][1] = y - dx * floor(y / dx); - while (verts[0][1] < ar->winy) { - glDrawArrays(GL_LINES, 0, 2); - verts[0][1] = verts[1][1] = verts[0][1] + dx; - } +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" - glDisableClientState(GL_VERTEX_ARRAY); -} +#include "view3d_intern.h" /* own include */ -#define GRID_MIN_PX_D 6.0 -#define GRID_MIN_PX_F 6.0f +/* ******************** general functions ***************** */ -static void drawgrid(UnitSettings *unit, ARegion *ar, View3D *v3d, const char **grid_unit) +/** + * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore + */ +void ED_view3d_update_viewmat( + Depsgraph *depsgraph, Scene *scene, View3D *v3d, ARegion *ar, + float viewmat[4][4], float winmat[4][4], const rcti *rect) { - /* extern short bgpicmode; */ RegionView3D *rv3d = ar->regiondata; - double wx, wy, x, y, fw, fx, fy, dx; - double vec4[4]; - unsigned char col[3], col2[3]; - fx = rv3d->persmat[3][0]; - fy = rv3d->persmat[3][1]; - fw = rv3d->persmat[3][3]; - - wx = (ar->winx / 2.0); /* because of rounding errors, grid at wrong location */ - wy = (ar->winy / 2.0); - - x = (wx) * fx / fw; - y = (wy) * fy / fw; - - vec4[0] = vec4[1] = v3d->grid; - - vec4[2] = 0.0; - vec4[3] = 1.0; - mul_m4_v4d(rv3d->persmat, vec4); - fx = vec4[0]; - fy = vec4[1]; - fw = vec4[3]; - - dx = fabs(x - (wx) * fx / fw); - if (dx == 0) dx = fabs(y - (wy) * fy / fw); - - glLineWidth(1.0f); - - glDepthMask(GL_FALSE); /* disable write in zbuffer */ - - /* check zoom out */ - UI_ThemeColor(TH_GRID); - - if (unit->system) { - /* Use GRID_MIN_PX * 2 for units because very very small grid - * items are less useful when dealing with units */ - const void *usys; - int len, i; - double dx_scalar; - float blend_fac; - - bUnit_GetSystem(unit->system, B_UNIT_LENGTH, &usys, &len); - - if (usys) { - i = len; - while (i--) { - double scalar = bUnit_GetScaler(usys, i); - - dx_scalar = dx * scalar / (double)unit->scale_length; - if (dx_scalar < (GRID_MIN_PX_D * 2.0)) - continue; - - /* Store the smallest drawn grid size units name so users know how big each grid cell is */ - if (*grid_unit == NULL) { - *grid_unit = bUnit_GetNameDisplay(usys, i); - rv3d->gridview = (float)((scalar * (double)v3d->grid) / (double)unit->scale_length); - } - blend_fac = 1.0f - ((GRID_MIN_PX_F * 2.0f) / (float)dx_scalar); - - /* tweak to have the fade a bit nicer */ - blend_fac = (blend_fac * blend_fac) * 2.0f; - CLAMP(blend_fac, 0.3f, 1.0f); - - - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, blend_fac); + /* setup window matrices */ + if (winmat) + copy_m4_m4(rv3d->winmat, winmat); + else + view3d_winmatrix_set(depsgraph, ar, v3d, rect); - drawgrid_draw(ar, wx, wy, x, y, dx_scalar); - } - } + /* setup view matrix */ + if (viewmat) { + copy_m4_m4(rv3d->viewmat, viewmat); } else { - const double sublines = v3d->gridsubdiv; - const float sublines_fl = v3d->gridsubdiv; - - if (dx < GRID_MIN_PX_D) { - rv3d->gridview *= sublines_fl; - dx *= sublines; - - if (dx < GRID_MIN_PX_D) { - rv3d->gridview *= sublines_fl; - dx *= sublines; - - if (dx < GRID_MIN_PX_D) { - rv3d->gridview *= sublines_fl; - dx *= sublines; - if (dx < GRID_MIN_PX_D) { - /* pass */ - } - else { - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx); - } - } - else { /* start blending out */ - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, sublines * dx); - } - } - else { /* start blending out (GRID_MIN_PX < dx < (GRID_MIN_PX * 10)) */ - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, sublines * dx); - } - } - else { - if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ - rv3d->gridview /= sublines_fl; - dx /= sublines; - if (dx > (GRID_MIN_PX_D * 10.0)) { /* start blending in */ - rv3d->gridview /= sublines_fl; - dx /= sublines; - if (dx > (GRID_MIN_PX_D * 10.0)) { - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx); - } - else { - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx * sublines); - } - } - else { - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx * sublines); - } - } - else { - UI_ThemeColorBlend(TH_HIGH_GRAD, TH_GRID, dx / (GRID_MIN_PX_D * 6.0)); - drawgrid_draw(ar, wx, wy, x, y, dx); - UI_ThemeColor(TH_GRID); - drawgrid_draw(ar, wx, wy, x, y, dx * sublines); - } + float rect_scale[2]; + if (rect) { + rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)ar->winx; + rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)ar->winy; } + /* note: calls BKE_object_where_is_calc for camera... */ + view3d_viewmatrix_set(depsgraph, scene, v3d, rv3d, rect ? rect_scale : NULL); } + /* update utility matrices */ + mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); + invert_m4_m4(rv3d->persinv, rv3d->persmat); + invert_m4_m4(rv3d->viewinv, rv3d->viewmat); + /* calculate GLSL view dependent values */ - x += (wx); - y += (wy); - UI_GetThemeColor3ubv(TH_GRID, col); - - setlinestyle(0); - - /* center cross */ - /* horizontal line */ - if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) - UI_make_axis_color(col, col2, 'Y'); - else UI_make_axis_color(col, col2, 'X'); - glColor3ubv(col2); - - fdrawline(0.0, y, (float)ar->winx, y); + /* store window coordinates scaling/offset */ + if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + rctf cameraborder; + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &cameraborder, false); + rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); + rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); - /* vertical line */ - if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) - UI_make_axis_color(col, col2, 'Y'); - else UI_make_axis_color(col, col2, 'Z'); - glColor3ubv(col2); + rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx; + rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy; + } + else { + rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f; + rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f; + } - fdrawline(x, 0.0, x, (float)ar->winy); + /* calculate pixelsize factor once, is used for lamps and obcenters */ + { + /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])' + * because of float point precision problems at large values [#23908] */ + float v1[3], v2[3]; + float len_px, len_sc; - glDepthMask(GL_TRUE); /* enable write in zbuffer */ -} -#undef GRID_MIN_PX + v1[0] = rv3d->persmat[0][0]; + v1[1] = rv3d->persmat[1][0]; + v1[2] = rv3d->persmat[2][0]; -/** could move this elsewhere, but tied into #ED_view3d_grid_scale */ -float ED_scene_grid_scale(Scene *scene, const char **grid_unit) -{ - /* apply units */ - if (scene->unit.system) { - const void *usys; - int len; + v2[0] = rv3d->persmat[0][1]; + v2[1] = rv3d->persmat[1][1]; + v2[2] = rv3d->persmat[2][1]; - bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len); + len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); + len_sc = (float)MAX2(ar->winx, ar->winy); - if (usys) { - int i = bUnit_GetBaseUnit(usys); - if (grid_unit) - *grid_unit = bUnit_GetNameDisplay(usys, i); - return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length; - } + rv3d->pixsize = len_px / len_sc; } - - return 1.0f; } -float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit) -{ - return v3d->grid * ED_scene_grid_scale(scene, grid_unit); -} - -static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit, bool write_depth) +static void view3d_main_region_setup_view( + Depsgraph *depsgraph, Scene *scene, + View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect) { - float grid, grid_scale; - unsigned char col_grid[3]; - const int gridlines = v3d->gridlines / 2; - - if (v3d->gridlines < 3) return; - - /* use 'grid_scale' instead of 'v3d->grid' from now on */ - grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit); - grid = gridlines * grid_scale; - - if (!write_depth) - glDepthMask(GL_FALSE); - - UI_GetThemeColor3ubv(TH_GRID, col_grid); - - glLineWidth(1); - - /* draw the Y axis and/or grid lines */ - if (v3d->gridflag & V3D_SHOW_FLOOR) { - const int sublines = v3d->gridsubdiv; - float vert[4][3] = {{0.0f}}; - unsigned char col_bg[3]; - unsigned char col_grid_emphasise[3], col_grid_light[3]; - int a; - int prev_emphasise = -1; - - UI_GetThemeColor3ubv(TH_BACK, col_bg); - - /* emphasise division lines lighter instead of darker, if background is darker than grid */ - UI_GetColorPtrShade3ubv(col_grid, col_grid_light, 10); - UI_GetColorPtrShade3ubv(col_grid, col_grid_emphasise, - (((col_grid[0] + col_grid[1] + col_grid[2]) + 30) > - (col_bg[0] + col_bg[1] + col_bg[2])) ? 20 : -10); - - /* set fixed axis */ - vert[0][0] = vert[2][1] = grid; - vert[1][0] = vert[3][1] = -grid; - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, 0, vert); - - for (a = -gridlines; a <= gridlines; a++) { - const float line = a * grid_scale; - const int is_emphasise = (a % sublines) == 0; - - if (is_emphasise != prev_emphasise) { - glColor3ubv(is_emphasise ? col_grid_emphasise : col_grid_light); - prev_emphasise = is_emphasise; - } - - /* set variable axis */ - vert[0][1] = vert[1][1] = vert[2][0] = vert[3][0] = line; - - glDrawArrays(GL_LINES, 0, 4); - } - - glDisableClientState(GL_VERTEX_ARRAY); - } + RegionView3D *rv3d = ar->regiondata; - /* draw the Z axis line */ - /* check for the 'show Z axis' preference */ - if (v3d->gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) { - glBegin(GL_LINES); - int axis; - for (axis = 0; axis < 3; axis++) { - if (v3d->gridflag & (V3D_SHOW_X << axis)) { - float vert[3]; - unsigned char tcol[3]; - - UI_make_axis_color(col_grid, tcol, 'X' + axis); - glColor3ubv(tcol); - - zero_v3(vert); - vert[axis] = grid; - glVertex3fv(vert); - vert[axis] = -grid; - glVertex3fv(vert); - } - } - glEnd(); - } + ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, viewmat, winmat, rect); - glDepthMask(GL_TRUE); + /* set for opengl */ + GPU_matrix_projection_set(rv3d->winmat); + GPU_matrix_set(rv3d->viewmat); } - -static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d) +static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d) { - int co[2]; - - /* we don't want the clipping for cursor */ - if (ED_view3d_project_int_global(ar, ED_view3d_cursor3d_get(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - const float f5 = 0.25f * U.widget_unit; - const float f10 = 0.5f * U.widget_unit; - const float f20 = U.widget_unit; - - glLineWidth(1); - setlinestyle(0); - cpack(0xFF); - circ((float)co[0], (float)co[1], f10); - setlinestyle(4); - cpack(0xFFFFFF); - circ((float)co[0], (float)co[1], f10); - setlinestyle(0); - - UI_ThemeColor(TH_VIEW_OVERLAY); - sdrawline(co[0] - f20, co[1], co[0] - f5, co[1]); - sdrawline(co[0] + f5, co[1], co[0] + f20, co[1]); - sdrawline(co[0], co[1] - f20, co[0], co[1] - f5); - sdrawline(co[0], co[1] + f5, co[0], co[1] + f20); + if ((scene->r.scemode & R_MULTIVIEW) == 0) { + return false; } -} - -/* Draw a live substitute of the view icon, which is always shown - * colors copied from transform_manipulator.c, we should keep these matching. */ -static void draw_view_axis(RegionView3D *rv3d, rcti *rect) -{ - const float k = U.rvisize * U.pixelsize; /* axis size */ - const float toll = 0.5; /* used to see when view is quasi-orthogonal */ - float startx = k + 1.0f; /* axis center in screen coordinates, x=y */ - float starty = k + 1.0f; - float ydisp = 0.0; /* vertical displacement to allow obj info text */ - int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */ - float vec[3]; - float dx, dy; - - int axis_order[3] = {0, 1, 2}; - int axis_i; - - startx += rect->xmin; - starty += rect->ymin; - - axis_sort_v3(rv3d->viewinv[2], axis_order); - - /* thickness of lines is proportional to k */ - glLineWidth(2); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - for (axis_i = 0; axis_i < 3; axis_i++) { - int i = axis_order[axis_i]; - const char axis_text[2] = {'x' + i, '\0'}; - - zero_v3(vec); - vec[i] = 1.0f; - mul_qt_v3(rv3d->viewquat, vec); - dx = vec[0] * k; - dy = vec[1] * k; - - UI_ThemeColorShadeAlpha(TH_AXIS_X + i, 0, bright); - glBegin(GL_LINES); - glVertex2f(startx, starty + ydisp); - glVertex2f(startx + dx, starty + dy + ydisp); - glEnd(); - - if (fabsf(dx) > toll || fabsf(dy) > toll) { - BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, axis_text, 1); - - /* BLF_draw_default disables blending */ - glEnable(GL_BLEND); - } + if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) { + return false; } - glDisable(GL_BLEND); -} - -#ifdef WITH_INPUT_NDOF -/* draw center and axis of rotation for ongoing 3D mouse navigation */ -static void draw_rotation_guide(RegionView3D *rv3d) -{ - float o[3]; /* center of rotation */ - float end[3]; /* endpoints for drawing */ - - float color[4] = {0.0f, 0.4235f, 1.0f, 1.0f}; /* bright blue so it matches device LEDs */ - - negate_v3_v3(o, rv3d->ofs); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPointSize(5); - glEnable(GL_POINT_SMOOTH); - glDepthMask(0); /* don't overwrite zbuf */ - - if (rv3d->rot_angle != 0.0f) { - /* -- draw rotation axis -- */ - float scaled_axis[3]; - const float scale = rv3d->dist; - mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale); - - - glBegin(GL_LINE_STRIP); - color[3] = 0.0f; /* more transparent toward the ends */ - glColor4fv(color); - add_v3_v3v3(end, o, scaled_axis); - glVertex3fv(end); - -#if 0 - color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */ - /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */ -#endif - - color[3] = 0.5f; /* more opaque toward the center */ - glColor4fv(color); - glVertex3fv(o); - - color[3] = 0.0f; - glColor4fv(color); - sub_v3_v3v3(end, o, scaled_axis); - glVertex3fv(end); - glEnd(); - - /* -- draw ring around rotation center -- */ - { -#define ROT_AXIS_DETAIL 13 - - const float s = 0.05f * scale; - const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL); - float angle; - int i; - - float q[4]; /* rotate ring so it's perpendicular to axis */ - const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f; - if (!upright) { - const float up[3] = {0.0f, 0.0f, 1.0f}; - float vis_angle, vis_axis[3]; - - cross_v3_v3v3(vis_axis, up, rv3d->rot_axis); - vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis)); - axis_angle_to_quat(q, vis_axis, vis_angle); + switch (v3d->stereo3d_camera) { + case STEREO_MONO_ID: + return false; + break; + case STEREO_3D_ID: + /* win will be NULL when calling this from the selection or draw loop. */ + if ((win == NULL) || (WM_stereo3d_enabled(win, true) == false)) { + return false; } - - color[3] = 0.25f; /* somewhat faint */ - glColor4fv(color); - glBegin(GL_LINE_LOOP); - for (i = 0, angle = 0.0f; i < ROT_AXIS_DETAIL; ++i, angle += step) { - float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f}; - - if (!upright) { - mul_qt_v3(q, p); - } - - add_v3_v3(p, o); - glVertex3fv(p); + if (((scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) != 0) && + !BKE_scene_multiview_is_stereo3d(&scene->r)) + { + return false; } - glEnd(); - -#undef ROT_AXIS_DETAIL - } - - color[3] = 1.0f; /* solid dot */ - } - else - color[3] = 0.5f; /* see-through dot */ - - /* -- draw rotation center -- */ - glColor4fv(color); - glBegin(GL_POINTS); - glVertex3fv(o); - glEnd(); - -#if 0 - /* find screen coordinates for rotation center, then draw pretty icon */ - mul_m4_v3(rv3d->persinv, rot_center); - UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN); - /* ^^ just playing around, does not work */ -#endif - - glDisable(GL_BLEND); - glDisable(GL_POINT_SMOOTH); - glDepthMask(1); -} -#endif /* WITH_INPUT_NDOF */ - -static void draw_view_icon(RegionView3D *rv3d, rcti *rect) -{ - BIFIconID icon; - - if (ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) - icon = ICON_AXIS_TOP; - else if (ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) - icon = ICON_AXIS_FRONT; - else if (ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) - icon = ICON_AXIS_SIDE; - else return; - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - UI_icon_draw(5.0 + rect->xmin, 5.0 + rect->ymin, icon); - - glDisable(GL_BLEND); -} - -static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d) -{ - const char *name = NULL; - - switch (rv3d->view) { - case RV3D_VIEW_FRONT: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Ortho"); - else name = IFACE_("Front Persp"); - break; - case RV3D_VIEW_BACK: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Ortho"); - else name = IFACE_("Back Persp"); break; - case RV3D_VIEW_TOP: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Ortho"); - else name = IFACE_("Top Persp"); - break; - case RV3D_VIEW_BOTTOM: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Ortho"); - else name = IFACE_("Bottom Persp"); - break; - case RV3D_VIEW_RIGHT: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Ortho"); - else name = IFACE_("Right Persp"); - break; - case RV3D_VIEW_LEFT: - if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Ortho"); - else name = IFACE_("Left Persp"); - break; - + /* We always need the stereo calculation for left and right cameras. */ + case STEREO_LEFT_ID: + case STEREO_RIGHT_ID: default: - if (rv3d->persp == RV3D_CAMOB) { - if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) { - Camera *cam; - cam = v3d->camera->data; - if (cam->type == CAM_PERSP) { - name = IFACE_("Camera Persp"); - } - else if (cam->type == CAM_ORTHO) { - name = IFACE_("Camera Ortho"); - } - else { - BLI_assert(cam->type == CAM_PANO); - name = IFACE_("Camera Pano"); - } - } - else { - name = IFACE_("Object as Camera"); - } - } - else { - name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Ortho") : IFACE_("User Persp"); - } break; } - - return name; + return true; } -static void draw_viewport_name(ARegion *ar, View3D *v3d, rcti *rect) -{ - RegionView3D *rv3d = ar->regiondata; - const char *name = view3d_get_name(v3d, rv3d); - /* increase size for unicode languages (Chinese in utf-8...) */ -#ifdef WITH_INTERNATIONAL - char tmpstr[96]; -#else - char tmpstr[32]; -#endif - - if (v3d->localvd) { - BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name); - name = tmpstr; - } - - UI_ThemeColor(TH_TEXT_HI); -#ifdef WITH_INTERNATIONAL - BLF_draw_default(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); -#else - BLF_draw_default_ascii(U.widget_unit + rect->xmin, rect->ymax - U.widget_unit, 0.0f, name, sizeof(tmpstr)); -#endif -} -/* draw info beside axes in bottom left-corner: - * framenum, object name, bone name (if available), marker name (if available) +/* setup the view and win matrices for the multiview cameras + * + * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called + * we have no winmatrix (i.e., projection matrix) defined at that time. + * Since the camera and the camera shift are needed for the winmat calculation + * we do a small hack to replace it temporarily so we don't need to change the + * view3d)main_region_setup_view() code to account for that. */ - -static void draw_selected_name(Scene *scene, Object *ob, const rcti *rect) +static void view3d_stereo3d_setup( + Depsgraph *depsgraph, Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect) { - const int cfra = CFRA; - const char *msg_pin = " (Pinned)"; - const char *msg_sep = " : "; + bool is_left; + const char *names[2] = { STEREO_LEFT_NAME, STEREO_RIGHT_NAME }; + const char *viewname; - char info[300]; - const char *markern; - char *s = info; - short offset = 1.5f * UI_UNIT_X + rect->xmin; + /* show only left or right camera */ + if (v3d->stereo3d_camera != STEREO_3D_ID) + v3d->multiview_eye = v3d->stereo3d_camera; - s += sprintf(s, "(%d)", cfra); + is_left = v3d->multiview_eye == STEREO_LEFT_ID; + viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID]; - /* - * info can contain: - * - a frame (7 + 2) - * - 3 object names (MAX_NAME) - * - 2 BREAD_CRUMB_SEPARATORs (6) - * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room! - * - a marker name (MAX_NAME + 3) - */ + /* update the viewport matrices with the new camera */ + if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { + Camera *data; + float viewmat[4][4]; + float shiftx; - /* get name of marker on current frame (if available) */ - markern = BKE_scene_find_marker_name(scene, cfra); + data = (Camera *)v3d->camera->data; + shiftx = data->shiftx; - /* check if there is an object */ - if (ob) { - *s++ = ' '; - s += BLI_strcpy_rlen(s, ob->id.name + 2); + BLI_thread_lock(LOCK_VIEW3D); + data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname); - /* name(s) to display depends on type of object */ - if (ob->type == OB_ARMATURE) { - bArmature *arm = ob->data; + BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); + view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, NULL, rect); - /* show name of active bone too (if possible) */ - if (arm->edbo) { - if (arm->act_edbone) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, arm->act_edbone->name); - } - } - else if (ob->mode & OB_MODE_POSE) { - if (arm->act_bone) { + data->shiftx = shiftx; + BLI_thread_unlock(LOCK_VIEW3D); + } + else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ + float viewmat[4][4]; + Object *view_ob = v3d->camera; + Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - if (arm->act_bone->layer & arm->layer) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, arm->act_bone->name); - } - } - } - } - else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { - Key *key = NULL; - KeyBlock *kb = NULL; + BLI_thread_lock(LOCK_VIEW3D); + v3d->camera = camera; - /* try to display active bone and active shapekey too (if they exist) */ + BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); + view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, NULL, rect); - if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) { - Object *armobj = BKE_object_pose_armature_get(ob); - if (armobj && armobj->mode & OB_MODE_POSE) { - bArmature *arm = armobj->data; - if (arm->act_bone) { - if (arm->act_bone->layer & arm->layer) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, arm->act_bone->name); - } - } - } - } + v3d->camera = view_ob; + BLI_thread_unlock(LOCK_VIEW3D); + } +} - key = BKE_key_from_object(ob); - if (key) { - kb = BLI_findlink(&key->block, ob->shapenr - 1); - if (kb) { - s += BLI_strcpy_rlen(s, msg_sep); - s += BLI_strcpy_rlen(s, kb->name); - if (ob->shapeflag & OB_SHAPE_LOCK) { - s += BLI_strcpy_rlen(s, IFACE_(msg_pin)); - } - } - } - } +/** + * Set the correct matrices + */ +void ED_view3d_draw_setup_view( + wmWindow *win, Depsgraph *depsgraph, Scene *scene, ARegion *ar, View3D *v3d, + float viewmat[4][4], float winmat[4][4], const rcti *rect) +{ + RegionView3D *rv3d = ar->regiondata; - /* color depends on whether there is a keyframe */ - if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) - UI_ThemeColor(TH_TIME_KEYFRAME); - else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) - UI_ThemeColor(TH_TIME_GP_KEYFRAME); - else - UI_ThemeColor(TH_TEXT_HI); + /* Setup the view matrix. */ + if (view3d_stereo3d_active(win, scene, v3d, rv3d)) { + view3d_stereo3d_setup(depsgraph, scene, v3d, ar, rect); } else { - /* no object */ - if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra)) - UI_ThemeColor(TH_TIME_GP_KEYFRAME); - else - UI_ThemeColor(TH_TEXT_HI); - } - - if (markern) { - s += sprintf(s, " <%s>", markern); + view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, rect); } - - if (U.uiflag & USER_SHOW_ROTVIEWICON) - offset = U.widget_unit + (U.rvisize * 2) + rect->xmin; - - BLF_draw_default(offset, 0.5f * U.widget_unit, 0.0f, info, sizeof(info)); } +/* ******************** view border ***************** */ + static void view3d_camera_border( - const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, + const Scene *scene, struct Depsgraph *depsgraph, + const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, rctf *r_viewborder, const bool no_shift, const bool no_zoom) { CameraParams params; rctf rect_view, rect_camera; + Object *camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera); /* get viewport viewplane */ BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, v3d, rv3d); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); if (no_zoom) params.zoom = 1.0f; BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); @@ -990,7 +322,7 @@ static void view3d_camera_border( /* fallback for non camera objects */ params.clipsta = v3d->near; params.clipend = v3d->far; - BKE_camera_params_from_object(¶ms, v3d->camera); + BKE_camera_params_from_object(¶ms, camera_eval); if (no_shift) { params.shiftx = 0.0f; params.shifty = 0.0f; @@ -1006,24 +338,26 @@ static void view3d_camera_border( } void ED_view3d_calc_camera_border_size( - const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, + const Scene *scene, Depsgraph *depsgraph, + const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, float r_size[2]) { rctf viewborder; - view3d_camera_border(scene, ar, v3d, rv3d, &viewborder, true, true); + view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, true, true); r_size[0] = BLI_rctf_size_x(&viewborder); r_size[1] = BLI_rctf_size_y(&viewborder); } void ED_view3d_calc_camera_border( - const Scene *scene, const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, + const Scene *scene, Depsgraph *depsgraph, + const ARegion *ar, const View3D *v3d, const RegionView3D *rv3d, rctf *r_viewborder, const bool no_shift) { - view3d_camera_border(scene, ar, v3d, rv3d, r_viewborder, no_shift, false); + view3d_camera_border(scene, depsgraph, ar, v3d, rv3d, r_viewborder, no_shift, false); } -static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float fac) +static void drawviewborder_grid3(uint shdr_pos, float x1, float x2, float y1, float y2, float fac) { float x3, y3, x4, y4; @@ -1032,29 +366,33 @@ static void drawviewborder_grid3(float x1, float x2, float y1, float y2, float f x4 = x1 + (1.0f - fac) * (x2 - x1); y4 = y1 + (1.0f - fac) * (y2 - y1); - glBegin(GL_LINES); - glVertex2f(x1, y3); - glVertex2f(x2, y3); + immBegin(GPU_PRIM_LINES, 8); + + immVertex2f(shdr_pos, x1, y3); + immVertex2f(shdr_pos, x2, y3); - glVertex2f(x1, y4); - glVertex2f(x2, y4); + immVertex2f(shdr_pos, x1, y4); + immVertex2f(shdr_pos, x2, y4); - glVertex2f(x3, y1); - glVertex2f(x3, y2); + immVertex2f(shdr_pos, x3, y1); + immVertex2f(shdr_pos, x3, y2); - glVertex2f(x4, y1); - glVertex2f(x4, y2); - glEnd(); + immVertex2f(shdr_pos, x4, y1); + immVertex2f(shdr_pos, x4, y2); + + immEnd(); } /* harmonious triangle */ -static void drawviewborder_triangle(float x1, float x2, float y1, float y2, const char golden, const char dir) +static void drawviewborder_triangle( + uint shdr_pos, float x1, float x2, float y1, float y2, const char golden, const char dir) { float ofs; float w = x2 - x1; float h = y2 - y1; - glBegin(GL_LINES); + immBegin(GPU_PRIM_LINES, 6); + if (w > h) { if (golden) { ofs = w * (1.0f - (1.0f / 1.61803399f)); @@ -1064,14 +402,14 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons } if (dir == 'B') SWAP(float, y1, y2); - glVertex2f(x1, y1); - glVertex2f(x2, y2); + immVertex2f(shdr_pos, x1, y1); + immVertex2f(shdr_pos, x2, y2); - glVertex2f(x2, y1); - glVertex2f(x1 + (w - ofs), y2); + immVertex2f(shdr_pos, x2, y1); + immVertex2f(shdr_pos, x1 + (w - ofs), y2); - glVertex2f(x1, y2); - glVertex2f(x1 + ofs, y1); + immVertex2f(shdr_pos, x1, y2); + immVertex2f(shdr_pos, x1 + ofs, y1); } else { if (golden) { @@ -1082,19 +420,20 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons } if (dir == 'B') SWAP(float, x1, x2); - glVertex2f(x1, y1); - glVertex2f(x2, y2); + immVertex2f(shdr_pos, x1, y1); + immVertex2f(shdr_pos, x2, y2); - glVertex2f(x2, y1); - glVertex2f(x1, y1 + ofs); + immVertex2f(shdr_pos, x2, y1); + immVertex2f(shdr_pos, x1, y1 + ofs); - glVertex2f(x1, y2); - glVertex2f(x2, y1 + (h - ofs)); + immVertex2f(shdr_pos, x1, y2); + immVertex2f(shdr_pos, x2, y1 + (h - ofs)); } - glEnd(); + + immEnd(); } -static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) +static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { float x1, x2, y1, y2; float x1i, x2i, y1i, y2i; @@ -1108,14 +447,14 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) if (v3d->camera->type == OB_CAMERA) ca = v3d->camera->data; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false); /* the offsets */ x1 = viewborder.xmin; y1 = viewborder.ymin; x2 = viewborder.xmax; y2 = viewborder.ymax; - glLineWidth(1.0f); + GPU_line_width(1.0f); /* apply offsets so the real 3D camera shows through */ @@ -1129,56 +468,74 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) x2i = (int)(x2 + (1.0f - 0.0001f)); y2i = (int)(y2 + (1.0f - 0.0001f)); - /* passepartout, specified in camera edit buttons */ - if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) { - const float winx = (ar->winx + 1); - const float winy = (ar->winy + 1); + uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - if (ca->passepartalpha == 1.0f) { - glColor3f(0, 0, 0); - } - else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glColor4f(0, 0, 0, ca->passepartalpha); - } + /* First, solid lines. */ + { + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if (x1i > 0.0f) - glRectf(0.0, winy, x1i, 0.0); - if (x2i < winx) - glRectf(x2i, winy, winx, 0.0); - if (y2i < winy) - glRectf(x1i, winy, x2i, y2i); - if (y2i > 0.0f) - glRectf(x1i, y1i, x2i, 0.0); + /* passepartout, specified in camera edit buttons */ + if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) { + const float winx = (ar->winx + 1); + const float winy = (ar->winy + 1); - glDisable(GL_BLEND); - } + float alpha = 1.0f; + + if (ca->passepartalpha != 1.0f) { + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); + alpha = ca->passepartalpha; + } - setlinestyle(0); + immUniformColor4f(0.0f, 0.0f, 0.0f, alpha); - UI_ThemeColor(TH_BACK); + if (x1i > 0.0f) + immRectf(shdr_pos, 0.0f, winy, x1i, 0.0f); + if (x2i < winx) + immRectf(shdr_pos, x2i, winy, winx, 0.0f); + if (y2i < winy) + immRectf(shdr_pos, x1i, winy, x2i, y2i); + if (y2i > 0.0f) + immRectf(shdr_pos, x1i, y1i, x2i, 0.0f); - fdrawbox(x1i, y1i, x2i, y2i); + GPU_blend(false); + } + + immUniformThemeColor(TH_BACK); + imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i); #ifdef VIEW3D_CAMERA_BORDER_HACK - if (view3d_camera_border_hack_test == true) { - glColor3ubv(view3d_camera_border_hack_col); - fdrawbox(x1i + 1, y1i + 1, x2i - 1, y2i - 1); - view3d_camera_border_hack_test = false; - } + if (view3d_camera_border_hack_test == true) { + immUniformColor3ubv(view3d_camera_border_hack_col); + imm_draw_box_wire_2d(shdr_pos, x1i + 1, y1i + 1, x2i - 1, y2i - 1); + view3d_camera_border_hack_test = false; + } #endif - setlinestyle(3); - - /* outer line not to confuse with object selecton */ - if (v3d->flag2 & V3D_LOCK_CAMERA) { - UI_ThemeColor(TH_REDALERT); - fdrawbox(x1i - 1, y1i - 1, x2i + 1, y2i + 1); + immUnbindProgram(); } - UI_ThemeColor(TH_VIEW_OVERLAY); - fdrawbox(x1i, y1i, x2i, y2i); + /* And now, the dashed lines! */ + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + + { + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniform1f("dash_width", 6.0f); + immUniform1f("dash_factor", 0.5f); + + /* outer line not to confuse with object selection */ + if (v3d->flag2 & V3D_LOCK_CAMERA) { + immUniformThemeColor(TH_REDALERT); + imm_draw_box_wire_2d(shdr_pos, x1i - 1, y1i - 1, x2i + 1, y2i + 1); + } + + immUniformThemeColor(TH_VIEW_OVERLAY); + imm_draw_box_wire_2d(shdr_pos, x1i, y1i, x2i, y2i); + } /* border */ if (scene->r.mode & R_BORDER) { @@ -1189,82 +546,76 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) x4 = floorf(x1 + (scene->r.border.xmax * (x2 - x1))) + (U.pixelsize - 1); y4 = floorf(y1 + (scene->r.border.ymax * (y2 - y1))) + (U.pixelsize - 1); - cpack(0x4040FF); - sdrawbox(x3, y3, x4, y4); + immUniformColor3f(1.0f, 0.25f, 0.25f); + imm_draw_box_wire_2d(shdr_pos, x3, y3, x4, y4); } /* safety border */ if (ca) { + immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f); + if (ca->dtx & CAM_DTX_CENTER) { float x3, y3; - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - x3 = x1 + 0.5f * (x2 - x1); y3 = y1 + 0.5f * (y2 - y1); - glBegin(GL_LINES); - glVertex2f(x1, y3); - glVertex2f(x2, y3); + immBegin(GPU_PRIM_LINES, 4); - glVertex2f(x3, y1); - glVertex2f(x3, y2); - glEnd(); + immVertex2f(shdr_pos, x1, y3); + immVertex2f(shdr_pos, x2, y3); + + immVertex2f(shdr_pos, x3, y1); + immVertex2f(shdr_pos, x3, y2); + + immEnd(); } if (ca->dtx & CAM_DTX_CENTER_DIAG) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); + immBegin(GPU_PRIM_LINES, 4); + + immVertex2f(shdr_pos, x1, y1); + immVertex2f(shdr_pos, x2, y2); - glBegin(GL_LINES); - glVertex2f(x1, y1); - glVertex2f(x2, y2); + immVertex2f(shdr_pos, x1, y2); + immVertex2f(shdr_pos, x2, y1); - glVertex2f(x1, y2); - glVertex2f(x2, y1); - glEnd(); + immEnd(); } if (ca->dtx & CAM_DTX_THIRDS) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_grid3(x1, x2, y1, y2, 1.0f / 3.0f); + drawviewborder_grid3(shdr_pos, x1, x2, y1, y2, 1.0f / 3.0f); } if (ca->dtx & CAM_DTX_GOLDEN) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_grid3(x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f)); + drawviewborder_grid3(shdr_pos, x1, x2, y1, y2, 1.0f - (1.0f / 1.61803399f)); } if (ca->dtx & CAM_DTX_GOLDEN_TRI_A) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 0, 'A'); + drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 0, 'A'); } if (ca->dtx & CAM_DTX_GOLDEN_TRI_B) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 0, 'B'); + drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 0, 'B'); } if (ca->dtx & CAM_DTX_HARMONY_TRI_A) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 1, 'A'); + drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 1, 'A'); } if (ca->dtx & CAM_DTX_HARMONY_TRI_B) { - UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0); - drawviewborder_triangle(x1, x2, y1, y2, 1, 'B'); + drawviewborder_triangle(shdr_pos, x1, x2, y1, y2, 1, 'B'); } if (ca->flag & CAM_SHOW_SAFE_MARGINS) { UI_draw_safe_areas( - x1, x2, y1, y2, - scene->safe_areas.title, - scene->safe_areas.action); + shdr_pos, x1, x2, y1, y2, + scene->safe_areas.title, scene->safe_areas.action); if (ca->flag & CAM_SHOW_SAFE_CENTER) { UI_draw_safe_areas( - x1, x2, y1, y2, - scene->safe_areas.title_center, - scene->safe_areas.action_center); + shdr_pos, x1, x2, y1, y2, + scene->safe_areas.title_center, scene->safe_areas.action_center); } } @@ -1300,1895 +651,759 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) } /* draw */ - UI_ThemeColorShade(TH_VIEW_OVERLAY, 100); - UI_draw_roundbox_gl_mode(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f); + immUniformThemeColorShade(TH_VIEW_OVERLAY, 100); + + /* TODO Was using UI_draw_roundbox_4fv(false, rect.xmin, rect.ymin, rect.xmax, rect.ymax, 2.0f, color). + * We'll probably need a new imm_draw_line_roundbox_dashed dor that - though in practice the + * 2.0f round corner effect was nearly not visible anyway... */ + imm_draw_box_wire_2d(shdr_pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); } } - setlinestyle(0); + immUnbindProgram(); + /* end dashed lines */ /* camera name - draw in highlighted text color */ if (ca && (ca->flag & CAM_SHOWNAME)) { - UI_ThemeColor(TH_TEXT_HI); + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); BLF_draw_default( x1i, y1i - (0.7f * U.widget_unit), 0.0f, v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2); } } -/* *********************** backdraw for selection *************** */ - -static void backdrawview3d(Scene *scene, wmWindow *win, ARegion *ar, View3D *v3d, Object *obact, Object *obedit) +static void drawrenderborder(ARegion *ar, View3D *v3d) { - RegionView3D *rv3d = ar->regiondata; - int multisample_enabled; + /* use the same program for everything */ + uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - BLI_assert(ar->regiontype == RGN_TYPE_WINDOW); + GPU_line_width(1.0f); - if (obact && (obact->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) || - BKE_paint_select_face_test(obact))) - { - /* do nothing */ - } - /* texture paint mode sampling */ - else if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT) && - (v3d->drawtype > OB_WIRE)) - { - /* do nothing */ - } - else if ((obact && (obact->mode & OB_MODE_PARTICLE_EDIT)) && - V3D_IS_ZBUF(v3d)) - { - /* do nothing */ - } - else if (obedit && - V3D_IS_ZBUF(v3d)) - { - /* do nothing */ - } - else { - v3d->flag &= ~V3D_INVALID_BACKBUF; - return; - } + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - if (!(v3d->flag & V3D_INVALID_BACKBUF)) - return; - -#if 0 - if (test) { - if (qtest()) { - addafterqueue(ar->win, BACKBUFDRAW, 1); - return; - } - } -#endif + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); - if (v3d->drawtype > OB_WIRE) v3d->zbuf = true; + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniform4f("color", 1.0f, 0.25f, 0.25f, 1.0f); + immUniform1f("dash_width", 6.0f); + immUniform1f("dash_factor", 0.5f); - /* dithering and AA break color coding, so disable */ - glDisable(GL_DITHER); + imm_draw_box_wire_2d(shdr_pos, + v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy, + v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy); - multisample_enabled = glIsEnabled(GL_MULTISAMPLE); - if (multisample_enabled) - glDisable(GL_MULTISAMPLE); - - if (win->multisamples != USER_MULTISAMPLE_NONE) { - /* for multisample we use an offscreen FBO. multisample drawing can fail - * with color coded selection drawing, and reading back depths from such - * a buffer can also cause a few seconds freeze on OS X / NVidia. */ - int w = BLI_rcti_size_x(&ar->winrct); - int h = BLI_rcti_size_y(&ar->winrct); - char error[256]; + immUnbindProgram(); +} - if (rv3d->gpuoffscreen) { - if (GPU_offscreen_width(rv3d->gpuoffscreen) != w || - GPU_offscreen_height(rv3d->gpuoffscreen) != h) - { - GPU_offscreen_free(rv3d->gpuoffscreen); - rv3d->gpuoffscreen = NULL; - } - } +void ED_view3d_draw_depth( + Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, bool alphaoverride) +{ + struct bThemeState theme_state; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + RegionView3D *rv3d = ar->regiondata; - if (!rv3d->gpuoffscreen) { - rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error); + short flag = v3d->flag; + float glalphaclip = U.glalphaclip; + int obcenter_dia = U.obcenter_dia; + /* temp set drawtype to solid */ + /* Setting these temporarily is not nice */ + v3d->flag &= ~V3D_SELECT_OUTLINE; + U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */ + U.obcenter_dia = 0; - if (!rv3d->gpuoffscreen) - fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); - } - } + /* Tools may request depth outside of regular drawing code. */ + UI_Theme_Store(&theme_state); + UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); - if (rv3d->gpuoffscreen) - GPU_offscreen_bind(rv3d->gpuoffscreen, true); - else - glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); + ED_view3d_draw_setup_view(NULL, depsgraph, scene, ar, v3d, NULL, NULL, NULL); - glClearColor(0.0, 0.0, 0.0, 0.0); - if (v3d->zbuf) { - glEnable(GL_DEPTH_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - else { - glClear(GL_COLOR_BUFFER_BIT); - glDisable(GL_DEPTH_TEST); - } + GPU_clear(GPU_DEPTH_BIT); - if (rv3d->rflag & RV3D_CLIPPING) + if (rv3d->rflag & RV3D_CLIPPING) { ED_view3d_clipping_set(rv3d); - - G.f |= G_BACKBUFSEL; - - if (obact && (obact->lay & v3d->lay)) { - draw_object_backbufsel(scene, v3d, rv3d, obact); } + /* get surface depth without bias */ + rv3d->rflag |= RV3D_ZOFFSET_DISABLED; - if (rv3d->gpuoffscreen) - GPU_offscreen_unbind(rv3d->gpuoffscreen, true); - else - ar->swap = 0; /* mark invalid backbuf for wm draw */ - - v3d->flag &= ~V3D_INVALID_BACKBUF; + GPU_depth_test(true); - G.f &= ~G_BACKBUFSEL; - v3d->zbuf = false; - glDisable(GL_DEPTH_TEST); - glEnable(GL_DITHER); - if (multisample_enabled) - glEnable(GL_MULTISAMPLE); + DRW_draw_depth_loop(depsgraph, ar, v3d); - if (rv3d->rflag & RV3D_CLIPPING) + if (rv3d->rflag & RV3D_CLIPPING) { ED_view3d_clipping_disable(); -} - -void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) -{ - RegionView3D *rv3d = ar->regiondata; - - if (rv3d->gpuoffscreen) { - GPU_offscreen_bind(rv3d->gpuoffscreen, true); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - glReadPixels(x, y, w, h, format, type, data); - GPU_offscreen_unbind(rv3d->gpuoffscreen, true); - } - else { - glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); } -} + rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED; -/* XXX depth reading exception, for code not using gpu offscreen */ -static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) -{ + /* Reset default for UI */ + GPU_depth_test(false); - glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); -} + U.glalphaclip = glalphaclip; + v3d->flag = flag; + U.obcenter_dia = obcenter_dia; -void ED_view3d_backbuf_validate(ViewContext *vc) -{ - if (vc->v3d->flag & V3D_INVALID_BACKBUF) { - backdrawview3d(vc->scene, vc->win, vc->ar, vc->v3d, vc->obact, vc->obedit); - } + UI_Theme_Restore(&theme_state); } -/** - * allow for small values [0.5 - 2.5], - * and large values, FLT_MAX by clamping by the area size - */ -int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist) -{ - return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx)); -} +/* ******************** other elements ***************** */ -/* samples a single pixel (copied from vpaint) */ -unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y) +/** could move this elsewhere, but tied into #ED_view3d_grid_scale */ +float ED_scene_grid_scale(Scene *scene, const char **grid_unit) { - unsigned int col; - - if (x >= vc->ar->winx || y >= vc->ar->winy) { - return 0; - } - - ED_view3d_backbuf_validate(vc); + /* apply units */ + if (scene->unit.system) { + const void *usys; + int len; - view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); - glReadBuffer(GL_BACK); + bUnit_GetSystem(scene->unit.system, B_UNIT_LENGTH, &usys, &len); - if (ENDIAN_ORDER == B_ENDIAN) { - BLI_endian_switch_uint32(&col); + if (usys) { + int i = bUnit_GetBaseUnit(usys); + if (grid_unit) + *grid_unit = bUnit_GetNameDisplay(usys, i); + return (float)bUnit_GetScaler(usys, i) / scene->unit.scale_length; + } } - return GPU_select_to_index(col); + return 1.0f; } -/* reads full rect, converts indices */ -ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int ymax) +float ED_view3d_grid_scale(Scene *scene, View3D *v3d, const char **grid_unit) { - struct ImBuf *ibuf_clip; - /* clip */ - const rcti clip = { - max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1), - max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)}; - const int size_clip[2] = { - BLI_rcti_size_x(&clip) + 1, - BLI_rcti_size_y(&clip) + 1}; - - if (UNLIKELY((clip.xmin > clip.xmax) || - (clip.ymin > clip.ymax))) - { - return NULL; - } - - ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect); - - ED_view3d_backbuf_validate(vc); - - view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect); - - glReadBuffer(GL_BACK); - - if (ENDIAN_ORDER == B_ENDIAN) { - IMB_convert_rgba_to_abgr(ibuf_clip); - } - - GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); - - if ((clip.xmin == xmin) && - (clip.xmax == xmax) && - (clip.ymin == ymin) && - (clip.ymax == ymax)) - { - return ibuf_clip; - } - else { - /* put clipped result into a non-clipped buffer */ - struct ImBuf *ibuf_full; - const int size[2] = { - (xmax - xmin + 1), - (ymax - ymin + 1)}; - - ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect); - - IMB_rectcpy( - ibuf_full, ibuf_clip, - clip.xmin - xmin, clip.ymin - ymin, - 0, 0, - size_clip[0], size_clip[1]); - IMB_freeImBuf(ibuf_clip); - return ibuf_full; - } + return v3d->grid * ED_scene_grid_scale(scene, grid_unit); } -/** - * Smart function to sample a rectangle spiral ling outside, nice for backbuf selection - */ -uint ED_view3d_backbuf_sample_rect( - ViewContext *vc, const int mval[2], int size, - unsigned int min, unsigned int max, float *r_dist) -{ - struct ImBuf *buf; - const unsigned int *bufmin, *bufmax, *tbuf; - int minx, miny; - int a, b, rc, nr, amount, dirvec[4][2]; - unsigned int index = 0; - - amount = (size - 1) / 2; - - minx = mval[0] - (amount + 1); - miny = mval[1] - (amount + 1); - buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1); - if (!buf) return 0; - - rc = 0; - - dirvec[0][0] = 1; dirvec[0][1] = 0; - dirvec[1][0] = 0; dirvec[1][1] = -size; - dirvec[2][0] = -1; dirvec[2][1] = 0; - dirvec[3][0] = 0; dirvec[3][1] = size; - - bufmin = buf->rect; - tbuf = buf->rect; - bufmax = buf->rect + size * size; - tbuf += amount * size + amount; - - for (nr = 1; nr <= size; nr++) { - - for (a = 0; a < 2; a++) { - for (b = 0; b < nr; b++) { - if (*tbuf && *tbuf >= min && *tbuf < max) { - /* we got a hit */ - - /* get x,y pixel coords from the offset - * (manhatten distance in keeping with other screen-based selection) */ - *r_dist = (float)( - abs(((int)(tbuf - buf->rect) % size) - (size / 2)) + - abs(((int)(tbuf - buf->rect) / size) - (size / 2))); - - /* indices start at 1 here */ - index = (*tbuf - min) + 1; - goto exit; +/* Simulates the grid scale that is visualized by the shaders drawing functions. + * The actual code is seen in `object_grid_frag.glsl` when you get the `grid_res` value. + * Currently the simulation is done only when RV3D_VIEW_IS_AXIS. */ +float ED_view3d_grid_view_scale( + Scene *scene, View3D *v3d, RegionView3D *rv3d, const char **grid_unit) +{ + float grid_scale = ED_view3d_grid_scale(scene, v3d, grid_unit); + if (!rv3d->is_persp && RV3D_VIEW_IS_AXIS(rv3d->view)) { + /* Decrease the distance between grid snap points depending on zoom. */ + float grid_subdiv = v3d->gridsubdiv; + if (grid_subdiv > 1) { + float grid_distance = rv3d->dist; + float lvl = (logf(grid_distance / grid_scale) / logf(grid_subdiv)); + if (lvl < 0.0f) { + /* Negative values need an offset for correct casting. + * By convention, the minimum lvl is limited to -2 (see `objec_mode.c`) */ + if (lvl > -2.0f) { + lvl -= 1.0f; } - - tbuf += (dirvec[rc][0] + dirvec[rc][1]); - - if (tbuf < bufmin || tbuf >= bufmax) { - goto exit; + else { + lvl = -2.0f; } } - rc++; - rc &= 3; + grid_scale *= pow(grid_subdiv, (int)lvl - 1); } } -exit: - IMB_freeImBuf(buf); - return index; + return grid_scale; } - -/* ************************************************************* */ - -static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser) +static void draw_view_axis(RegionView3D *rv3d, const rcti *rect) { - if (BKE_image_is_stereo(ima)) { - iuser->flag |= IMA_SHOW_STEREO; + const float k = U.rvisize * U.pixelsize; /* axis size */ + const int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */ - if ((scene->r.scemode & R_MULTIVIEW) == 0) { - iuser->multiview_eye = STEREO_LEFT_ID; - } - else if (v3d->stereo3d_camera != STEREO_3D_ID) { - /* show only left or right camera */ - iuser->multiview_eye = v3d->stereo3d_camera; - } + /* Axis center in screen coordinates. + * + * - Unit size offset so small text doesn't draw outside the screen + * - Extra X offset because of the panel expander. + */ + const float startx = rect->xmax - (k + UI_UNIT_X * 1.5); + const float starty = rect->ymax - (k + UI_UNIT_Y); - BKE_image_multiview_index(ima, iuser); - } - else { - iuser->flag &= ~IMA_SHOW_STEREO; - } -} + float axis_pos[3][2]; + unsigned char axis_col[3][4]; -static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame) -{ - RegionView3D *rv3d = ar->regiondata; - BGpic *bgpic; - int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0; + int axis_order[3] = {0, 1, 2}; + axis_sort_v3(rv3d->viewinv[2], axis_order); - for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - bgpic->iuser.scene = scene; /* Needed for render results. */ + for (int axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; - if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag) - continue; + /* get position of each axis tip on screen */ + float vec[3] = { 0.0f }; + vec[i] = 1.0f; + mul_qt_v3(rv3d->viewquat, vec); + axis_pos[i][0] = startx + vec[0] * k; + axis_pos[i][1] = starty + vec[1] * k; - if ((bgpic->view == 0) || /* zero for any */ - (bgpic->view & (1 << rv3d->view)) || /* check agaist flags */ - (rv3d->persp == RV3D_CAMOB && bgpic->view == (1 << RV3D_VIEW_CAMERA))) - { - float image_aspect[2]; - float fac, asp, zoomx, zoomy; - float x1, y1, x2, y2, centx, centy; - - ImBuf *ibuf = NULL, *freeibuf, *releaseibuf; - void *lock; - rctf clip_rect; - - Image *ima = NULL; - MovieClip *clip = NULL; - - /* disable individual images */ - if ((bgpic->flag & V3D_BGPIC_DISABLED)) - continue; - - freeibuf = NULL; - releaseibuf = NULL; - if (bgpic->source == V3D_BGPIC_IMAGE) { - ima = bgpic->ima; - if (ima == NULL) - continue; - BKE_image_user_frame_calc(&bgpic->iuser, CFRA, 0); - if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) { - ibuf = NULL; /* frame is out of range, dont show */ - } - else { - view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser); - ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock); - releaseibuf = ibuf; - } + /* get color of each axis */ + UI_GetThemeColorShade3ubv(TH_AXIS_X + i, bright, axis_col[i]); /* rgb */ + axis_col[i][3] = 255 * hypotf(vec[0], vec[1]); /* alpha */ + } - image_aspect[0] = ima->aspx; - image_aspect[1] = ima->aspy; - } - else if (bgpic->source == V3D_BGPIC_MOVIE) { - /* TODO: skip drawing when out of frame range (as image sequences do above) */ + /* draw axis lines */ + GPU_line_width(2.0f); + GPU_line_smooth(true); + GPU_blend(true); + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - if (bgpic->flag & V3D_BGPIC_CAMERACLIP) { - if (scene->camera) - clip = BKE_object_movieclip_get(scene, scene->camera, true); - } - else { - clip = bgpic->clip; - } + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - if (clip == NULL) - continue; + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GPU_PRIM_LINES, 6); - BKE_movieclip_user_set_frame(&bgpic->cuser, CFRA); - ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser); + for (int axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; - image_aspect[0] = clip->aspx; - image_aspect[1] = clip->aspy; + immAttr4ubv(col, axis_col[i]); + immVertex2f(pos, startx, starty); + immAttr4ubv(col, axis_col[i]); + immVertex2fv(pos, axis_pos[i]); + } - /* working with ibuf from image and clip has got different workflow now. - * ibuf acquired from clip is referenced by cache system and should - * be dereferenced after usage. */ - freeibuf = ibuf; - } - else { - /* perhaps when loading future files... */ - BLI_assert(0); - copy_v2_fl(image_aspect, 1.0f); - } + immEnd(); + immUnbindProgram(); + GPU_line_smooth(false); - if (ibuf == NULL) - continue; + /* draw axis names */ + for (int axis_i = 0; axis_i < 3; axis_i++) { + int i = axis_order[axis_i]; - if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */ - if (freeibuf) - IMB_freeImBuf(freeibuf); - if (releaseibuf) - BKE_image_release_ibuf(ima, releaseibuf, lock); + const char axis_text[2] = {'x' + i, '\0'}; + BLF_color4ubv(BLF_default(), axis_col[i]); + BLF_draw_default_ascii(axis_pos[i][0] + 2, axis_pos[i][1] + 2, 0.0f, axis_text, 1); + } +} - continue; - } +#ifdef WITH_INPUT_NDOF +/* draw center and axis of rotation for ongoing 3D mouse navigation */ +static void draw_rotation_guide(const RegionView3D *rv3d) +{ + float o[3]; /* center of rotation */ + float end[3]; /* endpoints for drawing */ - if (ibuf->rect == NULL) - IMB_rect_from_float(ibuf); + GLubyte color[4] = {0, 108, 255, 255}; /* bright blue so it matches device LEDs */ - if (rv3d->persp == RV3D_CAMOB) { + negate_v3_v3(o, rv3d->ofs); - if (do_camera_frame) { - rctf vb; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); - x1 = vb.xmin; - y1 = vb.ymin; - x2 = vb.xmax; - y2 = vb.ymax; - } - else { - x1 = ar->winrct.xmin; - y1 = ar->winrct.ymin; - x2 = ar->winrct.xmax; - y2 = ar->winrct.ymax; - } + GPU_blend(true); + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + glDepthMask(GL_FALSE); /* don't overwrite zbuf */ - /* apply offset last - camera offset is different to offset in blender units */ - /* so this has some sane way of working - this matches camera's shift _exactly_ */ - { - const float max_dim = max_ff(x2 - x1, y2 - y1); - const float xof_scale = bgpic->xof * max_dim; - const float yof_scale = bgpic->yof * max_dim; - - x1 += xof_scale; - y1 += yof_scale; - x2 += xof_scale; - y2 += yof_scale; - } + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - centx = (x1 + x2) / 2.0f; - centy = (y1 + y2) / 2.0f; + immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); - /* aspect correction */ - if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) { - /* apply aspect from clip */ - const float w_src = ibuf->x * image_aspect[0]; - const float h_src = ibuf->y * image_aspect[1]; + if (rv3d->rot_angle != 0.0f) { + /* -- draw rotation axis -- */ + float scaled_axis[3]; + const float scale = rv3d->dist; + mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale); - /* destination aspect is already applied from the camera frame */ - const float w_dst = x1 - x2; - const float h_dst = y1 - y2; - const float asp_src = w_src / h_src; - const float asp_dst = w_dst / h_dst; + immBegin(GPU_PRIM_LINE_STRIP, 3); + color[3] = 0; /* more transparent toward the ends */ + immAttr4ubv(col, color); + add_v3_v3v3(end, o, scaled_axis); + immVertex3fv(pos, end); - if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { - if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) { - /* fit X */ - const float div = asp_src / asp_dst; - x1 = ((x1 - centx) * div) + centx; - x2 = ((x2 - centx) * div) + centx; - } - else { - /* fit Y */ - const float div = asp_dst / asp_src; - y1 = ((y1 - centy) * div) + centy; - y2 = ((y2 - centy) * div) + centy; - } - } - } - } - else { - float tvec[3]; - float sco[2]; - const float mval_f[2] = {1.0f, 0.0f}; - const float co_zero[3] = {0}; - float zfac; - - /* calc window coord */ - zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL); - ED_view3d_win_to_delta(ar, mval_f, tvec, zfac); - fac = max_ff(fabsf(tvec[0]), max_ff(fabsf(tvec[1]), fabsf(tvec[2]))); /* largest abs axis */ - fac = 1.0f / fac; - - asp = (float)ibuf->y / (float)ibuf->x; - - zero_v3(tvec); - ED_view3d_project_float_v2_m4(ar, tvec, sco, rv3d->persmat); - - x1 = sco[0] + fac * (bgpic->xof - bgpic->size); - y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size); - x2 = sco[0] + fac * (bgpic->xof + bgpic->size); - y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size); - - centx = (x1 + x2) / 2.0f; - centy = (y1 + y2) / 2.0f; - } +#if 0 + color[3] = 0.2f + fabsf(rv3d->rot_angle); /* modulate opacity with angle */ + /* ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2 */ +#endif - /* complete clip? */ - BLI_rctf_init(&clip_rect, x1, x2, y1, y2); - if (bgpic->rotation) { - BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation); - } + color[3] = 127; /* more opaque toward the center */ + immAttr4ubv(col, color); + immVertex3fv(pos, o); - if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) { - if (freeibuf) - IMB_freeImBuf(freeibuf); - if (releaseibuf) - BKE_image_release_ibuf(ima, releaseibuf, lock); + color[3] = 0; + immAttr4ubv(col, color); + sub_v3_v3v3(end, o, scaled_axis); + immVertex3fv(pos, end); + immEnd(); - continue; - } + /* -- draw ring around rotation center -- */ + { +#define ROT_AXIS_DETAIL 13 - zoomx = (x2 - x1) / ibuf->x; - zoomy = (y2 - y1) / ibuf->y; + const float s = 0.05f * scale; + const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL); - /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */ - if (zoomx < 1.0f || zoomy < 1.0f) { - float tzoom = min_ff(zoomx, zoomy); - int mip = 0; + float q[4]; /* rotate ring so it's perpendicular to axis */ + const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f; + if (!upright) { + const float up[3] = {0.0f, 0.0f, 1.0f}; + float vis_angle, vis_axis[3]; - if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) { - IMB_remakemipmap(ibuf, 0); - ibuf->userflags &= ~IB_MIPMAP_INVALID; - } - else if (ibuf->mipmap[0] == NULL) - IMB_makemipmap(ibuf, 0); - - while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) { - tzoom *= 2.0f; - zoomx *= 2.0f; - zoomy *= 2.0f; - mip++; - } - if (mip > 0) - ibuf = ibuf->mipmap[mip - 1]; + cross_v3_v3v3(vis_axis, up, rv3d->rot_axis); + vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis)); + axis_angle_to_quat(q, vis_axis, vis_angle); } - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - glDepthMask(0); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - ED_region_pixelspace(ar); + immBegin(GPU_PRIM_LINE_LOOP, ROT_AXIS_DETAIL); + color[3] = 63; /* somewhat faint */ + immAttr4ubv(col, color); + float angle = 0.0f; + for (int i = 0; i < ROT_AXIS_DETAIL; ++i, angle += step) { + float p[3] = {s * cosf(angle), s * sinf(angle), 0.0f}; - glTranslatef(centx, centy, 0.0); - glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f); + if (!upright) { + mul_qt_v3(q, p); + } - if (bgpic->flag & V3D_BGPIC_FLIP_X) { - zoomx *= -1.0f; - x1 = x2; - } - if (bgpic->flag & V3D_BGPIC_FLIP_Y) { - zoomy *= -1.0f; - y1 = y2; + add_v3_v3(p, o); + immVertex3fv(pos, p); } - glPixelZoom(zoomx, zoomy); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend); - - /* could not use glaDrawPixelsAuto because it could fallback to - * glaDrawPixelsSafe in some cases, which will end up in missing - * alpha transparency for the background image (sergey) - */ - glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect); - - glPixelZoom(1.0, 1.0); - glPixelTransferf(GL_ALPHA_SCALE, 1.0f); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - glDisable(GL_BLEND); + immEnd(); - glDepthMask(1); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - - if (freeibuf) - IMB_freeImBuf(freeibuf); - if (releaseibuf) - BKE_image_release_ibuf(ima, releaseibuf, lock); +#undef ROT_AXIS_DETAIL } + + color[3] = 255; /* solid dot */ } -} + else + color[3] = 127; /* see-through dot */ -static void view3d_draw_bgpic_test(Scene *scene, ARegion *ar, View3D *v3d, - const bool do_foreground, const bool do_camera_frame) -{ - RegionView3D *rv3d = ar->regiondata; + immUnbindProgram(); - if ((v3d->flag & V3D_DISPBGPICS) == 0) - return; + /* -- draw rotation center -- */ + immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR); + GPU_point_size(5.0f); + immBegin(GPU_PRIM_POINTS, 1); + immAttr4ubv(col, color); + immVertex3fv(pos, o); + immEnd(); + immUnbindProgram(); - /* disabled - mango request, since footage /w only render is quite useful - * and this option is easy to disable all background images at once */ #if 0 - if (v3d->flag2 & V3D_RENDER_OVERRIDE) - return; + /* find screen coordinates for rotation center, then draw pretty icon */ + mul_m4_v3(rv3d->persinv, rot_center); + UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN); + /* ^^ just playing around, does not work */ #endif - if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) { - if (rv3d->persp == RV3D_CAMOB) { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); - } - } - else { - view3d_draw_bgpic(scene, ar, v3d, do_foreground, do_camera_frame); - } -} - -/* ****************** View3d afterdraw *************** */ - -typedef struct View3DAfter { - struct View3DAfter *next, *prev; - struct Base *base; - short dflag; -} View3DAfter; - -/* temp storage of Objects that need to be drawn as last */ -void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag) -{ - View3DAfter *v3da = MEM_callocN(sizeof(View3DAfter), "View 3d after"); - BLI_assert((base->flag & OB_FROMDUPLI) == 0); - BLI_addtail(lb, v3da); - v3da->base = base; - v3da->dflag = dflag; -} - -/* disables write in zbuffer and draws it over */ -static void view3d_draw_transp(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d) -{ - View3DAfter *v3da; - - glDepthMask(GL_FALSE); - v3d->transp = true; - - while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { - draw_object(bmain, scene, ar, v3d, v3da->base, v3da->dflag); - MEM_freeN(v3da); - } - v3d->transp = false; - + GPU_blend(false); glDepthMask(GL_TRUE); - -} - -/* clears zbuffer and draws it over */ -static void view3d_draw_xray(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, bool *clear) -{ - View3DAfter *v3da; - - if (*clear && v3d->zbuf) { - glClear(GL_DEPTH_BUFFER_BIT); - *clear = false; - } - - v3d->xray = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { - draw_object(bmain, scene, ar, v3d, v3da->base, v3da->dflag); - MEM_freeN(v3da); - } - v3d->xray = false; } +#endif /* WITH_INPUT_NDOF */ +/* ******************** info ***************** */ -/* clears zbuffer and draws it over */ -static void view3d_draw_xraytransp(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, const bool clear) -{ - View3DAfter *v3da; - - if (clear && v3d->zbuf) - glClear(GL_DEPTH_BUFFER_BIT); - - v3d->xray = true; - v3d->transp = true; - - glDepthMask(GL_FALSE); - - while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { - draw_object(bmain, scene, ar, v3d, v3da->base, v3da->dflag); - MEM_freeN(v3da); - } - - v3d->transp = false; - v3d->xray = false; - - glDepthMask(GL_TRUE); -} - -/* clears zbuffer and draws it over, - * note that in the select version we don't care about transparent flag as with regular drawing */ -static void view3d_draw_xray_select(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, bool *clear) +/** + * Render and camera border + */ +static void view3d_draw_border(const bContext *C, ARegion *ar) { - /* Not ideal, but we need to read from the previous depths before clearing - * otherwise we could have a function to load the depths after drawing. - * - * Clearing the depth buffer isn't all that common between drawing objects so accept this for now. - */ - if (U.gpu_select_pick_deph) { - GPU_select_load_id(-1); - } + Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + RegionView3D *rv3d = ar->regiondata; + View3D *v3d = CTX_wm_view3d(C); - View3DAfter *v3da; - if (*clear && v3d->zbuf) { - glClear(GL_DEPTH_BUFFER_BIT); - *clear = false; + if (rv3d->persp == RV3D_CAMOB) { + drawviewborder(scene, depsgraph, ar, v3d); } - - v3d->xray = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { - if (GPU_select_load_id(v3da->base->selcol)) { - draw_object_select(bmain, scene, ar, v3d, v3da->base, v3da->dflag); - } - MEM_freeN(v3da); + else if (v3d->flag2 & V3D_RENDER_BORDER) { + drawrenderborder(ar, v3d); } - v3d->xray = false; } -/* *********************** */ - -/* - * In most cases call draw_dupli_objects, - * draw_dupli_objects_color was added because when drawing set dupli's - * we need to force the color +/** + * Grease Pencil */ - -#if 0 -int dupli_ob_sort(void *arg1, void *arg2) +static void view3d_draw_grease_pencil(const bContext *UNUSED(C)) { - void *p1 = ((DupliObject *)arg1)->ob; - void *p2 = ((DupliObject *)arg2)->ob; - int val = 0; - if (p1 < p2) val = -1; - else if (p1 > p2) val = 1; - return val; + /* TODO viewport */ } -#endif - -static DupliObject *dupli_step(DupliObject *dob) -{ - while (dob && dob->no_draw) - dob = dob->next; - return dob; -} - -static void draw_dupli_objects_color( - Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, Base *base, - const short dflag, const int color) +/** + * Viewport Name + */ +static const char *view3d_get_name(View3D *v3d, RegionView3D *rv3d) { - RegionView3D *rv3d = ar->regiondata; - ListBase *lb; - LodLevel *savedlod; - DupliObject *dob_prev = NULL, *dob, *dob_next = NULL; - Base tbase = {NULL}; - BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */ - GLuint displist = 0; - unsigned char color_rgb[3]; - const short dflag_dupli = dflag | DRAW_CONSTCOLOR; - short transflag; - bool use_displist = false; /* -1 is initialize */ - char dt; - short dtx; - DupliApplyData *apply_data; - - if (base->object->restrictflag & OB_RESTRICT_VIEW) return; - if ((base->object->restrictflag & OB_RESTRICT_RENDER) && (v3d->flag2 & V3D_RENDER_OVERRIDE)) return; - - if (dflag & DRAW_CONSTCOLOR) { - BLI_assert(color == TH_UNDEFINED); - } - else { - UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb); - } - - tbase.flag = OB_FROMDUPLI | base->flag; - lb = object_duplilist(bmain, bmain->eval_ctx, scene, base->object); - // BLI_listbase_sort(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */ - - apply_data = duplilist_apply(base->object, scene, lb); - - dob = dupli_step(lb->first); - if (dob) dob_next = dupli_step(dob->next); - - for (; dob; dob_prev = dob, dob = dob_next, dob_next = dob_next ? dupli_step(dob_next->next) : NULL) { - bool testbb = false; - - tbase.object = dob->ob; - - /* Make sure lod is updated from dupli's position */ - savedlod = dob->ob->currentlod; - -#ifdef WITH_GAMEENGINE - if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { - BKE_object_lod_update(dob->ob, rv3d->viewinv[3]); - } -#endif - - /* extra service: draw the duplicator in drawtype of parent, minimum taken - * to allow e.g. boundbox box objects in groups for LOD */ - dt = tbase.object->dt; - tbase.object->dt = MIN2(tbase.object->dt, base->object->dt); - - /* inherit draw extra, but not if a boundbox under the assumption that this - * is intended to speed up drawing, and drawing extra (especially wire) can - * slow it down too much */ - dtx = tbase.object->dtx; - if (tbase.object->dt != OB_BOUNDBOX) - tbase.object->dtx = base->object->dtx; - - /* negative scale flag has to propagate */ - transflag = tbase.object->transflag; - - if (is_negative_m4(dob->mat)) - tbase.object->transflag |= OB_NEG_SCALE; - else - tbase.object->transflag &= ~OB_NEG_SCALE; - - /* should move outside the loop but possible color is set in draw_object still */ - if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(color_rgb); - } - - /* generate displist, test for new object */ - if (dob_prev && dob_prev->ob != dob->ob) { - if (use_displist == true) - glDeleteLists(displist, 1); - - use_displist = false; - } + const char *name = NULL; - if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) { - bb = *bb_tmp; /* must make a copy */ - testbb = true; - } + switch (rv3d->view) { + case RV3D_VIEW_FRONT: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Front Orthographic"); + else name = IFACE_("Front Perspective"); + break; + case RV3D_VIEW_BACK: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Back Orthographic"); + else name = IFACE_("Back Perspective"); + break; + case RV3D_VIEW_TOP: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Top Orthographic"); + else name = IFACE_("Top Perspective"); + break; + case RV3D_VIEW_BOTTOM: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Bottom Orthographic"); + else name = IFACE_("Bottom Perspective"); + break; + case RV3D_VIEW_RIGHT: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Right Orthographic"); + else name = IFACE_("Right Perspective"); + break; + case RV3D_VIEW_LEFT: + if (rv3d->persp == RV3D_ORTHO) name = IFACE_("Left Orthographic"); + else name = IFACE_("Left Perspective"); + break; - if (!testbb || ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) { - /* generate displist */ - if (use_displist == false) { - - /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP) - * however this is very slow, it was probably needed for the NLA - * offset feature (used in group-duplicate.blend but no longer works in 2.5) - * so for now it should be ok to - campbell */ - - if ( /* if this is the last no need to make a displist */ - (dob_next == NULL || dob_next->ob != dob->ob) || - /* lamp drawing messes with matrices, could be handled smarter... but this works */ - (dob->ob->type == OB_LAMP) || - (dob->type == OB_DUPLIGROUP && dob->animated) || - !bb_tmp || - draw_glsl_material(scene, dob->ob, v3d, dt) || - check_object_draw_texture(scene, v3d, dt) || - (v3d->flag2 & V3D_SOLID_MATCAP) != 0) - { - // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2); - use_displist = false; + default: + if (rv3d->persp == RV3D_CAMOB) { + if ((v3d->camera) && (v3d->camera->type == OB_CAMERA)) { + Camera *cam; + cam = v3d->camera->data; + if (cam->type == CAM_PERSP) { + name = IFACE_("Camera Perspective"); + } + else if (cam->type == CAM_ORTHO) { + name = IFACE_("Camera Orthographic"); + } + else { + BLI_assert(cam->type == CAM_PANO); + name = IFACE_("Camera Panoramic"); + } } else { - // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2); - - /* disable boundbox check for list creation */ - BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1); - /* need this for next part of code */ - unit_m4(dob->ob->obmat); /* obmat gets restored */ - - displist = glGenLists(1); - glNewList(displist, GL_COMPILE); - draw_object(bmain, scene, ar, v3d, &tbase, dflag_dupli); - glEndList(); - - use_displist = true; - BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0); + name = IFACE_("Object as Camera"); } } - - if (use_displist) { - glPushMatrix(); - glMultMatrixf(dob->mat); - glCallList(displist); - glPopMatrix(); - } else { - copy_m4_m4(dob->ob->obmat, dob->mat); - GPU_begin_dupli_object(dob); - draw_object(bmain, scene, ar, v3d, &tbase, dflag_dupli); - GPU_end_dupli_object(); + name = (rv3d->persp == RV3D_ORTHO) ? IFACE_("User Orthographic") : IFACE_("User Perspective"); } - } - - tbase.object->dt = dt; - tbase.object->dtx = dtx; - tbase.object->transflag = transflag; - tbase.object->currentlod = savedlod; } - if (apply_data) { - duplilist_restore(lb, apply_data); - duplilist_free_apply_data(apply_data); - } - - free_object_duplilist(lb); - - if (use_displist) - glDeleteLists(displist, 1); -} - -static void draw_dupli_objects(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, Base *base) -{ - /* define the color here so draw_dupli_objects_color can be called - * from the set loop */ - - int color = (base->flag & SELECT) ? TH_SELECT : TH_WIRE; - /* debug */ - if (base->object->dup_group && base->object->dup_group->id.us < 1) - color = TH_REDALERT; - - draw_dupli_objects_color(bmain, scene, ar, v3d, base, 0, color); + return name; } -/* XXX warning, not using gpu offscreen here */ -void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect) +static void draw_viewport_name(ARegion *ar, View3D *v3d, int xoffset, int *yoffset) { - int x, y, w, h; - rcti r; - /* clamp rect by region */ - - r.xmin = 0; - r.xmax = ar->winx - 1; - r.ymin = 0; - r.ymax = ar->winy - 1; - - /* Constrain rect to depth bounds */ - BLI_rcti_isect(&r, rect, rect); - - /* assign values to compare with the ViewDepths */ - x = rect->xmin; - y = rect->ymin; + RegionView3D *rv3d = ar->regiondata; + const char *name = view3d_get_name(v3d, rv3d); + const int font_id = BLF_default(); - w = BLI_rcti_size_x(rect); - h = BLI_rcti_size_y(rect); + /* increase size for unicode languages (Chinese in utf-8...) */ +#ifdef WITH_INTERNATIONAL + char tmpstr[96]; +#else + char tmpstr[32]; +#endif - if (w <= 0 || h <= 0) { - if (d->depths) - MEM_freeN(d->depths); - d->depths = NULL; + BLF_enable(font_id, BLF_SHADOW); + BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); + BLF_shadow_offset(font_id, 1, -1); - d->damaged = false; + if (v3d->localvd) { + BLI_snprintf(tmpstr, sizeof(tmpstr), IFACE_("%s (Local)"), name); + name = tmpstr; } - else if (d->w != w || - d->h != h || - d->x != x || - d->y != y || - d->depths == NULL - ) - { - d->x = x; - d->y = y; - d->w = w; - d->h = h; - if (d->depths) - MEM_freeN(d->depths); + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); - d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset"); + *yoffset -= U.widget_unit; - d->damaged = true; - } +#ifdef WITH_INTERNATIONAL + BLF_draw_default(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr)); +#else + BLF_draw_default_ascii(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr)); +#endif - if (d->damaged) { - /* XXX using special function here, it doesn't use the gpu offscreen system */ - view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); - glGetDoublev(GL_DEPTH_RANGE, d->depth_range); - d->damaged = false; - } + BLF_disable(font_id, BLF_SHADOW); } -/* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */ -void ED_view3d_depth_update(ARegion *ar) +/** + * draw info beside axes in bottom left-corner: + * framenum, collection, object name, bone name (if available), marker name (if available) + */ + +static void draw_selected_name(Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset) { - RegionView3D *rv3d = ar->regiondata; + const int cfra = CFRA; + const char *msg_pin = " (Pinned)"; + const char *msg_sep = " : "; - /* Create storage for, and, if necessary, copy depth buffer */ - if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths"); - if (rv3d->depths) { - ViewDepths *d = rv3d->depths; - if (d->w != ar->winx || - d->h != ar->winy || - !d->depths) - { - d->w = ar->winx; - d->h = ar->winy; - if (d->depths) - MEM_freeN(d->depths); - d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths"); - d->damaged = true; - } + const int font_id = BLF_default(); - if (d->damaged) { - view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); - glGetDoublev(GL_DEPTH_RANGE, d->depth_range); + char info[300]; + char *s = info; - d->damaged = false; - } - } -} + s += sprintf(s, "(%d)", cfra); -/* utility function to find the closest Z value, use for autodepth */ -float view3d_depth_near(ViewDepths *d) -{ - /* convert to float for comparisons */ - const float near = (float)d->depth_range[0]; - const float far_real = (float)d->depth_range[1]; - float far = far_real; - - const float *depths = d->depths; - float depth = FLT_MAX; - int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */ - - /* far is both the starting 'far' value - * and the closest value found. */ - while (i--) { - depth = *depths++; - if ((depth < far) && (depth > near)) { - far = depth; - } + if ((ob == NULL) || (ob->mode == OB_MODE_OBJECT)) { + LayerCollection *layer_collection = view_layer->active_collection; + s += sprintf(s, " %s%s", BKE_collection_ui_name_get(layer_collection->collection), (ob == NULL) ? "" : " |"); } - return far == far_real ? FLT_MAX : far; -} - -void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d) -{ - short zbuf = v3d->zbuf; - RegionView3D *rv3d = ar->regiondata; - - /* Setup view matrix. */ - ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->viewmat, rv3d->winmat, NULL); - - glClear(GL_DEPTH_BUFFER_BIT); + /* + * info can contain: + * - a frame (7 + 2) + * - a collection name (MAX_NAME + 3) + * - 3 object names (MAX_NAME) + * - 2 BREAD_CRUMB_SEPARATORs (6) + * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room! + * - a marker name (MAX_NAME + 3) + */ - v3d->zbuf = true; - glEnable(GL_DEPTH_TEST); + /* get name of marker on current frame (if available) */ + const char *markern = BKE_scene_find_marker_name(scene, cfra); - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - ED_gpencil_draw_view3d(NULL, scene, v3d, ar, true); - } + /* check if there is an object */ + if (ob) { + *s++ = ' '; + s += BLI_strcpy_rlen(s, ob->id.name + 2); - v3d->zbuf = zbuf; -} + /* name(s) to display depends on type of object */ + if (ob->type == OB_ARMATURE) { + bArmature *arm = ob->data; -static void view3d_draw_depth_loop(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d) -{ - Base *base; - - /* no need for color when drawing depth buffer */ - const short dflag_depth = DRAW_CONSTCOLOR; - - /* draw set first */ - if (scene->set) { - Scene *sce_iter; - for (SETLOOPER(scene->set, sce_iter, base)) { - if (v3d->lay & base->lay) { - draw_object(bmain, scene, ar, v3d, base, 0); - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects_color(bmain, scene, ar, v3d, base, dflag_depth, TH_UNDEFINED); + /* show name of active bone too (if possible) */ + if (arm->edbo) { + if (arm->act_edbone) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, arm->act_edbone->name); } } - } - } - - for (base = scene->base.first; base; base = base->next) { - if (v3d->lay & base->lay) { - /* dupli drawing */ - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects_color(bmain, scene, ar, v3d, base, dflag_depth, TH_UNDEFINED); - } - draw_object(bmain, scene, ar, v3d, base, dflag_depth); - } - } - - /* this isn't that nice, draw xray objects as if they are normal */ - if (v3d->afterdraw_transp.first || - v3d->afterdraw_xray.first || - v3d->afterdraw_xraytransp.first) - { - View3DAfter *v3da; - int mask_orig; - - v3d->xray = true; - - /* transp materials can change the depth mask, see #21388 */ - glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); - + else if (ob->mode & OB_MODE_POSE) { + if (arm->act_bone) { - if (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first) { - glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */ - for (v3da = v3d->afterdraw_xray.first; v3da; v3da = v3da->next) { - draw_object(bmain, scene, ar, v3d, v3da->base, dflag_depth); + if (arm->act_bone->layer & arm->layer) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, arm->act_bone->name); + } + } } - glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */ } + else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) { + /* try to display active bone and active shapekey too (if they exist) */ - /* draw 3 passes, transp/xray/xraytransp */ - v3d->xray = false; - v3d->transp = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_transp))) { - draw_object(bmain, scene, ar, v3d, v3da->base, dflag_depth); - MEM_freeN(v3da); - } - - v3d->xray = true; - v3d->transp = false; - while ((v3da = BLI_pophead(&v3d->afterdraw_xray))) { - draw_object(bmain, scene, ar, v3d, v3da->base, dflag_depth); - MEM_freeN(v3da); - } - - v3d->xray = true; - v3d->transp = true; - while ((v3da = BLI_pophead(&v3d->afterdraw_xraytransp))) { - draw_object(bmain, scene, ar, v3d, v3da->base, dflag_depth); - MEM_freeN(v3da); - } - - - v3d->xray = false; - v3d->transp = false; - - glDepthMask(mask_orig); - } -} - -void ED_view3d_draw_depth(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride) -{ - struct bThemeState theme_state; - RegionView3D *rv3d = ar->regiondata; - short zbuf = v3d->zbuf; - short flag = v3d->flag; - float glalphaclip = U.glalphaclip; - int obcenter_dia = U.obcenter_dia; - /* temp set drawtype to solid */ - - /* Setting these temporarily is not nice */ - v3d->flag &= ~V3D_SELECT_OUTLINE; - U.glalphaclip = alphaoverride ? 0.5f : glalphaclip; /* not that nice but means we wont zoom into billboards */ - U.obcenter_dia = 0; - - /* Tools may request depth outside of regular drawing code. */ - UI_Theme_Store(&theme_state); - UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); - - /* Setup view matrix. */ - ED_view3d_draw_setup_view(NULL, scene, ar, v3d, rv3d->viewmat, rv3d->winmat, NULL); - - glClear(GL_DEPTH_BUFFER_BIT); - - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_set(rv3d); - } - /* get surface depth without bias */ - rv3d->rflag |= RV3D_ZOFFSET_DISABLED; - - v3d->zbuf = true; - glEnable(GL_DEPTH_TEST); - - view3d_draw_depth_loop(bmain, scene, ar, v3d); - - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_disable(); - } - rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED; - - v3d->zbuf = zbuf; - if (!v3d->zbuf) glDisable(GL_DEPTH_TEST); - - U.glalphaclip = glalphaclip; - v3d->flag = flag; - U.obcenter_dia = obcenter_dia; - - UI_Theme_Restore(&theme_state); -} - -void ED_view3d_draw_select_loop( - ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, - bool use_obedit_skip, bool use_nearest) -{ - short code = 1; - const short dflag = DRAW_PICKING | DRAW_CONSTCOLOR; - - if (vc->obedit && vc->obedit->type == OB_MBALL) { - draw_object(vc->bmain, scene, ar, v3d, BASACT, dflag); - } - else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) { - /* if not drawing sketch, draw bones */ - if (!BDR_drawSketchNames(vc)) { - draw_object(vc->bmain, scene, ar, v3d, BASACT, dflag); - } - } - else { - Base *base; - - for (base = scene->base.first; base; base = base->next) { - if (base->lay & v3d->lay) { - - if ((base->object->restrictflag & OB_RESTRICT_SELECT) || - (use_obedit_skip && (scene->obedit->data == base->object->data))) - { - base->selcol = 0; - } - else { - base->selcol = code; - - if (use_nearest && (base->object->dtx & OB_DRAWXRAY)) { - ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag); - } - else { - if (GPU_select_load_id(code)) { - draw_object_select(vc->bmain, scene, ar, v3d, base, dflag); + if (ob->type == OB_MESH && ob->mode & OB_MODE_WEIGHT_PAINT) { + Object *armobj = BKE_object_pose_armature_get(ob); + if (armobj && armobj->mode & OB_MODE_POSE) { + bArmature *arm = armobj->data; + if (arm->act_bone) { + if (arm->act_bone->layer & arm->layer) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, arm->act_bone->name); } } - code++; } } - } - if (use_nearest) { - bool xrayclear = true; - if (v3d->afterdraw_xray.first) { - view3d_draw_xray_select(vc->bmain, scene, ar, v3d, &xrayclear); + Key *key = BKE_key_from_object(ob); + if (key) { + KeyBlock *kb = BLI_findlink(&key->block, ob->shapenr - 1); + if (kb) { + s += BLI_strcpy_rlen(s, msg_sep); + s += BLI_strcpy_rlen(s, kb->name); + if (ob->shapeflag & OB_SHAPE_LOCK) { + s += BLI_strcpy_rlen(s, IFACE_(msg_pin)); + } + } } } - } -} - -typedef struct View3DShadow { - struct View3DShadow *next, *prev; - GPULamp *lamp; -} View3DShadow; - -static void gpu_render_lamp_update(Scene *scene, View3D *v3d, - Object *ob, Object *par, - float obmat[4][4], unsigned int lay, - ListBase *shadows, SceneRenderLayer *srl) -{ - GPULamp *lamp; - Lamp *la = (Lamp *)ob->data; - View3DShadow *shadow; - unsigned int layers; - - lamp = GPU_lamp_from_blender(scene, ob, par); - - if (lamp) { - GPU_lamp_update(lamp, lay, (ob->restrictflag & OB_RESTRICT_RENDER), obmat); - GPU_lamp_update_colors(lamp, la->r, la->g, la->b, la->energy); - - layers = lay & v3d->lay; - if (srl) - layers &= srl->lay; - - if (layers && - GPU_lamp_has_shadow_buffer(lamp) && - /* keep last, may do string lookup */ - GPU_lamp_visible(lamp, srl, NULL)) - { - shadow = MEM_callocN(sizeof(View3DShadow), "View3DShadow"); - shadow->lamp = lamp; - BLI_addtail(shadows, shadow); - } - } -} - -static void gpu_update_lamps_shadows_world(Main *bmain, Scene *scene, View3D *v3d) -{ - ListBase shadows; - View3DShadow *shadow; - Scene *sce_iter; - Base *base; - Object *ob; - World *world = scene->world; - SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL; - - BLI_listbase_clear(&shadows); - - /* update lamp transform and gather shadow lamps */ - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - if (ob->type == OB_LAMP) - gpu_render_lamp_update(scene, v3d, ob, NULL, ob->obmat, ob->lay, &shadows, srl); - - if (ob->transflag & OB_DUPLI) { - DupliObject *dob; - ListBase *lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob); - - for (dob = lb->first; dob; dob = dob->next) - if (dob->ob->type == OB_LAMP) - gpu_render_lamp_update(scene, v3d, dob->ob, ob, dob->mat, ob->lay, &shadows, srl); - - free_object_duplilist(lb); - } + /* color depends on whether there is a keyframe */ + if (id_frame_has_keyframe((ID *)ob, /* BKE_scene_frame_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) + UI_FontThemeColor(font_id, TH_TIME_KEYFRAME); + else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) + UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME); + else + UI_FontThemeColor(font_id, TH_TEXT_HI); } - - /* render shadows after updating all lamps, nested object_duplilist - * don't work correct since it's replacing object matrices */ - for (shadow = shadows.first; shadow; shadow = shadow->next) { - /* this needs to be done better .. */ - float viewmat[4][4], winmat[4][4]; - int drawtype, lay, winsize, flag2 = v3d->flag2; - ARegion ar = {NULL}; - RegionView3D rv3d = {{{0}}}; - - drawtype = v3d->drawtype; - lay = v3d->lay; - - v3d->drawtype = OB_SOLID; - v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp); - v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP); - v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW; - - GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat); - - ar.regiondata = &rv3d; - ar.regiontype = RGN_TYPE_WINDOW; - rv3d.persp = RV3D_CAMOB; - copy_m4_m4(rv3d.winmat, winmat); - copy_m4_m4(rv3d.viewmat, viewmat); - invert_m4_m4(rv3d.viewinv, rv3d.viewmat); - mul_m4_m4m4(rv3d.persmat, rv3d.winmat, rv3d.viewmat); - invert_m4_m4(rv3d.persinv, rv3d.viewinv); - - /* no need to call ED_view3d_draw_offscreen_init since shadow buffers were already updated */ - ED_view3d_draw_offscreen( - bmain, scene, v3d, &ar, winsize, winsize, viewmat, winmat, - false, false, true, - NULL, NULL, NULL, NULL); - GPU_lamp_shadow_buffer_unbind(shadow->lamp); - - v3d->drawtype = drawtype; - v3d->lay = lay; - v3d->flag2 = flag2; + else { + /* no object */ + if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra)) + UI_FontThemeColor(font_id, TH_TIME_GP_KEYFRAME); + else + UI_FontThemeColor(font_id, TH_TEXT_HI); } - BLI_freelistN(&shadows); - - /* update world values */ - if (world) { - GPU_mist_update_enable(world->mode & WO_MIST); - GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr); - GPU_horizon_update_color(&world->horr); - GPU_ambient_update_color(&world->ambr); - GPU_zenith_update_color(&world->zenr); + if (markern) { + s += sprintf(s, " <%s>", markern); } -} -/* *********************** customdata **************** */ + BLF_enable(font_id, BLF_SHADOW); + BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); + BLF_shadow_offset(font_id, 1, -1); -CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d) -{ - CustomDataMask mask = 0; - const int drawtype = view3d_effective_drawtype(v3d); + *yoffset -= U.widget_unit; + BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info)); - if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) || - ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) - { - mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; - - if (BKE_scene_use_new_shading_nodes(scene)) { - if (drawtype == OB_MATERIAL) - mask |= CD_MASK_ORCO; - } - else { - if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) || - (drawtype == OB_MATERIAL)) - { - mask |= CD_MASK_ORCO; - } - } - } - - return mask; + BLF_disable(font_id, BLF_SHADOW); } -/* goes over all modes and view3d settings */ -CustomDataMask ED_view3d_screen_datamask(const bScreen *screen) -{ - const Scene *scene = screen->scene; - CustomDataMask mask = CD_MASK_BAREMESH; - const ScrArea *sa; - - /* check if we need tfaces & mcols due to view mode */ - for (sa = screen->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_VIEW3D) { - mask |= ED_view3d_datamask(scene, sa->spacedata.first); - } - } - - return mask; -} +/* ******************** view loop ***************** */ /** - * \note keep this synced with #ED_view3d_mats_rv3d_backup/#ED_view3d_mats_rv3d_restore + * Information drawn on top of the solid plates and composed data */ -void ED_view3d_update_viewmat( - Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect) +void view3d_draw_region_info(const bContext *C, ARegion *ar) { RegionView3D *rv3d = ar->regiondata; + View3D *v3d = CTX_wm_view3d(C); + Scene *scene = CTX_data_scene(C); + wmWindowManager *wm = CTX_wm_manager(C); - /* setup window matrices */ - if (winmat) - copy_m4_m4(rv3d->winmat, winmat); - else - view3d_winmatrix_set(ar, v3d, rect); - - /* setup view matrix */ - if (viewmat) { - copy_m4_m4(rv3d->viewmat, viewmat); - } - else { - float rect_scale[2]; - if (rect) { - rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)ar->winx; - rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)ar->winy; - } - view3d_viewmatrix_set(scene, v3d, rv3d, rect ? rect_scale : NULL); /* note: calls BKE_object_where_is_calc for camera... */ - } - - /* update utility matrices */ - mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); - invert_m4_m4(rv3d->persinv, rv3d->persmat); - invert_m4_m4(rv3d->viewinv, rv3d->viewmat); - - /* calculate GLSL view dependent values */ - - /* store window coordinates scaling/offset */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { - rctf cameraborder; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); - rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); - rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); - - rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx; - rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy; - } - else { - rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f; - rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f; - } - - /** - * Calculate pixel-size factor once, is used for lamps and object centers. - * Used by #ED_view3d_pixel_size and typically not accessed directly. - * - * \note #BKE_camera_params_compute_viewplane' also calculates a pixel-size value, - * passed to #RE_SetPixelSize, in ortho mode this is compatible with this value, - * but in perspective mode its offset by the near-clip. - * - * 'RegionView3D.pixsize' is used for viewport drawing, not rendering. - */ +#ifdef WITH_INPUT_NDOF + if ((U.ndof_flag & NDOF_SHOW_GUIDE) && + ((rv3d->viewlock & RV3D_LOCKED) == 0) && + (rv3d->persp != RV3D_CAMOB)) { - /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])' - * because of float point precision problems at large values [#23908] */ - float v1[3], v2[3]; - float len_px, len_sc; + /* TODO: draw something else (but not this) during fly mode */ + draw_rotation_guide(rv3d); + } +#endif - v1[0] = rv3d->persmat[0][0]; - v1[1] = rv3d->persmat[1][0]; - v1[2] = rv3d->persmat[2][0]; + /* correct projection matrix */ + ED_region_pixelspace(ar); - v2[0] = rv3d->persmat[0][1]; - v2[1] = rv3d->persmat[1][1]; - v2[2] = rv3d->persmat[2][1]; + /* local coordinate visible rect inside region, to accommodate overlapping ui */ + rcti rect; + ED_region_visible_rect(ar, &rect); - len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); - len_sc = (float)MAX2(ar->winx, ar->winy); - rv3d->pixsize = len_px / len_sc; - } -} + view3d_draw_border(C, ar); + view3d_draw_grease_pencil(C); -/** - * Shared by #ED_view3d_draw_offscreen and #view3d_main_region_draw_objects - * - * \note \a C and \a grid_unit will be NULL when \a draw_offscreen is set. - * \note Drawing lamps and opengl render uses this, so dont do grease pencil or view widgets here. - */ -static void view3d_draw_objects( - const bContext *C, - Main *bmain, - Scene *scene, View3D *v3d, ARegion *ar, - const char **grid_unit, - const bool do_bgpic, const bool draw_offscreen, GPUFX *fx) -{ - if (bmain == NULL) { - bmain = CTX_data_main(C); - } - RegionView3D *rv3d = ar->regiondata; - Base *base; - const bool do_camera_frame = !draw_offscreen; - const bool draw_grids = !draw_offscreen && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0; - const bool draw_floor = (rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO); - /* only draw grids after in solid modes, else it hovers over mesh wires */ - const bool draw_grids_after = draw_grids && draw_floor && (v3d->drawtype > OB_WIRE) && fx; - bool do_composite_xray = false; - bool xrayclear = true; - - if (!draw_offscreen) { - ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW); - } - - if (rv3d->rflag & RV3D_CLIPPING) - view3d_draw_clipping(rv3d); + BLF_batch_draw_begin(); - /* set zbuffer after we draw clipping region */ - if (v3d->drawtype > OB_WIRE) { - v3d->zbuf = true; + if ((U.uiflag & USER_SHOW_GIZMO_AXIS) || + (v3d->flag2 & V3D_RENDER_OVERRIDE) || + /* No need to display gizmo and this info. */ + (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_NAVIGATE))) + { + /* pass */ } else { - v3d->zbuf = false; - } - - /* special case (depth for wire color) */ - if (v3d->drawtype <= OB_WIRE) { - if (scene->obedit && scene->obedit->type == OB_MESH) { - Mesh *me = scene->obedit->data; - if (me->drawflag & ME_DRAWEIGHT) { - v3d->zbuf = true; - } - } + draw_view_axis(rv3d, &rect); } - if (v3d->zbuf) { - glEnable(GL_DEPTH_TEST); - } + int xoffset = rect.xmin + U.widget_unit; + int yoffset = rect.ymax; - /* ortho grid goes first, does not write to depth buffer and doesn't need depth test so it will override - * objects if done last */ - if (draw_grids) { - /* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */ - rv3d->gridview = ED_view3d_grid_scale(scene, v3d, grid_unit); - - if (!draw_floor) { - ED_region_pixelspace(ar); - *grid_unit = NULL; /* drawgrid need this to detect/affect smallest valid unit... */ - drawgrid(&scene->unit, ar, v3d, grid_unit); - /* XXX make function? replaces persp(1) */ - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(rv3d->winmat); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(rv3d->viewmat); - } - else if (!draw_grids_after) { - drawfloor(scene, v3d, grid_unit, true); + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0 && + (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) + { + if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { + ED_scene_draw_fps(scene, xoffset, &yoffset); } - } - - /* important to do before clipping */ - if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, false, do_camera_frame); - } - - if (rv3d->rflag & RV3D_CLIPPING) { - ED_view3d_clipping_set(rv3d); - } - - /* draw set first */ - if (scene->set) { - const short dflag = DRAW_CONSTCOLOR | DRAW_SCENESET; - Scene *sce_iter; - for (SETLOOPER(scene->set, sce_iter, base)) { - if (v3d->lay & base->lay) { - UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f); - draw_object(bmain, scene, ar, v3d, base, dflag); - - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects_color(bmain, scene, ar, v3d, base, dflag, TH_UNDEFINED); - } - } + else if (U.uiflag & USER_SHOW_VIEWPORTNAME) { + draw_viewport_name(ar, v3d, xoffset, &yoffset); } - /* Transp and X-ray afterdraw stuff for sets is done later */ - } - - - if (draw_offscreen) { - for (base = scene->base.first; base; base = base->next) { - if (v3d->lay & base->lay) { - /* dupli drawing */ - if (base->object->transflag & OB_DUPLI) - draw_dupli_objects(bmain, scene, ar, v3d, base); - - draw_object(bmain, scene, ar, v3d, base, 0); - } + if (U.uiflag & USER_DRAWVIEWINFO) { + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + draw_selected_name(scene, view_layer, ob, xoffset, &yoffset); } - } - else { - unsigned int lay_used = 0; - /* then draw not selected and the duplis, but skip editmode object */ - for (base = scene->base.first; base; base = base->next) { - lay_used |= base->lay; - - if (v3d->lay & base->lay) { +#if 0 /* TODO */ + if (grid_unit) { /* draw below the viewport name */ + char numstr[32] = ""; - /* dupli drawing */ - if (base->object->transflag & OB_DUPLI) { - draw_dupli_objects(bmain, scene, ar, v3d, base); - } - if ((base->flag & SELECT) == 0) { - if (base->object != scene->obedit) - draw_object(bmain, scene, ar, v3d, base, 0); - } + UI_FontThemeColor(BLF_default(), TH_TEXT_HI); + if (v3d->grid != 1.0f) { + BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); } - } - - /* mask out localview */ - v3d->lay_used = lay_used & ((1 << 20) - 1); - /* draw selected and editmode */ - for (base = scene->base.first; base; base = base->next) { - if (v3d->lay & base->lay) { - if (base->object == scene->obedit || (base->flag & SELECT)) { - draw_object(bmain, scene, ar, v3d, base, 0); - } - } + *yoffset -= U.widget_unit; + BLF_draw_default_ascii(xoffset, *yoffset, numstr[0] ? numstr : grid_unit, sizeof(numstr)); } +#endif } - /* perspective floor goes last to use scene depth and avoid writing to depth buffer */ - if (draw_grids_after) { - drawfloor(scene, v3d, grid_unit, false); - } - - /* must be before xray draw which clears the depth buffer */ - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - wmWindowManager *wm = (C != NULL) ? CTX_wm_manager(C) : NULL; - - /* must be before xray draw which clears the depth buffer */ - if (v3d->zbuf) glDisable(GL_DEPTH_TEST); - ED_gpencil_draw_view3d(wm, scene, v3d, ar, true); - if (v3d->zbuf) glEnable(GL_DEPTH_TEST); - } - - /* transp and X-ray afterdraw stuff */ - if (v3d->afterdraw_transp.first) view3d_draw_transp(bmain, scene, ar, v3d); - - /* always do that here to cleanup depth buffers if none needed */ - if (fx) { - do_composite_xray = v3d->zbuf && (v3d->afterdraw_xray.first || v3d->afterdraw_xraytransp.first); - GPU_fx_compositor_setup_XRay_pass(fx, do_composite_xray); - } - - if (v3d->afterdraw_xray.first) view3d_draw_xray(bmain, scene, ar, v3d, &xrayclear); - if (v3d->afterdraw_xraytransp.first) view3d_draw_xraytransp(bmain, scene, ar, v3d, xrayclear); - - if (fx && do_composite_xray) { - GPU_fx_compositor_XRay_resolve(fx); - } - - if (!draw_offscreen) { - ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW); + if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) { + DRW_draw_region_engine_info(xoffset, yoffset); } - if (rv3d->rflag & RV3D_CLIPPING) - ED_view3d_clipping_disable(); - - /* important to do after clipping */ - if (do_bgpic) { - view3d_draw_bgpic_test(scene, ar, v3d, true, do_camera_frame); - } + BLF_batch_draw_end(); +} - if (!draw_offscreen) { - BIF_draw_manipulator(C); - } +static void view3d_draw_view(const bContext *C, ARegion *ar) +{ + ED_view3d_draw_setup_view(CTX_wm_window(C), CTX_data_depsgraph(C), CTX_data_scene(C), ar, CTX_wm_view3d(C), NULL, NULL, NULL); - /* cleanup */ - if (v3d->zbuf) { - v3d->zbuf = false; - glDisable(GL_DEPTH_TEST); - } + /* Only 100% compliant on new spec goes below */ + DRW_draw_view(C); +} - if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - GPU_free_images_old(bmain); +RenderEngineType *ED_view3d_engine_type(Scene *scene, int drawtype) +{ + /* + * Temporary viewport draw modes until we have a proper system. + * all modes are done in the draw manager, except + * cycles material as it is an external render engine. + */ + if (strcmp(scene->r.engine, RE_engine_id_CYCLES) == 0 && drawtype == OB_MATERIAL) { + return RE_engines_find(RE_engine_id_BLENDER_EEVEE); } + return RE_engines_find(scene->r.engine); } -static void view3d_main_region_setup_view( - Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4], const rcti *rect) +void view3d_main_region_draw(const bContext *C, ARegion *ar) { - RegionView3D *rv3d = ar->regiondata; + Main *bmain = CTX_data_main(C); + View3D *v3d = CTX_wm_view3d(C); - ED_view3d_update_viewmat(scene, v3d, ar, viewmat, winmat, rect); + view3d_draw_view(C, ar); - /* set for opengl */ - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(rv3d->winmat); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(rv3d->viewmat); -} + GPU_free_images_old(bmain); + GPU_pass_cache_garbage_collect(); -/** - * Store values from #RegionView3D, set when drawing. - * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example). - * - * Values set by #ED_view3d_update_viewmat should be handled here. - */ -struct RV3DMatrixStore { - float winmat[4][4]; - float viewmat[4][4]; - float viewinv[4][4]; - float persmat[4][4]; - float persinv[4][4]; - float viewcamtexcofac[4]; - float pixsize; -}; - -struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d) -{ - struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__); - copy_m4_m4(rv3dmat->winmat, rv3d->winmat); - copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat); - copy_m4_m4(rv3dmat->persmat, rv3d->persmat); - copy_m4_m4(rv3dmat->persinv, rv3d->persinv); - copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv); - copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac); - rv3dmat->pixsize = rv3d->pixsize; - return (void *)rv3dmat; -} + /* XXX This is in order to draw UI batches with the DRW + * olg context since we now use it for drawing the entire area */ + gpu_batch_presets_reset(); -void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat) -{ - copy_m4_m4(rv3d->winmat, rv3dmat->winmat); - copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat); - copy_m4_m4(rv3d->persmat, rv3dmat->persmat); - copy_m4_m4(rv3d->persinv, rv3dmat->persinv); - copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv); - copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac); - rv3d->pixsize = rv3dmat->pixsize; -} + /* No depth test for drawing action zones afterwards. */ + GPU_depth_test(false); -void ED_view3d_draw_offscreen_init(Main *bmain, Scene *scene, View3D *v3d) -{ - /* shadow buffers, before we setup matrices */ - if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) - gpu_update_lamps_shadows_world(bmain, scene, v3d); + v3d->flag |= V3D_INVALID_BACKBUF; } -/* - * Function to clear the view - */ -static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) -{ - if (scene->world && (v3d->flag2 & V3D_SHOW_WORLD)) { - RegionView3D *rv3d = ar->regiondata; - GPUMaterial *gpumat = GPU_material_world(scene, scene->world); - - /* calculate full shader for background */ - GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0)); - - bool material_not_bound = !GPU_material_bound(gpumat); - - if (material_not_bound) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glColor4f(0.0f, 0.0f, 0.0f, 1.0f); - } +/* -------------------------------------------------------------------- */ - /* Draw world */ - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glBegin(GL_TRIANGLE_STRIP); - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - glVertex3f(-1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, 1.0); - glEnd(); - - if (material_not_bound) { - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } +/** \name Offscreen Drawing + * \{ */ - GPU_material_unbind(gpumat); +static void view3d_stereo3d_setup_offscreen( + Depsgraph *depsgraph, Scene *scene, View3D *v3d, ARegion *ar, + float winmat[4][4], const char *viewname) +{ + /* update the viewport matrices with the new camera */ + if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { + float viewmat[4][4]; + const bool is_left = STREQ(viewname, STEREO_LEFT_NAME); - glDepthFunc(GL_LEQUAL); - glDisable(GL_DEPTH_TEST); + BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); + view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL); } - else { - if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_ALWAYS); - glBegin(GL_QUADS); - UI_ThemeColor(TH_LOW_GRAD); - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - UI_ThemeColor(TH_HIGH_GRAD); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(-1.0, 1.0, 1.0); - glEnd(); - glDepthFunc(GL_LEQUAL); - glDisable(GL_DEPTH_TEST); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - } - else { - UI_ThemeClearColorAlpha(TH_HIGH_GRAD, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } + else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ + float viewmat[4][4]; + Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); + + BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); + view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL); } } -/* ED_view3d_draw_offscreen_init should be called before this to initialize - * stuff like shadow buffers - */ void ED_view3d_draw_offscreen( - Main *bmain, Scene *scene, View3D *v3d, ARegion *ar, int winx, int winy, + Depsgraph *depsgraph, Scene *scene, + int drawtype, + View3D *v3d, ARegion *ar, int winx, int winy, float viewmat[4][4], float winmat[4][4], - bool do_bgpic, bool do_sky, bool is_persp, const char *viewname, - GPUFX *fx, GPUFXSettings *fx_settings, - GPUOffScreen *ofs) + bool do_sky, bool UNUSED(is_persp), const char *viewname, + GPUFXSettings *UNUSED(fx_settings), + GPUOffScreen *ofs, GPUViewport *viewport) { - struct bThemeState theme_state; - int bwinx, bwiny; - rcti brect; - bool do_compositing = false; RegionView3D *rv3d = ar->regiondata; - - glPushMatrix(); + RenderEngineType *engine_type = ED_view3d_engine_type(scene, drawtype); /* set temporary new size */ - bwinx = ar->winx; - bwiny = ar->winy; - brect = ar->winrct; + int bwinx = ar->winx; + int bwiny = ar->winy; + rcti brect = ar->winrct; ar->winx = winx; ar->winy = winy; @@ -3197,6 +1412,7 @@ void ED_view3d_draw_offscreen( ar->winrct.xmax = winx; ar->winrct.ymax = winy; + struct bThemeState theme_state; UI_Theme_Store(&theme_state); UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); @@ -3206,69 +1422,31 @@ void ED_view3d_draw_offscreen( if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { /* free images which can have changed on frame-change * warning! can be slow so only free animated images - campbell */ - GPU_free_images_anim(bmain); + GPU_free_images_anim(G.main); /* XXX :((( */ } - /* setup view matrices before fx or unbinding the offscreen buffers will cause issues */ + GPU_matrix_push_projection(); + GPU_matrix_identity_set(); + GPU_matrix_push(); + GPU_matrix_identity_set(); + if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera) - view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname); + view3d_stereo3d_setup_offscreen(depsgraph, scene, v3d, ar, winmat, viewname); else - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL); - - /* framebuffer fx needed, we need to draw offscreen first */ - if (v3d->fx_settings.fx_flag && fx) { - GPUSSAOSettings *ssao = NULL; - - if (v3d->drawtype < OB_SOLID) { - ssao = v3d->fx_settings.ssao; - v3d->fx_settings.ssao = NULL; - } - - do_compositing = GPU_fx_compositor_initialize_passes(fx, &ar->winrct, NULL, fx_settings); - - if (ssao) - v3d->fx_settings.ssao = ssao; - } - - /* clear opengl buffers */ - if (do_sky) { - view3d_main_region_clear(scene, v3d, ar); - } - else { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } + view3d_main_region_setup_view(depsgraph, scene, v3d, ar, viewmat, winmat, NULL); /* main drawing call */ - view3d_draw_objects(NULL, bmain, scene, v3d, ar, NULL, do_bgpic, true, do_compositing ? fx : NULL); - - /* post process */ - if (do_compositing) { - if (!winmat) - is_persp = rv3d->is_persp; - GPU_fx_do_composite_pass(fx, winmat, is_persp, scene, ofs); - } - - if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - /* draw grease-pencil stuff */ - ED_region_pixelspace(ar); - - - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(NULL, scene, v3d, ar, false); - } - - /* freeing the images again here could be done after the operator runs, leaving for now */ - GPU_free_images_anim(bmain); - } + DRW_draw_render_loop_offscreen( + depsgraph, engine_type, ar, v3d, + do_sky, ofs, viewport); /* restore size */ ar->winx = bwinx; ar->winy = bwiny; ar->winrct = brect; - glPopMatrix(); + GPU_matrix_pop_projection(); + GPU_matrix_pop(); UI_Theme_Restore(&theme_state); @@ -3276,40 +1454,22 @@ void ED_view3d_draw_offscreen( } /** - * Set the correct matrices - */ -void ED_view3d_draw_setup_view( - wmWindow *win, Scene *scene, ARegion *ar, View3D *v3d, float viewmat[4][4], float winmat[4][4], const rcti *rect) -{ - RegionView3D *rv3d = ar->regiondata; - - /* Setup the view matrix. */ - if (view3d_stereo3d_active(win, scene, v3d, rv3d)) { - view3d_stereo3d_setup(scene, v3d, ar, rect); - } - else { - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, rect); - } -} - -/** * Utility func for ED_view3d_draw_offscreen * * \param ofs: Optional off-screen buffer, can be NULL. * (avoids re-creating when doing multiple GL renders). */ ImBuf *ED_view3d_draw_offscreen_imbuf( - Main *bmain, Scene *scene, + Depsgraph *depsgraph, Scene *scene, + int drawtype, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag, unsigned int draw_flags, int alpha_mode, int samples, const char *viewname, /* output vars */ - GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) + GPUOffScreen *ofs, char err_out[256]) { RegionView3D *rv3d = ar->regiondata; - ImBuf *ibuf; const bool draw_sky = (alpha_mode == R_ADDSKY); - const bool draw_background = (draw_flags & V3D_OFSDRAW_USE_BACKGROUND); const bool use_full_sample = (draw_flags & V3D_OFSDRAW_USE_FULL_SAMPLE); /* view state */ @@ -3322,34 +1482,43 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( ofs = NULL; } + GPUFrameBuffer *old_fb = GPU_framebuffer_active_get(); + + if (old_fb) { + GPU_framebuffer_restore(); + } + const bool own_ofs = (ofs == NULL); + DRW_opengl_context_enable(); if (own_ofs) { /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, err_out); + ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, true, false, err_out); if (ofs == NULL) { + DRW_opengl_context_disable(); return NULL; } } - ED_view3d_draw_offscreen_init(bmain, scene, v3d); - GPU_offscreen_bind(ofs, true); /* read in pixels & stamp */ - ibuf = IMB_allocImBuf(sizex, sizey, 32, flag); + ImBuf *ibuf = IMB_allocImBuf(sizex, sizey, 32, flag); /* render 3d view */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { CameraParams params; Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); + const Object *camera_eval = DEG_get_evaluated_object( + depsgraph, + camera); BKE_camera_params_init(¶ms); /* fallback for non camera objects */ params.clipsta = v3d->near; params.clipend = v3d->far; - BKE_camera_params_from_object(¶ms, camera); - BKE_camera_multiview_params(&scene->r, ¶ms, camera, viewname); + BKE_camera_params_from_object(¶ms, camera_eval); + BKE_camera_multiview_params(&scene->r, ¶ms, camera_eval, viewname); BKE_camera_params_compute_viewplane(¶ms, sizex, sizey, scene->r.xasp, scene->r.yasp); BKE_camera_params_compute_matrix(¶ms); @@ -3362,7 +1531,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( rctf viewplane; float clipsta, clipend; - is_ortho = ED_view3d_viewplane_get(v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); + is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, sizex, sizey, &viewplane, &clipsta, &clipend, NULL); if (is_ortho) { orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); } @@ -3374,9 +1543,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( if ((samples && use_full_sample) == 0) { /* Single-pass render, common case */ ED_view3d_draw_offscreen( - bmain, scene, v3d, ar, sizex, sizey, NULL, winmat, - draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); + depsgraph, scene, drawtype, + v3d, ar, sizex, sizey, NULL, winmat, + draw_sky, !is_ortho, viewname, + &fx_settings, ofs, NULL); if (ibuf->rect_float) { GPU_offscreen_read_pixels(ofs, GL_FLOAT, ibuf->rect_float); @@ -3390,28 +1560,22 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( * Use because OpenGL may use a lower quality MSAA, and only over-sample edges. */ static float jit_ofs[32][2]; float winmat_jitter[4][4]; - /* use imbuf as temp storage, before writing into it from accumulation buffer */ - unsigned char *rect_temp = ibuf->rect ? (void *)ibuf->rect : (void *)ibuf->rect_float; - unsigned int *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(int[4]), "accum1"); - unsigned int i; - int j; + float *rect_temp = (ibuf->rect_float) ? ibuf->rect_float : MEM_mallocN(sizex * sizey * sizeof(float[4]), "rect_temp"); + float *accum_buffer = MEM_mallocN(sizex * sizey * sizeof(float[4]), "accum_buffer"); + GPUViewport *viewport = GPU_viewport_create_from_offscreen(ofs); BLI_jitter_init(jit_ofs, samples); /* first sample buffer, also initializes 'rv3d->persmat' */ ED_view3d_draw_offscreen( - bmain, scene, v3d, ar, sizex, sizey, NULL, winmat, - draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); - - i = sizex * sizey * 4; - while (i--) { - accum_buffer[i] = rect_temp[i]; - } + depsgraph, scene, drawtype, + v3d, ar, sizex, sizey, NULL, winmat, + draw_sky, !is_ortho, viewname, + &fx_settings, ofs, viewport); + GPU_offscreen_read_pixels(ofs, GL_FLOAT, accum_buffer); /* skip the first sample */ - for (j = 1; j < samples; j++) { + for (int j = 1; j < samples; j++) { copy_m4_m4(winmat_jitter, winmat); window_translate_m4( winmat_jitter, rv3d->persmat, @@ -3419,29 +1583,40 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( (jit_ofs[j][1] * 2.0f) / sizey); ED_view3d_draw_offscreen( - bmain, scene, v3d, ar, sizex, sizey, NULL, winmat_jitter, - draw_background, draw_sky, !is_ortho, viewname, - fx, &fx_settings, ofs); - GPU_offscreen_read_pixels(ofs, GL_UNSIGNED_BYTE, rect_temp); + depsgraph, scene, drawtype, + v3d, ar, sizex, sizey, NULL, winmat_jitter, + draw_sky, !is_ortho, viewname, + &fx_settings, ofs, viewport); + GPU_offscreen_read_pixels(ofs, GL_FLOAT, rect_temp); - i = sizex * sizey * 4; + unsigned int i = sizex * sizey * 4; while (i--) { accum_buffer[i] += rect_temp[i]; } } + { + /* don't free data owned by 'ofs' */ + GPU_viewport_clear_from_offscreen(viewport); + GPU_viewport_free(viewport); + } + + if (ibuf->rect_float == NULL) { + MEM_freeN(rect_temp); + } + if (ibuf->rect_float) { float *rect_float = ibuf->rect_float; - i = sizex * sizey * 4; + unsigned int i = sizex * sizey * 4; while (i--) { - rect_float[i] = (float)(accum_buffer[i] / samples) * (1.0f / 255.0f); + rect_float[i] = accum_buffer[i] / samples; } } else { unsigned char *rect_ub = (unsigned char *)ibuf->rect; - i = sizex * sizey * 4; + unsigned int i = sizex * sizey * 4; while (i--) { - rect_ub[i] = accum_buffer[i] / samples; + rect_ub[i] = (unsigned char)(255.0f * accum_buffer[i] / samples); } } @@ -3455,6 +1630,12 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( GPU_offscreen_free(ofs); } + DRW_opengl_context_disable(); + + if (old_fb) { + GPU_framebuffer_bind(old_fb); + } + if (ibuf->rect_float && ibuf->rect) IMB_rect_from_float(ibuf); @@ -3470,11 +1651,12 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( * \note used by the sequencer */ ImBuf *ED_view3d_draw_offscreen_imbuf_simple( - Main *bmain, Scene *scene, + Depsgraph *depsgraph, Scene *scene, + int drawtype, Object *camera, int width, int height, - unsigned int flag, unsigned int draw_flags, int drawtype, + unsigned int flag, unsigned int draw_flags, int alpha_mode, int samples, const char *viewname, - GPUFX *fx, GPUOffScreen *ofs, char err_out[256]) + GPUOffScreen *ofs, char err_out[256]) { View3D v3d = {NULL}; ARegion ar = {NULL}; @@ -3486,19 +1668,18 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple( ar.regiontype = RGN_TYPE_WINDOW; v3d.camera = camera; - v3d.lay = scene->lay; - v3d.drawtype = drawtype; + v3d.shading.type = drawtype; v3d.flag2 = V3D_RENDER_OVERRIDE; if (draw_flags & V3D_OFSDRAW_USE_GPENCIL) { - v3d.flag2 |= V3D_SHOW_GPENCIL; + v3d.flag2 |= V3D_SHOW_ANNOTATION; } if (draw_flags & V3D_OFSDRAW_USE_SOLID_TEX) { v3d.flag2 |= V3D_SOLID_TEX; } - if (draw_flags & V3D_OFSDRAW_USE_BACKGROUND) { - v3d.flag2 |= V3D_SHOW_WORLD; - } + + v3d.shading.background_type = V3D_SHADING_BACKGROUND_WORLD; + if (draw_flags & V3D_OFSDRAW_USE_CAMERA_DOF) { if (camera->type == OB_CAMERA) { v3d.fx_settings.dof = &((Camera *)camera->data)->gpu_dof; @@ -3514,11 +1695,13 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple( { CameraParams params; - Object *view_camera = BKE_camera_multiview_render(scene, v3d.camera, viewname); + const Object *view_camera_eval = DEG_get_evaluated_object( + depsgraph, + BKE_camera_multiview_render(scene, v3d.camera, viewname)); BKE_camera_params_init(¶ms); - BKE_camera_params_from_object(¶ms, view_camera); - BKE_camera_multiview_params(&scene->r, ¶ms, view_camera, viewname); + BKE_camera_params_from_object(¶ms, view_camera_eval); + BKE_camera_multiview_params(&scene->r, ¶ms, view_camera_eval, viewname); BKE_camera_params_compute_viewplane(¶ms, width, height, scene->r.xasp, scene->r.yasp); BKE_camera_params_compute_matrix(¶ms); @@ -3532,671 +1715,9 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple( invert_m4_m4(rv3d.persinv, rv3d.viewinv); return ED_view3d_draw_offscreen_imbuf( - bmain, scene, &v3d, &ar, width, height, flag, draw_flags, - alpha_mode, samples, viewname, fx, ofs, err_out); -} - - -/** - * \note The info that this uses is updated in #ED_refresh_viewport_fps, - * which currently gets called during #SCREEN_OT_animation_step. - */ -void ED_scene_draw_fps(Scene *scene, const rcti *rect) -{ - ScreenFrameRateInfo *fpsi = scene->fps_info; - float fps; - char printable[16]; - int i, tot; - - if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime) - return; - - printable[0] = '\0'; - -#if 0 - /* this is too simple, better do an average */ - fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)) -#else - fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)); - - for (i = 0, tot = 0, fps = 0.0f; i < REDRAW_FRAME_AVERAGE; i++) { - if (fpsi->redrawtimes_fps[i]) { - fps += fpsi->redrawtimes_fps[i]; - tot++; - } - } - if (tot) { - fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE; - - //fpsi->redrawtime_index++; - //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE) - // fpsi->redrawtime = 0; - - fps = fps / tot; - } -#endif - - /* is this more than half a frame behind? */ - if (fps + 0.5f < (float)(FPS)) { - UI_ThemeColor(TH_REDALERT); - BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps); - } - else { - UI_ThemeColor(TH_TEXT_HI); - BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f)); - } - -#ifdef WITH_INTERNATIONAL - BLF_draw_default(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); -#else - BLF_draw_default_ascii(rect->xmin + U.widget_unit, rect->ymax - U.widget_unit, 0.0f, printable, sizeof(printable)); -#endif -} - -static bool view3d_main_region_do_render_draw(const Scene *scene) -{ - RenderEngineType *type = RE_engines_find(scene->r.engine); - - return (type && type->view_update && type->view_draw); -} - -bool ED_view3d_calc_render_border( - const Scene *scene, const View3D *v3d, const ARegion *ar, - rcti *rect) -{ - RegionView3D *rv3d = ar->regiondata; - rctf viewborder; - bool use_border; - - /* test if there is a 3d view rendering */ - if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene)) - return false; - - /* test if there is a border render */ - if (rv3d->persp == RV3D_CAMOB) - use_border = (scene->r.mode & R_BORDER) != 0; - else - use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0; - - if (!use_border) - return false; - - /* compute border */ - if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &viewborder, false); - - rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); - rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); - rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder); - rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder); - } - else { - rect->xmin = v3d->render_border.xmin * ar->winx; - rect->xmax = v3d->render_border.xmax * ar->winx; - rect->ymin = v3d->render_border.ymin * ar->winy; - rect->ymax = v3d->render_border.ymax * ar->winy; - } - - BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin); - BLI_rcti_isect(&ar->winrct, rect, rect); - - return true; + depsgraph, scene, drawtype, + &v3d, &ar, width, height, flag, + draw_flags, alpha_mode, samples, viewname, ofs, err_out); } -static bool view3d_main_region_draw_engine(const bContext *C, Scene *scene, - ARegion *ar, View3D *v3d, - bool clip_border, const rcti *border_rect) -{ - RegionView3D *rv3d = ar->regiondata; - RenderEngineType *type; - GLint scissor[4]; - - /* create render engine */ - if (!rv3d->render_engine) { - RenderEngine *engine; - - type = RE_engines_find(scene->r.engine); - - if (!(type->view_update && type->view_draw)) - return false; - - engine = RE_engine_create_ex(type, true); - - engine->tile_x = scene->r.tilex; - engine->tile_y = scene->r.tiley; - - type->view_update(engine, C); - - rv3d->render_engine = engine; - } - - /* setup view matrices */ - view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL, NULL); - - /* background draw */ - ED_region_pixelspace(ar); - - if (clip_border) { - /* for border draw, we only need to clear a subset of the 3d view */ - if (border_rect->xmax > border_rect->xmin && border_rect->ymax > border_rect->ymin) { - glGetIntegerv(GL_SCISSOR_BOX, scissor); - glScissor(border_rect->xmin, border_rect->ymin, - BLI_rcti_size_x(border_rect), BLI_rcti_size_y(border_rect)); - } - else { - return false; - } - } - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if (v3d->flag & V3D_DISPBGPICS) - view3d_draw_bgpic_test(scene, ar, v3d, false, true); - else - fdrawcheckerboard(0, 0, ar->winx, ar->winy); - - /* render result draw */ - type = rv3d->render_engine->type; - type->view_draw(rv3d->render_engine, C); - - if (v3d->flag & V3D_DISPBGPICS) - view3d_draw_bgpic_test(scene, ar, v3d, true, true); - - if (clip_border) { - /* restore scissor as it was before */ - glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); - } - - return true; -} - -static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border) -{ - float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f}; - - if (!rv3d->render_engine || !rv3d->render_engine->text[0]) - return; - - if (render_border) { - /* draw darkened background color. no alpha because border render does - * partial redraw and will not redraw the region behind this info bar */ - float alpha = 1.0f - fill_color[3]; - Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); - - if (camera) { - if (camera->flag & CAM_SHOWPASSEPARTOUT) { - alpha *= (1.0f - camera->passepartalpha); - } - } - - UI_GetThemeColor3fv(TH_HIGH_GRAD, fill_color); - mul_v3_fl(fill_color, alpha); - fill_color[3] = 1.0f; - } - - ED_region_info_draw(ar, rv3d->render_engine->text, fill_color, true); -} - -static bool view3d_stereo3d_active(wmWindow *win, Scene *scene, View3D *v3d, RegionView3D *rv3d) -{ - if ((scene->r.scemode & R_MULTIVIEW) == 0) { - return false; - } - - if ((v3d->camera == NULL) || (v3d->camera->type != OB_CAMERA) || rv3d->persp != RV3D_CAMOB) { - return false; - } - - switch (v3d->stereo3d_camera) { - case STEREO_MONO_ID: - return false; - break; - case STEREO_3D_ID: - /* win will be NULL when calling this from the selection or draw loop. */ - if ((win == NULL) || (WM_stereo3d_enabled(win, true) == false)) { - return false; - } - if (((scene->r.views_format & SCE_VIEWS_FORMAT_MULTIVIEW) != 0) && - !BKE_scene_multiview_is_stereo3d(&scene->r)) - { - return false; - } - break; - /* We always need the stereo calculation for left and right cameras. */ - case STEREO_LEFT_ID: - case STEREO_RIGHT_ID: - default: - break; - } - return true; -} - -/* setup the view and win matrices for the multiview cameras - * - * unlike view3d_stereo3d_setup_offscreen, when view3d_stereo3d_setup is called - * we have no winmatrix (i.e., projection matrix) defined at that time. - * Since the camera and the camera shift are needed for the winmat calculation - * we do a small hack to replace it temporarily so we don't need to change the - * view3d)main_region_setup_view() code to account for that. - */ -static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar, const rcti *rect) -{ - bool is_left; - const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; - const char *viewname; - - /* show only left or right camera */ - if (v3d->stereo3d_camera != STEREO_3D_ID) - v3d->multiview_eye = v3d->stereo3d_camera; - - is_left = v3d->multiview_eye == STEREO_LEFT_ID; - viewname = names[is_left ? STEREO_LEFT_ID : STEREO_RIGHT_ID]; - - /* update the viewport matrices with the new camera */ - if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { - Camera *data; - float viewmat[4][4]; - float shiftx; - - data = (Camera *)v3d->camera->data; - shiftx = data->shiftx; - - BLI_thread_lock(LOCK_VIEW3D); - data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname); - - BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect); - - data->shiftx = shiftx; - BLI_thread_unlock(LOCK_VIEW3D); - } - else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ - float viewmat[4][4]; - Object *view_ob = v3d->camera; - Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - - BLI_thread_lock(LOCK_VIEW3D); - v3d->camera = camera; - - BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL, rect); - - v3d->camera = view_ob; - BLI_thread_unlock(LOCK_VIEW3D); - } -} - -static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion *ar, - float winmat[4][4], const char *viewname) -{ - /* update the viewport matrices with the new camera */ - if (scene->r.views_format == SCE_VIEWS_FORMAT_STEREO_3D) { - float viewmat[4][4]; - const bool is_left = STREQ(viewname, STEREO_LEFT_NAME); - - BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL); - } - else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ - float viewmat[4][4]; - Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); - - BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat, NULL); - } -} - -#ifdef WITH_GAMEENGINE -static void update_lods(Scene *scene, float camera_pos[3]) -{ - Scene *sce_iter; - Base *base; - Object *ob; - - for (SETLOOPER(scene, sce_iter, base)) { - ob = base->object; - BKE_object_lod_update(ob, camera_pos); - } -} -#endif - -static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, View3D *v3d, - ARegion *ar, const char **grid_unit) -{ - Main *bmain = CTX_data_main(C); - wmWindow *win = CTX_wm_window(C); - RegionView3D *rv3d = ar->regiondata; - unsigned int lay_used = v3d->lay_used; - - /* post processing */ - bool do_compositing = false; - - /* shadow buffers, before we setup matrices */ - if (draw_glsl_material(scene, NULL, v3d, v3d->drawtype)) - gpu_update_lamps_shadows_world(bmain, scene, v3d); - - /* reset default OpenGL lights if needed (i.e. after preferences have been altered) */ - if (rv3d->rflag & RV3D_GPULIGHT_UPDATE) { - rv3d->rflag &= ~RV3D_GPULIGHT_UPDATE; - GPU_default_lights(); - } - - /* Setup the view matrix. */ - ED_view3d_draw_setup_view(CTX_wm_window(C), scene, ar, v3d, NULL, NULL, NULL); - - rv3d->rflag &= ~RV3D_IS_GAME_ENGINE; -#ifdef WITH_GAMEENGINE - if (STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)) { - rv3d->rflag |= RV3D_IS_GAME_ENGINE; - - /* Make sure LoDs are up to date */ - update_lods(scene, rv3d->viewinv[3]); - } -#endif - - /* framebuffer fx needed, we need to draw offscreen first */ - if (v3d->fx_settings.fx_flag && v3d->drawtype >= OB_SOLID) { - GPUFXSettings fx_settings; - BKE_screen_gpu_fx_validate(&v3d->fx_settings); - fx_settings = v3d->fx_settings; - if (!rv3d->compositor) - rv3d->compositor = GPU_fx_compositor_create(); - - if (rv3d->persp == RV3D_CAMOB && v3d->camera) - BKE_camera_to_gpu_dof(v3d->camera, &fx_settings); - else { - fx_settings.dof = NULL; - } - - do_compositing = GPU_fx_compositor_initialize_passes(rv3d->compositor, &ar->winrct, &ar->drawrct, &fx_settings); - } - - /* clear the background */ - view3d_main_region_clear(scene, v3d, ar); - - /* enables anti-aliasing for 3D view drawing */ - if (win->multisamples != USER_MULTISAMPLE_NONE) { - glEnable(GL_MULTISAMPLE); - } - - /* main drawing call */ - view3d_draw_objects(C, bmain, scene, v3d, ar, grid_unit, true, false, do_compositing ? rv3d->compositor : NULL); - - /* post process */ - if (do_compositing) { - GPU_fx_do_composite_pass(rv3d->compositor, rv3d->winmat, rv3d->is_persp, scene, NULL); - } - - /* Disable back anti-aliasing */ - if (win->multisamples != USER_MULTISAMPLE_NONE) { - glDisable(GL_MULTISAMPLE); - } - - if (v3d->lay_used != lay_used) { /* happens when loading old files or loading with UI load */ - /* find header and force tag redraw */ - ScrArea *sa = CTX_wm_area(C); - ARegion *ar_header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); - ED_region_tag_redraw(ar_header); /* can be NULL */ - } - - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - BDR_drawSketch(C); - } - -#ifdef WITH_INPUT_NDOF - if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((rv3d->viewlock & RV3D_LOCKED) == 0) && (rv3d->persp != RV3D_CAMOB)) - /* TODO: draw something else (but not this) during fly mode */ - draw_rotation_guide(rv3d); -#endif -} - -static bool is_cursor_visible(Scene *scene) -{ - if (U.app_flag & USER_APP_VIEW3D_HIDE_CURSOR) { - return false; - } - - Object *ob = OBACT; - - /* don't draw cursor in paint modes, but with a few exceptions */ - if (ob && ob->mode & OB_MODE_ALL_PAINT) { - /* exception: object is in weight paint and has deforming armature in pose mode */ - if (ob->mode & OB_MODE_WEIGHT_PAINT) { - if (BKE_object_pose_armature_get(ob) != NULL) { - return true; - } - } - /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */ - else if (ob->mode & OB_MODE_TEXTURE_PAINT) { - const Paint *p = BKE_paint_get_active(scene); - - if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) { - if ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) == 0) { - return true; - } - } - } - - /* no exception met? then don't draw cursor! */ - return false; - } - - return true; -} - -static void view3d_main_region_draw_info(const bContext *C, Scene *scene, - ARegion *ar, View3D *v3d, - const char *grid_unit, bool render_border) -{ - wmWindowManager *wm = CTX_wm_manager(C); - RegionView3D *rv3d = ar->regiondata; - rcti rect; - - /* local coordinate visible rect inside region, to accomodate overlapping ui */ - ED_region_visible_rect(ar, &rect); - - if (rv3d->persp == RV3D_CAMOB) { - drawviewborder(scene, ar, v3d); - } - else if (v3d->flag2 & V3D_RENDER_BORDER) { - glLineWidth(1.0f); - setlinestyle(3); - cpack(0x4040FF); - - sdrawbox(v3d->render_border.xmin * ar->winx, v3d->render_border.ymin * ar->winy, - v3d->render_border.xmax * ar->winx, v3d->render_border.ymax * ar->winy); - - setlinestyle(0); - } - - if (v3d->flag2 & V3D_SHOW_GPENCIL) { - /* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */ - ED_gpencil_draw_view3d(wm, scene, v3d, ar, false); - } - - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - Object *ob; - - /* 3d cursor */ - if (is_cursor_visible(scene)) { - drawcursor(scene, ar, v3d); - } - - if (U.uiflag & USER_SHOW_ROTVIEWICON) - draw_view_axis(rv3d, &rect); - else - draw_view_icon(rv3d, &rect); - - ob = OBACT; - if (U.uiflag & USER_DRAWVIEWINFO) - draw_selected_name(scene, ob, &rect); - } - - if (rv3d->render_engine) { - view3d_main_region_draw_engine_info(v3d, rv3d, ar, render_border); - return; - } - - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { - if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { - ED_scene_draw_fps(scene, &rect); - } - else if (U.uiflag & USER_SHOW_VIEWPORTNAME) { - draw_viewport_name(ar, v3d, &rect); - } - - if (grid_unit) { /* draw below the viewport name */ - char numstr[32] = ""; - - UI_ThemeColor(TH_TEXT_HI); - if (v3d->grid != 1.0f) { - BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); - } - - BLF_draw_default_ascii(rect.xmin + U.widget_unit, - rect.ymax - (USER_SHOW_VIEWPORTNAME ? 2 * U.widget_unit : U.widget_unit), 0.0f, - numstr[0] ? numstr : grid_unit, sizeof(numstr)); - } - } -} - -void view3d_main_region_draw(const bContext *C, ARegion *ar) -{ - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - const char *grid_unit = NULL; - rcti border_rect; - bool render_border, clip_border; - - /* if we only redraw render border area, skip opengl draw and also - * don't do scissor because it's already set */ - render_border = ED_view3d_calc_render_border(scene, v3d, ar, &border_rect); - clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect)); - - /* draw viewport using opengl */ - if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) { - view3d_main_region_draw_objects(C, scene, v3d, ar, &grid_unit); - -#ifdef DEBUG_DRAW - bl_debug_draw(); -#endif - if (G.debug & G_DEBUG_SIMDATA) - draw_sim_debug_data(scene, v3d, ar); - - ED_region_pixelspace(ar); - } - - /* draw viewport using external renderer */ - if (v3d->drawtype == OB_RENDER) - view3d_main_region_draw_engine(C, scene, ar, v3d, clip_border, &border_rect); - - view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border); - - v3d->flag |= V3D_INVALID_BACKBUF; - - BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_transp)); - BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xray)); - BLI_assert(BLI_listbase_is_empty(&v3d->afterdraw_xraytransp)); -} - -#ifdef DEBUG_DRAW -/* debug drawing */ -#define _DEBUG_DRAW_QUAD_TOT 1024 -#define _DEBUG_DRAW_EDGE_TOT 1024 -static float _bl_debug_draw_quads[_DEBUG_DRAW_QUAD_TOT][4][3]; -static int _bl_debug_draw_quads_tot = 0; -static float _bl_debug_draw_edges[_DEBUG_DRAW_QUAD_TOT][2][3]; -static int _bl_debug_draw_edges_tot = 0; -static unsigned int _bl_debug_draw_quads_color[_DEBUG_DRAW_QUAD_TOT]; -static unsigned int _bl_debug_draw_edges_color[_DEBUG_DRAW_EDGE_TOT]; -static unsigned int _bl_debug_draw_color; - -void bl_debug_draw_quad_clear(void) -{ - _bl_debug_draw_quads_tot = 0; - _bl_debug_draw_edges_tot = 0; - _bl_debug_draw_color = 0x00FF0000; -} -void bl_debug_color_set(const unsigned int color) -{ - _bl_debug_draw_color = color; -} -void bl_debug_draw_quad_add(const float v0[3], const float v1[3], const float v2[3], const float v3[3]) -{ - if (_bl_debug_draw_quads_tot >= _DEBUG_DRAW_QUAD_TOT) { - printf("%s: max quad count hit %d!", __func__, _bl_debug_draw_quads_tot); - } - else { - float *pt = &_bl_debug_draw_quads[_bl_debug_draw_quads_tot][0][0]; - copy_v3_v3(pt, v0); pt += 3; - copy_v3_v3(pt, v1); pt += 3; - copy_v3_v3(pt, v2); pt += 3; - copy_v3_v3(pt, v3); pt += 3; - _bl_debug_draw_quads_color[_bl_debug_draw_quads_tot] = _bl_debug_draw_color; - _bl_debug_draw_quads_tot++; - } -} -void bl_debug_draw_edge_add(const float v0[3], const float v1[3]) -{ - if (_bl_debug_draw_quads_tot >= _DEBUG_DRAW_EDGE_TOT) { - printf("%s: max edge count hit %d!", __func__, _bl_debug_draw_edges_tot); - } - else { - float *pt = &_bl_debug_draw_edges[_bl_debug_draw_edges_tot][0][0]; - copy_v3_v3(pt, v0); pt += 3; - copy_v3_v3(pt, v1); pt += 3; - _bl_debug_draw_edges_color[_bl_debug_draw_edges_tot] = _bl_debug_draw_color; - _bl_debug_draw_edges_tot++; - } -} -static void bl_debug_draw(void) -{ - unsigned int color; - if (_bl_debug_draw_quads_tot) { - int i; - color = _bl_debug_draw_quads_color[0]; - cpack(color); - for (i = 0; i < _bl_debug_draw_quads_tot; i ++) { - if (_bl_debug_draw_quads_color[i] != color) { - color = _bl_debug_draw_quads_color[i]; - cpack(color); - } - glBegin(GL_LINE_LOOP); - glVertex3fv(_bl_debug_draw_quads[i][0]); - glVertex3fv(_bl_debug_draw_quads[i][1]); - glVertex3fv(_bl_debug_draw_quads[i][2]); - glVertex3fv(_bl_debug_draw_quads[i][3]); - glEnd(); - } - } - if (_bl_debug_draw_edges_tot) { - int i; - color = _bl_debug_draw_edges_color[0]; - cpack(color); - glBegin(GL_LINES); - for (i = 0; i < _bl_debug_draw_edges_tot; i ++) { - if (_bl_debug_draw_edges_color[i] != color) { - color = _bl_debug_draw_edges_color[i]; - cpack(color); - } - glVertex3fv(_bl_debug_draw_edges[i][0]); - glVertex3fv(_bl_debug_draw_edges[i][1]); - } - glEnd(); - color = _bl_debug_draw_edges_color[0]; - cpack(color); - glPointSize(4.0); - glBegin(GL_POINTS); - for (i = 0; i < _bl_debug_draw_edges_tot; i ++) { - if (_bl_debug_draw_edges_color[i] != color) { - color = _bl_debug_draw_edges_color[i]; - cpack(color); - } - glVertex3fv(_bl_debug_draw_edges[i][0]); - glVertex3fv(_bl_debug_draw_edges[i][1]); - } - glEnd(); - } -} -#endif +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c new file mode 100644 index 00000000000..f51a46cd95f --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -0,0 +1,1075 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_draw_legacy.c + * \ingroup spview3d + */ + +#include <string.h> +#include <stdio.h> +#include <math.h> + +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_collection_types.h" +#include "DNA_customdata_types.h" +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_scene_types.h" +#include "DNA_world_types.h" +#include "DNA_brush_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_jitter_2d.h" +#include "BLI_utildefines.h" +#include "BLI_endian_switch.h" +#include "BLI_threads.h" + +#include "BKE_anim.h" +#include "BKE_camera.h" +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_image.h" +#include "BKE_key.h" +#include "BKE_layer.h" +#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_global.h" +#include "BKE_paint.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_unit.h" +#include "BKE_movieclip.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" +#include "IMB_colormanagement.h" + +#include "BIF_glutil.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "BLF_api.h" +#include "BLT_translation.h" + +#include "ED_armature.h" +#include "ED_keyframing.h" +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_screen_types.h" +#include "ED_transform.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_resources.h" + +#include "GPU_draw.h" +#include "GPU_framebuffer.h" +#include "GPU_material.h" +#include "GPU_extensions.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_select.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + +#include "RE_engine.h" + +#include "DRW_engine.h" + +#include "view3d_intern.h" /* own include */ + +/* ********* custom clipping *********** */ + +void ED_view3d_clipping_set(RegionView3D *rv3d) +{ + double plane[4]; + const unsigned int tot = (rv3d->viewlock & RV3D_BOXCLIP) ? 4 : 6; + + for (unsigned a = 0; a < tot; a++) { + copy_v4db_v4fl(plane, rv3d->clip[a]); + glClipPlane(GL_CLIP_PLANE0 + a, plane); + glEnable(GL_CLIP_PLANE0 + a); + } +} + +/* use these to temp disable/enable clipping when 'rv3d->rflag & RV3D_CLIPPING' is set */ +void ED_view3d_clipping_disable(void) +{ + for (unsigned a = 0; a < 6; a++) { + glDisable(GL_CLIP_PLANE0 + a); + } +} +void ED_view3d_clipping_enable(void) +{ + for (unsigned a = 0; a < 6; a++) { + glEnable(GL_CLIP_PLANE0 + a); + } +} + +static bool view3d_clipping_test(const float co[3], const float clip[6][4]) +{ + if (plane_point_side_v3(clip[0], co) > 0.0f) + if (plane_point_side_v3(clip[1], co) > 0.0f) + if (plane_point_side_v3(clip[2], co) > 0.0f) + if (plane_point_side_v3(clip[3], co) > 0.0f) + return false; + + return true; +} + +/* for 'local' ED_view3d_clipping_local must run first + * then all comparisons can be done in localspace */ +bool ED_view3d_clipping_test(const RegionView3D *rv3d, const float co[3], const bool is_local) +{ + return view3d_clipping_test(co, is_local ? rv3d->clip_local : rv3d->clip); +} + +/* *********************** backdraw for selection *************** */ + +static void backdrawview3d( + struct Depsgraph *depsgraph, Scene *scene, + ARegion *ar, View3D *v3d, + Object *obact, Object *obedit, + short select_mode) +{ + RegionView3D *rv3d = ar->regiondata; + Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id); + Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact); + + BLI_assert(ar->regiontype == RGN_TYPE_WINDOW); + + if (obact_eval && (obact_eval->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT) || + BKE_paint_select_face_test(obact_eval))) + { + /* do nothing */ + } + /* texture paint mode sampling */ + else if (obact_eval && (obact_eval->mode & OB_MODE_TEXTURE_PAINT) && + (v3d->shading.type > OB_WIRE)) + { + /* do nothing */ + } + else if ((obact_eval && (obact_eval->mode & OB_MODE_PARTICLE_EDIT)) && + V3D_IS_ZBUF(v3d)) + { + /* do nothing */ + } + else if ((obedit && (obedit->mode & OB_MODE_EDIT)) && + V3D_IS_ZBUF(v3d)) + { + /* do nothing */ + } + else { + v3d->flag &= ~V3D_INVALID_BACKBUF; + return; + } + + if (!(v3d->flag & V3D_INVALID_BACKBUF)) + return; + +#if 0 + if (test) { + if (qtest()) { + addafterqueue(ar->win, BACKBUFDRAW, 1); + return; + } + } +#endif + +#if 0 /* v3d->zbuf deprecated */ + if (v3d->shading.type > OB_WIRE) v3d->zbuf = true; +#endif + + /* dithering and AA break color coding, so disable */ + glDisable(GL_DITHER); + + if (false) { + /* for multisample we use an offscreen FBO. multisample drawing can fail + * with color coded selection drawing, and reading back depths from such + * a buffer can also cause a few seconds freeze on OS X / NVidia. + * + * NOTE: code is no longer used now, but offscreen drawing is likely + * what we will always want to do for the new viewport. */ + int w = BLI_rcti_size_x(&ar->winrct); + int h = BLI_rcti_size_y(&ar->winrct); + char error[256]; + + if (rv3d->gpuoffscreen) { + if (GPU_offscreen_width(rv3d->gpuoffscreen) != w || + GPU_offscreen_height(rv3d->gpuoffscreen) != h) + { + GPU_offscreen_free(rv3d->gpuoffscreen); + rv3d->gpuoffscreen = NULL; + } + } + + if (!rv3d->gpuoffscreen) { + rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, true, false, error); + + if (!rv3d->gpuoffscreen) + fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); + } + } + + if (rv3d->gpuoffscreen) + GPU_offscreen_bind(rv3d->gpuoffscreen, true); + else + GPU_scissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); + + GPU_clear_color(0.0, 0.0, 0.0, 0.0); + GPU_depth_test(true); + GPU_clear(GPU_COLOR_BIT | GPU_DEPTH_BIT); + + if (rv3d->rflag & RV3D_CLIPPING) + ED_view3d_clipping_set(rv3d); + + G.f |= G_BACKBUFSEL; + + if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) { + draw_object_backbufsel(depsgraph, scene_eval, v3d, rv3d, obact_eval, select_mode); + } + + if (rv3d->gpuoffscreen) + GPU_offscreen_unbind(rv3d->gpuoffscreen, true); + + v3d->flag &= ~V3D_INVALID_BACKBUF; + + G.f &= ~G_BACKBUFSEL; + GPU_depth_test(false); + glEnable(GL_DITHER); + + if (rv3d->rflag & RV3D_CLIPPING) + ED_view3d_clipping_disable(); +} + +void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) +{ + RegionView3D *rv3d = ar->regiondata; + + if (rv3d->gpuoffscreen) { + GPU_offscreen_bind(rv3d->gpuoffscreen, true); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glReadPixels(x, y, w, h, format, type, data); + GPU_offscreen_unbind(rv3d->gpuoffscreen, true); + } + else { + glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); + } +} + +/* XXX depth reading exception, for code not using gpu offscreen */ +static void view3d_opengl_read_Z_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data) +{ + glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data); +} + +void ED_view3d_backbuf_validate_with_select_mode(ViewContext *vc, short select_mode) +{ + if (vc->v3d->flag & V3D_INVALID_BACKBUF) { + backdrawview3d(vc->depsgraph, vc->scene, vc->ar, vc->v3d, vc->obact, vc->obedit, select_mode); + } +} + +void ED_view3d_backbuf_validate(ViewContext *vc) +{ + ED_view3d_backbuf_validate_with_select_mode(vc, -1); +} + +/** + * allow for small values [0.5 - 2.5], + * and large values, FLT_MAX by clamping by the area size + */ +int ED_view3d_backbuf_sample_size_clamp(ARegion *ar, const float dist) +{ + return (int)min_ff(ceilf(dist), (float)max_ii(ar->winx, ar->winx)); +} + +/* samples a single pixel (copied from vpaint) */ +unsigned int ED_view3d_backbuf_sample( + ViewContext *vc, int x, int y) +{ + if (x >= vc->ar->winx || y >= vc->ar->winy) { + return 0; + } + + ED_view3d_backbuf_validate(vc); + + unsigned int col; + view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col); + glReadBuffer(GL_BACK); + + if (ENDIAN_ORDER == B_ENDIAN) { + BLI_endian_switch_uint32(&col); + } + + return GPU_select_to_index(col); +} + +/* reads full rect, converts indices */ +ImBuf *ED_view3d_backbuf_read( + ViewContext *vc, int xmin, int ymin, int xmax, int ymax) +{ + /* clip */ + const rcti clip = { + max_ii(xmin, 0), min_ii(xmax, vc->ar->winx - 1), + max_ii(ymin, 0), min_ii(ymax, vc->ar->winy - 1)}; + const int size_clip[2] = { + BLI_rcti_size_x(&clip) + 1, + BLI_rcti_size_y(&clip) + 1}; + + if (UNLIKELY((clip.xmin > clip.xmax) || + (clip.ymin > clip.ymax))) + { + return NULL; + } + + ImBuf *ibuf_clip = IMB_allocImBuf(size_clip[0], size_clip[1], 32, IB_rect); + + ED_view3d_backbuf_validate(vc); + + view3d_opengl_read_pixels(vc->ar, clip.xmin, clip.ymin, size_clip[0], size_clip[1], GL_RGBA, GL_UNSIGNED_BYTE, ibuf_clip->rect); + + glReadBuffer(GL_BACK); + + if (ENDIAN_ORDER == B_ENDIAN) { + IMB_convert_rgba_to_abgr(ibuf_clip); + } + + GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); + + if ((clip.xmin == xmin) && + (clip.xmax == xmax) && + (clip.ymin == ymin) && + (clip.ymax == ymax)) + { + return ibuf_clip; + } + else { + /* put clipped result into a non-clipped buffer */ + const int size[2] = { + (xmax - xmin + 1), + (ymax - ymin + 1)}; + + ImBuf *ibuf_full = IMB_allocImBuf(size[0], size[1], 32, IB_rect); + + IMB_rectcpy( + ibuf_full, ibuf_clip, + clip.xmin - xmin, clip.ymin - ymin, + 0, 0, + size_clip[0], size_clip[1]); + IMB_freeImBuf(ibuf_clip); + return ibuf_full; + } +} + +/* smart function to sample a rect spiralling outside, nice for backbuf selection */ +unsigned int ED_view3d_backbuf_sample_rect( + ViewContext *vc, const int mval[2], int size, + unsigned int min, unsigned int max, float *r_dist) +{ + int dirvec[4][2]; + + const int amount = (size - 1) / 2; + + const int minx = mval[0] - (amount + 1); + const int miny = mval[1] - (amount + 1); + ImBuf *buf = ED_view3d_backbuf_read(vc, minx, miny, minx + size - 1, miny + size - 1); + if (!buf) return 0; + + unsigned index = 0; + int rc = 0; + + dirvec[0][0] = 1; dirvec[0][1] = 0; + dirvec[1][0] = 0; dirvec[1][1] = -size; + dirvec[2][0] = -1; dirvec[2][1] = 0; + dirvec[3][0] = 0; dirvec[3][1] = size; + + const unsigned *bufmin = buf->rect; + const unsigned *tbuf = buf->rect; + const unsigned *bufmax = buf->rect + size * size; + tbuf += amount * size + amount; + + for (int nr = 1; nr <= size; nr++) { + for (int a = 0; a < 2; a++) { + for (int b = 0; b < nr; b++) { + if (*tbuf && *tbuf >= min && *tbuf < max) { + /* we got a hit */ + + /* get x,y pixel coords from the offset + * (manhatten distance in keeping with other screen-based selection) */ + *r_dist = (float)( + abs(((int)(tbuf - buf->rect) % size) - (size / 2)) + + abs(((int)(tbuf - buf->rect) / size) - (size / 2))); + + /* indices start at 1 here */ + index = (*tbuf - min) + 1; + goto exit; + } + + tbuf += (dirvec[rc][0] + dirvec[rc][1]); + + if (tbuf < bufmin || tbuf >= bufmax) { + goto exit; + } + } + rc++; + rc &= 3; + } + } + +exit: + IMB_freeImBuf(buf); + return index; +} + + +/* ************************************************************* */ + +static void view3d_stereo_bgpic_setup(Scene *scene, View3D *v3d, Image *ima, ImageUser *iuser) +{ + if (BKE_image_is_stereo(ima)) { + iuser->flag |= IMA_SHOW_STEREO; + + if ((scene->r.scemode & R_MULTIVIEW) == 0) { + iuser->multiview_eye = STEREO_LEFT_ID; + } + else if (v3d->stereo3d_camera != STEREO_3D_ID) { + /* show only left or right camera */ + iuser->multiview_eye = v3d->stereo3d_camera; + } + + BKE_image_multiview_index(ima, iuser); + } + else { + iuser->flag &= ~IMA_SHOW_STEREO; + } +} + +static void view3d_draw_bgpic(Scene *scene, Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, + const bool do_foreground, const bool do_camera_frame) +{ + RegionView3D *rv3d = ar->regiondata; + int fg_flag = do_foreground ? CAM_BGIMG_FLAG_FOREGROUND : 0; + if (v3d->camera == NULL || v3d->camera->type != OB_CAMERA) { + return; + } + Camera *cam = v3d->camera->data; + + for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) { + bgpic->iuser.scene = scene; /* Needed for render results. */ + + if ((bgpic->flag & CAM_BGIMG_FLAG_FOREGROUND) != fg_flag) + continue; + + { + float image_aspect[2]; + float x1, y1, x2, y2, centx, centy; + + void *lock; + + Image *ima = NULL; + + /* disable individual images */ + if ((bgpic->flag & CAM_BGIMG_FLAG_DISABLED)) + continue; + + ImBuf *ibuf = NULL; + ImBuf *freeibuf = NULL; + ImBuf *releaseibuf = NULL; + if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) { + ima = bgpic->ima; + if (ima == NULL) + continue; + BKE_image_user_frame_calc(&bgpic->iuser, (int)DEG_get_ctime(depsgraph)); + if (ima->source == IMA_SRC_SEQUENCE && !(bgpic->iuser.flag & IMA_USER_FRAME_IN_RANGE)) { + ibuf = NULL; /* frame is out of range, dont show */ + } + else { + view3d_stereo_bgpic_setup(scene, v3d, ima, &bgpic->iuser); + ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock); + releaseibuf = ibuf; + } + + image_aspect[0] = ima->aspx; + image_aspect[1] = ima->aspy; + } + else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) { + /* TODO: skip drawing when out of frame range (as image sequences do above) */ + MovieClip *clip = NULL; + + if (bgpic->flag & CAM_BGIMG_FLAG_CAMERACLIP) { + if (scene->camera) + clip = BKE_object_movieclip_get(scene, scene->camera, true); + } + else { + clip = bgpic->clip; + } + + if (clip == NULL) + continue; + + BKE_movieclip_user_set_frame(&bgpic->cuser, (int)DEG_get_ctime(depsgraph)); + ibuf = BKE_movieclip_get_ibuf(clip, &bgpic->cuser); + + image_aspect[0] = clip->aspx; + image_aspect[1] = clip->aspy; + + /* working with ibuf from image and clip has got different workflow now. + * ibuf acquired from clip is referenced by cache system and should + * be dereferenced after usage. */ + freeibuf = ibuf; + } + else { + /* perhaps when loading future files... */ + BLI_assert(0); + copy_v2_fl(image_aspect, 1.0f); + } + + if (ibuf == NULL) + continue; + + if ((ibuf->rect == NULL && ibuf->rect_float == NULL) || ibuf->channels != 4) { /* invalid image format */ + if (freeibuf) + IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, lock); + + continue; + } + + if (ibuf->rect == NULL) + IMB_rect_from_float(ibuf); + + BLI_assert(rv3d->persp == RV3D_CAMOB); + { + if (do_camera_frame) { + rctf vb; + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false); + x1 = vb.xmin; + y1 = vb.ymin; + x2 = vb.xmax; + y2 = vb.ymax; + } + else { + x1 = ar->winrct.xmin; + y1 = ar->winrct.ymin; + x2 = ar->winrct.xmax; + y2 = ar->winrct.ymax; + } + + /* apply offset last - camera offset is different to offset in blender units */ + /* so this has some sane way of working - this matches camera's shift _exactly_ */ + { + const float max_dim = max_ff(x2 - x1, y2 - y1); + const float xof_scale = bgpic->offset[0] * max_dim; + const float yof_scale = bgpic->offset[1] * max_dim; + + x1 += xof_scale; + y1 += yof_scale; + x2 += xof_scale; + y2 += yof_scale; + } + + centx = (x1 + x2) * 0.5f; + centy = (y1 + y2) * 0.5f; + + /* aspect correction */ + if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) { + /* apply aspect from clip */ + const float w_src = ibuf->x * image_aspect[0]; + const float h_src = ibuf->y * image_aspect[1]; + + /* destination aspect is already applied from the camera frame */ + const float w_dst = x1 - x2; + const float h_dst = y1 - y2; + + const float asp_src = w_src / h_src; + const float asp_dst = w_dst / h_dst; + + if (fabsf(asp_src - asp_dst) >= FLT_EPSILON) { + if ((asp_src > asp_dst) == ((bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) != 0)) { + /* fit X */ + const float div = asp_src / asp_dst; + x1 = ((x1 - centx) * div) + centx; + x2 = ((x2 - centx) * div) + centx; + } + else { + /* fit Y */ + const float div = asp_dst / asp_src; + y1 = ((y1 - centy) * div) + centy; + y2 = ((y2 - centy) * div) + centy; + } + } + } + } + + /* complete clip? */ + rctf clip_rect; + BLI_rctf_init(&clip_rect, x1, x2, y1, y2); + if (bgpic->rotation) { + BLI_rctf_rotate_expand(&clip_rect, &clip_rect, bgpic->rotation); + } + + if (clip_rect.xmax < 0 || clip_rect.ymax < 0 || clip_rect.xmin > ar->winx || clip_rect.ymin > ar->winy) { + if (freeibuf) + IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, lock); + + continue; + } + + float zoomx = (x2 - x1) / ibuf->x; + float zoomy = (y2 - y1) / ibuf->y; + + /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */ + if (zoomx < 1.0f || zoomy < 1.0f) { + float tzoom = min_ff(zoomx, zoomy); + int mip = 0; + + if ((ibuf->userflags & IB_MIPMAP_INVALID) != 0) { + IMB_remakemipmap(ibuf, 0); + ibuf->userflags &= ~IB_MIPMAP_INVALID; + } + else if (ibuf->mipmap[0] == NULL) + IMB_makemipmap(ibuf, 0); + + while (tzoom < 1.0f && mip < 8 && ibuf->mipmap[mip]) { + tzoom *= 2.0f; + zoomx *= 2.0f; + zoomy *= 2.0f; + mip++; + } + if (mip > 0) + ibuf = ibuf->mipmap[mip - 1]; + } + + GPU_depth_test(!do_foreground); + glDepthMask(GL_FALSE); + + GPU_blend(true); + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + GPU_matrix_push_projection(); + GPU_matrix_push(); + ED_region_pixelspace(ar); + + GPU_matrix_translate_2f(centx, centy); + GPU_matrix_scale_1f(bgpic->scale); + GPU_matrix_rotate_2d(RAD2DEGF(-bgpic->rotation)); + + if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_X) { + zoomx *= -1.0f; + x1 = x2; + } + if (bgpic->flag & CAM_BGIMG_FLAG_FLIP_Y) { + zoomy *= -1.0f; + y1 = y2; + } + + float col[4] = {1.0f, 1.0f, 1.0f, bgpic->alpha}; + IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); + immDrawPixelsTex(&state, x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect, + zoomx, zoomy, col); + + GPU_matrix_pop_projection(); + GPU_matrix_pop(); + + GPU_blend(false); + + glDepthMask(GL_TRUE); + GPU_depth_test(true); + + if (freeibuf) + IMB_freeImBuf(freeibuf); + if (releaseibuf) + BKE_image_release_ibuf(ima, releaseibuf, lock); + } + } +} + +void ED_view3d_draw_bgpic_test( + Scene *scene, Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, + const bool do_foreground, const bool do_camera_frame) +{ + RegionView3D *rv3d = ar->regiondata; + + if ((rv3d->persp == RV3D_CAMOB) && v3d->camera && (v3d->camera->type == OB_CAMERA)) { + Camera *cam = v3d->camera->data; + if ((cam->flag & CAM_SHOW_BG_IMAGE) == 0) { + return; + } + } + else { + return; + } + + /* disabled - mango request, since footage /w only render is quite useful + * and this option is easy to disable all background images at once */ +#if 0 + if (v3d->flag2 & V3D_RENDER_OVERRIDE) + return; +#endif + + if ((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) { + if (rv3d->persp == RV3D_CAMOB) { + view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame); + } + } + else { + view3d_draw_bgpic(scene, depsgraph, ar, v3d, do_foreground, do_camera_frame); + } +} + +/* *********************** */ + +/* XXX warning, not using gpu offscreen here */ +void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect) +{ + /* clamp rect by region */ + rcti r = { + .xmin = 0, + .xmax = ar->winx - 1, + .ymin = 0, + .ymax = ar->winy - 1 + }; + + /* Constrain rect to depth bounds */ + BLI_rcti_isect(&r, rect, rect); + + /* assign values to compare with the ViewDepths */ + int x = rect->xmin; + int y = rect->ymin; + + int w = BLI_rcti_size_x(rect); + int h = BLI_rcti_size_y(rect); + + if (w <= 0 || h <= 0) { + if (d->depths) + MEM_freeN(d->depths); + d->depths = NULL; + + d->damaged = false; + } + else if (d->w != w || + d->h != h || + d->x != x || + d->y != y || + d->depths == NULL + ) + { + d->x = x; + d->y = y; + d->w = w; + d->h = h; + + if (d->depths) + MEM_freeN(d->depths); + + d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths Subset"); + + d->damaged = true; + } + + if (d->damaged) { + /* XXX using special function here, it doesn't use the gpu offscreen system */ + view3d_opengl_read_Z_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); + glGetDoublev(GL_DEPTH_RANGE, d->depth_range); + d->damaged = false; + } +} + +/* note, with nouveau drivers the glReadPixels() is very slow. [#24339] */ +void ED_view3d_depth_update(ARegion *ar) +{ + RegionView3D *rv3d = ar->regiondata; + + /* Create storage for, and, if necessary, copy depth buffer */ + if (!rv3d->depths) rv3d->depths = MEM_callocN(sizeof(ViewDepths), "ViewDepths"); + if (rv3d->depths) { + ViewDepths *d = rv3d->depths; + if (d->w != ar->winx || + d->h != ar->winy || + !d->depths) + { + d->w = ar->winx; + d->h = ar->winy; + if (d->depths) + MEM_freeN(d->depths); + d->depths = MEM_mallocN(sizeof(float) * d->w * d->h, "View depths"); + d->damaged = true; + } + + if (d->damaged) { + view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths); + glGetDoublev(GL_DEPTH_RANGE, d->depth_range); + + d->damaged = false; + } + } +} + +/* utility function to find the closest Z value, use for autodepth */ +float view3d_depth_near(ViewDepths *d) +{ + /* convert to float for comparisons */ + const float near = (float)d->depth_range[0]; + const float far_real = (float)d->depth_range[1]; + float far = far_real; + + const float *depths = d->depths; + float depth = FLT_MAX; + int i = (int)d->w * (int)d->h; /* cast to avoid short overflow */ + + /* far is both the starting 'far' value + * and the closest value found. */ + while (i--) { + depth = *depths++; + if ((depth < far) && (depth > near)) { + far = depth; + } + } + + return far == far_real ? FLT_MAX : far; +} + +void ED_view3d_draw_depth_gpencil( + Depsgraph *depsgraph, Scene *scene, ARegion *ar, View3D *v3d) +{ + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); + + /* Setup view matrix. */ + ED_view3d_draw_setup_view(NULL, depsgraph, scene, ar, v3d, NULL, NULL, NULL); + + GPU_clear(GPU_DEPTH_BIT); + + GPU_depth_test(true); + + ED_gpencil_draw_view3d(NULL, scene, view_layer, depsgraph, v3d, ar, true); + + GPU_depth_test(false); +} + +/* *********************** customdata **************** */ + +CustomDataMask ED_view3d_datamask(const Scene *UNUSED(scene), const View3D *v3d) +{ + CustomDataMask mask = 0; + const int drawtype = view3d_effective_drawtype(v3d); + + if (ELEM(drawtype, OB_TEXTURE, OB_MATERIAL) || + ((drawtype == OB_SOLID) && (v3d->flag2 & V3D_SOLID_TEX))) + { + mask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL; + + if (drawtype == OB_MATERIAL) + mask |= CD_MASK_ORCO; + } + + return mask; +} + +/* goes over all modes and view3d settings */ +CustomDataMask ED_view3d_screen_datamask(const Scene *scene, const bScreen *screen) +{ + CustomDataMask mask = CD_MASK_BAREMESH; + + /* check if we need tfaces & mcols due to view mode */ + for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + if (sa->spacetype == SPACE_VIEW3D) { + mask |= ED_view3d_datamask(scene, sa->spacedata.first); + } + } + + return mask; +} + +/** + * Store values from #RegionView3D, set when drawing. + * This is needed when we draw with to a viewport using a different matrix (offscreen drawing for example). + * + * Values set by #ED_view3d_update_viewmat should be handled here. + */ +struct RV3DMatrixStore { + float winmat[4][4]; + float viewmat[4][4]; + float viewinv[4][4]; + float persmat[4][4]; + float persinv[4][4]; + float viewcamtexcofac[4]; + float pixsize; +}; + +struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d) +{ + struct RV3DMatrixStore *rv3dmat = MEM_mallocN(sizeof(*rv3dmat), __func__); + copy_m4_m4(rv3dmat->winmat, rv3d->winmat); + copy_m4_m4(rv3dmat->viewmat, rv3d->viewmat); + copy_m4_m4(rv3dmat->persmat, rv3d->persmat); + copy_m4_m4(rv3dmat->persinv, rv3d->persinv); + copy_m4_m4(rv3dmat->viewinv, rv3d->viewinv); + copy_v4_v4(rv3dmat->viewcamtexcofac, rv3d->viewcamtexcofac); + rv3dmat->pixsize = rv3d->pixsize; + return (void *)rv3dmat; +} + +void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat_pt) +{ + struct RV3DMatrixStore *rv3dmat = rv3dmat_pt; + copy_m4_m4(rv3d->winmat, rv3dmat->winmat); + copy_m4_m4(rv3d->viewmat, rv3dmat->viewmat); + copy_m4_m4(rv3d->persmat, rv3dmat->persmat); + copy_m4_m4(rv3d->persinv, rv3dmat->persinv); + copy_m4_m4(rv3d->viewinv, rv3dmat->viewinv); + copy_v4_v4(rv3d->viewcamtexcofac, rv3dmat->viewcamtexcofac); + rv3d->pixsize = rv3dmat->pixsize; +} + +/** + * \note The info that this uses is updated in #ED_refresh_viewport_fps, + * which currently gets called during #SCREEN_OT_animation_step. + */ +void ED_scene_draw_fps(Scene *scene, int xoffset, int *yoffset) +{ + ScreenFrameRateInfo *fpsi = scene->fps_info; + char printable[16]; + + if (!fpsi || !fpsi->lredrawtime || !fpsi->redrawtime) + return; + + printable[0] = '\0'; + +#if 0 + /* this is too simple, better do an average */ + fps = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)) +#else + fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / (fpsi->lredrawtime - fpsi->redrawtime)); + + float fps = 0.0f; + int tot = 0; + for (int i = 0; i < REDRAW_FRAME_AVERAGE; i++) { + if (fpsi->redrawtimes_fps[i]) { + fps += fpsi->redrawtimes_fps[i]; + tot++; + } + } + if (tot) { + fpsi->redrawtime_index = (fpsi->redrawtime_index + 1) % REDRAW_FRAME_AVERAGE; + + //fpsi->redrawtime_index++; + //if (fpsi->redrawtime >= REDRAW_FRAME_AVERAGE) + // fpsi->redrawtime = 0; + + fps = fps / tot; + } +#endif + + const int font_id = BLF_default(); + + /* is this more than half a frame behind? */ + if (fps + 0.5f < (float)(FPS)) { + UI_FontThemeColor(font_id, TH_REDALERT); + BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps); + } + else { + UI_FontThemeColor(font_id, TH_TEXT_HI); + BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f)); + } + + BLF_enable(font_id, BLF_SHADOW); + BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); + BLF_shadow_offset(font_id, 1, -1); + + *yoffset -= U.widget_unit; + +#ifdef WITH_INTERNATIONAL + BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable)); +#else + BLF_draw_default_ascii(xoffset, *yoffset, 0.0f, printable, sizeof(printable)); +#endif + + BLF_disable(font_id, BLF_SHADOW); +} + +static bool view3d_main_region_do_render_draw(const Scene *scene) +{ + RenderEngineType *type = RE_engines_find(scene->r.engine); + return (type && type->view_update && type->view_draw); +} + +bool ED_view3d_calc_render_border(const Scene *scene, Depsgraph *depsgraph, View3D *v3d, ARegion *ar, rcti *rect) +{ + RegionView3D *rv3d = ar->regiondata; + bool use_border; + + /* test if there is a 3d view rendering */ + if (v3d->shading.type != OB_RENDER || !view3d_main_region_do_render_draw(scene)) + return false; + + /* test if there is a border render */ + if (rv3d->persp == RV3D_CAMOB) + use_border = (scene->r.mode & R_BORDER) != 0; + else + use_border = (v3d->flag2 & V3D_RENDER_BORDER) != 0; + + if (!use_border) + return false; + + /* compute border */ + if (rv3d->persp == RV3D_CAMOB) { + rctf viewborder; + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewborder, false); + + rect->xmin = viewborder.xmin + scene->r.border.xmin * BLI_rctf_size_x(&viewborder); + rect->ymin = viewborder.ymin + scene->r.border.ymin * BLI_rctf_size_y(&viewborder); + rect->xmax = viewborder.xmin + scene->r.border.xmax * BLI_rctf_size_x(&viewborder); + rect->ymax = viewborder.ymin + scene->r.border.ymax * BLI_rctf_size_y(&viewborder); + } + else { + rect->xmin = v3d->render_border.xmin * ar->winx; + rect->xmax = v3d->render_border.xmax * ar->winx; + rect->ymin = v3d->render_border.ymin * ar->winy; + rect->ymax = v3d->render_border.ymax * ar->winy; + } + + BLI_rcti_translate(rect, ar->winrct.xmin, ar->winrct.ymin); + BLI_rcti_isect(&ar->winrct, rect, rect); + + return true; +} diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 23c445ebc3e..d073c62dfcc 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -36,6 +36,7 @@ #include <float.h> #include "DNA_armature_types.h" +#include "DNA_camera_types.h" #include "DNA_curve_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -47,9 +48,13 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_camera.h" #include "BKE_context.h" #include "BKE_font.h" +#include "BKE_gpencil.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_object.h" @@ -57,14 +62,13 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" -#include "BKE_action.h" - -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "RNA_access.h" #include "RNA_define.h" @@ -74,8 +78,8 @@ #include "ED_screen.h" #include "ED_transform.h" #include "ED_mesh.h" -#include "ED_gpencil.h" #include "ED_view3d.h" +#include "ED_transform_snap_object_context.h" #include "UI_resources.h" @@ -133,6 +137,7 @@ typedef struct ViewOpsData { ARegion *ar; View3D *v3d; RegionView3D *rv3d; + Depsgraph *depsgraph; /** Needed for continuous zoom. */ wmTimer *timer; @@ -218,6 +223,7 @@ static void viewops_data_alloc(bContext *C, wmOperator *op) /* store data */ op->customdata = vod; vod->bmain = CTX_data_main(C); + vod->depsgraph = CTX_data_depsgraph(C); vod->scene = CTX_data_scene(C); vod->sa = CTX_wm_area(C); vod->ar = CTX_wm_region(C); @@ -245,8 +251,12 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) static float lastofs[3] = {0, 0, 0}; bool is_set = false; + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); - Object *ob_act = OBACT; + ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); + View3D *v3d = CTX_wm_view3d(C); + Object *ob_act_eval = OBACT(view_layer_eval); + Object *ob_act = DEG_get_original_object(ob_act_eval); if (ob_act && (ob_act->mode & OB_MODE_ALL_PAINT) && /* with weight-paint + pose-mode, fall through to using calculateTransformCenter */ @@ -258,16 +268,16 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) */ if (ob_act->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { float stroke[3]; - BKE_paint_stroke_get_average(scene, ob_act, stroke); + BKE_paint_stroke_get_average(scene, ob_act_eval, stroke); copy_v3_v3(lastofs, stroke); } else { - copy_v3_v3(lastofs, ob_act->obmat[3]); + copy_v3_v3(lastofs, ob_act_eval->obmat[3]); } is_set = true; } else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) { - Curve *cu = ob_act->data; + Curve *cu = ob_act_eval->data; EditFont *ef = cu->editfont; int i; @@ -277,33 +287,32 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) } mul_v2_fl(lastofs, 1.0f / 4.0f); - mul_m4_v3(ob_act->obmat, lastofs); + mul_m4_v3(ob_act_eval->obmat, lastofs); is_set = true; } else if (ob_act == NULL || ob_act->mode == OB_MODE_OBJECT) { /* object mode use boundbox centers */ - View3D *v3d = CTX_wm_view3d(C); - Base *base; + Base *base_eval; unsigned int tot = 0; float select_center[3]; zero_v3(select_center); - for (base = FIRSTBASE; base; base = base->next) { - if (TESTBASE(v3d, base)) { + for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) { + if (TESTBASE(v3d, base_eval)) { /* use the boundbox if we can */ - Object *ob = base->object; + Object *ob_eval = base_eval->object; - if (ob->bb && !(ob->bb->flag & BOUNDBOX_DIRTY)) { + if (ob_eval->bb && !(ob_eval->bb->flag & BOUNDBOX_DIRTY)) { float cent[3]; - BKE_boundbox_calc_center_aabb(ob->bb, cent); + BKE_boundbox_calc_center_aabb(ob_eval->bb, cent); - mul_m4_v3(ob->obmat, cent); + mul_m4_v3(ob_eval->obmat, cent); add_v3_v3(select_center, cent); } else { - add_v3_v3(select_center, ob->obmat[3]); + add_v3_v3(select_center, ob_eval->obmat[3]); } tot++; } @@ -366,6 +375,7 @@ static void viewops_data_create( bContext *C, wmOperator *op, const wmEvent *event, enum eViewOpsFlag viewops_flag) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); ViewOpsData *vod = op->customdata; RegionView3D *rv3d = vod->rv3d; @@ -383,7 +393,7 @@ static void viewops_data_create( negate_v3_v3(fallback_depth_pt, rv3d->ofs); vod->use_dyn_ofs = ED_view3d_autodist( - vod->bmain, vod->scene, vod->ar, vod->v3d, + depsgraph, vod->ar, vod->v3d, event->mval, vod->dyn_ofs, true, fallback_depth_pt); } else { @@ -391,7 +401,7 @@ static void viewops_data_create( } if (viewops_flag & VIEWOPS_FLAG_PERSP_ENSURE) { - if (ED_view3d_persp_ensure(vod->v3d, vod->ar)) { + if (ED_view3d_persp_ensure(depsgraph, vod->v3d, vod->ar)) { /* If we're switching from camera view to the perspective one, * need to tag viewport update, so camera vuew and borders * are properly updated. @@ -402,7 +412,7 @@ static void viewops_data_create( /* set the view from the camera, if view locking is enabled. * we may want to make this optional but for now its needed always */ - ED_view3d_camera_lock_init(vod->v3d, vod->rv3d); + ED_view3d_camera_lock_init(depsgraph, vod->v3d, vod->rv3d); vod->init.dist = rv3d->dist; vod->init.camzoom = rv3d->camzoom; @@ -506,8 +516,9 @@ static void viewops_data_create( static void viewops_data_free(bContext *C, wmOperator *op) { ARegion *ar; +#if 0 Paint *p = BKE_paint_get_active_from_context(C); - +#endif if (op->customdata) { ViewOpsData *vod = op->customdata; ar = vod->ar; @@ -523,7 +534,9 @@ static void viewops_data_free(bContext *C, wmOperator *op) ar = CTX_wm_region(C); } +#if 0 if (p && (p->flags & PAINT_FAST_NAVIGATE)) +#endif ED_region_tag_redraw(ar); } @@ -571,13 +584,6 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf) keymap = WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items); - /* items for modal map */ - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); - - WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE); - WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE); - /* disabled mode switching for now, can re-implement better, later on */ #if 0 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM); @@ -802,7 +808,7 @@ static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2]) vod->prev.event_xy[0] = event_xy[0]; vod->prev.event_xy[1] = event_xy[1]; - ED_view3d_camera_lock_sync(vod->v3d, rv3d); + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, rv3d); ED_region_tag_redraw(vod->ar); } @@ -1100,7 +1106,6 @@ static void view3d_ndof_pan_zoom( static void view3d_ndof_orbit( const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, - /* optional, can be NULL*/ ViewOpsData *vod, const bool apply_dyn_ofs) { View3D *v3d = sa->spacedata.first; @@ -1110,7 +1115,7 @@ static void view3d_ndof_orbit( BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0); - ED_view3d_persp_ensure(v3d, ar); + ED_view3d_persp_ensure(vod->depsgraph, v3d, ar); rv3d->view = RV3D_VIEW_USER; @@ -1299,6 +1304,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } else { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); ViewOpsData *vod; View3D *v3d; RegionView3D *rv3d; @@ -1319,7 +1325,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* off by default, until changed later this function */ rv3d->rot_angle = 0.0f; - ED_view3d_camera_lock_init_ex(v3d, rv3d, false); + ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); if (ndof->progress != P_FINISHING) { const bool has_rotation = NDOF_HAS_ROTATE; @@ -1336,7 +1342,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) } } - ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); ED_region_tag_redraw(vod->ar); @@ -1367,6 +1373,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev return OPERATOR_CANCELLED; } else { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); ViewOpsData *vod; View3D *v3d; RegionView3D *rv3d; @@ -1388,7 +1395,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev /* off by default, until changed later this function */ rv3d->rot_angle = 0.0f; - ED_view3d_camera_lock_init_ex(v3d, rv3d, false); + ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); if (ndof->progress == P_FINISHING) { /* pass */ @@ -1431,13 +1438,13 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev ED_view3d_distance_set(rv3d, 0.0f); if (has_rotation) { - view3d_ndof_orbit(ndof, vod->sa, vod->ar, NULL, false); + view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod, false); } ED_view3d_distance_set(rv3d, dist_backup); } - ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); ED_region_tag_redraw(vod->ar); @@ -1471,6 +1478,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e return OPERATOR_CANCELLED; } else { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); const wmNDOFMotionData *ndof = event->customdata; @@ -1484,7 +1492,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e if (!(has_translate || has_zoom)) return OPERATOR_CANCELLED; - ED_view3d_camera_lock_init_ex(v3d, rv3d, false); + ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false); if (ndof->progress != P_FINISHING) { ScrArea *sa = CTX_wm_area(C); @@ -1495,7 +1503,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e } } - ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); ED_region_tag_redraw(CTX_wm_region(C)); @@ -1540,7 +1548,7 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, const wmEvent *event) void VIEW3D_OT_ndof_all(struct wmOperatorType *ot) { /* identifiers */ - ot->name = "NDOF Move View"; + ot->name = "NDOF Pan View"; ot->description = "Pan and rotate the view with the 3D mouse"; ot->idname = "VIEW3D_OT_ndof_all"; @@ -1628,7 +1636,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y) vod->prev.event_xy[0] = x; vod->prev.event_xy[1] = y; - ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); ED_region_tag_redraw(vod->ar); } @@ -1730,7 +1738,7 @@ void VIEW3D_OT_move(wmOperatorType *ot) { /* identifiers */ - ot->name = "Move View"; + ot->name = "Pan View"; ot->description = "Move the view"; ot->idname = "VIEW3D_OT_move"; @@ -1773,10 +1781,6 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) keymap = WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items); - /* items for modal map */ - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); - /* disabled mode switching for now, can re-implement better, later on */ #if 0 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); @@ -1792,7 +1796,7 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf) * \param zoom_xy: Optionally zoom to window location (coords compatible w/ #wmEvent.x, y). Use when not NULL. */ static void view_zoom_to_window_xy_camera( - Scene *scene, View3D *v3d, + Scene *scene, Depsgraph *depsgraph, View3D *v3d, ARegion *ar, float dfac, const int zoom_xy[2]) { RegionView3D *rv3d = ar->regiondata; @@ -1810,13 +1814,13 @@ static void view_zoom_to_window_xy_camera( float pt_dst[2]; float delta_px[2]; - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_old, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_old, false); BLI_rctf_translate(&camera_frame_old, ar->winrct.xmin, ar->winrct.ymin); rv3d->camzoom = camzoom_new; CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &camera_frame_new, false); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &camera_frame_new, false); BLI_rctf_translate(&camera_frame_new, ar->winrct.xmin, ar->winrct.ymin); BLI_rctf_transform_pt_v(&camera_frame_new, &camera_frame_old, pt_dst, pt_src); @@ -1989,7 +1993,7 @@ static void viewzoom_apply_camera( /* calculate inverted, then invert again (needed because of camera zoom scaling) */ zfac = 1.0f / zfac; view_zoom_to_window_xy_camera( - vod->scene, vod->v3d, + vod->scene, vod->depsgraph, vod->v3d, vod->ar, zfac, zoom_to_pos ? vod->prev.event_xy : NULL); } @@ -2027,7 +2031,7 @@ static void viewzoom_apply_3d( view3d_boxview_sync(vod->sa, vod->ar); } - ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); ED_region_tag_redraw(vod->ar); } @@ -2109,6 +2113,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) static int viewzoom_exec(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); View3D *v3d; RegionView3D *rv3d; @@ -2151,7 +2156,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) const float step = 1.2f; /* this min and max is also in viewmove() */ if (use_cam_zoom) { - view_zoom_to_window_xy_camera(scene, v3d, ar, step, zoom_xy); + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy); } else { if (rv3d->dist < dist_range[1]) { @@ -2162,7 +2167,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) else { const float step = 1.0f / 1.2f; if (use_cam_zoom) { - view_zoom_to_window_xy_camera(scene, v3d, ar, step, zoom_xy); + view_zoom_to_window_xy_camera(scene, depsgraph, v3d, ar, step, zoom_xy); } else { if (rv3d->dist > dist_range[0]) { @@ -2177,7 +2182,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op) ED_view3d_depth_tag_update(rv3d); - ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true); ED_region_tag_redraw(ar); @@ -2307,10 +2312,6 @@ void viewdolly_modal_keymap(wmKeyConfig *keyconf) keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items); - /* items for modal map */ - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM); - /* disabled mode switching for now, can re-implement better, later on */ #if 0 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE); @@ -2371,7 +2372,7 @@ static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_ view3d_boxview_sync(vod->sa, vod->ar); } - ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); ED_region_tag_redraw(vod->ar); } @@ -2472,7 +2473,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op) ED_view3d_depth_tag_update(rv3d); - ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_sync(CTX_data_depsgraph(C), v3d, rv3d); ED_region_tag_redraw(ar); @@ -2506,7 +2507,8 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (vod->rv3d->persp != RV3D_PERSP) { if (vod->rv3d->persp == RV3D_CAMOB) { /* ignore rv3d->lpersp because dolly only makes sense in perspective mode */ - ED_view3d_persp_switch_from_camera(vod->v3d, vod->rv3d, RV3D_PERSP); + const Depsgraph *depsgraph = CTX_data_depsgraph(C); + ED_view3d_persp_switch_from_camera(depsgraph, vod->v3d, vod->rv3d, RV3D_PERSP); } else { vod->rv3d->persp = RV3D_PERSP; @@ -2640,7 +2642,7 @@ static void view3d_from_minmax( } if (ok_dist) { - new_dist = ED_view3d_radius_to_dist(v3d, ar, persp, true, (size / 2) * VIEW3D_MARGIN); + new_dist = ED_view3d_radius_to_dist(v3d, ar, CTX_data_depsgraph(C), persp, true, (size / 2) * VIEW3D_MARGIN); if (rv3d->is_persp) { /* don't zoom closer than the near clipping plane */ new_dist = max_ff(new_dist, v3d->near * 1.5f); @@ -2695,8 +2697,9 @@ static int view3d_all_exec(bContext *C, wmOperator *op) ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); - Base *base; - float *curs; + const Depsgraph *depsgraph = CTX_data_depsgraph(C); + ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); + Base *base_eval; const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions"); const bool skip_camera = (ED_view3d_camera_lock_check(v3d, ar->regiondata) || /* any one of the regions may be locked */ @@ -2709,26 +2712,33 @@ static int view3d_all_exec(bContext *C, wmOperator *op) if (center) { /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */ - curs = ED_view3d_cursor3d_get(scene, v3d); + View3DCursor *cursor = &scene->cursor; zero_v3(min); zero_v3(max); - zero_v3(curs); + zero_v3(cursor->location); + unit_qt(cursor->rotation); } else { INIT_MINMAX(min, max); } - for (base = scene->base.first; base; base = base->next) { - if (BASE_VISIBLE(v3d, base)) { + for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) { + if (BASE_VISIBLE(v3d, base_eval)) { changed = true; - if (skip_camera && base->object == v3d->camera) { + Object *ob = DEG_get_original_object(base_eval->object); + if (skip_camera && ob == v3d->camera) { continue; } - BKE_object_minmax(base->object, min, max, false); + BKE_object_minmax(base_eval->object, min, max, false); } } + + if (center) { + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + } + if (!changed) { ED_region_tag_redraw(ar); /* TODO - should this be cancel? @@ -2782,13 +2792,16 @@ void VIEW3D_OT_view_all(wmOperatorType *ot) /* like a localview without local!, was centerview() in 2.4x */ static int viewselected_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); bGPdata *gpd = CTX_data_gpencil_data(C); - const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); - Object *ob = OBACT; + const bool is_gp_edit = GPENCIL_ANY_MODE(gpd); + const bool is_face_map = ((is_gp_edit == false) && ar->gizmo_map && + WM_gizmomap_is_any_selected(ar->gizmo_map)); + Object *ob_eval = OBACT(view_layer_eval); Object *obedit = CTX_data_edit_object(C); float min[3], max[3]; bool ok = false, ok_dist = true; @@ -2799,71 +2812,91 @@ static int viewselected_exec(bContext *C, wmOperator *op) const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); INIT_MINMAX(min, max); - - if (is_gp_edit) { - ob = NULL; + if (is_face_map) { + ob_eval = NULL; } - if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) { + if (ob_eval && (ob_eval->mode & OB_MODE_WEIGHT_PAINT)) { /* hard-coded exception, we look for the one selected armature */ /* this is weak code this way, we should make a generic active/selection callback interface once... */ - Base *base; - for (base = scene->base.first; base; base = base->next) { - if (TESTBASELIB(v3d, base)) { - if (base->object->type == OB_ARMATURE) - if (base->object->mode & OB_MODE_POSE) + Base *base_eval; + for (base_eval = view_layer_eval->object_bases.first; base_eval; base_eval = base_eval->next) { + if (TESTBASELIB(v3d, base_eval)) { + if (base_eval->object->type == OB_ARMATURE) + if (base_eval->object->mode & OB_MODE_POSE) break; } } - if (base) - ob = base->object; + if (base_eval) + ob_eval = base_eval->object; } - if (is_gp_edit) { CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { /* we're only interested in selected points here... */ if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) { - if (ED_gpencil_stroke_minmax(gps, true, min, max)) { - ok = true; - } + ok |= BKE_gpencil_stroke_minmax(gps, true, min, max); } } CTX_DATA_END; + + if ((ob_eval) && (ok)) { + add_v3_v3(min, ob_eval->obmat[3]); + add_v3_v3(max, ob_eval->obmat[3]); + } + } + else if (ob_eval && (ob_eval->type == OB_GPENCIL)) { + ok |= BKE_gpencil_data_minmax(ob_eval, gpd, min, max); + /* if no strokes, use object location */ + if ((ob_eval) && (!ok)) { + copy_v3_v3(min, ob_eval->obmat[3]); + copy_v3_v3(max, ob_eval->obmat[3]); + ok = true; + } + } + else if (is_face_map) { + ok = WM_gizmomap_minmax(ar->gizmo_map, true, true, min, max); } else if (obedit) { - ok = ED_view3d_minmax_verts(obedit, min, max); /* only selected */ + /* only selected */ + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, obedit->type, obedit->mode, ob_eval_iter) { + ok |= ED_view3d_minmax_verts(ob_eval_iter, min, max); + } + FOREACH_OBJECT_IN_MODE_END; } - else if (ob && (ob->mode & OB_MODE_POSE)) { - ok = BKE_pose_minmax(ob, min, max, true, true); + else if (ob_eval && (ob_eval->mode & OB_MODE_POSE)) { + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer_eval, v3d, ob_eval->type, ob_eval->mode, ob_eval_iter) { + ok |= BKE_pose_minmax(ob_eval_iter, min, max, true, true); + } + FOREACH_OBJECT_IN_MODE_END; } - else if (BKE_paint_select_face_test(ob)) { - ok = paintface_minmax(ob, min, max); + else if (BKE_paint_select_face_test(ob_eval)) { + ok = paintface_minmax(ob_eval, min, max); } - else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { - ok = PE_minmax(bmain, scene, min, max); + else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) { + ok = PE_minmax(scene, view_layer_eval, min, max); } - else if (ob && - (ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) + else if (ob_eval && + (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { - BKE_paint_stroke_get_average(scene, ob, min); + BKE_paint_stroke_get_average(scene, ob_eval, min); copy_v3_v3(max, min); ok = true; ok_dist = 0; /* don't zoom */ } else { - Base *base; - for (base = FIRSTBASE; base; base = base->next) { - if (TESTBASE(v3d, base)) { + Base *base_eval; + for (base_eval = FIRSTBASE(view_layer_eval); base_eval; base_eval = base_eval->next) { + if (TESTBASE(v3d, base_eval)) { - if (skip_camera && base->object == v3d->camera) { + if (skip_camera && base_eval->object == v3d->camera) { continue; } /* account for duplis */ - if (BKE_object_minmax_dupli(bmain, scene, base->object, min, max, false) == 0) - BKE_object_minmax(base->object, min, max, false); /* use if duplis not found */ + if (BKE_object_minmax_dupli(depsgraph, scene, base_eval->object, min, max, false) == 0) + BKE_object_minmax(base_eval->object, min, max, false); /* use if duplis not found */ ok = 1; } @@ -2952,14 +2985,14 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) Object *obact = CTX_data_active_object(C); if (v3d) { - ED_view3d_lock_clear(v3d); v3d->ob_centre = obact; /* can be NULL */ if (obact && obact->type == OB_ARMATURE) { if (obact->mode & OB_MODE_POSE) { - bPoseChannel *pcham_act = BKE_pose_channel_active(obact); + Object *obact_eval = DEG_get_evaluated_object(CTX_data_depsgraph(C), obact); + bPoseChannel *pcham_act = BKE_pose_channel_active(obact_eval); if (pcham_act) { BLI_strncpy(v3d->ob_centre_bone, pcham_act->name, sizeof(v3d->ob_centre_bone)); } @@ -3017,7 +3050,7 @@ static int viewcenter_cursor_exec(bContext *C, wmOperator *op) /* non camera center */ float new_ofs[3]; - negate_v3_v3(new_ofs, ED_view3d_cursor3d_get(scene, v3d)); + negate_v3_v3(new_ofs, scene->cursor.location); ED_view3d_smooth_view( C, v3d, ar, smooth_viewtx, &(const V3D_SmoothParams) {.ofs = new_ofs}); @@ -3051,13 +3084,12 @@ void VIEW3D_OT_view_center_cursor(wmOperatorType *ot) static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Main *bmain = CTX_data_main(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); - Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); if (rv3d) { + struct Depsgraph *depsgraph = CTX_data_depsgraph(C); float new_ofs[3]; const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); @@ -3065,7 +3097,7 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev view3d_operator_needs_opengl(C); - if (ED_view3d_autodist(bmain, scene, ar, v3d, event->mval, new_ofs, false, NULL)) { + if (ED_view3d_autodist(depsgraph, ar, v3d, event->mval, new_ofs, false, NULL)) { /* pass */ } else { @@ -3105,6 +3137,7 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot) static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */ { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); float xfac, yfac; float size[2]; @@ -3119,7 +3152,7 @@ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was rv3d->camdx = rv3d->camdy = 0.0f; - ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size); + ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size); /* 4px is just a little room from the edge of the area */ xfac = (float)ar->winx / (float)(size[0] + 4); @@ -3197,18 +3230,14 @@ static int render_border_exec(bContext *C, wmOperator *op) rcti rect; rctf vb, border; - const bool camera_only = RNA_boolean_get(op->ptr, "camera_only"); - - if (camera_only && rv3d->persp != RV3D_CAMOB) - return OPERATOR_PASS_THROUGH; - - /* get border select values using rna */ + /* get box select values using rna */ WM_operator_properties_border_to_rcti(op, &rect); /* calculate range */ if (rv3d->persp == RV3D_CAMOB) { - ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &vb, false); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &vb, false); } else { vb.xmin = 0; @@ -3253,23 +3282,24 @@ static int render_border_exec(bContext *C, wmOperator *op) v3d->flag2 |= V3D_RENDER_BORDER; } + if (rv3d->persp == RV3D_CAMOB) { + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + } return OPERATOR_FINISHED; } void VIEW3D_OT_render_border(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Set Render Border"; ot->description = "Set the boundaries of the border render and enable border render"; ot->idname = "VIEW3D_OT_render_border"; /* api callbacks */ - ot->invoke = WM_gesture_border_invoke; + ot->invoke = WM_gesture_box_invoke; ot->exec = render_border_exec; - ot->modal = WM_gesture_border_modal; - ot->cancel = WM_gesture_border_cancel; + ot->modal = WM_gesture_box_modal; + ot->cancel = WM_gesture_box_cancel; ot->poll = ED_operator_view3d_active; @@ -3278,10 +3308,6 @@ void VIEW3D_OT_render_border(wmOperatorType *ot) /* properties */ WM_operator_properties_border(ot); - - prop = RNA_def_boolean(ot->srna, "camera_only", false, "Camera Only", - "Set render border for camera view and final render only"); - RNA_def_property_flag(prop, PROP_HIDDEN); } /** \} */ @@ -3316,6 +3342,9 @@ static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op)) border->xmax = 1.0f; border->ymax = 1.0f; + if (rv3d->persp == RV3D_CAMOB) { + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + } return OPERATOR_FINISHED; } @@ -3342,11 +3371,9 @@ void VIEW3D_OT_clear_render_border(wmOperatorType *ot) static int view3d_zoom_border_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); - Scene *scene = CTX_data_scene(C); const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* Zooms in on a border drawn by the user */ @@ -3359,14 +3386,13 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) float new_ofs[3]; /* ZBuffer depth vars */ - bglMats mats; float depth_close = FLT_MAX; - double cent[2], p[3]; + float cent[2], p[3]; /* note; otherwise opengl won't work */ view3d_operator_needs_opengl(C); - /* get border select values using rna */ + /* get box select values using rna */ WM_operator_properties_border_to_rcti(op, &rect); /* check if zooming in/out view */ @@ -3375,8 +3401,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) ED_view3d_dist_range_get(v3d, dist_range); /* Get Z Depths, needed for perspective, nice for ortho */ - bgl_get_mats(&mats); - ED_view3d_draw_depth(bmain, scene, ar, v3d, true); + ED_view3d_draw_depth(CTX_data_depsgraph(C), ar, v3d, true); { /* avoid allocating the whole depth buffer */ @@ -3391,11 +3416,11 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) MEM_SAFE_FREE(depth_temp.depths); } - cent[0] = (((double)rect.xmin) + ((double)rect.xmax)) / 2; - cent[1] = (((double)rect.ymin) + ((double)rect.ymax)) / 2; + cent[0] = (((float)rect.xmin) + ((float)rect.xmax)) / 2; + cent[1] = (((float)rect.ymin) + ((float)rect.ymax)) / 2; if (rv3d->is_persp) { - double p_corner[3]; + float p_corner[3]; /* no depths to use, we cant do anything! */ if (depth_close == FLT_MAX) { @@ -3403,23 +3428,14 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } /* convert border to 3d coordinates */ - if ((!gluUnProject(cent[0], cent[1], depth_close, - mats.modelview, mats.projection, (GLint *)mats.viewport, - &p[0], &p[1], &p[2])) || - (!gluUnProject((double)rect.xmin, (double)rect.ymin, depth_close, - mats.modelview, mats.projection, (GLint *)mats.viewport, - &p_corner[0], &p_corner[1], &p_corner[2]))) + if ((!ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) || + (!ED_view3d_unproject(ar, rect.xmin, rect.ymin, depth_close, p_corner))) { return OPERATOR_CANCELLED; } - dvec[0] = p[0] - p_corner[0]; - dvec[1] = p[1] - p_corner[1]; - dvec[2] = p[2] - p_corner[2]; - - new_ofs[0] = -p[0]; - new_ofs[1] = -p[1]; - new_ofs[2] = -p[2]; + sub_v3_v3v3(dvec, p, p_corner); + negate_v3_v3(new_ofs, p); new_dist = len_v3(dvec); @@ -3434,13 +3450,8 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) new_dist = rv3d->dist; /* convert the drawn rectangle into 3d space */ - if (depth_close != FLT_MAX && gluUnProject(cent[0], cent[1], depth_close, - mats.modelview, mats.projection, (GLint *)mats.viewport, - &p[0], &p[1], &p[2])) - { - new_ofs[0] = -p[0]; - new_ofs[1] = -p[1]; - new_ofs[2] = -p[2]; + if (depth_close != FLT_MAX && ED_view3d_unproject(ar, cent[0], cent[1], depth_close, p)) { + negate_v3_v3(new_ofs, p); } else { float mval_f[2]; @@ -3477,6 +3488,13 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) /* clamp after because we may have been zooming out */ CLAMP(new_dist, dist_range[0], dist_range[1]); + /* TODO(campbell): 'is_camera_lock' not currently working well. */ + const bool is_camera_lock = ED_view3d_camera_lock_check(v3d, rv3d); + if ((rv3d->persp == RV3D_CAMOB) && (is_camera_lock == false)) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, RV3D_PERSP); + } + ED_view3d_smooth_view( C, v3d, ar, smooth_viewtx, &(const V3D_SmoothParams) {.ofs = new_ofs, .dist = &new_dist}); @@ -3488,18 +3506,6 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = CTX_wm_region_view3d(C); - - /* if in camera view do not exec the operator so we do not conflict with set render border*/ - if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) - return WM_gesture_border_invoke(C, op, event); - else - return OPERATOR_PASS_THROUGH; -} - void VIEW3D_OT_zoom_border(wmOperatorType *ot) { /* identifiers */ @@ -3508,10 +3514,10 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot) ot->idname = "VIEW3D_OT_zoom_border"; /* api callbacks */ - ot->invoke = view3d_zoom_border_invoke; + ot->invoke = WM_gesture_box_invoke; ot->exec = view3d_zoom_border_exec; - ot->modal = WM_gesture_border_modal; - ot->cancel = WM_gesture_border_cancel; + ot->modal = WM_gesture_box_modal; + ot->cancel = WM_gesture_box_cancel; ot->poll = ED_operator_region_view3d_active; @@ -3519,7 +3525,7 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot) ot->flag = 0; /* properties */ - WM_operator_properties_gesture_border_zoom(ot); + WM_operator_properties_gesture_box_zoom(ot); } /** \} */ @@ -3530,13 +3536,13 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot) * Sets the view to 1:1 camera/render-pixel. * \{ */ -static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d) +static void view3d_set_1_to_1_viewborder(Scene *scene, Depsgraph *depsgraph, ARegion *ar, View3D *v3d) { RegionView3D *rv3d = ar->regiondata; float size[2]; int im_width = (scene->r.size * scene->r.xsch) / 100; - ED_view3d_calc_camera_border_size(scene, ar, v3d, rv3d, size); + ED_view3d_calc_camera_border_size(scene, depsgraph, ar, v3d, rv3d, size); rv3d->camzoom = BKE_screen_view3d_zoom_from_fac((float)im_width / size[0]); CLAMP(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX); @@ -3544,6 +3550,7 @@ static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar, View3D *v3d) static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op)) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); View3D *v3d; @@ -3552,7 +3559,7 @@ static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* no NULL check is needed, poll checks */ ED_view3d_context_user_region(C, &v3d, &ar); - view3d_set_1_to_1_viewborder(scene, ar, v3d); + view3d_set_1_to_1_viewborder(scene, depsgraph, ar, v3d); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); @@ -3577,7 +3584,7 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name View Axis/Type Operator +/** \name View Axis Operator * \{ */ static const EnumPropertyItem prop_view_items[] = { @@ -3587,17 +3594,20 @@ static const EnumPropertyItem prop_view_items[] = { {RV3D_VIEW_TOP, "TOP", ICON_TRIA_UP, "Top", "View From the Top"}, {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"}, {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"}, - {RV3D_VIEW_CAMERA, "CAMERA", ICON_CAMERA_DATA, "Camera", "View From the Active Camera"}, {0, NULL, 0, NULL, NULL} }; /* would like to make this a generic function - outside of transform */ +/** + * \param align_to_quat: When not NULL, set the axis relative to this rotation. + */ static void axis_set_view( bContext *C, View3D *v3d, ARegion *ar, const float quat_[4], - short view, int perspo, bool align_active, + short view, int perspo, + const float *align_to_quat, const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; /* no NULL check is needed, poll checks */ @@ -3607,29 +3617,12 @@ static void axis_set_view( normalize_qt_qt(quat, quat_); - if (align_active) { - /* align to active object */ - Object *obact = CTX_data_active_object(C); - if (obact == NULL) { - /* no active object, ignore this option */ - align_active = false; - } - else { - float obact_quat[4]; - float twmat[3][3]; - - /* same as transform manipulator when normal is set */ - ED_getTransformOrientationMatrix(C, twmat, V3D_AROUND_ACTIVE); - - mat3_to_quat(obact_quat, twmat); - invert_qt_normalized(obact_quat); - mul_qt_qtqt(quat, quat, obact_quat); - - rv3d->view = view = RV3D_VIEW_USER; - } + if (align_to_quat) { + mul_qt_qtqt(quat, quat, align_to_quat); + rv3d->view = view = RV3D_VIEW_USER; } - if (align_active == false) { + if (align_to_quat == NULL) { rv3d->view = view; } @@ -3659,7 +3652,8 @@ static void axis_set_view( dist = rv3d->dist; /* so we animate _from_ the camera location */ - ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, &rv3d->dist, NULL); + Object *camera_eval = DEG_get_evaluated_object(CTX_data_depsgraph(C), v3d->camera); + ED_view3d_from_object(camera_eval, rv3d->ofs, NULL, &rv3d->dist, NULL); ED_view3d_smooth_view( C, v3d, ar, smooth_viewtx, @@ -3684,15 +3678,13 @@ static void axis_set_view( } } -static int viewnumpad_exec(bContext *C, wmOperator *op) +static int view_axis_exec(bContext *C, wmOperator *op) { View3D *v3d; ARegion *ar; RegionView3D *rv3d; - Scene *scene = CTX_data_scene(C); static int perspo = RV3D_PERSP; - int viewnum, nextperspo; - bool align_active; + int viewnum; const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); /* no NULL check is needed, poll checks */ @@ -3702,118 +3694,209 @@ static int viewnumpad_exec(bContext *C, wmOperator *op) ED_view3d_smooth_view_force_finish(C, v3d, ar); viewnum = RNA_enum_get(op->ptr, "type"); - align_active = RNA_boolean_get(op->ptr, "align_active"); - /* Use this to test if we started out with a camera */ + float align_quat_buf[4]; + float *align_quat = NULL; - if (rv3d->persp == RV3D_CAMOB) { - nextperspo = rv3d->lpersp; - } - else { - nextperspo = perspo; + if (RNA_boolean_get(op->ptr, "align_active")) { + /* align to active object */ + Object *obact = CTX_data_active_object(C); + if (obact != NULL) { + float twmat[3][3]; + /* same as transform gizmo when normal is set */ + ED_getTransformOrientationMatrix(C, twmat, V3D_AROUND_ACTIVE); + align_quat = align_quat_buf; + mat3_to_quat(align_quat, twmat); + invert_qt_normalized(align_quat); + } } - if (RV3D_VIEW_IS_AXIS(viewnum)) { - float quat[4]; + if (RNA_boolean_get(op->ptr, "relative")) { + float z_rel[3]; - ED_view3d_quat_from_axis_view(viewnum, quat); - axis_set_view(C, v3d, ar, quat, viewnum, nextperspo, align_active, smooth_viewtx); + if (viewnum == RV3D_VIEW_RIGHT) { + negate_v3_v3(z_rel, rv3d->viewinv[0]); + } + else if (viewnum == RV3D_VIEW_LEFT) { + copy_v3_v3(z_rel, rv3d->viewinv[0]); + } + else if (viewnum == RV3D_VIEW_TOP) { + negate_v3_v3(z_rel, rv3d->viewinv[1]); + } + else if (viewnum == RV3D_VIEW_BOTTOM) { + copy_v3_v3(z_rel, rv3d->viewinv[1]); + } + else if (viewnum == RV3D_VIEW_FRONT) { + negate_v3_v3(z_rel, rv3d->viewinv[2]); + } + else if (viewnum == RV3D_VIEW_BACK) { + copy_v3_v3(z_rel, rv3d->viewinv[2]); + } + else { + BLI_assert(0); + } + + float angle_max = FLT_MAX; + int view_closest = -1; + for (int i = RV3D_VIEW_FRONT; i <= RV3D_VIEW_BOTTOM; i++) { + float quat[4]; + float mat[3][3]; + ED_view3d_quat_from_axis_view(i, quat); + quat[0] *= -1.0f; + quat_to_mat3(mat, quat); + if (align_quat) { + mul_qt_qtqt(quat, quat, align_quat); + } + const float angle_test = angle_normalized_v3v3(z_rel, mat[2]); + if (angle_max > angle_test) { + angle_max = angle_test; + view_closest = i; + } + } + if (view_closest == -1) { + view_closest = RV3D_VIEW_FRONT; + } + viewnum = view_closest; } - else if (viewnum == RV3D_VIEW_CAMERA) { - if ((rv3d->viewlock & RV3D_LOCKED) == 0) { - /* lastview - */ - if (rv3d->persp != RV3D_CAMOB) { - Object *ob = OBACT; + /* Use this to test if we started out with a camera */ + const int nextperspo = (rv3d->persp == RV3D_CAMOB) ? rv3d->lpersp : perspo; + float quat[4]; + ED_view3d_quat_from_axis_view(viewnum, quat); + axis_set_view(C, v3d, ar, quat, viewnum, nextperspo, align_quat, smooth_viewtx); - if (!rv3d->smooth_timer) { - /* store settings of current view before allowing overwriting with camera view - * only if we're not currently in a view transition */ + perspo = rv3d->persp; - ED_view3d_lastview_store(rv3d); - } + return OPERATOR_FINISHED; +} + + +void VIEW3D_OT_view_axis(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "View Axis"; + ot->description = "Use a preset viewpoint"; + ot->idname = "VIEW3D_OT_view_axis"; + + /* api callbacks */ + ot->exec = view_axis_exec; + ot->poll = ED_operator_rv3d_user_region_poll; + + /* flags */ + ot->flag = 0; + + ot->prop = RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "Preset viewpoint to use"); + RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active object's axis"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "relative", 0, "Relative", "Rotate relative to the current orientation"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Camera Operator + * \{ */ + +static int view_camera_exec(bContext *C, wmOperator *op) +{ + View3D *v3d; + ARegion *ar; + RegionView3D *rv3d; + const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + + /* no NULL check is needed, poll checks */ + ED_view3d_context_user_region(C, &v3d, &ar); + rv3d = ar->regiondata; + + ED_view3d_smooth_view_force_finish(C, v3d, ar); + + if ((rv3d->viewlock & RV3D_LOCKED) == 0) { + /* lastview - */ + + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + + if (rv3d->persp != RV3D_CAMOB) { + Object *ob = OBACT(view_layer); + + if (!rv3d->smooth_timer) { + /* store settings of current view before allowing overwriting with camera view + * only if we're not currently in a view transition */ + + ED_view3d_lastview_store(rv3d); + } #if 0 - if (G.qual == LR_ALTKEY) { - if (oldcamera && is_an_active_object(oldcamera)) { - v3d->camera = oldcamera; - } - handle_view3d_lock(); + if (G.qual == LR_ALTKEY) { + if (oldcamera && is_an_active_object(oldcamera)) { + v3d->camera = oldcamera; } + handle_view3d_lock(); + } #endif - /* first get the default camera for the view lock type */ - if (v3d->scenelock) { - /* sets the camera view if available */ + /* first get the default camera for the view lock type */ + if (v3d->scenelock) { + /* sets the camera view if available */ + v3d->camera = scene->camera; + } + else { + /* use scene camera if one is not set (even though we're unlocked) */ + if (v3d->camera == NULL) { v3d->camera = scene->camera; } - else { - /* use scene camera if one is not set (even though we're unlocked) */ - if (v3d->camera == NULL) { - v3d->camera = scene->camera; - } - } + } - /* if the camera isn't found, check a number of options */ - if (v3d->camera == NULL && ob && ob->type == OB_CAMERA) - v3d->camera = ob; + /* if the camera isn't found, check a number of options */ + if (v3d->camera == NULL && ob && ob->type == OB_CAMERA) + v3d->camera = ob; - if (v3d->camera == NULL) - v3d->camera = BKE_scene_camera_find(scene); + if (v3d->camera == NULL) + v3d->camera = BKE_view_layer_camera_find(view_layer); - /* couldnt find any useful camera, bail out */ - if (v3d->camera == NULL) - return OPERATOR_CANCELLED; + /* couldn't find any useful camera, bail out */ + if (v3d->camera == NULL) + return OPERATOR_CANCELLED; - /* important these don't get out of sync for locked scenes */ - if (v3d->scenelock) - scene->camera = v3d->camera; + /* important these don't get out of sync for locked scenes */ + if (v3d->scenelock) + scene->camera = v3d->camera; - /* finally do snazzy view zooming */ - rv3d->persp = RV3D_CAMOB; - ED_view3d_smooth_view( - C, v3d, ar, smooth_viewtx, - &(const V3D_SmoothParams) { - .camera = v3d->camera, .ofs = rv3d->ofs, .quat = rv3d->viewquat, - .dist = &rv3d->dist, .lens = &v3d->lens}); - } - else { - /* return to settings of last view */ - /* does view3d_smooth_view too */ - axis_set_view(C, v3d, ar, - rv3d->lviewquat, - rv3d->lview, rv3d->lpersp, 0, - smooth_viewtx); - } + /* finally do snazzy view zooming */ + rv3d->persp = RV3D_CAMOB; + ED_view3d_smooth_view( + C, v3d, ar, smooth_viewtx, + &(const V3D_SmoothParams) { + .camera = v3d->camera, .ofs = rv3d->ofs, .quat = rv3d->viewquat, + .dist = &rv3d->dist, .lens = &v3d->lens}); + } + else { + /* return to settings of last view */ + /* does view3d_smooth_view too */ + axis_set_view(C, v3d, ar, rv3d->lviewquat, rv3d->lview, rv3d->lpersp, NULL, smooth_viewtx); } } - if (rv3d->persp != RV3D_CAMOB) perspo = rv3d->persp; - return OPERATOR_FINISHED; } - -void VIEW3D_OT_viewnumpad(wmOperatorType *ot) +void VIEW3D_OT_view_camera(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ - ot->name = "View Numpad"; - ot->description = "Use a preset viewpoint"; - ot->idname = "VIEW3D_OT_viewnumpad"; + ot->name = "View Camera"; + ot->description = "Toggle the camera view"; + ot->idname = "VIEW3D_OT_view_camera"; /* api callbacks */ - ot->exec = viewnumpad_exec; + ot->exec = view_camera_exec; ot->poll = ED_operator_rv3d_user_region_poll; /* flags */ ot->flag = 0; - - ot->prop = RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "Preset viewpoint to use"); - RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active object's axis"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ @@ -3867,7 +3950,8 @@ static int vieworbit_exec(bContext *C, wmOperator *op) float quat_new[4]; if (view_opposite == RV3D_VIEW_USER) { - ED_view3d_persp_ensure(v3d, ar); + const Depsgraph *depsgraph = CTX_data_depsgraph(C); + ED_view3d_persp_ensure(depsgraph, v3d, ar); } if (ELEM(orbitdir, V3D_VIEW_STEPLEFT, V3D_VIEW_STEPRIGHT)) { @@ -3992,7 +4076,7 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y)) view3d_boxview_sync(vod->sa, vod->ar); } - ED_view3d_camera_lock_sync(vod->v3d, vod->rv3d); + ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d); ED_region_tag_redraw(vod->ar); } @@ -4226,8 +4310,8 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event) void VIEW3D_OT_view_pan(wmOperatorType *ot) { /* identifiers */ - ot->name = "View Pan"; - ot->description = "Pan the view"; + ot->name = "Pan View Direction"; + ot->description = "Pan the view in a given direction"; ot->idname = "VIEW3D_OT_view_pan"; /* api callbacks */ @@ -4325,52 +4409,67 @@ void VIEW3D_OT_navigate(wmOperatorType *ot) /** \name Background Image Add Operator * \{ */ -static BGpic *background_image_add(bContext *C) + +static Camera *background_image_camera_from_context(bContext *C) { + /* Needed to support drag-and-drop & camera buttons context. */ View3D *v3d = CTX_wm_view3d(C); - - return ED_view3d_background_image_new(v3d); + if (v3d != NULL) { + if (v3d->camera && v3d->camera->data && v3d->camera->type == OB_CAMERA) { + return v3d->camera->data; + } + return NULL; + } + else { + return CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; + } } static int background_image_add_exec(bContext *C, wmOperator *UNUSED(op)) { - background_image_add(C); + Camera *cam = background_image_camera_from_context(C); + BKE_camera_background_image_new(cam); return OPERATOR_FINISHED; } static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - View3D *v3d = CTX_wm_view3d(C); + Camera *cam = background_image_camera_from_context(C); Image *ima; - BGpic *bgpic; + CameraBGImage *bgpic; ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM); /* may be NULL, continue anyway */ - bgpic = background_image_add(C); + bgpic = BKE_camera_background_image_new(cam); bgpic->ima = ima; - v3d->flag |= V3D_DISPBGPICS; + cam->flag |= CAM_SHOW_BG_IMAGE; - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam); return OPERATOR_FINISHED; } +static bool background_image_add_poll(bContext *C) +{ + return background_image_camera_from_context(C) != NULL; +} + void VIEW3D_OT_background_image_add(wmOperatorType *ot) { /* identifiers */ /* note: having key shortcut here is bad practice, * but for now keep because this displays when dragging an image over the 3D viewport */ - ot->name = "Add Background Image (Ctrl for Empty Object)"; - ot->description = "Add a new background image (Ctrl for Empty Object)"; + ot->name = "Add Background Image"; + ot->description = "Add a new background image"; ot->idname = "VIEW3D_OT_background_image_add"; /* api callbacks */ ot->invoke = background_image_add_invoke; ot->exec = background_image_add_exec; - ot->poll = ED_operator_view3d_active; + ot->poll = background_image_add_poll; /* flags */ ot->flag = OPTYPE_UNDO; @@ -4390,21 +4489,21 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot) static int background_image_remove_exec(bContext *C, wmOperator *op) { - View3D *v3d = CTX_wm_view3d(C); + Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; const int index = RNA_int_get(op->ptr, "index"); - BGpic *bgpic_rem = BLI_findlink(&v3d->bgpicbase, index); + CameraBGImage *bgpic_rem = BLI_findlink(&cam->bg_images, index); if (bgpic_rem) { - if (bgpic_rem->source == V3D_BGPIC_IMAGE) { + if (bgpic_rem->source == CAM_BGIMG_SOURCE_IMAGE) { id_us_min((ID *)bgpic_rem->ima); } - else if (bgpic_rem->source == V3D_BGPIC_MOVIE) { + else if (bgpic_rem->source == CAM_BGIMG_SOURCE_MOVIE) { id_us_min((ID *)bgpic_rem->clip); } - ED_view3d_background_image_remove(v3d, bgpic_rem); + BKE_camera_background_image_remove(cam, bgpic_rem); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam); return OPERATOR_FINISHED; } else { @@ -4421,7 +4520,7 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot) /* api callbacks */ ot->exec = background_image_remove_exec; - ot->poll = ED_operator_view3d_active; + ot->poll = ED_operator_camera; /* flags */ ot->flag = 0; @@ -4459,11 +4558,12 @@ void ED_view3d_clipping_local(RegionView3D *rv3d, float mat[4][4]) calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat); } +#if 0 /* TODO Missing from 2.8 drawing code. Find a solution to support clip border then uncomment it. */ + static int view3d_clipping_exec(bContext *C, wmOperator *op) { + ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); - ViewContext vc; - bglMats mats; rcti rect; WM_operator_properties_border_to_rcti(op, &rect); @@ -4471,12 +4571,8 @@ static int view3d_clipping_exec(bContext *C, wmOperator *op) rv3d->rflag |= RV3D_CLIPPING; rv3d->clipbb = MEM_callocN(sizeof(BoundBox), "clipbb"); - /* note; otherwise opengl won't work */ - view3d_operator_needs_opengl(C); - - ED_view3d_viewcontext_init(C, &vc); - view3d_get_transformation(vc.ar, vc.rv3d, NULL, &mats); /* NULL because we don't want it in object space */ - ED_view3d_clipping_calc(rv3d->clipbb, rv3d->clip, &mats, &rect); + /* NULL object because we don't want it in object space */ + ED_view3d_clipping_calc(rv3d->clipbb, rv3d->clip, ar, NULL, &rect); return OPERATOR_FINISHED; } @@ -4494,7 +4590,7 @@ static int view3d_clipping_invoke(bContext *C, wmOperator *op, const wmEvent *ev return OPERATOR_FINISHED; } else { - return WM_gesture_border_invoke(C, op, event); + return WM_gesture_box_invoke(C, op, event); } } @@ -4509,8 +4605,8 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* api callbacks */ ot->invoke = view3d_clipping_invoke; ot->exec = view3d_clipping_exec; - ot->modal = WM_gesture_border_modal; - ot->cancel = WM_gesture_border_cancel; + ot->modal = WM_gesture_box_modal; + ot->cancel = WM_gesture_box_cancel; ot->poll = ED_operator_region_view3d_active; @@ -4520,6 +4616,7 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* properties */ WM_operator_properties_border(ot); } +#endif /** \} */ @@ -4529,10 +4626,8 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* cursor position in vec, result in vec, mval in region coords */ /* note: cannot use event->mval here (called by object_add() */ -void ED_view3d_cursor3d_position(bContext *C, const int mval[2], float cursor_co[3]) +void ED_view3d_cursor3d_position(bContext *C, const int mval[2], const bool use_depth, float cursor_co[3]) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ar->regiondata; @@ -4553,10 +4648,13 @@ void ED_view3d_cursor3d_position(bContext *C, const int mval[2], float cursor_co ED_view3d_calc_zfac(rv3d, cursor_co, NULL /* &flip */ ); } - if (U.uiflag & USER_DEPTH_CURSOR) { /* maybe this should be accessed some other way */ + if (use_depth) { /* maybe this should be accessed some other way */ + struct Depsgraph *depsgraph = CTX_data_depsgraph(C); + view3d_operator_needs_opengl(C); - if (ED_view3d_autodist(bmain, scene, ar, v3d, mval, cursor_co, true, NULL)) + if (ED_view3d_autodist(depsgraph, ar, v3d, mval, cursor_co, true, NULL)) { depth_used = true; + } } if (depth_used == false) { @@ -4566,31 +4664,122 @@ void ED_view3d_cursor3d_position(bContext *C, const int mval[2], float cursor_co } } -void ED_view3d_cursor3d_update(bContext *C, const int mval[2]) +void ED_view3d_cursor3d_position_rotation( + bContext *C, const int mval[2], + const bool use_depth, enum eV3DCursorOrient orientation, + float cursor_co[3], float cursor_quat[4]) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + /* XXX, caller should check. */ + if (rv3d == NULL) + return; - float *cursor_co_curr = ED_view3d_cursor3d_get(scene, v3d); - float cursor_co_prev[3]; + ED_view3d_cursor3d_position(C, mval, use_depth, cursor_co); + + if (orientation == V3D_CURSOR_ORIENT_NONE) { + /* pass */ + } + else if (orientation == V3D_CURSOR_ORIENT_VIEW) { + copy_qt_qt(cursor_quat, rv3d->viewquat); + cursor_quat[0] *= -1.0f; + } + else if (orientation == V3D_CURSOR_ORIENT_XFORM) { + float mat[3][3]; + ED_transform_calc_orientation_from_type(C, mat); + mat3_to_quat(cursor_quat, mat); + } + else if (orientation == V3D_CURSOR_ORIENT_GEOM) { + copy_qt_qt(cursor_quat, rv3d->viewquat); + cursor_quat[0] *= -1.0f; + + const float mval_fl[2] = {UNPACK2(mval)}; + float ray_no[3]; + float ray_co[3]; + + struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( + bmain, scene, CTX_data_depsgraph(C), 0, ar, v3d); + + float obmat[4][4]; + Object *ob_dummy = NULL; + float dist_px = 0; + if (ED_transform_snap_object_project_view3d_ex( + snap_context, + SCE_SNAP_MODE_FACE, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .use_object_edit_cage = false, + }, + mval_fl, &dist_px, + ray_co, ray_no, NULL, + &ob_dummy, obmat)) + { + if (use_depth) { + copy_v3_v3(cursor_co, ray_co); + } + + float tquat[4]; + + /* Math normal (Z). */ + { + float z_src[3] = {0, 0, 1}; + mul_qt_v3(cursor_quat, z_src); + rotation_between_vecs_to_quat(tquat, z_src, ray_no); + mul_qt_qtqt(cursor_quat, tquat, cursor_quat); + } + + /* Match object matrix (X). */ + { + const float ortho_axis_dot[3] = { + dot_v3v3(ray_no, obmat[0]), + dot_v3v3(ray_no, obmat[1]), + dot_v3v3(ray_no, obmat[2]), + }; + const int ortho_axis = axis_dominant_v3_ortho_single(ortho_axis_dot); + float x_src[3] = {1, 0, 0}; + float x_dst[3]; + mul_qt_v3(cursor_quat, x_src); + project_plane_v3_v3v3(x_dst, obmat[ortho_axis], ray_no); + normalize_v3(x_dst); + rotation_between_vecs_to_quat(tquat, x_src, x_dst); + mul_qt_qtqt(cursor_quat, tquat, cursor_quat); + } + } + ED_transform_snap_object_context_destroy(snap_context); + } +} + +void ED_view3d_cursor3d_update( + bContext *C, const int mval[2], + const bool use_depth, enum eV3DCursorOrient orientation) +{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; - copy_v3_v3(cursor_co_prev, cursor_co_curr); + View3DCursor *cursor_curr = &scene->cursor; + View3DCursor cursor_prev = *cursor_curr; - ED_view3d_cursor3d_position(C, mval, cursor_co_curr); + ED_view3d_cursor3d_position_rotation( + C, mval, + use_depth, orientation, + cursor_curr->location, cursor_curr->rotation); /* offset the cursor lock to avoid jumping to new offset */ if (v3d->ob_centre_cursor) { - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - if (U.uiflag & USER_LOCK_CURSOR_ADJUST) { float co_2d_curr[2], co_2d_prev[2]; if ((ED_view3d_project_float_global( - ar, cursor_co_prev, co_2d_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) && + ar, cursor_prev.location, co_2d_prev, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) && (ED_view3d_project_float_global( - ar, cursor_co_curr, co_2d_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) + ar, cursor_curr->location, co_2d_curr, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) { rv3d->ofs_lock[0] += (co_2d_curr[0] - co_2d_prev[0]) / (ar->winx * 0.5f); rv3d->ofs_lock[1] += (co_2d_curr[1] - co_2d_prev[1]) / (ar->winy * 0.5f); @@ -4606,11 +4795,30 @@ void ED_view3d_cursor3d_update(bContext *C, const int mval[2]) WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); else WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene); + + { + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + WM_msg_publish_rna_prop( + mbus, &scene->id, scene, Scene, cursor_location); + } + + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); } -static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +static int view3d_cursor3d_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ED_view3d_cursor3d_update(C, event->mval); + bool use_depth = (U.uiflag & USER_DEPTH_CURSOR); + { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_depth"); + if (RNA_property_is_set(op->ptr, prop)) { + use_depth = RNA_property_boolean_get(op->ptr, prop); + } + else { + RNA_property_boolean_set(op->ptr, prop, use_depth); + } + } + const enum eV3DCursorOrient orientation = RNA_enum_get(op->ptr, "orientation"); + ED_view3d_cursor3d_update(C, event->mval, use_depth, orientation); return OPERATOR_FINISHED; } @@ -4630,128 +4838,147 @@ void VIEW3D_OT_cursor3d(wmOperatorType *ot) /* flags */ // ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; -} - -/** \} */ -/* -------------------------------------------------------------------- */ -/** \name Transform Manipulator Operator - * \{ */ - -static int manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - View3D *v3d = CTX_wm_view3d(C); - - if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH; - if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH; - - /* note; otherwise opengl won't work */ - view3d_operator_needs_opengl(C); - - if (BIF_do_manipulator(C, event, op) == 0) - return OPERATOR_PASS_THROUGH; - - return OPERATOR_FINISHED; -} - -void VIEW3D_OT_manipulator(wmOperatorType *ot) -{ PropertyRNA *prop; + static const EnumPropertyItem orientation_items[] = { + {V3D_CURSOR_ORIENT_NONE, "NONE", 0, "None", "Leave orientation unchanged"}, + {V3D_CURSOR_ORIENT_VIEW, "VIEW", 0, "View", "Orient to the viewport"}, + {V3D_CURSOR_ORIENT_XFORM, "XFORM", 0, "Transform", "Orient to the current transform setting"}, + {V3D_CURSOR_ORIENT_GEOM, "GEOM", 0, "Geometry", "Match the surface normal"}, + {0, NULL, 0, NULL, NULL} + }; - /* identifiers */ - ot->name = "3D Manipulator"; - ot->description = "Manipulate selected item by axis"; - ot->idname = "VIEW3D_OT_manipulator"; - - /* api callbacks */ - ot->invoke = manipulator_invoke; - - ot->poll = ED_operator_view3d_active; - - /* properties to pass to transform */ - Transform_Properties(ot, P_CONSTRAINT); + prop = RNA_def_boolean( + ot->srna, "use_depth", true, "Surface Project", + "Project onto the surface"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "use_planar_constraint", false, "Planar Constraint", "Limit the transformation to the " - "two axes that have not been clicked (translate/scale only)"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + prop = RNA_def_enum( + ot->srna, "orientation", orientation_items, V3D_CURSOR_ORIENT_VIEW, + "Orientation", "Preset viewpoint to use"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ /* -------------------------------------------------------------------- */ -/** \name Enable Transform Manipulator Operator +/** \name Toggle Shading Operator * \{ */ -static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static const EnumPropertyItem prop_shading_type_items[] = { + {OB_WIRE, "WIREFRAME", 0, "Wireframe", "Toggle wireframe shading"}, + {OB_SOLID, "SOLID", 0, "Solid", "Toggle solid shading"}, + {OB_MATERIAL, "MATERIAL", 0, "LookDev", "Toggle lookdev shading"}, + {OB_RENDER, "RENDERED", 0, "Rendered", "Toggle rendered shading"}, + {0, NULL, 0, NULL, NULL} +}; + +static int toggle_shading_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); View3D *v3d = CTX_wm_view3d(C); + ScrArea *sa = CTX_wm_area(C); + int type = RNA_enum_get(op->ptr, "type"); - v3d->twtype = 0; - - if (RNA_boolean_get(op->ptr, "translate")) - v3d->twtype |= V3D_MANIP_TRANSLATE; - if (RNA_boolean_get(op->ptr, "rotate")) - v3d->twtype |= V3D_MANIP_ROTATE; - if (RNA_boolean_get(op->ptr, "scale")) - v3d->twtype |= V3D_MANIP_SCALE; + if (type == OB_SOLID) { + if (v3d->shading.type != type) { + v3d->shading.type = type; + } + else if (v3d->shading.type == OB_WIRE) { + v3d->shading.type = OB_SOLID; + } + else { + v3d->shading.type = OB_WIRE; + } + } + else { + char *prev_type = ( + (type == OB_WIRE) ? + &v3d->shading.prev_type_wire : + &v3d->shading.prev_type); + if (v3d->shading.type == type) { + if (*prev_type == type || !ELEM(*prev_type, OB_WIRE, OB_SOLID, OB_MATERIAL, OB_RENDER)) { + *prev_type = OB_SOLID; + } + v3d->shading.type = *prev_type; + } + else { + *prev_type = v3d->shading.type; + v3d->shading.type = type; + } + } + ED_view3d_shade_update(bmain, v3d, sa); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); return OPERATOR_FINISHED; } -void VIEW3D_OT_enable_manipulator(wmOperatorType *ot) +void VIEW3D_OT_toggle_shading(wmOperatorType *ot) { PropertyRNA *prop; /* identifiers */ - ot->name = "Enable 3D Manipulator"; - ot->description = "Enable the transform manipulator for use"; - ot->idname = "VIEW3D_OT_enable_manipulator"; + ot->name = "Toggle Shading Type"; + ot->description = "Toggle shading type in 3D viewport"; + ot->idname = "VIEW3D_OT_toggle_shading"; /* api callbacks */ - ot->invoke = enable_manipulator_invoke; + ot->exec = toggle_shading_exec; ot->poll = ED_operator_view3d_active; - /* properties */ - prop = RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "scale", 0, "Scale", "Enable the scale manipulator"); + prop = RNA_def_enum(ot->srna, "type", prop_shading_type_items, 0, "Type", "Shading type to toggle"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ + /* -------------------------------------------------------------------- */ -/** \name Toggle Render Shading Operator +/** \name Toggle XRay * \{ */ -static int toggle_render_exec(bContext *C, wmOperator *UNUSED(op)) +static int toggle_xray_exec(bContext *C, wmOperator *op) { View3D *v3d = CTX_wm_view3d(C); - if (v3d->drawtype == OB_RENDER) { - v3d->drawtype = v3d->prev_drawtype; + ScrArea *sa = CTX_wm_area(C); + Object *obact = CTX_data_active_object(C); + + if (obact && + ((obact->mode & OB_MODE_POSE) || + ((obact->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(obact)))) + { + v3d->overlay.flag ^= V3D_OVERLAY_BONE_SELECT; } else { - v3d->prev_drawtype = v3d->drawtype; - v3d->drawtype = OB_RENDER; + const bool xray_active = ( + (obact && (obact->mode & OB_MODE_EDIT)) || + ELEM(v3d->shading.type, OB_WIRE, OB_SOLID)); + + if (v3d->shading.type == OB_WIRE) { + v3d->shading.flag ^= V3D_SHADING_XRAY_BONE; + } + else { + v3d->shading.flag ^= V3D_SHADING_XRAY; + } + if (!xray_active) { + BKE_report(op->reports, RPT_INFO, "X-Ray not available in current mode"); + } } - ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C)); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + + ED_area_tag_redraw(sa); + return OPERATOR_FINISHED; } -void VIEW3D_OT_toggle_render(wmOperatorType *ot) +void VIEW3D_OT_toggle_xray(wmOperatorType *ot) { /* identifiers */ - ot->name = "Toggle Rendered Shading"; - ot->description = "Toggle rendered shading mode of the viewport"; - ot->idname = "VIEW3D_OT_toggle_render"; + ot->name = "Toggle X-Ray"; + ot->idname = "VIEW3D_OT_toggle_xray"; /* api callbacks */ - ot->exec = toggle_render_exec; + ot->exec = toggle_xray_exec; ot->poll = ED_operator_view3d_active; } diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 175dab28cbe..de5d5d29e52 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -56,6 +56,10 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_immediate.h" + +#include "DEG_depsgraph.h" + #include "view3d_intern.h" /* own include */ /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ @@ -133,56 +137,6 @@ void fly_modal_keymap(wmKeyConfig *keyconf) keymap = WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items); - /* items for modal map */ - WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CANCEL); - WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CANCEL); - - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, SPACEKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); - - WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_ACCELERATE); - WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, KM_ANY, 0, FLY_MODAL_DECELERATE); - WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_ACCELERATE); - WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_DECELERATE); - - WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, FLY_MODAL_SPEED); - - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_PAN_ENABLE); - /* XXX - Bug in the event system, middle mouse release doesn't work */ - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PAN_DISABLE); - - /* WASD */ - WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD); - WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD); - WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT); - WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT); - WM_modalkeymap_add_item(keymap, EKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP); - WM_modalkeymap_add_item(keymap, QKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN); - - /* for legacy reasons, leave R/F working */ - WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP); - WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN); - - WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD); - WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD); - WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT); - WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT); - - WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X); - WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z); - - WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE); - WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE); - - /* for legacy reasons, leave shift working */ - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE); - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE); - - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_FREELOOK_ENABLE); - WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_FREELOOK_DISABLE); - /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly"); } @@ -192,6 +146,7 @@ typedef struct FlyInfo { RegionView3D *rv3d; View3D *v3d; ARegion *ar; + struct Depsgraph *depsgraph; Scene *scene; wmTimer *timer; /* needed for redraws */ @@ -241,7 +196,7 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), float x1, x2, y1, y2; if (ED_view3d_cameracontrol_object_get(fly->v3d_camera_control)) { - ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); + ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); xoff = viewborder.xmin; yoff = viewborder.ymin; } @@ -258,36 +213,45 @@ static void drawFlyPixel(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), x2 = xoff + 0.55f * fly->width; y2 = yoff + 0.55f * fly->height; - UI_ThemeColor(TH_VIEW_OVERLAY); - glBegin(GL_LINES); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_VIEW_OVERLAY); + + immBegin(GPU_PRIM_LINES, 16); + /* bottom left */ - glVertex2f(x1, y1); - glVertex2f(x1, y1 + 5); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y1 + 5); - glVertex2f(x1, y1); - glVertex2f(x1 + 5, y1); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1 + 5, y1); /* top right */ - glVertex2f(x2, y2); - glVertex2f(x2, y2 - 5); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2, y2 - 5); - glVertex2f(x2, y2); - glVertex2f(x2 - 5, y2); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2 - 5, y2); /* top left */ - glVertex2f(x1, y2); - glVertex2f(x1, y2 - 5); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x1, y2 - 5); - glVertex2f(x1, y2); - glVertex2f(x1 + 5, y2); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x1 + 5, y2); /* bottom right */ - glVertex2f(x2, y1); - glVertex2f(x2, y1 + 5); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y1 + 5); + + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2 - 5, y1); - glVertex2f(x2, y1); - glVertex2f(x2 - 5, y1); - glEnd(); + immEnd(); + immUnbindProgram(); } static void fly_update_header(bContext *C, wmOperator *op, FlyInfo *fly) @@ -320,7 +284,7 @@ static void fly_update_header(bContext *C, wmOperator *op, FlyInfo *fly) #undef WM_MODALKEY - ED_area_headerprint(CTX_wm_area(C), header); + ED_workspace_status_text(C, header); } /* FlyInfo->state */ @@ -341,6 +305,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent fly->rv3d = CTX_wm_region_view3d(C); fly->v3d = CTX_wm_view3d(C); fly->ar = CTX_wm_region(C); + fly->depsgraph = CTX_data_depsgraph(C); fly->scene = CTX_data_scene(C); #ifdef NDOF_FLY_DEBUG @@ -407,12 +372,12 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent } fly->v3d_camera_control = ED_view3d_cameracontrol_acquire( - fly->scene, fly->v3d, fly->rv3d, + CTX_data_depsgraph(C), fly->scene, fly->v3d, fly->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); /* calculate center */ if (ED_view3d_cameracontrol_object_get(fly->v3d_camera_control)) { - ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); + ED_view3d_calc_camera_border(fly->scene, fly->depsgraph, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); fly->width = BLI_rctf_size_x(&viewborder); fly->height = BLI_rctf_size_y(&viewborder); @@ -1067,7 +1032,7 @@ static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event) } if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) - ED_area_headerprint(CTX_wm_area(C), NULL); + ED_workspace_status_text(C, NULL); return exit_code; } diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c new file mode 100644 index 00000000000..0a3d20979a0 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c @@ -0,0 +1,229 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_gizmo_armature.c + * \ingroup spview3d + */ + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_armature.h" +#include "BKE_action.h" +#include "BKE_context.h" +#include "BKE_object.h" + +#include "DNA_object_types.h" +#include "DNA_armature_types.h" + +#include "ED_armature.h" +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "view3d_intern.h" /* own include */ + + +/* -------------------------------------------------------------------- */ + +/** \name Armature Spline Gizmo + * + * \{ */ + +/* + * TODO(campbell): Current conversion is a approximation (usable not correct), + * we'll need to take the next/previous bones into account to get the tangent directions. + * First last matrices from 'BKE_pchan_bbone_spline_setup' are close but also not quite accurate + * since they're not at either end-points on the curve. + * + * Likely we'll need a function especially to get the first/last orientations. + */ + +#define BBONE_SCALE_Y 3.0f + +struct BoneSplineHandle { + wmGizmo *gizmo; + bPoseChannel *pchan; + /* We could remove, keep since at the moment for checking the conversion. */ + float co[3]; + int index; +}; + +struct BoneSplineWidgetGroup { + struct BoneSplineHandle handles[2]; +}; + +static void gizmo_bbone_offset_get( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, + void *value_p) +{ + struct BoneSplineHandle *bh = gz_prop->custom_func.user_data; + bPoseChannel *pchan = bh->pchan; + + float *value = value_p; + BLI_assert(gz_prop->type->array_length == 3); + + if (bh->index == 0) { + bh->co[1] = pchan->bone->ease1 / BBONE_SCALE_Y; + bh->co[0] = pchan->curveInX; + bh->co[2] = pchan->curveInY; + } + else { + bh->co[1] = -pchan->bone->ease2 / BBONE_SCALE_Y; + bh->co[0] = pchan->curveOutX; + bh->co[2] = pchan->curveOutY; + } + copy_v3_v3(value, bh->co); +} + +static void gizmo_bbone_offset_set( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, + const void *value_p) +{ + struct BoneSplineHandle *bh = gz_prop->custom_func.user_data; + bPoseChannel *pchan = bh->pchan; + + const float *value = value_p; + + BLI_assert(gz_prop->type->array_length == 3); + copy_v3_v3(bh->co, value); + + if (bh->index == 0) { + pchan->bone->ease1 = max_ff(0.0f, bh->co[1] * BBONE_SCALE_Y); + pchan->curveInX = bh->co[0]; + pchan->curveInY = bh->co[2]; + } + else { + pchan->bone->ease2 = max_ff(0.0f, -bh->co[1] * BBONE_SCALE_Y); + pchan->curveOutX = bh->co[0]; + pchan->curveOutY = bh->co[2]; + } + +} + +static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt)) +{ + Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + if (ob != NULL) { + const bArmature *arm = ob->data; + if (arm->drawtype == ARM_B_BONE) { + bPoseChannel *pchan = BKE_pose_channel_active(ob); + if (pchan && pchan->bone->segments > 1) { + View3D *v3d = CTX_wm_view3d(C); + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT))) + { + /* pass */ + } + else { + return true; + } + } + } + } + return false; +} + + +static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *gzgroup) +{ + Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + bPoseChannel *pchan = BKE_pose_channel_active(ob); + + const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true); + + struct BoneSplineWidgetGroup *bspline_group = MEM_callocN(sizeof(struct BoneSplineWidgetGroup), __func__); + gzgroup->customdata = bspline_group; + + /* Handles */ + for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) { + wmGizmo *gz; + gz = bspline_group->handles[i].gizmo = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL); + RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D); + RNA_enum_set(gz->ptr, "draw_options", + ED_GIZMO_MOVE_DRAW_FLAG_FILL | ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW); + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true); + + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); + + gz->scale_basis = 0.06f; + + if (i == 0) { + copy_v3_v3(gz->matrix_basis[3], pchan->loc); + } + } +} + +static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup *gzgroup) +{ + Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + + if (!gzgroup->customdata) + return; + + struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata; + bPoseChannel *pchan = BKE_pose_channel_active(ob); + + /* Handles */ + for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) { + wmGizmo *gz = bspline_group->handles[i].gizmo; + bspline_group->handles[i].pchan = pchan; + bspline_group->handles[i].index = i; + + float mat[4][4]; + mul_m4_m4m4(mat, ob->obmat, (i == 0) ? pchan->disp_mat : pchan->disp_tail_mat); + copy_m4_m4(gz->matrix_space, mat); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + WM_gizmo_target_property_def_func( + gz, "offset", + &(const struct wmGizmoPropertyFnParams) { + .value_get_fn = gizmo_bbone_offset_get, + .value_set_fn = gizmo_bbone_offset_set, + .range_get_fn = NULL, + .user_data = &bspline_group->handles[i], + }); + } +} + +void VIEW3D_GGT_armature_spline(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Armature Spline Widgets"; + gzgt->idname = "VIEW3D_GGT_armature_spline"; + + gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT | + WM_GIZMOGROUPTYPE_3D); + + gzgt->poll = WIDGETGROUP_armature_spline_poll; + gzgt->setup = WIDGETGROUP_armature_spline_setup; + gzgt->refresh = WIDGETGROUP_armature_spline_refresh; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c new file mode 100644 index 00000000000..3c29d4c407b --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c @@ -0,0 +1,472 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_gizmo_camera.c + * \ingroup spview3d + */ + + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_camera.h" +#include "BKE_context.h" + +#include "DNA_object_types.h" +#include "DNA_camera_types.h" + +#include "ED_armature.h" +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "WM_message.h" + +#include "view3d_intern.h" /* own include */ + + +/* -------------------------------------------------------------------- */ + +/** \name Camera Gizmos + * \{ */ + +struct CameraWidgetGroup { + wmGizmo *dop_dist; + wmGizmo *focal_len; + wmGizmo *ortho_scale; +}; + +static bool WIDGETGROUP_camera_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT))) + { + return false; + } + + Object *ob = CTX_data_active_object(C); + if (ob && ob->type == OB_CAMERA) { + Camera *camera = ob->data; + /* TODO: support overrides. */ + if (camera->id.lib == NULL) { + return true; + } + } + return false; +} + +static void WIDGETGROUP_camera_setup(const bContext *C, wmGizmoGroup *gzgroup) +{ + Object *ob = CTX_data_active_object(C); + float dir[3]; + + const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true); + + struct CameraWidgetGroup *cagzgroup = MEM_callocN(sizeof(struct CameraWidgetGroup), __func__); + gzgroup->customdata = cagzgroup; + + negate_v3_v3(dir, ob->obmat[2]); + + /* dof distance */ + { + wmGizmo *gz; + gz = cagzgroup->dop_dist = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); + RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_CROSS); + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_HOVER, true); + + UI_GetThemeColor3fv(TH_GIZMO_A, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); + } + + /* focal length + * - logic/calculations are similar to BKE_camera_view_frame_ex, better keep in sync */ + { + wmGizmo *gz; + gz = cagzgroup->focal_len = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); + gz->flag |= WM_GIZMO_DRAW_NO_SCALE; + RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_CONE); + RNA_enum_set(gz->ptr, "transform", ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED); + + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); + + gz = cagzgroup->ortho_scale = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); + gz->flag |= WM_GIZMO_DRAW_NO_SCALE; + RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_CONE); + RNA_enum_set(gz->ptr, "transform", ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED); + + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); + } +} + +static void WIDGETGROUP_camera_refresh(const bContext *C, wmGizmoGroup *gzgroup) +{ + if (!gzgroup->customdata) + return; + + struct CameraWidgetGroup *cagzgroup = gzgroup->customdata; + Object *ob = CTX_data_active_object(C); + Camera *ca = ob->data; + PointerRNA camera_ptr; + float dir[3]; + + RNA_pointer_create(&ca->id, &RNA_Camera, ca, &camera_ptr); + + negate_v3_v3(dir, ob->obmat[2]); + + if (ca->flag & CAM_SHOWLIMITS) { + WM_gizmo_set_matrix_location(cagzgroup->dop_dist, ob->obmat[3]); + WM_gizmo_set_matrix_rotation_from_yz_axis(cagzgroup->dop_dist, ob->obmat[1], dir); + WM_gizmo_set_scale(cagzgroup->dop_dist, ca->drawsize); + WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, false); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + WM_gizmo_target_property_def_rna(cagzgroup->dop_dist, "offset", &camera_ptr, "dof_distance", -1); + } + else { + WM_gizmo_set_flag(cagzgroup->dop_dist, WM_GIZMO_HIDDEN, true); + } + + /* TODO - make focal length/ortho ob_scale_inv widget optional */ + const Scene *scene = CTX_data_scene(C); + const float aspx = (float)scene->r.xsch * scene->r.xasp; + const float aspy = (float)scene->r.ysch * scene->r.yasp; + const bool is_ortho = (ca->type == CAM_ORTHO); + const int sensor_fit = BKE_camera_sensor_fit(ca->sensor_fit, aspx, aspy); + wmGizmo *widget = is_ortho ? cagzgroup->ortho_scale : cagzgroup->focal_len; + float scale_matrix; + if (true) { + float offset[3]; + float aspect[2]; + + WM_gizmo_set_flag(widget, WM_GIZMO_HIDDEN, false); + WM_gizmo_set_flag(is_ortho ? cagzgroup->focal_len : cagzgroup->ortho_scale, WM_GIZMO_HIDDEN, true); + + + /* account for lens shifting */ + offset[0] = ((ob->size[0] > 0.0f) ? -2.0f : 2.0f) * ca->shiftx; + offset[1] = 2.0f * ca->shifty; + offset[2] = 0.0f; + + /* get aspect */ + aspect[0] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? 1.0f : aspx / aspy; + aspect[1] = (sensor_fit == CAMERA_SENSOR_FIT_HOR) ? aspy / aspx : 1.0f; + + unit_m4(widget->matrix_basis); + WM_gizmo_set_matrix_location(widget, ob->obmat[3]); + WM_gizmo_set_matrix_rotation_from_yz_axis(widget, ob->obmat[1], dir); + + if (is_ortho) { + scale_matrix = ca->ortho_scale * 0.5f; + } + else { + const float ob_scale_inv[3] = { + 1.0f / len_v3(ob->obmat[0]), + 1.0f / len_v3(ob->obmat[1]), + 1.0f / len_v3(ob->obmat[2]), + }; + const float ob_scale_uniform_inv = (ob_scale_inv[0] + ob_scale_inv[1] + ob_scale_inv[2]) / 3.0f; + scale_matrix = (ca->drawsize * 0.5f) / ob_scale_uniform_inv; + } + mul_v3_fl(widget->matrix_basis[0], scale_matrix); + mul_v3_fl(widget->matrix_basis[1], scale_matrix); + + RNA_float_set_array(widget->ptr, "aspect", aspect); + + WM_gizmo_set_matrix_offset_location(widget, offset); + } + + /* define & update properties */ + { + const char *propname = is_ortho ? "ortho_scale" : "lens"; + PropertyRNA *prop = RNA_struct_find_property(&camera_ptr, propname); + const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(widget->type, "offset"); + + WM_gizmo_target_property_clear_rna_ptr(widget, gz_prop_type); + + float min, max, range; + float step, precision; + + /* get property range */ + RNA_property_float_ui_range(&camera_ptr, prop, &min, &max, &step, &precision); + range = max - min; + + ED_gizmo_arrow3d_set_range_fac( + widget, is_ortho ? + ((range / ca->ortho_scale) * ca->drawsize) : + (scale_matrix * range / + /* Half sensor, intentionally use sensor from camera and not calculated above. */ + (0.5f * ((sensor_fit == CAMERA_SENSOR_FIT_HOR) ? ca->sensor_x : ca->sensor_y)))); + + WM_gizmo_target_property_def_rna_ptr(widget, gz_prop_type, &camera_ptr, prop, -1); + } + +} + +static void WIDGETGROUP_camera_message_subscribe( + const bContext *C, wmGizmoGroup *gzgroup, struct wmMsgBus *mbus) +{ + ARegion *ar = CTX_wm_region(C); + Object *ob = CTX_data_active_object(C); + Camera *ca = ob->data; + + wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = { + .owner = ar, + .user_data = gzgroup->parent_gzmap, + .notify = WM_gizmo_do_msg_notify_tag_refresh, + }; + + { + extern PropertyRNA rna_Camera_dof_distance; + extern PropertyRNA rna_Camera_display_size; + extern PropertyRNA rna_Camera_ortho_scale; + extern PropertyRNA rna_Camera_sensor_fit; + extern PropertyRNA rna_Camera_sensor_width; + extern PropertyRNA rna_Camera_shift_x; + extern PropertyRNA rna_Camera_shift_y; + extern PropertyRNA rna_Camera_type; + extern PropertyRNA rna_Camera_lens; + const PropertyRNA *props[] = { + &rna_Camera_dof_distance, + &rna_Camera_display_size, + &rna_Camera_ortho_scale, + &rna_Camera_sensor_fit, + &rna_Camera_sensor_width, + &rna_Camera_shift_x, + &rna_Camera_shift_y, + &rna_Camera_type, + &rna_Camera_lens, + }; + + PointerRNA idptr; + RNA_id_pointer_create(&ca->id, &idptr); + + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_gz_tag_refresh, __func__); + } + } + + /* Subscribe to render settings */ + { + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_gz_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_gz_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_gz_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_gz_tag_refresh); + } +} + +void VIEW3D_GGT_camera(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Camera Widgets"; + gzgt->idname = "VIEW3D_GGT_camera"; + + gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT | + WM_GIZMOGROUPTYPE_3D | + WM_GIZMOGROUPTYPE_DEPTH_3D); + + gzgt->poll = WIDGETGROUP_camera_poll; + gzgt->setup = WIDGETGROUP_camera_setup; + gzgt->refresh = WIDGETGROUP_camera_refresh; + gzgt->message_subscribe = WIDGETGROUP_camera_message_subscribe; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name CameraView Gizmos + * \{ */ + +struct CameraViewWidgetGroup { + wmGizmo *border; + + struct { + rctf *edit_border; + rctf view_border; + } state; +}; + +/* scale callbacks */ +static void gizmo_render_border_prop_matrix_get( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, + void *value_p) +{ + float (*matrix)[4] = value_p; + BLI_assert(gz_prop->type->array_length == 16); + struct CameraViewWidgetGroup *viewgroup = gz_prop->custom_func.user_data; + const rctf *border = viewgroup->state.edit_border; + + unit_m4(matrix); + matrix[0][0] = BLI_rctf_size_x(border); + matrix[1][1] = BLI_rctf_size_y(border); + matrix[3][0] = BLI_rctf_cent_x(border); + matrix[3][1] = BLI_rctf_cent_y(border); +} + +static void gizmo_render_border_prop_matrix_set( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, + const void *value_p) +{ + const float (*matrix)[4] = value_p; + struct CameraViewWidgetGroup *viewgroup = gz_prop->custom_func.user_data; + rctf *border = viewgroup->state.edit_border; + BLI_assert(gz_prop->type->array_length == 16); + + BLI_rctf_resize(border, len_v3(matrix[0]), len_v3(matrix[1])); + BLI_rctf_recenter(border, matrix[3][0], matrix[3][1]); + BLI_rctf_isect(&(rctf){.xmin = 0, .ymin = 0, .xmax = 1, .ymax = 1}, border, border); +} + +static bool WIDGETGROUP_camera_view_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt)) +{ + Scene *scene = CTX_data_scene(C); + + /* This is just so the border isn't always in the way, + * stealing mouse clicks from regular usage. + * We could change the rules for when to show. */ + { + ViewLayer *view_layer = CTX_data_view_layer(C); + if (scene->camera != OBACT(view_layer)) { + return false; + } + } + + View3D *v3d = CTX_wm_view3d(C); + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT))) + { + return false; + } + + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + if (rv3d->persp == RV3D_CAMOB) { + if (scene->r.mode & R_BORDER) { + /* TODO: support overrides. */ + if (scene->id.lib == NULL) { + return true; + } + } + } + else if (v3d->flag2 & V3D_RENDER_BORDER) { + return true; + } + return false; +} + +static void WIDGETGROUP_camera_view_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + struct CameraViewWidgetGroup *viewgroup = MEM_mallocN(sizeof(struct CameraViewWidgetGroup), __func__); + + viewgroup->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL); + + RNA_enum_set(viewgroup->border->ptr, "transform", + ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE); + /* Box style is more subtle in this case. */ + RNA_enum_set(viewgroup->border->ptr, "draw_style", ED_GIZMO_CAGE2D_STYLE_BOX); + + + gzgroup->customdata = viewgroup; +} + +static void WIDGETGROUP_camera_view_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) +{ + struct CameraViewWidgetGroup *viewgroup = gzgroup->customdata; + + ARegion *ar = CTX_wm_region(C); + struct Depsgraph *depsgraph = CTX_data_depsgraph(C); + RegionView3D *rv3d = ar->regiondata; + if (rv3d->persp == RV3D_CAMOB) { + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &viewgroup->state.view_border, false); + } + else { + viewgroup->state.view_border = (rctf){.xmin = 0, .ymin = 0, .xmax = ar->winx, .ymax = ar->winy}; + } + + wmGizmo *gz = viewgroup->border; + unit_m4(gz->matrix_space); + mul_v3_fl(gz->matrix_space[0], BLI_rctf_size_x(&viewgroup->state.view_border)); + mul_v3_fl(gz->matrix_space[1], BLI_rctf_size_y(&viewgroup->state.view_border)); + gz->matrix_space[3][0] = viewgroup->state.view_border.xmin; + gz->matrix_space[3][1] = viewgroup->state.view_border.ymin; +} + +static void WIDGETGROUP_camera_view_refresh(const bContext *C, wmGizmoGroup *gzgroup) +{ + struct CameraViewWidgetGroup *viewgroup = gzgroup->customdata; + + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + Scene *scene = CTX_data_scene(C); + + { + wmGizmo *gz = viewgroup->border; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); + + RNA_enum_set(viewgroup->border->ptr, "transform", + ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE); + + if (rv3d->persp == RV3D_CAMOB) { + viewgroup->state.edit_border = &scene->r.border; + } + else { + viewgroup->state.edit_border = &v3d->render_border; + } + + WM_gizmo_target_property_def_func( + gz, "matrix", + &(const struct wmGizmoPropertyFnParams) { + .value_get_fn = gizmo_render_border_prop_matrix_get, + .value_set_fn = gizmo_render_border_prop_matrix_set, + .range_get_fn = NULL, + .user_data = viewgroup, + }); + } + +} + +void VIEW3D_GGT_camera_view(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Camera View Widgets"; + gzgt->idname = "VIEW3D_GGT_camera_view"; + + gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT | + WM_GIZMOGROUPTYPE_SCALE); + + gzgt->poll = WIDGETGROUP_camera_view_poll; + gzgt->setup = WIDGETGROUP_camera_view_setup; + gzgt->draw_prepare = WIDGETGROUP_camera_view_draw_prepare; + gzgt->refresh = WIDGETGROUP_camera_view_refresh; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_empty.c b/source/blender/editors/space_view3d/view3d_gizmo_empty.c new file mode 100644 index 00000000000..df1ae8c82e9 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c @@ -0,0 +1,210 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_gizmo_empty.c + * \ingroup spview3d + */ + + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_object.h" +#include "BKE_image.h" + +#include "DEG_depsgraph.h" + +#include "DNA_object_types.h" +#include "DNA_lamp_types.h" + +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ + +/** \name Empty Image Gizmos + * \{ */ + +struct EmptyImageWidgetGroup { + wmGizmo *gizmo; + struct { + Object *ob; + float dims[2]; + } state; +}; + +/* translate callbacks */ +static void gizmo_empty_image_prop_matrix_get( + const wmGizmo *gz, wmGizmoProperty *gz_prop, + void *value_p) +{ + float (*matrix)[4] = value_p; + BLI_assert(gz_prop->type->array_length == 16); + struct EmptyImageWidgetGroup *igzgroup = gz_prop->custom_func.user_data; + const Object *ob = igzgroup->state.ob; + + unit_m4(matrix); + matrix[0][0] = ob->empty_drawsize; + matrix[1][1] = ob->empty_drawsize; + + float dims[2] = {0.0f, 0.0f}; + RNA_float_get_array(gz->ptr, "dimensions", dims); + dims[0] *= ob->empty_drawsize; + dims[1] *= ob->empty_drawsize; + + matrix[3][0] = (ob->ima_ofs[0] * dims[0]) + (0.5f * dims[0]); + matrix[3][1] = (ob->ima_ofs[1] * dims[1]) + (0.5f * dims[1]); +} + +static void gizmo_empty_image_prop_matrix_set( + const wmGizmo *gz, wmGizmoProperty *gz_prop, + const void *value_p) +{ + const float (*matrix)[4] = value_p; + BLI_assert(gz_prop->type->array_length == 16); + struct EmptyImageWidgetGroup *igzgroup = gz_prop->custom_func.user_data; + Object *ob = igzgroup->state.ob; + + ob->empty_drawsize = matrix[0][0]; + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + + float dims[2]; + RNA_float_get_array(gz->ptr, "dimensions", dims); + dims[0] *= ob->empty_drawsize; + dims[1] *= ob->empty_drawsize; + + ob->ima_ofs[0] = (matrix[3][0] - (0.5f * dims[0])) / dims[0]; + ob->ima_ofs[1] = (matrix[3][1] - (0.5f * dims[1])) / dims[1]; +} + +static bool WIDGETGROUP_empty_image_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = CTX_wm_region_view3d(C); + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT))) + { + return false; + } + + Object *ob = CTX_data_active_object(C); + + if (ob && ob->type == OB_EMPTY) { + if (ob->empty_drawtype == OB_EMPTY_IMAGE) { + return BKE_object_empty_image_is_visible_in_view3d(ob, rv3d); + } + } + return false; +} + +static void WIDGETGROUP_empty_image_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + struct EmptyImageWidgetGroup *igzgroup = MEM_mallocN(sizeof(struct EmptyImageWidgetGroup), __func__); + igzgroup->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL); + wmGizmo *gz = igzgroup->gizmo; + RNA_enum_set(gz->ptr, "transform", + ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE); + + gzgroup->customdata = igzgroup; + + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_HOVER, true); + + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); +} + +static void WIDGETGROUP_empty_image_refresh(const bContext *C, wmGizmoGroup *gzgroup) +{ + struct EmptyImageWidgetGroup *igzgroup = gzgroup->customdata; + Object *ob = CTX_data_active_object(C); + wmGizmo *gz = igzgroup->gizmo; + + copy_m4_m4(gz->matrix_basis, ob->obmat); + + RNA_enum_set(gz->ptr, "transform", + ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | + ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE | + ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM); + + igzgroup->state.ob = ob; + + /* Use dimensions for aspect. */ + if (ob->data != NULL) { + const Image *image = ob->data; + ImageUser iuser = *ob->iuser; + float size[2]; + BKE_image_get_size_fl(ob->data, &iuser, size); + + /* Get the image aspect even if the buffer is invalid */ + if (image->aspx > image->aspy) { + size[1] *= image->aspy / image->aspx; + } + else if (image->aspx < image->aspy) { + size[0] *= image->aspx / image->aspy; + } + + const float dims_max = max_ff(size[0], size[1]); + igzgroup->state.dims[0] = size[0] / dims_max; + igzgroup->state.dims[1] = size[1] / dims_max; + } + else { + copy_v2_fl(igzgroup->state.dims, 1.0f); + } + RNA_float_set_array(gz->ptr, "dimensions", igzgroup->state.dims); + + WM_gizmo_target_property_def_func( + gz, "matrix", + &(const struct wmGizmoPropertyFnParams) { + .value_get_fn = gizmo_empty_image_prop_matrix_get, + .value_set_fn = gizmo_empty_image_prop_matrix_set, + .range_get_fn = NULL, + .user_data = igzgroup, + }); +} + +void VIEW3D_GGT_empty_image(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Area Light Widgets"; + gzgt->idname = "VIEW3D_GGT_empty_image"; + + gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT | + WM_GIZMOGROUPTYPE_3D | + WM_GIZMOGROUPTYPE_DEPTH_3D); + + gzgt->poll = WIDGETGROUP_empty_image_poll; + gzgt->setup = WIDGETGROUP_empty_image_setup; + gzgt->refresh = WIDGETGROUP_empty_image_refresh; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c new file mode 100644 index 00000000000..e2a8d2802e7 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c @@ -0,0 +1,125 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_gizmo_forcefield.c + * \ingroup spview3d + */ + + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_object.h" + +#include "DNA_object_types.h" +#include "DNA_object_force_types.h" + +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ + +/** \name Force Field Gizmos + * \{ */ + +static bool WIDGETGROUP_forcefield_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT))) + { + return false; + } + + Object *ob = CTX_data_active_object(C); + + return (ob && ob->pd && ob->pd->forcefield); +} + +static void WIDGETGROUP_forcefield_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + /* only wind effector for now */ + wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__); + gzgroup->customdata = wwrapper; + + wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_arrow_3d", gzgroup, NULL); + wmGizmo *gz = wwrapper->gizmo; + RNA_enum_set(gz->ptr, "transform", ED_GIZMO_ARROW_XFORM_FLAG_CONSTRAINED); + ED_gizmo_arrow3d_set_ui_range(gz, -200.0f, 200.0f); + ED_gizmo_arrow3d_set_range_fac(gz, 6.0f); + + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); +} + +static void WIDGETGROUP_forcefield_refresh(const bContext *C, wmGizmoGroup *gzgroup) +{ + wmGizmoWrapper *wwrapper = gzgroup->customdata; + wmGizmo *gz = wwrapper->gizmo; + Object *ob = CTX_data_active_object(C); + PartDeflect *pd = ob->pd; + + if (pd->forcefield == PFIELD_WIND) { + const float size = (ob->type == OB_EMPTY) ? ob->empty_drawsize : 1.0f; + const float ofs[3] = {0.0f, -size, 0.0f}; + PointerRNA field_ptr; + + RNA_pointer_create(&ob->id, &RNA_FieldSettings, pd, &field_ptr); + WM_gizmo_set_matrix_location(gz, ob->obmat[3]); + WM_gizmo_set_matrix_rotation_from_z_axis(gz, ob->obmat[2]); + WM_gizmo_set_matrix_offset_location(gz, ofs); + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); + WM_gizmo_target_property_def_rna(gz, "offset", &field_ptr, "strength", -1); + } + else { + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); + } +} + +void VIEW3D_GGT_force_field(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Force Field Widgets"; + gzgt->idname = "VIEW3D_GGT_force_field"; + + gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT | + WM_GIZMOGROUPTYPE_3D | + WM_GIZMOGROUPTYPE_SCALE | + WM_GIZMOGROUPTYPE_DEPTH_3D); + + gzgt->poll = WIDGETGROUP_forcefield_poll; + gzgt->setup = WIDGETGROUP_forcefield_setup; + gzgt->refresh = WIDGETGROUP_forcefield_refresh; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_lamp.c b/source/blender/editors/space_view3d/view3d_gizmo_lamp.c new file mode 100644 index 00000000000..3eaddce582b --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_lamp.c @@ -0,0 +1,307 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_gizmo_lamp.c + * \ingroup spview3d + */ + + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_object.h" + +#include "DNA_object_types.h" +#include "DNA_lamp_types.h" + +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ + +/** \name Spot Lamp Gizmos + * \{ */ + +static bool WIDGETGROUP_lamp_spot_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT))) + { + return false; + } + + Object *ob = CTX_data_active_object(C); + + if (ob && ob->type == OB_LAMP) { + Lamp *la = ob->data; + return (la->type == LA_SPOT); + } + return false; +} + +static void WIDGETGROUP_lamp_spot_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__); + + wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_arrow_3d", gzgroup, NULL); + wmGizmo *gz = wwrapper->gizmo; + RNA_enum_set(gz->ptr, "transform", ED_GIZMO_ARROW_XFORM_FLAG_INVERTED); + + gzgroup->customdata = wwrapper; + + ED_gizmo_arrow3d_set_range_fac(gz, 4.0f); + + UI_GetThemeColor3fv(TH_GIZMO_SECONDARY, gz->color); +} + +static void WIDGETGROUP_lamp_spot_refresh(const bContext *C, wmGizmoGroup *gzgroup) +{ + wmGizmoWrapper *wwrapper = gzgroup->customdata; + wmGizmo *gz = wwrapper->gizmo; + Object *ob = CTX_data_active_object(C); + Lamp *la = ob->data; + float dir[3]; + + negate_v3_v3(dir, ob->obmat[2]); + + WM_gizmo_set_matrix_rotation_from_z_axis(gz, dir); + WM_gizmo_set_matrix_location(gz, ob->obmat[3]); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + PointerRNA lamp_ptr; + const char *propname = "spot_size"; + RNA_pointer_create(&la->id, &RNA_Light, la, &lamp_ptr); + WM_gizmo_target_property_def_rna(gz, "offset", &lamp_ptr, propname, -1); +} + +void VIEW3D_GGT_lamp_spot(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Spot Light Widgets"; + gzgt->idname = "VIEW3D_GGT_lamp_spot"; + + gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT | + WM_GIZMOGROUPTYPE_3D | + WM_GIZMOGROUPTYPE_DEPTH_3D); + + gzgt->poll = WIDGETGROUP_lamp_spot_poll; + gzgt->setup = WIDGETGROUP_lamp_spot_setup; + gzgt->refresh = WIDGETGROUP_lamp_spot_refresh; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Area Lamp Gizmos + * \{ */ + +/* scale callbacks */ +static void gizmo_area_lamp_prop_matrix_get( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, + void *value_p) +{ + BLI_assert(gz_prop->type->array_length == 16); + float (*matrix)[4] = value_p; + const Lamp *la = gz_prop->custom_func.user_data; + + matrix[0][0] = la->area_size; + matrix[1][1] = ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE) ? la->area_sizey : la->area_size; +} + +static void gizmo_area_lamp_prop_matrix_set( + const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, + const void *value_p) +{ + const float (*matrix)[4] = value_p; + BLI_assert(gz_prop->type->array_length == 16); + Lamp *la = gz_prop->custom_func.user_data; + + if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_ELLIPSE)) { + la->area_size = len_v3(matrix[0]); + la->area_sizey = len_v3(matrix[1]); + } + else { + la->area_size = len_v3(matrix[0]); + } +} + +static bool WIDGETGROUP_lamp_area_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + + Object *ob = CTX_data_active_object(C); + if (ob && ob->type == OB_LAMP) { + Lamp *la = ob->data; + return (la->type == LA_AREA); + } + return false; +} + +static void WIDGETGROUP_lamp_area_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__); + wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL); + wmGizmo *gz = wwrapper->gizmo; + RNA_enum_set(gz->ptr, "transform", + ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE); + + gzgroup->customdata = wwrapper; + + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_HOVER, true); + + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); +} + +static void WIDGETGROUP_lamp_area_refresh(const bContext *C, wmGizmoGroup *gzgroup) +{ + wmGizmoWrapper *wwrapper = gzgroup->customdata; + Object *ob = CTX_data_active_object(C); + Lamp *la = ob->data; + wmGizmo *gz = wwrapper->gizmo; + + copy_m4_m4(gz->matrix_basis, ob->obmat); + + int flag = ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE; + if (ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_DISK)) { + flag |= ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE_UNIFORM; + } + RNA_enum_set(gz->ptr, "transform", flag); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + WM_gizmo_target_property_def_func( + gz, "matrix", + &(const struct wmGizmoPropertyFnParams) { + .value_get_fn = gizmo_area_lamp_prop_matrix_get, + .value_set_fn = gizmo_area_lamp_prop_matrix_set, + .range_get_fn = NULL, + .user_data = la, + }); +} + +void VIEW3D_GGT_lamp_area(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Area Light Widgets"; + gzgt->idname = "VIEW3D_GGT_lamp_area"; + + gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT | + WM_GIZMOGROUPTYPE_3D | + WM_GIZMOGROUPTYPE_DEPTH_3D); + + gzgt->poll = WIDGETGROUP_lamp_area_poll; + gzgt->setup = WIDGETGROUP_lamp_area_setup; + gzgt->refresh = WIDGETGROUP_lamp_area_refresh; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Lamp Target Gizmo + * \{ */ + +static bool WIDGETGROUP_lamp_target_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + return false; + } + + Object *ob = CTX_data_active_object(C); + + if (ob != NULL) { + if (ob->type == OB_LAMP) { + Lamp *la = ob->data; + return (ELEM(la->type, LA_SUN, LA_SPOT, LA_AREA)); + } +#if 0 + else if (ob->type == OB_CAMERA) { + return true; + } +#endif + } + return false; +} + +static void WIDGETGROUP_lamp_target_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__); + wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, NULL); + wmGizmo *gz = wwrapper->gizmo; + + gzgroup->customdata = wwrapper; + + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); + + gz->scale_basis = 0.06f; + + wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_transform_axis_target", true); + + RNA_enum_set(gz->ptr, "draw_options", + ED_GIZMO_MOVE_DRAW_FLAG_FILL | ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW); + + WM_gizmo_operator_set(gz, 0, ot, NULL); +} + +static void WIDGETGROUP_lamp_target_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) +{ + wmGizmoWrapper *wwrapper = gzgroup->customdata; + Object *ob = CTX_data_active_object(C); + wmGizmo *gz = wwrapper->gizmo; + + copy_m4_m4(gz->matrix_basis, ob->obmat); + unit_m4(gz->matrix_offset); + gz->matrix_offset[3][2] = -2.4f / gz->scale_basis; + WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_OFFSET_SCALE, true); +} + +void VIEW3D_GGT_lamp_target(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Target Light Widgets"; + gzgt->idname = "VIEW3D_GGT_lamp_target"; + + gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT | + WM_GIZMOGROUPTYPE_3D); + + gzgt->poll = WIDGETGROUP_lamp_target_poll; + gzgt->setup = WIDGETGROUP_lamp_target_setup; + gzgt->draw_prepare = WIDGETGROUP_lamp_target_draw_prepare; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c new file mode 100644 index 00000000000..d45da76a477 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c @@ -0,0 +1,325 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_gizmo_navigate.c + * \ingroup spview3d + */ + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_object.h" + +#include "DNA_object_types.h" + +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name View3D Navigation Gizmo Group + * \{ */ + +/* Offset from screen edge. */ +#define GIZMO_OFFSET_FAC 1.2f +/* Size of main icon. */ +#define GIZMO_SIZE 80 +/* Factor for size of smaller button. */ +#define GIZMO_MINI_FAC 0.35f +/* How much mini buttons offset from the primary. */ +#define GIZMO_MINI_OFFSET_FAC 0.38f + + +enum { + MPR_MOVE = 0, + MPR_ROTATE = 1, + MPR_ZOOM = 2, + + /* just buttons */ + /* overlaps MPR_ORTHO (switch between) */ + MPR_PERSP = 3, + MPR_ORTHO = 4, + MPR_CAMERA = 5, + + MPR_TOTAL = 6, +}; + +struct NavigateGizmoInfo { + const char *opname; + const char *gizmo; + uint icon; +}; + +static struct NavigateGizmoInfo g_navigate_params[MPR_TOTAL] = { + { + .opname = "VIEW3D_OT_move", + .gizmo = "GIZMO_GT_button_2d", + ICON_VIEW_PAN, + }, { + .opname = "VIEW3D_OT_rotate", + .gizmo = "VIEW3D_GT_navigate_rotate", + 0, + }, { + .opname = "VIEW3D_OT_zoom", + .gizmo = "GIZMO_GT_button_2d", + ICON_VIEW_ZOOM, + }, { + .opname = "VIEW3D_OT_view_persportho", + .gizmo = "GIZMO_GT_button_2d", + ICON_VIEW_PERSPECTIVE, + }, { + .opname = "VIEW3D_OT_view_persportho", + .gizmo = "GIZMO_GT_button_2d", + ICON_VIEW_ORTHO, + }, { + .opname = "VIEW3D_OT_view_camera", + .gizmo = "GIZMO_GT_button_2d", + ICON_VIEW_CAMERA, + }, +}; + +struct NavigateWidgetGroup { + wmGizmo *gz_array[MPR_TOTAL]; + /* Store the view state to check for changes. */ + struct { + rcti rect_visible; + struct { + char is_persp; + char is_camera; + char viewlock; + } rv3d; + } state; + int region_size[2]; +}; + +static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + if (((U.uiflag & USER_SHOW_GIZMO_AXIS) == 0) || + (v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_NAVIGATE))) + { + return false; + } + return true; + +} + +static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + struct NavigateWidgetGroup *navgroup = MEM_callocN(sizeof(struct NavigateWidgetGroup), __func__); + + navgroup->region_size[0] = -1; + navgroup->region_size[1] = -1; + + wmOperatorType *ot_view_axis = WM_operatortype_find("VIEW3D_OT_view_axis", true); + wmOperatorType *ot_view_camera = WM_operatortype_find("VIEW3D_OT_view_camera", true); + + for (int i = 0; i < MPR_TOTAL; i++) { + const struct NavigateGizmoInfo *info = &g_navigate_params[i]; + navgroup->gz_array[i] = WM_gizmo_new(info->gizmo, gzgroup, NULL); + wmGizmo *gz = navgroup->gz_array[i]; + gz->flag |= WM_GIZMO_MOVE_CURSOR | WM_GIZMO_DRAW_MODAL; + + if (i == MPR_ROTATE) { + gz->color[3] = 0.0f; + gz->color_hi[3] = 0.1f; + } + else { + UI_GetThemeColorShade3fv(TH_HEADER, -40, gz->color); + UI_GetThemeColorShade3fv(TH_HEADER, 160, gz->color_hi); + gz->color[3] = 0.4f; + gz->color_hi[3] = 0.2f; + } + + + /* may be overwritten later */ + gz->scale_basis = (GIZMO_SIZE * GIZMO_MINI_FAC) / 2; + if (info->icon != 0) { + PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon"); + RNA_property_enum_set(gz->ptr, prop, info->icon); + RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_OUTLINE | ED_GIZMO_BUTTON_SHOW_BACKDROP); + } + + wmOperatorType *ot = WM_operatortype_find(info->opname, true); + WM_gizmo_operator_set(gz, 0, ot, NULL); + } + + { + wmGizmo *gz = navgroup->gz_array[MPR_CAMERA]; + WM_gizmo_operator_set(gz, 0, ot_view_camera, NULL); + } + + /* Click only buttons (not modal). */ + { + int gz_ids[] = {MPR_PERSP, MPR_ORTHO, MPR_CAMERA}; + for (int i = 0; i < ARRAY_SIZE(gz_ids); i++) { + wmGizmo *gz = navgroup->gz_array[gz_ids[i]]; + RNA_boolean_set(gz->ptr, "show_drag", false); + } + } + + /* Modal operators, don't use initial mouse location since we're clicking on a button. */ + { + int gz_ids[] = {MPR_MOVE, MPR_ROTATE, MPR_ZOOM}; + for (int i = 0; i < ARRAY_SIZE(gz_ids); i++) { + wmGizmo *gz = navgroup->gz_array[gz_ids[i]]; + wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0); + RNA_boolean_set(&gzop->ptr, "use_mouse_init", false); + } + } + + { + wmGizmo *gz = navgroup->gz_array[MPR_ROTATE]; + gz->scale_basis = GIZMO_SIZE / 2; + char mapping[6] = { + RV3D_VIEW_LEFT, + RV3D_VIEW_RIGHT, + RV3D_VIEW_FRONT, + RV3D_VIEW_BACK, + RV3D_VIEW_BOTTOM, + RV3D_VIEW_TOP, + }; + + for (int part_index = 0; part_index < 6; part_index += 1) { + PointerRNA *ptr = WM_gizmo_operator_set(gz, part_index + 1, ot_view_axis, NULL); + RNA_enum_set(ptr, "type", mapping[part_index]); + } + + /* When dragging an axis, use this instead. */ + gz->drag_part = 0; + } + + gzgroup->customdata = navgroup; +} + +static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) +{ + struct NavigateWidgetGroup *navgroup = gzgroup->customdata; + ARegion *ar = CTX_wm_region(C); + const RegionView3D *rv3d = ar->regiondata; + + for (int i = 0; i < 3; i++) { + copy_v3_v3(navgroup->gz_array[MPR_ROTATE]->matrix_offset[i], rv3d->viewmat[i]); + } + + rcti rect_visible; + ED_region_visible_rect(ar, &rect_visible); + + if ((navgroup->state.rect_visible.xmax == rect_visible.xmax) && + (navgroup->state.rect_visible.ymax == rect_visible.ymax) && + (navgroup->state.rv3d.is_persp == rv3d->is_persp) && + (navgroup->state.rv3d.is_camera == (rv3d->persp == RV3D_CAMOB)) && + (navgroup->state.rv3d.viewlock == rv3d->viewlock)) + { + return; + } + + navgroup->state.rect_visible = rect_visible; + navgroup->state.rv3d.is_persp = rv3d->is_persp; + navgroup->state.rv3d.is_camera = (rv3d->persp == RV3D_CAMOB); + navgroup->state.rv3d.viewlock = rv3d->viewlock; + + const bool show_rotate = ( + ((rv3d->viewlock & RV3D_LOCKED) == 0) && + (navgroup->state.rv3d.is_camera == false)); + const bool show_fixed_offset = navgroup->state.rv3d.is_camera; + const float icon_size = GIZMO_SIZE; + const float icon_offset = (icon_size * 0.52f) * GIZMO_OFFSET_FAC * UI_DPI_FAC; + const float icon_offset_mini = icon_size * GIZMO_MINI_OFFSET_FAC * UI_DPI_FAC; + const float co_rotate[2] = { + rect_visible.xmax - icon_offset, + rect_visible.ymax - icon_offset, + }; + const float co[2] = { + rect_visible.xmax - ((show_rotate || show_fixed_offset) ? (icon_offset * 2.0f) : (icon_offset_mini * 0.75f)), + rect_visible.ymax - icon_offset_mini * 0.75f, + }; + + wmGizmo *gz; + + for (uint i = 0; i < ARRAY_SIZE(navgroup->gz_array); i++) { + gz = navgroup->gz_array[i]; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); + } + + /* RV3D_LOCKED or Camera: only show supported buttons. */ + if (show_rotate) { + gz = navgroup->gz_array[MPR_ROTATE]; + gz->matrix_basis[3][0] = co_rotate[0]; + gz->matrix_basis[3][1] = co_rotate[1]; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); + } + + int icon_mini_slot = 0; + + gz = navgroup->gz_array[MPR_ZOOM]; + gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); + gz->matrix_basis[3][1] = co[1]; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); + + gz = navgroup->gz_array[MPR_MOVE]; + gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); + gz->matrix_basis[3][1] = co[1]; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); + + if ((rv3d->viewlock & RV3D_LOCKED) == 0) { + gz = navgroup->gz_array[MPR_CAMERA]; + gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); + gz->matrix_basis[3][1] = co[1]; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); + + if (navgroup->state.rv3d.is_camera == false) { + gz = navgroup->gz_array[rv3d->is_persp ? MPR_PERSP : MPR_ORTHO]; + gz->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); + gz->matrix_basis[3][1] = co[1]; + WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); + } + } +} + +void VIEW3D_GGT_navigate(wmGizmoGroupType *gzgt) +{ + gzgt->name = "View3D Navigate"; + gzgt->idname = "VIEW3D_GGT_navigate"; + + gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT | + WM_GIZMOGROUPTYPE_SCALE | + WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL); + + gzgt->poll = WIDGETGROUP_navigate_poll; + gzgt->setup = WIDGETGROUP_navigate_setup; + gzgt->draw_prepare = WIDGETGROUP_navigate_draw_prepare; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c new file mode 100644 index 00000000000..f57ff4464e0 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c @@ -0,0 +1,535 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file view3d_gizmo_navigate_type.c + * \ingroup wm + * + * \name Custom Orientation/Navigation Gizmo for the 3D View + * + * \brief Simple gizmo to axis and translate. + * + * - scale_basis: used for the size. + * - matrix_basis: used for the location. + * - matrix_offset: used to store the orientation. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_sort_utils.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_state.h" +#include "GPU_batch.h" +#include "GPU_batch_presets.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" + +#include "view3d_intern.h" + +#define USE_AXIS_FONT +#define USE_FADE_BACKGROUND + +#ifdef USE_AXIS_FONT +# include "BLF_api.h" +#endif + +#define DIAL_RESOLUTION 32 + +/* Sizes of axis spheres containing XYZ characters. */ +#define AXIS_HANDLE_SIZE_FG 0.19f +/* When pointing away from the view. */ +#define AXIS_HANDLE_SIZE_BG 0.15f +/* How far axis handles are away from the center. */ +#define AXIS_HANDLE_OFFSET (1.0f - AXIS_HANDLE_SIZE_FG) + +struct AxisDrawInfo { + /* Matrix is needed for screen-aligned font drawing. */ +#ifdef USE_AXIS_FONT + float matrix_final[4][4]; +#endif +#ifdef USE_FADE_BACKGROUND + float color_bg[3]; +#endif +}; + +#ifndef USE_AXIS_FONT +/** + * \param viewmat_local_unit: is typically the 'rv3d->viewmatob' + * copied into a 3x3 matrix and normalized. + */ +static void draw_xyz_wire( + uint pos_id, const float viewmat_local_unit[3][3], const float c[3], float size, int axis) +{ + int line_type; + float buffer[4][3]; + int n = 0; + + float v1[3] = {0.0f, 0.0f, 0.0f}, v2[3] = {0.0f, 0.0f, 0.0f}; + float dim = size * 0.1f; + float dx[3], dy[3]; + + dx[0] = dim; dx[1] = 0.0f; dx[2] = 0.0f; + dy[0] = 0.0f; dy[1] = dim; dy[2] = 0.0f; + + switch (axis) { + case 0: /* x axis */ + line_type = GPU_PRIM_LINES; + + /* bottom left to top right */ + negate_v3_v3(v1, dx); + sub_v3_v3(v1, dy); + copy_v3_v3(v2, dx); + add_v3_v3(v2, dy); + + copy_v3_v3(buffer[n++], v1); + copy_v3_v3(buffer[n++], v2); + + /* top left to bottom right */ + mul_v3_fl(dy, 2.0f); + add_v3_v3(v1, dy); + sub_v3_v3(v2, dy); + + copy_v3_v3(buffer[n++], v1); + copy_v3_v3(buffer[n++], v2); + + break; + case 1: /* y axis */ + line_type = GPU_PRIM_LINES; + + /* bottom left to top right */ + mul_v3_fl(dx, 0.75f); + negate_v3_v3(v1, dx); + sub_v3_v3(v1, dy); + copy_v3_v3(v2, dx); + add_v3_v3(v2, dy); + + copy_v3_v3(buffer[n++], v1); + copy_v3_v3(buffer[n++], v2); + + /* top left to center */ + mul_v3_fl(dy, 2.0f); + add_v3_v3(v1, dy); + zero_v3(v2); + + copy_v3_v3(buffer[n++], v1); + copy_v3_v3(buffer[n++], v2); + + break; + case 2: /* z axis */ + line_type = GPU_PRIM_LINE_STRIP; + + /* start at top left */ + negate_v3_v3(v1, dx); + add_v3_v3(v1, dy); + + copy_v3_v3(buffer[n++], v1); + + mul_v3_fl(dx, 2.0f); + add_v3_v3(v1, dx); + + copy_v3_v3(buffer[n++], v1); + + mul_v3_fl(dy, 2.0f); + sub_v3_v3(v1, dx); + sub_v3_v3(v1, dy); + + copy_v3_v3(buffer[n++], v1); + + add_v3_v3(v1, dx); + + copy_v3_v3(buffer[n++], v1); + + break; + default: + BLI_assert(0); + return; + } + + for (int i = 0; i < n; i++) { + mul_transposed_m3_v3((float (*)[3])viewmat_local_unit, buffer[i]); + add_v3_v3(buffer[i], c); + } + + immBegin(line_type, n); + for (int i = 0; i < n; i++) { + immVertex3fv(pos_id, buffer[i]); + } + immEnd(); +} +#endif /* !USE_AXIS_FONT */ + +/** + * \param draw_info: Extra data needed for drawing. + */ +static void axis_geom_draw( + const wmGizmo *gz, const float color[4], const bool select, + const struct AxisDrawInfo *draw_info) +{ + GPU_line_width(gz->line_width); + + GPUVertFormat *format = immVertexFormat(); + const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + struct { + float depth; + char index; + char axis; + bool is_pos; + } axis_order[6] = { + {-gz->matrix_offset[0][2], 0, 0, false}, + {+gz->matrix_offset[0][2], 1, 0, true}, + {-gz->matrix_offset[1][2], 2, 1, false}, + {+gz->matrix_offset[1][2], 3, 1, true}, + {-gz->matrix_offset[2][2], 4, 2, false}, + {+gz->matrix_offset[2][2], 5, 2, true}, + }; + + int axis_align = -1; + for (int axis = 0; axis < 3; axis++) { + if (len_squared_v2(gz->matrix_offset[axis]) < 1e-6f) { + axis_align = axis; + break; + } + } + + /* Show backwards pointing highlight on-top (else we can't see it at all). */ + if ((select == false) && (gz->highlight_part > 0) && (axis_align != -1)) { + if (axis_order[gz->highlight_part - 1].is_pos == false) { + axis_order[gz->highlight_part - 1].depth = FLT_MAX; + } + } + + qsort(&axis_order, ARRAY_SIZE(axis_order), sizeof(axis_order[0]), BLI_sortutil_cmp_float); + + static const float axis_highlight[4] = {1, 1, 1, 1}; + static const float axis_black[4] = {0, 0, 0, 1}; + static float axis_color[3][4]; + + const float axis_depth_bias = 0.01f; + +#ifdef USE_AXIS_FONT + struct { + float matrix[4][4]; + int id; + } font; + + if (select == false) { + font.id = blf_mono_font; + BLF_disable(font.id, BLF_ROTATION | BLF_SHADOW | BLF_MATRIX | BLF_ASPECT | BLF_WORD_WRAP); + BLF_color4fv(font.id, axis_black); + BLF_size(font.id, 11 * U.dpi_fac, 72); + + /* Calculate the inverse of the (matrix_final * matrix_offset). + * This allows us to use the final location, while reversing the rotation so fonts + * show without any rotation. */ + float m3[3][3]; + float m3_offset[3][3]; + copy_m3_m4(m3, draw_info->matrix_final); + copy_m3_m4(m3_offset, gz->matrix_offset); + mul_m3_m3m3(m3, m3, m3_offset); + invert_m3(m3); + copy_m4_m3(font.matrix, m3); + } +#endif + + GPU_matrix_push(); + GPU_matrix_mul(gz->matrix_offset); + + bool draw_center_done = false; + + for (int axis_index = 0; axis_index < ARRAY_SIZE(axis_order); axis_index++) { + const int index = axis_order[axis_index].index; + const int axis = axis_order[axis_index].axis; + const bool is_pos = axis_order[axis_index].is_pos; + const bool is_highlight = index + 1 == gz->highlight_part; + + /* Draw slightly before, so axis aligned arrows draw ontop. */ + if ((draw_center_done == false) && (axis_order[axis_index].depth > -axis_depth_bias)) { + + /* Circle defining active area (revert back to 2D space). */ + if (color[3] != 0.0f) { + GPU_matrix_pop(); + immUniformColor4fv(color); + imm_draw_circle_fill_3d(pos_id, 0, 0, 1.0f, DIAL_RESOLUTION); + GPU_matrix_push(); + GPU_matrix_mul(gz->matrix_offset); + } + draw_center_done = true; + } + UI_GetThemeColor3fv(TH_AXIS_X + axis, axis_color[axis]); + axis_color[axis][3] = 1.0f; + + const int index_z = axis; + const int index_y = (axis + 1) % 3; + const int index_x = (axis + 2) % 3; + + bool ok = true; + + /* Skip view align axis when selecting (allows to switch to opposite side). */ + if (select && ((axis_align == axis) && (gz->matrix_offset[axis][2] > 0.0f) == is_pos)) { + ok = false; + } + if (ok) { + /* Check aligned, since the front axis won't display in this case, + * and we want to make sure all 3 axes have a character at all times. */ + const bool show_axis_char = (is_pos || (axis == axis_align)); + const float v[3] = {0, 0, AXIS_HANDLE_OFFSET * (is_pos ? 1 : -1)}; + const float v_final[3] = {v[index_x], v[index_y], v[index_z]}; + const float *color_current = is_highlight ? axis_highlight : axis_color[axis]; + float color_current_fade[4]; + + /* Flip the faded state when axis aligned, since we're hiding the front-mode axis + * otherwise we see the color for the back-most axis, which is useful for + * click-to-rotate 180d but not useful to visualize. + * + * Use depth bias so axis-aligned views show the positive axis as being in-front. + * This is a detail so primary axes show as dominant. + */ + const bool is_pos_color = ( + axis_order[axis_index].depth > (axis_depth_bias * (is_pos ? -1 : 1))); + + + if (select == false) { +#ifdef USE_FADE_BACKGROUND + interp_v3_v3v3(color_current_fade, draw_info->color_bg, color_current, is_highlight ? 1.0 : 0.5f); + color_current_fade[3] = color_current[3]; +#else + copy_v4_v4(color_current_fade, color_current); + color_current_fade[3] *= 0.2; +#endif + } + else { + copy_v4_fl(color_current_fade, 1.0f); + } + + /* Axis Line. */ + if (is_pos) { + float v_start[3]; + GPU_line_width(2.0f); + immUniformColor4fv(is_pos_color ? color_current : color_current_fade); + immBegin(GPU_PRIM_LINES, 2); + if (axis_align == -1) { + zero_v3(v_start); + } + else { + /* When axis aligned we don't draw the front most axis + * (allowing us to switch to the opposite side). + * In this case don't draw lines over axis pointing away from us + * because it obscures character and looks noisy. + */ + mul_v3_v3fl(v_start, v_final, 0.3f); + } + immVertex3fv(pos_id, v_start); + immVertex3fv(pos_id, v_final); + immEnd(); + } + + /* Axis Ball. */ + { + GPU_matrix_push(); + GPU_matrix_translate_3fv(v_final); + GPU_matrix_scale_1f(is_pos ? AXIS_HANDLE_SIZE_FG : AXIS_HANDLE_SIZE_BG); + + GPUBatch *sphere = GPU_batch_preset_sphere(0); + GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR); + GPU_batch_uniform_4fv(sphere, "color", is_pos_color ? color_current : color_current_fade); + GPU_batch_draw(sphere); + GPU_matrix_pop(); + } + + /* Axis XYZ Character. */ + if (show_axis_char && (select == false)) { +#ifdef USE_AXIS_FONT + immUnbindProgram(); + + GPU_matrix_push(); + GPU_matrix_translate_3fv(v_final); + GPU_matrix_mul(font.matrix); + + const char axis_str[2] = {'X' + axis, 0}; + float offset[2] = {0}; + BLF_width_and_height(font.id, axis_str, 2, &offset[0], &offset[1]); + BLF_position(font.id, roundf(offset[0] * -0.5f), roundf(offset[1] * -0.5f), 0); + BLF_draw_ascii(font.id, axis_str, 2); + GPU_blend(true); /* XXX, blf disables */ + GPU_matrix_pop(); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); +#else + GPU_line_width(1.0f); + float m3[3][3]; + copy_m3_m4(m3, gz->matrix_offset); + immUniformColor4fv(axis_black); + draw_xyz_wire(pos_id, m3, v_final, 1.0, axis); +#endif + } + } + } + + GPU_matrix_pop(); + immUnbindProgram(); +} + +static void axis3d_draw_intern( + const bContext *C, wmGizmo *gz, + const bool select, const bool highlight) +{ + const float *color = highlight ? gz->color_hi : gz->color; + float matrix_final[4][4]; + float matrix_unit[4][4]; + + unit_m4(matrix_unit); + + WM_gizmo_calc_matrix_final_params( + gz, + &((struct WM_GizmoMatrixParams) { + .matrix_offset = matrix_unit, + }), matrix_final); + + GPU_matrix_push(); + GPU_matrix_mul(matrix_final); + + + struct AxisDrawInfo draw_info; +#ifdef USE_AXIS_FONT + if (select == false) { + copy_m4_m4(draw_info.matrix_final, matrix_final); + } +#endif + +#ifdef USE_FADE_BACKGROUND + if (select == false) { + ED_view3d_background_color_get(CTX_data_scene(C), CTX_wm_view3d(C), draw_info.color_bg); + } +#else + UNUSED_VARS(C); +#endif + + GPU_blend(true); + axis_geom_draw( + gz, color, select, + &draw_info); + GPU_blend(false); + GPU_matrix_pop(); +} + +static void gizmo_axis_draw(const bContext *C, wmGizmo *gz) +{ + const bool is_modal = gz->state & WM_GIZMO_STATE_MODAL; + const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0; + + (void)is_modal; + + GPU_blend(true); + axis3d_draw_intern(C, gz, false, is_highlight); + GPU_blend(false); +} + +static int gizmo_axis_test_select( + bContext *UNUSED(C), wmGizmo *gz, const int mval[2]) +{ + float point_local[2] = {UNPACK2(mval)}; + sub_v2_v2(point_local, gz->matrix_basis[3]); + mul_v2_fl(point_local, 1.0f / (gz->scale_basis * UI_DPI_FAC)); + + const float len_sq = len_squared_v2(point_local); + if (len_sq > 1.0) { + return -1; + } + + int part_best = -1; + int part_index = 1; + /* Use 'SQUARE(HANDLE_SIZE)' if we want to be able to _not_ focus on one of the axis. */ + float i_best_len_sq = FLT_MAX; + for (int i = 0; i < 3; i++) { + for (int is_pos = 0; is_pos < 2; is_pos++) { + float co[2] = { + gz->matrix_offset[i][0] * (is_pos ? 1 : -1), + gz->matrix_offset[i][1] * (is_pos ? 1 : -1), + }; + + bool ok = true; + + /* Check if we're viewing on an axis, there is no point to clicking on the current axis so show the reverse. */ + if (len_squared_v2(co) < 1e-6f && (gz->matrix_offset[i][2] > 0.0f) == is_pos) { + ok = false; + } + + if (ok) { + const float len_axis_sq = len_squared_v2v2(co, point_local); + if (len_axis_sq < i_best_len_sq) { + part_best = part_index; + i_best_len_sq = len_axis_sq; + } + } + part_index += 1; + } + } + + if (part_best != -1) { + return part_best; + } + + /* The 'gz->scale_final' is already applied when projecting. */ + if (len_sq < 1.0f) { + return 0; + } + + return -1; +} + +static int gizmo_axis_cursor_get(wmGizmo *gz) +{ + if (gz->highlight_part > 0) { + return CURSOR_EDIT; + } + return BC_NSEW_SCROLLCURSOR; +} + +void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt) +{ + /* identifiers */ + gzt->idname = "VIEW3D_GT_navigate_rotate"; + + /* api callbacks */ + gzt->draw = gizmo_axis_draw; + gzt->test_select = gizmo_axis_test_select; + gzt->cursor_get = gizmo_axis_cursor_get; + + gzt->struct_size = sizeof(wmGizmo); +} diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect.c new file mode 100644 index 00000000000..7b8e3a76c85 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect.c @@ -0,0 +1,114 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_gizmo_preselect.c + * \ingroup spview3d + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" + +#include "ED_gizmo_utils.h" +#include "ED_screen.h" + +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "WM_toolsystem.h" + +#include "view3d_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Pre-Select Element Gizmo + * + * \{ */ + +struct GizmoGroupPreSelElem { + wmGizmo *gizmo; +}; + +static void WIDGETGROUP_mesh_preselect_elem_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + const wmGizmoType *gzt_presel = WM_gizmotype_find("GIZMO_GT_mesh_preselect_elem_3d", true); + struct GizmoGroupPreSelElem *ggd = MEM_callocN(sizeof(struct GizmoGroupPreSelElem), __func__); + gzgroup->customdata = ggd; + + wmGizmo *gz = ggd->gizmo = WM_gizmo_new_ptr(gzt_presel, gzgroup, NULL); + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); +} + +void VIEW3D_GGT_mesh_preselect_elem(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Mesh Preselect Element"; + gzgt->idname = "VIEW3D_GGT_mesh_preselect_elem"; + + gzgt->flag = WM_GIZMOGROUPTYPE_3D; + + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + + gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; + gzgt->setup = WIDGETGROUP_mesh_preselect_elem_setup; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Pre-Select Edge Ring Gizmo + * + * \{ */ + +struct GizmoGroupPreSelEdgeRing { + wmGizmo *gizmo; +}; + +static void WIDGETGROUP_mesh_preselect_edgering_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) +{ + const wmGizmoType *gzt_presel = WM_gizmotype_find("GIZMO_GT_mesh_preselect_edgering_3d", true); + struct GizmoGroupPreSelEdgeRing *ggd = MEM_callocN(sizeof(struct GizmoGroupPreSelEdgeRing), __func__); + gzgroup->customdata = ggd; + + wmGizmo *gz = ggd->gizmo = WM_gizmo_new_ptr(gzt_presel, gzgroup, NULL); + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); +} + +void VIEW3D_GGT_mesh_preselect_edgering(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Mesh Preselect Edge Ring"; + gzgt->idname = "VIEW3D_GGT_mesh_preselect_edgering"; + + gzgt->flag = WM_GIZMOGROUPTYPE_3D; + + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + + gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; + gzgt->setup = WIDGETGROUP_mesh_preselect_edgering_setup; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c new file mode 100644 index 00000000000..be07928d5fc --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c @@ -0,0 +1,429 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file view3d_gizmo_preselect_type.c + * \ingroup wm + * + * \name Preselection Gizmo + * + * Use for tools to hover over data before activation. + * + * \note This is a slight mis-use of gizmo's, since clicking performs no action. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "DNA_mesh_types.h" + +#include "BKE_context.h" +#include "BKE_layer.h" +#include "BKE_editmesh.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "bmesh.h" + +#include "ED_screen.h" +#include "ED_mesh.h" +#include "ED_view3d.h" +#include "ED_gizmo_library.h" + +/* -------------------------------------------------------------------- */ +/** \name Mesh Element (Vert/Edge/Face) Pre-Select Gizmo API + * + * \{ */ + + +typedef struct MeshElemGizmo3D { + wmGizmo gizmo; + Base **bases; + uint bases_len; + int base_index; + int vert_index; + int edge_index; + int face_index; + struct EditMesh_PreSelElem *psel; +} MeshElemGizmo3D; + +static void gizmo_preselect_elem_draw(const bContext *UNUSED(C), wmGizmo *gz) +{ + MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; + if (gz_ele->base_index != -1) { + Object *ob = gz_ele->bases[gz_ele->base_index]->object; + EDBM_preselect_elem_draw(gz_ele->psel, ob->obmat); + } +} + +static int gizmo_preselect_elem_test_select( + bContext *C, wmGizmo *gz, const int mval[2]) +{ + MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; + struct { + Object *ob; + BMElem *ele; + float dist; + int base_index; + } best = { + .dist = ED_view3d_select_dist_px(), + }; + + struct { + int base_index; + int vert_index; + int edge_index; + int face_index; + } prev = { + .base_index = gz_ele->base_index, + .vert_index = gz_ele->vert_index, + .edge_index = gz_ele->edge_index, + .face_index = gz_ele->face_index, + }; + + { + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + if (((gz_ele->bases)) == NULL || + (gz_ele->bases[0] != view_layer->basact)) + { + MEM_SAFE_FREE(gz_ele->bases); + gz_ele->bases = BKE_view_layer_array_from_bases_in_edit_mode( + view_layer, v3d, &gz_ele->bases_len); + } + } + + ViewContext vc; + em_setup_viewcontext(C, &vc); + copy_v2_v2_int(vc.mval, mval); + + { + /* TODO: support faces. */ + int base_index = -1; + BMVert *eve_test; + BMEdge *eed_test; + + if (EDBM_unified_findnearest_from_raycast( + &vc, gz_ele->bases, gz_ele->bases_len, + true, &base_index, &eve_test, &eed_test, NULL)) + { + Base *base = gz_ele->bases[base_index]; + best.ob = base->object; + if (eve_test) { + best.ele = (BMElem *)eve_test; + } + else if (eed_test) { + best.ele = (BMElem *)eed_test; + } + else { + BLI_assert(0); + } + best.base_index = base_index; + /* Check above should never fail, if it does it's an internal error. */ + BLI_assert(best.base_index != -1); + } + } + + BMesh *bm = NULL; + + gz_ele->base_index = -1; + gz_ele->vert_index = -1; + gz_ele->edge_index = -1; + gz_ele->face_index = -1; + + if (best.ele) { + gz_ele->base_index = best.base_index; + bm = BKE_editmesh_from_object(gz_ele->bases[gz_ele->base_index]->object)->bm; + BM_mesh_elem_index_ensure(bm, best.ele->head.htype); + + if (best.ele->head.htype == BM_VERT) { + gz_ele->vert_index = BM_elem_index_get(best.ele); + } + else if (best.ele->head.htype == BM_EDGE) { + gz_ele->edge_index = BM_elem_index_get(best.ele); + } + else if (best.ele->head.htype == BM_FACE) { + gz_ele->face_index = BM_elem_index_get(best.ele); + } + } + + if ((prev.base_index == gz_ele->base_index) && + (prev.vert_index == gz_ele->vert_index) && + (prev.edge_index == gz_ele->edge_index) && + (prev.face_index == gz_ele->face_index)) + { + /* pass (only recalculate on change) */ + } + else { + if (best.ele) { + const float (*coords)[3] = NULL; + { + Object *ob = gz_ele->bases[gz_ele->base_index]->object; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data); + if (me_eval->runtime.edit_data) { + coords = me_eval->runtime.edit_data->vertexCos; + } + } + EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords); + } + else { + EDBM_preselect_elem_clear(gz_ele->psel); + } + + RNA_int_set(gz->ptr, "object_index", gz_ele->base_index); + RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index); + RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index); + RNA_int_set(gz->ptr, "face_index", gz_ele->face_index); + + ARegion *ar = CTX_wm_region(C); + ED_region_tag_redraw(ar); + } + + // return best.eed ? 0 : -1; + return -1; +} + +static void gizmo_preselect_elem_setup(wmGizmo *gz) +{ + MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; + if (gz_ele->psel == NULL) { + gz_ele->psel = EDBM_preselect_elem_create(); + } + gz_ele->base_index = -1; +} + +static void gizmo_preselect_elem_free(wmGizmo *gz) +{ + MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; + EDBM_preselect_elem_destroy(gz_ele->psel); + gz_ele->psel = NULL; + MEM_SAFE_FREE(gz_ele->bases); +} + +static int gizmo_preselect_elem_invoke( + bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event)) +{ + return OPERATOR_PASS_THROUGH; +} + +static void GIZMO_GT_mesh_preselect_elem_3d(wmGizmoType *gzt) +{ + /* identifiers */ + gzt->idname = "GIZMO_GT_mesh_preselect_elem_3d"; + + /* api callbacks */ + gzt->invoke = gizmo_preselect_elem_invoke; + gzt->draw = gizmo_preselect_elem_draw; + gzt->test_select = gizmo_preselect_elem_test_select; + gzt->setup = gizmo_preselect_elem_setup; + gzt->free = gizmo_preselect_elem_free; + + gzt->struct_size = sizeof(MeshElemGizmo3D); + + RNA_def_int(gzt->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", -1, INT_MAX); + RNA_def_int(gzt->srna, "vert_index", -1, -1, INT_MAX, "Vert Index", "", -1, INT_MAX); + RNA_def_int(gzt->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", -1, INT_MAX); + RNA_def_int(gzt->srna, "face_index", -1, -1, INT_MAX, "Face Index", "", -1, INT_MAX); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Edge-Ring Pre-Select Gizmo API + * + * \{ */ + +typedef struct MeshEdgeRingGizmo3D { + wmGizmo gizmo; + Base **bases; + uint bases_len; + int base_index; + int edge_index; + struct EditMesh_PreSelEdgeRing *psel; +} MeshEdgeRingGizmo3D; + +static void gizmo_preselect_edgering_draw(const bContext *UNUSED(C), wmGizmo *gz) +{ + MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; + if (gz_ring->base_index != -1) { + Object *ob = gz_ring->bases[gz_ring->base_index]->object; + EDBM_preselect_edgering_draw(gz_ring->psel, ob->obmat); + } +} + +static int gizmo_preselect_edgering_test_select( + bContext *C, wmGizmo *gz, const int mval[2]) +{ + MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; + struct { + Object *ob; + BMEdge *eed; + float dist; + int base_index; + } best = { + .dist = ED_view3d_select_dist_px(), + }; + + struct { + int base_index; + int edge_index; + } prev = { + .base_index = gz_ring->base_index, + .edge_index = gz_ring->edge_index, + }; + + { + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + if (((gz_ring->bases)) == NULL || + (gz_ring->bases[0] != view_layer->basact)) + { + MEM_SAFE_FREE(gz_ring->bases); + gz_ring->bases = BKE_view_layer_array_from_bases_in_edit_mode( + view_layer, v3d, &gz_ring->bases_len); + } + } + + ViewContext vc; + em_setup_viewcontext(C, &vc); + copy_v2_v2_int(vc.mval, mval); + + for (uint base_index = 0; base_index < gz_ring->bases_len; base_index++) { + Object *ob_iter = gz_ring->bases[base_index]->object; + ED_view3d_viewcontext_init_object(&vc, ob_iter); + BMEdge *eed_test = EDBM_edge_find_nearest_ex(&vc, &best.dist, NULL, false, false, NULL); + if (eed_test) { + best.ob = ob_iter; + best.eed = eed_test; + best.base_index = base_index; + } + } + + BMesh *bm = NULL; + if (best.eed) { + gz_ring->base_index = best.base_index; + bm = BKE_editmesh_from_object(gz_ring->bases[gz_ring->base_index]->object)->bm; + BM_mesh_elem_index_ensure(bm, BM_EDGE); + gz_ring->edge_index = BM_elem_index_get(best.eed); + } + else { + gz_ring->base_index = -1; + gz_ring->edge_index = -1; + } + + + if ((prev.base_index == gz_ring->base_index) && + (prev.edge_index == gz_ring->edge_index)) + { + /* pass (only recalculate on change) */ + } + else { + if (best.eed) { + const float (*coords)[3] = NULL; + { + Object *ob = gz_ring->bases[gz_ring->base_index]->object; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data); + if (me_eval->runtime.edit_data) { + coords = me_eval->runtime.edit_data->vertexCos; + } + } + EDBM_preselect_edgering_update_from_edge(gz_ring->psel, bm, best.eed, 1, coords); + } + else { + EDBM_preselect_edgering_clear(gz_ring->psel); + } + + RNA_int_set(gz->ptr, "object_index", gz_ring->base_index); + RNA_int_set(gz->ptr, "edge_index", gz_ring->edge_index); + + ARegion *ar = CTX_wm_region(C); + ED_region_tag_redraw(ar); + } + + // return best.eed ? 0 : -1; + return -1; +} + +static void gizmo_preselect_edgering_setup(wmGizmo *gz) +{ + MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; + if (gz_ring->psel == NULL) { + gz_ring->psel = EDBM_preselect_edgering_create(); + } + gz_ring->base_index = -1; +} + +static void gizmo_preselect_edgering_free(wmGizmo *gz) +{ + MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; + EDBM_preselect_edgering_destroy(gz_ring->psel); + gz_ring->psel = NULL; + MEM_SAFE_FREE(gz_ring->bases); +} + +static int gizmo_preselect_edgering_invoke( + bContext *UNUSED(C), wmGizmo *UNUSED(gz), const wmEvent *UNUSED(event)) +{ + return OPERATOR_PASS_THROUGH; +} + + +static void GIZMO_GT_mesh_preselect_edgering_3d(wmGizmoType *gzt) +{ + /* identifiers */ + gzt->idname = "GIZMO_GT_mesh_preselect_edgering_3d"; + + /* api callbacks */ + gzt->invoke = gizmo_preselect_edgering_invoke; + gzt->draw = gizmo_preselect_edgering_draw; + gzt->test_select = gizmo_preselect_edgering_test_select; + gzt->setup = gizmo_preselect_edgering_setup; + gzt->free = gizmo_preselect_edgering_free; + + gzt->struct_size = sizeof(MeshEdgeRingGizmo3D); + + RNA_def_int(gzt->srna, "object_index", -1, -1, INT_MAX, "Object Index", "", -1, INT_MAX); + RNA_def_int(gzt->srna, "edge_index", -1, -1, INT_MAX, "Edge Index", "", -1, INT_MAX); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Gizmo API + * + * \{ */ + +void ED_gizmotypes_preselect_3d(void) +{ + WM_gizmotype_append(GIZMO_GT_mesh_preselect_elem_3d); + WM_gizmotype_append(GIZMO_GT_mesh_preselect_edgering_3d); +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c new file mode 100644 index 00000000000..ed5a1ab7720 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -0,0 +1,1101 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_view3d/view3d_gizmo_ruler.c + * \ingroup spview3d + */ + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_rect.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "BKE_object.h" +#include "BKE_unit.h" +#include "BKE_material.h" + +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_view3d_types.h" + +#include "BIF_gl.h" + +#include "ED_gizmo_utils.h" +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_transform_snap_object_context.h" +#include "ED_view3d.h" + +#include "UI_resources.h" +#include "UI_interface.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "WM_toolsystem.h" + +#include "view3d_intern.h" /* own include */ + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_select.h" +#include "GPU_state.h" + +#include "BLF_api.h" + + +static const char *view3d_gzgt_ruler_id = "VIEW3D_GGT_ruler"; + + +#define MVAL_MAX_PX_DIST 12.0f + +/* -------------------------------------------------------------------- */ +/* Ruler Item (we can have many) */ +enum { + RULERITEM_USE_ANGLE = (1 << 0), /* use protractor */ + RULERITEM_USE_RAYCAST = (1 << 1) +}; + +enum { + RULERITEM_DIRECTION_IN = 0, + RULERITEM_DIRECTION_OUT +}; + +/* keep smaller then selection, since we may want click elsewhere without selecting a ruler */ +#define RULER_PICK_DIST 12.0f +#define RULER_PICK_DIST_SQ (RULER_PICK_DIST * RULER_PICK_DIST) + +/* not clicking on a point */ +#define PART_LINE 0xff + +/* -------------------------------------------------------------------- */ +/* Ruler Info (wmGizmoGroup customdata) */ + +enum { + RULER_STATE_NORMAL = 0, + RULER_STATE_DRAG +}; + +enum { + RULER_SNAP_OK = (1 << 0), +}; + +typedef struct RulerInfo { + // ListBase items; + int item_active; + int flag; + int snap_flag; + int state; + + struct SnapObjectContext *snap_context; + + /* wm state */ + wmWindow *win; + ScrArea *sa; + ARegion *ar; /* re-assigned every modal update */ +} RulerInfo; + +/* -------------------------------------------------------------------- */ +/* Ruler Item (two or three points) */ + +typedef struct RulerItem { + wmGizmo gz; + + /* worldspace coords, middle being optional */ + float co[3][3]; + + int flag; + int raycast_dir; /* RULER_DIRECTION_* */ +} RulerItem; + +typedef struct RulerInteraction { + /* selected coord */ + char co_index; /* 0 -> 2 */ + float drag_start_co[3]; + uint inside_region : 1; +} RulerInteraction; + +/* -------------------------------------------------------------------- */ +/** \name Internal Ruler Utilities + * \{ */ + +static RulerItem *ruler_item_add(wmGizmoGroup *gzgroup) +{ + /* could pass this as an arg */ + const wmGizmoType *gzt_ruler = WM_gizmotype_find("VIEW3D_GT_ruler_item", true); + RulerItem *ruler_item = (RulerItem *)WM_gizmo_new_ptr(gzt_ruler, gzgroup, NULL); + WM_gizmo_set_flag(&ruler_item->gz, WM_GIZMO_DRAW_MODAL, true); + return ruler_item; +} + +static void ruler_item_remove(bContext *C, wmGizmoGroup *gzgroup, RulerItem *ruler_item) +{ + WM_gizmo_unlink(&gzgroup->gizmos, gzgroup->parent_gzmap, &ruler_item->gz, C); +} + +static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit, + char *numstr, size_t numstr_size, int prec) +{ + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + const float ruler_angle = angle_v3v3v3(ruler_item->co[0], + ruler_item->co[1], + ruler_item->co[2]); + + if (unit->system == USER_UNIT_NONE) { + BLI_snprintf(numstr, numstr_size, "%.*f°", prec, RAD2DEGF(ruler_angle)); + } + else { + bUnit_AsString2( + numstr, numstr_size, (double)ruler_angle, + prec, B_UNIT_ROTATION, unit, false); + } + } + else { + const float ruler_len = len_v3v3(ruler_item->co[0], + ruler_item->co[2]); + + if (unit->system == USER_UNIT_NONE) { + BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len); + } + else { + bUnit_AsString2( + numstr, numstr_size, (double)(ruler_len * unit->scale_length), + prec, B_UNIT_LENGTH, unit, false); + } + } +} + +static bool view3d_ruler_pick( + wmGizmoGroup *gzgroup, RulerItem *ruler_item, const float mval[2], + int *r_co_index) +{ + RulerInfo *ruler_info = gzgroup->customdata; + ARegion *ar = ruler_info->ar; + bool found = false; + + float dist_best = RULER_PICK_DIST_SQ; + int co_index_best = -1; + + { + float co_ss[3][2]; + float dist; + int j; + + /* should these be checked? - ok for now not to */ + for (j = 0; j < 3; j++) { + ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); + } + + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]), + dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2])); + if (dist < dist_best) { + dist_best = dist; + found = true; + + { + const float dist_points[3] = { + len_squared_v2v2(co_ss[0], mval), + len_squared_v2v2(co_ss[1], mval), + len_squared_v2v2(co_ss[2], mval), + }; + if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) { + co_index_best = min_axis_v3(dist_points); + } + else { + co_index_best = -1; + } + } + } + } + else { + dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]); + if (dist < dist_best) { + dist_best = dist; + found = true; + + { + const float dist_points[2] = { + len_squared_v2v2(co_ss[0], mval), + len_squared_v2v2(co_ss[2], mval), + }; + if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) { + co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2; + } + else { + co_index_best = -1; + } + } + } + } + } + + *r_co_index = co_index_best; + return found; +} + +/** + * Ensure the 'snap_context' is only cached while dragging, + * needed since the user may toggle modes between tool use. + */ +static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) +{ + Main *bmain = CTX_data_main(C); + if (state == ruler_info->state) { + return; + } + + /* always remove */ + if (ruler_info->snap_context) { + ED_transform_snap_object_context_destroy(ruler_info->snap_context); + ruler_info->snap_context = NULL; + } + + if (state == RULER_STATE_NORMAL) { + /* pass */ + } + else if (state == RULER_STATE_DRAG) { + ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( + bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0, + ruler_info->ar, CTX_wm_view3d(C)); + } + else { + BLI_assert(0); + } + + ruler_info->state = state; +} + +static void view3d_ruler_item_project( + RulerInfo *ruler_info, float r_co[3], + const int xy[2]) +{ + ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->ar, r_co, xy, r_co); +} + +/* use for mousemove events */ +static bool view3d_ruler_item_mousemove( + RulerInfo *ruler_info, RulerItem *ruler_item, const int mval[2], + const bool do_thickness, const bool do_snap) +{ + const float eps_bias = 0.0002f; + float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ + + ruler_info->snap_flag &= ~RULER_SNAP_OK; + + if (ruler_item) { + RulerInteraction *inter = ruler_item->gz.interaction_data; + float *co = ruler_item->co[inter->co_index]; + /* restore the initial depth */ + copy_v3_v3(co, inter->drag_start_co); + view3d_ruler_item_project(ruler_info, co, mval); + if (do_thickness && inter->co_index != 1) { + // Scene *scene = CTX_data_scene(C); + // View3D *v3d = ruler_info->sa->spacedata.first; + const float mval_fl[2] = {UNPACK2(mval)}; + float ray_normal[3]; + float ray_start[3]; + float *co_other; + + co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0]; + + if (ED_transform_snap_object_project_view3d( + ruler_info->snap_context, + SCE_SNAP_MODE_FACE, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .use_object_edit_cage = true, + }, + mval_fl, &dist_px, + co, ray_normal)) + { + negate_v3(ray_normal); + /* add some bias */ + madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias); + ED_transform_snap_object_project_ray( + ruler_info->snap_context, + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .use_object_edit_cage = true, + }, + ray_start, ray_normal, NULL, + co_other, NULL); + } + } + else if (do_snap) { + const float mval_fl[2] = {UNPACK2(mval)}; + + if (ED_transform_snap_object_project_view3d( + ruler_info->snap_context, + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE), + &(const struct SnapObjectParams){ + .snap_select = SNAP_ALL, + .use_object_edit_cage = true, + .use_occlusion_test = true, + }, + mval_fl, &dist_px, + co, NULL)) + { + ruler_info->snap_flag |= RULER_SNAP_OK; + } + } + return true; + } + else { + return false; + } +} + + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Ruler/Grease Pencil Conversion + * \{ */ + +#define RULER_ID "RulerData3D" +static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) +{ + // RulerInfo *ruler_info = gzgroup->customdata; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + bGPdata *gpd; + bGPDlayer *gpl; + bGPDframe *gpf; + bGPDstroke *gps; + RulerItem *ruler_item; + const char *ruler_name = RULER_ID; + bool changed = false; + + if (scene->gpd == NULL) { + scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations"); + } + gpd = scene->gpd; + + gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + if (gpl == NULL) { + gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false); + copy_v4_v4(gpl->color, U.gpencil_new_layer_col); + gpl->thickness = 1; + gpl->flag |= GP_LAYER_HIDE; + } + + gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW); + BKE_gpencil_free_strokes(gpf); + + for (ruler_item = gzgroup->gizmos.first; ruler_item; ruler_item = (RulerItem *)ruler_item->gz.next) { + bGPDspoint *pt; + int j; + + /* allocate memory for a new stroke */ + gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + gps->totpoints = 3; + pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + for (j = 0; j < 3; j++) { + copy_v3_v3(&pt->x, ruler_item->co[j]); + pt->pressure = 1.0f; + pt->strength = 1.0f; + pt++; + } + } + else { + gps->totpoints = 2; + pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + for (j = 0; j < 3; j += 2) { + copy_v3_v3(&pt->x, ruler_item->co[j]); + pt->pressure = 1.0f; + pt->strength = 1.0f; + pt++; + } + } + gps->flag = GP_STROKE_3DSPACE; + gps->thickness = 3; + + BLI_addtail(&gpf->strokes, gps); + changed = true; + } + + return changed; +} + +static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup) +{ + Scene *scene = CTX_data_scene(C); + bool changed = false; + + if (scene->gpd) { + bGPDlayer *gpl; + const char *ruler_name = RULER_ID; + gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + if (gpl) { + bGPDframe *gpf; + gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV); + if (gpf) { + bGPDstroke *gps; + for (gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt = gps->points; + int j; + RulerItem *ruler_item = NULL; + if (gps->totpoints == 3) { + ruler_item = ruler_item_add(gzgroup); + for (j = 0; j < 3; j++) { + copy_v3_v3(ruler_item->co[j], &pt->x); + pt++; + } + ruler_item->flag |= RULERITEM_USE_ANGLE; + changed = true; + } + else if (gps->totpoints == 2) { + ruler_item = ruler_item_add(gzgroup); + for (j = 0; j < 3; j += 2) { + copy_v3_v3(ruler_item->co[j], &pt->x); + pt++; + } + changed = true; + } + } + } + } + } + + return changed; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Ruler Item Gizmo Type + * \{ */ + +static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) +{ + Scene *scene = CTX_data_scene(C); + UnitSettings *unit = &scene->unit; + RulerInfo *ruler_info = gz->parent_gzgroup->customdata; + RulerItem *ruler_item = (RulerItem *)gz; + ARegion *ar = ruler_info->ar; + RegionView3D *rv3d = ar->regiondata; + const float cap_size = 4.0f; + const float bg_margin = 4.0f * U.pixelsize; + const float arc_size = 64.0f * U.pixelsize; +#define ARC_STEPS 24 + const int arc_steps = ARC_STEPS; + const float color_act[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float color_base[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + unsigned char color_text[3]; + unsigned char color_wire[3]; + float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f}; + + /* anti-aliased lines for more consistent appearance */ + GPU_line_smooth(true); + GPU_line_width(1.0f); + + BLF_enable(blf_mono_font, BLF_ROTATION); + BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi); + BLF_rotation(blf_mono_font, 0.0f); + + UI_GetThemeColor3ubv(TH_TEXT, color_text); + UI_GetThemeColor3ubv(TH_WIRE, color_wire); + + /* Avoid white on white text. (TODO Fix by using theme) */ + if ((int)color_text[0] + (int)color_text[1] + (int)color_text[2] > 127 * 3 * 0.6f) { + copy_v3_fl(color_back, 0.0f); + } + + const bool is_act = (gz->flag & WM_GIZMO_DRAW_HOVER); + float dir_ruler[2]; + float co_ss[3][2]; + int j; + + /* should these be checked? - ok for now not to */ + for (j = 0; j < 3; j++) { + ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); + } + + GPU_blend(true); + + const uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniform1i("colors_len", 2); /* "advanced" mode */ + const float *col = is_act ? color_act : color_base; + immUniformArray4fv("colors", (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, 2); + immUniform1f("dash_width", 6.0f); + + immBegin(GPU_PRIM_LINE_STRIP, 3); + + immVertex2fv(shdr_pos, co_ss[0]); + immVertex2fv(shdr_pos, co_ss[1]); + immVertex2fv(shdr_pos, co_ss[2]); + + immEnd(); + + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* arc */ + { + float dir_tmp[3]; + float co_tmp[3]; + float arc_ss_coord[2]; + + float dir_a[3]; + float dir_b[3]; + float quat[4]; + float axis[3]; + float angle; + const float px_scale = (ED_view3d_pixel_size_no_ui_scale(rv3d, ruler_item->co[1]) * + min_fff(arc_size, + len_v2v2(co_ss[0], co_ss[1]) / 2.0f, + len_v2v2(co_ss[2], co_ss[1]) / 2.0f)); + + sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]); + sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]); + normalize_v3(dir_a); + normalize_v3(dir_b); + + cross_v3_v3v3(axis, dir_a, dir_b); + angle = angle_normalized_v3v3(dir_a, dir_b); + + axis_angle_to_quat(quat, axis, angle / arc_steps); + + copy_v3_v3(dir_tmp, dir_a); + + immUniformColor3ubv(color_wire); + + immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1); + + for (j = 0; j <= arc_steps; j++) { + madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale); + ED_view3d_project_float_global(ar, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP); + mul_qt_v3(quat, dir_tmp); + + immVertex2fv(shdr_pos, arc_ss_coord); + } + + immEnd(); + } + + /* capping */ + { + float rot_90_vec_a[2]; + float rot_90_vec_b[2]; + float cap[2]; + + sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]); + rot_90_vec_a[0] = -dir_ruler[1]; + rot_90_vec_a[1] = dir_ruler[0]; + normalize_v2(rot_90_vec_a); + + sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]); + rot_90_vec_b[0] = -dir_ruler[1]; + rot_90_vec_b[1] = dir_ruler[0]; + normalize_v2(rot_90_vec_b); + + GPU_blend(true); + + immUniformColor3ubv(color_wire); + + immBegin(GPU_PRIM_LINES, 8); + + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); + immVertex2fv(shdr_pos, cap); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); + immVertex2fv(shdr_pos, cap); + + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); + immVertex2fv(shdr_pos, cap); + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); + immVertex2fv(shdr_pos, cap); + + /* angle vertex */ + immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); + immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); + immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); + + immEnd(); + + GPU_blend(false); + } + + /* text */ + char numstr[256]; + float numstr_size[2]; + float posit[2]; + const int prec = 2; /* XXX, todo, make optional */ + + ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); + + BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); + + posit[0] = co_ss[1][0] + (cap_size * 2.0f); + posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); + + /* draw text (bg) */ + { + immUniformColor4fv(color_back); + GPU_blend(true); + immRectf(shdr_pos, + posit[0] - bg_margin, posit[1] - bg_margin, + posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1]); + GPU_blend(false); + } + + immUnbindProgram(); + + /* draw text */ + { + BLF_color3ubv(blf_mono_font, color_text); + BLF_position(blf_mono_font, posit[0], posit[1], 0.0f); + BLF_rotation(blf_mono_font, 0.0f); + BLF_draw(blf_mono_font, numstr, sizeof(numstr)); + } + } + else { + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniform1i("colors_len", 2); /* "advanced" mode */ + const float *col = is_act ? color_act : color_base; + immUniformArray4fv("colors", (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, 2); + immUniform1f("dash_width", 6.0f); + + immBegin(GPU_PRIM_LINES, 2); + + immVertex2fv(shdr_pos, co_ss[0]); + immVertex2fv(shdr_pos, co_ss[2]); + + immEnd(); + + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); + + /* capping */ + { + float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]}; + float cap[2]; + + normalize_v2(rot_90_vec); + + GPU_blend(true); + + immUniformColor3ubv(color_wire); + + immBegin(GPU_PRIM_LINES, 4); + + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); + immVertex2fv(shdr_pos, cap); + madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); + immVertex2fv(shdr_pos, cap); + + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); + immVertex2fv(shdr_pos, cap); + madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); + immVertex2fv(shdr_pos, cap); + + immEnd(); + + GPU_blend(false); + } + + /* text */ + char numstr[256]; + float numstr_size[2]; + const int prec = 6; /* XXX, todo, make optional */ + float posit[2]; + + ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); + + BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); + + mid_v2_v2v2(posit, co_ss[0], co_ss[2]); + + /* center text */ + posit[0] -= numstr_size[0] / 2.0f; + posit[1] -= numstr_size[1] / 2.0f; + + /* draw text (bg) */ + { + immUniformColor4fv(color_back); + GPU_blend(true); + immRectf(shdr_pos, + posit[0] - bg_margin, posit[1] - bg_margin, + posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1]); + GPU_blend(false); + } + + immUnbindProgram(); + + /* draw text */ + { + BLF_color3ubv(blf_mono_font, color_text); + BLF_position(blf_mono_font, posit[0], posit[1], 0.0f); + BLF_draw(blf_mono_font, numstr, sizeof(numstr)); + } + } + + GPU_line_smooth(false); + + BLF_disable(blf_mono_font, BLF_ROTATION); + +#undef ARC_STEPS + + /* draw snap */ + if ((ruler_info->snap_flag & RULER_SNAP_OK) && + (ruler_info->state == RULER_STATE_DRAG) && + (ruler_item->gz.interaction_data != NULL)) + { + RulerInteraction *inter = ruler_item->gz.interaction_data; + /* size from drawSnapping */ + const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); + float co_ss_snap[3]; + ED_view3d_project_float_global(ar, ruler_item->co[inter->co_index], co_ss_snap, V3D_PROJ_TEST_NOP); + + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(color_act); + + imm_draw_circle_wire_2d(pos, co_ss_snap[0], co_ss_snap[1], size * U.pixelsize, 32); + + immUnbindProgram(); + } +} + +static int gizmo_ruler_test_select( + bContext *UNUSED(C), wmGizmo *gz, const int mval[2]) +{ + RulerItem *ruler_item_pick = (RulerItem *)gz; + float mval_fl[2] = {UNPACK2(mval)}; + int co_index; + + /* select and drag */ + if (view3d_ruler_pick(gz->parent_gzgroup, ruler_item_pick, mval_fl, &co_index)) { + if (co_index == -1) { + if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) { + return PART_LINE; + } + } + else { + return co_index; + } + } + return -1; +} + +static int gizmo_ruler_modal( + bContext *C, wmGizmo *gz, const wmEvent *event, + eWM_GizmoFlagTweak UNUSED(tweak_flag)) +{ + bool do_draw = false; + int exit_code = OPERATOR_RUNNING_MODAL; + RulerInfo *ruler_info = gz->parent_gzgroup->customdata; + RulerItem *ruler_item = (RulerItem *)gz; + RulerInteraction *inter = ruler_item->gz.interaction_data; + ARegion *ar = CTX_wm_region(C); + + ruler_info->ar = ar; + + switch (event->type) { + case MOUSEMOVE: + { + if (ruler_info->state == RULER_STATE_DRAG) { + if (view3d_ruler_item_mousemove( + ruler_info, ruler_item, event->mval, + event->shift != 0, event->ctrl != 0)) + { + do_draw = true; + } + inter->inside_region = BLI_rcti_isect_pt_v(&ar->winrct, &event->x); + } + break; + } + } + if (do_draw) { + ED_region_tag_redraw(ar); + } + return exit_code; +} + +static int gizmo_ruler_invoke( + bContext *C, wmGizmo *gz, const wmEvent *event) +{ + wmGizmoGroup *gzgroup = gz->parent_gzgroup; + RulerInfo *ruler_info = gzgroup->customdata; + RulerItem *ruler_item_pick = (RulerItem *)gz; + RulerInteraction *inter = MEM_callocN(sizeof(RulerInteraction), __func__); + gz->interaction_data = inter; + + ARegion *ar = ruler_info->ar; + + const float mval_fl[2] = {UNPACK2(event->mval)}; + + /* select and drag */ + if (gz->highlight_part == PART_LINE) { + if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) { + /* Add Center Point */ + ruler_item_pick->flag |= RULERITEM_USE_ANGLE; + inter->co_index = 1; + ruler_state_set(C, ruler_info, RULER_STATE_DRAG); + + /* find the factor */ + { + float co_ss[2][2]; + float fac; + + ED_view3d_project_float_global(ar, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP); + ED_view3d_project_float_global(ar, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP); + + fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]); + CLAMP(fac, 0.0f, 1.0f); + + interp_v3_v3v3(ruler_item_pick->co[1], + ruler_item_pick->co[0], + ruler_item_pick->co[2], fac); + } + + /* update the new location */ + view3d_ruler_item_mousemove( + ruler_info, ruler_item_pick, event->mval, + event->shift != 0, event->ctrl != 0); + } + } + else { + inter->co_index = gz->highlight_part; + ruler_state_set(C, ruler_info, RULER_STATE_DRAG); + + /* store the initial depth */ + copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]); + } + + /* Should always be true. */ + inter->inside_region = BLI_rcti_isect_pt_v(&ar->winrct, &event->x); + + return OPERATOR_RUNNING_MODAL; +} + +static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel) +{ + wmGizmoGroup *gzgroup = gz->parent_gzgroup; + RulerInfo *ruler_info = gzgroup->customdata; + + if (!cancel) { + if (ruler_info->state == RULER_STATE_DRAG) { + RulerItem *ruler_item = (RulerItem *)gz; + RulerInteraction *inter = gz->interaction_data; + /* rubber-band angle removal */ + if (!inter->inside_region) { + if ((inter->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) { + ruler_item->flag &= ~RULERITEM_USE_ANGLE; + } + else { + /* Not ideal, since the ruler isn't a mode and we don't want to override delete key + * use dragging out of the view for removal. */ + ruler_item_remove(C, gzgroup, ruler_item); + ruler_item = NULL; + gz = NULL; + inter = NULL; + } + } + if (ruler_info->snap_flag & RULER_SNAP_OK) { + ruler_info->snap_flag &= ~RULER_SNAP_OK; + } + ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); + } + /* We could convert only the current gizmo, for now just re-generate. */ + view3d_ruler_to_gpencil(C, gzgroup); + } + + if (gz) { + MEM_SAFE_FREE(gz->interaction_data); + } + + ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); +} + +static int gizmo_ruler_cursor_get(wmGizmo *gz) +{ + if (gz->highlight_part == PART_LINE) { + return BC_CROSSCURSOR; + } + return BC_NSEW_SCROLLCURSOR; +} + +void VIEW3D_GT_ruler_item(wmGizmoType *gzt) +{ + /* identifiers */ + gzt->idname = "VIEW3D_GT_ruler_item"; + + /* api callbacks */ + gzt->draw = gizmo_ruler_draw; + gzt->test_select = gizmo_ruler_test_select; + gzt->modal = gizmo_ruler_modal; + gzt->invoke = gizmo_ruler_invoke; + gzt->exit = gizmo_ruler_exit; + gzt->cursor_get = gizmo_ruler_cursor_get; + + gzt->struct_size = sizeof(RulerItem); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Ruler Gizmo Group + * \{ */ + +static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup) +{ + RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__); + + if (view3d_ruler_from_gpencil(C, gzgroup)) { + /* nop */ + } + + wmWindow *win = CTX_wm_window(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + ruler_info->win = win; + ruler_info->sa = sa; + ruler_info->ar = ar; + + gzgroup->customdata = ruler_info; +} + +void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt) +{ + gzgt->name = "Ruler Widgets"; + gzgt->idname = view3d_gzgt_ruler_id; + + gzgt->flag |= WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL; + + gzgt->gzmap_params.spaceid = SPACE_VIEW3D; + gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW; + + gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool; + gzgt->setup = WIDGETGROUP_ruler_setup; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Ruler Operator + * \{ */ + +static bool view3d_ruler_poll(bContext *C) +{ + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); + if ((tref_rt == NULL) || + !STREQ(view3d_gzgt_ruler_id, tref_rt->gizmo_group) || + CTX_wm_region_view3d(C) == NULL) + { + return false; + } + return true; +} + +static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ar->regiondata; + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL))) + { + BKE_report(op->reports, RPT_WARNING, "Gizmos hidden in this view"); + return OPERATOR_CANCELLED; + } + + wmGizmoMap *gzmap = ar->gizmo_map; + wmGizmoGroup *gzgroup = WM_gizmomap_group_find(gzmap, view3d_gzgt_ruler_id); + const bool use_depth = (v3d->shading.type >= OB_SOLID); + + /* Create new line */ + RulerItem *ruler_item; + ruler_item = ruler_item_add(gzgroup); + + /* This is a little weak, but there is no real good way to tweak directly. */ + WM_gizmo_highlight_set(gzmap, &ruler_item->gz); + if (WM_operator_name_call( + C, "GIZMOGROUP_OT_gizmo_tweak", + WM_OP_INVOKE_REGION_WIN, NULL) == OPERATOR_RUNNING_MODAL) + { + RulerInfo *ruler_info = gzgroup->customdata; + RulerInteraction *inter = ruler_item->gz.interaction_data; + if (use_depth) { + /* snap the first point added, not essential but handy */ + inter->co_index = 0; + view3d_ruler_item_mousemove(ruler_info, ruler_item, event->mval, false, true); + copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]); + } + else { + negate_v3_v3(inter->drag_start_co, rv3d->ofs); + copy_v3_v3(ruler_item->co[0], inter->drag_start_co); + view3d_ruler_item_project(ruler_info, ruler_item->co[0], event->mval); + } + + copy_v3_v3(ruler_item->co[2], ruler_item->co[0]); + ruler_item->gz.highlight_part = inter->co_index = 2; + } + return OPERATOR_FINISHED; +} + +void VIEW3D_OT_ruler_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Ruler Add"; + ot->idname = "VIEW3D_OT_ruler_add"; + + ot->invoke = view3d_ruler_add_invoke; + ot->poll = view3d_ruler_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 27dda99e715..854bf01b158 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -41,11 +41,12 @@ #include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_main.h" #include "BKE_screen.h" #include "BKE_editmesh.h" +#include "DEG_depsgraph.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -68,162 +69,33 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event); #define B_SEL_EDGE 111 #define B_SEL_FACE 112 -/* XXX quickly ported across */ -static void handle_view3d_lock(bContext *C) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = CTX_wm_view3d(C); - - if (v3d != NULL && sa != NULL) { - if (v3d->localvd == NULL && v3d->scenelock && sa->spacetype == SPACE_VIEW3D) { - /* copy to scene */ - scene->lay = v3d->lay; - scene->layact = v3d->layact; - scene->camera = v3d->camera; - - /* not through notifier, listener don't have context - * and non-open screens or spaces need to be updated too */ - BKE_screen_view3d_main_sync(&bmain->screen, scene); - - /* notifiers for scene update */ - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - } - } -} - -/** - * layer code is on three levels actually: - * - here for operator - * - uiTemplateLayers in interface/ code for buttons - * - ED_view3d_scene_layer_set for RNA - */ -static void view3d_layers_editmode_ensure(Scene *scene, View3D *v3d) -{ - /* sanity check - when in editmode disallow switching the editmode layer off since its confusing - * an alternative would be to always draw the editmode object. */ - if (scene->obedit && (scene->obedit->lay & v3d->lay) == 0) { - int bit; - for (bit = 0; bit < 32; bit++) { - if (scene->obedit->lay & (1u << bit)) { - v3d->lay |= (1u << bit); - break; - } - } - } -} +/* -------------------------------------------------------------------- */ +/** \name Toggle Matcap Flip Operator + * \{ */ -static int view3d_layers_exec(bContext *C, wmOperator *op) +static int toggle_matcap_flip(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - int nr = RNA_int_get(op->ptr, "nr"); - const bool toggle = RNA_boolean_get(op->ptr, "toggle"); - - if (nr < 0) - return OPERATOR_CANCELLED; - - if (nr == 0) { - /* all layers */ - if (!v3d->lay_prev) - v3d->lay_prev = 1; - - if (toggle && v3d->lay == ((1 << 20) - 1)) { - /* return to active layer only */ - v3d->lay = v3d->lay_prev; - - view3d_layers_editmode_ensure(scene, v3d); - } - else { - v3d->lay_prev = v3d->lay; - v3d->lay |= (1 << 20) - 1; - } - } - else { - int bit; - nr--; - - if (RNA_boolean_get(op->ptr, "extend")) { - if (toggle && v3d->lay & (1 << nr) && (v3d->lay & ~(1 << nr))) - v3d->lay &= ~(1 << nr); - else - v3d->lay |= (1 << nr); - } - else { - v3d->lay = (1 << nr); - } - - view3d_layers_editmode_ensure(scene, v3d); - - /* set active layer, ensure to always have one */ - if (v3d->lay & (1 << nr)) - v3d->layact = 1 << nr; - else if ((v3d->lay & v3d->layact) == 0) { - for (bit = 0; bit < 32; bit++) { - if (v3d->lay & (1u << bit)) { - v3d->layact = (1u << bit); - break; - } - } - } - } - - if (v3d->scenelock) handle_view3d_lock(C); - - DAG_on_visible_update(CTX_data_main(C), false); - - ED_area_tag_redraw(sa); - - return OPERATOR_FINISHED; -} - -/* applies shift and alt, lazy coding or ok? :) */ -/* the local per-keymap-entry keymap will solve it */ -static int view3d_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - if (event->ctrl || event->oskey) - return OPERATOR_PASS_THROUGH; - - if (event->shift) - RNA_boolean_set(op->ptr, "extend", true); - else - RNA_boolean_set(op->ptr, "extend", false); - - if (event->alt) { - const int nr = RNA_int_get(op->ptr, "nr") + 10; - RNA_int_set(op->ptr, "nr", nr); - } - view3d_layers_exec(C, op); - + View3D *v3d = CTX_wm_view3d(C); + v3d->shading.flag ^= V3D_SHADING_MATCAP_FLIP_X; + ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C)); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); return OPERATOR_FINISHED; } -static bool view3d_layers_poll(bContext *C) -{ - return (ED_operator_view3d_active(C) && CTX_wm_view3d(C)->localvd == NULL); -} - -void VIEW3D_OT_layers(wmOperatorType *ot) +void VIEW3D_OT_toggle_matcap_flip(wmOperatorType *ot) { /* identifiers */ - ot->name = "Layers"; - ot->description = "Toggle layer(s) visibility"; - ot->idname = "VIEW3D_OT_layers"; + ot->name = "Flip MatCap"; + ot->description = "Flip MatCap"; + ot->idname = "VIEW3D_OT_toggle_matcap_flip"; /* api callbacks */ - ot->invoke = view3d_layers_invoke; - ot->exec = view3d_layers_exec; - ot->poll = view3d_layers_poll; + ot->exec = toggle_matcap_flip; + ot->poll = ED_operator_view3d_active; +} - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +/** \} */ - RNA_def_int(ot->srna, "nr", 1, 0, 20, "Number", "The layer number to set, zero for all layers", 0, 20); - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Add this layer to the current view layers"); - RNA_def_boolean(ot->srna, "toggle", 1, "Toggle", "Toggle the layer"); -} static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) { @@ -278,21 +150,66 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C) } } +static void uiTemplatePaintModeSelection(uiLayout *layout, struct bContext *C) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + + /* Gizmos aren't used in paint modes */ + if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) { + /* masks aren't used for sculpt and particle painting */ + PointerRNA meshptr; + + RNA_pointer_create(ob->data, &RNA_Mesh, ob->data, &meshptr); + if (ob->mode & (OB_MODE_TEXTURE_PAINT)) { + uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + } + else { + uiLayout *row = uiLayoutRow(layout, true); + uiItemR(row, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + if (ob->mode & OB_MODE_WEIGHT_PAINT) { + uiItemR(row, &meshptr, "use_paint_mask_vertex", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + } + } + } +} + +void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C) +{ + /* Extracted from: uiTemplateHeader3D */ + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + Object *obedit = CTX_data_edit_object(C); + bGPdata *gpd = CTX_data_gpencil_data(C); + + bool is_paint = ( + ob && !(gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) && + ELEM(ob->mode, + OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT)); + + uiTemplateEditModeSelection(layout, C); + if ((obedit == NULL) && is_paint) { + uiTemplatePaintModeSelection(layout, C); + } +} + void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) { bScreen *screen = CTX_wm_screen(C); ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); ToolSettings *ts = CTX_data_tool_settings(C); PointerRNA v3dptr, toolsptr, sceneptr; - Object *ob = OBACT; + Object *ob = OBACT(view_layer); Object *obedit = CTX_data_edit_object(C); bGPdata *gpd = CTX_data_gpencil_data(C); uiBlock *block; - uiLayout *row; - bool is_paint = false; - int modeselect; + bool is_paint = ( + ob && !(gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) && + ELEM(ob->mode, + OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT)); RNA_pointer_create(&screen->id, &RNA_SpaceView3D, v3d, &v3dptr); RNA_pointer_create(&scene->id, &RNA_ToolSettings, ts, &toolsptr); @@ -304,81 +221,39 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) /* other buttons: */ UI_block_emboss_set(block, UI_EMBOSS); - /* mode */ - if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { - modeselect = OB_MODE_GPENCIL; - } - else if (ob) { - modeselect = ob->mode; - is_paint = ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT); - } - else { - modeselect = OB_MODE_OBJECT; - } - - row = uiLayoutRow(layout, false); - { - const EnumPropertyItem *item = rna_enum_object_mode_items; - const char *name = ""; - int icon = ICON_OBJECT_DATAMODE; - - while (item->identifier) { - if (item->value == modeselect && item->identifier[0]) { - name = IFACE_(item->name); - icon = item->icon; - break; - } - item++; - } - - uiItemMenuEnumO(row, C, "OBJECT_OT_mode_set", "mode", name, icon); - } - - /* Draw type */ - uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - - row = uiLayoutRow(layout, true); + /* moved to topbar */ +#if 0 + uiLayout *row = uiLayoutRow(layout, true); uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); if (!ob || ELEM(ob->mode, OB_MODE_OBJECT, OB_MODE_POSE, OB_MODE_WEIGHT_PAINT)) { uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); } +#endif if (obedit == NULL && is_paint) { - /* Manipulators aren't used in paint modes */ - if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) { - /* masks aren't used for sculpt and particle painting */ - PointerRNA meshptr; - - RNA_pointer_create(ob->data, &RNA_Mesh, ob->data, &meshptr); - if (ob->mode & (OB_MODE_TEXTURE_PAINT)) { - uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - } - else { - row = uiLayoutRow(layout, true); - uiItemR(row, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - uiItemR(row, &meshptr, "use_paint_mask_vertex", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - } - } + /* Currently Python calls this directly. */ +#if 0 + uiTemplatePaintModeSelection(layout, C); +#endif + } else { - /* Transform widget / manipulators */ + /* Moved to popover and topbar. */ +#if 0 + /* Transform widget / gizmos */ row = uiLayoutRow(layout, true); - uiItemR(row, &v3dptr, "show_manipulator", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - if (v3d->twflag & V3D_USE_MANIPULATOR) { - uiItemR(row, &v3dptr, "transform_manipulators", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - } - uiItemR(row, &v3dptr, "transform_orientation", 0, "", ICON_NONE); + uiItemR(row, &v3dptr, "show_gizmo", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + uiItemR(row, &sceneptr, "transform_orientation", 0, "", ICON_NONE); +#endif } if (obedit == NULL && v3d->localvd == NULL) { - unsigned int ob_lay = ob ? ob->lay : 0; - - /* Layers */ - uiTemplateLayers(layout, v3d->scenelock ? &sceneptr : &v3dptr, "layers", &v3dptr, "layers_used", ob_lay); - /* Scene lock */ uiItemR(layout, &v3dptr, "lock_camera_and_layers", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); } + /* Currently Python calls this directly. */ +#if 0 uiTemplateEditModeSelection(layout, C); +#endif } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index be444ce27cd..164c444d9a5 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -37,8 +37,10 @@ struct ARegion; struct ARegionType; +struct Base; struct BoundBox; -struct DerivedMesh; +struct GPUBatch; +struct Depsgraph; struct Object; struct SmokeDomainSettings; struct bAnimVizSettings; @@ -46,9 +48,12 @@ struct bContext; struct bMotionPath; struct bPoseChannel; struct Mesh; +struct ViewLayer; struct wmOperatorType; -struct wmWindowManager; struct wmKeyConfig; +struct wmGizmoGroupType; +struct wmGizmoType; +struct wmWindowManager; /* drawing flags: */ enum { @@ -57,14 +62,9 @@ enum { DRAW_SCENESET = (1 << 2) }; -/* draw_mesh_fancy/draw_mesh_textured draw_flags */ -enum { - DRAW_MODIFIERS_PREVIEW = (1 << 0), - DRAW_FACE_SELECT = (1 << 1) -}; - /* view3d_header.c */ void VIEW3D_OT_layers(struct wmOperatorType *ot); +void VIEW3D_OT_toggle_matcap_flip(struct wmOperatorType *ot); /* view3d_ops.c */ void view3d_operatortypes(void); @@ -82,7 +82,8 @@ void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot); void VIEW3D_OT_ndof_all(struct wmOperatorType *ot); #endif /* WITH_INPUT_NDOF */ void VIEW3D_OT_view_all(struct wmOperatorType *ot); -void VIEW3D_OT_viewnumpad(struct wmOperatorType *ot); +void VIEW3D_OT_view_axis(struct wmOperatorType *ot); +void VIEW3D_OT_view_camera(struct wmOperatorType *ot); void VIEW3D_OT_view_selected(struct wmOperatorType *ot); void VIEW3D_OT_view_lock_clear(struct wmOperatorType *ot); void VIEW3D_OT_view_lock_to_active(struct wmOperatorType *ot); @@ -97,17 +98,16 @@ void VIEW3D_OT_background_image_add(struct wmOperatorType *ot); void VIEW3D_OT_background_image_remove(struct wmOperatorType *ot); void VIEW3D_OT_view_orbit(struct wmOperatorType *ot); void VIEW3D_OT_view_roll(struct wmOperatorType *ot); -void VIEW3D_OT_clip_border(struct wmOperatorType *ot); +// void VIEW3D_OT_clip_border(struct wmOperatorType *ot); void VIEW3D_OT_cursor3d(struct wmOperatorType *ot); -void VIEW3D_OT_manipulator(struct wmOperatorType *ot); -void VIEW3D_OT_enable_manipulator(struct wmOperatorType *ot); void VIEW3D_OT_render_border(struct wmOperatorType *ot); void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot); void VIEW3D_OT_zoom_border(struct wmOperatorType *ot); -void VIEW3D_OT_toggle_render(struct wmOperatorType *ot); +void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot); +void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot); -void view3d_boxview_copy(ScrArea *sa, ARegion *ar); -void view3d_boxview_sync(ScrArea *sa, ARegion *ar); +void view3d_boxview_copy(struct ScrArea *sa, struct ARegion *ar); +void view3d_boxview_sync(struct ScrArea *sa, struct ARegion *ar); void view3d_orbit_apply_dyn_ofs( float r_ofs[3], const float ofs_old[3], const float viewquat_old[4], @@ -133,104 +133,51 @@ void VIEW3D_OT_walk(struct wmOperatorType *ot); /* view3d_ruler.c */ void VIEW3D_OT_ruler(struct wmOperatorType *ot); -/* drawanim.c */ -void draw_motion_paths_init(View3D *v3d, struct ARegion *ar); -void draw_motion_path_instance(Scene *scene, - struct Object *ob, struct bPoseChannel *pchan, - struct bAnimVizSettings *avs, struct bMotionPath *mpath); -void draw_motion_paths_cleanup(View3D *v3d); - - - /* drawobject.c */ -void draw_object( - struct Main *bmain, Scene *scene, struct ARegion *ar, View3D *v3d, - Base *base, const short dflag); -void draw_object_select( - struct Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, - Base *base, const short dflag); - -bool draw_glsl_material(Scene *scene, struct Object *ob, View3D *v3d, const char dt); -void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob, const char dt, int outline); -void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, struct Object *ob); -void drawaxes(const float viewmat_local[4][4], float size, char drawtype); - -void view3d_cached_text_draw_begin(void); -void view3d_cached_text_draw_add(const float co[3], - const char *str, const size_t str_len, - short xoffs, short flag, const unsigned char col[4]); -void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write); - -bool check_object_draw_texture(struct Scene *scene, struct View3D *v3d, const char drawtype); - -enum { - V3D_CACHE_TEXT_ZBUF = (1 << 0), - V3D_CACHE_TEXT_WORLDSPACE = (1 << 1), - V3D_CACHE_TEXT_ASCII = (1 << 2), - V3D_CACHE_TEXT_GLOBALSPACE = (1 << 3), - V3D_CACHE_TEXT_LOCALCLIP = (1 << 4) -}; +void draw_object_backbufsel( + struct Depsgraph *depsgraph, Scene *scene, + View3D *v3d, RegionView3D *rv3d, struct Object *ob, + short select_mode); int view3d_effective_drawtype(const struct View3D *v3d); -/* drawarmature.c */ -bool draw_armature( - Scene *scene, View3D *v3d, ARegion *ar, Base *base, - const short dt, const short dflag, const unsigned char ob_wire_col[4], - const bool is_outline); - -/* drawmesh.c */ -void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, - struct Object *ob, struct DerivedMesh *dm, const int draw_flags); -void draw_mesh_face_select( - struct RegionView3D *rv3d, struct Mesh *me, struct DerivedMesh *dm, - bool draw_select_edges); -void draw_mesh_paint_weight_faces(struct DerivedMesh *dm, const bool do_light, - void *facemask_cb, void *user_data); -void draw_mesh_paint_vcolor_faces(struct DerivedMesh *dm, const bool use_light, - void *facemask_cb, void *user_data, - const struct Mesh *me); -void draw_mesh_paint_weight_edges(RegionView3D *rv3d, struct DerivedMesh *dm, - const bool use_depth, const bool use_alpha, - void *edgemask_cb, void *user_data); -void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, - struct Object *ob, struct DerivedMesh *dm, const int draw_flags); - -/* drawsimdebug.c */ -void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar); - /* view3d_draw.c */ void view3d_main_region_draw(const struct bContext *C, struct ARegion *ar); +void view3d_draw_region_info(const struct bContext *C, struct ARegion *ar); void ED_view3d_draw_depth( - struct Main *bmain, struct Scene *scene, + struct Depsgraph *depsgraph, struct ARegion *ar, View3D *v3d, bool alphaoverride); -void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d); + +/* view3d_draw_legacy.c */ +void ED_view3d_draw_depth_gpencil(struct Depsgraph *depsgraph, Scene *scene, struct ARegion *ar, View3D *v3d); + void ED_view3d_draw_select_loop( - ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, + struct Depsgraph *depsgraph, ViewContext *vc, Scene *scene, struct ViewLayer *view_layer, View3D *v3d, struct ARegion *ar, bool use_obedit_skip, bool use_nearest); -void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag);\ +void ED_view3d_draw_depth_loop( + struct Depsgraph *depsgraph, Scene *scene, struct ARegion *ar, View3D *v3d); + +void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag); -void circf(float x, float y, float rad); -void circ(float x, float y, float rad); void view3d_update_depths_rect(struct ARegion *ar, struct ViewDepths *d, struct rcti *rect); float view3d_depth_near(struct ViewDepths *d); /* view3d_select.c */ void VIEW3D_OT_select(struct wmOperatorType *ot); void VIEW3D_OT_select_circle(struct wmOperatorType *ot); -void VIEW3D_OT_select_border(struct wmOperatorType *ot); +void VIEW3D_OT_select_box(struct wmOperatorType *ot); void VIEW3D_OT_select_lasso(struct wmOperatorType *ot); void VIEW3D_OT_select_menu(struct wmOperatorType *ot); +/* view3d_view.c */ void VIEW3D_OT_smoothview(struct wmOperatorType *ot); void VIEW3D_OT_camera_to_view(struct wmOperatorType *ot); void VIEW3D_OT_camera_to_view_selected(struct wmOperatorType *ot); void VIEW3D_OT_object_as_camera(struct wmOperatorType *ot); void VIEW3D_OT_localview(struct wmOperatorType *ot); -void VIEW3D_OT_game_start(struct wmOperatorType *ot); - +void VIEW3D_OT_localview_remove_from(struct wmOperatorType *ot); bool ED_view3d_boundbox_clip_ex(const RegionView3D *rv3d, const struct BoundBox *bb, float obmat[4][4]); bool ED_view3d_boundbox_clip(RegionView3D *rv3d, const struct BoundBox *bb); @@ -243,6 +190,7 @@ typedef struct V3D_SmoothParams { } V3D_SmoothParams; void ED_view3d_smooth_view_ex( + const struct Depsgraph *depsgraph, struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa, struct View3D *v3d, struct ARegion *ar, const int smooth_viewtx, const V3D_SmoothParams *sview); @@ -257,9 +205,10 @@ void ED_view3d_smooth_view_force_finish( struct View3D *v3d, struct ARegion *ar); void view3d_winmatrix_set( - ARegion *ar, const View3D *v3d, const rcti *rect); + struct Depsgraph *depsgraph, + struct ARegion *ar, const View3D *v3d, const rcti *rect); void view3d_viewmatrix_set( - Scene *scene, + struct Depsgraph *depsgraph, Scene *scene, const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]); void fly_modal_keymap(struct wmKeyConfig *keyconf); @@ -271,11 +220,12 @@ void viewdolly_modal_keymap(struct wmKeyConfig *keyconf); /* view3d_buttons.c */ void VIEW3D_OT_properties(struct wmOperatorType *ot); +void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot); void view3d_buttons_register(struct ARegionType *art); /* view3d_camera_control.c */ struct View3DCameraControl *ED_view3d_cameracontrol_acquire( - Scene *scene, View3D *v3d, RegionView3D *rv3d, + struct Depsgraph *depsgraph, Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root); void ED_view3d_cameracontrol_update( struct View3DCameraControl *vctrl, @@ -284,13 +234,11 @@ void ED_view3d_cameracontrol_update( void ED_view3d_cameracontrol_release( struct View3DCameraControl *vctrl, const bool restore); -Object *ED_view3d_cameracontrol_object_get( +struct Object *ED_view3d_cameracontrol_object_get( struct View3DCameraControl *vctrl); /* view3d_toolbar.c */ void VIEW3D_OT_toolshelf(struct wmOperatorType *ot); -void view3d_toolshelf_register(struct ARegionType *art); -void view3d_tool_props_register(struct ARegionType *art); /* view3d_snap.c */ bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]); @@ -304,11 +252,30 @@ void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot); /* space_view3d.c */ -ARegion *view3d_has_buttons_region(ScrArea *sa); -ARegion *view3d_has_tools_region(ScrArea *sa); +struct ARegion *view3d_has_buttons_region(struct ScrArea *sa); +struct ARegion *view3d_has_tools_region(struct ScrArea *sa); extern const char *view3d_context_dir[]; /* doc access */ +/* view3d_widgets.c */ +void VIEW3D_GGT_lamp_spot(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_lamp_area(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_lamp_target(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_camera(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_camera_view(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_force_field(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_empty_image(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_armature_spline(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_navigate(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_mesh_preselect_elem(struct wmGizmoGroupType *gzgt); +void VIEW3D_GGT_mesh_preselect_edgering(struct wmGizmoGroupType *gzgt); + +void VIEW3D_GGT_ruler(struct wmGizmoGroupType *gzgt); +void VIEW3D_GT_ruler_item(struct wmGizmoType *gzt); +void VIEW3D_OT_ruler_add(struct wmOperatorType *ot); + +void VIEW3D_GT_navigate_rotate(struct wmGizmoType *gzt); + /* draw_volume.c */ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob, const float min[3], const float max[3], diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index ef7b01f7a21..9ee7cbabd2a 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -28,6 +28,7 @@ #include "DNA_lattice_types.h" #include "DNA_meta_types.h" #include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_armature_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -35,11 +36,18 @@ #include "BLI_utildefines.h" #include "BLI_rect.h" +#include "BKE_action.h" #include "BKE_armature.h" #include "BKE_curve.h" #include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_editmesh.h" +#include "BKE_context.h" +#include "BKE_mesh_runtime.h" +#include "BKE_mesh_iterators.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "bmesh.h" @@ -109,7 +117,12 @@ void meshobject_foreachScreenVert( void *userData, eV3DProjTest clip_flag) { foreachScreenObjectVert_userData data; - DerivedMesh *dm = mesh_get_derived_deform(vc->scene, vc->obact, CD_MASK_BAREMESH); + Mesh *me; + + Scene *scene_eval = DEG_get_evaluated_scene(vc->depsgraph); + Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact); + + me = mesh_get_eval_deform(vc->depsgraph, scene_eval, ob_eval, CD_MASK_BAREMESH); ED_view3d_check_mats_rv3d(vc->rv3d); @@ -122,9 +135,7 @@ void meshobject_foreachScreenVert( ED_view3d_clipping_local(vc->rv3d, vc->obact->obmat); } - dm->foreachMappedVert(dm, meshobject_foreachScreenVert__mapFunc, &data, DM_FOREACH_NOP); - - dm->release(dm); + BKE_mesh_foreach_mapped_vert(me, meshobject_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP); } static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3], @@ -150,7 +161,8 @@ void mesh_foreachScreenVert( void *userData, eV3DProjTest clip_flag) { foreachScreenVert_userData data; - DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + + Mesh *me = editbmesh_get_eval_cage_from_orig(vc->depsgraph, vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); ED_view3d_check_mats_rv3d(vc->rv3d); @@ -164,9 +176,7 @@ void mesh_foreachScreenVert( } BM_mesh_elem_table_ensure(vc->em->bm, BM_VERT); - dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data, DM_FOREACH_NOP); - - dm->release(dm); + BKE_mesh_foreach_mapped_vert(me, mesh_foreachScreenVert__mapFunc, &data, MESH_FOREACH_NOP); } /* ------------------------------------------------------------------------ */ @@ -204,7 +214,8 @@ void mesh_foreachScreenEdge( void *userData, eV3DProjTest clip_flag) { foreachScreenEdge_userData data; - DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + + Mesh *me = editbmesh_get_eval_cage_from_orig(vc->depsgraph, vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); ED_view3d_check_mats_rv3d(vc->rv3d); @@ -224,9 +235,7 @@ void mesh_foreachScreenEdge( } BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE); - dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data); - - dm->release(dm); + BKE_mesh_foreach_mapped_edge(me, mesh_foreachScreenEdge__mapFunc, &data); } /* ------------------------------------------------------------------------ */ @@ -250,8 +259,8 @@ void mesh_foreachScreenFace( void *userData, const eV3DProjTest clip_flag) { foreachScreenFace_userData data; - DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + Mesh *me = editbmesh_get_eval_cage_from_orig(vc->depsgraph, vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); ED_view3d_check_mats_rv3d(vc->rv3d); data.vc = *vc; @@ -260,9 +269,7 @@ void mesh_foreachScreenFace( data.clip_flag = clip_flag; BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE); - dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data, DM_FOREACH_NOP); - - dm->release(dm); + BKE_mesh_foreach_mapped_face_center(me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); } /* ------------------------------------------------------------------------ */ @@ -291,7 +298,7 @@ void nurbs_foreachScreenVert( if (bezt->hide == 0) { float screen_co[2]; - if (cu->drawflag & CU_HIDE_HANDLES) { + if ((vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { if (ED_view3d_project_float_object(vc->ar, bezt->vec[1], screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == V3D_PROJ_RET_OK) { @@ -366,7 +373,7 @@ void lattice_foreachScreenVert( Object *obedit = vc->obedit; Lattice *lt = obedit->data; BPoint *bp = lt->editlatt->latt->def; - DispList *dl = obedit->curve_cache ? BKE_displist_find(&obedit->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = obedit->runtime.curve_cache ? BKE_displist_find(&obedit->runtime.curve_cache->disp, DL_VERTS) : NULL; const float *co = dl ? dl->verts : NULL; int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; @@ -438,19 +445,21 @@ void pose_foreachScreenBone( void (*func)(void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]), void *userData, const eV3DProjTest clip_flag) { - bArmature *arm = vc->obact->data; + const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact); + const bArmature *arm_eval = ob_eval->data; bPose *pose = vc->obact->pose; bPoseChannel *pchan; ED_view3d_check_mats_rv3d(vc->rv3d); for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { - if (PBONE_VISIBLE(arm, pchan->bone)) { + if (PBONE_VISIBLE(arm_eval, pchan->bone)) { + bPoseChannel *pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, pchan->name); float screen_co_a[2], screen_co_b[2]; int points_proj_tot = 0; /* project head location to screenspace */ - if (ED_view3d_project_float_object(vc->ar, pchan->pose_head, screen_co_a, clip_flag) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object(vc->ar, pchan_eval->pose_head, screen_co_a, clip_flag) == V3D_PROJ_RET_OK) { points_proj_tot++; } else { @@ -459,7 +468,7 @@ void pose_foreachScreenBone( } /* project tail location to screenspace */ - if (ED_view3d_project_float_object(vc->ar, pchan->pose_tail, screen_co_b, clip_flag) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_object(vc->ar, pchan_eval->pose_tail, screen_co_b, clip_flag) == V3D_PROJ_RET_OK) { points_proj_tot++; } else { diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 5d662282e56..46a00ffeacf 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -33,8 +33,8 @@ #include <math.h> +#include "DNA_collection_types.h" #include "DNA_object_types.h" -#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -45,6 +45,7 @@ #include "BKE_appdir.h" #include "BKE_blender_copybuffer.h" +#include "BKE_collection.h" #include "BKE_context.h" #include "BKE_main.h" #include "BKE_report.h" @@ -56,6 +57,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "view3d_intern.h" @@ -80,12 +82,14 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - for (Group *group = bmain->group.first; group; group = group->id.next) { - for (GroupObject *go = group->gobject.first; go; go = go->next) { - if (go->ob && (go->ob->id.tag & LIB_TAG_DOIT)) { - BKE_copybuffer_tag_ID(&group->id); + for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) { + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + Object *object = cob->ob; + + if (object && (object->id.tag & LIB_TAG_DOIT)) { + BKE_copybuffer_tag_ID(&collection->id); /* don't expand out to all other objects */ - group->id.tag &= ~LIB_TAG_NEED_EXPAND; + collection->id.tag &= ~LIB_TAG_NEED_EXPAND; break; } } @@ -119,8 +123,8 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT; - if (RNA_boolean_get(op->ptr, "active_layer")) - flag |= FILE_ACTIVELAY; + if (RNA_boolean_get(op->ptr, "active_collection")) + flag |= FILE_ACTIVE_COLLECTION; BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); if (BKE_copybuffer_paste(C, str, flag, op->reports)) { @@ -152,7 +156,7 @@ static void VIEW3D_OT_pastebuffer(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "autoselect", true, "Select", "Select pasted objects"); - RNA_def_boolean(ot->srna, "active_layer", true, "Active Layer", "Put pasted objects on the active layer"); + RNA_def_boolean(ot->srna, "active_collection", true, "Active Collection", "Put pasted objects on the active collection"); } /* ************************** registration **********************************/ @@ -171,7 +175,8 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_ndof_all); #endif /* WITH_INPUT_NDOF */ WM_operatortype_append(VIEW3D_OT_view_all); - WM_operatortype_append(VIEW3D_OT_viewnumpad); + WM_operatortype_append(VIEW3D_OT_view_axis); + WM_operatortype_append(VIEW3D_OT_view_camera); WM_operatortype_append(VIEW3D_OT_view_orbit); WM_operatortype_append(VIEW3D_OT_view_roll); WM_operatortype_append(VIEW3D_OT_view_pan); @@ -186,15 +191,13 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_view_center_camera); WM_operatortype_append(VIEW3D_OT_view_center_lock); WM_operatortype_append(VIEW3D_OT_select); - WM_operatortype_append(VIEW3D_OT_select_border); - WM_operatortype_append(VIEW3D_OT_clip_border); + WM_operatortype_append(VIEW3D_OT_select_box); + // WM_operatortype_append(VIEW3D_OT_clip_border); WM_operatortype_append(VIEW3D_OT_select_circle); WM_operatortype_append(VIEW3D_OT_smoothview); WM_operatortype_append(VIEW3D_OT_render_border); WM_operatortype_append(VIEW3D_OT_clear_render_border); WM_operatortype_append(VIEW3D_OT_zoom_border); - WM_operatortype_append(VIEW3D_OT_manipulator); - WM_operatortype_append(VIEW3D_OT_enable_manipulator); WM_operatortype_append(VIEW3D_OT_cursor3d); WM_operatortype_append(VIEW3D_OT_select_lasso); WM_operatortype_append(VIEW3D_OT_select_menu); @@ -202,16 +205,15 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_camera_to_view_selected); WM_operatortype_append(VIEW3D_OT_object_as_camera); WM_operatortype_append(VIEW3D_OT_localview); - WM_operatortype_append(VIEW3D_OT_game_start); + WM_operatortype_append(VIEW3D_OT_localview_remove_from); WM_operatortype_append(VIEW3D_OT_fly); WM_operatortype_append(VIEW3D_OT_walk); WM_operatortype_append(VIEW3D_OT_navigate); - WM_operatortype_append(VIEW3D_OT_ruler); - WM_operatortype_append(VIEW3D_OT_layers); WM_operatortype_append(VIEW3D_OT_copybuffer); WM_operatortype_append(VIEW3D_OT_pastebuffer); WM_operatortype_append(VIEW3D_OT_properties); + WM_operatortype_append(VIEW3D_OT_object_mode_pie_or_toggle); WM_operatortype_append(VIEW3D_OT_toolshelf); WM_operatortype_append(VIEW3D_OT_snap_selected_to_grid); @@ -222,334 +224,21 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active); - WM_operatortype_append(VIEW3D_OT_toggle_render); + WM_operatortype_append(VIEW3D_OT_toggle_shading); + WM_operatortype_append(VIEW3D_OT_toggle_xray); + WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip); + + WM_operatortype_append(VIEW3D_OT_ruler_add); transform_operatortypes(); } void view3d_keymap(wmKeyConfig *keyconf) { - wmKeyMap *keymap; - wmKeyMapItem *kmi; - - keymap = WM_keymap_ensure(keyconf, "3D View Generic", SPACE_VIEW3D, 0); - - WM_keymap_add_item(keymap, "VIEW3D_OT_properties", NKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_toolshelf", TKEY, KM_PRESS, 0, 0); + WM_keymap_ensure(keyconf, "3D View Generic", SPACE_VIEW3D, 0); /* only for region 3D window */ - keymap = WM_keymap_ensure(keyconf, "3D View", SPACE_VIEW3D, 0); - - /* Shift+LMB behavior first, so it has priority over KM_ANY item below. */ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "release_confirm", true); - RNA_boolean_set(kmi->ptr, "use_planar_constraint", true); - RNA_boolean_set(kmi->ptr, "use_accurate", false); - - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "release_confirm", true); - RNA_boolean_set(kmi->ptr, "use_planar_constraint", false); - RNA_boolean_set(kmi->ptr, "use_accurate", true); - - /* Using KM_ANY here to allow holding modifiers before starting to transform. */ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0); - RNA_boolean_set(kmi->ptr, "release_confirm", true); - RNA_boolean_set(kmi->ptr, "use_planar_constraint", false); - RNA_boolean_set(kmi->ptr, "use_accurate", false); - - WM_keymap_verify_item(keymap, "VIEW3D_OT_cursor3d", ACTIONMOUSE, KM_PRESS, 0, 0); - - WM_keymap_verify_item(keymap, "VIEW3D_OT_rotate", MIDDLEMOUSE, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "VIEW3D_OT_move", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0); - WM_keymap_verify_item(keymap, "VIEW3D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0); - WM_keymap_verify_item(keymap, "VIEW3D_OT_dolly", MIDDLEMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", PADPERIOD, KM_PRESS, KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "use_all_regions", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "use_all_regions", false); - - WM_keymap_verify_item(keymap, "VIEW3D_OT_view_lock_to_active", PADPERIOD, KM_PRESS, KM_SHIFT, 0); - WM_keymap_verify_item(keymap, "VIEW3D_OT_view_lock_clear", PADPERIOD, KM_PRESS, KM_ALT, 0); - - WM_keymap_verify_item(keymap, "VIEW3D_OT_navigate", FKEY, KM_PRESS, KM_SHIFT, 0); - - WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0); - - WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, 0, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEROTATE, 0, 0, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEZOOM, 0, 0, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0); - - /*numpad +/-*/ - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", PADPLUSKEY, KM_PRESS, 0, 0)->ptr, "delta", 1); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", PADMINUS, KM_PRESS, 0, 0)->ptr, "delta", -1); - /*ctrl +/-*/ - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", EQUALKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MINUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1); - - /*wheel mouse forward/back*/ - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", WHEELINMOUSE, KM_PRESS, 0, 0)->ptr, "delta", 1); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", WHEELOUTMOUSE, KM_PRESS, 0, 0)->ptr, "delta", -1); - - /* ... and for dolly */ - /*numpad +/-*/ - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_dolly", PADPLUSKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "delta", 1); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_dolly", PADMINUS, KM_PRESS, KM_SHIFT, 0)->ptr, "delta", -1); - /*ctrl +/-*/ - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_dolly", EQUALKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "delta", 1); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_dolly", MINUSKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "delta", -1); - - WM_keymap_add_item(keymap, "VIEW3D_OT_zoom_camera_1_to_1", PADENTER, KM_PRESS, KM_SHIFT, 0); - - WM_keymap_add_item(keymap, "VIEW3D_OT_view_center_camera", HOMEKEY, KM_PRESS, 0, 0); /* only with camera view */ - WM_keymap_add_item(keymap, "VIEW3D_OT_view_center_lock", HOMEKEY, KM_PRESS, 0, 0); /* only with lock view */ - - WM_keymap_add_item(keymap, "VIEW3D_OT_view_center_cursor", HOMEKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_view_center_pick", FKEY, KM_PRESS, KM_ALT, 0); - - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "center", false); /* only without camera view */ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", HOMEKEY, KM_PRESS, KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "use_all_regions", true); - RNA_boolean_set(kmi->ptr, "center", false); /* only without camera view */ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", CKEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "center", true); - - /* numpad view hotkeys*/ - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD0, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_CAMERA); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD2, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPDOWN); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD3, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD4, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPLEFT); - WM_keymap_add_item(keymap, "VIEW3D_OT_view_persportho", PAD5, KM_PRESS, 0, 0); - - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD6, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPRIGHT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD7, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD8, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPUP); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_CTRL, 0)->ptr, "type", RV3D_VIEW_BACK); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD3, KM_PRESS, KM_CTRL, 0)->ptr, "type", RV3D_VIEW_LEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD7, KM_PRESS, KM_CTRL, 0)->ptr, "type", RV3D_VIEW_BOTTOM); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD2, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANDOWN); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD4, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD6, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANUP); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPLEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD6, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", PAD9, KM_PRESS, 0, 0); - RNA_enum_set(kmi->ptr, "type", V3D_VIEW_STEPRIGHT); - RNA_float_set(kmi->ptr, "angle", (float)M_PI); - - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_PANUP); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_PANDOWN); - - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPLEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELUPMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPUP); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPDOWN); - - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPLEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT); - - /* active aligned, replaces '*' key in 2.4x */ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT); - RNA_boolean_set(kmi->ptr, "align_active", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD3, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT); - RNA_boolean_set(kmi->ptr, "align_active", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD7, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP); - RNA_boolean_set(kmi->ptr, "align_active", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_BACK); - RNA_boolean_set(kmi->ptr, "align_active", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD3, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_LEFT); - RNA_boolean_set(kmi->ptr, "align_active", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD7, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_BOTTOM); - RNA_boolean_set(kmi->ptr, "align_active", true); - - WM_keymap_add_item(keymap, "VIEW3D_OT_localview", PADSLASHKEY, KM_PRESS, 0, 0); - -#ifdef WITH_INPUT_NDOF - /* note: positioned here so keymaps show keyboard keys if assigned */ - /* 3D mouse */ - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit_zoom", NDOF_MOTION, 0, 0, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit", NDOF_MOTION, 0, KM_CTRL, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, KM_CTRL | KM_SHIFT, 0); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "use_all_regions", false); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPLEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "type", V3D_VIEW_STEPRIGHT); - - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP); - RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM); - - /* 3D mouse align */ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT); - RNA_boolean_set(kmi->ptr, "align_active", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT); - RNA_boolean_set(kmi->ptr, "align_active", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0); - RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP); - RNA_boolean_set(kmi->ptr, "align_active", true); -#endif /* WITH_INPUT_NDOF */ - - /* layers, shift + alt are properties set in invoke() */ - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ACCENTGRAVEKEY, KM_PRESS, 0, 0)->ptr, "nr", 0); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ONEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 1); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", TWOKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 2); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", THREEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 3); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", FOURKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 4); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", FIVEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 5); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", SIXKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 6); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", SEVENKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 7); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", EIGHTKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 8); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", NINEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 9); - RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ZEROKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 10); - - /* drawtype */ - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.viewport_shade"); - RNA_string_set(kmi->ptr, "value_1", "SOLID"); - RNA_string_set(kmi->ptr, "value_2", "WIREFRAME"); - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", ZKEY, KM_PRESS, KM_ALT, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.viewport_shade"); - RNA_string_set(kmi->ptr, "value_1", "SOLID"); - RNA_string_set(kmi->ptr, "value_2", "TEXTURED"); - - WM_keymap_add_item(keymap, "VIEW3D_OT_toggle_render", ZKEY, KM_PRESS, KM_SHIFT, 0); - - /* selection*/ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "extend", false); - RNA_boolean_set(kmi->ptr, "deselect", false); - RNA_boolean_set(kmi->ptr, "toggle", false); - RNA_boolean_set(kmi->ptr, "center", false); - RNA_boolean_set(kmi->ptr, "object", false); - RNA_boolean_set(kmi->ptr, "enumerate", false); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "extend", false); - RNA_boolean_set(kmi->ptr, "deselect", false); - RNA_boolean_set(kmi->ptr, "toggle", true); - RNA_boolean_set(kmi->ptr, "center", false); - RNA_boolean_set(kmi->ptr, "object", false); - RNA_boolean_set(kmi->ptr, "enumerate", false); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "extend", false); - RNA_boolean_set(kmi->ptr, "deselect", false); - RNA_boolean_set(kmi->ptr, "toggle", false); - RNA_boolean_set(kmi->ptr, "center", true); - RNA_boolean_set(kmi->ptr, "object", true); /* use Ctrl+Select for 2 purposes */ - RNA_boolean_set(kmi->ptr, "enumerate", false); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); - RNA_boolean_set(kmi->ptr, "extend", false); - RNA_boolean_set(kmi->ptr, "deselect", false); - RNA_boolean_set(kmi->ptr, "toggle", false); - RNA_boolean_set(kmi->ptr, "center", false); - RNA_boolean_set(kmi->ptr, "object", false); - RNA_boolean_set(kmi->ptr, "enumerate", true); - - /* selection key-combinations */ - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "extend", true); - RNA_boolean_set(kmi->ptr, "deselect", false); - RNA_boolean_set(kmi->ptr, "toggle", true); - RNA_boolean_set(kmi->ptr, "center", true); - RNA_boolean_set(kmi->ptr, "object", false); - RNA_boolean_set(kmi->ptr, "enumerate", false); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL | KM_ALT, 0); - RNA_boolean_set(kmi->ptr, "extend", false); - RNA_boolean_set(kmi->ptr, "deselect", false); - RNA_boolean_set(kmi->ptr, "toggle", false); - RNA_boolean_set(kmi->ptr, "center", true); - RNA_boolean_set(kmi->ptr, "object", false); - RNA_boolean_set(kmi->ptr, "enumerate", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0); - RNA_boolean_set(kmi->ptr, "extend", false); - RNA_boolean_set(kmi->ptr, "deselect", false); - RNA_boolean_set(kmi->ptr, "toggle", true); - RNA_boolean_set(kmi->ptr, "center", false); - RNA_boolean_set(kmi->ptr, "object", false); - RNA_boolean_set(kmi->ptr, "enumerate", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL | KM_ALT, 0); - RNA_boolean_set(kmi->ptr, "extend", false); - RNA_boolean_set(kmi->ptr, "deselect", false); - RNA_boolean_set(kmi->ptr, "toggle", true); - RNA_boolean_set(kmi->ptr, "center", true); - RNA_boolean_set(kmi->ptr, "object", false); - RNA_boolean_set(kmi->ptr, "enumerate", true); - - WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "deselect", false); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "deselect", true); - WM_keymap_add_item(keymap, "VIEW3D_OT_select_circle", CKEY, KM_PRESS, 0, 0); - - WM_keymap_add_item(keymap, "VIEW3D_OT_clip_border", BKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_zoom_border", BKEY, KM_PRESS, KM_SHIFT, 0); - - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_render_border", BKEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "camera_only", true); - kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_render_border", BKEY, KM_PRESS, KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "camera_only", false); - - WM_keymap_add_item(keymap, "VIEW3D_OT_clear_render_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); - - WM_keymap_add_item(keymap, "VIEW3D_OT_camera_to_view", PAD0, KM_PRESS, KM_ALT | KM_CTRL, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_object_as_camera", PAD0, KM_PRESS, KM_CTRL, 0); - - WM_keymap_add_menu(keymap, "VIEW3D_MT_snap", SKEY, KM_PRESS, KM_SHIFT, 0); - -#ifdef __APPLE__ - WM_keymap_add_item(keymap, "VIEW3D_OT_copybuffer", CKEY, KM_PRESS, KM_OSKEY, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_pastebuffer", VKEY, KM_PRESS, KM_OSKEY, 0); -#endif - WM_keymap_add_item(keymap, "VIEW3D_OT_copybuffer", CKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "VIEW3D_OT_pastebuffer", VKEY, KM_PRESS, KM_CTRL, 0); - - /* context ops */ - kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point"); - RNA_string_set(kmi->ptr, "value", "BOUNDING_BOX_CENTER"); - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, KM_CTRL, 0); /* 2.4x allowed Comma+Shift too, rather not use both */ - RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point"); - RNA_string_set(kmi->ptr, "value", "MEDIAN_POINT"); - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", COMMAKEY, KM_PRESS, KM_ALT, 0); /* new in 2.5 */ - RNA_string_set(kmi->ptr, "data_path", "space_data.use_pivot_point_align"); - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SPACEKEY, KM_PRESS, KM_CTRL, 0); /* new in 2.5 */ - RNA_string_set(kmi->ptr, "data_path", "space_data.show_manipulator"); - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point"); - RNA_string_set(kmi->ptr, "value", "CURSOR"); - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, KM_CTRL, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point"); - RNA_string_set(kmi->ptr, "value", "INDIVIDUAL_ORIGINS"); - - kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, KM_ALT, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point"); - RNA_string_set(kmi->ptr, "value", "ACTIVE_ELEMENT"); - - transform_keymap_for_space(keyconf, keymap, SPACE_VIEW3D); + WM_keymap_ensure(keyconf, "3D View", SPACE_VIEW3D, 0); fly_modal_keymap(keyconf); walk_modal_keymap(keyconf); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 20f3feb28ac..718f3cd40f1 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -36,14 +36,13 @@ #include "BLI_sys_types.h" /* int64_t */ -#include "BIF_gl.h" /* bglMats */ -#include "BIF_glutil.h" /* bglMats */ - #include "BLI_math_vector.h" #include "BKE_camera.h" #include "BKE_screen.h" +#include "GPU_matrix.h" + #include "ED_view3d.h" /* own include */ #define BL_NEAR_CLIP 0.001 @@ -315,6 +314,7 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f } static void view3d_win_to_ray_segment( + struct Depsgraph *depsgraph, const ARegion *ar, const View3D *v3d, const float mval[2], float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3]) { @@ -332,7 +332,7 @@ static void view3d_win_to_ray_segment( start_offset = -end_offset; } else { - ED_view3d_clip_range_get(v3d, rv3d, &start_offset, &end_offset, false); + ED_view3d_clip_range_get(depsgraph, v3d, rv3d, &start_offset, &end_offset, false); } if (r_ray_start) { @@ -371,12 +371,13 @@ bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float * \return success, false if the ray is totally clipped. */ bool ED_view3d_win_to_ray_clipped_ex( + struct Depsgraph *depsgraph, const ARegion *ar, const View3D *v3d, const float mval[2], float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip_planes) { float ray_end[3]; - view3d_win_to_ray_segment(ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end); + view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end); /* bounds clipping */ if (do_clip_planes) { @@ -400,10 +401,11 @@ bool ED_view3d_win_to_ray_clipped_ex( * \return success, false if the ray is totally clipped. */ bool ED_view3d_win_to_ray_clipped( + struct Depsgraph *depsgraph, const ARegion *ar, const View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_normal[3], const bool do_clip_planes) { - return ED_view3d_win_to_ray_clipped_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip_planes); + return ED_view3d_win_to_ray_clipped_ex(depsgraph, ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip_planes); } /** @@ -677,10 +679,11 @@ void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3 * \return success, false if the segment is totally clipped. */ bool ED_view3d_win_to_segment_clipped( + struct Depsgraph *depsgraph, const ARegion *ar, View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip_planes) { - view3d_win_to_ray_segment(ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end); + view3d_win_to_ray_segment(depsgraph, ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end); /* bounds clipping */ if (do_clip_planes) { @@ -710,16 +713,22 @@ void ED_view3d_ob_project_mat_get_from_obmat(const RegionView3D *rv3d, float obm } /** - * Uses window coordinates (x,y) and depth component z to find a point in - * modelspace */ -void ED_view3d_unproject(bglMats *mats, float out[3], const float x, const float y, const float z) + * Convert between region relative coordinates (x,y) and depth component z and + * a point in world space. */ +void ED_view3d_project(const struct ARegion *ar, const float world[3], float region[3]) { - double ux, uy, uz; + // viewport is set up to make coordinates relative to the region, not window + RegionView3D *rv3d = ar->regiondata; + int viewport[4] = {0, 0, ar->winx, ar->winy}; - gluUnProject(x, y, z, mats->modelview, mats->projection, - (GLint *)mats->viewport, &ux, &uy, &uz); + GPU_matrix_project(world, rv3d->viewmat, rv3d->winmat, viewport, region); +} + +bool ED_view3d_unproject(const struct ARegion *ar, float regionx, float regiony, float regionz, float world[3]) +{ + RegionView3D *rv3d = ar->regiondata; + int viewport[4] = {0, 0, ar->winx, ar->winy}; + float region[3] = {regionx, regiony, regionz}; - out[0] = ux; - out[1] = uy; - out[2] = uz; + return GPU_matrix_unproject(region, rv3d->viewmat, rv3d->winmat, viewport, world); } diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c deleted file mode 100644 index f51b47032aa..00000000000 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ /dev/null @@ -1,1085 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributor(s): Campbell Barton - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/view3d_ruler.c - * \ingroup spview3d - */ - -/* defines VIEW3D_OT_ruler modal operator */ - -#include "DNA_scene_types.h" -#include "DNA_object_types.h" -#include "DNA_gpencil_types.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" -#include "BLI_blenlib.h" - -#include "BLT_translation.h" - -#include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_main.h" -#include "BKE_unit.h" - -#include "BIF_gl.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_screen.h" -#include "ED_view3d.h" -#include "ED_transform_snap_object_context.h" -#include "ED_space_api.h" - -#include "BLF_api.h" -#include "BIF_glutil.h" - -#include "UI_resources.h" -#include "UI_interface.h" - -#include "view3d_intern.h" /* own include */ - -#define MVAL_MAX_PX_DIST 12.0f - - -/* -------------------------------------------------------------------- */ -/* Ruler Item (we can have many) */ -enum { - RULERITEM_USE_ANGLE = (1 << 0), /* use protractor */ - RULERITEM_USE_RAYCAST = (1 << 1) -}; - -enum { - RULERITEM_DIRECTION_IN = 0, - RULERITEM_DIRECTION_OUT -}; - -/* keep smaller then selection, since we may want click elsewhere without selecting a ruler */ -#define RULER_PICK_DIST 12.0f -#define RULER_PICK_DIST_SQ (RULER_PICK_DIST * RULER_PICK_DIST) - -typedef struct RulerItem { - struct RulerItem *next, *prev; - - /* worldspace coords, middle being optional */ - float co[3][3]; - - /* selected coord */ - char co_index; /* 0 -> 2*/ - - int flag; - int raycast_dir; /* RULER_DIRECTION_* */ -} RulerItem; - - -/* -------------------------------------------------------------------- */ -/* Ruler Info (one per session) */ - -enum { - RULER_STATE_NORMAL = 0, - RULER_STATE_DRAG -}; - -enum { - RULER_SNAP_OK = (1 << 0), -}; - -typedef struct RulerInfo { - ListBase items; - int item_active; - int flag; - int snap_flag; - int state; - float drag_start_co[3]; - - struct SnapObjectContext *snap_context; - - /* wm state */ - wmWindow *win; - ScrArea *sa; - void *draw_handle_pixel; - ARegion *ar; /* re-assigned every modal update */ -} RulerInfo; - -/* -------------------------------------------------------------------- */ -/* local functions */ -static RulerItem *ruler_item_add(RulerInfo *ruler_info) -{ - RulerItem *ruler_item = MEM_callocN(sizeof(RulerItem), "RulerItem"); - BLI_addtail(&ruler_info->items, ruler_item); - return ruler_item; -} - -static void ruler_item_remove(RulerInfo *ruler_info, RulerItem *ruler_item) -{ - BLI_remlink(&ruler_info->items, ruler_item); - - MEM_freeN(ruler_item); -} - -static RulerItem *ruler_item_active_get(RulerInfo *ruler_info) -{ - return BLI_findlink(&ruler_info->items, ruler_info->item_active); -} - -static void ruler_item_active_set(RulerInfo *ruler_info, RulerItem *ruler_item) -{ - ruler_info->item_active = BLI_findindex(&ruler_info->items, ruler_item); -} - -static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit, - char *numstr, size_t numstr_size, int prec) -{ - const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0; - - if (ruler_item->flag & RULERITEM_USE_ANGLE) { - const float ruler_angle = angle_v3v3v3(ruler_item->co[0], - ruler_item->co[1], - ruler_item->co[2]); - - if (unit->system == USER_UNIT_NONE) { - BLI_snprintf(numstr, numstr_size, "%.*f°", prec, RAD2DEGF(ruler_angle)); - } - else { - bUnit_AsString(numstr, numstr_size, - (double)ruler_angle, - prec, unit->system, B_UNIT_ROTATION, do_split, false); - } - } - else { - const float ruler_len = len_v3v3(ruler_item->co[0], - ruler_item->co[2]); - - if (unit->system == USER_UNIT_NONE) { - BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len); - } - else { - bUnit_AsString(numstr, numstr_size, - (double)(ruler_len * unit->scale_length), - prec, unit->system, B_UNIT_LENGTH, do_split, false); - } - } - -} - -static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2], - RulerItem **r_ruler_item, int *r_co_index) -{ - ARegion *ar = ruler_info->ar; - RulerItem *ruler_item; - - float dist_best = RULER_PICK_DIST_SQ; - RulerItem *ruler_item_best = NULL; - int co_index_best = -1; - - for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) { - float co_ss[3][2]; - float dist; - int j; - - /* should these be checked? - ok for now not to */ - for (j = 0; j < 3; j++) { - ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); - } - - if (ruler_item->flag & RULERITEM_USE_ANGLE) { - dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]), - dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2])); - if (dist < dist_best) { - dist_best = dist; - ruler_item_best = ruler_item; - - { - const float dist_points[3] = { - len_squared_v2v2(co_ss[0], mval), - len_squared_v2v2(co_ss[1], mval), - len_squared_v2v2(co_ss[2], mval), - }; - if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) { - co_index_best = min_axis_v3(dist_points); - } - else { - co_index_best = -1; - } - } - } - } - else { - dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]); - if (dist < dist_best) { - dist_best = dist; - ruler_item_best = ruler_item; - - { - const float dist_points[2] = { - len_squared_v2v2(co_ss[0], mval), - len_squared_v2v2(co_ss[2], mval), - }; - if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) { - co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2; - } - else { - co_index_best = -1; - } - } - } - } - } - - if (ruler_item_best) { - *r_ruler_item = ruler_item_best; - *r_co_index = co_index_best; - return true; - } - else { - *r_ruler_item = NULL; - *r_co_index = -1; - return false; - } -} - -/** - * Ensure the 'snap_context' is only cached while dragging, - * needed since the user may toggle modes between tool use. - */ -static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) -{ - if (state == ruler_info->state) { - return; - } - - /* always remove */ - if (ruler_info->snap_context) { - ED_transform_snap_object_context_destroy(ruler_info->snap_context); - ruler_info->snap_context = NULL; - } - - if (state == RULER_STATE_NORMAL) { - /* pass */ - } - else if (state == RULER_STATE_DRAG) { - ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), 0, - ruler_info->ar, CTX_wm_view3d(C)); - } - else { - BLI_assert(0); - } - - ruler_info->state = state; -} - -#define RULER_ID "RulerData3D" -static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - bGPDlayer *gpl; - bGPDframe *gpf; - bGPDstroke *gps; - bGPDpalette *palette; - bGPDpalettecolor *palcolor; - RulerItem *ruler_item; - const char *ruler_name = RULER_ID; - bool changed = false; - - if (scene->gpd == NULL) { - scene->gpd = BKE_gpencil_data_addnew(bmain, "GPencil"); - } - - gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); - if (gpl == NULL) { - gpl = BKE_gpencil_layer_addnew(scene->gpd, ruler_name, false); - gpl->thickness = 1; - gpl->flag |= GP_LAYER_HIDE; - } - - /* try to get active palette or create a new one */ - palette = BKE_gpencil_palette_getactive(scene->gpd); - if (palette == NULL) { - palette = BKE_gpencil_palette_addnew(scene->gpd, DATA_("GP_Palette"), true); - } - /* try to get color with the ruler name or create a new one */ - palcolor = BKE_gpencil_palettecolor_getbyname(palette, (char *)ruler_name); - if (palcolor == NULL) { - palcolor = BKE_gpencil_palettecolor_addnew(palette, (char *)ruler_name, true); - } - - gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true); - BKE_gpencil_free_strokes(gpf); - - for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) { - bGPDspoint *pt; - int j; - - /* allocate memory for a new stroke */ - gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); - if (ruler_item->flag & RULERITEM_USE_ANGLE) { - gps->totpoints = 3; - pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); - for (j = 0; j < 3; j++) { - copy_v3_v3(&pt->x, ruler_item->co[j]); - pt->pressure = 1.0f; - pt->strength = 1.0f; - pt++; - } - } - else { - gps->totpoints = 2; - pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); - for (j = 0; j < 3; j += 2) { - copy_v3_v3(&pt->x, ruler_item->co[j]); - pt->pressure = 1.0f; - pt->strength = 1.0f; - pt++; - } - } - gps->flag = GP_STROKE_3DSPACE; - gps->thickness = 3; - /* assign color to stroke */ - BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname)); - gps->palcolor = palcolor; - BLI_addtail(&gpf->strokes, gps); - changed = true; - } - - return changed; -} - -static bool view3d_ruler_from_gpencil(bContext *C, RulerInfo *ruler_info) -{ - Scene *scene = CTX_data_scene(C); - bool changed = false; - - if (scene->gpd) { - bGPDlayer *gpl; - const char *ruler_name = RULER_ID; - gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); - if (gpl) { - bGPDframe *gpf; - gpf = BKE_gpencil_layer_getframe(gpl, CFRA, false); - if (gpf) { - bGPDstroke *gps; - for (gps = gpf->strokes.first; gps; gps = gps->next) { - bGPDspoint *pt = gps->points; - int j; - if (gps->totpoints == 3) { - RulerItem *ruler_item = ruler_item_add(ruler_info); - for (j = 0; j < 3; j++) { - copy_v3_v3(ruler_item->co[j], &pt->x); - pt++; - } - ruler_item->flag |= RULERITEM_USE_ANGLE; - changed = true; - } - else if (gps->totpoints == 2) { - RulerItem *ruler_item = ruler_item_add(ruler_info); - for (j = 0; j < 3; j += 2) { - copy_v3_v3(ruler_item->co[j], &pt->x); - pt++; - } - changed = true; - } - } - } - } - } - - return changed; -} - -/* -------------------------------------------------------------------- */ -/* local callbacks */ - -static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *arg) -{ - Scene *scene = CTX_data_scene(C); - UnitSettings *unit = &scene->unit; - RulerItem *ruler_item; - RulerInfo *ruler_info = arg; - RegionView3D *rv3d = ar->regiondata; -// ARegion *ar = ruler_info->ar; - const float cap_size = 4.0f; - const float bg_margin = 4.0f * U.pixelsize; - const float bg_radius = 4.0f * U.pixelsize; - const float arc_size = 64.0f * U.pixelsize; -#define ARC_STEPS 24 - const int arc_steps = ARC_STEPS; - int i; - //unsigned int color_act = 0x666600; - unsigned int color_act = 0xffffff; - unsigned int color_base = 0x0; - unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80}; - unsigned char color_text[3]; - unsigned char color_wire[3]; - - /* anti-aliased lines for more consistent appearance */ - glEnable(GL_LINE_SMOOTH); - - BLF_enable(blf_mono_font, BLF_ROTATION); - BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi); - BLF_rotation(blf_mono_font, 0.0f); - - UI_GetThemeColor3ubv(TH_TEXT, color_text); - UI_GetThemeColor3ubv(TH_WIRE, color_wire); - - for (ruler_item = ruler_info->items.first, i = 0; ruler_item; ruler_item = ruler_item->next, i++) { - const bool is_act = (i == ruler_info->item_active); - float dir_ruler[2]; - float co_ss[3][2]; - int j; - - /* should these be checked? - ok for now not to */ - for (j = 0; j < 3; j++) { - ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); - } - - glEnable(GL_BLEND); - - cpack(is_act ? color_act : color_base); - - if (ruler_item->flag & RULERITEM_USE_ANGLE) { - glBegin(GL_LINE_STRIP); - for (j = 0; j < 3; j++) { - glVertex2fv(co_ss[j]); - } - glEnd(); - cpack(0xaaaaaa); - setlinestyle(3); - glBegin(GL_LINE_STRIP); - for (j = 0; j < 3; j++) { - glVertex2fv(co_ss[j]); - } - glEnd(); - setlinestyle(0); - - /* arc */ - { - float dir_tmp[3]; - float co_tmp[3]; - float arc_ss_coords[ARC_STEPS + 1][2]; - - float dir_a[3]; - float dir_b[3]; - float quat[4]; - float axis[3]; - float angle; - const float px_scale = (ED_view3d_pixel_size_no_ui_scale(rv3d, ruler_item->co[1]) * - min_fff(arc_size, - len_v2v2(co_ss[0], co_ss[1]) / 2.0f, - len_v2v2(co_ss[2], co_ss[1]) / 2.0f)); - - sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]); - sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]); - normalize_v3(dir_a); - normalize_v3(dir_b); - - cross_v3_v3v3(axis, dir_a, dir_b); - angle = angle_normalized_v3v3(dir_a, dir_b); - - axis_angle_to_quat(quat, axis, angle / arc_steps); - - copy_v3_v3(dir_tmp, dir_a); - - glColor3ubv(color_wire); - - for (j = 0; j <= arc_steps; j++) { - madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale); - ED_view3d_project_float_global(ar, co_tmp, arc_ss_coords[j], V3D_PROJ_TEST_NOP); - mul_qt_v3(quat, dir_tmp); - } - - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, arc_ss_coords); - glDrawArrays(GL_LINE_STRIP, 0, arc_steps + 1); - glDisableClientState(GL_VERTEX_ARRAY); - } - - /* text */ - { - char numstr[256]; - float numstr_size[2]; - float pos[2]; - const int prec = 2; /* XXX, todo, make optional */ - - ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); - - BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); - - pos[0] = co_ss[1][0] + (cap_size * 2.0f); - pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f); - - /* draw text (bg) */ - glColor4ubv(color_back); - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox( - pos[0] - bg_margin, pos[1] - bg_margin, - pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], - bg_radius); - /* draw text */ - glColor3ubv(color_text); - BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); - BLF_rotation(blf_mono_font, 0.0f); - BLF_draw(blf_mono_font, numstr, sizeof(numstr)); - } - - /* capping */ - { - float rot_90_vec_a[2]; - float rot_90_vec_b[2]; - float cap[2]; - - sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]); - rot_90_vec_a[0] = -dir_ruler[1]; - rot_90_vec_a[1] = dir_ruler[0]; - normalize_v2(rot_90_vec_a); - - sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]); - rot_90_vec_b[0] = -dir_ruler[1]; - rot_90_vec_b[1] = dir_ruler[0]; - normalize_v2(rot_90_vec_b); - - glEnable(GL_BLEND); - - glColor3ubv(color_wire); - - glBegin(GL_LINES); - - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size); - glVertex2fv(cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size); - glVertex2fv(cap); - - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size); - glVertex2fv(cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size); - glVertex2fv(cap); - - /* angle vertex */ - glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] - cap_size); - glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] + cap_size); - glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] + cap_size); - glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] - cap_size); - glEnd(); - - glDisable(GL_BLEND); - } - } - else { - glBegin(GL_LINE_STRIP); - for (j = 0; j < 3; j += 2) { - glVertex2fv(co_ss[j]); - } - glEnd(); - cpack(0xaaaaaa); - setlinestyle(3); - glBegin(GL_LINE_STRIP); - for (j = 0; j < 3; j += 2) { - glVertex2fv(co_ss[j]); - } - glEnd(); - setlinestyle(0); - - sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]); - - /* text */ - { - char numstr[256]; - float numstr_size[2]; - const int prec = 6; /* XXX, todo, make optional */ - float pos[2]; - - ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); - - BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); - - mid_v2_v2v2(pos, co_ss[0], co_ss[2]); - - /* center text */ - pos[0] -= numstr_size[0] / 2.0f; - pos[1] -= numstr_size[1] / 2.0f; - - /* draw text (bg) */ - glColor4ubv(color_back); - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox(pos[0] - bg_margin, pos[1] - bg_margin, - pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1], - bg_radius); - /* draw text */ - glColor3ubv(color_text); - BLF_position(blf_mono_font, pos[0], pos[1], 0.0f); - BLF_draw(blf_mono_font, numstr, sizeof(numstr)); - } - - /* capping */ - { - float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]}; - float cap[2]; - - normalize_v2(rot_90_vec); - - glEnable(GL_BLEND); - glColor3ubv(color_wire); - - glBegin(GL_LINES); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size); - glVertex2fv(cap); - madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size); - glVertex2fv(cap); - - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size); - glVertex2fv(cap); - madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size); - glVertex2fv(cap); - glEnd(); - - glDisable(GL_BLEND); - } - } - } - - glDisable(GL_LINE_SMOOTH); - - BLF_disable(blf_mono_font, BLF_ROTATION); - -#undef ARC_STEPS - - /* draw snap */ - if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG)) { - ruler_item = ruler_item_active_get(ruler_info); - if (ruler_item) { - /* size from drawSnapping */ - const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE); - float co_ss[3]; - ED_view3d_project_float_global(ar, ruler_item->co[ruler_item->co_index], co_ss, V3D_PROJ_TEST_NOP); - - cpack(color_act); - circ(co_ss[0], co_ss[1], size * U.pixelsize); - } - } - -} - -/* free, use for both cancel and finish */ -static void view3d_ruler_end(const struct bContext *UNUSED(C), RulerInfo *ruler_info) -{ - ED_region_draw_cb_exit(ruler_info->ar->type, ruler_info->draw_handle_pixel); -} - -static void view3d_ruler_free(RulerInfo *ruler_info) -{ - BLI_freelistN(&ruler_info->items); - - if (ruler_info->snap_context) { - ED_transform_snap_object_context_destroy(ruler_info->snap_context); - } - - MEM_freeN(ruler_info); -} - -static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], - const int xy[2]) -{ - ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->ar, r_co, xy, r_co); -} - -/* use for mousemove events */ -static bool view3d_ruler_item_mousemove( - RulerInfo *ruler_info, const int mval[2], - const bool do_thickness, const bool do_snap) -{ - const float eps_bias = 0.0002f; - float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */ - RulerItem *ruler_item = ruler_item_active_get(ruler_info); - - ruler_info->snap_flag &= ~RULER_SNAP_OK; - - if (ruler_item) { - float *co = ruler_item->co[ruler_item->co_index]; - /* restore the initial depth */ - copy_v3_v3(co, ruler_info->drag_start_co); - view3d_ruler_item_project(ruler_info, co, mval); - if (do_thickness && ruler_item->co_index != 1) { - // Scene *scene = CTX_data_scene(C); - // View3D *v3d = ruler_info->sa->spacedata.first; - const float mval_fl[2] = {UNPACK2(mval)}; - float ray_normal[3]; - float ray_start[3]; - float *co_other; - - co_other = ruler_item->co[ruler_item->co_index == 0 ? 2 : 0]; - - if (ED_transform_snap_object_project_view3d_mixed( - ruler_info->snap_context, - SCE_SELECT_FACE, - &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, - .use_object_edit_cage = true, - }, - mval_fl, &dist_px, true, - co, ray_normal)) - { - negate_v3(ray_normal); - /* add some bias */ - madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias); - ED_transform_snap_object_project_ray( - ruler_info->snap_context, - &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, - .use_object_edit_cage = true, - }, - ray_start, ray_normal, NULL, - co_other, NULL); - } - } - else if (do_snap) { - // Scene *scene = CTX_data_scene(C); - View3D *v3d = ruler_info->sa->spacedata.first; - const float mval_fl[2] = {UNPACK2(mval)}; - bool use_depth = (v3d->drawtype >= OB_SOLID); - - if (ED_transform_snap_object_project_view3d_mixed( - ruler_info->snap_context, - (SCE_SELECT_VERTEX | SCE_SELECT_EDGE) | (use_depth ? SCE_SELECT_FACE : 0), - &(const struct SnapObjectParams){ - .snap_select = SNAP_ALL, - .use_object_edit_cage = true, - }, - mval_fl, &dist_px, use_depth, - co, NULL)) - { - ruler_info->snap_flag |= RULER_SNAP_OK; - } - } - return true; - } - else { - return false; - } -} - -static void view3d_ruler_header_update(ScrArea *sa) -{ - const char *text = IFACE_("Ctrl+LMB: Add, " - "Del: Remove, " - "Ctrl+Drag: Snap, " - "Shift+Drag: Thickness, " - "Ctrl+C: Copy Value, " - "Enter: Store, " - "Esc: Cancel"); - - ED_area_headerprint(sa, text); -} - -/* -------------------------------------------------------------------- */ -/* Operator callbacks */ - -static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - wmWindow *win = CTX_wm_window(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - RulerInfo *ruler_info; - - ruler_info = MEM_callocN(sizeof(RulerInfo), "RulerInfo"); - - if (view3d_ruler_from_gpencil(C, ruler_info)) { - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); - } - - op->customdata = ruler_info; - - ruler_info->win = win; - ruler_info->sa = sa; - ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel, - ruler_info, REGION_DRAW_POST_PIXEL); - - view3d_ruler_header_update(sa); - - op->flag |= OP_IS_MODAL_CURSOR_REGION; - - WM_cursor_modal_set(win, BC_CROSSCURSOR); - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; -} - -static void view3d_ruler_cancel(bContext *C, wmOperator *op) -{ - RulerInfo *ruler_info = op->customdata; - - view3d_ruler_end(C, ruler_info); - view3d_ruler_free(ruler_info); - op->customdata = NULL; -} - -static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - bool do_draw = false; - int exit_code = OPERATOR_RUNNING_MODAL; - RulerInfo *ruler_info = op->customdata; - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - - /* its possible to change spaces while running the operator [#34894] */ - if (UNLIKELY(sa != ruler_info->sa)) { - exit_code = OPERATOR_FINISHED; - goto exit; - } - - ruler_info->ar = ar; - - switch (event->type) { - case LEFTMOUSE: - if (event->val == KM_RELEASE) { - if (ruler_info->state == RULER_STATE_DRAG) { - /* rubber-band angle removal */ - RulerItem *ruler_item = ruler_item_active_get(ruler_info); - if (ruler_item && (ruler_item->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) { - if (!BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) { - ruler_item->flag &= ~RULERITEM_USE_ANGLE; - do_draw = true; - } - } - if (ruler_info->snap_flag & RULER_SNAP_OK) { - ruler_info->snap_flag &= ~RULER_SNAP_OK; - do_draw = true; - } - ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); - } - } - else { - if (ruler_info->state == RULER_STATE_NORMAL) { - - if (event->ctrl || - /* weak - but user friendly */ - BLI_listbase_is_empty(&ruler_info->items)) - { - View3D *v3d = CTX_wm_view3d(C); - const bool use_depth = (v3d->drawtype >= OB_SOLID); - - /* Create new line */ - RulerItem *ruler_item_prev = ruler_item_active_get(ruler_info); - RulerItem *ruler_item; - /* check if we want to drag an existing point or add a new one */ - ruler_state_set(C, ruler_info, RULER_STATE_DRAG); - - ruler_item = ruler_item_add(ruler_info); - ruler_item_active_set(ruler_info, ruler_item); - - if (use_depth) { - /* snap the first point added, not essential but handy */ - ruler_item->co_index = 0; - view3d_ruler_item_mousemove(ruler_info, event->mval, false, true); - copy_v3_v3(ruler_info->drag_start_co, ruler_item->co[ruler_item->co_index]); - } - else { - /* initial depth either previous ruler, view offset */ - if (ruler_item_prev) { - copy_v3_v3(ruler_info->drag_start_co, ruler_item_prev->co[ruler_item_prev->co_index]); - } - else { - negate_v3_v3(ruler_info->drag_start_co, rv3d->ofs); - } - - copy_v3_v3(ruler_item->co[0], ruler_info->drag_start_co); - view3d_ruler_item_project(ruler_info, ruler_item->co[0], event->mval); - } - - copy_v3_v3(ruler_item->co[2], ruler_item->co[0]); - ruler_item->co_index = 2; - - do_draw = true; - } - else { - float mval_fl[2] = {UNPACK2(event->mval)}; - RulerItem *ruler_item_pick; - int co_index; - - /* select and drag */ - if (view3d_ruler_pick(ruler_info, mval_fl, &ruler_item_pick, &co_index)) { - if (co_index == -1) { - if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) { - /* Add Center Point */ - ruler_item_active_set(ruler_info, ruler_item_pick); - ruler_item_pick->flag |= RULERITEM_USE_ANGLE; - ruler_item_pick->co_index = 1; - ruler_state_set(C, ruler_info, RULER_STATE_DRAG); - - /* find the factor */ - { - float co_ss[2][2]; - float fac; - - ED_view3d_project_float_global(ar, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP); - ED_view3d_project_float_global(ar, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP); - - fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]); - CLAMP(fac, 0.0f, 1.0f); - - interp_v3_v3v3(ruler_item_pick->co[1], - ruler_item_pick->co[0], - ruler_item_pick->co[2], fac); - } - - /* update the new location */ - view3d_ruler_item_mousemove(ruler_info, event->mval, - event->shift != 0, event->ctrl != 0); - do_draw = true; - } - } - else { - ruler_item_active_set(ruler_info, ruler_item_pick); - ruler_item_pick->co_index = co_index; - ruler_state_set(C, ruler_info, RULER_STATE_DRAG); - - /* store the initial depth */ - copy_v3_v3(ruler_info->drag_start_co, ruler_item_pick->co[ruler_item_pick->co_index]); - - do_draw = true; - } - } - else { - exit_code = OPERATOR_PASS_THROUGH; - } - - } - } - } - break; - case CKEY: - { - if (event->ctrl) { - RulerItem *ruler_item = ruler_item_active_get(ruler_info); - if (ruler_item) { - const int prec = 8; - char numstr[256]; - Scene *scene = CTX_data_scene(C); - UnitSettings *unit = &scene->unit; - - ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); - WM_clipboard_text_set((void *) numstr, false); - } - } - break; - } - case RIGHTCTRLKEY: - case LEFTCTRLKEY: - { - WM_event_add_mousemove(C); - break; - } - case MOUSEMOVE: - { - if (ruler_info->state == RULER_STATE_DRAG) { - if (view3d_ruler_item_mousemove(ruler_info, event->mval, - event->shift != 0, event->ctrl != 0)) - { - do_draw = true; - } - } - break; - } - case ESCKEY: - { - do_draw = true; - exit_code = OPERATOR_CANCELLED; - break; - } - case RETKEY: - { - /* Enter may be used to invoke from search. */ - if (event->val == KM_PRESS) { - view3d_ruler_to_gpencil(C, ruler_info); - do_draw = true; - exit_code = OPERATOR_FINISHED; - } - break; - } - case DELKEY: - { - if (event->val == KM_PRESS) { - if (ruler_info->state == RULER_STATE_NORMAL) { - RulerItem *ruler_item = ruler_item_active_get(ruler_info); - if (ruler_item) { - RulerItem *ruler_item_other = ruler_item->prev ? ruler_item->prev : ruler_item->next; - ruler_item_remove(ruler_info, ruler_item); - ruler_item_active_set(ruler_info, ruler_item_other); - do_draw = true; - } - } - } - break; - } - default: - exit_code = OPERATOR_PASS_THROUGH; - break; - - } - - if (ruler_info->state == RULER_STATE_DRAG) { - op->flag &= ~OP_IS_MODAL_CURSOR_REGION; - } - else { - op->flag |= OP_IS_MODAL_CURSOR_REGION; - } - - if (do_draw) { - view3d_ruler_header_update(sa); - - /* all 3d views draw rulers */ - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); - } - -exit: - if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) { - WM_cursor_modal_restore(ruler_info->win); - - view3d_ruler_end(C, ruler_info); - view3d_ruler_free(ruler_info); - op->customdata = NULL; - - ED_area_headerprint(sa, NULL); - } - - return exit_code; -} - -void VIEW3D_OT_ruler(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Ruler/Protractor"; - ot->description = "Interactive ruler"; - ot->idname = "VIEW3D_OT_ruler"; - - /* api callbacks */ - ot->invoke = view3d_ruler_invoke; - ot->cancel = view3d_ruler_cancel; - ot->modal = view3d_ruler_modal; - ot->poll = ED_operator_view3d_active; - - /* flags */ - ot->flag = 0; -} diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index d8c21da48a4..b2fbdbad31c 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -44,9 +44,11 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_tracking_types.h" +#include "DNA_gpencil_types.h" #include "MEM_guardedalloc.h" +#include "BLI_array.h" #include "BLI_math.h" #include "BLI_lasso_2d.h" #include "BLI_rect.h" @@ -55,6 +57,10 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#ifdef __BIG_ENDIAN__ +# include "BLI_endian_switch.h" +#endif + /* vertex box select */ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -63,16 +69,17 @@ #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_curve.h" -#include "BKE_depsgraph.h" +#include "BKE_layer.h" #include "BKE_mball.h" #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_editmesh.h" +#include "BKE_scene.h" #include "BKE_tracking.h" +#include "BKE_workspace.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "DEG_depsgraph.h" #include "WM_api.h" #include "WM_types.h" @@ -88,12 +95,16 @@ #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_sculpt.h" #include "ED_mball.h" +#include "ED_gpencil.h" #include "UI_interface.h" #include "GPU_draw.h" +#include "GPU_glew.h" +#include "GPU_matrix.h" #include "view3d_intern.h" /* own include */ @@ -108,9 +119,12 @@ float ED_view3d_select_dist_px(void) void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc) { memset(vc, 0, sizeof(ViewContext)); + vc->C = C; vc->ar = CTX_wm_region(C); vc->bmain = CTX_data_main(C); + vc->depsgraph = CTX_data_depsgraph(C); vc->scene = CTX_data_scene(C); + vc->view_layer = CTX_data_view_layer(C); vc->v3d = CTX_wm_view3d(C); vc->win = CTX_wm_window(C); vc->rv3d = CTX_wm_region_view3d(C); @@ -118,39 +132,26 @@ void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc) vc->obedit = CTX_data_edit_object(C); } -/* - * ob == NULL if you want global matrices - * */ -void view3d_get_transformation(const ARegion *ar, RegionView3D *rv3d, Object *ob, bglMats *mats) +void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact) { - float cpy[4][4]; - int i, j; - - if (ob) { - mul_m4_m4m4(cpy, rv3d->viewmat, ob->obmat); - } - else { - copy_m4_m4(cpy, rv3d->viewmat); - } + vc->obact = obact; + if (vc->obedit) { + BLI_assert(BKE_object_is_in_editmode(obact)); + vc->obedit = obact; + /* previous selections are now invalid. */ + vc->v3d->flag |= V3D_INVALID_BACKBUF; - for (i = 0; i < 4; ++i) { - for (j = 0; j < 4; ++j) { - mats->projection[i * 4 + j] = rv3d->winmat[i][j]; - mats->modelview[i * 4 + j] = cpy[i][j]; + if (vc->em) { + vc->em = BKE_editmesh_from_object(vc->obedit); } } - - mats->viewport[0] = ar->winrct.xmin; - mats->viewport[1] = ar->winrct.ymin; - mats->viewport[2] = ar->winx; - mats->viewport[3] = ar->winy; } /* ********************** view3d_select: selection manipulations ********************* */ /* local prototypes */ -static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const bool select) +static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp sel_op) { BMVert *eve; BMIter iter; @@ -158,15 +159,18 @@ static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const bool selec BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - if (EDBM_backbuf_check(index)) { - BM_vert_select_set(em->bm, eve, select); + const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_vert_select_set(em->bm, eve, sel_op_result); } } index++; } } -static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const bool select) +static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const eSelectOp sel_op) { BMEdge *eed; BMIter iter; @@ -174,15 +178,18 @@ static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const bool selec BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - if (EDBM_backbuf_check(index)) { - BM_edge_select_set(em->bm, eed, select); + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(em->bm, eed, sel_op_result); } } index++; } } -static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const bool select) +static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const eSelectOp sel_op) { BMFace *efa; BMIter iter; @@ -190,26 +197,31 @@ static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const bool selec BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - if (EDBM_backbuf_check(index)) { - BM_face_select_set(em->bm, efa, select); + const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_face_select_set(em->bm, efa, sel_op_result); } } index++; } } - /* object mode, edbm_ prefix is confusing here, rename? */ -static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const bool select) +static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const eSelectOp sel_op) { MVert *mv = me->mvert; unsigned int index; if (mv) { for (index = 1; index <= me->totvert; index++, mv++) { - if (EDBM_backbuf_check(index)) { - if (!(mv->flag & ME_HIDE)) { - mv->flag = select ? (mv->flag | SELECT) : (mv->flag & ~SELECT); + if (!(mv->flag & ME_HIDE)) { + const bool is_select = mv->flag & SELECT; + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); } } } @@ -217,15 +229,20 @@ static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const bool sele } /* object mode, edbm_ prefix is confusing here, rename? */ -static void edbm_backbuf_check_and_select_tfaces(Mesh *me, const bool select) +static void edbm_backbuf_check_and_select_tfaces(Mesh *me, const eSelectOp sel_op) { MPoly *mpoly = me->mpoly; unsigned int index; if (mpoly) { for (index = 1; index <= me->totpoly; index++, mpoly++) { - if (EDBM_backbuf_check(index)) { - mpoly->flag = select ? (mpoly->flag | ME_FACE_SEL) : (mpoly->flag & ~ME_FACE_SEL); + if (!(mpoly->flag & ME_HIDE)) { + const bool is_select = mpoly->flag & ME_FACE_SEL; + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL); + } } } } @@ -240,7 +257,7 @@ typedef struct LassoSelectUserData { rctf _rect_fl; const int (*mcords)[2]; int moves; - bool select; + eSelectOp sel_op; /* runtime */ int pass; @@ -251,7 +268,7 @@ typedef struct LassoSelectUserData { static void view3d_userdata_lassoselect_init( LassoSelectUserData *r_data, ViewContext *vc, const rcti *rect, const int (*mcords)[2], - const int moves, const bool select) + const int moves, const eSelectOp sel_op) { r_data->vc = vc; @@ -261,7 +278,7 @@ static void view3d_userdata_lassoselect_init( r_data->mcords = mcords; r_data->moves = moves; - r_data->select = select; + r_data->sel_op = sel_op; /* runtime */ r_data->pass = 0; @@ -295,7 +312,7 @@ static bool view3d_selectable_data(bContext *C) } -/* helper also for borderselect */ +/* helper also for box_select */ static bool edge_fully_inside_rect(const rctf *rect, const float v1[2], const float v2[2]) { return BLI_rctf_isect_pt_v(rect, v1) && BLI_rctf_isect_pt_v(rect, v2); @@ -326,7 +343,7 @@ static bool edge_inside_rect(const rctf *rect, const float v1[2], const float v2 return 1; } -static void do_lasso_select_pose__doSelectBone( +static void do_lasso_select_pose__do_tag( void *userData, struct bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]) { LassoSelectUserData *data = userData; @@ -336,26 +353,21 @@ static void do_lasso_select_pose__doSelectBone( bool is_point_done = false; int points_proj_tot = 0; - const int x0 = screen_co_a[0]; - const int y0 = screen_co_a[1]; - const int x1 = screen_co_b[0]; - const int y1 = screen_co_b[1]; - /* project head location to screenspace */ - if (x0 != IS_CLIPPED) { + if (screen_co_a[0] != IS_CLIPPED) { points_proj_tot++; - if (BLI_rcti_isect_pt(data->rect, x0, y0) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX)) + if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) { is_point_done = true; } } /* project tail location to screenspace */ - if (x1 != IS_CLIPPED) { + if (screen_co_b[0] != IS_CLIPPED) { points_proj_tot++; - if (BLI_rcti_isect_pt(data->rect, x1, y1) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX)) + if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) { is_point_done = true; } @@ -364,16 +376,14 @@ static void do_lasso_select_pose__doSelectBone( /* if one of points selected, we skip the bone itself */ if ((is_point_done == true) || ((is_point_done == false) && (points_proj_tot == 2) && - BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX))) + BLI_lasso_is_edge_inside(data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX))) { - if (data->select) pchan->bone->flag |= BONE_SELECTED; - else pchan->bone->flag &= ~BONE_SELECTED; - data->is_changed = true; + pchan->bone->flag |= BONE_DONE; } data->is_changed |= is_point_done; } } -static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves, const bool select) +static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves) { ViewContext vc_tmp; LassoSelectUserData data; @@ -388,106 +398,218 @@ static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[] BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, 0); - ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); + ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d); - pose_foreachScreenBone(&vc_tmp, do_lasso_select_pose__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT); - - if (data.is_changed) { - bArmature *arm = ob->data; - if (arm->flag & ARM_HAS_VIZ_DEPS) { - /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - } + pose_foreachScreenBone(&vc_tmp, do_lasso_select_pose__do_tag, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } -static void object_deselect_all_visible(Scene *scene, View3D *v3d) +static void object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d) { Base *base; - for (base = scene->base.first; base; base = base->next) { + for (base = view_layer->object_bases.first; base; base = base->next) { if (BASE_SELECTABLE(v3d, base)) { - ED_base_object_select(base, BA_DESELECT); + ED_object_base_select(base, BA_DESELECT); } } } static void do_lasso_select_objects( ViewContext *vc, const int mcords[][2], const short moves, - const bool extend, const bool select) + const eSelectOp sel_op) { + View3D *v3d = vc->v3d; Base *base; - if (extend == false && select) - object_deselect_all_visible(vc->scene, vc->v3d); - - for (base = vc->scene->base.first; base; base = base->next) { - if (BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */ - if (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) { - if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) { + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + object_deselect_all_visible(vc->view_layer, vc->v3d); + } - ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT); - base->object->flag = base->flag; - } - } - if (vc->obact == base->object && (base->object->mode & OB_MODE_POSE)) { - do_lasso_select_pose(vc, base->object, mcords, moves, select); + bool changed = false; + for (base = vc->view_layer->object_bases.first; base; base = base->next) { + if (BASE_SELECTABLE(v3d, base)) { /* use this to avoid un-needed lasso lookups */ + const bool is_select = base->flag & BASE_SELECTED; + const bool is_inside = ( + (ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) && + BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); + changed = true; } } } + + if (changed) { + DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene); + } } -static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index)) -{ - LassoSelectUserData *data = userData; - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) - { - BM_vert_select_set(data->vc->em->bm, eve, data->select); +/** + * Use for lasso & box select. + */ +static Base **do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len) +{ + Base **bases = NULL; + BLI_array_declare(bases); + FOREACH_BASE_IN_MODE_BEGIN (vc->view_layer, vc->v3d, OB_ARMATURE, OB_MODE_POSE, base_iter) { + Object *ob_iter = base_iter->object; + bArmature *arm = ob_iter->data; + for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { + Bone *bone = pchan->bone; + bone->flag &= ~BONE_DONE; + } + arm->id.tag |= LIB_TAG_DOIT; + ob_iter->id.tag &= ~LIB_TAG_DOIT; + BLI_array_append(bases, base_iter); } + FOREACH_BASE_IN_MODE_END; + *r_bases_len = BLI_array_len(bases); + return bases; } -static void do_lasso_select_mesh__doSelectEdge( - void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) -{ - LassoSelectUserData *data = userData; - if (EDBM_backbuf_check(bm_solidoffs + index)) { - const int x0 = screen_co_a[0]; - const int y0 = screen_co_a[1]; - const int x1 = screen_co_b[0]; - const int y1 = screen_co_b[1]; +static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const eSelectOp sel_op) +{ + bool changed_multi = false; - if (data->pass == 0) { - if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, IS_CLIPPED) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, IS_CLIPPED)) - { - BM_edge_select_set(data->vc->em->bm, eed, data->select); - data->is_done = true; + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + for (int i = 0; i < bases_len; i++) { + Base *base_iter = bases[i]; + Object *ob_iter = base_iter->object; + if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, false)) { + ED_pose_bone_select_tag_update(ob_iter); + changed_multi = true; } } + } + + for (int i = 0; i < bases_len; i++) { + Base *base_iter = bases[i]; + Object *ob_iter = base_iter->object; + bArmature *arm = ob_iter->data; + + /* Don't handle twice. */ + if (arm->id.tag & LIB_TAG_DOIT) { + arm->id.tag &= ~LIB_TAG_DOIT; + } else { - if (BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, IS_CLIPPED)) { - BM_edge_select_set(data->vc->em->bm, eed, data->select); + continue; + } + + bool changed = true; + for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { + Bone *bone = pchan->bone; + if ((bone->flag & BONE_UNSELECTABLE) == 0) { + const bool is_select = bone->flag & BONE_SELECTED; + const bool is_inside = bone->flag & BONE_DONE; + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bone->flag, sel_op_result, BONE_SELECTED); + if (sel_op_result == 0) { + if (arm->act_bone == bone) { + arm->act_bone = NULL; + } + } + changed = true; + } } } + if (changed) { + ED_pose_bone_select_tag_update(ob_iter); + changed_multi = true; + } } + return changed_multi; } -static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index)) + +static void do_lasso_select_pose( + ViewContext *vc, const int mcords[][2], const short moves, + const eSelectOp sel_op) +{ + uint bases_len; + Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len); + + for (int i = 0; i < bases_len; i++) { + Base *base_iter = bases[i]; + Object *ob_iter = base_iter->object; + do_lasso_tag_pose(vc, ob_iter, mcords, moves); + } + + const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op); + if (changed_multi) { + DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, vc->scene); + } + + if (bases != NULL) { + MEM_freeN(bases); + } +} + +static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index)) +{ + LassoSelectUserData *data = userData; + const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_vert_select_set(data->vc->em->bm, eve, sel_op_result); + } +} +static void do_lasso_select_mesh__doSelectEdge_pass0( + void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) +{ + LassoSelectUserData *data = userData; + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = ( + EDBM_backbuf_check(bm_solidoffs + index) && + edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); + data->is_done = true; + } +} +static void do_lasso_select_mesh__doSelectEdge_pass1( + void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { LassoSelectUserData *data = userData; + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = ( + EDBM_backbuf_check(bm_solidoffs + index) && + BLI_lasso_is_edge_inside( + data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); + } +} - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) - { - BM_face_select_set(data->vc->em->bm, efa, data->select); +static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index)) +{ + LassoSelectUserData *data = userData; + const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_face_select_set(data->vc->em->bm, efa, sel_op_result); } } -static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_mesh( + ViewContext *vc, + const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; @@ -499,20 +621,21 @@ static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short m BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT); + } /* for non zbuf projections, don't change the GL state */ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - glLoadMatrixf(vc->rv3d->viewmat); + GPU_matrix_set(vc->rv3d->viewmat); bbsel = EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); if (ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { - edbm_backbuf_check_and_select_verts(vc->em, select); + edbm_backbuf_check_and_select_verts(vc->em, sel_op); } else { mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -520,18 +643,15 @@ static void do_lasso_select_mesh(ViewContext *vc, const int mcords[][2], short m } if (ts->selectmode & SCE_SELECT_EDGE) { /* Does both bbsel and non-bbsel versions (need screen cos for both) */ - data.pass = 0; - mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); - + mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR); if (data.is_done == false) { - data.pass = 1; - mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); + mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR); } } if (ts->selectmode & SCE_SELECT_FACE) { if (bbsel) { - edbm_backbuf_check_and_select_faces(vc->em, select); + edbm_backbuf_check_and_select_faces(vc->em, sel_op); } else { mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -546,43 +666,46 @@ static void do_lasso_select_curve__doSelect( void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) { LassoSelectUserData *data = userData; - Object *obedit = data->vc->obedit; - Curve *cu = (Curve *)obedit->data; - if (BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) { - if (bp) { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + const bool is_inside = BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED); + if (bp) { + const bool is_select = bp->f1 & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); } - else { - if (cu->drawflag & CU_HIDE_HANDLES) { - /* can only be (beztindex == 0) here since handles are hidden */ - bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); + } + else { + if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { + /* can only be (beztindex == 0) here since handles are hidden */ + const bool is_select = bezt->f2 & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT); } - else { - if (beztindex == 0) { - bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT); - } - else if (beztindex == 1) { - bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); - } - else { - bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT); - } + bezt->f1 = bezt->f3 = bezt->f2; + } + else { + char *flag_p = (&bezt->f1) + beztindex; + const bool is_select = *flag_p & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT); } } } } -static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); - if (extend == false && select) { + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { Curve *curve = (Curve *) vc->obedit->data; ED_curve_deselect_all(curve->editnurb); } @@ -595,74 +718,83 @@ static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2]) { LassoSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) - { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + const bool is_select = bp->f1 & SELECT; + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); } } -static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { ED_lattice_flags_set(vc->obedit, 0); + } ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } -static void do_lasso_select_armature__doSelectBone( - void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2]) +static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2]) { LassoSelectUserData *data = userData; bArmature *arm = data->vc->obedit->data; - - if (data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone)) { + if (EBONE_VISIBLE(arm, ebone)) { bool is_point_done = false; int points_proj_tot = 0; - const int x0 = screen_co_a[0]; - const int y0 = screen_co_a[1]; - const int x1 = screen_co_b[0]; - const int y1 = screen_co_b[1]; - /* project head location to screenspace */ - if (x0 != IS_CLIPPED) { + if (screen_co_a[0] != IS_CLIPPED) { points_proj_tot++; - if (BLI_rcti_isect_pt(data->rect, x0, y0) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX)) - { - is_point_done = true; - if (data->select) ebone->flag |= BONE_ROOTSEL; - else ebone->flag &= ~BONE_ROOTSEL; + const bool is_select = ebone->flag & BONE_ROOTSEL; + const bool is_inside = ( + BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { + SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL); + } } + is_point_done |= is_inside; } /* project tail location to screenspace */ - if (x1 != IS_CLIPPED) { + if (screen_co_b[0] != IS_CLIPPED) { points_proj_tot++; - if (BLI_rcti_isect_pt(data->rect, x1, y1) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX)) - { - is_point_done = true; - if (data->select) ebone->flag |= BONE_TIPSEL; - else ebone->flag &= ~BONE_TIPSEL; + const bool is_select = ebone->flag & BONE_TIPSEL; + const bool is_inside = ( + BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { + SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL); + } } + is_point_done |= is_inside; } /* if one of points selected, we skip the bone itself */ - if ((is_point_done == false) && (points_proj_tot == 2) && - BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX)) - { - if (data->select) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + if ((is_point_done == false) && (points_proj_tot == 2)) { + const bool is_select = ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + const bool is_inside = BLI_lasso_is_edge_inside( + data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { + SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)); + } + } data->is_changed = true; } @@ -670,19 +802,20 @@ static void do_lasso_select_armature__doSelectBone( } } -static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { ED_armature_edit_deselect_all_visible(vc->obedit); + } armature_foreachScreenBone(vc, do_lasso_select_armature__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -697,48 +830,52 @@ static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], sho static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem *ml, const float screen_co[2]) { LassoSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)) - { - if (data->select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; + const bool is_select = ml->flag & SELECT; + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT); data->is_changed = true; } } -static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; MetaBall *mb = (MetaBall *)vc->obedit->data; - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { BKE_mball_deselect_all(mb); + } BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } -static void do_lasso_select_meshobject__doSelectVert( - void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) +static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) { LassoSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) - { - SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT); + const bool is_select = mv->flag & SELECT; + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); + data->is_changed = true; } } -static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { - const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0; + const bool use_zbuf = V3D_IS_ZBUF(vc->v3d); Object *ob = vc->obact; Mesh *me = ob->data; rcti rect; @@ -746,8 +883,9 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh if (me == NULL || me->totvert == 0) return; - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { paintvert_deselect_all_visible(ob, SEL_DESELECT, false); /* flush selection at the end */ + } BLI_lasso_boundbox(&rect, mcords, moves); @@ -756,14 +894,14 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - edbm_backbuf_check_and_select_verts_obmode(me, select); + edbm_backbuf_check_and_select_verts_obmode(me, sel_op); EDBM_backbuf_free(); } else { LassoSelectUserData data; - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); @@ -771,12 +909,13 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh } - if (select == false) { + if (SEL_OP_CAN_DESELECT(sel_op)) { BKE_mesh_mselect_validate(me); } paintvert_flush_flags(ob); + paintvert_tag_select_update(vc->C, ob); } -static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { Object *ob = vc->obact; Mesh *me = ob->data; @@ -785,23 +924,24 @@ static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], sh if (me == NULL || me->totpoly == 0) return; - if (extend == false && select) - paintface_deselect_all_visible(ob, SEL_DESELECT, false); /* flush selection at the end */ + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false); /* flush selection at the end */ + } bm_vertoffs = me->totpoly + 1; /* max index array */ BLI_lasso_boundbox(&rect, mcords, moves); EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - edbm_backbuf_check_and_select_tfaces(me, select); + edbm_backbuf_check_and_select_tfaces(me, sel_op); EDBM_backbuf_free(); - paintface_flush_flags(ob, SELECT); + paintface_flush_flags(vc->C, ob, SELECT); } #if 0 -static void do_lasso_select_node(int mcords[][2], short moves, const bool select) +static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp sel_op) { SpaceNode *snode = sa->spacedata.first; @@ -818,13 +958,13 @@ static void do_lasso_select_node(int mcords[][2], short moves, const bool select node_centf[1] = BLI_RCT_CENTER_Y(&node->totr); ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent); - if (BLI_rcti_isect_pt_v(&rect, node_cent) && BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])) { - if (select) { - node->flag |= SELECT; - } - else { - node->flag &= ~SELECT; - } + const bool is_select = node->flag & SELECT; + const bool is_inside = ( + BLI_rcti_isect_pt_v(&rect, node_cent) && + BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT); } } BIF_undo_push("Lasso select nodes"); @@ -834,49 +974,61 @@ static void do_lasso_select_node(int mcords[][2], short moves, const bool select static void view3d_lasso_select( bContext *C, ViewContext *vc, const int mcords[][2], short moves, - bool extend, bool select) + const eSelectOp sel_op) { Object *ob = CTX_data_active_object(C); if (vc->obedit == NULL) { /* Object Mode */ - if (BKE_paint_select_face_test(ob)) - do_lasso_select_paintface(vc, mcords, moves, extend, select); - else if (BKE_paint_select_vert_test(ob)) - do_lasso_select_paintvert(vc, mcords, moves, extend, select); + if (BKE_paint_select_face_test(ob)) { + do_lasso_select_paintface(vc, mcords, moves, sel_op); + } + else if (BKE_paint_select_vert_test(ob)) { + do_lasso_select_paintvert(vc, mcords, moves, sel_op); + } else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { /* pass */ } - else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) - PE_lasso_select(C, mcords, moves, extend, select); + else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { + PE_lasso_select(C, mcords, moves, sel_op); + } + else if (ob && (ob->mode & OB_MODE_POSE)) { + do_lasso_select_pose(vc, mcords, moves, sel_op); + } else { - do_lasso_select_objects(vc, mcords, moves, extend, select); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); + do_lasso_select_objects(vc, mcords, moves, sel_op); } } else { /* Edit Mode */ - switch (vc->obedit->type) { - case OB_MESH: - do_lasso_select_mesh(vc, mcords, moves, extend, select); - break; - case OB_CURVE: - case OB_SURF: - do_lasso_select_curve(vc, mcords, moves, extend, select); - break; - case OB_LATTICE: - do_lasso_select_lattice(vc, mcords, moves, extend, select); - break; - case OB_ARMATURE: - do_lasso_select_armature(vc, mcords, moves, extend, select); - break; - case OB_MBALL: - do_lasso_select_meta(vc, mcords, moves, extend, select); - break; - default: - assert(!"lasso select on incorrect object type"); - break; - } - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data); + FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, vc->v3d, ob->type, ob->mode, ob_iter) { + ED_view3d_viewcontext_init_object(vc, ob_iter); + + switch (vc->obedit->type) { + case OB_MESH: + do_lasso_select_mesh(vc, mcords, moves, sel_op); + break; + case OB_CURVE: + case OB_SURF: + do_lasso_select_curve(vc, mcords, moves, sel_op); + break; + case OB_LATTICE: + do_lasso_select_lattice(vc, mcords, moves, sel_op); + break; + case OB_ARMATURE: + do_lasso_select_armature(vc, mcords, moves, sel_op); + break; + case OB_MBALL: + do_lasso_select_meta(vc, mcords, moves, sel_op); + break; + default: + assert(!"lasso select on incorrect object type"); + break; + } + + DEG_id_tag_update(vc->obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc->obedit->data); + } + FOREACH_OBJECT_IN_MODE_END; } } @@ -890,15 +1042,13 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { - bool extend, select; view3d_operator_needs_opengl(C); /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc); - extend = RNA_boolean_get(op->ptr, "extend"); - select = !RNA_boolean_get(op->ptr, "deselect"); - view3d_lasso_select(C, &vc, mcords, mcords_tot, extend, select); + eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op); MEM_freeN((void *)mcords); @@ -923,7 +1073,8 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; /* properties */ - WM_operator_properties_gesture_lasso_select(ot); + WM_operator_properties_gesture_lasso(ot); + WM_operator_properties_select_operation(ot); } /* ************************** mouse select ************************* */ @@ -974,8 +1125,8 @@ static int object_select_menu_exec(bContext *C, wmOperator *op) if (!toggle) { CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if (base->flag & SELECT) { - ED_base_object_select(base, BA_DESELECT); + if ((base->flag & BASE_SELECTED) != 0) { + ED_object_base_select(base, BA_DESELECT); changed = true; } } @@ -986,8 +1137,8 @@ static int object_select_menu_exec(bContext *C, wmOperator *op) { /* this is a bit dodjy, there should only be ONE object with this name, but library objects can mess this up */ if (STREQ(name, base->object->id.name + 2)) { - ED_base_object_activate(C, base); - ED_base_object_select(base, BA_SELECT); + ED_object_base_activate(C, base); + ED_object_base_select(base, BA_SELECT); changed = true; } } @@ -998,7 +1149,9 @@ static int object_select_menu_exec(bContext *C, wmOperator *op) /* undo? */ if (changed) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C)); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); return OPERATOR_FINISHED; } else { @@ -1031,14 +1184,12 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot) RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle selection instead of deselecting everything first"); } -static void deselectall_except(Scene *scene, Base *b) /* deselect all except b */ +static void deselectall_except(ViewLayer *view_layer, Base *b) /* deselect all except b */ { - Base *base; - - for (base = FIRSTBASE; base; base = base->next) { - if (base->flag & SELECT) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (base->flag & BASE_SELECTED) { if (b != base) { - ED_base_object_select(base, BA_DESELECT); + ED_object_base_select(base, BA_DESELECT); } } } @@ -1052,6 +1203,7 @@ static Base *object_mouse_select_menu( bool ok; LinkNode *linklist = NULL; + /* handle base->object->select_color */ CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { ok = false; @@ -1060,7 +1212,7 @@ static Base *object_mouse_select_menu( if (buffer) { for (int a = 0; a < hits; a++) { /* index was converted */ - if (base->selcol == (buffer[(4 * a) + 3] & ~0xFFFF0000)) { + if (base->object->select_color == (buffer[(4 * a) + 3] & ~0xFFFF0000)) { ok = true; break; } @@ -1156,41 +1308,17 @@ static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits15, const return hits5; } -/* we want a select buffer with bones, if there are... */ -/* so check three selection levels and compare */ +/** + * Populate a select buffer with objects and bones, if there are any. + * Checks three selection levels and compare. + */ static int mixed_bones_object_selectbuffer( - ViewContext *vc, unsigned int *buffer, const int mval[2], - bool use_cycle, bool enumerate, - bool *r_do_nearest) + ViewContext *vc, unsigned int *buffer, const int mval[2], eV3DSelectObjectFilter select_filter, + bool do_nearest) { rcti rect; int hits15, hits9 = 0, hits5 = 0; bool has_bones15 = false, has_bones9 = false, has_bones5 = false; - static int last_mval[2] = {-100, -100}; - bool do_nearest = false; - View3D *v3d = vc->v3d; - - /* define if we use solid nearest select or not */ - if (use_cycle) { - if (v3d->drawtype > OB_WIRE) { - do_nearest = true; - if (len_manhattan_v2v2_int(mval, last_mval) < 3) { - do_nearest = false; - } - } - copy_v2_v2_int(last_mval, mval); - } - else { - if (v3d->drawtype > OB_WIRE) { - do_nearest = true; - } - } - - if (r_do_nearest) { - *r_do_nearest = do_nearest; - } - - do_nearest = do_nearest && !enumerate; const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL); int hits = 0; @@ -1199,7 +1327,7 @@ static int mixed_bones_object_selectbuffer( view3d_opengl_select_cache_begin(); BLI_rcti_init_pt_radius(&rect, mval, 14); - hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode); + hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter); if (hits15 == 1) { hits = selectbuffer_ret_hits_15(buffer, hits15); goto finally; @@ -1210,7 +1338,7 @@ static int mixed_bones_object_selectbuffer( offs = 4 * hits15; BLI_rcti_init_pt_radius(&rect, mval, 9); - hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode); + hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter); if (hits9 == 1) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; @@ -1220,7 +1348,7 @@ static int mixed_bones_object_selectbuffer( offs += 4 * hits9; BLI_rcti_init_pt_radius(&rect, mval, 5); - hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode); + hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter); if (hits5 == 1) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; @@ -1241,6 +1369,59 @@ static int mixed_bones_object_selectbuffer( finally: view3d_opengl_select_cache_end(); + return hits; +} + +static int mixed_bones_object_selectbuffer_extended( + ViewContext *vc, unsigned int *buffer, const int mval[2], eV3DSelectObjectFilter select_filter, + bool use_cycle, bool enumerate, bool *r_do_nearest) +{ + static int last_mval[2] = {-100, -100}; + bool do_nearest = false; + View3D *v3d = vc->v3d; + + /* define if we use solid nearest select or not */ + if (use_cycle) { + if (v3d->shading.type > OB_WIRE) { + do_nearest = true; + if (len_manhattan_v2v2_int(mval, last_mval) < 3) { + do_nearest = false; + } + } + copy_v2_v2_int(last_mval, mval); + } + else { + if (v3d->shading.type > OB_WIRE) { + do_nearest = true; + } + } + + if (r_do_nearest) { + *r_do_nearest = do_nearest; + } + + do_nearest = do_nearest && !enumerate; + + int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest); + + if (vc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { + const bool is_pose_mode = ( + (vc->obact && vc->obact->mode & OB_MODE_POSE) || + (select_filter == VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK)); + struct { + uint data[4]; + } *buffer4 = (void *)buffer; + uint j = 0; + for (uint i = 0; i < hits; i++) { + if (((buffer4[i].data[3] & 0xFFFF0000) != 0) == is_pose_mode) { + if (i != j) { + buffer4[j] = buffer4[i]; + } + j++; + } + } + hits = j; + } return hits; } @@ -1250,7 +1431,7 @@ static Base *mouse_select_eval_buffer( ViewContext *vc, const uint *buffer, int hits, Base *startbase, bool has_bones, bool do_nearest) { - Scene *scene = vc->scene; + ViewLayer *view_layer = vc->view_layer; View3D *v3d = vc->v3d; Base *base, *basact = NULL; int a; @@ -1271,7 +1452,9 @@ static Base *mouse_select_eval_buffer( } else { /* only exclude active object when it is selected... */ - if (BASACT && (BASACT->flag & SELECT) && hits > 1) notcol = BASACT->selcol; + if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED) && hits > 1) { + notcol = BASACT(view_layer)->object->select_color; + } for (a = 0; a < hits; a++) { if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) { @@ -1281,10 +1464,10 @@ static Base *mouse_select_eval_buffer( } } - base = FIRSTBASE; + base = FIRSTBASE(view_layer); while (base) { if (BASE_SELECTABLE(v3d, base)) { - if (base->selcol == selcol) break; + if (base->object->select_color == selcol) break; } base = base->next; } @@ -1296,9 +1479,9 @@ static Base *mouse_select_eval_buffer( while (base) { /* skip objects with select restriction, to prevent prematurely ending this loop * with an un-selectable choice */ - if (base->object->restrictflag & OB_RESTRICT_SELECT) { + if ((base->flag & BASE_SELECTABLE) == 0) { base = base->next; - if (base == NULL) base = FIRSTBASE; + if (base == NULL) base = FIRSTBASE(view_layer); if (base == startbase) break; } @@ -1307,12 +1490,12 @@ static Base *mouse_select_eval_buffer( if (has_bones) { /* skip non-bone objects */ if ((buffer[4 * a + 3] & 0xFFFF0000)) { - if (base->selcol == (buffer[(4 * a) + 3] & 0xFFFF)) + if (base->object->select_color == (buffer[(4 * a) + 3] & 0xFFFF)) basact = base; } } else { - if (base->selcol == (buffer[(4 * a) + 3] & 0xFFFF)) + if (base->object->select_color == (buffer[(4 * a) + 3] & 0xFFFF)) basact = base; } } @@ -1321,7 +1504,7 @@ static Base *mouse_select_eval_buffer( if (basact) break; base = base->next; - if (base == NULL) base = FIRSTBASE; + if (base == NULL) base = FIRSTBASE(view_layer); if (base == startbase) break; } } @@ -1335,23 +1518,36 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) ViewContext vc; Base *basact = NULL; unsigned int buffer[MAXPICKBUF]; - int hits; - bool do_nearest; /* setup view context for argument to callbacks */ view3d_operator_needs_opengl(C); + ED_view3d_viewcontext_init(C, &vc); - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, false, false, &do_nearest); + const bool do_nearest = (vc.v3d->shading.type > OB_WIRE); + const int hits = mixed_bones_object_selectbuffer( + &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest); if (hits > 0) { const bool has_bones = selectbuffer_has_bones(buffer, hits); - basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.scene->base.first, has_bones, do_nearest); + basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.view_layer->object_bases.first, has_bones, do_nearest); } return basact; } +Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2]) +{ + Base *base = ED_view3d_give_base_under_cursor(C, mval); + if (base) return base->object; + return NULL; +} + +bool ED_view3d_is_object_under_cursor(bContext *C, const int mval[2]) +{ + return ED_view3d_give_object_under_cursor(C, mval) != NULL; +} + static void deselect_all_tracks(MovieTracking *tracking) { MovieTrackingObject *object; @@ -1378,16 +1574,17 @@ static bool ed_object_select_pick( { ViewContext vc; ARegion *ar = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); - Base *base, *startbase = NULL, *basact = NULL, *oldbasact = NULL; + ViewLayer *view_layer = CTX_data_view_layer(C); + View3D *v3d = CTX_wm_view3d(C); + Base *base, *startbase = NULL, *basact = NULL, *oldbasact = BASACT(view_layer); + const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT; bool is_obedit; float dist = ED_view3d_select_dist_px() * 1.3333f; bool retval = false; int hits; const float mval_fl[2] = {(float)mval[0], (float)mval[1]}; - /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc); @@ -1397,9 +1594,12 @@ static bool ed_object_select_pick( vc.obedit = NULL; } + /* In pose mode we don't want to mess with object selection. */ + const bool is_pose_mode = (vc.obact && vc.obact->mode & OB_MODE_POSE); + /* always start list from basact in wire mode */ - startbase = FIRSTBASE; - if (BASACT && BASACT->next) startbase = BASACT->next; + startbase = FIRSTBASE(view_layer); + if (BASACT(view_layer) && BASACT(view_layer)->next) startbase = BASACT(view_layer)->next; /* This block uses the control key to make the object selected by its center point rather than its contents */ /* in editmode do not activate */ @@ -1419,7 +1619,7 @@ static bool ed_object_select_pick( V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { float dist_temp = len_manhattan_v2v2(mval_fl, screen_co); - if (base == BASACT) dist_temp += 10.0f; + if (base == BASACT(view_layer)) dist_temp += 10.0f; if (dist_temp < dist) { dist = dist_temp; basact = base; @@ -1428,10 +1628,23 @@ static bool ed_object_select_pick( } base = base->next; - if (base == NULL) base = FIRSTBASE; + if (base == NULL) base = FIRSTBASE(view_layer); if (base == startbase) break; } } + if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { + if (is_obedit == false) { + if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) { + if (object_mode == OB_MODE_OBJECT) { + struct Main *bmain = CTX_data_main(C); + ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object); + } + if (!BKE_object_is_mode_compat(basact->object, object_mode)) { + basact = NULL; + } + } + } + } } else { unsigned int buffer[MAXPICKBUF]; @@ -1440,7 +1653,12 @@ static bool ed_object_select_pick( // TIMEIT_START(select_time); /* if objects have posemode set, the bones are in the same selection buffer */ - hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, true, enumerate, &do_nearest); + const eV3DSelectObjectFilter select_filter = ( + (object == false) ? ED_view3d_select_filter_from_mode(scene, vc.obact) : VIEW3D_SELECT_FILTER_NOP); + hits = mixed_bones_object_selectbuffer_extended( + &vc, buffer, mval, select_filter, + true, enumerate, + &do_nearest); // TIMEIT_END(select_time); @@ -1458,7 +1676,7 @@ static bool ed_object_select_pick( if (has_bones && basact) { if (basact->object->type == OB_CAMERA) { - if (BASACT == basact) { + if (BASACT(view_layer) == basact) { int i, hitresult; bool changed = false; @@ -1467,7 +1685,7 @@ static bool ed_object_select_pick( /* if there's bundles in buffer select bundles first, * so non-camera elements should be ignored in buffer */ - if (basact->selcol != (hitresult & 0xFFFF)) { + if (basact->object->select_color != (hitresult & 0xFFFF)) { continue; } @@ -1496,11 +1714,13 @@ static bool ed_object_select_pick( changed = true; } - basact->flag |= SELECT; - basact->object->flag = basact->flag; + basact->flag |= BASE_SELECTED; + BKE_scene_object_base_flag_sync_from_base(basact); retval = true; + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + DEG_id_tag_update(&clip->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, track); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); @@ -1516,30 +1736,58 @@ static bool ed_object_select_pick( } } else if (ED_armature_pose_select_pick_with_buffer( - scene, basact, buffer, hits, extend, deselect, toggle, do_nearest)) + view_layer, v3d, basact, buffer, hits, extend, deselect, toggle, do_nearest)) { /* then bone is found */ /* we make the armature selected: * not-selected active object in posemode won't work well for tools */ - basact->flag |= SELECT; - basact->object->flag = basact->flag; + basact->flag |= BASE_SELECTED; + BKE_scene_object_base_flag_sync_from_base(basact); retval = true; WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object); /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */ - if (BASACT && (BASACT->object->mode & OB_MODE_WEIGHT_PAINT)) { + if (BASACT(view_layer) && (BASACT(view_layer)->object->mode & OB_MODE_WEIGHT_PAINT)) { /* prevent activating */ basact = NULL; } } /* prevent bone selecting to pass on to object selecting */ - if (basact == BASACT) + if (basact == BASACT(view_layer)) basact = NULL; } + + if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { + if (is_obedit == false) { + if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) { + if (object_mode == OB_MODE_OBJECT) { + struct Main *bmain = CTX_data_main(C); + ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object); + } + if (!BKE_object_is_mode_compat(basact->object, object_mode)) { + basact = NULL; + } + } + } + } + } + } + + if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { + /* Disallow switching modes, + * special exception for edit-mode - vertex-parent operator. */ + if (is_obedit == false) { + if (oldbasact && basact) { + if ((oldbasact->object->mode != basact->object->mode) && + (oldbasact->object->mode & basact->object->mode) == 0) + { + basact = NULL; + } + } } } @@ -1549,40 +1797,63 @@ static bool ed_object_select_pick( if (vc.obedit) { /* only do select */ - deselectall_except(scene, basact); - ED_base_object_select(basact, BA_SELECT); + deselectall_except(view_layer, basact); + ED_object_base_select(basact, BA_SELECT); } /* also prevent making it active on mouse selection */ else if (BASE_SELECTABLE(v3d, basact)) { - - oldbasact = BASACT; - if (extend) { - ED_base_object_select(basact, BA_SELECT); + ED_object_base_select(basact, BA_SELECT); } else if (deselect) { - ED_base_object_select(basact, BA_DESELECT); + ED_object_base_select(basact, BA_DESELECT); } else if (toggle) { - if (basact->flag & SELECT) { + if (basact->flag & BASE_SELECTED) { if (basact == oldbasact) { - ED_base_object_select(basact, BA_DESELECT); + ED_object_base_select(basact, BA_DESELECT); } } else { - ED_base_object_select(basact, BA_SELECT); + ED_object_base_select(basact, BA_SELECT); } } else { - deselectall_except(scene, basact); - ED_base_object_select(basact, BA_SELECT); + /* When enabled, this puts other objects out of multi pose-mode. */ + if (is_pose_mode == false) { + deselectall_except(view_layer, basact); + ED_object_base_select(basact, BA_SELECT); + } } if ((oldbasact != basact) && (is_obedit == false)) { - ED_base_object_activate(C, basact); /* adds notifier */ + ED_object_base_activate(C, basact); /* adds notifier */ + } + + /* Set special modes for grease pencil + The grease pencil modes are not real modes, but a hack to make the interface + consistent, so need some tricks to keep UI synchronized */ + // XXX: This stuff needs reviewing (Aligorith) + if (false && + (((oldbasact) && oldbasact->object->type == OB_GPENCIL) || + (basact->object->type == OB_GPENCIL))) + { + /* set cursor */ + if (ELEM(basact->object->mode, + OB_MODE_GPENCIL_PAINT, + OB_MODE_GPENCIL_SCULPT, + OB_MODE_GPENCIL_WEIGHT)) + { + ED_gpencil_toggle_brush_cursor(C, true, NULL); + } + else { + /* TODO: maybe is better use restore */ + ED_gpencil_toggle_brush_cursor(C, false, NULL); + } } } + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } @@ -1596,17 +1867,16 @@ typedef struct BoxSelectUserData { const rcti *rect; const rctf *rect_fl; rctf _rect_fl; - bool select; + eSelectOp sel_op; /* runtime */ - int pass; bool is_done; bool is_changed; } BoxSelectUserData; static void view3d_userdata_boxselect_init( BoxSelectUserData *r_data, - ViewContext *vc, const rcti *rect, const bool select) + ViewContext *vc, const rcti *rect, const eSelectOp sel_op) { r_data->vc = vc; @@ -1614,10 +1884,9 @@ static void view3d_userdata_boxselect_init( r_data->rect_fl = &r_data->_rect_fl; BLI_rctf_rcti_copy(&r_data->_rect_fl, rect); - r_data->select = select; + r_data->sel_op = sel_op; /* runtime */ - r_data->pass = 0; r_data->is_done = false; r_data->is_changed = false; } @@ -1631,14 +1900,17 @@ bool edge_inside_circle(const float cent[2], float radius, const float screen_co static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) { BoxSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT); + const bool is_select = mv->flag & SELECT; + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); } } -static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, bool extend) +static int do_paintvert_box_select( + ViewContext *vc, rcti *rect, const eSelectOp sel_op) { - const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0; + const bool use_zbuf = V3D_IS_ZBUF(vc->v3d); Mesh *me; MVert *mvert; struct ImBuf *ibuf; @@ -1655,8 +1927,9 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo return OPERATOR_CANCELLED; } - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, false); + } if (use_zbuf) { selar = MEM_callocN(me->totvert + 1, "selar"); @@ -1686,10 +1959,12 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo mvert = me->mvert; for (a = 1; a <= me->totvert; a++, mvert++) { - if (selar[a]) { - if ((mvert->flag & ME_HIDE) == 0) { - if (select) mvert->flag |= SELECT; - else mvert->flag &= ~SELECT; + if ((mvert->flag & ME_HIDE) == 0) { + const bool is_select = mvert->flag & SELECT; + const bool is_inside = (selar[a] != 0); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mvert->flag, sel_op_result, SELECT); } } } @@ -1704,17 +1979,18 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo else { BoxSelectUserData data; - view3d_userdata_boxselect_init(&data, vc, rect, select); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); meshobject_foreachScreenVert(vc, do_paintvert_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } - if (select == false) { + if (SEL_OP_CAN_DESELECT(sel_op)) { BKE_mesh_mselect_validate(me); } paintvert_flush_flags(vc->obact); + paintvert_tag_select_update(vc->C, vc->obact); return OPERATOR_FINISHED; } @@ -1723,39 +1999,42 @@ static void do_nurbs_box_select__doSelect( void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) { BoxSelectUserData *data = userData; - Object *obedit = data->vc->obedit; - Curve *cu = (Curve *)obedit->data; - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - if (bp) { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + if (bp) { + const bool is_select = bp->f1 & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); } - else { - if (cu->drawflag & CU_HIDE_HANDLES) { - /* can only be (beztindex == 0) here since handles are hidden */ - bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); + } + else { + if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { + /* can only be (beztindex == 0) here since handles are hidden */ + const bool is_select = bezt->f2 & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT); } - else { - if (beztindex == 0) { - bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT); - } - else if (beztindex == 1) { - bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); - } - else { - bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT); - } + bezt->f1 = bezt->f3 = bezt->f2; + } + else { + char *flag_p = (&bezt->f1) + beztindex; + const bool is_select = *flag_p & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT); } } } } -static int do_nurbs_box_select(ViewContext *vc, rcti *rect, bool select, bool extend) +static int do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op) { BoxSelectUserData data; - view3d_userdata_boxselect_init(&data, vc, rect, select); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op); - if (extend == false && select) { + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { Curve *curve = (Curve *) vc->obedit->data; ED_curve_deselect_all(curve->editnurb); } @@ -1770,19 +2049,22 @@ static int do_nurbs_box_select(ViewContext *vc, rcti *rect, bool select, bool ex static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2]) { BoxSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + const bool is_select = bp->f1 & SELECT; + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); } } -static int do_lattice_box_select(ViewContext *vc, rcti *rect, bool select, bool extend) +static int do_lattice_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op) { BoxSelectUserData data; - view3d_userdata_boxselect_init(&data, vc, rect, select); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { ED_lattice_flags_set(vc->obedit, 0); + } ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -1793,58 +2075,72 @@ static int do_lattice_box_select(ViewContext *vc, rcti *rect, bool select, bool static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index)) { BoxSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - BM_vert_select_set(data->vc->em->bm, eve, data->select); + const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_vert_select_set(data->vc->em->bm, eve, sel_op_result); } } -static void do_mesh_box_select__doSelectEdge( +static void do_mesh_box_select__doSelectEdge_pass0( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { BoxSelectUserData *data = userData; - - if (EDBM_backbuf_check(bm_solidoffs + index)) { - if (data->pass == 0) { - if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) { - BM_edge_select_set(data->vc->em->bm, eed, data->select); - data->is_done = true; - } - } - else { - if (edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) { - BM_edge_select_set(data->vc->em->bm, eed, data->select); - } - } + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = ( + EDBM_backbuf_check(bm_solidoffs + index) && + edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); + data->is_done = true; + } +} +static void do_mesh_box_select__doSelectEdge_pass1( + void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) +{ + BoxSelectUserData *data = userData; + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = ( + EDBM_backbuf_check(bm_solidoffs + index) && + edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); } } static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index)) { BoxSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - BM_face_select_set(data->vc->em->bm, efa, data->select); + const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_face_select_set(data->vc->em->bm, efa, sel_op_result); } } -static int do_mesh_box_select(ViewContext *vc, rcti *rect, bool select, bool extend) +static int do_mesh_box_select( + ViewContext *vc, rcti *rect, const eSelectOp sel_op) { BoxSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; int bbsel; - view3d_userdata_boxselect_init(&data, vc, rect, select); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT); + } /* for non zbuf projections, don't change the GL state */ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - glLoadMatrixf(vc->rv3d->viewmat); + GPU_matrix_set(vc->rv3d->viewmat); bbsel = EDBM_backbuf_border_init(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax); if (ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { - edbm_backbuf_check_and_select_verts(vc->em, select); + edbm_backbuf_check_and_select_verts(vc->em, sel_op); } else { mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -1852,19 +2148,15 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, bool select, bool ext } if (ts->selectmode & SCE_SELECT_EDGE) { /* Does both bbsel and non-bbsel versions (need screen cos for both) */ - - data.pass = 0; - mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); - - if (data.is_done == 0) { - data.pass = 1; - mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); + mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR); + if (data.is_done == false) { + mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR); } } if (ts->selectmode & SCE_SELECT_FACE) { if (bbsel) { - edbm_backbuf_check_and_select_faces(vc->em, select); + edbm_backbuf_check_and_select_faces(vc->em, sel_op); } else { mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -1878,56 +2170,109 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, bool select, bool ext return OPERATOR_FINISHED; } -static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool extend) +static int do_meta_box_select( + ViewContext *vc, + const rcti *rect, const eSelectOp sel_op) { - MetaBall *mb = (MetaBall *)vc->obedit->data; + Object *ob = vc->obedit; + MetaBall *mb = (MetaBall *)ob->data; MetaElem *ml; int a; unsigned int buffer[MAXPICKBUF]; int hits; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL); + hits = view3d_opengl_select( + vc, buffer, MAXPICKBUF, rect, + VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { BKE_mball_deselect_all(mb); + } + + int metaelem_id = 0; + for (ml = mb->editelems->first; ml; ml = ml->next, metaelem_id += 0x10000) { + bool is_inside_radius = false; + bool is_inside_stiff = false; - for (ml = mb->editelems->first; ml; ml = ml->next) { for (a = 0; a < hits; a++) { - if (ml->selcol1 == buffer[(4 * a) + 3]) { - ml->flag |= MB_SCALE_RAD; - if (select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; + int hitresult = buffer[(4 * a) + 3]; + + if (hitresult == -1) { + continue; + } + else if (hitresult & MBALL_NOSEL) { + continue; + } + + const uint hit_object = hitresult & 0xFFFF; + if (vc->obedit->select_color != hit_object) { + continue; + } + + if (metaelem_id != (hitresult & 0xFFFF0000 & ~(MBALLSEL_ANY))) { + continue; + } + + if (hitresult & MBALLSEL_RADIUS) { + is_inside_radius = true; break; } - if (ml->selcol2 == buffer[(4 * a) + 3]) { - ml->flag &= ~MB_SCALE_RAD; - if (select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; + + if (hitresult & MBALLSEL_STIFF) { + is_inside_stiff = true; break; } } + if (is_inside_radius) { + ml->flag |= MB_SCALE_RAD; + } + if (is_inside_stiff) { + ml->flag &= ~MB_SCALE_RAD; + } + + const bool is_select = (ml->flag & SELECT); + const bool is_inside = is_inside_radius || is_inside_stiff; + + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT); + } } return OPERATOR_FINISHED; } -static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool extend) +static int do_armature_box_select( + ViewContext *vc, + const rcti *rect, const eSelectOp sel_op) { - bArmature *arm = vc->obedit->data; + /* TODO(campbell): Full support for seleciton operations for edit bones. */ + const bool select = sel_op == SEL_OP_ADD; int a; unsigned int buffer[MAXPICKBUF]; int hits; - hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL); + hits = view3d_opengl_select( + vc, buffer, MAXPICKBUF, rect, + VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(vc->view_layer, vc->v3d, &objects_len); /* clear flag we use to detect point was affected */ - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) - ebone->flag &= ~BONE_DONE; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + bArmature *arm = obedit->data; + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + ebone->flag &= ~BONE_DONE; + } + } - if (extend == false && select) - ED_armature_edit_deselect_all_visible(vc->obedit); + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + ED_armature_edit_deselect_all_visible_multi(objects, objects_len); + } /* first we only check points inside the border */ for (a = 0; a < hits; a++) { @@ -1936,7 +2281,9 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool if ((index & 0xFFFF0000) == 0) { continue; } - EditBone *ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY)); + + EditBone *ebone; + ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone); if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) { if (index & BONESEL_TIP) { ebone->flag |= BONE_DONE; @@ -1954,10 +2301,14 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool } /* now we have to flush tag from parents... */ - for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - if (ebone->parent->flag & BONE_DONE) { - ebone->flag |= BONE_DONE; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + bArmature *arm = obedit->data; + for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { + if (ebone->parent->flag & BONE_DONE) { + ebone->flag |= BONE_DONE; + } } } } @@ -1967,7 +2318,8 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool int index = buffer[(4 * a) + 3]; if (index != -1) { if (index & BONESEL_BONE) { - EditBone *ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY)); + EditBone *ebone; + ED_armature_object_and_ebone_from_select_buffer(objects, objects_len, index, &ebone); if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) { if (!(ebone->flag & BONE_DONE)) { if (select) { @@ -1982,45 +2334,131 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool } } - ED_armature_edit_sync_selection(arm->edbo); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + bArmature *arm = obedit->data; + ED_armature_edit_sync_selection(arm->edbo); + } + + MEM_freeN(objects); return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } -static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend) +/** + * Compare result of 'GPU_select': 'uint[4]', + * needed for when we need to align with object draw-order. + */ +static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_p) { - Bone *bone; - Object *ob = vc->obact; - unsigned int *vbuffer = NULL; /* selection buffer */ - unsigned int *col; /* color in buffer */ - int bone_only; - int bone_selected = 0; + /* 4th element is select id */ + uint sel_a = ((uint *)sel_a_p)[3]; + uint sel_b = ((uint *)sel_b_p)[3]; + +#ifdef __BIG_ENDIAN__ + BLI_endian_switch_uint32(&sel_a); + BLI_endian_switch_uint32(&sel_b); +#endif + + if (sel_a < sel_b) { + return -1; + } + else if (sel_a > sel_b) { + return 1; + } + else { + return 0; + } +} + +static int do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op) +{ + View3D *v3d = vc->v3d; + bool changed = false; int totobj = MAXPICKBUF; /* XXX solve later */ - int hits; - if ((ob) && (ob->mode & OB_MODE_POSE)) - bone_only = 1; - else - bone_only = 0; + /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ + uint *vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(uint[4]), "selection buffer"); + const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact); + const int hits = view3d_opengl_select( + vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, + VIEW3D_SELECT_ALL, select_filter); - if (extend == false && select) { - if (bone_only) { - CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) - { - if ((select == false) || ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)) { - pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } + for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) { + base->object->id.tag &= ~LIB_TAG_DOIT; + } + + Base **bases = NULL; + BLI_array_declare(bases); + + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + object_deselect_all_visible(vc->view_layer, vc->v3d); + changed = true; + } + + if ((hits == -1) && !SEL_OP_USE_OUTSIDE(sel_op)) { + goto finally; + } + + for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) { + if (BASE_SELECTABLE(v3d, base)) { + if ((base->object->select_color & 0x0000FFFF) != 0) { + BLI_array_append(bases, base); } - CTX_DATA_END; } - else { - object_deselect_all_visible(vc->scene, vc->v3d); + } + + /* The draw order doesn't always match the order we populate the engine, see: T51695. */ + qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp); + + for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) { + Bone *bone; + Base *base = ED_armature_base_and_bone_from_select_buffer(bases, BLI_array_len(bases), *col, &bone); + base->object->id.tag |= LIB_TAG_DOIT; + } + + for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) { + if (BASE_SELECTABLE(v3d, base)) { + const bool is_select = base->flag & BASE_SELECTED; + const bool is_inside = base->object->id.tag & LIB_TAG_DOIT; + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); + changed = true; + } } } +finally: + if (bases != NULL) { + MEM_freeN(bases); + } + + MEM_freeN(vbuffer); + + if (changed) { + DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static int do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op) +{ + uint bases_len; + Base **bases = do_pose_tag_select_op_prepare(vc, &bases_len); + + int totobj = MAXPICKBUF; /* XXX solve later */ + /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ - vbuffer = MEM_mallocN(4 * (totobj + MAXPICKELEMS) * sizeof(unsigned int), "selection buffer"); - hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL); + uint *vbuffer = MEM_mallocN((totobj + MAXPICKELEMS) * sizeof(uint[4]), "selection buffer"); + const eV3DSelectObjectFilter select_filter = ED_view3d_select_filter_from_mode(vc->scene, vc->obact); + const int hits = view3d_opengl_select( + vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, + VIEW3D_SELECT_ALL, select_filter); /* * LOGIC NOTES (theeth): * The buffer and ListBase have the same relative order, which makes the selection @@ -2028,73 +2466,66 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b * is the same as the object, we have a hit and can move to the next color * and object pair, if not, just move to the next object, * keeping the same color until we have a hit. - * - * The buffer order is defined by OGL standard, hopefully no stupid GFX card - * does it incorrectly. */ - if (hits > 0) { /* no need to loop if there's no hit */ - Base *base; - col = vbuffer + 3; - - for (base = vc->scene->base.first; base && hits; base = base->next) { - if (BASE_SELECTABLE(vc->v3d, base)) { - while (base->selcol == (*col & 0xFFFF)) { /* we got an object */ - if (*col & 0xFFFF0000) { /* we got a bone */ - bone = ED_armature_bone_find_index(base->object, *col & ~(BONESEL_ANY)); - if (bone) { - if (select) { - if ((bone->flag & BONE_UNSELECTABLE) == 0) { - bone->flag |= BONE_SELECTED; - bone_selected = 1; - } - } - else { - bArmature *arm = base->object->data; - bone->flag &= ~BONE_SELECTED; - if (arm->act_bone == bone) - arm->act_bone = NULL; - } - } - } - else if (!bone_only) { - ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT); - } + if (hits > 0) { + /* no need to loop if there's no hit */ - col += 4; /* next color */ - hits--; - if (hits == 0) break; - } - } + /* The draw order doesn't always match the order we populate the engine, see: T51695. */ + qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp); - if (bone_selected) { - if (base->object && (base->object->type == OB_ARMATURE)) { - bArmature *arm = base->object->data; + for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) { + Bone *bone; + Base *base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, *col, &bone); - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object); + if (base == NULL) { + continue; + } - if (arm && (arm->flag & ARM_HAS_VIZ_DEPS)) { - /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + /* Loop over contiguous bone hits for 'base'. */ + for (; col != col_end; col += 4) { + /* should never fail */ + if (bone != NULL) { + base->object->id.tag |= LIB_TAG_DOIT; + bone->flag |= BONE_DONE; + } + + /* Select the next bone if we're not switching bases. */ + if (col + 4 != col_end) { + if ((base->object->select_color & 0x0000FFFF) != (col[4] & 0x0000FFFF)) { + break; + } + if (base->object->pose != NULL) { + const uint hit_bone = (col[4] & ~BONESEL_ANY) >> 16; + bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone); + bone = pchan ? pchan->bone : NULL; + } + else { + bone = NULL; } } } } + } + const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op); + if (changed_multi) { + DEG_id_tag_update(&vc->scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); } + + if (bases != NULL) { + MEM_freeN(bases); + } MEM_freeN(vbuffer); return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } -static int view3d_borderselect_exec(bContext *C, wmOperator *op) +static int view3d_box_select_exec(bContext *C, wmOperator *op) { ViewContext vc; rcti rect; - bool extend; - bool select; - int ret = OPERATOR_CANCELLED; view3d_operator_needs_opengl(C); @@ -2102,94 +2533,115 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc); - select = !RNA_boolean_get(op->ptr, "deselect"); - extend = RNA_boolean_get(op->ptr, "extend"); + eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); WM_operator_properties_border_to_rcti(op, &rect); if (vc.obedit) { - switch (vc.obedit->type) { - case OB_MESH: - vc.em = BKE_editmesh_from_object(vc.obedit); - ret = do_mesh_box_select(&vc, &rect, select, extend); -// if (EM_texFaceCheck()) - if (ret & OPERATOR_FINISHED) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); - } - break; - case OB_CURVE: - case OB_SURF: - ret = do_nurbs_box_select(&vc, &rect, select, extend); - if (ret & OPERATOR_FINISHED) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); - } - break; - case OB_MBALL: - ret = do_meta_box_select(&vc, &rect, select, extend); - if (ret & OPERATOR_FINISHED) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); - } - break; - case OB_ARMATURE: - ret = do_armature_box_select(&vc, &rect, select, extend); - if (ret & OPERATOR_FINISHED) { - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); - } - break; - case OB_LATTICE: - ret = do_lattice_box_select(&vc, &rect, select, extend); - if (ret & OPERATOR_FINISHED) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); - } - break; - default: - assert(!"border select on incorrect object type"); - break; + + FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, vc.obedit->type, vc.obedit->mode, ob_iter) { + ED_view3d_viewcontext_init_object(&vc, ob_iter); + + switch (vc.obedit->type) { + case OB_MESH: + vc.em = BKE_editmesh_from_object(vc.obedit); + ret |= do_mesh_box_select(&vc, &rect, sel_op); + if (ret & OPERATOR_FINISHED) { + DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); + } + break; + case OB_CURVE: + case OB_SURF: + ret |= do_nurbs_box_select(&vc, &rect, sel_op); + if (ret & OPERATOR_FINISHED) { + DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); + } + break; + case OB_MBALL: + ret |= do_meta_box_select(&vc, &rect, sel_op); + if (ret & OPERATOR_FINISHED) { + DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); + } + break; + case OB_ARMATURE: + ret |= do_armature_box_select(&vc, &rect, sel_op); + if (ret & OPERATOR_FINISHED) { + DEG_id_tag_update(&vc.obedit->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); + } + break; + case OB_LATTICE: + ret |= do_lattice_box_select(&vc, &rect, sel_op); + if (ret & OPERATOR_FINISHED) { + DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); + } + break; + default: + assert(!"box select on incorrect object type"); + break; + } } + FOREACH_OBJECT_IN_MODE_END; } else { /* no editmode, unified for bones and objects */ if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) { - ret = ED_sculpt_mask_box_select(C, &vc, &rect, select, extend); + /* XXX, this is not selection, could be it's own operator. */ + ret |= ED_sculpt_mask_box_select(C, &vc, &rect, sel_op == SEL_OP_ADD ? true : false); } else if (vc.obact && BKE_paint_select_face_test(vc.obact)) { - ret = do_paintface_box_select(&vc, &rect, select, extend); + ret |= do_paintface_box_select(&vc, &rect, sel_op); } else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) { - ret = do_paintvert_box_select(&vc, &rect, select, extend); + ret |= do_paintvert_box_select(&vc, &rect, sel_op); } else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) { - ret = PE_border_select(C, &rect, select, extend); + ret |= PE_box_select(C, &rect, sel_op); + } + else if (vc.obact && vc.obact->mode & OB_MODE_POSE) { + ret |= do_pose_box_select(C, &vc, &rect, sel_op); } else { /* object mode with none active */ - ret = do_object_pose_box_select(C, &vc, &rect, select, extend); + ret |= do_object_box_select(C, &vc, &rect, sel_op); } } + if (ret & OPERATOR_FINISHED) { + ret = OPERATOR_FINISHED; + } + else { + ret = OPERATOR_CANCELLED; + } + return ret; } /* *****************Selection Operators******************* */ -/* ****** Border Select ****** */ -void VIEW3D_OT_select_border(wmOperatorType *ot) +/* ****** Box Select ****** */ +void VIEW3D_OT_select_box(wmOperatorType *ot) { /* identifiers */ - ot->name = "Border Select"; - ot->description = "Select items using border selection"; - ot->idname = "VIEW3D_OT_select_border"; + ot->name = "Box Select"; + ot->description = "Select items using box selection"; + ot->idname = "VIEW3D_OT_select_box"; /* api callbacks */ - ot->invoke = WM_gesture_border_invoke; - ot->exec = view3d_borderselect_exec; - ot->modal = WM_gesture_border_modal; + ot->invoke = WM_gesture_box_invoke; + ot->exec = view3d_box_select_exec; + ot->modal = WM_gesture_box_modal; ot->poll = view3d_selectable_data; - ot->cancel = WM_gesture_border_cancel; + ot->cancel = WM_gesture_box_cancel; /* flags */ ot->flag = OPTYPE_UNDO; /* rna */ - WM_operator_properties_gesture_border_select(ot); + WM_operator_properties_gesture_box(ot); + WM_operator_properties_select_operation(ot); } @@ -2200,7 +2652,7 @@ static bool ed_wpaint_vertex_select_pick( bool extend, bool deselect, bool toggle, Object *obact) { View3D *v3d = CTX_wm_view3d(C); - const bool use_zbuf = (v3d->flag & V3D_ZBUF_SELECT) != 0; + const bool use_zbuf = V3D_IS_ZBUF(v3d); Mesh *me = obact->data; /* already checked for NULL */ unsigned int index = 0; @@ -2231,7 +2683,7 @@ static bool ed_wpaint_vertex_select_pick( } paintvert_flush_flags(obact); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); + paintvert_tag_select_update(C, obact); return true; } return false; @@ -2319,8 +2771,8 @@ void VIEW3D_OT_select(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "Activate/Select"; - ot->description = "Activate/select item(s)"; + ot->name = "Select"; + ot->description = "Select and activate item(s)"; ot->idname = "VIEW3D_OT_select"; /* api callbacks */ @@ -2334,9 +2786,12 @@ void VIEW3D_OT_select(wmOperatorType *ot) /* properties */ WM_operator_properties_mouse_select(ot); - RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting, in editmode used to extend object selection"); - RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)"); - RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)"); + prop = RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting, in editmode used to extend object selection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX); RNA_def_property_flag(prop, PROP_HIDDEN); @@ -2415,7 +2870,7 @@ static void mesh_circle_select(ViewContext *vc, const bool select, const int mva if (ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { - edbm_backbuf_check_and_select_verts(vc->em, select); + edbm_backbuf_check_and_select_verts(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } else { mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -2424,7 +2879,7 @@ static void mesh_circle_select(ViewContext *vc, const bool select, const int mva if (ts->selectmode & SCE_SELECT_EDGE) { if (bbsel) { - edbm_backbuf_check_and_select_edges(vc->em, select); + edbm_backbuf_check_and_select_edges(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } else { mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); @@ -2433,7 +2888,7 @@ static void mesh_circle_select(ViewContext *vc, const bool select, const int mva if (ts->selectmode & SCE_SELECT_FACE) { if (bbsel) { - edbm_backbuf_check_and_select_faces(vc->em, select); + edbm_backbuf_check_and_select_faces(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } else { mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -2454,14 +2909,13 @@ static void paint_facesel_circle_select(ViewContext *vc, const bool select, cons bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); if (bbsel) { - edbm_backbuf_check_and_select_tfaces(me, select); + edbm_backbuf_check_and_select_tfaces(me, select ? SEL_OP_ADD : SEL_OP_SUB); EDBM_backbuf_free(); - paintface_flush_flags(ob, SELECT); + paintface_flush_flags(vc->C, ob, SELECT); } } -static void paint_vertsel_circle_select_doSelectVert( - void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) +static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) { CircleSelectUserData *data = userData; @@ -2471,7 +2925,7 @@ static void paint_vertsel_circle_select_doSelectVert( } static void paint_vertsel_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad) { - const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0; + const bool use_zbuf = V3D_IS_ZBUF(vc->v3d); Object *ob = vc->obact; Mesh *me = ob->data; bool bbsel; @@ -2482,7 +2936,7 @@ static void paint_vertsel_circle_select(ViewContext *vc, const bool select, cons bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); if (bbsel) { - edbm_backbuf_check_and_select_verts_obmode(me, select); + edbm_backbuf_check_and_select_verts_obmode(me, select ? SEL_OP_ADD : SEL_OP_SET); EDBM_backbuf_free(); } } @@ -2499,6 +2953,7 @@ static void paint_vertsel_circle_select(ViewContext *vc, const bool select, cons BKE_mesh_mselect_validate(me); } paintvert_flush_flags(ob); + paintvert_tag_select_update(vc->C, ob); } @@ -2506,15 +2961,13 @@ static void nurbscurve_circle_doSelect( void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) { CircleSelectUserData *data = userData; - Object *obedit = data->vc->obedit; - Curve *cu = (Curve *)obedit->data; if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) { if (bp) { bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); } else { - if (cu->drawflag & CU_HIDE_HANDLES) { + if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) { /* can only be (beztindex == 0) here since handles are hidden */ bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); } @@ -2632,14 +3085,7 @@ static void pose_circle_select(ViewContext *vc, const bool select, const int mva pose_foreachScreenBone(vc, do_circle_select_pose__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT); if (data.is_changed) { - bArmature *arm = vc->obact->data; - - WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, vc->obact); - - if (arm->flag & ARM_HAS_VIZ_DEPS) { - /* mask modifier ('armature' mode), etc. */ - DAG_id_tag_update(&vc->obact->id, OB_RECALC_DATA); - } + ED_pose_bone_select_tag_update(vc->obact); } } @@ -2749,7 +3195,8 @@ static void mball_circle_select(ViewContext *vc, const bool select, const int mv /** Callbacks for circle selection in Editmode */ -static void obedit_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad) +static void obedit_circle_select( + ViewContext *vc, const bool select, const int mval[2], float rad) { switch (vc->obedit->type) { case OB_MESH: @@ -2775,23 +3222,25 @@ static void obedit_circle_select(ViewContext *vc, const bool select, const int m static bool object_circle_select(ViewContext *vc, const bool select, const int mval[2], float rad) { - Scene *scene = vc->scene; + ViewLayer *view_layer = vc->view_layer; + View3D *v3d = vc->v3d; + const float radius_squared = rad * rad; const float mval_fl[2] = {mval[0], mval[1]}; bool changed = false; - const int select_flag = select ? SELECT : 0; + const int select_flag = select ? BASE_SELECTED : 0; Base *base; - for (base = FIRSTBASE; base; base = base->next) { - if (BASE_SELECTABLE(vc->v3d, base) && ((base->flag & SELECT) != select_flag)) { + for (base = FIRSTBASE(view_layer); base; base = base->next) { + if (BASE_SELECTABLE(v3d, base) && ((base->flag & BASE_SELECTED) != select_flag)) { float screen_co[2]; if (ED_view3d_project_float_global( vc->ar, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) { - ED_base_object_select(base, select ? BA_SELECT : BA_DESELECT); + ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); changed = true; } } @@ -2805,43 +3254,54 @@ static bool object_circle_select(ViewContext *vc, const bool select, const int m static int view3d_circle_select_exec(bContext *C, wmOperator *op) { ViewContext vc; - ED_view3d_viewcontext_init(C, &vc); - Object *obact = vc.obact; - Object *obedit = vc.obedit; const int radius = RNA_int_get(op->ptr, "radius"); const bool select = !RNA_boolean_get(op->ptr, "deselect"); const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")}; + + ED_view3d_viewcontext_init(C, &vc); + + Object *obact = vc.obact; + Object *obedit = vc.obedit; + if (obedit || BKE_paint_select_elem_test(obact) || (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT | OB_MODE_POSE))) ) { view3d_operator_needs_opengl(C); - if (CTX_data_edit_object(C)) { - obedit_circle_select(&vc, select, mval, (float)radius); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); - } - else if (BKE_paint_select_face_test(obact)) { - paint_facesel_circle_select(&vc, select, mval, (float)radius); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); - } - else if (BKE_paint_select_vert_test(obact)) { - paint_vertsel_circle_select(&vc, select, mval, (float)radius); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); - } - else if (obact->mode & OB_MODE_POSE) { - pose_circle_select(&vc, select, mval, (float)radius); - } - else { - return PE_circle_select(C, select, mval, (float)radius); + FOREACH_OBJECT_IN_MODE_BEGIN (vc.view_layer, vc.v3d, obact->type, obact->mode, ob_iter) { + ED_view3d_viewcontext_init_object(&vc, ob_iter); + + obact = vc.obact; + obedit = vc.obedit; + + if (CTX_data_edit_object(C)) { + obedit_circle_select(&vc, select, mval, (float)radius); + DEG_id_tag_update(obact->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obact->data); + } + else if (BKE_paint_select_face_test(obact)) { + paint_facesel_circle_select(&vc, select, mval, (float)radius); + } + else if (BKE_paint_select_vert_test(obact)) { + paint_vertsel_circle_select(&vc, select, mval, (float)radius); + } + else if (obact->mode & OB_MODE_POSE) { + pose_circle_select(&vc, select, mval, (float)radius); + } + else { + return PE_circle_select(C, select, mval, (float)radius); + } } + FOREACH_OBJECT_IN_MODE_END; } else if (obact && obact->mode & OB_MODE_SCULPT) { return OPERATOR_CANCELLED; } else { if (object_circle_select(&vc, select, mval, (float)radius)) { + DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene); } } diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 80586217691..1bff52e7950 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -30,6 +30,8 @@ */ +#include "MEM_guardedalloc.h" + #include "DNA_armature_types.h" #include "DNA_object_types.h" @@ -40,13 +42,17 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" +#include "BKE_editmesh.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_tracking.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "WM_api.h" #include "WM_types.h" @@ -66,75 +72,96 @@ static bool snap_calc_active_center(bContext *C, const bool select_only, float r /* *********************** operators ******************** */ +/** Snaps every individual object center to its nearest point on the grid. **/ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); Object *obedit = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); - RegionView3D *rv3d = CTX_wm_region_data(C); + View3D *v3d = CTX_wm_view3d(C); TransVertStore tvs = {NULL}; TransVert *tv; float gridf, imat[3][3], bmat[3][3], vec[3]; int a; - gridf = rv3d->gridview; + gridf = ED_view3d_grid_scale(scene, v3d, NULL); if (obedit) { - if (ED_transverts_check_obedit(obedit)) - ED_transverts_create_from_obedit(&tvs, obedit, 0); - if (tvs.transverts_tot == 0) - return OPERATOR_CANCELLED; - - copy_m3_m4(bmat, obedit->obmat); - invert_m3_m3(imat, bmat); - - tv = tvs.transverts; - for (a = 0; a < tvs.transverts_tot; a++, tv++) { - copy_v3_v3(vec, tv->loc); - mul_m3_v3(bmat, vec); - add_v3_v3(vec, obedit->obmat[3]); - vec[0] = gridf * floorf(0.5f + vec[0] / gridf); - vec[1] = gridf * floorf(0.5f + vec[1] / gridf); - vec[2] = gridf * floorf(0.5f + vec[2] / gridf); - sub_v3_v3(vec, obedit->obmat[3]); - - mul_m3_v3(imat, vec); - copy_v3_v3(tv->loc, vec); - } + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + obedit = objects[ob_index]; - ED_transverts_update_obedit(&tvs, obedit); - ED_transverts_free(&tvs); + if (obedit->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totvertsel == 0) { + continue; + } + } + + if (ED_transverts_check_obedit(obedit)) { + ED_transverts_create_from_obedit(&tvs, obedit, 0); + } + + if (tvs.transverts_tot != 0) { + copy_m3_m4(bmat, obedit->obmat); + invert_m3_m3(imat, bmat); + + tv = tvs.transverts; + for (a = 0; a < tvs.transverts_tot; a++, tv++) { + copy_v3_v3(vec, tv->loc); + mul_m3_v3(bmat, vec); + add_v3_v3(vec, obedit->obmat[3]); + vec[0] = gridf * floorf(0.5f + vec[0] / gridf); + vec[1] = gridf * floorf(0.5f + vec[1] / gridf); + vec[2] = gridf * floorf(0.5f + vec[2] / gridf); + sub_v3_v3(vec, obedit->obmat[3]); + + mul_m3_v3(imat, vec); + copy_v3_v3(tv->loc, vec); + } + ED_transverts_update_obedit(&tvs, obedit); + } + ED_transverts_free(&tvs); + } + MEM_freeN(objects); } else { struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) + FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(view_layer_eval, v3d, ob_eval) { + Object *ob = DEG_get_original_object(ob_eval); if (ob->mode & OB_MODE_POSE) { - bPoseChannel *pchan; - bArmature *arm = ob->data; + bPoseChannel *pchan_eval; + bArmature *arm_eval = ob_eval->data; - invert_m4_m4(ob->imat, ob->obmat); + invert_m4_m4(ob_eval->imat, ob_eval->obmat); - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->flag & BONE_SELECTED) { - if (pchan->bone->layer & arm->layer) { - if ((pchan->bone->flag & BONE_CONNECTED) == 0) { + for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval; pchan_eval = pchan_eval->next) { + if (pchan_eval->bone->flag & BONE_SELECTED) { + if (pchan_eval->bone->layer & arm_eval->layer) { + if ((pchan_eval->bone->flag & BONE_CONNECTED) == 0) { float nLoc[3]; /* get nearest grid point to snap to */ - copy_v3_v3(nLoc, pchan->pose_mat[3]); + copy_v3_v3(nLoc, pchan_eval->pose_mat[3]); /* We must operate in world space! */ - mul_m4_v3(ob->obmat, nLoc); + mul_m4_v3(ob_eval->obmat, nLoc); vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf); vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf); vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf); /* Back in object space... */ - mul_m4_v3(ob->imat, vec); + mul_m4_v3(ob_eval->imat, vec); /* Get location of grid point in pose space. */ - BKE_armature_loc_pose_to_bone(pchan, vec, vec); + BKE_armature_loc_pose_to_bone(pchan_eval, vec, vec); - /* adjust location */ + /* adjust location on the original pchan*/ + bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, pchan_eval->name); if ((pchan->protectflag & OB_LOCK_LOCX) == 0) pchan->loc[0] = vec[0]; if ((pchan->protectflag & OB_LOCK_LOCY) == 0) @@ -153,34 +180,34 @@ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) } ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } else { - vec[0] = -ob->obmat[3][0] + gridf * floorf(0.5f + ob->obmat[3][0] / gridf); - vec[1] = -ob->obmat[3][1] + gridf * floorf(0.5f + ob->obmat[3][1] / gridf); - vec[2] = -ob->obmat[3][2] + gridf * floorf(0.5f + ob->obmat[3][2] / gridf); + vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf); + vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf); + vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf); if (ob->parent) { float originmat[3][3]; - BKE_object_where_is_calc_ex(scene, NULL, ob, originmat); + BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat); invert_m3_m3(imat, originmat); mul_m3_v3(imat, vec); } if ((ob->protectflag & OB_LOCK_LOCX) == 0) - ob->loc[0] += vec[0]; + ob->loc[0] = ob_eval->loc[0] + vec[0]; if ((ob->protectflag & OB_LOCK_LOCY) == 0) - ob->loc[1] += vec[1]; + ob->loc[1] = ob_eval->loc[1] + vec[1]; if ((ob->protectflag & OB_LOCK_LOCZ) == 0) - ob->loc[2] += vec[2]; + ob->loc[2] = ob_eval->loc[2] + vec[2]; /* auto-keyframing */ ED_autokeyframe_object(C, scene, ob, ks); - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } } - CTX_DATA_END; + FOREACH_SELECTED_EDITABLE_OBJECT_END; } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); @@ -192,7 +219,7 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Selection to Grid"; - ot->description = "Snap selected item(s) to nearest grid division"; + ot->description = "Snap selected item(s) to their nearest grid division"; ot->idname = "VIEW3D_OT_snap_selected_to_grid"; /* api callbacks */ @@ -200,13 +227,20 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot) ot->poll = ED_operator_region_view3d_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; } /* *************************************************** */ +/** Snaps the selection as a whole (use_offset=true) or each selected object to the given location. + * + * \param snap_target_global: a location in global space to snap to (eg. 3D cursor or active object). + * \param use_offset: if the selected objects should maintain their relative offsets and be snapped by the selection + * pivot point (median, active), or if every object origin should be snapped to the given location. +**/ static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); @@ -219,7 +253,7 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global int a; if (use_offset) { - if ((v3d && v3d->around == V3D_AROUND_ACTIVE) && + if ((v3d && scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) && snap_calc_active_center(C, true, center_global)) { /* pass */ @@ -232,104 +266,122 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global if (obedit) { float snap_target_local[3]; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + obedit = objects[ob_index]; - if (ED_transverts_check_obedit(obedit)) - ED_transverts_create_from_obedit(&tvs, obedit, 0); - if (tvs.transverts_tot == 0) - return OPERATOR_CANCELLED; + if (obedit->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); - copy_m3_m4(bmat, obedit->obmat); - invert_m3_m3(imat, bmat); + if (em->bm->totvertsel == 0) { + continue; + } + } - /* get the cursor in object space */ - sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]); - mul_m3_v3(imat, snap_target_local); + if (ED_transverts_check_obedit(obedit)) { + ED_transverts_create_from_obedit(&tvs, obedit, 0); + } - if (use_offset) { - float offset_local[3]; + if (tvs.transverts_tot != 0) { + copy_m3_m4(bmat, obedit->obmat); + invert_m3_m3(imat, bmat); - mul_v3_m3v3(offset_local, imat, offset_global); + /* get the cursor in object space */ + sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]); + mul_m3_v3(imat, snap_target_local); - tv = tvs.transverts; - for (a = 0; a < tvs.transverts_tot; a++, tv++) { - add_v3_v3(tv->loc, offset_local); - } - } - else { - tv = tvs.transverts; - for (a = 0; a < tvs.transverts_tot; a++, tv++) { - copy_v3_v3(tv->loc, snap_target_local); + if (use_offset) { + float offset_local[3]; + + mul_v3_m3v3(offset_local, imat, offset_global); + + tv = tvs.transverts; + for (a = 0; a < tvs.transverts_tot; a++, tv++) { + add_v3_v3(tv->loc, offset_local); + } + } + else { + tv = tvs.transverts; + for (a = 0; a < tvs.transverts_tot; a++, tv++) { + copy_v3_v3(tv->loc, snap_target_local); + } + } + ED_transverts_update_obedit(&tvs, obedit); } + ED_transverts_free(&tvs); } - - ED_transverts_update_obedit(&tvs, obedit); - ED_transverts_free(&tvs); + MEM_freeN(objects); } else if (obact && (obact->mode & OB_MODE_POSE)) { struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); - - bPoseChannel *pchan; - bArmature *arm = obact->data; - float snap_target_local[3]; - - invert_m4_m4(obact->imat, obact->obmat); - mul_v3_m4v3(snap_target_local, obact->imat, snap_target_global); - - for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { - if ((pchan->bone->flag & BONE_SELECTED) && - (PBONE_VISIBLE(arm, pchan->bone)) && - /* if the bone has a parent and is connected to the parent, - * don't do anything - will break chain unless we do auto-ik. - */ - (pchan->bone->flag & BONE_CONNECTED) == 0) - { - pchan->bone->flag |= BONE_TRANSFORM; - } - else { - pchan->bone->flag &= ~BONE_TRANSFORM; - } - } - - for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { - if ((pchan->bone->flag & BONE_TRANSFORM) && - /* check that our parents not transformed (if we have one) */ - ((pchan->bone->parent && - BKE_armature_bone_flag_test_recursive(pchan->bone->parent, BONE_TRANSFORM)) == 0)) - { - /* Get position in pchan (pose) space. */ - float cursor_pose[3]; - - if (use_offset) { - mul_v3_m4v3(cursor_pose, obact->obmat, pchan->pose_mat[3]); - add_v3_v3(cursor_pose, offset_global); - - mul_m4_v3(obact->imat, cursor_pose); - BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose); + CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) + { + bPoseChannel *pchan; + bArmature *arm = ob->data; + float snap_target_local[3]; + + invert_m4_m4(ob->imat, ob->obmat); + mul_v3_m4v3(snap_target_local, ob->imat, snap_target_global); + + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if ((pchan->bone->flag & BONE_SELECTED) && + (PBONE_VISIBLE(arm, pchan->bone)) && + /* if the bone has a parent and is connected to the parent, + * don't do anything - will break chain unless we do auto-ik. + */ + (pchan->bone->flag & BONE_CONNECTED) == 0) + { + pchan->bone->flag |= BONE_TRANSFORM; } else { - BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose); + pchan->bone->flag &= ~BONE_TRANSFORM; } + } - /* copy new position */ - if ((pchan->protectflag & OB_LOCK_LOCX) == 0) - pchan->loc[0] = cursor_pose[0]; - if ((pchan->protectflag & OB_LOCK_LOCY) == 0) - pchan->loc[1] = cursor_pose[1]; - if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) - pchan->loc[2] = cursor_pose[2]; + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if ((pchan->bone->flag & BONE_TRANSFORM) && + /* check that our parents not transformed (if we have one) */ + ((pchan->bone->parent && + BKE_armature_bone_flag_test_recursive(pchan->bone->parent, BONE_TRANSFORM)) == 0)) + { + /* Get position in pchan (pose) space. */ + float cursor_pose[3]; + + if (use_offset) { + mul_v3_m4v3(cursor_pose, ob->obmat, pchan->pose_mat[3]); + add_v3_v3(cursor_pose, offset_global); + + mul_m4_v3(ob->imat, cursor_pose); + BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose); + } + else { + BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose); + } - /* auto-keyframing */ - ED_autokeyframe_pchan(C, scene, obact, pchan, ks); + /* copy new position */ + if ((pchan->protectflag & OB_LOCK_LOCX) == 0) + pchan->loc[0] = cursor_pose[0]; + if ((pchan->protectflag & OB_LOCK_LOCY) == 0) + pchan->loc[1] = cursor_pose[1]; + if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) + pchan->loc[2] = cursor_pose[2]; + + /* auto-keyframing */ + ED_autokeyframe_pchan(C, scene, ob, pchan, ks); + } } - } - for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { - pchan->bone->flag &= ~BONE_TRANSFORM; - } + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + pchan->bone->flag &= ~BONE_TRANSFORM; + } - obact->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK); + ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK); - DAG_id_tag_update(&obact->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + CTX_DATA_END; } else { struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID); @@ -370,7 +422,7 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global if (ob->parent) { float originmat[3][3]; - BKE_object_where_is_calc_ex(scene, NULL, ob, originmat); + BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat); invert_m3_m3(imat, originmat); mul_m3_v3(imat, cursor_parent); @@ -385,7 +437,7 @@ static int snap_selected_to_location(bContext *C, const float snap_target_global /* auto-keyframing */ ED_autokeyframe_object(C, scene, ob, ks); - DAG_id_tag_update(&ob->id, OB_RECALC_OB); + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } } @@ -402,9 +454,8 @@ static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op) const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - const float *snap_target_global = ED_view3d_cursor3d_get(scene, v3d); + const float *snap_target_global = scene->cursor.location; return snap_selected_to_location(C, snap_target_global, use_offset); } @@ -413,7 +464,7 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Selection to Cursor"; - ot->description = "Snap selected item(s) to cursor"; + ot->description = "Snap selected item(s) to the 3D cursor"; ot->idname = "VIEW3D_OT_snap_selected_to_cursor"; /* api callbacks */ @@ -421,12 +472,16 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; /* rna */ - RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", ""); + RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", + "If the selection should be snapped as a whole or by each object center"); } +/* *************************************************** */ + +/** Snaps each selected object to the location of the active selected object. **/ static int snap_selected_to_active_exec(bContext *C, wmOperator *op) { float snap_target_global[3]; @@ -451,27 +506,28 @@ void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; } /* *************************************************** */ +/** Snaps the 3D cursor location to its nearest point on the grid. **/ static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - RegionView3D *rv3d = CTX_wm_region_data(C); View3D *v3d = CTX_wm_view3d(C); float gridf, *curs; - gridf = rv3d->gridview; - curs = ED_view3d_cursor3d_get(scene, v3d); + gridf = ED_view3d_grid_scale(scene, v3d, NULL); + curs = scene->cursor.location; curs[0] = gridf * floorf(0.5f + curs[0] / gridf); curs[1] = gridf * floorf(0.5f + curs[1] / gridf); curs[2] = gridf * floorf(0.5f + curs[2] / gridf); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); /* hrm */ + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -480,7 +536,7 @@ void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Cursor to Grid"; - ot->description = "Snap cursor to nearest grid division"; + ot->description = "Snap 3D cursor to the nearest grid division"; ot->idname = "VIEW3D_OT_snap_cursor_to_grid"; /* api callbacks */ @@ -493,7 +549,8 @@ void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot) /* **************************************************** */ -static void bundle_midpoint(Scene *scene, Object *ob, float vec[3]) +/** Returns the center position of a tracking marker visible on the viewport (useful to snap to). **/ +static void bundle_midpoint(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_vec[3]) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); MovieTracking *tracking; @@ -508,7 +565,7 @@ static void bundle_midpoint(Scene *scene, Object *ob, float vec[3]) copy_m4_m4(cammat, ob->obmat); - BKE_tracking_get_camera_object_matrix(scene, ob, mat); + BKE_tracking_get_camera_object_matrix(depsgraph, scene, ob, mat); INIT_MINMAX(min, max); @@ -541,12 +598,15 @@ static void bundle_midpoint(Scene *scene, Object *ob, float vec[3]) } if (ok) { - mid_v3_v3v3(vec, min, max); + mid_v3_v3v3(r_vec, min, max); } } +/** Snaps the 3D cursor location to the median point of the selection. **/ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); Object *obedit = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -560,46 +620,64 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) zero_v3(centroid); if (obedit) { + int global_transverts_tot = 0; + ViewLayer *view_layer = CTX_data_view_layer(C); + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + obedit = objects[ob_index]; + + /* We can do that quick check for meshes only... */ + if (obedit->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (em->bm->totvertsel == 0) { + continue; + } + } - if (ED_transverts_check_obedit(obedit)) - ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES); - - if (tvs.transverts_tot == 0) { - return false; - } - - copy_m3_m4(bmat, obedit->obmat); + if (ED_transverts_check_obedit(obedit)) { + ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES); + } - tv = tvs.transverts; - for (a = 0; a < tvs.transverts_tot; a++, tv++) { - copy_v3_v3(vec, tv->loc); - mul_m3_v3(bmat, vec); - add_v3_v3(vec, obedit->obmat[3]); - add_v3_v3(centroid, vec); - minmax_v3v3_v3(min, max, vec); + global_transverts_tot += tvs.transverts_tot; + if (tvs.transverts_tot != 0) { + Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); + copy_m3_m4(bmat, obedit_eval->obmat); + + tv = tvs.transverts; + for (a = 0; a < tvs.transverts_tot; a++, tv++) { + copy_v3_v3(vec, tv->loc); + mul_m3_v3(bmat, vec); + add_v3_v3(vec, obedit_eval->obmat[3]); + add_v3_v3(centroid, vec); + minmax_v3v3_v3(min, max, vec); + } + } + ED_transverts_free(&tvs); } + MEM_freeN(objects); - if (v3d->around == V3D_AROUND_CENTER_MEAN) { - mul_v3_fl(centroid, 1.0f / (float)tvs.transverts_tot); + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEAN) { + mul_v3_fl(centroid, 1.0f / (float)global_transverts_tot); copy_v3_v3(cursor, centroid); } else { mid_v3_v3v3(cursor, min, max); } - - ED_transverts_free(&tvs); } else { Object *obact = CTX_data_active_object(C); if (obact && (obact->mode & OB_MODE_POSE)) { - bArmature *arm = obact->data; + Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact); + bArmature *arm = obact_eval->data; bPoseChannel *pchan; - for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { + for (pchan = obact_eval->pose->chanbase.first; pchan; pchan = pchan->next) { if (arm->layer & pchan->bone->layer) { if (pchan->bone->flag & BONE_SELECTED) { copy_v3_v3(vec, pchan->pose_head); - mul_m4_v3(obact->obmat, vec); + mul_m4_v3(obact_eval->obmat, vec); add_v3_v3(centroid, vec); minmax_v3v3_v3(min, max, vec); count++; @@ -608,15 +686,15 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) } } else { - CTX_DATA_BEGIN (C, Object *, ob, selected_objects) + FOREACH_SELECTED_OBJECT_BEGIN(view_layer_eval, v3d, ob_eval) { - copy_v3_v3(vec, ob->obmat[3]); + copy_v3_v3(vec, ob_eval->obmat[3]); /* special case for camera -- snap to bundles */ - if (ob->type == OB_CAMERA) { + if (ob_eval->type == OB_CAMERA) { /* snap to bundles should happen only when bundles are visible */ if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) { - bundle_midpoint(scene, ob, vec); + bundle_midpoint(depsgraph, scene, DEG_get_original_object(ob_eval), vec); } } @@ -624,14 +702,14 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) minmax_v3v3_v3(min, max, vec); count++; } - CTX_DATA_END; + FOREACH_SELECTED_OBJECT_END; } if (count == 0) { return false; } - if (v3d->around == V3D_AROUND_CENTER_MEAN) { + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEAN) { mul_v3_fl(centroid, 1.0f / (float)count); copy_v3_v3(cursor, centroid); } @@ -645,13 +723,9 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) static int snap_curs_to_sel_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - float *curs; - - curs = ED_view3d_cursor3d_get(scene, v3d); - - if (snap_curs_to_sel_ex(C, curs)) { - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + if (snap_curs_to_sel_ex(C, scene->cursor.location)) { + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -664,7 +738,7 @@ void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Cursor to Selected"; - ot->description = "Snap cursor to center of selected item(s)"; + ot->description = "Snap 3D cursor to the middle of the selected item(s)"; ot->idname = "VIEW3D_OT_snap_cursor_to_selected"; /* api callbacks */ @@ -672,16 +746,19 @@ void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; } /* ********************************************** */ -/* this could be exported to be a generic function - * see: calculateCenterActive */ - +/** Calculates the center position of the active object in global space. + * + * Note: this could be exported to be a generic function. + * see: calculateCenterActive +**/ static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3]) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); Object *obedit = CTX_data_edit_object(C); if (obedit) { @@ -692,21 +769,23 @@ static bool snap_calc_active_center(bContext *C, const bool select_only, float r } else { Object *ob = CTX_data_active_object(C); - if (ob) { + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + if (ob->mode & OB_MODE_POSE) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active(ob_eval); if (pchan) { if (!select_only || (pchan->bone->flag & BONE_SELECTED)) { copy_v3_v3(r_center, pchan->pose_head); - mul_m4_v3(ob->obmat, r_center); + mul_m4_v3(ob_eval->obmat, r_center); return true; } } } else { - if (!select_only || (ob->flag & SELECT)) { - copy_v3_v3(r_center, ob->obmat[3]); + + if (!select_only || (ob_eval->flag & SELECT)) { + copy_v3_v3(r_center, ob_eval->obmat[3]); return true; } } @@ -720,12 +799,11 @@ static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); - float *curs; - - curs = ED_view3d_cursor3d_get(scene, v3d); - if (snap_calc_active_center(C, false, curs)) { + if (snap_calc_active_center(C, false, scene->cursor.location)) { WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + return OPERATOR_FINISHED; } else { @@ -737,7 +815,7 @@ void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Cursor to Active"; - ot->description = "Snap cursor to active item"; + ot->description = "Snap 3D cursor to the active item"; ot->idname = "VIEW3D_OT_snap_cursor_to_active"; /* api callbacks */ @@ -745,30 +823,29 @@ void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA; } /* **************************************************** */ -/*New Code - Snap Cursor to Center -*/ + +/** Snaps the 3D cursor location to the origin. **/ static int snap_curs_to_center_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - float *curs; - curs = ED_view3d_cursor3d_get(scene, v3d); - zero_v3(curs); + zero_v3(scene->cursor.location); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); return OPERATOR_FINISHED; } void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot) { /* identifiers */ - ot->name = "Snap Cursor to Center"; - ot->description = "Snap cursor to the Center"; + ot->name = "Snap Cursor to World Origin"; + ot->description = "Snap 3D cursor to the world origin"; ot->idname = "VIEW3D_OT_snap_cursor_to_center"; /* api callbacks */ @@ -781,23 +858,22 @@ void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot) /* **************************************************** */ - -bool ED_view3d_minmax_verts(Object *obedit, float min[3], float max[3]) +/** Calculates the bounding box corners (min and max) for \a obedit. The returned values are in global space. **/ +bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3]) { TransVertStore tvs = {NULL}; TransVert *tv; float centroid[3], vec[3], bmat[3][3]; - int a; - /* metaballs are an exception */ + /* Metaballs are an exception. */ if (obedit->type == OB_MBALL) { float ob_min[3], ob_max[3]; bool changed; changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT); if (changed) { - minmax_v3v3_v3(min, max, ob_min); - minmax_v3v3_v3(min, max, ob_max); + minmax_v3v3_v3(r_min, r_max, ob_min); + minmax_v3v3_v3(r_min, r_max, ob_max); } return changed; } @@ -811,12 +887,12 @@ bool ED_view3d_minmax_verts(Object *obedit, float min[3], float max[3]) copy_m3_m4(bmat, obedit->obmat); tv = tvs.transverts; - for (a = 0; a < tvs.transverts_tot; a++, tv++) { + for (int a = 0; a < tvs.transverts_tot; a++, tv++) { copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc); mul_m3_v3(bmat, vec); add_v3_v3(vec, obedit->obmat[3]); add_v3_v3(centroid, vec); - minmax_v3v3_v3(min, max, vec); + minmax_v3v3_v3(r_min, r_max, vec); } ED_transverts_free(&tvs); diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index 76697a02270..707e0e7a394 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -28,231 +28,24 @@ * \ingroup spview3d */ - #include <string.h> #include <stdio.h> #include <math.h> #include <float.h> -#include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "BLI_ghash.h" - -#include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_screen.h" - #include "WM_api.h" #include "WM_types.h" -#include "RNA_access.h" - #include "ED_screen.h" -#include "ED_undo.h" - -#include "UI_interface.h" -#include "UI_resources.h" #include "view3d_intern.h" /* own include */ - -/* ******************* view3d space & buttons ************** */ - -static void view3d_panel_operator_redo_buts(const bContext *C, Panel *pa, wmOperator *op) -{ - uiTemplateOperatorPropertyButs(C, pa->layout, op, 'V', 0); -} - -static void view3d_panel_operator_redo_header(const bContext *C, Panel *pa) -{ - wmOperator *op = WM_operator_last_redo(C); - - if (op) - BLI_strncpy(pa->drawname, RNA_struct_ui_name(op->type->srna), sizeof(pa->drawname)); - else - BLI_strncpy(pa->drawname, IFACE_("Operator"), sizeof(pa->drawname)); -} - -static void view3d_panel_operator_redo_operator(const bContext *C, Panel *pa, wmOperator *op) -{ - if (op->type->flag & OPTYPE_MACRO) { - for (op = op->macro.first; op; op = op->next) { - uiItemL(pa->layout, RNA_struct_ui_name(op->type->srna), ICON_NONE); - view3d_panel_operator_redo_operator(C, pa, op); - } - } - else { - view3d_panel_operator_redo_buts(C, pa, op); - } -} - -/* TODO de-duplicate redo panel functions - campbell */ -static void view3d_panel_operator_redo(const bContext *C, Panel *pa) -{ - wmOperator *op = WM_operator_last_redo(C); - ARegion *ar; - ARegion *ar1; - - if (op == NULL) { - return; - } - - /* keep in sync with logic in ED_undo_operator_repeat() */ - ar = CTX_wm_region(C); - ar1 = BKE_area_find_region_active_win(CTX_wm_area(C)); - if (ar1) - CTX_wm_region_set((bContext *)C, ar1); - - if (WM_operator_poll((bContext *)C, op->type)) { - uiBlock *block = uiLayoutGetBlock(pa->layout); - - if (!WM_operator_check_ui_enabled(C, op->type->name)) - uiLayoutSetEnabled(pa->layout, false); - - /* note, blockfunc is a default but->func, use Handle func to allow button callbacks too */ - UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op); - - view3d_panel_operator_redo_operator(C, pa, op); - } - - /* set region back */ - CTX_wm_region_set((bContext *)C, ar); -} - -/* ******************* */ - -typedef struct CustomTool { - struct CustomTool *next, *prev; - char opname[OP_MAX_TYPENAME]; - char context[OP_MAX_TYPENAME]; -} CustomTool; - -static void operator_call_cb(struct bContext *C, void *arg_listbase, void *arg2) -{ - wmOperatorType *ot = arg2; - - if (ot) { - CustomTool *ct = MEM_callocN(sizeof(CustomTool), "CustomTool"); - - BLI_addtail(arg_listbase, ct); - BLI_strncpy(ct->opname, ot->idname, OP_MAX_TYPENAME); - BLI_strncpy(ct->context, CTX_data_mode_string(C), OP_MAX_TYPENAME); - } - -} - -static void operator_search_cb(const struct bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items) -{ - GHashIterator iter; - - for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); - - if (BLI_strcasestr(ot->name, str)) { - if (WM_operator_poll((bContext *)C, ot)) { - - if (false == UI_search_item_add(items, ot->name, ot, 0)) - break; - } - } - } -} - - -/* ID Search browse menu, open */ -static uiBlock *tool_search_menu(bContext *C, ARegion *ar, void *arg_listbase) -{ - static char search[OP_MAX_TYPENAME]; - wmEvent event; - wmWindow *win = CTX_wm_window(C); - uiBlock *block; - uiBut *but; - - /* clear initial search string, then all items show */ - search[0] = 0; - - block = UI_block_begin(C, ar, "_popup", UI_EMBOSS); - UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_SEARCH_MENU); - UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); - - /* fake button, it holds space for search items */ - uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 15, UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL); - - but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 0, 150, 19, 0, 0, ""); - UI_but_func_search_set(but, NULL, operator_search_cb, arg_listbase, operator_call_cb, NULL); - - UI_block_bounds_set_normal(block, 6); - UI_block_direction_set(block, UI_DIR_DOWN); - UI_block_end(C, block); - - wm_event_init_from_window(win, &event); - event.type = EVT_BUT_OPEN; - event.val = KM_PRESS; - event.customdata = but; - event.customdatafree = false; - wm_event_add(win, &event); - - return block; -} - - -static void view3d_panel_tool_shelf(const bContext *C, Panel *pa) -{ - SpaceLink *sl = CTX_wm_space_data(C); - SpaceType *st = NULL; - uiLayout *col; - const char *context = CTX_data_mode_string(C); - - if (sl) - st = BKE_spacetype_from_id(sl->spacetype); - - if (st && st->toolshelf.first) { - CustomTool *ct; - - for (ct = st->toolshelf.first; ct; ct = ct->next) { - if (STREQLEN(context, ct->context, OP_MAX_TYPENAME)) { - col = uiLayoutColumn(pa->layout, true); - uiItemFullO(col, ct->opname, NULL, ICON_NONE, NULL, WM_OP_INVOKE_REGION_WIN, 0, NULL); - } - } - } - col = uiLayoutColumn(pa->layout, true); - uiDefBlockBut(uiLayoutGetBlock(pa->layout), tool_search_menu, &st->toolshelf, "Add Tool", 0, 0, UI_UNIT_X, UI_UNIT_Y, "Add Tool in shelf, gets saved in files"); -} - - -void view3d_toolshelf_register(ARegionType *art) -{ - PanelType *pt; - - pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel tools"); - strcpy(pt->idname, "VIEW3D_PT_tool_shelf"); - strcpy(pt->label, N_("Tool Shelf")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw = view3d_panel_tool_shelf; - BLI_addtail(&art->paneltypes, pt); -} - -void view3d_tool_props_register(ARegionType *art) -{ - PanelType *pt; - - pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel last operator"); - strcpy(pt->idname, "VIEW3D_PT_last_operator"); - strcpy(pt->label, N_("Operator")); - strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); - pt->draw_header = view3d_panel_operator_redo_header; - pt->draw = view3d_panel_operator_redo; - BLI_addtail(&art->paneltypes, pt); -} - /* ********** operator to open/close toolshelf region */ static int view3d_toolshelf_toggle_exec(bContext *C, wmOperator *UNUSED(op)) @@ -268,7 +61,7 @@ static int view3d_toolshelf_toggle_exec(bContext *C, wmOperator *UNUSED(op)) void VIEW3D_OT_toolshelf(wmOperatorType *ot) { - ot->name = "Tool Shelf"; + ot->name = "Toggle Toolbar"; ot->description = "Toggles tool shelf display"; ot->idname = "VIEW3D_OT_toolshelf"; diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 90da960ada8..87f2e6b32d4 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -36,6 +36,7 @@ #include "DNA_curve_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_world_types.h" #include "MEM_guardedalloc.h" @@ -46,14 +47,18 @@ #include "BKE_camera.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" /* for ED_view3d_camera_lock_sync */ #include "BKE_main.h" #include "BKE_object.h" #include "BKE_screen.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_matrix.h" + #include "WM_api.h" #include "WM_types.h" @@ -61,6 +66,8 @@ #include "ED_screen.h" #include "ED_view3d.h" +#include "UI_resources.h" + #include "view3d_intern.h" /* own include */ /* -------------------------------------------------------------------- */ @@ -68,10 +75,33 @@ * * \{ */ -float *ED_view3d_cursor3d_get(Scene *scene, View3D *v3d) +void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float r_color[3]) { - if (v3d && v3d->localvd) return v3d->cursor; - else return scene->cursor; + switch (v3d->shading.background_type) { + case V3D_SHADING_BACKGROUND_WORLD: + copy_v3_v3(r_color, &scene->world->horr); + break; + case V3D_SHADING_BACKGROUND_VIEWPORT: + copy_v3_v3(r_color, v3d->shading.background_color); + break; + case V3D_SHADING_BACKGROUND_THEME: + default: + UI_GetThemeColor3fv(TH_HIGH_GRAD, r_color); + break; + } +} + +void ED_view3d_cursor3d_calc_mat3(const Scene *scene, float mat[3][3]) +{ + const View3DCursor *cursor = &scene->cursor; + quat_to_mat3(mat, cursor->rotation); +} + +void ED_view3d_cursor3d_calc_mat4(const Scene *scene, float mat[4][4]) +{ + const View3DCursor *cursor = &scene->cursor; + quat_to_mat4(mat, cursor->rotation); + copy_v3_v3(mat[3], cursor->location); } Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d) @@ -97,6 +127,7 @@ void ED_view3d_dist_range_get( * \note copies logic of #ED_view3d_viewplane_get(), keep in sync. */ bool ED_view3d_clip_range_get( + Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d, float *r_clipsta, float *r_clipend, const bool use_ortho_factor) @@ -104,7 +135,7 @@ bool ED_view3d_clip_range_get( CameraParams params; BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, v3d, rv3d); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); if (use_ortho_factor && params.is_ortho) { const float fac = 2.0f / (params.clipend - params.clipsta); @@ -119,13 +150,14 @@ bool ED_view3d_clip_range_get( } bool ED_view3d_viewplane_get( + Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d, int winx, int winy, rctf *r_viewplane, float *r_clipsta, float *r_clipend, float *r_pixsize) { CameraParams params; BKE_camera_params_init(¶ms); - BKE_camera_params_from_view3d(¶ms, v3d, rv3d); + BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, rv3d); BKE_camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f); if (r_viewplane) *r_viewplane = params.viewplane; @@ -156,7 +188,7 @@ void view3d_operator_needs_opengl(const bContext *C) view3d_region_operator_needs_opengl(win, ar); } -void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) +void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *ar) { /* for debugging purpose, context should always be OK */ if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) { @@ -165,11 +197,9 @@ void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) else { RegionView3D *rv3d = ar->regiondata; - wmSubWindowSet(win, ar->swinid); - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(rv3d->winmat); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(rv3d->viewmat); + wmViewport(&ar->winrct); // TODO: bad + GPU_matrix_projection_set(rv3d->winmat); + GPU_matrix_set(rv3d->viewmat); } } @@ -231,6 +261,7 @@ bool ED_view3d_context_activate(bContext *C) /** \name View Clipping Utilities * * \{ */ + void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) { int val; @@ -245,40 +276,35 @@ void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, } } -void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, const rcti *rect) +void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], const ARegion *ar, const Object *ob, const rcti *rect) { - float modelview[4][4]; - double xs, ys, p[3]; - int val, flip_sign, a; - - /* near zero floating point values can give issues with gluUnProject - * in side view on some implementations */ - if (fabs(mats->modelview[0]) < 1e-6) mats->modelview[0] = 0.0; - if (fabs(mats->modelview[5]) < 1e-6) mats->modelview[5] = 0.0; - - /* Set up viewport so that gluUnProject will give correct values */ - mats->viewport[0] = 0; - mats->viewport[1] = 0; + /* init in case unproject fails */ + memset(bb->vec, 0, sizeof(bb->vec)); /* four clipping planes and bounding volume */ /* first do the bounding volume */ - for (val = 0; val < 4; val++) { - xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax; - ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax; + for (int val = 0; val < 4; val++) { + float xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax; + float ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax; + + ED_view3d_unproject(ar, xs, ys, 0.0, bb->vec[val]); + ED_view3d_unproject(ar, xs, ys, 1.0, bb->vec[4 + val]); + } - gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]); - copy_v3fl_v3db(bb->vec[val], p); + /* optionally transform to object space */ + if (ob) { + float imat[4][4]; + invert_m4_m4(imat, ob->obmat); - gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]); - copy_v3fl_v3db(bb->vec[4 + val], p); + for (int val = 0; val < 8; val++) { + mul_m4_v3(imat, bb->vec[val]); + } } /* verify if we have negative scale. doing the transform before cross * product flips the sign of the vector compared to doing cross product * before transform then, so we correct for that. */ - for (a = 0; a < 16; a++) - ((float *)modelview)[a] = mats->modelview[a]; - flip_sign = is_negative_m4(modelview); + int flip_sign = (ob) ? is_negative_m4(ob->obmat) : false; ED_view3d_clipping_calc_from_boundbox(planes, bb, flip_sign); } @@ -379,14 +405,15 @@ void ED_view3d_lock_clear(View3D *v3d) * sets the ``ofs`` and ``dist`` values of the viewport so it matches the camera, * otherwise switching out of camera view may jump to a different part of the scene. */ -void ED_view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const char persp) +void ED_view3d_persp_switch_from_camera(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, const char persp) { BLI_assert(rv3d->persp == RV3D_CAMOB); BLI_assert(persp != RV3D_CAMOB); if (v3d->camera) { - rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); - ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera); + rv3d->dist = ED_view3d_offset_distance(ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); } if (!ED_view3d_camera_lock_check(v3d, rv3d)) { @@ -399,7 +426,7 @@ void ED_view3d_persp_switch_from_camera(View3D *v3d, RegionView3D *rv3d, const c * * shared with NDOF. */ -bool ED_view3d_persp_ensure(struct View3D *v3d, ARegion *ar) +bool ED_view3d_persp_ensure(const Depsgraph *depsgraph, View3D *v3d, ARegion *ar) { RegionView3D *rv3d = ar->regiondata; const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0; @@ -413,7 +440,7 @@ bool ED_view3d_persp_ensure(struct View3D *v3d, ARegion *ar) if (rv3d->persp == RV3D_CAMOB) { /* If autopersp and previous view was an axis one, switch back to PERSP mode, else reuse previous mode. */ char persp = (autopersp && RV3D_VIEW_IS_AXIS(rv3d->lview)) ? RV3D_PERSP : rv3d->lpersp; - ED_view3d_persp_switch_from_camera(v3d, rv3d, persp); + ED_view3d_persp_switch_from_camera(depsgraph, v3d, rv3d, persp); } else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) { rv3d->persp = RV3D_PERSP; @@ -447,20 +474,21 @@ bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) * Apply the camera object transformation to the view-port. * (needed so we can use regular view-port manipulation operators, that sync back to the camera). */ -void ED_view3d_camera_lock_init_ex(View3D *v3d, RegionView3D *rv3d, const bool calc_dist) +void ED_view3d_camera_lock_init_ex(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d, const bool calc_dist) { if (ED_view3d_camera_lock_check(v3d, rv3d)) { + Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera); if (calc_dist) { /* using a fallback dist is OK here since ED_view3d_from_object() compensates for it */ - rv3d->dist = ED_view3d_offset_distance(v3d->camera->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); + rv3d->dist = ED_view3d_offset_distance(ob_camera_eval->obmat, rv3d->ofs, VIEW3D_DIST_FALLBACK); } - ED_view3d_from_object(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); + ED_view3d_from_object(ob_camera_eval, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL); } } -void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d) +void ED_view3d_camera_lock_init(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d) { - ED_view3d_camera_lock_init_ex(v3d, rv3d, true); + ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, true); } /** @@ -468,7 +496,7 @@ void ED_view3d_camera_lock_init(View3D *v3d, RegionView3D *rv3d) * * \return true if the camera is moved. */ -bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) +bool ED_view3d_camera_lock_sync(const Depsgraph *depsgraph, View3D *v3d, RegionView3D *rv3d) { if (ED_view3d_camera_lock_check(v3d, rv3d)) { ObjectTfmProtectedChannels obtfm; @@ -485,15 +513,17 @@ bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) while (root_parent->parent) { root_parent = root_parent->parent; } + Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera); + Object *root_parent_eval = DEG_get_evaluated_object(depsgraph, root_parent); ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); - normalize_m4_m4(tmat, v3d->camera->obmat); + normalize_m4_m4(tmat, ob_camera_eval->obmat); invert_m4_m4(imat, tmat); mul_m4_m4m4(diff_mat, view_mat, imat); - mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat); + mul_m4_m4m4(parent_mat, diff_mat, root_parent_eval->obmat); BKE_object_tfm_protected_backup(root_parent, &obtfm); BKE_object_apply_mat4(root_parent, parent_mat, true, false); @@ -501,7 +531,7 @@ bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) ob_update = v3d->camera; while (ob_update) { - DAG_id_tag_update(&ob_update->id, OB_RECALC_OB); + DEG_id_tag_update(&ob_update->id, ID_RECALC_TRANSFORM); WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, ob_update); ob_update = ob_update->parent; } @@ -510,10 +540,10 @@ bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) /* always maintain the same scale */ const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ); BKE_object_tfm_protected_backup(v3d->camera, &obtfm); - ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); + ED_view3d_to_object(depsgraph, v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all); - DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); + DEG_id_tag_update(&v3d->camera->id, ID_RECALC_TRANSFORM); WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera); } @@ -594,6 +624,7 @@ bool ED_view3d_camera_lock_autokey( /** \} */ + /* -------------------------------------------------------------------- */ /** \name Box View Support * @@ -878,22 +909,17 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg * \param fallback_depth_pt: Use this points depth when no depth can be found. */ bool ED_view3d_autodist( - Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, + Depsgraph *depsgraph, ARegion *ar, View3D *v3d, const int mval[2], float mouse_worldloc[3], const bool alphaoverride, const float fallback_depth_pt[3]) { - bglMats mats; /* ZBuffer depth vars */ float depth_close; - double cent[2], p[3]; int margin_arr[] = {0, 2, 4}; int i; bool depth_ok = false; /* Get Z Depths, needed for perspective, nice for ortho */ - ED_view3d_draw_depth(bmain, scene, ar, v3d, alphaoverride); - - /* call after in case settings have been modified since last drawing, see: T47089 */ - bgl_get_mats(&mats); + ED_view3d_draw_depth(depsgraph, ar, v3d, alphaoverride); /* Attempt with low margin's first */ i = 0; @@ -903,15 +929,10 @@ bool ED_view3d_autodist( } while ((depth_ok == false) && (i < ARRAY_SIZE(margin_arr))); if (depth_ok) { - cent[0] = (double)mval[0] + 0.5; - cent[1] = (double)mval[1] + 0.5; + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; - if (gluUnProject(cent[0], cent[1], depth_close, - mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) - { - mouse_worldloc[0] = (float)p[0]; - mouse_worldloc[1] = (float)p[1]; - mouse_worldloc[2] = (float)p[2]; + if (ED_view3d_unproject(ar, centx, centy, depth_close, mouse_worldloc)) { return true; } } @@ -925,27 +946,28 @@ bool ED_view3d_autodist( } } -void ED_view3d_autodist_init(Main *bmain, Scene *scene, ARegion *ar, View3D *v3d, int mode) +void ED_view3d_autodist_init(Depsgraph *depsgraph, + ARegion *ar, View3D *v3d, int mode) { /* Get Z Depths, needed for perspective, nice for ortho */ switch (mode) { case 0: - ED_view3d_draw_depth(bmain, scene, ar, v3d, true); + ED_view3d_draw_depth(depsgraph, ar, v3d, true); break; case 1: - ED_view3d_draw_depth_gpencil(scene, ar, v3d); + { + Scene *scene = DEG_get_evaluated_scene(depsgraph); + ED_view3d_draw_depth_gpencil(depsgraph, scene, ar, v3d); break; + } } } /* no 4x4 sampling, run #ED_view3d_autodist_init first */ -bool ED_view3d_autodist_simple( - ARegion *ar, const int mval[2], float mouse_worldloc[3], - int margin, float *force_depth) +bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3], + int margin, float *force_depth) { - bglMats mats; /* ZBuffer depth vars, could cache? */ float depth; - double cent[2], p[3]; /* Get Z Depths, needed for perspective, nice for ortho */ if (force_depth) @@ -956,21 +978,9 @@ bool ED_view3d_autodist_simple( if (depth == FLT_MAX) return false; - cent[0] = (double)mval[0] + 0.5; - cent[1] = (double)mval[1] + 0.5; - - bgl_get_mats(&mats); - - if (!gluUnProject(cent[0], cent[1], depth, - mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) - { - return false; - } - - mouse_worldloc[0] = (float)p[0]; - mouse_worldloc[1] = (float)p[1]; - mouse_worldloc[2] = (float)p[2]; - return true; + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + return ED_view3d_unproject(ar, centx, centy, depth, mouse_worldloc); } bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth) @@ -1066,6 +1076,7 @@ float ED_view3d_radius_to_dist_ortho(const float lens, const float radius) */ float ED_view3d_radius_to_dist( const View3D *v3d, const ARegion *ar, + const struct Depsgraph *depsgraph, const char persp, const bool use_aspect, const float radius) { @@ -1086,7 +1097,8 @@ float ED_view3d_radius_to_dist( BKE_camera_params_init(¶ms); params.clipsta = v3d->near; params.clipend = v3d->far; - BKE_camera_params_from_object(¶ms, v3d->camera); + Object *camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera); + BKE_camera_params_from_object(¶ms, camera_eval); lens = params.lens; sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y); @@ -1276,7 +1288,7 @@ bool ED_view3d_lock(RegionView3D *rv3d) * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat. * \param dist: The view distance from ofs, normally from RegionView3D.dist. */ -void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist) +void ED_view3d_from_m4(const float mat[4][4], float ofs[3], float quat[4], float *dist) { float nmat[3][3]; @@ -1327,7 +1339,7 @@ void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], c * \param dist: The view distance from ofs to be set, normally from RegionView3D.dist. * \param lens: The view lens angle set for cameras and lamps, normally from View3D.lens. */ -void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, float *lens) +void ED_view3d_from_object(const Object *ob, float ofs[3], float quat[4], float *dist, float *lens) { ED_view3d_from_m4(ob->obmat, ofs, quat, dist); @@ -1342,16 +1354,19 @@ void ED_view3d_from_object(Object *ob, float ofs[3], float quat[4], float *dist, /** * Set the object transformation from RegionView3D members. + * \param depsgraph: The depsgraph to get the evaluated object parent for the transformation calculation. * \param ob: The object which has the transformation assigned. * \param ofs: The view offset, normally from RegionView3D.ofs. * \param quat: The view rotation, quaternion normally from RegionView3D.viewquat. * \param dist: The view distance from ofs, normally from RegionView3D.dist. */ -void ED_view3d_to_object(Object *ob, const float ofs[3], const float quat[4], const float dist) +void ED_view3d_to_object(const Depsgraph *depsgraph, Object *ob, const float ofs[3], const float quat[4], const float dist) { float mat[4][4]; ED_view3d_to_m4(mat, ofs, quat, dist); - BKE_object_apply_mat4(ob, mat, true, true); + + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + BKE_object_apply_mat4_ex(ob, mat, ob_eval->parent, ob_eval->parentinv, true); } /** \} */ @@ -1377,7 +1392,7 @@ float ED_view3d_depth_read_cached(const ViewContext *vc, const int mval[2]) } bool ED_view3d_depth_read_cached_normal( - const ViewContext *vc, const bglMats *mats, const int mval[2], + const ViewContext *vc, const int mval[2], float r_normal[3]) { /* Note: we could support passing in a radius. @@ -1396,7 +1411,7 @@ bool ED_view3d_depth_read_cached_normal( const double depth = (double)ED_view3d_depth_read_cached(vc, mval_ofs); if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) { - if (ED_view3d_depth_unproject(ar, mats, mval_ofs, depth, coords[i])) { + if (ED_view3d_depth_unproject(ar, mval_ofs, depth, coords[i])) { depths_valid[i] = true; } } @@ -1438,21 +1453,13 @@ bool ED_view3d_depth_read_cached_normal( } bool ED_view3d_depth_unproject( - const ARegion *ar, const bglMats *mats, + const ARegion *ar, const int mval[2], const double depth, float r_location_world[3]) { - double p[3]; - if (gluUnProject( - (double)ar->winrct.xmin + mval[0] + 0.5, - (double)ar->winrct.ymin + mval[1] + 0.5, - depth, mats->modelview, mats->projection, (const GLint *)mats->viewport, - &p[0], &p[1], &p[2])) - { - copy_v3fl_v3db(r_location_world, p); - return true; - } - return false; + float centx = (float)mval[0] + 0.5f; + float centy = (float)mval[1] + 0.5f; + return ED_view3d_unproject(ar, centx, centy, depth, r_location_world); } void ED_view3d_depth_tag_update(RegionView3D *rv3d) @@ -1462,46 +1469,3 @@ void ED_view3d_depth_tag_update(RegionView3D *rv3d) } /** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Background Image Utilities - * \{ */ - -BGpic *ED_view3d_background_image_new(View3D *v3d) -{ - BGpic *bgpic = MEM_callocN(sizeof(BGpic), "Background Image"); - - bgpic->rotation = 0.0f; - bgpic->size = 5.0f; - bgpic->blend = 0.5f; - bgpic->iuser.fie_ima = 2; - bgpic->iuser.ok = 1; - bgpic->view = 0; /* 0 for all */ - bgpic->flag |= V3D_BGPIC_EXPANDED; - - BLI_addtail(&v3d->bgpicbase, bgpic); - - return bgpic; -} - -void ED_view3d_background_image_remove(View3D *v3d, BGpic *bgpic) -{ - BLI_remlink(&v3d->bgpicbase, bgpic); - - MEM_freeN(bgpic); -} - -void ED_view3d_background_image_clear(View3D *v3d) -{ - BGpic *bgpic = v3d->bgpicbase.first; - - while (bgpic) { - BGpic *next_bgpic = bgpic->next; - - ED_view3d_background_image_remove(v3d, bgpic); - - bgpic = next_bgpic; - } -} - -/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index cfd506caf6e..4d698428dfd 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -41,32 +41,30 @@ #include "BKE_action.h" #include "BKE_camera.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_object.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BIF_gl.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "UI_resources.h" +#include "GPU_glew.h" #include "GPU_select.h" +#include "GPU_matrix.h" +#include "GPU_state.h" #include "WM_api.h" #include "WM_types.h" +#include "ED_object.h" #include "ED_screen.h" -#ifdef WITH_GAMEENGINE -# include "BLI_listbase.h" -# include "BLI_callbacks.h" - -# include "GPU_draw.h" - -# include "BL_System.h" -#endif +#include "DRW_engine.h" #include "view3d_intern.h" /* own include */ @@ -125,7 +123,7 @@ static void view3d_smooth_view_state_restore(const struct SmoothView3DState *sms /* the arguments are the desired situation */ void ED_view3d_smooth_view_ex( /* avoid passing in the context */ - wmWindowManager *wm, wmWindow *win, ScrArea *sa, + const Depsgraph *depsgraph, wmWindowManager *wm, wmWindow *win, ScrArea *sa, View3D *v3d, ARegion *ar, const int smooth_viewtx, const V3D_SmoothParams *sview) { @@ -156,7 +154,7 @@ void ED_view3d_smooth_view_ex( * we allow camera option locking to initialize the view settings from the camera. */ if (sview->camera == NULL && sview->camera_old == NULL) { - ED_view3d_camera_lock_init(v3d, rv3d); + ED_view3d_camera_lock_init(depsgraph, v3d, rv3d); } /* store the options we want to end with */ @@ -181,13 +179,14 @@ void ED_view3d_smooth_view_ex( } if (sview->camera) { - sms.dst.dist = ED_view3d_offset_distance(sview->camera->obmat, sview->ofs, VIEW3D_DIST_FALLBACK); - ED_view3d_from_object(sview->camera, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens); + Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera); + sms.dst.dist = ED_view3d_offset_distance(ob_camera_eval->obmat, sview->ofs, VIEW3D_DIST_FALLBACK); + ED_view3d_from_object(ob_camera_eval, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens); sms.to_camera = true; /* restore view3d values in end */ } /* skip smooth viewing for render engine draw */ - if (smooth_viewtx && v3d->drawtype != OB_RENDER) { + if (smooth_viewtx && v3d->shading.type != OB_RENDER) { bool changed = false; /* zero means no difference */ if (sview->camera_old != sview->camera) @@ -206,9 +205,10 @@ void ED_view3d_smooth_view_ex( if (changed) { /* original values */ if (sview->camera_old) { - sms.src.dist = ED_view3d_offset_distance(sview->camera_old->obmat, rv3d->ofs, 0.0f); + Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old); + sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, rv3d->ofs, 0.0f); /* this */ - ED_view3d_from_object(sview->camera_old, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens); + ED_view3d_from_object(ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens); } /* grid draw as floor */ if ((rv3d->viewlock & RV3D_LOCKED) == 0) { @@ -230,9 +230,10 @@ void ED_view3d_smooth_view_ex( /* ensure it shows correct */ if (sms.to_camera) { /* use ortho if we move from an ortho view to an ortho camera */ + Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera); rv3d->persp = (((rv3d->is_persp == false) && - (sview->camera->type == OB_CAMERA) && - (((Camera *)sview->camera->data)->type == CAM_ORTHO)) ? + (ob_camera_eval->type == OB_CAMERA) && + (((Camera *)ob_camera_eval->data)->type == CAM_ORTHO)) ? RV3D_ORTHO : RV3D_PERSP); } @@ -265,7 +266,7 @@ void ED_view3d_smooth_view_ex( rv3d->dist = sms.dst.dist; v3d->lens = sms.dst.lens; - ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); } if (rv3d->viewlock & RV3D_BOXVIEW) { @@ -281,11 +282,13 @@ void ED_view3d_smooth_view( View3D *v3d, ARegion *ar, const int smooth_viewtx, const struct V3D_SmoothParams *sview) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); ScrArea *sa = CTX_wm_area(C); ED_view3d_smooth_view_ex( + depsgraph, wm, win, sa, v3d, ar, smooth_viewtx, sview); @@ -294,6 +297,7 @@ void ED_view3d_smooth_view( /* only meant for timer usage */ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool sync_boxview) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); RegionView3D *rv3d = ar->regiondata; struct SmoothView3DStore *sms = rv3d->sms; float step, step_inv; @@ -314,7 +318,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool else { view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d); - ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } @@ -347,7 +351,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *ar, bool rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv; v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv; - ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d); if (ED_screen_animation_playing(CTX_wm_manager(C))) { ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } @@ -405,8 +409,9 @@ void ED_view3d_smooth_view_force_finish( /* force update of view matrix so tools that run immediately after * can use them without redrawing first */ + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); - ED_view3d_update_viewmat(scene, v3d, ar, NULL, NULL, NULL); + ED_view3d_update_viewmat(depsgraph, scene, v3d, ar, NULL, NULL, NULL); } } @@ -433,6 +438,7 @@ void VIEW3D_OT_smoothview(wmOperatorType *ot) static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op)) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); View3D *v3d; ARegion *ar; RegionView3D *rv3d; @@ -446,11 +452,11 @@ static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op)) BKE_object_tfm_protected_backup(v3d->camera, &obtfm); - ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); + ED_view3d_to_object(depsgraph, v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag); - DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); + DEG_id_tag_update(&v3d->camera->id, ID_RECALC_TRANSFORM); rv3d->persp = RV3D_CAMOB; WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, v3d->camera); @@ -503,29 +509,30 @@ void VIEW3D_OT_camera_to_view(wmOperatorType *ot) * meant to take into account vertex/bone selection for eg. */ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); /* can be NULL */ Object *camera_ob = v3d ? v3d->camera : scene->camera; + Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob); float r_co[3]; /* the new location to apply */ float r_scale; /* only for ortho cameras */ - if (camera_ob == NULL) { + if (camera_ob_eval == NULL) { BKE_report(op->reports, RPT_ERROR, "No active camera"); return OPERATOR_CANCELLED; } /* this function does all the important stuff */ - if (BKE_camera_view_frame_fit_to_scene(bmain, scene, v3d, camera_ob, r_co, &r_scale)) { + if (BKE_camera_view_frame_fit_to_scene(depsgraph, scene, camera_ob_eval, r_co, &r_scale)) { ObjectTfmProtectedChannels obtfm; float obmat_new[4][4]; - if ((camera_ob->type == OB_CAMERA) && (((Camera *)camera_ob->data)->type == CAM_ORTHO)) { + if ((camera_ob_eval->type == OB_CAMERA) && (((Camera *)camera_ob_eval->data)->type == CAM_ORTHO)) { ((Camera *)camera_ob->data)->ortho_scale = r_scale; } - copy_m4_m4(obmat_new, camera_ob->obmat); + copy_m4_m4(obmat_new, camera_ob_eval->obmat); copy_v3_v3(obmat_new[3], r_co); /* only touch location */ @@ -534,7 +541,7 @@ static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *op) BKE_object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D); /* notifiers */ - DAG_id_tag_update(&camera_ob->id, OB_RECALC_OB); + DEG_id_tag_update(&camera_ob->id, ID_RECALC_TRANSFORM); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, camera_ob); return OPERATOR_FINISHED; } @@ -689,14 +696,14 @@ void VIEW3D_OT_object_as_camera(wmOperatorType *ot) /** * \param rect: optional for picking (can be NULL). */ -void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect) +void view3d_winmatrix_set(Depsgraph *depsgraph, ARegion *ar, const View3D *v3d, const rcti *rect) { RegionView3D *rv3d = ar->regiondata; rctf viewplane; float clipsta, clipend; bool is_ortho; - is_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL); + is_ortho = ED_view3d_viewplane_get(depsgraph, v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL); rv3d->is_persp = !is_ortho; #if 0 @@ -715,14 +722,14 @@ void view3d_winmatrix_set(ARegion *ar, const View3D *v3d, const rcti *rect) } if (is_ortho) { - wmOrtho(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); + GPU_matrix_ortho_set(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); } else { - wmFrustum(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); + GPU_matrix_frustum_set(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); } /* update matrix in 3d view region */ - glGetFloatv(GL_PROJECTION_MATRIX, (float *)rv3d->winmat); + GPU_matrix_projection_get(rv3d->winmat); } static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) @@ -741,6 +748,7 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) /** * Sets #RegionView3D.viewmat * + * \param depsgraph: Depsgraph. * \param scene: Scene for camera and cursor location. * \param v3d: View 3D space data. * \param rv3d: 3D region which stores the final matrices. @@ -750,13 +758,14 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob) * \note don't set windows active in here, is used by renderwin too. */ void view3d_viewmatrix_set( - Scene *scene, + Depsgraph *depsgraph, Scene *scene, const View3D *v3d, RegionView3D *rv3d, const float rect_scale[2]) { if (rv3d->persp == RV3D_CAMOB) { /* obs/camera */ if (v3d->camera) { - BKE_object_where_is_calc(scene, v3d->camera); - obmat_to_viewmat(rv3d, v3d->camera); + Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera); + BKE_object_where_is_calc(depsgraph, scene, ob_camera_eval); + obmat_to_viewmat(rv3d, ob_camera_eval); } else { quat_to_mat4(rv3d->viewmat, rv3d->viewquat); @@ -774,15 +783,15 @@ void view3d_viewmatrix_set( quat_to_mat4(rv3d->viewmat, rv3d->viewquat); if (rv3d->persp == RV3D_PERSP) rv3d->viewmat[3][2] -= rv3d->dist; if (v3d->ob_centre) { - Object *ob = v3d->ob_centre; + Object *ob_eval = DEG_get_evaluated_object(depsgraph, v3d->ob_centre); float vec[3]; - copy_v3_v3(vec, ob->obmat[3]); - if (ob->type == OB_ARMATURE && v3d->ob_centre_bone[0]) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, v3d->ob_centre_bone); + copy_v3_v3(vec, ob_eval->obmat[3]); + if (ob_eval->type == OB_ARMATURE && v3d->ob_centre_bone[0]) { + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_eval->pose, v3d->ob_centre_bone); if (pchan) { copy_v3_v3(vec, pchan->pose_mat[3]); - mul_m4_v3(ob->obmat, vec); + mul_m4_v3(ob_eval->obmat, vec); } } translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]); @@ -790,7 +799,7 @@ void view3d_viewmatrix_set( } else if (v3d->ob_centre_cursor) { float vec[3]; - copy_v3_v3(vec, ED_view3d_cursor3d_get(scene, (View3D *)v3d)); + copy_v3_v3(vec, scene->cursor.location); translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]); use_lock_ofs = true; } @@ -849,6 +858,71 @@ void view3d_opengl_select_cache_end(void) GPU_select_cache_end(); } +struct DrawSelectLoopUserData { + uint pass; + uint hits; + uint *buffer; + uint buffer_len; + const rcti *rect; + char gpu_select_mode; +}; + +static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data) +{ + bool continue_pass = false; + struct DrawSelectLoopUserData *data = user_data; + if (stage == DRW_SELECT_PASS_PRE) { + GPU_select_begin(data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits); + /* always run POST after PRE. */ + continue_pass = true; + } + else if (stage == DRW_SELECT_PASS_POST) { + int hits = GPU_select_end(); + if (data->pass == 0) { + /* quirk of GPU_select_end, only take hits value from first call. */ + data->hits = hits; + } + if (data->gpu_select_mode == GPU_SELECT_NEAREST_FIRST_PASS) { + data->gpu_select_mode = GPU_SELECT_NEAREST_SECOND_PASS; + continue_pass = (hits > 0); + } + data->pass += 1; + } + else { + BLI_assert(0); + } + return continue_pass; + +} + +eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const Scene *scene, const Object *obact) +{ + if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { + if (obact && (obact->mode & OB_MODE_WEIGHT_PAINT) && + BKE_object_pose_armature_get((Object *)obact)) + { + return VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK; + } + return VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK; + } + return VIEW3D_SELECT_FILTER_NOP; +} + +/** Implement #VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK. */ +static bool drw_select_filter_object_mode_lock(Object *ob, void *user_data) +{ + const Object *obact = user_data; + return BKE_object_is_mode_compat(ob, obact->mode); +} + +/** Implement #VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK for special case when + * we want to select pose bones (this doesn't switch modes). */ +static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void *user_data) +{ + const Object *ob_pose = user_data; + return (DEG_get_original_object(ob) == ob_pose); +} + /** * \warning be sure to account for a negative return value * This is an error, "Too many objects in select buffer" @@ -858,25 +932,27 @@ void view3d_opengl_select_cache_end(void) */ int view3d_opengl_select( ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, - eV3DSelectMode select_mode) + eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter) { struct bThemeState theme_state; + Depsgraph *depsgraph = vc->depsgraph; Scene *scene = vc->scene; View3D *v3d = vc->v3d; ARegion *ar = vc->ar; rcti rect; - int hits; - const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL); + int hits = 0; + const bool use_obedit_skip = (OBEDIT_FROM_VIEW_LAYER(vc->view_layer) != NULL) && (vc->obedit == NULL); const bool is_pick_select = (U.gpu_select_pick_deph != 0); const bool do_passes = ( (is_pick_select == false) && (select_mode == VIEW3D_SELECT_PICK_NEAREST) && GPU_select_query_check_active()); const bool use_nearest = (is_pick_select && select_mode == VIEW3D_SELECT_PICK_NEAREST); + bool draw_surface = true; char gpu_select_mode; - /* case not a border select */ + /* case not a box select */ if (input->xmin == input->xmax) { /* seems to be default value for bones only now */ BLI_rcti_init_pt_radius(&rect, (const int[2]){input->xmin, input->ymin}, 12); @@ -905,6 +981,35 @@ int view3d_opengl_select( } } + struct { + DRW_ObjectFilterFn fn; + void *user_data; + } object_filter = {NULL, NULL}; + switch (select_filter) { + case VIEW3D_SELECT_FILTER_OBJECT_MODE_LOCK: + { + Object *obact = OBACT(vc->view_layer); + if (obact && obact->mode != OB_MODE_OBJECT) { + object_filter.fn = drw_select_filter_object_mode_lock; + object_filter.user_data = obact; + } + break; + } + case VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK: + { + Object *obact = OBACT(vc->view_layer); + BLI_assert(obact && (obact->mode & OB_MODE_WEIGHT_PAINT)); + Object *ob_pose = BKE_object_pose_armature_get(obact); + + object_filter.fn = drw_select_filter_object_mode_lock_for_weight_paint; + object_filter.user_data = ob_pose; + break; + } + case VIEW3D_SELECT_FILTER_NOP: + break; + + } + /* Tools may request depth outside of regular drawing code. */ UI_Theme_Store(&theme_state); UI_SetTheme(SPACE_VIEW3D, RGN_TYPE_WINDOW); @@ -918,47 +1023,81 @@ int view3d_opengl_select( goto finally; } + /* All of the queries need to be perform on the drawing context. */ + DRW_opengl_context_enable(); + G.f |= G_PICKSEL; /* Important we use the 'viewmat' and don't re-calculate since * the object & bone view locking takes 'rect' into account, see: T51629. */ - ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, vc->rv3d->viewmat, NULL, &rect); + ED_view3d_draw_setup_view(vc->win, depsgraph, scene, ar, v3d, vc->rv3d->viewmat, NULL, &rect); - if (v3d->drawtype > OB_WIRE) { - v3d->zbuf = true; - glEnable(GL_DEPTH_TEST); + if (v3d->shading.type > OB_WIRE) { + GPU_depth_test(true); } - if (vc->rv3d->rflag & RV3D_CLIPPING) + if (vc->rv3d->rflag & RV3D_CLIPPING) { ED_view3d_clipping_set(vc->rv3d); + } - GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0); - - ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest); - - hits = GPU_select_end(); - - /* second pass, to get the closest object to camera */ - if (do_passes && (hits > 0)) { - GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits); - - ED_view3d_draw_select_loop(vc, scene, v3d, ar, use_obedit_skip, use_nearest); + /* If in xray mode, we select the wires in priority. */ + if ((v3d->shading.flag & V3D_XRAY_FLAG(v3d)) && use_nearest) { + /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop + * because the OpenGL context created & destroyed inside this function. */ + struct DrawSelectLoopUserData drw_select_loop_user_data = { + .pass = 0, + .hits = 0, + .buffer = buffer, + .buffer_len = bufsize, + .rect = &rect, + .gpu_select_mode = gpu_select_mode, + }; + draw_surface = false; + DRW_draw_select_loop( + depsgraph, ar, v3d, + use_obedit_skip, draw_surface, use_nearest, &rect, + drw_select_loop_pass, &drw_select_loop_user_data, + object_filter.fn, object_filter.user_data); + hits = drw_select_loop_user_data.hits; + /* FIX: This cleanup the state before doing another selection pass. + * (see T56695) */ + GPU_select_cache_end(); + } - GPU_select_end(); + if (hits == 0) { + /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop + * because the OpenGL context created & destroyed inside this function. */ + struct DrawSelectLoopUserData drw_select_loop_user_data = { + .pass = 0, + .hits = 0, + .buffer = buffer, + .buffer_len = bufsize, + .rect = &rect, + .gpu_select_mode = gpu_select_mode, + }; + draw_surface = true; + DRW_draw_select_loop( + depsgraph, ar, v3d, + use_obedit_skip, draw_surface, use_nearest, &rect, + drw_select_loop_pass, &drw_select_loop_user_data, + object_filter.fn, object_filter.user_data); + hits = drw_select_loop_user_data.hits; } G.f &= ~G_PICKSEL; - ED_view3d_draw_setup_view(vc->win, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL); + ED_view3d_draw_setup_view(vc->win, depsgraph, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL); - if (v3d->drawtype > OB_WIRE) { - v3d->zbuf = 0; - glDisable(GL_DEPTH_TEST); + if (v3d->shading.type > OB_WIRE) { + GPU_depth_test(false); } if (vc->rv3d->rflag & RV3D_CLIPPING) ED_view3d_clipping_disable(); + DRW_opengl_context_disable(); + finally: + if (hits < 0) printf("Too many objects in select buffer\n"); /* XXX make error message */ UI_Theme_Restore(&theme_state); @@ -974,11 +1113,10 @@ finally: static unsigned int free_localbit(Main *bmain) { - unsigned int lay; ScrArea *sa; bScreen *sc; - lay = 0; + unsigned short local_view_bits = 0; /* sometimes we loose a localview: when an area is closed */ /* check all areas: which localviews are in use? */ @@ -988,72 +1126,38 @@ static unsigned int free_localbit(Main *bmain) for (; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *) sl; - lay |= v3d->lay; + if (v3d->localvd) { + local_view_bits |= v3d->local_view_uuid; + } } } } } - if ((lay & 0x01000000) == 0) return 0x01000000; - if ((lay & 0x02000000) == 0) return 0x02000000; - if ((lay & 0x04000000) == 0) return 0x04000000; - if ((lay & 0x08000000) == 0) return 0x08000000; - if ((lay & 0x10000000) == 0) return 0x10000000; - if ((lay & 0x20000000) == 0) return 0x20000000; - if ((lay & 0x40000000) == 0) return 0x40000000; - if ((lay & 0x80000000) == 0) return 0x80000000; - - return 0; -} - -int ED_view3d_scene_layer_set(int lay, const bool *values, int *active) -{ - int i, tot = 0; - - /* ensure we always have some layer selected */ - for (i = 0; i < 20; i++) - if (values[i]) - tot++; - - if (tot == 0) - return lay; - - for (i = 0; i < 20; i++) { - - if (active) { - /* if this value has just been switched on, make that layer active */ - if (values[i] && (lay & (1 << i)) == 0) { - *active = (1 << i); - } - } - - if (values[i]) lay |= (1 << i); - else lay &= ~(1 << i); - } - - /* ensure always an active layer */ - if (active && (lay & *active) == 0) { - for (i = 0; i < 20; i++) { - if (lay & (1 << i)) { - *active = 1 << i; - break; - } + for (int i = 0; i < 16; i++) { + if ((local_view_bits & (1 << i)) == 0) { + return (1 << i); } } - return lay; + return 0; } static bool view3d_localview_init( - wmWindowManager *wm, wmWindow *win, - Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx, + const Depsgraph *depsgraph, + wmWindowManager *wm, + wmWindow *win, + Main *bmain, + ViewLayer *view_layer, + ScrArea *sa, + const int smooth_viewtx, ReportList *reports) { View3D *v3d = sa->spacedata.first; Base *base; float min[3], max[3], box[3], mid[3]; float size = 0.0f; - unsigned int locallay; + unsigned int local_view_bit; bool ok = false; if (v3d->localvd) { @@ -1062,27 +1166,28 @@ static bool view3d_localview_init( INIT_MINMAX(min, max); - locallay = free_localbit(bmain); + local_view_bit = free_localbit(bmain); - if (locallay == 0) { - BKE_report(reports, RPT_ERROR, "No more than 8 local views"); + if (local_view_bit == 0) { + /* TODO(dfelinto): We can kick one of the other 3D views out of local view + specially if it is not being used. */ + BKE_report(reports, RPT_ERROR, "No more than 16 local views"); ok = false; } else { - if (scene->obedit) { - BKE_object_minmax(scene->obedit, min, max, false); - - ok = true; - - BASACT->lay |= locallay; - scene->obedit->lay = BASACT->lay; + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); + if (obedit) { + FOREACH_BASE_IN_EDIT_MODE_BEGIN(view_layer, v3d, base_iter) { + BKE_object_minmax(base_iter->object, min, max, false); + base_iter->local_view_bits |= local_view_bit; + ok = true; + } FOREACH_BASE_IN_EDIT_MODE_END; } else { - for (base = FIRSTBASE; base; base = base->next) { + for (base = FIRSTBASE(view_layer); base; base = base->next) { if (TESTBASE(v3d, base)) { BKE_object_minmax(base->object, min, max, false); - base->lay |= locallay; - base->object->lay = base->lay; + base->local_view_bits |= local_view_bit; ok = true; } } @@ -1101,14 +1206,12 @@ static bool view3d_localview_init( mid_v3_v3v3(mid, min, max); - copy_v3_v3(v3d->cursor, mid); - for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = ar->regiondata; bool ok_dist = true; - /* new view values */ + /* New view values. */ Object *camera_old = NULL; float dist_new, ofs_new[3]; @@ -1129,14 +1232,16 @@ static bool view3d_localview_init( } if (ok_dist) { - dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN); + dist_new = ED_view3d_radius_to_dist(v3d, ar, depsgraph, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN); + if (rv3d->persp == RV3D_PERSP) { - /* don't zoom closer than the near clipping plane */ + /* Don't zoom closer than the near clipping plane. */ dist_new = max_ff(dist_new, v3d->near * 1.5f); } } ED_view3d_smooth_view_ex( + depsgraph, wm, win, sa, v3d, ar, smooth_viewtx, &(const V3D_SmoothParams) { .camera_old = camera_old, @@ -1145,26 +1250,20 @@ static bool view3d_localview_init( } } - v3d->lay = locallay; - } - else { - /* clear flags */ - for (base = FIRSTBASE; base; base = base->next) { - if (base->lay & locallay) { - base->lay -= locallay; - if (base->lay == 0) base->lay = v3d->layact; - if (base->object != scene->obedit) base->flag |= SELECT; - base->object->lay = base->lay; - } - } + v3d->local_view_uuid = local_view_bit; } - DAG_on_visible_update(bmain, false); - + DEG_on_visible_update(bmain, false); return ok; } -static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, ScrArea *sa, const int smooth_viewtx) +static void restore_localviewdata( + const Depsgraph *depsgraph, + wmWindowManager *wm, + wmWindow *win, + Main *bmain, + ScrArea *sa, + const int smooth_viewtx) { const bool free = true; ARegion *ar; @@ -1176,9 +1275,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai camera_old = v3d->camera; camera_new = v3d->localvd->camera; - v3d->lay = v3d->localvd->lay; - v3d->layact = v3d->localvd->layact; - v3d->drawtype = v3d->localvd->drawtype; + v3d->local_view_uuid = 0; v3d->camera = v3d->localvd->camera; if (free) { @@ -1201,6 +1298,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai rv3d->camzoom = rv3d->localvd->camzoom; ED_view3d_smooth_view_ex( + depsgraph, wm, win, sa, v3d, ar, smooth_viewtx, &(const V3D_SmoothParams) { @@ -1220,35 +1318,35 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai } static bool view3d_localview_exit( - wmWindowManager *wm, wmWindow *win, - Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx) + const Depsgraph *depsgraph, + wmWindowManager *wm, + wmWindow *win, + Main *bmain, + ViewLayer *view_layer, + ScrArea *sa, + const int smooth_viewtx) { View3D *v3d = sa->spacedata.first; struct Base *base; - unsigned int locallay; + unsigned int local_view_bit; if (v3d->localvd) { - locallay = v3d->lay & 0xFF000000; - - restore_localviewdata(wm, win, bmain, sa, smooth_viewtx); + local_view_bit = v3d->local_view_uuid; - /* for when in other window the layers have changed */ - if (v3d->scenelock) v3d->lay = scene->lay; + restore_localviewdata(depsgraph, wm, win, bmain, sa, smooth_viewtx); - for (base = FIRSTBASE; base; base = base->next) { - if (base->lay & locallay) { - base->lay -= locallay; - if (base->lay == 0) base->lay = v3d->layact; - if (base->object != scene->obedit) { - base->flag |= SELECT; - base->object->flag |= SELECT; + Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer); + for (base = FIRSTBASE(view_layer); base; base = base->next) { + if (base->local_view_bits & local_view_bit) { + base->local_view_bits &= ~local_view_bit; + if (base->object != obedit) { + ED_object_base_select(base, BA_SELECT); } - base->object->lay = base->lay; } } - DAG_on_visible_update(bmain, false); + DEG_on_visible_update(bmain, false); return true; } @@ -1259,30 +1357,36 @@ static bool view3d_localview_exit( static int localview_exec(bContext *C, wmOperator *op) { + const Depsgraph *depsgraph = CTX_data_depsgraph(C); const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); ScrArea *sa = CTX_wm_area(C); View3D *v3d = CTX_wm_view3d(C); bool changed; if (v3d->localvd) { - changed = view3d_localview_exit(wm, win, bmain, scene, sa, smooth_viewtx); + changed = view3d_localview_exit(depsgraph, wm, win, bmain, view_layer, sa, smooth_viewtx); } else { - changed = view3d_localview_init(wm, win, bmain, scene, sa, smooth_viewtx, op->reports); + changed = view3d_localview_init(depsgraph, wm, win, bmain, view_layer, sa, smooth_viewtx, op->reports); } if (changed) { - DAG_id_type_tag(bmain, ID_OB); + DEG_id_type_tag(bmain, ID_OB); ED_area_tag_redraw(sa); - /* unselected objects become selected when exiting */ + /* Unselected objects become selected when exiting. */ if (v3d->localvd == NULL) { + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } + else { + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + } return OPERATOR_FINISHED; } @@ -1305,217 +1409,105 @@ void VIEW3D_OT_localview(wmOperatorType *ot) ot->poll = ED_operator_view3d_active; } -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Game Engine Operator - * - * Start the game engine (handles context switching). - * \{ */ - -#ifdef WITH_GAMEENGINE - -static ListBase queue_back; -static void game_engine_save_state(bContext *C, wmWindow *win) +static int localview_remove_from_exec(bContext *C, wmOperator *op) { + View3D *v3d = CTX_wm_view3d(C); Main *bmain = CTX_data_main(C); - Object *obact = CTX_data_active_object(C); - - glPushAttrib(GL_ALL_ATTRIB_BITS); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + bool changed = false; - if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) - GPU_paint_set_mipmap(bmain, 1); + for (Base *base = FIRSTBASE(view_layer); base; base = base->next) { + if (TESTBASE(v3d, base)) { + base->local_view_bits &= ~v3d->local_view_uuid; + ED_object_base_select(base, BA_DESELECT); - queue_back = win->queue; + if (base == BASACT(view_layer)) { + view_layer->basact = NULL; + } + changed = true; + } + } - BLI_listbase_clear(&win->queue); + if (changed) { + DEG_on_visible_update(bmain, false); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No object selected"); + return OPERATOR_CANCELLED; + } } -static void game_engine_restore_state(bContext *C, wmWindow *win) +static bool localview_remove_from_poll(bContext *C) { - Main *bmain = CTX_data_main(C); - Object *obact = CTX_data_active_object(C); - - if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) - GPU_paint_set_mipmap(bmain, 0); - - /* check because closing win can set to NULL */ - if (win) { - win->queue = queue_back; + if (CTX_data_edit_object(C) != NULL) { + return false; } - GPU_state_init(); - GPU_set_tpage(NULL, 0, 0); - - glPopAttrib(); + View3D *v3d = CTX_wm_view3d(C); + return v3d && v3d->localvd; } -/* was space_set_commmandline_options in 2.4x */ -static void game_set_commmandline_options(GameData *gm) +void VIEW3D_OT_localview_remove_from(wmOperatorType *ot) { - SYS_SystemHandle syshandle; - int test; - - if ((syshandle = SYS_GetSystem())) { - /* User defined settings */ - test = (U.gameflags & USER_DISABLE_MIPMAP); - GPU_set_mipmap(G_MAIN, !test); - SYS_WriteCommandLineInt(syshandle, "nomipmap", test); - - /* File specific settings: */ - /* Only test the first one. These two are switched - * simultaneously. */ - test = (gm->flag & GAME_SHOW_FRAMERATE); - SYS_WriteCommandLineInt(syshandle, "show_framerate", test); - SYS_WriteCommandLineInt(syshandle, "show_profile", test); - - test = (gm->flag & GAME_SHOW_DEBUG_PROPS); - SYS_WriteCommandLineInt(syshandle, "show_properties", test); - - test = (gm->flag & GAME_SHOW_PHYSICS); - SYS_WriteCommandLineInt(syshandle, "show_physics", test); - - test = (gm->flag & GAME_ENABLE_ALL_FRAMES); - SYS_WriteCommandLineInt(syshandle, "fixedtime", test); - - test = (gm->flag & GAME_ENABLE_ANIMATION_RECORD); - SYS_WriteCommandLineInt(syshandle, "animation_record", test); - - test = (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS); - SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test); - - test = (gm->matmode == GAME_MAT_MULTITEX); - SYS_WriteCommandLineInt(syshandle, "blender_material", test); - test = (gm->matmode == GAME_MAT_GLSL); - SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test); - test = (gm->flag & GAME_DISPLAY_LISTS); - SYS_WriteCommandLineInt(syshandle, "displaylists", test); - + /* identifiers */ + ot->name = "Remove from Local View"; + ot->description = "Move selected objects out of local view"; + ot->idname = "VIEW3D_OT_localview_remove_from"; - } + /* api callbacks */ + ot->exec = localview_remove_from_exec; + ot->invoke = WM_operator_confirm; + ot->poll = localview_remove_from_poll; + ot->flag = OPTYPE_UNDO; } -#endif /* WITH_GAMEENGINE */ - -static bool game_engine_poll(bContext *C) -{ - bScreen *screen; - /* we need a context and area to launch BGE - * it's a temporary solution to avoid crash at load time - * if we try to auto run the BGE. Ideally we want the - * context to be set as soon as we load the file. */ - - if (CTX_wm_window(C) == NULL) return 0; - if ((screen = CTX_wm_screen(C)) == NULL) return 0; - - if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT) - return 0; - - if (!BKE_scene_uses_blender_game(screen->scene)) - return 0; +/** \} */ - return 1; -} +/* -------------------------------------------------------------------- */ +/** \name View Layer Utilities + * \{ */ -static int game_engine_exec(bContext *C, wmOperator *op) +int ED_view3d_view_layer_set(int lay, const bool *values, int *active) { -#ifdef WITH_GAMEENGINE - Scene *startscene = CTX_data_scene(C); - Main *bmain = CTX_data_main(C); - ScrArea /* *sa, */ /* UNUSED */ *prevsa = CTX_wm_area(C); - ARegion *ar, *prevar = CTX_wm_region(C); - wmWindow *prevwin = CTX_wm_window(C); - RegionView3D *rv3d; - rcti cam_frame; - - UNUSED_VARS(op); - - /* bad context switch .. */ - if (!ED_view3d_context_activate(C)) - return OPERATOR_CANCELLED; - - /* redraw to hide any menus/popups, we don't go back to - * the window manager until after this operator exits */ - WM_redraw_windows(C); - - BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_PRE); - - rv3d = CTX_wm_region_view3d(C); - /* sa = CTX_wm_area(C); */ /* UNUSED */ - ar = CTX_wm_region(C); - - view3d_operator_needs_opengl(C); - - game_set_commmandline_options(&startscene->gm); + int i, tot = 0; - if ((rv3d->persp == RV3D_CAMOB) && - (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) && - (startscene->gm.stereoflag != STEREO_DOME)) - { - /* Letterbox */ - rctf cam_framef; - ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, false); - cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin; - cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin; - cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin; - cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin; - BLI_rcti_isect(&ar->winrct, &cam_frame, &cam_frame); - } - else { - cam_frame.xmin = ar->winrct.xmin; - cam_frame.xmax = ar->winrct.xmax; - cam_frame.ymin = ar->winrct.ymin; - cam_frame.ymax = ar->winrct.ymax; - } + /* ensure we always have some layer selected */ + for (i = 0; i < 20; i++) + if (values[i]) + tot++; + if (tot == 0) + return lay; - game_engine_save_state(C, prevwin); + for (i = 0; i < 20; i++) { - StartKetsjiShell(C, ar, &cam_frame, 1); + if (active) { + /* if this value has just been switched on, make that layer active */ + if (values[i] && (lay & (1 << i)) == 0) { + *active = (1 << i); + } + } - /* window wasnt closed while the BGE was running */ - if (BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) { - prevwin = NULL; - CTX_wm_window_set(C, NULL); + if (values[i]) lay |= (1 << i); + else lay &= ~(1 << i); } - ED_area_tag_redraw(CTX_wm_area(C)); - - if (prevwin) { - /* restore context, in case it changed in the meantime, for - * example by working in another window or closing it */ - CTX_wm_region_set(C, prevar); - CTX_wm_window_set(C, prevwin); - CTX_wm_area_set(C, prevsa); + /* ensure always an active layer */ + if (active && (lay & *active) == 0) { + for (i = 0; i < 20; i++) { + if (lay & (1 << i)) { + *active = 1 << i; + break; + } + } } - game_engine_restore_state(C, prevwin); - - //XXX restore_all_scene_cfra(scene_cfra_store); - BKE_scene_set_background(CTX_data_main(C), startscene); - //XXX BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); - - BLI_callback_exec(bmain, &startscene->id, BLI_CB_EVT_GAME_POST); - - return OPERATOR_FINISHED; -#else - UNUSED_VARS(C); - BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build"); - return OPERATOR_CANCELLED; -#endif -} - -void VIEW3D_OT_game_start(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Start Game Engine"; - ot->description = "Start game engine"; - ot->idname = "VIEW3D_OT_game_start"; - - /* api callbacks */ - ot->exec = game_engine_exec; - - ot->poll = game_engine_poll; + return lay; } /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index b2846a630d2..a716264febb 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -37,6 +37,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_main.h" #include "BKE_report.h" #include "BLT_translation.h" @@ -56,6 +57,10 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_immediate.h" + +#include "DEG_depsgraph.h" + #include "view3d_intern.h" /* own include */ #ifdef WITH_INPUT_NDOF @@ -172,59 +177,6 @@ void walk_modal_keymap(wmKeyConfig *keyconf) keymap = WM_modalkeymap_add(keyconf, "View3D Walk Modal", modal_items); - /* items for modal map */ - WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, WALK_MODAL_CANCEL); - WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_CANCEL); - - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, WALK_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, WALK_MODAL_CONFIRM); - - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_FAST_ENABLE); - WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_FAST_DISABLE); - - WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_SLOW_ENABLE); - WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_SLOW_DISABLE); - - /* WASD */ - WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_FORWARD); - WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_BACKWARD); - WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_LEFT); - WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_RIGHT); - WM_modalkeymap_add_item(keymap, EKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_UP); - WM_modalkeymap_add_item(keymap, QKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_DIR_DOWN); - - WM_modalkeymap_add_item(keymap, WKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_FORWARD_STOP); - WM_modalkeymap_add_item(keymap, SKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_BACKWARD_STOP); - WM_modalkeymap_add_item(keymap, AKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_LEFT_STOP); - WM_modalkeymap_add_item(keymap, DKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_RIGHT_STOP); - WM_modalkeymap_add_item(keymap, EKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_UP_STOP); - WM_modalkeymap_add_item(keymap, QKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_DOWN_STOP); - - WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_FORWARD); - WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_BACKWARD); - WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_LEFT); - WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_PRESS, 0, 0, WALK_MODAL_DIR_RIGHT); - - WM_modalkeymap_add_item(keymap, UPARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_FORWARD_STOP); - WM_modalkeymap_add_item(keymap, DOWNARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_BACKWARD_STOP); - WM_modalkeymap_add_item(keymap, LEFTARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_LEFT_STOP); - WM_modalkeymap_add_item(keymap, RIGHTARROWKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_DIR_RIGHT_STOP); - - WM_modalkeymap_add_item(keymap, TABKEY, KM_PRESS, 0, 0, WALK_MODAL_TOGGLE); - WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, WALK_MODAL_TOGGLE); - - WM_modalkeymap_add_item(keymap, VKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_JUMP); - WM_modalkeymap_add_item(keymap, VKEY, KM_RELEASE, KM_ANY, 0, WALK_MODAL_JUMP_STOP); - - WM_modalkeymap_add_item(keymap, SPACEKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_TELEPORT); - WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_ANY, KM_ANY, 0, WALK_MODAL_TELEPORT); - - WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, KM_ANY, 0, WALK_MODAL_ACCELERATE); - WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, KM_ANY, 0, WALK_MODAL_DECELERATE); - WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ANY, 0, WALK_MODAL_ACCELERATE); - WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ANY, 0, WALK_MODAL_DECELERATE); - /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_walk"); } @@ -245,6 +197,7 @@ typedef struct WalkInfo { RegionView3D *rv3d; View3D *v3d; ARegion *ar; + struct Depsgraph *depsgraph; Scene *scene; wmTimer *timer; /* needed for redraws */ @@ -328,7 +281,7 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a rctf viewborder; if (ED_view3d_cameracontrol_object_get(walk->v3d_camera_control)) { - ED_view3d_calc_camera_border(walk->scene, ar, walk->v3d, walk->rv3d, &viewborder, false); + ED_view3d_calc_camera_border(walk->scene, walk->depsgraph, ar, walk->v3d, walk->rv3d, &viewborder, false); xoff = viewborder.xmin + BLI_rctf_size_x(&viewborder) * 0.5f; yoff = viewborder.ymin + BLI_rctf_size_y(&viewborder) * 0.5f; } @@ -337,24 +290,33 @@ static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *a yoff = walk->ar->winy / 2; } - UI_ThemeColor(TH_VIEW_OVERLAY); - glBegin(GL_LINES); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformThemeColor(TH_VIEW_OVERLAY); + + immBegin(GPU_PRIM_LINES, 8); + /* North */ - glVertex2i(xoff, yoff + inner_length); - glVertex2i(xoff, yoff + outter_length); + immVertex2i(pos, xoff, yoff + inner_length); + immVertex2i(pos, xoff, yoff + outter_length); /* East */ - glVertex2i(xoff + inner_length, yoff); - glVertex2i(xoff + outter_length, yoff); + immVertex2i(pos, xoff + inner_length, yoff); + immVertex2i(pos, xoff + outter_length, yoff); /* South */ - glVertex2i(xoff, yoff - inner_length); - glVertex2i(xoff, yoff - outter_length); + immVertex2i(pos, xoff, yoff - inner_length); + immVertex2i(pos, xoff, yoff - outter_length); /* West */ - glVertex2i(xoff - inner_length, yoff); - glVertex2i(xoff - outter_length, yoff); - glEnd(); + immVertex2i(pos, xoff - inner_length, yoff); + immVertex2i(pos, xoff - outter_length, yoff); + + immEnd(); + immUnbindProgram(); } static void walk_update_header(bContext *C, wmOperator *op, WalkInfo *walk) @@ -389,7 +351,7 @@ static void walk_update_header(bContext *C, wmOperator *op, WalkInfo *walk) #undef WM_MODALKEY - ED_area_headerprint(CTX_wm_area(C), header); + ED_workspace_status_text(C, header); } static void walk_navigation_mode_set(bContext *C, wmOperator *op, WalkInfo *walk, eWalkMethod mode) @@ -493,11 +455,13 @@ static float userdef_speed = -1.f; static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) { + Main *bmain = CTX_data_main(C); wmWindow *win = CTX_wm_window(C); walk->rv3d = CTX_wm_region_view3d(C); walk->v3d = CTX_wm_view3d(C); walk->ar = CTX_wm_region(C); + walk->depsgraph = CTX_data_depsgraph(C); walk->scene = CTX_data_scene(C); #ifdef NDOF_WALK_DEBUG @@ -587,11 +551,11 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->rflag |= RV3D_NAVIGATING; walk->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), walk->scene, 0, + bmain, walk->scene, CTX_data_depsgraph(C), 0, walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( - walk->scene, walk->v3d, walk->rv3d, + walk->depsgraph, walk->scene, walk->v3d, walk->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); /* center the mouse */ @@ -1419,7 +1383,7 @@ static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event) } if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) - ED_area_headerprint(CTX_wm_area(C), NULL); + ED_workspace_status_text(C, NULL); return exit_code; } |