From cd1600413246a62156441f6e7910489b19ae5a28 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 14 Jul 2018 23:16:34 +0200 Subject: WM: rename files, manipulator -> gizmo Edit doxy files and header guards only. --- source/blender/editors/CMakeLists.txt | 2 +- .../blender/editors/gizmo_library/CMakeLists.txt | 60 + .../gizmo_library/geometry/geom_arrow_gizmo.c | 141 ++ .../gizmo_library/geometry/geom_cube_gizmo.c | 75 + .../gizmo_library/geometry/geom_dial_gizmo.c | 813 +++++++++ .../editors/gizmo_library/gizmo_draw_utils.c | 121 ++ .../blender/editors/gizmo_library/gizmo_geometry.h | 54 + .../editors/gizmo_library/gizmo_library_intern.h | 111 ++ .../editors/gizmo_library/gizmo_library_presets.c | 150 ++ .../editors/gizmo_library/gizmo_library_utils.c | 256 +++ .../gizmo_library/gizmo_types/arrow2d_gizmo.c | 225 +++ .../gizmo_library/gizmo_types/arrow3d_gizmo.c | 492 ++++++ .../gizmo_library/gizmo_types/button2d_gizmo.c | 322 ++++ .../gizmo_library/gizmo_types/cage2d_gizmo.c | 1100 ++++++++++++ .../gizmo_library/gizmo_types/cage3d_gizmo.c | 692 ++++++++ .../gizmo_library/gizmo_types/dial3d_gizmo.c | 487 ++++++ .../gizmo_library/gizmo_types/grab3d_gizmo.c | 375 ++++ .../gizmo_library/gizmo_types/primitive3d_gizmo.c | 191 +++ source/blender/editors/include/ED_gizmo_library.h | 222 +++ .../editors/include/ED_manipulator_library.h | 222 --- .../editors/manipulator_library/CMakeLists.txt | 60 - .../geometry/geom_arrow_manipulator.c | 141 -- .../geometry/geom_cube_manipulator.c | 75 - .../geometry/geom_dial_manipulator.c | 813 --------- .../manipulator_library/manipulator_draw_utils.c | 121 -- .../manipulator_library/manipulator_geometry.h | 54 - .../manipulator_library_intern.h | 111 -- .../manipulator_library_presets.c | 150 -- .../manipulator_library_utils.c | 256 --- .../manipulator_types/arrow2d_manipulator.c | 225 --- .../manipulator_types/arrow3d_manipulator.c | 492 ------ .../manipulator_types/button2d_manipulator.c | 322 ---- .../manipulator_types/cage2d_manipulator.c | 1100 ------------ .../manipulator_types/cage3d_manipulator.c | 692 -------- .../manipulator_types/dial3d_manipulator.c | 487 ------ .../manipulator_types/grab3d_manipulator.c | 375 ---- .../manipulator_types/primitive3d_manipulator.c | 191 --- source/blender/editors/mesh/CMakeLists.txt | 2 +- source/blender/editors/mesh/editmesh_add_gizmo.c | 426 +++++ .../editors/mesh/editmesh_add_manipulator.c | 426 ----- source/blender/editors/mesh/editmesh_bisect.c | 2 +- source/blender/editors/mesh/editmesh_extrude.c | 2 +- .../blender/editors/mesh/editmesh_extrude_spin.c | 2 +- source/blender/editors/space_api/spacetypes.c | 2 +- source/blender/editors/space_node/CMakeLists.txt | 2 +- source/blender/editors/space_node/node_gizmo.c | 621 +++++++ .../blender/editors/space_node/node_manipulators.c | 621 ------- source/blender/editors/space_view3d/CMakeLists.txt | 16 +- .../editors/space_view3d/view3d_gizmo_armature.c | 228 +++ .../editors/space_view3d/view3d_gizmo_camera.c | 473 ++++++ .../editors/space_view3d/view3d_gizmo_empty.c | 204 +++ .../editors/space_view3d/view3d_gizmo_forcefield.c | 125 ++ .../editors/space_view3d/view3d_gizmo_lamp.c | 307 ++++ .../editors/space_view3d/view3d_gizmo_navigate.c | 371 ++++ .../space_view3d/view3d_gizmo_navigate_type.c | 310 ++++ .../editors/space_view3d/view3d_gizmo_ruler.c | 1101 ++++++++++++ .../space_view3d/view3d_manipulator_armature.c | 228 --- .../space_view3d/view3d_manipulator_camera.c | 473 ------ .../space_view3d/view3d_manipulator_empty.c | 204 --- .../space_view3d/view3d_manipulator_forcefield.c | 125 -- .../editors/space_view3d/view3d_manipulator_lamp.c | 307 ---- .../space_view3d/view3d_manipulator_navigate.c | 371 ---- .../view3d_manipulator_navigate_type.c | 310 ---- .../space_view3d/view3d_manipulator_ruler.c | 1101 ------------ source/blender/editors/transform/CMakeLists.txt | 4 +- .../blender/editors/transform/transform_gizmo_2d.c | 382 +++++ .../blender/editors/transform/transform_gizmo_3d.c | 1790 ++++++++++++++++++++ .../editors/transform/transform_manipulator_2d.c | 382 ----- .../editors/transform/transform_manipulator_3d.c | 1790 -------------------- source/blender/editors/util/CMakeLists.txt | 2 +- 70 files changed, 12243 insertions(+), 12243 deletions(-) create mode 100644 source/blender/editors/gizmo_library/CMakeLists.txt create mode 100644 source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c create mode 100644 source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c create mode 100644 source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c create mode 100644 source/blender/editors/gizmo_library/gizmo_draw_utils.c create mode 100644 source/blender/editors/gizmo_library/gizmo_geometry.h create mode 100644 source/blender/editors/gizmo_library/gizmo_library_intern.h create mode 100644 source/blender/editors/gizmo_library/gizmo_library_presets.c create mode 100644 source/blender/editors/gizmo_library/gizmo_library_utils.c create mode 100644 source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c create mode 100644 source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c create mode 100644 source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c create mode 100644 source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c create mode 100644 source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c create mode 100644 source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c create mode 100644 source/blender/editors/gizmo_library/gizmo_types/grab3d_gizmo.c create mode 100644 source/blender/editors/gizmo_library/gizmo_types/primitive3d_gizmo.c create mode 100644 source/blender/editors/include/ED_gizmo_library.h delete mode 100644 source/blender/editors/include/ED_manipulator_library.h delete mode 100644 source/blender/editors/manipulator_library/CMakeLists.txt delete mode 100644 source/blender/editors/manipulator_library/geometry/geom_arrow_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/geometry/geom_cube_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/geometry/geom_dial_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_draw_utils.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_geometry.h delete mode 100644 source/blender/editors/manipulator_library/manipulator_library_intern.h delete mode 100644 source/blender/editors/manipulator_library/manipulator_library_presets.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_library_utils.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_types/arrow2d_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_types/cage3d_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c delete mode 100644 source/blender/editors/manipulator_library/manipulator_types/primitive3d_manipulator.c create mode 100644 source/blender/editors/mesh/editmesh_add_gizmo.c delete mode 100644 source/blender/editors/mesh/editmesh_add_manipulator.c create mode 100644 source/blender/editors/space_node/node_gizmo.c delete mode 100644 source/blender/editors/space_node/node_manipulators.c create mode 100644 source/blender/editors/space_view3d/view3d_gizmo_armature.c create mode 100644 source/blender/editors/space_view3d/view3d_gizmo_camera.c create mode 100644 source/blender/editors/space_view3d/view3d_gizmo_empty.c create mode 100644 source/blender/editors/space_view3d/view3d_gizmo_forcefield.c create mode 100644 source/blender/editors/space_view3d/view3d_gizmo_lamp.c create mode 100644 source/blender/editors/space_view3d/view3d_gizmo_navigate.c create mode 100644 source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c create mode 100644 source/blender/editors/space_view3d/view3d_gizmo_ruler.c delete mode 100644 source/blender/editors/space_view3d/view3d_manipulator_armature.c delete mode 100644 source/blender/editors/space_view3d/view3d_manipulator_camera.c delete mode 100644 source/blender/editors/space_view3d/view3d_manipulator_empty.c delete mode 100644 source/blender/editors/space_view3d/view3d_manipulator_forcefield.c delete mode 100644 source/blender/editors/space_view3d/view3d_manipulator_lamp.c delete mode 100644 source/blender/editors/space_view3d/view3d_manipulator_navigate.c delete mode 100644 source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c delete mode 100644 source/blender/editors/space_view3d/view3d_manipulator_ruler.c create mode 100644 source/blender/editors/transform/transform_gizmo_2d.c create mode 100644 source/blender/editors/transform/transform_gizmo_3d.c delete mode 100644 source/blender/editors/transform/transform_manipulator_2d.c delete mode 100644 source/blender/editors/transform/transform_manipulator_3d.c (limited to 'source/blender/editors') diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt index 2b30382f4a4..cf1db751c85 100644 --- a/source/blender/editors/CMakeLists.txt +++ b/source/blender/editors/CMakeLists.txt @@ -30,7 +30,7 @@ if(WITH_BLENDER) add_subdirectory(interface) add_subdirectory(io) add_subdirectory(lattice) - add_subdirectory(manipulator_library) + add_subdirectory(gizmo_library) add_subdirectory(mask) add_subdirectory(mesh) add_subdirectory(metaball) diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt new file mode 100644 index 00000000000..389820240e2 --- /dev/null +++ b/source/blender/editors/gizmo_library/CMakeLists.txt @@ -0,0 +1,60 @@ +# ***** 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 ***** + +set(INC + ../include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../bmesh + ../../depsgraph + ../../gpu + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc + ../../../../intern/eigen + ../../../../intern/glew-mx +) + +set(INC_SYS + ${GLEW_INCLUDE_PATH} +) + +set(SRC + gizmo_draw_utils.c + gizmo_geometry.h + gizmo_library_intern.h + gizmo_library_presets.c + gizmo_library_utils.c + geometry/geom_arrow_gizmo.c + geometry/geom_cube_gizmo.c + geometry/geom_dial_gizmo.c + gizmo_types/arrow2d_gizmo.c + gizmo_types/arrow3d_gizmo.c + gizmo_types/button2d_gizmo.c + gizmo_types/cage2d_gizmo.c + gizmo_types/cage3d_gizmo.c + gizmo_types/dial3d_gizmo.c + gizmo_types/grab3d_gizmo.c + gizmo_types/primitive3d_gizmo.c +) + +add_definitions(${GL_DEFINITIONS}) + +blender_add_lib(bf_editor_gizmo_library "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c new file mode 100644 index 00000000000..e8804238590 --- /dev/null +++ b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c @@ -0,0 +1,141 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file geom_arrow_gizmo.c + * \ingroup wm + */ + +#include "../gizmo_geometry.h" + +static float verts[][3] = { + {-0.000000, 0.012320, 0.000000}, + {-0.000000, 0.012320, 0.974306}, + {0.008711, 0.008711, 0.000000}, + {0.008711, 0.008711, 0.974306}, + {0.012320, -0.000000, 0.000000}, + {0.012320, -0.000000, 0.974306}, + {0.008711, -0.008711, 0.000000}, + {0.008711, -0.008711, 0.974306}, + {-0.000000, -0.012320, 0.000000}, + {-0.000000, -0.012320, 0.974306}, + {-0.008711, -0.008711, 0.000000}, + {-0.008711, -0.008711, 0.974306}, + {-0.012320, 0.000000, 0.000000}, + {-0.012320, 0.000000, 0.974306}, + {-0.008711, 0.008711, 0.000000}, + {-0.008711, 0.008711, 0.974306}, + {0.000000, 0.072555, 0.974306}, + {0.051304, 0.051304, 0.974306}, + {0.072555, -0.000000, 0.974306}, + {0.051304, -0.051304, 0.974306}, + {-0.000000, -0.072555, 0.974306}, + {-0.051304, -0.051304, 0.974306}, + {-0.072555, 0.000000, 0.974306}, + {-0.051304, 0.051304, 0.974306}, + {0.000000, -0.000000, 1.268098}, +}; + +static float normals[][3] = { + {0.000000, 0.776360, -0.630238}, + {0.000000, 0.594348, -0.804163}, + {0.548967, 0.548967, -0.630238}, + {0.420270, 0.420270, -0.804163}, + {0.776360, 0.000000, -0.630238}, + {0.594378, 0.000000, -0.804163}, + {0.548967, -0.548967, -0.630238}, + {0.420270, -0.420270, -0.804163}, + {0.000000, -0.776360, -0.630238}, + {0.000000, -0.594378, -0.804163}, + {-0.548967, -0.548967, -0.630238}, + {-0.420270, -0.420270, -0.804163}, + {-0.776360, 0.000000, -0.630238}, + {-0.594378, 0.000000, -0.804163}, + {-0.548967, 0.548967, -0.630238}, + {-0.420270, 0.420270, -0.804163}, + {0.000000, 0.843226, -0.537492}, + {0.596271, 0.596271, -0.537492}, + {0.843226, 0.000000, -0.537492}, + {0.596271, -0.596271, -0.537492}, + {0.000000, -0.843226, -0.537492}, + {-0.596271, -0.596271, -0.537492}, + {-0.843226, 0.000000, -0.537492}, + {-0.596271, 0.596271, -0.537492}, + {0.000000, 0.000000, 1.000000}, +}; + +static unsigned short indices[] = { + 1, 3, 2, + 3, 5, 4, + 5, 7, 6, + 7, 9, 8, + 9, 11, 10, + 11, 13, 12, + 5, 18, 19, + 15, 1, 0, + 13, 15, 14, + 6, 10, 14, + 11, 21, 22, + 7, 19, 20, + 13, 22, 23, + 3, 17, 18, + 9, 20, 21, + 15, 23, 16, + 1, 16, 17, + 23, 22, 24, + 21, 20, 24, + 19, 18, 24, + 17, 16, 24, + 16, 23, 24, + 22, 21, 24, + 20, 19, 24, + 18, 17, 24, + 0, 1, 2, + 2, 3, 4, + 4, 5, 6, + 6, 7, 8, + 8, 9, 10, + 10, 11, 12, + 7, 5, 19, + 14, 15, 0, + 12, 13, 14, + 14, 0, 2, + 2, 4, 6, + 6, 8, 10, + 10, 12, 14, + 14, 2, 6, + 13, 11, 22, + 9, 7, 20, + 15, 13, 23, + 5, 3, 18, + 11, 9, 21, + 1, 15, 16, + 3, 1, 17, +}; + +ManipulatorGeomInfo wm_manipulator_geom_data_arrow = { + .nverts = 25, + .ntris = 46, + .verts = verts, + .normals = normals, + .indices = indices, +}; diff --git a/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c new file mode 100644 index 00000000000..f2d03821302 --- /dev/null +++ b/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c @@ -0,0 +1,75 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file geom_cube_gizmo.c + * \ingroup wm + */ + +#include "../gizmo_geometry.h" + +static const float verts[][3] = { + {1.000000, 1.000000, -1.000000}, + {1.000000, -1.000000, -1.000000}, + {-1.000000, -1.000000, -1.000000}, + {-1.000000, 1.000000, -1.000000}, + {1.000000, 1.000000, 1.000000}, + {0.999999, -1.000001, 1.000000}, + {-1.000000, -1.000000, 1.000000}, + {-1.000000, 1.000000, 1.000000}, +}; + +static const float normals[][3] = { + {0.577349, 0.577349, -0.577349}, + {0.577349, -0.577349, -0.577349}, + {-0.577349, -0.577349, -0.577349}, + {-0.577349, 0.577349, -0.577349}, + {0.577349, 0.577349, 0.577349}, + {0.577349, -0.577349, 0.577349}, + {-0.577349, -0.577349, 0.577349}, + {-0.577349, 0.577349, 0.577349}, +}; + +static const unsigned short indices[] = { + 1, 2, 3, + 7, 6, 5, + 4, 5, 1, + 5, 6, 2, + 2, 6, 7, + 0, 3, 7, + 0, 1, 3, + 4, 7, 5, + 0, 4, 1, + 1, 5, 2, + 3, 2, 7, + 4, 0, 7, +}; + +ManipulatorGeomInfo wm_manipulator_geom_data_cube = { + .nverts = 8, + .ntris = 12, + .verts = verts, + .normals = normals, + .indices = indices, +}; diff --git a/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c new file mode 100644 index 00000000000..bc3fb6fcaff --- /dev/null +++ b/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c @@ -0,0 +1,813 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file geom_dial_gizmo.c + * \ingroup wm + */ + +#include "../gizmo_geometry.h" + +static const float verts[][3] = { + {1.034000, 0.000000, 0.000000}, + {1.017000, 0.000000, 0.029445}, + {0.983000, 0.000000, 0.029445}, + {0.966000, 0.000000, 0.000000}, + {0.983000, 0.000000, -0.029445}, + {1.017000, 0.000000, -0.029445}, + {1.014132, 0.201723, 0.000000}, + {0.997459, 0.198407, 0.029445}, + {0.964112, 0.191774, 0.029445}, + {0.947439, 0.188457, 0.000000}, + {0.964112, 0.191774, -0.029445}, + {0.997459, 0.198407, -0.029445}, + {0.955292, 0.395695, 0.000000}, + {0.939586, 0.389189, 0.029445}, + {0.908174, 0.376178, 0.029445}, + {0.892468, 0.369672, 0.000000}, + {0.908174, 0.376178, -0.029445}, + {0.939586, 0.389189, -0.029445}, + {0.859740, 0.574460, 0.000000}, + {0.845605, 0.565015, 0.029445}, + {0.817335, 0.546126, 0.029445}, + {0.803200, 0.536681, 0.000000}, + {0.817335, 0.546126, -0.029445}, + {0.845605, 0.565015, -0.029445}, + {0.731148, 0.731148, 0.000000}, + {0.719128, 0.719128, 0.029445}, + {0.695086, 0.695086, 0.029445}, + {0.683065, 0.683065, 0.000000}, + {0.695086, 0.695086, -0.029445}, + {0.719128, 0.719128, -0.029445}, + {0.574460, 0.859740, 0.000000}, + {0.565015, 0.845605, 0.029445}, + {0.546125, 0.817335, 0.029445}, + {0.536681, 0.803200, 0.000000}, + {0.546125, 0.817335, -0.029445}, + {0.565015, 0.845605, -0.029445}, + {0.395695, 0.955291, 0.000000}, + {0.389189, 0.939585, 0.029445}, + {0.376178, 0.908173, 0.029445}, + {0.369672, 0.892467, 0.000000}, + {0.376178, 0.908173, -0.029445}, + {0.389189, 0.939585, -0.029445}, + {0.201724, 1.014132, 0.000000}, + {0.198407, 0.997459, 0.029445}, + {0.191774, 0.964112, 0.029445}, + {0.188457, 0.947439, 0.000000}, + {0.191774, 0.964112, -0.029445}, + {0.198407, 0.997459, -0.029445}, + {0.000000, 1.034000, 0.000000}, + {0.000000, 1.017000, 0.029445}, + {0.000000, 0.983000, 0.029445}, + {0.000000, 0.966000, 0.000000}, + {0.000000, 0.983000, -0.029445}, + {0.000000, 1.017000, -0.029445}, + {-0.201723, 1.014132, 0.000000}, + {-0.198407, 0.997459, 0.029445}, + {-0.191774, 0.964112, 0.029445}, + {-0.188457, 0.947439, 0.000000}, + {-0.191774, 0.964112, -0.029445}, + {-0.198407, 0.997459, -0.029445}, + {-0.395695, 0.955291, 0.000000}, + {-0.389189, 0.939585, 0.029445}, + {-0.376178, 0.908174, 0.029445}, + {-0.369672, 0.892468, 0.000000}, + {-0.376178, 0.908174, -0.029445}, + {-0.389189, 0.939585, -0.029445}, + {-0.574459, 0.859740, 0.000000}, + {-0.565015, 0.845605, 0.029445}, + {-0.546125, 0.817335, 0.029445}, + {-0.536681, 0.803200, 0.000000}, + {-0.546125, 0.817335, -0.029445}, + {-0.565015, 0.845605, -0.029445}, + {-0.731149, 0.731148, 0.000000}, + {-0.719128, 0.719127, 0.029445}, + {-0.695086, 0.695086, 0.029445}, + {-0.683065, 0.683065, 0.000000}, + {-0.695086, 0.695086, -0.029445}, + {-0.719128, 0.719127, -0.029445}, + {-0.859740, 0.574460, 0.000000}, + {-0.845604, 0.565015, 0.029445}, + {-0.817335, 0.546126, 0.029445}, + {-0.803200, 0.536681, 0.000000}, + {-0.817335, 0.546126, -0.029445}, + {-0.845604, 0.565015, -0.029445}, + {-0.955291, 0.395695, 0.000000}, + {-0.939585, 0.389189, 0.029445}, + {-0.908173, 0.376178, 0.029445}, + {-0.892468, 0.369672, 0.000000}, + {-0.908173, 0.376178, -0.029445}, + {-0.939585, 0.389189, -0.029445}, + {-1.014132, 0.201723, 0.000000}, + {-0.997459, 0.198407, 0.029445}, + {-0.964112, 0.191774, 0.029445}, + {-0.947439, 0.188457, 0.000000}, + {-0.964112, 0.191774, -0.029445}, + {-0.997459, 0.198407, -0.029445}, + {-1.034000, 0.000000, 0.000000}, + {-1.017000, 0.000000, 0.029445}, + {-0.983000, 0.000000, 0.029445}, + {-0.966000, 0.000000, 0.000000}, + {-0.983000, 0.000000, -0.029445}, + {-1.017000, 0.000000, -0.029445}, + {-1.014132, -0.201723, 0.000000}, + {-0.997459, -0.198407, 0.029445}, + {-0.964112, -0.191774, 0.029445}, + {-0.947439, -0.188457, 0.000000}, + {-0.964112, -0.191774, -0.029445}, + {-0.997459, -0.198407, -0.029445}, + {-0.955292, -0.395694, 0.000000}, + {-0.939586, -0.389189, 0.029445}, + {-0.908174, -0.376177, 0.029445}, + {-0.892468, -0.369672, 0.000000}, + {-0.908174, -0.376177, -0.029445}, + {-0.939586, -0.389189, -0.029445}, + {-0.859740, -0.574460, 0.000000}, + {-0.845604, -0.565015, 0.029445}, + {-0.817335, -0.546126, 0.029445}, + {-0.803200, -0.536681, 0.000000}, + {-0.817335, -0.546126, -0.029445}, + {-0.845604, -0.565015, -0.029445}, + {-0.731149, -0.731148, 0.000000}, + {-0.719128, -0.719127, 0.029445}, + {-0.695086, -0.695086, 0.029445}, + {-0.683065, -0.683065, 0.000000}, + {-0.695086, -0.695086, -0.029445}, + {-0.719128, -0.719127, -0.029445}, + {-0.574460, -0.859739, 0.000000}, + {-0.565015, -0.845604, 0.029445}, + {-0.546126, -0.817334, 0.029445}, + {-0.536681, -0.803199, 0.000000}, + {-0.546126, -0.817334, -0.029445}, + {-0.565015, -0.845604, -0.029445}, + {-0.395695, -0.955291, 0.000000}, + {-0.389189, -0.939585, 0.029445}, + {-0.376178, -0.908174, 0.029445}, + {-0.369672, -0.892468, 0.000000}, + {-0.376178, -0.908174, -0.029445}, + {-0.389189, -0.939585, -0.029445}, + {-0.201724, -1.014132, 0.000000}, + {-0.198407, -0.997459, 0.029445}, + {-0.191774, -0.964112, 0.029445}, + {-0.188458, -0.947438, 0.000000}, + {-0.191774, -0.964112, -0.029445}, + {-0.198407, -0.997459, -0.029445}, + {0.000000, -1.034000, 0.000000}, + {0.000000, -1.017000, 0.029445}, + {0.000000, -0.983000, 0.029445}, + {0.000000, -0.966000, 0.000000}, + {0.000000, -0.983000, -0.029445}, + {0.000000, -1.017000, -0.029445}, + {0.201723, -1.014132, 0.000000}, + {0.198407, -0.997459, 0.029445}, + {0.191773, -0.964112, 0.029445}, + {0.188457, -0.947439, 0.000000}, + {0.191773, -0.964112, -0.029445}, + {0.198407, -0.997459, -0.029445}, + {0.395695, -0.955291, 0.000000}, + {0.389189, -0.939585, 0.029445}, + {0.376178, -0.908173, 0.029445}, + {0.369672, -0.892467, 0.000000}, + {0.376178, -0.908173, -0.029445}, + {0.389189, -0.939585, -0.029445}, + {0.574460, -0.859740, 0.000000}, + {0.565015, -0.845605, 0.029445}, + {0.546125, -0.817335, 0.029445}, + {0.536681, -0.803200, 0.000000}, + {0.546125, -0.817335, -0.029445}, + {0.565015, -0.845605, -0.029445}, + {0.731148, -0.731149, 0.000000}, + {0.719127, -0.719128, 0.029445}, + {0.695086, -0.695086, 0.029445}, + {0.683065, -0.683066, 0.000000}, + {0.695086, -0.695086, -0.029445}, + {0.719127, -0.719128, -0.029445}, + {0.859740, -0.574460, 0.000000}, + {0.845605, -0.565015, 0.029445}, + {0.817335, -0.546126, 0.029445}, + {0.803200, -0.536681, 0.000000}, + {0.817335, -0.546126, -0.029445}, + {0.845605, -0.565015, -0.029445}, + {0.955291, -0.395695, 0.000000}, + {0.939585, -0.389189, 0.029445}, + {0.908173, -0.376178, 0.029445}, + {0.892467, -0.369673, 0.000000}, + {0.908173, -0.376178, -0.029445}, + {0.939585, -0.389189, -0.029445}, + {1.014132, -0.201723, 0.000000}, + {0.997459, -0.198407, 0.029445}, + {0.964112, -0.191774, 0.029445}, + {0.947439, -0.188457, 0.000000}, + {0.964112, -0.191774, -0.029445}, + {0.997459, -0.198407, -0.029445}, +}; + +static const float normals[][3] = { + {1.000000, 0.000000, 0.000000}, + {0.522691, 0.000000, 0.852504}, + {-0.475845, 0.000000, 0.879513}, + {-1.000000, 0.000000, 0.000000}, + {-0.475845, 0.000000, -0.879513}, + {0.522691, 0.000000, -0.852504}, + {0.980773, 0.195074, 0.000000}, + {0.512650, 0.101962, 0.852504}, + {-0.466689, -0.092807, 0.879513}, + {-0.980773, -0.195074, 0.000000}, + {-0.466689, -0.092807, -0.879513}, + {0.512650, 0.101962, -0.852504}, + {0.923856, 0.382672, 0.000000}, + {0.482894, 0.200018, 0.852504}, + {-0.439619, -0.182073, 0.879513}, + {-0.923856, -0.382672, 0.000000}, + {-0.439619, -0.182073, -0.879513}, + {0.482894, 0.200018, -0.852504}, + {0.831446, 0.555559, 0.000000}, + {0.434614, 0.290384, 0.852504}, + {-0.395642, -0.264351, 0.879513}, + {-0.831446, -0.555559, 0.000000}, + {-0.395642, -0.264351, -0.879513}, + {0.434614, 0.290384, -0.852504}, + {0.707083, 0.707083, 0.000000}, + {0.369610, 0.369610, 0.852504}, + {-0.336467, -0.336467, 0.879513}, + {-0.707083, -0.707083, 0.000000}, + {-0.336467, -0.336467, -0.879513}, + {0.369610, 0.369610, -0.852504}, + {0.555559, 0.831446, 0.000000}, + {0.290384, 0.434614, 0.852504}, + {-0.264351, -0.395642, 0.879513}, + {-0.555559, -0.831446, 0.000000}, + {-0.264351, -0.395642, -0.879513}, + {0.290384, 0.434614, -0.852504}, + {0.382672, 0.923856, 0.000000}, + {0.200018, 0.482894, 0.852504}, + {-0.182073, -0.439619, 0.879513}, + {-0.382672, -0.923856, 0.000000}, + {-0.182073, -0.439619, -0.879513}, + {0.200018, 0.482894, -0.852504}, + {0.195074, 0.980773, 0.000000}, + {0.101962, 0.512650, 0.852504}, + {-0.092807, -0.466689, 0.879513}, + {-0.195074, -0.980773, 0.000000}, + {-0.092807, -0.466689, -0.879513}, + {0.101962, 0.512650, -0.852504}, + {0.000000, 1.000000, 0.000000}, + {0.000000, 0.522691, 0.852504}, + {0.000000, -0.475845, 0.879513}, + {0.000000, -1.000000, 0.000000}, + {0.000000, -0.475845, -0.879513}, + {0.000000, 0.522691, -0.852504}, + {-0.195074, 0.980773, 0.000000}, + {-0.101962, 0.512650, 0.852504}, + {0.092807, -0.466689, 0.879513}, + {0.195074, -0.980773, 0.000000}, + {0.092807, -0.466689, -0.879513}, + {-0.101962, 0.512650, -0.852504}, + {-0.382672, 0.923856, 0.000000}, + {-0.200018, 0.482894, 0.852504}, + {0.182073, -0.439619, 0.879513}, + {0.382672, -0.923856, 0.000000}, + {0.182073, -0.439619, -0.879513}, + {-0.200018, 0.482894, -0.852504}, + {-0.555559, 0.831446, 0.000000}, + {-0.290384, 0.434614, 0.852504}, + {0.264351, -0.395642, 0.879513}, + {0.555559, -0.831446, 0.000000}, + {0.264351, -0.395642, -0.879513}, + {-0.290384, 0.434614, -0.852504}, + {-0.707083, 0.707083, 0.000000}, + {-0.369610, 0.369610, 0.852504}, + {0.336467, -0.336467, 0.879513}, + {0.707083, -0.707083, 0.000000}, + {0.336467, -0.336467, -0.879513}, + {-0.369610, 0.369610, -0.852504}, + {-0.831446, 0.555559, 0.000000}, + {-0.434614, 0.290384, 0.852504}, + {0.395642, -0.264351, 0.879513}, + {0.831446, -0.555559, 0.000000}, + {0.395642, -0.264351, -0.879513}, + {-0.434614, 0.290384, -0.852504}, + {-0.923856, 0.382672, 0.000000}, + {-0.482894, 0.200018, 0.852504}, + {0.439619, -0.182073, 0.879513}, + {0.923856, -0.382672, 0.000000}, + {0.439619, -0.182073, -0.879513}, + {-0.482894, 0.200018, -0.852504}, + {-0.980773, 0.195074, 0.000000}, + {-0.512650, 0.101962, 0.852504}, + {0.466689, -0.092807, 0.879513}, + {0.980773, -0.195074, 0.000000}, + {0.466689, -0.092807, -0.879513}, + {-0.512650, 0.101962, -0.852504}, + {-1.000000, 0.000000, 0.000000}, + {-0.522691, 0.000000, 0.852504}, + {0.475845, 0.000000, 0.879513}, + {1.000000, 0.000000, 0.000000}, + {0.475845, 0.000000, -0.879513}, + {-0.522691, 0.000000, -0.852504}, + {-0.980773, -0.195074, 0.000000}, + {-0.512650, -0.101962, 0.852504}, + {0.466689, 0.092807, 0.879513}, + {0.980773, 0.195074, 0.000000}, + {0.466689, 0.092807, -0.879513}, + {-0.512650, -0.101962, -0.852504}, + {-0.923856, -0.382672, 0.000000}, + {-0.482894, -0.200018, 0.852504}, + {0.439619, 0.182073, 0.879513}, + {0.923856, 0.382672, 0.000000}, + {0.439619, 0.182073, -0.879513}, + {-0.482894, -0.200018, -0.852504}, + {-0.831446, -0.555559, 0.000000}, + {-0.434614, -0.290384, 0.852504}, + {0.395642, 0.264351, 0.879513}, + {0.831446, 0.555559, 0.000000}, + {0.395642, 0.264351, -0.879513}, + {-0.434614, -0.290384, -0.852504}, + {-0.707083, -0.707083, 0.000000}, + {-0.369610, -0.369610, 0.852504}, + {0.336467, 0.336467, 0.879513}, + {0.707083, 0.707083, 0.000000}, + {0.336467, 0.336467, -0.879513}, + {-0.369610, -0.369610, -0.852504}, + {-0.555559, -0.831446, 0.000000}, + {-0.290384, -0.434614, 0.852504}, + {0.264351, 0.395642, 0.879513}, + {0.555559, 0.831446, 0.000000}, + {0.264351, 0.395642, -0.879513}, + {-0.290384, -0.434614, -0.852504}, + {-0.382672, -0.923856, 0.000000}, + {-0.200018, -0.482894, 0.852504}, + {0.182073, 0.439619, 0.879513}, + {0.382672, 0.923856, 0.000000}, + {0.182073, 0.439619, -0.879513}, + {-0.200018, -0.482894, -0.852504}, + {-0.195074, -0.980773, 0.000000}, + {-0.101962, -0.512650, 0.852504}, + {0.092807, 0.466689, 0.879513}, + {0.195074, 0.980773, 0.000000}, + {0.092807, 0.466689, -0.879513}, + {-0.101962, -0.512650, -0.852504}, + {0.000000, -1.000000, 0.000000}, + {0.000000, -0.522691, 0.852504}, + {0.000000, 0.475845, 0.879513}, + {0.000000, 1.000000, 0.000000}, + {0.000000, 0.475845, -0.879513}, + {0.000000, -0.522691, -0.852504}, + {0.195074, -0.980773, 0.000000}, + {0.101962, -0.512650, 0.852504}, + {-0.092807, 0.466689, 0.879513}, + {-0.195074, 0.980773, 0.000000}, + {-0.092807, 0.466689, -0.879513}, + {0.101962, -0.512650, -0.852504}, + {0.382672, -0.923856, 0.000000}, + {0.200018, -0.482894, 0.852504}, + {-0.182073, 0.439619, 0.879513}, + {-0.382672, 0.923856, 0.000000}, + {-0.182073, 0.439619, -0.879513}, + {0.200018, -0.482894, -0.852504}, + {0.555559, -0.831446, 0.000000}, + {0.290384, -0.434614, 0.852504}, + {-0.264351, 0.395642, 0.879513}, + {-0.555559, 0.831446, 0.000000}, + {-0.264351, 0.395642, -0.879513}, + {0.290384, -0.434614, -0.852504}, + {0.707083, -0.707083, 0.000000}, + {0.369610, -0.369610, 0.852504}, + {-0.336467, 0.336467, 0.879513}, + {-0.707083, 0.707083, 0.000000}, + {-0.336467, 0.336467, -0.879513}, + {0.369610, -0.369610, -0.852504}, + {0.831446, -0.555559, 0.000000}, + {0.434614, -0.290384, 0.852504}, + {-0.395642, 0.264351, 0.879513}, + {-0.831446, 0.555559, 0.000000}, + {-0.395642, 0.264351, -0.879513}, + {0.434614, -0.290384, -0.852504}, + {0.923856, -0.382672, 0.000000}, + {0.482894, -0.200018, 0.852504}, + {-0.439619, 0.182073, 0.879513}, + {-0.923856, 0.382672, 0.000000}, + {-0.439619, 0.182073, -0.879513}, + {0.482894, -0.200018, -0.852504}, + {0.980773, -0.195074, 0.000000}, + {0.512650, -0.101962, 0.852504}, + {-0.466689, 0.092807, 0.879513}, + {-0.980773, 0.195074, 0.000000}, + {-0.466689, 0.092807, -0.879513}, + {0.512650, -0.101962, -0.852504}, +}; + +static const unsigned short indices[] = { + 6, 7, 1, + 7, 8, 2, + 8, 9, 3, + 9, 10, 4, + 10, 11, 5, + 5, 11, 6, + 12, 13, 7, + 13, 14, 8, + 14, 15, 9, + 15, 16, 10, + 16, 17, 11, + 11, 17, 12, + 18, 19, 13, + 13, 19, 20, + 20, 21, 15, + 15, 21, 22, + 22, 23, 17, + 17, 23, 18, + 24, 25, 19, + 19, 25, 26, + 26, 27, 21, + 21, 27, 28, + 28, 29, 23, + 23, 29, 24, + 30, 31, 25, + 25, 31, 32, + 26, 32, 33, + 27, 33, 34, + 34, 35, 29, + 29, 35, 30, + 36, 37, 31, + 31, 37, 38, + 38, 39, 33, + 39, 40, 34, + 40, 41, 35, + 35, 41, 36, + 36, 42, 43, + 43, 44, 38, + 44, 45, 39, + 45, 46, 40, + 46, 47, 41, + 47, 42, 36, + 48, 49, 43, + 49, 50, 44, + 50, 51, 45, + 51, 52, 46, + 52, 53, 47, + 47, 53, 48, + 54, 55, 49, + 49, 55, 56, + 50, 56, 57, + 57, 58, 52, + 58, 59, 53, + 53, 59, 54, + 60, 61, 55, + 55, 61, 62, + 56, 62, 63, + 63, 64, 58, + 64, 65, 59, + 59, 65, 60, + 66, 67, 61, + 61, 67, 68, + 68, 69, 63, + 69, 70, 64, + 70, 71, 65, + 71, 66, 60, + 72, 73, 67, + 73, 74, 68, + 68, 74, 75, + 75, 76, 70, + 76, 77, 71, + 71, 77, 72, + 78, 79, 73, + 79, 80, 74, + 74, 80, 81, + 81, 82, 76, + 82, 83, 77, + 83, 78, 72, + 78, 84, 85, + 85, 86, 80, + 80, 86, 87, + 87, 88, 82, + 82, 88, 89, + 89, 84, 78, + 90, 91, 85, + 91, 92, 86, + 86, 92, 93, + 93, 94, 88, + 88, 94, 95, + 95, 90, 84, + 96, 97, 91, + 97, 98, 92, + 98, 99, 93, + 99, 100, 94, + 100, 101, 95, + 101, 96, 90, + 102, 103, 97, + 103, 104, 98, + 104, 105, 99, + 99, 105, 106, + 106, 107, 101, + 101, 107, 102, + 108, 109, 103, + 103, 109, 110, + 110, 111, 105, + 105, 111, 112, + 112, 113, 107, + 107, 113, 108, + 114, 115, 109, + 115, 116, 110, + 116, 117, 111, + 111, 117, 118, + 112, 118, 119, + 113, 119, 114, + 114, 120, 121, + 121, 122, 116, + 122, 123, 117, + 117, 123, 124, + 124, 125, 119, + 125, 120, 114, + 126, 127, 121, + 121, 127, 128, + 128, 129, 123, + 123, 129, 130, + 130, 131, 125, + 125, 131, 126, + 132, 133, 127, + 133, 134, 128, + 128, 134, 135, + 135, 136, 130, + 136, 137, 131, + 131, 137, 132, + 132, 138, 139, + 133, 139, 140, + 134, 140, 141, + 141, 142, 136, + 142, 143, 137, + 143, 138, 132, + 138, 144, 145, + 139, 145, 146, + 146, 147, 141, + 141, 147, 148, + 148, 149, 143, + 149, 144, 138, + 144, 150, 151, + 151, 152, 146, + 146, 152, 153, + 153, 154, 148, + 154, 155, 149, + 155, 150, 144, + 156, 157, 151, + 151, 157, 158, + 158, 159, 153, + 159, 160, 154, + 160, 161, 155, + 155, 161, 156, + 156, 162, 163, + 163, 164, 158, + 158, 164, 165, + 165, 166, 160, + 160, 166, 167, + 167, 162, 156, + 162, 168, 169, + 169, 170, 164, + 164, 170, 171, + 165, 171, 172, + 166, 172, 173, + 173, 168, 162, + 174, 175, 169, + 175, 176, 170, + 170, 176, 177, + 177, 178, 172, + 172, 178, 179, + 173, 179, 174, + 174, 180, 181, + 181, 182, 176, + 176, 182, 183, + 183, 184, 178, + 178, 184, 185, + 179, 185, 180, + 186, 187, 181, + 187, 188, 182, + 188, 189, 183, + 183, 189, 190, + 190, 191, 185, + 191, 186, 180, + 0, 1, 187, + 1, 2, 188, + 2, 3, 189, + 3, 4, 190, + 190, 4, 5, + 191, 5, 0, + 0, 6, 1, + 1, 7, 2, + 2, 8, 3, + 3, 9, 4, + 4, 10, 5, + 0, 5, 6, + 6, 12, 7, + 7, 13, 8, + 8, 14, 9, + 9, 15, 10, + 10, 16, 11, + 6, 11, 12, + 12, 18, 13, + 14, 13, 20, + 14, 20, 15, + 16, 15, 22, + 16, 22, 17, + 12, 17, 18, + 18, 24, 19, + 20, 19, 26, + 20, 26, 21, + 22, 21, 28, + 22, 28, 23, + 18, 23, 24, + 24, 30, 25, + 26, 25, 32, + 27, 26, 33, + 28, 27, 34, + 28, 34, 29, + 24, 29, 30, + 30, 36, 31, + 32, 31, 38, + 32, 38, 33, + 33, 39, 34, + 34, 40, 35, + 30, 35, 36, + 37, 36, 43, + 37, 43, 38, + 38, 44, 39, + 39, 45, 40, + 40, 46, 41, + 41, 47, 36, + 42, 48, 43, + 43, 49, 44, + 44, 50, 45, + 45, 51, 46, + 46, 52, 47, + 42, 47, 48, + 48, 54, 49, + 50, 49, 56, + 51, 50, 57, + 51, 57, 52, + 52, 58, 53, + 48, 53, 54, + 54, 60, 55, + 56, 55, 62, + 57, 56, 63, + 57, 63, 58, + 58, 64, 59, + 54, 59, 60, + 60, 66, 61, + 62, 61, 68, + 62, 68, 63, + 63, 69, 64, + 64, 70, 65, + 65, 71, 60, + 66, 72, 67, + 67, 73, 68, + 69, 68, 75, + 69, 75, 70, + 70, 76, 71, + 66, 71, 72, + 72, 78, 73, + 73, 79, 74, + 75, 74, 81, + 75, 81, 76, + 76, 82, 77, + 77, 83, 72, + 79, 78, 85, + 79, 85, 80, + 81, 80, 87, + 81, 87, 82, + 83, 82, 89, + 83, 89, 78, + 84, 90, 85, + 85, 91, 86, + 87, 86, 93, + 87, 93, 88, + 89, 88, 95, + 89, 95, 84, + 90, 96, 91, + 91, 97, 92, + 92, 98, 93, + 93, 99, 94, + 94, 100, 95, + 95, 101, 90, + 96, 102, 97, + 97, 103, 98, + 98, 104, 99, + 100, 99, 106, + 100, 106, 101, + 96, 101, 102, + 102, 108, 103, + 104, 103, 110, + 104, 110, 105, + 106, 105, 112, + 106, 112, 107, + 102, 107, 108, + 108, 114, 109, + 109, 115, 110, + 110, 116, 111, + 112, 111, 118, + 113, 112, 119, + 108, 113, 114, + 115, 114, 121, + 115, 121, 116, + 116, 122, 117, + 118, 117, 124, + 118, 124, 119, + 119, 125, 114, + 120, 126, 121, + 122, 121, 128, + 122, 128, 123, + 124, 123, 130, + 124, 130, 125, + 120, 125, 126, + 126, 132, 127, + 127, 133, 128, + 129, 128, 135, + 129, 135, 130, + 130, 136, 131, + 126, 131, 132, + 133, 132, 139, + 134, 133, 140, + 135, 134, 141, + 135, 141, 136, + 136, 142, 137, + 137, 143, 132, + 139, 138, 145, + 140, 139, 146, + 140, 146, 141, + 142, 141, 148, + 142, 148, 143, + 143, 149, 138, + 145, 144, 151, + 145, 151, 146, + 147, 146, 153, + 147, 153, 148, + 148, 154, 149, + 149, 155, 144, + 150, 156, 151, + 152, 151, 158, + 152, 158, 153, + 153, 159, 154, + 154, 160, 155, + 150, 155, 156, + 157, 156, 163, + 157, 163, 158, + 159, 158, 165, + 159, 165, 160, + 161, 160, 167, + 161, 167, 156, + 163, 162, 169, + 163, 169, 164, + 165, 164, 171, + 166, 165, 172, + 167, 166, 173, + 167, 173, 162, + 168, 174, 169, + 169, 175, 170, + 171, 170, 177, + 171, 177, 172, + 173, 172, 179, + 168, 173, 174, + 175, 174, 181, + 175, 181, 176, + 177, 176, 183, + 177, 183, 178, + 179, 178, 185, + 174, 179, 180, + 180, 186, 181, + 181, 187, 182, + 182, 188, 183, + 184, 183, 190, + 184, 190, 185, + 185, 191, 180, + 186, 0, 187, + 187, 1, 188, + 188, 2, 189, + 189, 3, 190, + 191, 190, 5, + 186, 191, 0, +}; + +ManipulatorGeomInfo wm_manipulator_geom_data_dial = { + .nverts = 192, + .ntris = 384, + .verts = verts, + .normals = normals, + .indices = indices, +}; diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c new file mode 100644 index 00000000000..8ae21f61758 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c @@ -0,0 +1,121 @@ +/* + * ***** 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 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gizmo_draw_utils.c + * \ingroup wm + */ + +#include "BLI_listbase.h" +#include "BLI_ghash.h" +#include "BLI_math.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" + +#include "BKE_context.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "GPU_batch.h" +#include "GPU_glew.h" +#include "GPU_immediate.h" +#include "GPU_state.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +/* only for own init/exit calls (wm_manipulatortype_init/wm_manipulatortype_free) */ +#include "wm.h" + +/* own includes */ +#include "gizmo_library_intern.h" + +/** + * Main draw call for ManipulatorGeomInfo data + */ +void wm_manipulator_geometryinfo_draw(const ManipulatorGeomInfo *info, const bool UNUSED(select), const float color[4]) +{ + /* TODO store the Batches inside the ManipulatorGeomInfo and updated it when geom changes + * So we don't need to re-created and discard it every time */ + + Gwn_VertBuf *vbo; + Gwn_IndexBuf *el; + Gwn_Batch *batch; + Gwn_IndexBufBuilder elb = {0}; + + Gwn_VertFormat format = {0}; + uint pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + /* Elements */ + GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, info->ntris, info->nverts); + for (int i = 0; i < info->ntris; ++i) { + const unsigned short *idx = &info->indices[i * 3]; + GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]); + } + el = GWN_indexbuf_build(&elb); + + vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, info->nverts); + + GWN_vertbuf_attr_fill(vbo, pos_id, info->verts); + + batch = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, el, GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); + GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); + + GWN_batch_uniform_4fv(batch, "color", color); + + /* We may want to re-visit this, for now disable + * since it causes issues leaving the GL state modified. */ +#if 0 + glEnable(GL_CULL_FACE); + GPU_depth_test(true); +#endif + + GWN_batch_draw(batch); + +#if 0 + GPU_depth_test(false); + glDisable(GL_CULL_FACE); +#endif + + + GWN_batch_discard(batch); +} + +void wm_manipulator_vec_draw( + const float color[4], const float (*verts)[3], uint vert_count, + uint pos, uint primitive_type) +{ + immUniformColor4fv(color); + immBegin(primitive_type, vert_count); + for (int i = 0; i < vert_count; i++) { + immVertex3fv(pos, verts[i]); + } + immEnd(); +} diff --git a/source/blender/editors/gizmo_library/gizmo_geometry.h b/source/blender/editors/gizmo_library/gizmo_geometry.h new file mode 100644 index 00000000000..de976bbad48 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_geometry.h @@ -0,0 +1,54 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gizmo_geometry.h + * \ingroup wm + * + * \name Manipulator Geometry + * + * \brief Prototypes for arrays defining the manipulator geometry. The actual definitions can be found in files usually + * called geom_xxx_manipulator.c + */ + + +#ifndef __GIZMO_GEOMETRY_H__ +#define __GIZMO_GEOMETRY_H__ + +typedef struct ManipulatorGeomInfo { + int nverts; + int ntris; + const float (*verts)[3]; + const float (*normals)[3]; + const unsigned short *indices; +} ManipulatorGeomInfo; + +/* arrow manipulator */ +extern ManipulatorGeomInfo wm_manipulator_geom_data_arrow; + +/* cube manipulator */ +extern ManipulatorGeomInfo wm_manipulator_geom_data_cube; + +/* dial manipulator */ +extern ManipulatorGeomInfo wm_manipulator_geom_data_dial; + +#endif /* __GIZMO_GEOMETRY_H__ */ diff --git a/source/blender/editors/gizmo_library/gizmo_library_intern.h b/source/blender/editors/gizmo_library/gizmo_library_intern.h new file mode 100644 index 00000000000..17121d3752e --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_library_intern.h @@ -0,0 +1,111 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gizmo_library_intern.h + * \ingroup wm + */ + +#ifndef __GIZMO_LIBRARY_INTERN_H__ +#define __GIZMO_LIBRARY_INTERN_H__ + +/* distance around which manipulators respond to input (and get highlighted) */ +#define MANIPULATOR_HOTSPOT 14.0f + +/** + * Data for common interactions. Used in manipulator_library_utils.c functions. + */ +typedef struct ManipulatorCommonData { + int flag; + + float range_fac; /* factor for arrow min/max distance */ + float offset; + + /* property range for constrained manipulators */ + float range; + /* min/max value for constrained manipulators */ + float min, max; +} ManipulatorCommonData; + +typedef struct ManipulatorInteraction { + float init_value; /* initial property value */ + float init_mval[2]; + float init_offset; + float init_matrix_final[4][4]; + float init_matrix_basis[4][4]; + + /* offset of last handling step */ + float prev_offset; + /* Total offset added by precision tweaking. + * Needed to allow toggling precision on/off without causing jumps */ + float precision_offset; +} ManipulatorInteraction; + +/* ManipulatorCommonData->flag */ +enum { + MANIPULATOR_CUSTOM_RANGE_SET = (1 << 0), +}; + + +float manipulator_offset_from_value( + ManipulatorCommonData *data, const float value, + const bool constrained, const bool inverted); +float manipulator_value_from_offset( + ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset, + const bool constrained, const bool inverted, const bool use_precision); + +void manipulator_property_data_update( + struct wmManipulator *mpr, ManipulatorCommonData *data, wmManipulatorProperty *mpr_prop, + const bool constrained, const bool inverted); + +void manipulator_property_value_reset( + bContext *C, const struct wmManipulator *mpr, ManipulatorInteraction *inter, wmManipulatorProperty *mpr_prop); + + +/* -------------------------------------------------------------------- */ + +void manipulator_color_get( + const struct wmManipulator *mpr, const bool highlight, + float r_color[4]); + +bool manipulator_window_project_2d( + bContext *C, const struct wmManipulator *mpr, const float mval[2], int axis, bool use_offset, + float r_co[2]); + +bool manipulator_window_project_3d( + bContext *C, const struct wmManipulator *mpr, const float mval[2], bool use_offset, + float r_co[3]); + +/* -------------------------------------------------------------------- */ +/* Manipulator drawing */ + +#include "gizmo_geometry.h" + +void wm_manipulator_geometryinfo_draw(const struct ManipulatorGeomInfo *info, const bool select, const float color[4]); +void wm_manipulator_vec_draw( + const float color[4], const float (*verts)[3], uint vert_count, + uint pos, uint primitive_type); + + +#endif /* __GIZMO_LIBRARY_INTERN_H__ */ diff --git a/source/blender/editors/gizmo_library/gizmo_library_presets.c b/source/blender/editors/gizmo_library/gizmo_library_presets.c new file mode 100644 index 00000000000..d58e0c9dc85 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_library_presets.c @@ -0,0 +1,150 @@ +/* + * ***** 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/gizmo_library/gizmo_library_presets.c + * \ingroup wm + * + * \name Manipulator Lib Presets + * + * \brief Preset shapes that can be drawn from any manipulator type. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "DNA_view3d_types.h" +#include "DNA_object_types.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" + +#include "GPU_draw.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_select.h" + +#include "DEG_depsgraph.h" + +#include "RNA_access.h" + +#include "WM_types.h" +#include "WM_api.h" + +#include "ED_view3d.h" +#include "ED_screen.h" + +/* own includes */ +#include "ED_gizmo_library.h" /* own include */ +#include "gizmo_library_intern.h" /* own include */ + +/* TODO, this is to be used by RNA. might move to ED_manipulator_library */ + +/** + * Given a single axis, orient the matrix to a different direction. + */ +static void single_axis_convert( + int src_axis, float src_mat[4][4], + int dst_axis, float dst_mat[4][4]) +{ + copy_m4_m4(dst_mat, src_mat); + if (src_axis == dst_axis) { + return; + } + + float rotmat[3][3]; + mat3_from_axis_conversion_single(src_axis, dst_axis, rotmat); + transpose_m3(rotmat); + mul_m4_m4m3(dst_mat, src_mat, rotmat); +} + +/** + * Use for all geometry. + */ +static void ed_manipulator_draw_preset_geometry( + const struct wmManipulator *mpr, float mat[4][4], int select_id, + const ManipulatorGeomInfo *info) +{ + const bool is_select = (select_id != -1); + const bool is_highlight = is_select && (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + + float color[4]; + manipulator_color_get(mpr, is_highlight, color); + + if (is_select) { + GPU_select_load_id(select_id); + } + + gpuPushMatrix(); + gpuMultMatrix(mat); + wm_manipulator_geometryinfo_draw(info, is_select, color); + gpuPopMatrix(); + + if (is_select) { + GPU_select_load_id(-1); + } +} + +void ED_manipulator_draw_preset_box( + const struct wmManipulator *mpr, float mat[4][4], int select_id) +{ + ed_manipulator_draw_preset_geometry(mpr, mat, select_id, &wm_manipulator_geom_data_cube); +} + +void ED_manipulator_draw_preset_arrow( + const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id) +{ + float mat_rotate[4][4]; + single_axis_convert(OB_POSZ, mat, axis, mat_rotate); + ed_manipulator_draw_preset_geometry(mpr, mat_rotate, select_id, &wm_manipulator_geom_data_arrow); +} + +void ED_manipulator_draw_preset_circle( + const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id) +{ + float mat_rotate[4][4]; + single_axis_convert(OB_POSZ, mat, axis, mat_rotate); + ed_manipulator_draw_preset_geometry(mpr, mat_rotate, select_id, &wm_manipulator_geom_data_dial); +} + +void ED_manipulator_draw_preset_facemap( + const bContext *C, const struct wmManipulator *mpr, struct Scene *scene, Object *ob, const int facemap, int select_id) +{ + const bool is_select = (select_id != -1); + const bool is_highlight = is_select && (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + + float color[4]; + manipulator_color_get(mpr, is_highlight, color); + + if (is_select) { + GPU_select_load_id(select_id); + } + + gpuPushMatrix(); + gpuMultMatrix(ob->obmat); + ED_draw_object_facemap(CTX_data_depsgraph(C), scene, ob, color, facemap); + gpuPopMatrix(); + + if (is_select) { + GPU_select_load_id(-1); + } +} diff --git a/source/blender/editors/gizmo_library/gizmo_library_utils.c b/source/blender/editors/gizmo_library/gizmo_library_utils.c new file mode 100644 index 00000000000..794728dd03c --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_library_utils.c @@ -0,0 +1,256 @@ +/* + * ***** 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) 2015 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gizmo_library_utils.c + * \ingroup wm + * + * \name Manipulator Library Utilities + * + * \brief This file contains functions for common behaviors of manipulators. + */ + +#include "BLI_math.h" +#include "BLI_listbase.h" + +#include "DNA_view3d_types.h" +#include "DNA_screen_types.h" + +#include "BKE_context.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_view3d.h" + +/* own includes */ +#include "gizmo_library_intern.h" + +/* factor for precision tweaking */ +#define MANIPULATOR_PRECISION_FAC 0.05f + + +BLI_INLINE float manipulator_offset_from_value_constr( + const float range_fac, const float min, const float range, const float value, + const bool inverted) +{ + return inverted ? (range_fac * (min + range - value) / range) : (range_fac * (value / range)); +} + +BLI_INLINE float manipulator_value_from_offset_constr( + const float range_fac, const float min, const float range, const float value, + const bool inverted) +{ + return inverted ? (min + range - (value * range / range_fac)) : (value * range / range_fac); +} + +float manipulator_offset_from_value( + ManipulatorCommonData *data, const float value, const bool constrained, const bool inverted) +{ + if (constrained) + return manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted); + + return value; +} + +float manipulator_value_from_offset( + ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset, + const bool constrained, const bool inverted, const bool use_precision) +{ + const float max = data->min + data->range; + + if (use_precision) { + /* add delta offset of this step to total precision_offset */ + inter->precision_offset += offset - inter->prev_offset; + } + inter->prev_offset = offset; + + float ofs_new = inter->init_offset + offset - inter->precision_offset * (1.0f - MANIPULATOR_PRECISION_FAC); + float value; + + if (constrained) { + value = manipulator_value_from_offset_constr(data->range_fac, data->min, data->range, ofs_new, inverted); + } + else { + value = ofs_new; + } + + /* clamp to custom range */ + if (data->flag & MANIPULATOR_CUSTOM_RANGE_SET) { + CLAMP(value, data->min, max); + } + + return value; +} + +void manipulator_property_data_update( + wmManipulator *mpr, ManipulatorCommonData *data, wmManipulatorProperty *mpr_prop, + const bool constrained, const bool inverted) +{ + if (mpr_prop->custom_func.value_get_fn != NULL) { + /* pass */ + } + else if (mpr_prop->prop != NULL) { + /* pass */ + } + else { + data->offset = 0.0f; + return; + } + + float value = WM_manipulator_target_property_value_get(mpr, mpr_prop); + + if (constrained) { + if ((data->flag & MANIPULATOR_CUSTOM_RANGE_SET) == 0) { + float range[2]; + if (WM_manipulator_target_property_range_get(mpr, mpr_prop, range)) { + data->range = range[1] - range[0]; + data->min = range[0]; + } + else { + BLI_assert(0); + } + } + data->offset = manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted); + } + else { + data->offset = value; + } +} + +void manipulator_property_value_reset( + bContext *C, const wmManipulator *mpr, ManipulatorInteraction *inter, + wmManipulatorProperty *mpr_prop) +{ + WM_manipulator_target_property_value_set(C, mpr, mpr_prop, inter->init_value); +} + +/* -------------------------------------------------------------------- */ + +void manipulator_color_get( + const wmManipulator *mpr, const bool highlight, + float r_col[4]) +{ + if (highlight && !(mpr->flag & WM_MANIPULATOR_DRAW_HOVER)) { + copy_v4_v4(r_col, mpr->color_hi); + } + else { + copy_v4_v4(r_col, mpr->color); + } +} + +/* -------------------------------------------------------------------- */ + +/** + * Takes mouse coordinates and returns them in relation to the manipulator. + * Both 2D & 3D supported, use so we can use 2D manipulators in the 3D view. + */ +bool manipulator_window_project_2d( + bContext *C, const struct wmManipulator *mpr, const float mval[2], int axis, bool use_offset, + float r_co[2]) +{ + float mat[4][4]; + { + float mat_identity[4][4]; + struct WM_ManipulatorMatrixParams params = {NULL}; + if (use_offset == false) { + unit_m4(mat_identity); + params.matrix_offset = mat_identity; + } + WM_manipulator_calc_matrix_final_params(mpr, ¶ms, mat); + } + + /* rotate mouse in relation to the center and relocate it */ + if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { + /* For 3d views, transform 2D mouse pos onto plane. */ + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + + float plane[4]; + + plane_from_point_normal_v3(plane, mat[3], mat[2]); + + float ray_origin[3], ray_direction[3]; + + if (ED_view3d_win_to_ray(CTX_data_depsgraph(C), ar, v3d, mval, ray_origin, ray_direction, false)) { + float lambda; + if (isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, true)) { + float co[3]; + madd_v3_v3v3fl(co, ray_origin, ray_direction, lambda); + float imat[4][4]; + invert_m4_m4(imat, mat); + mul_m4_v3(imat, co); + r_co[0] = co[(axis + 1) % 3]; + r_co[1] = co[(axis + 2) % 3]; + return true; + } + } + return false; + } + else { + float co[3] = {mval[0], mval[1], 0.0f}; + float imat[4][4]; + invert_m4_m4(imat, mat); + mul_mat3_m4_v3(imat, co); + copy_v2_v2(r_co, co); + return true; + } +} + +bool manipulator_window_project_3d( + bContext *C, const struct wmManipulator *mpr, const float mval[2], bool use_offset, + float r_co[3]) +{ + float mat[4][4]; + { + float mat_identity[4][4]; + struct WM_ManipulatorMatrixParams params = {NULL}; + if (use_offset == false) { + unit_m4(mat_identity); + params.matrix_offset = mat_identity; + } + WM_manipulator_calc_matrix_final_params(mpr, ¶ms, mat); + } + + if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + /* Note: we might want a custom reference point passed in, + * instead of the manipulator center. */ + ED_view3d_win_to_3d(v3d, ar, mat[3], mval, r_co); + invert_m4(mat); + mul_m4_v3(mat, r_co); + return true; + } + else { + float co[3] = {mval[0], mval[1], 0.0f}; + float imat[4][4]; + invert_m4_m4(imat, mat); + mul_m4_v3(imat, co); + copy_v2_v2(r_co, co); + return true; + } +} diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c new file mode 100644 index 00000000000..fbb30b95562 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/arrow2d_gizmo.c @@ -0,0 +1,225 @@ +/* + * ***** 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) 2016 Blender Foundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file arrow2d_gizmo.c + * \ingroup wm + * + * \name 2D Arrow Manipulator + * + * \brief Simple arrow manipulator which is dragged into a certain direction. + */ + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_rect.h" + +#include "DNA_windowmanager_types.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" + +#include "GPU_draw.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +/* own includes */ +#include "WM_api.h" + +#include "../gizmo_library_intern.h" + +static void arrow2d_draw_geom(wmManipulator *mpr, const float matrix[4][4], const float color[4]) +{ + const float size = 0.11f; + const float size_breadth = size / 2.0f; + const float size_length = size * 1.7f; + /* Subtract the length so the arrow fits in the hotspot. */ + const float arrow_length = RNA_float_get(mpr->ptr, "length") - size_length; + const float arrow_angle = RNA_float_get(mpr->ptr, "angle"); + + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + gpuPushMatrix(); + gpuMultMatrix(matrix); + gpuRotate2D(RAD2DEGF(arrow_angle)); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4fv(color); + + immBegin(GWN_PRIM_LINES, 2); + immVertex2f(pos, 0.0f, 0.0f); + immVertex2f(pos, 0.0f, arrow_length); + immEnd(); + + immBegin(GWN_PRIM_TRIS, 3); + immVertex2f(pos, size_breadth, arrow_length); + immVertex2f(pos, -size_breadth, arrow_length); + immVertex2f(pos, 0.0f, arrow_length + size_length); + immEnd(); + + immUnbindProgram(); + + gpuPopMatrix(); +} + +static void manipulator_arrow2d_draw(const bContext *UNUSED(C), wmManipulator *mpr) +{ + float color[4]; + + float matrix_final[4][4]; + + manipulator_color_get(mpr, mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT, color); + + GPU_line_width(mpr->line_width); + + WM_manipulator_calc_matrix_final(mpr, matrix_final); + + GPU_blend(true); + arrow2d_draw_geom(mpr, matrix_final, color); + GPU_blend(false); + + if (mpr->interaction_data) { + ManipulatorInteraction *inter = mpr->interaction_data; + + GPU_blend(true); + arrow2d_draw_geom(mpr, inter->init_matrix_final, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}); + GPU_blend(false); + } +} + +static void manipulator_arrow2d_setup(wmManipulator *mpr) +{ + mpr->flag |= WM_MANIPULATOR_DRAW_MODAL; +} + +static int manipulator_arrow2d_invoke( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *UNUSED(event)) +{ + ManipulatorInteraction *inter = MEM_callocN(sizeof(ManipulatorInteraction), __func__); + + copy_m4_m4(inter->init_matrix_basis, mpr->matrix_basis); + WM_manipulator_calc_matrix_final(mpr, inter->init_matrix_final); + + mpr->interaction_data = inter; + + return OPERATOR_RUNNING_MODAL; +} + +static int manipulator_arrow2d_test_select( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) +{ + const float mval[2] = {event->mval[0], event->mval[1]}; + const float arrow_length = RNA_float_get(mpr->ptr, "length"); + const float arrow_angle = RNA_float_get(mpr->ptr, "angle"); + const float line_len = arrow_length * mpr->scale_final; + float mval_local[2]; + + copy_v2_v2(mval_local, mval); + sub_v2_v2(mval_local, mpr->matrix_basis[3]); + + float line[2][2]; + line[0][0] = line[0][1] = line[1][0] = 0.0f; + line[1][1] = line_len; + + /* rotate only if needed */ + if (arrow_angle != 0.0f) { + float rot_point[2]; + copy_v2_v2(rot_point, line[1]); + rotate_v2_v2fl(line[1], rot_point, arrow_angle); + } + + /* arrow line intersection check */ + float isect_1[2], isect_2[2]; + const int isect = isect_line_sphere_v2( + line[0], line[1], mval_local, MANIPULATOR_HOTSPOT + mpr->line_width * 0.5f, + isect_1, isect_2); + + if (isect > 0) { + float line_ext[2][2]; /* extended line for segment check including hotspot */ + copy_v2_v2(line_ext[0], line[0]); + line_ext[1][0] = line[1][0] + MANIPULATOR_HOTSPOT * ((line[1][0] - line[0][0]) / line_len); + line_ext[1][1] = line[1][1] + MANIPULATOR_HOTSPOT * ((line[1][1] - line[0][1]) / line_len); + + const float lambda_1 = line_point_factor_v2(isect_1, line_ext[0], line_ext[1]); + if (isect == 1) { + if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f)) { + return 0; + } + } + else { + BLI_assert(isect == 2); + const float lambda_2 = line_point_factor_v2(isect_2, line_ext[0], line_ext[1]); + if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f) && IN_RANGE_INCL(lambda_2, 0.0f, 1.0f)) { + return 0; + } + } + } + + return -1; +} + +/* -------------------------------------------------------------------- */ +/** \name 2D Arrow Manipulator API + * + * \{ */ + +static void MANIPULATOR_WT_arrow_2d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_arrow_2d"; + + /* api callbacks */ + wt->draw = manipulator_arrow2d_draw; + wt->setup = manipulator_arrow2d_setup; + wt->invoke = manipulator_arrow2d_invoke; + wt->test_select = manipulator_arrow2d_test_select; + + wt->struct_size = sizeof(wmManipulator); + + /* rna */ + RNA_def_float(wt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX); + RNA_def_float_rotation( + wt->srna, "angle", 0, NULL, DEG2RADF(-360.0f), DEG2RADF(360.0f), + "Roll", "", DEG2RADF(-360.0f), DEG2RADF(360.0f)); +} + +void ED_manipulatortypes_arrow_2d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_arrow_2d); +} + +/** \} */ diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c new file mode 100644 index 00000000000..72b24e03c00 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c @@ -0,0 +1,492 @@ +/* + * ***** 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 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file arrow3d_gizmo.c + * \ingroup wm + * + * \name Arrow Manipulator + * + * 3D Manipulator + * + * \brief Simple arrow manipulator which is dragged into a certain direction. + * The arrow head can have varying shapes, e.g. cone, box, etc. + * + * - `matrix[0]` is derived from Y and Z. + * - `matrix[1]` is 'up' for manipulator types that have an up. + * - `matrix[2]` is the arrow direction (for all arrowes). + */ + +#include "BIF_gl.h" + +#include "BLI_math.h" + +#include "DNA_view3d_types.h" + +#include "BKE_context.h" + +#include "GPU_draw.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_select.h" +#include "GPU_state.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_types.h" +#include "WM_api.h" + +#include "ED_view3d.h" +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +/* own includes */ +#include "../gizmo_geometry.h" +#include "../gizmo_library_intern.h" + +/* to use custom arrows exported to geom_arrow_manipulator.c */ +//#define USE_MANIPULATOR_CUSTOM_ARROWS + +typedef struct ArrowManipulator3D { + wmManipulator manipulator; + ManipulatorCommonData data; +} ArrowManipulator3D; + + +/* -------------------------------------------------------------------- */ + +static void manipulator_arrow_matrix_basis_get(const wmManipulator *mpr, float r_matrix[4][4]) +{ + ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; + + copy_m4_m4(r_matrix, arrow->manipulator.matrix_basis); + madd_v3_v3fl(r_matrix[3], arrow->manipulator.matrix_basis[2], arrow->data.offset); +} + +static void arrow_draw_geom(const ArrowManipulator3D *arrow, const bool select, const float color[4]) +{ + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + bool unbind_shader = true; + const int draw_style = RNA_enum_get(arrow->manipulator.ptr, "draw_style"); + const int draw_options = RNA_enum_get(arrow->manipulator.ptr, "draw_options"); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + if (draw_style == ED_MANIPULATOR_ARROW_STYLE_CROSS) { + immUniformColor4fv(color); + + immBegin(GWN_PRIM_LINES, 4); + immVertex3f(pos, -1.0f, 0.0f, 0.0f); + immVertex3f(pos, 1.0f, 0.0f, 0.0f); + immVertex3f(pos, 0.0f, -1.0f, 0.0f); + immVertex3f(pos, 0.0f, 1.0f, 0.0f); + immEnd(); + } + else if (draw_style == ED_MANIPULATOR_ARROW_STYLE_CONE) { + float aspect[2]; + RNA_float_get_array(arrow->manipulator.ptr, "aspect", aspect); + const float unitx = aspect[0]; + const float unity = aspect[1]; + const float vec[4][3] = { + {-unitx, -unity, 0}, + { unitx, -unity, 0}, + { unitx, unity, 0}, + {-unitx, unity, 0}, + }; + + GPU_line_width(arrow->manipulator.line_width); + wm_manipulator_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GWN_PRIM_LINE_LOOP); + } + else { +#ifdef USE_MANIPULATOR_CUSTOM_ARROWS + wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_arrow, select, color); +#else + const float arrow_length = RNA_float_get(arrow->manipulator.ptr, "length"); + + const float vec[2][3] = { + {0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, arrow_length}, + }; + + if (draw_options & ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM) { + GPU_line_width(arrow->manipulator.line_width); + wm_manipulator_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GWN_PRIM_LINE_STRIP); + } + else { + immUniformColor4fv(color); + } + + /* *** draw arrow head *** */ + + gpuPushMatrix(); + + if (draw_style == ED_MANIPULATOR_ARROW_STYLE_BOX) { + const float size = 0.05f; + + /* translate to line end with some extra offset so box starts exactly where line ends */ + gpuTranslate3f(0.0f, 0.0f, arrow_length + size); + /* scale down to box size */ + gpuScale3f(size, size, size); + + /* draw cube */ + immUnbindProgram(); + unbind_shader = false; + wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_cube, select, color); + } + else { + BLI_assert(draw_style == ED_MANIPULATOR_ARROW_STYLE_NORMAL); + + const float len = 0.25f; + const float width = 0.06f; + + /* translate to line end */ + gpuTranslate3f(0.0f, 0.0f, arrow_length); + + imm_draw_circle_fill_3d(pos, 0.0, 0.0, width, 8); + imm_draw_cylinder_fill_3d(pos, width, 0.0, len, 8, 1); + } + + gpuPopMatrix(); +#endif /* USE_MANIPULATOR_CUSTOM_ARROWS */ + } + + if (unbind_shader) { + immUnbindProgram(); + } +} + +static void arrow_draw_intern(ArrowManipulator3D *arrow, const bool select, const bool highlight) +{ + wmManipulator *mpr = &arrow->manipulator; + float color[4]; + float matrix_final[4][4]; + + manipulator_color_get(mpr, highlight, color); + + WM_manipulator_calc_matrix_final(mpr, matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + GPU_blend(true); + arrow_draw_geom(arrow, select, color); + GPU_blend(false); + + gpuPopMatrix(); + + if (mpr->interaction_data) { + ManipulatorInteraction *inter = mpr->interaction_data; + + gpuPushMatrix(); + gpuMultMatrix(inter->init_matrix_final); + + + GPU_blend(true); + arrow_draw_geom(arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}); + GPU_blend(false); + + gpuPopMatrix(); + } +} + +static void manipulator_arrow_draw_select( + const bContext *UNUSED(C), wmManipulator *mpr, + int select_id) +{ + GPU_select_load_id(select_id); + arrow_draw_intern((ArrowManipulator3D *)mpr, true, false); +} + +static void manipulator_arrow_draw(const bContext *UNUSED(C), wmManipulator *mpr) +{ + arrow_draw_intern((ArrowManipulator3D *)mpr, false, (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0); +} + +/** + * Calculate arrow offset independent from prop min value, + * meaning the range will not be offset by min value first. + */ +static int manipulator_arrow_modal( + bContext *C, wmManipulator *mpr, const wmEvent *event, + eWM_ManipulatorTweak tweak_flag) +{ + ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; + ManipulatorInteraction *inter = mpr->interaction_data; + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + float offset[3]; + float facdir = 1.0f; + + /* (src, dst) */ + struct { + float mval[2]; + float ray_origin[3], ray_direction[3]; + float location[3]; + } proj[2] = { + {.mval = {UNPACK2(inter->init_mval)}}, + {.mval = {UNPACK2(event->mval)}}, + }; + + float arrow_co[3]; + float arrow_no[3]; + copy_v3_v3(arrow_co, inter->init_matrix_basis[3]); + normalize_v3_v3(arrow_no, arrow->manipulator.matrix_basis[2]); + + int ok = 0; + + for (int j = 0; j < 2; j++) { + if (ED_view3d_win_to_ray( + CTX_data_depsgraph(C), + ar, v3d, proj[j].mval, + proj[j].ray_origin, proj[j].ray_direction, false)) + { + /* Force Y axis if we're view aligned */ + if (j == 0) { + if (RAD2DEGF(acosf(dot_v3v3(proj[j].ray_direction, arrow->manipulator.matrix_basis[2]))) < 5.0f) { + normalize_v3_v3(arrow_no, rv3d->viewinv[1]); + } + } + + float arrow_no_proj[3]; + project_plane_v3_v3v3(arrow_no_proj, arrow_no, proj[j].ray_direction); + + normalize_v3(arrow_no_proj); + + float plane[4]; + plane_from_point_normal_v3(plane, proj[j].ray_origin, arrow_no_proj); + + float lambda; + if (isect_ray_plane_v3(arrow_co, arrow_no, plane, &lambda, false)) { + madd_v3_v3v3fl(proj[j].location, arrow_co, arrow_no, lambda); + ok++; + } + } + } + + if (ok != 2) { + return OPERATOR_RUNNING_MODAL; + } + + sub_v3_v3v3(offset, proj[1].location, proj[0].location); + facdir = dot_v3v3(arrow_no, offset) < 0.0f ? -1 : 1; + + ManipulatorCommonData *data = &arrow->data; + const float ofs_new = facdir * len_v3(offset); + + wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); + + /* set the property for the operator and call its modal function */ + if (WM_manipulator_target_property_is_valid(mpr_prop)) { + const int transform_flag = RNA_enum_get(arrow->manipulator.ptr, "transform"); + const bool constrained = (transform_flag & ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED) != 0; + const bool inverted = (transform_flag & ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED) != 0; + const bool use_precision = (tweak_flag & WM_MANIPULATOR_TWEAK_PRECISE) != 0; + float value = manipulator_value_from_offset(data, inter, ofs_new, constrained, inverted, use_precision); + + WM_manipulator_target_property_value_set(C, mpr, mpr_prop, value); + /* get clamped value */ + value = WM_manipulator_target_property_value_get(mpr, mpr_prop); + + data->offset = manipulator_offset_from_value(data, value, constrained, inverted); + } + else { + data->offset = ofs_new; + } + + /* tag the region for redraw */ + ED_region_tag_redraw(ar); + WM_event_add_mousemove(C); + + return OPERATOR_RUNNING_MODAL; +} + +static void manipulator_arrow_setup(wmManipulator *mpr) +{ + ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; + + arrow->manipulator.flag |= WM_MANIPULATOR_DRAW_MODAL; + + arrow->data.range_fac = 1.0f; +} + +static int manipulator_arrow_invoke( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) +{ + ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; + ManipulatorInteraction *inter = MEM_callocN(sizeof(ManipulatorInteraction), __func__); + wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); + + /* Some manipulators don't use properties. */ + if (WM_manipulator_target_property_is_valid(mpr_prop)) { + inter->init_value = WM_manipulator_target_property_value_get(mpr, mpr_prop); + } + + inter->init_offset = arrow->data.offset; + + inter->init_mval[0] = event->mval[0]; + inter->init_mval[1] = event->mval[1]; + + manipulator_arrow_matrix_basis_get(mpr, inter->init_matrix_basis); + WM_manipulator_calc_matrix_final(mpr, inter->init_matrix_final); + + mpr->interaction_data = inter; + + return OPERATOR_RUNNING_MODAL; +} + +static void manipulator_arrow_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop) +{ + ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; + const int transform_flag = RNA_enum_get(arrow->manipulator.ptr, "transform"); + const bool constrained = (transform_flag & ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED) != 0; + const bool inverted = (transform_flag & ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED) != 0; + manipulator_property_data_update(mpr, &arrow->data, mpr_prop, constrained, inverted); +} + +static void manipulator_arrow_exit(bContext *C, wmManipulator *mpr, const bool cancel) +{ + ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; + ManipulatorCommonData *data = &arrow->data; + wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); + const bool is_prop_valid = WM_manipulator_target_property_is_valid(mpr_prop); + + if (!cancel) { + /* Assign incase applying the opetration needs an updated offset + * editmesh bisect needs this. */ + if (is_prop_valid) { + data->offset = WM_manipulator_target_property_value_get(mpr, mpr_prop); + } + return; + } + + ManipulatorInteraction *inter = mpr->interaction_data; + if (is_prop_valid) { + manipulator_property_value_reset(C, mpr, inter, mpr_prop); + } + data->offset = inter->init_offset; +} + + +/* -------------------------------------------------------------------- */ +/** \name Arrow Manipulator API + * + * \{ */ + +/** + * Define a custom property UI range + * + * \note Needs to be called before WM_manipulator_target_property_def_rna! + */ +void ED_manipulator_arrow3d_set_ui_range(wmManipulator *mpr, const float min, const float max) +{ + ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; + + BLI_assert(min < max); + BLI_assert(!(WM_manipulator_target_property_is_valid(WM_manipulator_target_property_find(mpr, "offset")) && + "Make sure this function is called before WM_manipulator_target_property_def_rna")); + + arrow->data.range = max - min; + arrow->data.min = min; + arrow->data.flag |= MANIPULATOR_CUSTOM_RANGE_SET; +} + +/** + * Define a custom factor for arrow min/max distance + * + * \note Needs to be called before WM_manipulator_target_property_def_rna! + */ +void ED_manipulator_arrow3d_set_range_fac(wmManipulator *mpr, const float range_fac) +{ + ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; + BLI_assert(!(WM_manipulator_target_property_is_valid(WM_manipulator_target_property_find(mpr, "offset")) && + "Make sure this function is called before WM_manipulator_target_property_def_rna")); + + arrow->data.range_fac = range_fac; +} + +static void MANIPULATOR_WT_arrow_3d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_arrow_3d"; + + /* api callbacks */ + wt->draw = manipulator_arrow_draw; + wt->draw_select = manipulator_arrow_draw_select; + wt->matrix_basis_get = manipulator_arrow_matrix_basis_get; + wt->modal = manipulator_arrow_modal; + wt->setup = manipulator_arrow_setup; + wt->invoke = manipulator_arrow_invoke; + wt->property_update = manipulator_arrow_property_update; + wt->exit = manipulator_arrow_exit; + + wt->struct_size = sizeof(ArrowManipulator3D); + + /* rna */ + static EnumPropertyItem rna_enum_draw_style_items[] = { + {ED_MANIPULATOR_ARROW_STYLE_NORMAL, "NORMAL", 0, "Normal", ""}, + {ED_MANIPULATOR_ARROW_STYLE_CROSS, "CROSS", 0, "Cross", ""}, + {ED_MANIPULATOR_ARROW_STYLE_BOX, "BOX", 0, "Box", ""}, + {ED_MANIPULATOR_ARROW_STYLE_CONE, "CONE", 0, "Cone", ""}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem rna_enum_draw_options_items[] = { + {ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM, "STEM", 0, "Stem", ""}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem rna_enum_transform_items[] = { + {ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED, "INVERT", 0, "Inverted", ""}, + {ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED, "CONSTRAIN", 0, "Constrained", ""}, + {0, NULL, 0, NULL, NULL} + }; + + RNA_def_enum( + wt->srna, "draw_style", rna_enum_draw_style_items, + ED_MANIPULATOR_ARROW_STYLE_NORMAL, + "Draw Style", ""); + RNA_def_enum_flag( + wt->srna, "draw_options", rna_enum_draw_options_items, + ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM, + "Draw Options", ""); + RNA_def_enum_flag( + wt->srna, "transform", rna_enum_transform_items, + 0, + "Transform", ""); + + RNA_def_float(wt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX); + RNA_def_float_vector(wt->srna, "aspect", 2, NULL, 0, FLT_MAX, "Aspect", "Cone/box style only", 0.0f, FLT_MAX); + + WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 1); +} + +void ED_manipulatortypes_arrow_3d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_arrow_3d); +} + +/** \} */ diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c new file mode 100644 index 00000000000..78f374064e6 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c @@ -0,0 +1,322 @@ +/* + * ***** 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 button2d_gizmo.c + * \ingroup wm + * + * \name Button Manipulator + * + * 2D Manipulator, also works in 3D views. + * + * \brief Single click button action for use in manipulator groups. + * + * \note Currently only basic icon & vector-shape buttons are supported. + * + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.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_select.h" +#include "GPU_batch.h" +#include "GPU_state.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_gizmo_library.h" + +#include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_resources.h" + +/* own includes */ +#include "../gizmo_geometry.h" +#include "../gizmo_library_intern.h" + +typedef struct ButtonManipulator2D { + wmManipulator manipulator; + bool is_init; + /* Use an icon or shape */ + int icon; + Gwn_Batch *shape_batch[2]; +} ButtonManipulator2D; + +#define CIRCLE_RESOLUTION 32 + +/* -------------------------------------------------------------------- */ + +static void button2d_geom_draw_backdrop( + const wmManipulator *mpr, const float color[4], const bool select) +{ + GPU_line_width(mpr->line_width); + + Gwn_VertFormat *format = immVertexFormat(); + uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + immUniformColor4fv(color); + + /* TODO, other draw styles */ + imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION); + + immUnbindProgram(); + + UNUSED_VARS(select); +} + +static void button2d_draw_intern( + const bContext *C, wmManipulator *mpr, + const bool select, const bool highlight) +{ + ButtonManipulator2D *button = (ButtonManipulator2D *)mpr; + + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + if (button->is_init == false) { + button->is_init = true; + PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "icon"); + if (RNA_property_is_set(mpr->ptr, prop)) { + button->icon = RNA_property_enum_get(mpr->ptr, prop); + } + else { + prop = RNA_struct_find_property(mpr->ptr, "shape"); + const uint polys_len = RNA_property_string_length(mpr->ptr, prop); + /* We shouldn't need the +1, but a NULL char is set. */ + char *polys = MEM_mallocN(polys_len + 1, __func__); + RNA_property_string_get(mpr->ptr, prop, polys); + button->shape_batch[0] = GPU_batch_tris_from_poly_2d_encoded((uchar *)polys, polys_len, NULL); + button->shape_batch[1] = GPU_batch_wire_from_poly_2d_encoded((uchar *)polys, polys_len, NULL); + MEM_freeN(polys); + } + } + + float color[4]; + float matrix_final[4][4]; + + manipulator_color_get(mpr, highlight, color); + WM_manipulator_calc_matrix_final(mpr, matrix_final); + + + bool is_3d = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) != 0; + + + if (draw_options & ED_MANIPULATOR_BUTTON_SHOW_HELPLINE) { + float matrix_final_no_offset[4][4]; + WM_manipulator_calc_matrix_final_no_offset(mpr, matrix_final_no_offset); + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv(color); + GPU_line_width(mpr->line_width); + immUniformColor4fv(color); + immBegin(GWN_PRIM_LINE_STRIP, 2); + immVertex3fv(pos, matrix_final[3]); + immVertex3fv(pos, matrix_final_no_offset[3]); + immEnd(); + immUnbindProgram(); + } + + bool need_to_pop = true; + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + if (is_3d) { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + float matrix_align[4][4]; + float matrix_final_unit[4][4]; + normalize_m4_m4(matrix_final_unit, matrix_final); + mul_m4_m4m4(matrix_align, rv3d->viewmat, matrix_final_unit); + zero_v3(matrix_align[3]); + transpose_m4(matrix_align); + gpuMultMatrix(matrix_align); + } + + if (select) { + BLI_assert(is_3d); + button2d_geom_draw_backdrop(mpr, color, select); + } + else { + + GPU_blend(true); + if (button->shape_batch[0] != NULL) { + GPU_line_smooth(true); + GPU_polygon_smooth(false); + GPU_line_width(1.0f); + for (uint i = 0; i < ARRAY_SIZE(button->shape_batch) && button->shape_batch[i]; i++) { + /* Invert line color for wire. */ + GWN_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR); + GWN_batch_uniform_4f(button->shape_batch[i], "color", UNPACK4(color)); + GWN_batch_draw(button->shape_batch[i]); + + if (draw_options & ED_MANIPULATOR_BUTTON_SHOW_OUTLINE) { + color[0] = 1.0f - color[0]; + color[1] = 1.0f - color[1]; + color[2] = 1.0f - color[2]; + } + } + GPU_line_smooth(false); + GPU_polygon_smooth(true); + } + else if (button->icon != ICON_NONE) { + button2d_geom_draw_backdrop(mpr, color, select); + float size[2]; + if (is_3d) { + const float fac = 2.0f; + gpuTranslate2f(-(fac / 2), -(fac / 2)); + gpuScale2f(fac / (ICON_DEFAULT_WIDTH * UI_DPI_FAC), fac / (ICON_DEFAULT_HEIGHT * UI_DPI_FAC)); + size[0] = 1.0f; + size[1] = 1.0f; + } + else { + size[0] = mpr->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * UI_DPI_FAC; + size[1] = mpr->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * UI_DPI_FAC; + gpuPopMatrix(); + need_to_pop = false; + } + UI_icon_draw(size[0], size[1], button->icon); + } + GPU_blend(false); + } + + if (need_to_pop) { + gpuPopMatrix(); + } +} + +static void manipulator_button2d_draw_select(const bContext *C, wmManipulator *mpr, int select_id) +{ + GPU_select_load_id(select_id); + button2d_draw_intern(C, mpr, true, false); +} + +static void manipulator_button2d_draw(const bContext *C, wmManipulator *mpr) +{ + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + + GPU_blend(true); + button2d_draw_intern(C, mpr, false, is_highlight); + GPU_blend(false); +} + +static int manipulator_button2d_test_select( + bContext *C, wmManipulator *mpr, const wmEvent *event) +{ + float point_local[2]; + + if (0) { + /* correct, but unnecessarily slow. */ + if (manipulator_window_project_2d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false) + { + return -1; + } + } + else { + copy_v2_v2(point_local, (float[2]){UNPACK2(event->mval)}); + sub_v2_v2(point_local, mpr->matrix_basis[3]); + mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * UI_DPI_FAC)); + } + /* The 'mpr->scale_final' is already applied when projecting. */ + if (len_squared_v2(point_local) < 1.0f) { + return 0; + } + + return -1; +} + +static int manipulator_button2d_cursor_get(wmManipulator *mpr) +{ + if (RNA_boolean_get(mpr->ptr, "show_drag")) { + return BC_NSEW_SCROLLCURSOR; + } + return CURSOR_STD; +} + +static void manipulator_button2d_free(wmManipulator *mpr) +{ + ButtonManipulator2D *shape = (ButtonManipulator2D *)mpr; + + for (uint i = 0; i < ARRAY_SIZE(shape->shape_batch); i++) { + GWN_BATCH_DISCARD_SAFE(shape->shape_batch[i]); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Button Manipulator API + * + * \{ */ + +static void MANIPULATOR_WT_button_2d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_button_2d"; + + /* api callbacks */ + wt->draw = manipulator_button2d_draw; + wt->draw_select = manipulator_button2d_draw_select; + wt->test_select = manipulator_button2d_test_select; + wt->cursor_get = manipulator_button2d_cursor_get; + wt->free = manipulator_button2d_free; + + wt->struct_size = sizeof(ButtonManipulator2D); + + /* rna */ + static EnumPropertyItem rna_enum_draw_options[] = { + {ED_MANIPULATOR_BUTTON_SHOW_OUTLINE, "OUTLINE", 0, "Outline", ""}, + {ED_MANIPULATOR_BUTTON_SHOW_HELPLINE, "HELPLINE", 0, "Help Line", ""}, + {0, NULL, 0, NULL, NULL} + }; + PropertyRNA *prop; + + RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", ""); + + prop = RNA_def_property(wt->srna, "icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_icon_items); + + /* Passed to 'GPU_batch_tris_from_poly_2d_encoded' */ + RNA_def_property(wt->srna, "shape", PROP_STRING, PROP_BYTESTRING); + + /* Currently only used for cursor display. */ + RNA_def_boolean(wt->srna, "show_drag", true, "Show Drag", ""); +} + +void ED_manipulatortypes_button_2d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_button_2d); +} + +/** \} */ // Button Manipulator API diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c new file mode 100644 index 00000000000..382733d298f --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c @@ -0,0 +1,1100 @@ +/* + * ***** 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 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file cage2d_gizmo.c + * \ingroup wm + * + * \name Cage Manipulator + * + * 2D Manipulator + * + * \brief Rectangular manipulator acting as a 'cage' around its content. + * Interacting scales or translates the manipulator. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_dial_2d.h" +#include "BLI_rect.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" + +#include "GPU_matrix.h" +#include "GPU_shader.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_select.h" +#include "GPU_state.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_gizmo_library.h" + +/* own includes */ +#include "../gizmo_library_intern.h" + +#define MANIPULATOR_RESIZER_SIZE 10.0f +#define MANIPULATOR_MARGIN_OFFSET_SCALE 1.5f + +static void manipulator_calc_rect_view_scale( + const wmManipulator *mpr, const float dims[2], float scale[2]) +{ + float matrix_final_no_offset[4][4]; + float asp[2] = {1.0f, 1.0f}; + if (dims[0] > dims[1]) { + asp[0] = dims[1] / dims[0]; + } + else { + asp[1] = dims[0] / dims[1]; + } + float x_axis[3], y_axis[3]; + WM_manipulator_calc_matrix_final_no_offset(mpr, matrix_final_no_offset); + mul_v3_mat3_m4v3(x_axis, matrix_final_no_offset, mpr->matrix_offset[0]); + mul_v3_mat3_m4v3(y_axis, matrix_final_no_offset, mpr->matrix_offset[1]); + + mul_v2_v2(x_axis, asp); + mul_v2_v2(y_axis, asp); + + scale[0] = 1.0f / len_v3(x_axis); + scale[1] = 1.0f / len_v3(y_axis); +} + +static void manipulator_calc_rect_view_margin( + const wmManipulator *mpr, const float dims[2], float margin[2]) +{ + float handle_size; + if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { + handle_size = 0.15f; + } + else { + handle_size = MANIPULATOR_RESIZER_SIZE; + } + handle_size *= mpr->scale_final; + float scale_xy[2]; + manipulator_calc_rect_view_scale(mpr, dims, scale_xy); + margin[0] = ((handle_size * scale_xy[0])); + margin[1] = ((handle_size * scale_xy[1])); +} + +/* -------------------------------------------------------------------- */ + +static void manipulator_rect_pivot_from_scale_part(int part, float r_pt[2], bool r_constrain_axis[2]) +{ + bool x = true, y = true; + switch (part) { + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X: { ARRAY_SET_ITEMS(r_pt, 0.5, 0.0); x = false; break; } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X: { ARRAY_SET_ITEMS(r_pt, -0.5, 0.0); x = false; break; } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y: { ARRAY_SET_ITEMS(r_pt, 0.0, 0.5); y = false; break; } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y: { ARRAY_SET_ITEMS(r_pt, 0.0, -0.5); y = false; break; } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y: { ARRAY_SET_ITEMS(r_pt, 0.5, 0.5); x = y = false; break; } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y: { ARRAY_SET_ITEMS(r_pt, 0.5, -0.5); x = y = false; break; } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y: { ARRAY_SET_ITEMS(r_pt, -0.5, 0.5); x = y = false; break; } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y: { ARRAY_SET_ITEMS(r_pt, -0.5, -0.5); x = y = false; break; } + default: BLI_assert(0); + } + r_constrain_axis[0] = x; + r_constrain_axis[1] = y; +} + +/* -------------------------------------------------------------------- */ +/** \name Box Draw Style + * + * Useful for 3D views, see: #ED_MANIPULATOR_CAGE2D_STYLE_BOX + * \{ */ + +static void cage2d_draw_box_corners( + const rctf *r, const float margin[2], const float color[3]) +{ + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fv(color); + + immBegin(GWN_PRIM_LINES, 16); + + immVertex2f(pos, r->xmin, r->ymin + margin[1]); + immVertex2f(pos, r->xmin, r->ymin); + immVertex2f(pos, r->xmin, r->ymin); + immVertex2f(pos, r->xmin + margin[0], r->ymin); + + immVertex2f(pos, r->xmax, r->ymin + margin[1]); + immVertex2f(pos, r->xmax, r->ymin); + immVertex2f(pos, r->xmax, r->ymin); + immVertex2f(pos, r->xmax - margin[0], r->ymin); + + immVertex2f(pos, r->xmax, r->ymax - margin[1]); + immVertex2f(pos, r->xmax, r->ymax); + immVertex2f(pos, r->xmax, r->ymax); + immVertex2f(pos, r->xmax - margin[0], r->ymax); + + immVertex2f(pos, r->xmin, r->ymax - margin[1]); + immVertex2f(pos, r->xmin, r->ymax); + immVertex2f(pos, r->xmin, r->ymax); + immVertex2f(pos, r->xmin + margin[0], r->ymax); + + immEnd(); + + immUnbindProgram(); +} + +static void cage2d_draw_box_interaction( + const float color[4], const int highlighted, + const float size[2], const float margin[2], + const float line_width, const bool is_solid, const int draw_options) +{ + /* 4 verts for translate, otherwise only 3 are used. */ + float verts[4][2]; + uint verts_len = 0; + Gwn_PrimType prim_type = GWN_PRIM_NONE; + + switch (highlighted) { + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X: + { + rctf r = { + .xmin = -size[0], .xmax = -size[0] + margin[0], + .ymin = -size[1] + margin[1], .ymax = size[1] - margin[1], + }; + ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin); + ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymax); + verts_len = 2; + if (is_solid) { + ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax); + ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymin); + verts_len += 2; + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINE_STRIP; + } + break; + } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X: + { + rctf r = { + .xmin = size[0] - margin[0], .xmax = size[0], + .ymin = -size[1] + margin[1], .ymax = size[1] - margin[1], + }; + ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymin); + ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax); + verts_len = 2; + if (is_solid) { + ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymax); + ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin); + verts_len += 2; + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINE_STRIP; + } + break; + } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y: + { + rctf r = { + .xmin = -size[0] + margin[0], .xmax = size[0] - margin[0], + .ymin = -size[1], .ymax = -size[1] + margin[1], + }; + ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin); + ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymin); + verts_len = 2; + if (is_solid) { + ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax); + ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymax); + verts_len += 2; + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINE_STRIP; + } + break; + } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y: + { + rctf r = { + .xmin = -size[0] + margin[0], .xmax = size[0] - margin[0], + .ymin = size[1] - margin[1], .ymax = size[1], + }; + ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymax); + ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax); + verts_len = 2; + if (is_solid) { + ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymin); + ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin); + verts_len += 2; + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINE_STRIP; + } + break; + } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y: + { + rctf r = { + .xmin = -size[0], .xmax = -size[0] + margin[0], + .ymin = -size[1], .ymax = -size[1] + margin[1], + }; + ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymin); + ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax); + ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymax); + verts_len = 3; + if (is_solid) { + ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin); + verts_len += 1; + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINE_STRIP; + } + break; + } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y: + { + rctf r = { + .xmin = -size[0], .xmax = -size[0] + margin[0], + .ymin = size[1] - margin[1], .ymax = size[1], + }; + ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymax); + ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymin); + ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymin); + verts_len = 3; + if (is_solid) { + ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymax); + verts_len += 1; + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINE_STRIP; + } + break; + } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y: + { + rctf r = { + .xmin = size[0] - margin[0], .xmax = size[0], + .ymin = -size[1], .ymax = -size[1] + margin[1], + }; + ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin); + ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymax); + ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax); + verts_len = 3; + if (is_solid) { + ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymin); + verts_len += 1; + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINE_STRIP; + } + break; + } + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y: + { + rctf r = { + .xmin = size[0] - margin[0], .xmax = size[0], + .ymin = size[1] - margin[1], .ymax = size[1], + }; + ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymax); + ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymin); + ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymin); + verts_len = 3; + if (is_solid) { + ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymax); + verts_len += 1; + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINE_STRIP; + } + break; + } + case ED_MANIPULATOR_CAGE2D_PART_ROTATE: + { + const float rotate_pt[2] = {0.0f, size[1] + margin[1]}; + const rctf r_rotate = { + .xmin = rotate_pt[0] - margin[0] / 2.0f, + .xmax = rotate_pt[0] + margin[0] / 2.0f, + .ymin = rotate_pt[1] - margin[1] / 2.0f, + .ymax = rotate_pt[1] + margin[1] / 2.0f, + }; + + ARRAY_SET_ITEMS(verts[0], r_rotate.xmin, r_rotate.ymin); + ARRAY_SET_ITEMS(verts[1], r_rotate.xmin, r_rotate.ymax); + ARRAY_SET_ITEMS(verts[2], r_rotate.xmax, r_rotate.ymax); + ARRAY_SET_ITEMS(verts[3], r_rotate.xmax, r_rotate.ymin); + verts_len = 4; + if (is_solid) { + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINE_STRIP; + } + break; + } + + case ED_MANIPULATOR_CAGE2D_PART_TRANSLATE: + if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { + ARRAY_SET_ITEMS(verts[0], -margin[0] / 2, -margin[1] / 2); + ARRAY_SET_ITEMS(verts[1], margin[0] / 2, margin[1] / 2); + ARRAY_SET_ITEMS(verts[2], -margin[0] / 2, margin[1] / 2); + ARRAY_SET_ITEMS(verts[3], margin[0] / 2, -margin[1] / 2); + verts_len = 4; + if (is_solid) { + prim_type = GWN_PRIM_TRI_FAN; + } + else { + prim_type = GWN_PRIM_LINES; + } + } + else { + /* Only used for 3D view selection, never displayed to the user. */ + ARRAY_SET_ITEMS(verts[0], -size[0], -size[1]); + ARRAY_SET_ITEMS(verts[1], -size[0], size[1]); + ARRAY_SET_ITEMS(verts[2], size[0], size[1]); + ARRAY_SET_ITEMS(verts[3], size[0], -size[1]); + verts_len = 4; + if (is_solid) { + prim_type = GWN_PRIM_TRI_FAN; + } + else { + /* unreachable */ + BLI_assert(0); + prim_type = GWN_PRIM_LINE_STRIP; + } + } + break; + default: + return; + } + + BLI_assert(prim_type != GWN_PRIM_NONE); + + Gwn_VertFormat *format = immVertexFormat(); + struct { + uint pos, col; + } attr_id = { + .pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT), + .col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT), + }; + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + + { + if (is_solid) { + BLI_assert(ELEM(prim_type, GWN_PRIM_TRI_FAN)); + immBegin(prim_type, verts_len); + immAttrib3f(attr_id.col, 0.0f, 0.0f, 0.0f); + for (uint i = 0; i < verts_len; i++) { + immVertex2fv(attr_id.pos, verts[i]); + } + immEnd(); + } + else { + BLI_assert(ELEM(prim_type, GWN_PRIM_LINE_STRIP, GWN_PRIM_LINES)); + GPU_line_width(line_width + 3.0f); + + immBegin(prim_type, verts_len); + immAttrib3f(attr_id.col, 0.0f, 0.0f, 0.0f); + for (uint i = 0; i < verts_len; i++) { + immVertex2fv(attr_id.pos, verts[i]); + } + immEnd(); + + GPU_line_width(line_width); + + immBegin(prim_type, verts_len); + immAttrib3fv(attr_id.col, color); + for (uint i = 0; i < verts_len; i++) { + immVertex2fv(attr_id.pos, verts[i]); + } + immEnd(); + } + } + + immUnbindProgram(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Circle Draw Style + * + * Useful for 2D views, see: #ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE + * \{ */ + +static void imm_draw_point_aspect_2d( + uint pos, float x, float y, float rad_x, float rad_y, bool solid) +{ + immBegin(solid ? GWN_PRIM_TRI_FAN : GWN_PRIM_LINE_LOOP, 4); + immVertex2f(pos, x - rad_x, y - rad_y); + immVertex2f(pos, x - rad_x, y + rad_y); + immVertex2f(pos, x + rad_x, y + rad_y); + immVertex2f(pos, x + rad_x, y - rad_y); + immEnd(); +} + +static void cage2d_draw_circle_wire( + const rctf *r, const float margin[2], const float color[3], + const int transform_flag, const int draw_options) +{ + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fv(color); + + immBegin(GWN_PRIM_LINE_LOOP, 4); + immVertex2f(pos, r->xmin, r->ymin); + immVertex2f(pos, r->xmax, r->ymin); + immVertex2f(pos, r->xmax, r->ymax); + immVertex2f(pos, r->xmin, r->ymax); + immEnd(); + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { + immBegin(GWN_PRIM_LINE_LOOP, 2); + immVertex2f(pos, BLI_rctf_cent_x(r), r->ymax); + immVertex2f(pos, BLI_rctf_cent_x(r), r->ymax + margin[1]); + immEnd(); + } + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { + if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { + const float rad[2] = {margin[0] / 2, margin[1] / 2}; + const float center[2] = {BLI_rctf_cent_x(r), BLI_rctf_cent_y(r)}; + + immBegin(GWN_PRIM_LINES, 4); + immVertex2f(pos, center[0] - rad[0], center[1] - rad[1]); + immVertex2f(pos, center[0] + rad[0], center[1] + rad[1]); + immVertex2f(pos, center[0] + rad[0], center[1] - rad[1]); + immVertex2f(pos, center[0] - rad[0], center[1] + rad[1]); + immEnd(); + } + } + + immUnbindProgram(); +} + +static void cage2d_draw_circle_handles( + const rctf *r, const float margin[2], const float color[3], + const int transform_flag, + bool solid) +{ + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + void (*circle_fn)(uint, float, float, float, float, int) = + (solid) ? imm_draw_circle_fill_aspect_2d : imm_draw_circle_wire_aspect_2d; + const int resolu = 12; + const float rad[2] = {margin[0] / 3, margin[1] / 3}; + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fv(color); + + /* should really divide by two, but looks too bulky. */ + { + imm_draw_point_aspect_2d(pos, r->xmin, r->ymin, rad[0], rad[1], solid); + imm_draw_point_aspect_2d(pos, r->xmax, r->ymin, rad[0], rad[1], solid); + imm_draw_point_aspect_2d(pos, r->xmax, r->ymax, rad[0], rad[1], solid); + imm_draw_point_aspect_2d(pos, r->xmin, r->ymax, rad[0], rad[1], solid); + } + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { + const float handle[2] = {BLI_rctf_cent_x(r), r->ymax + (margin[1] * MANIPULATOR_MARGIN_OFFSET_SCALE)}; + circle_fn(pos, handle[0], handle[1], rad[0], rad[1], resolu); + } + + immUnbindProgram(); +} + +/** \} */ + +static void manipulator_cage2d_draw_intern( + wmManipulator *mpr, const bool select, const bool highlight, const int select_id) +{ + // const bool use_clamp = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) == 0; + float dims[2]; + RNA_float_get_array(mpr->ptr, "dimensions", dims); + float matrix_final[4][4]; + + const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); + const int draw_style = RNA_enum_get(mpr->ptr, "draw_style"); + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + + const float size_real[2] = {dims[0] / 2.0f, dims[1] / 2.0f}; + + WM_manipulator_calc_matrix_final(mpr, matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + float margin[2]; + manipulator_calc_rect_view_margin(mpr, dims, margin); + + /* Handy for quick testing draw (if it's outside bounds). */ + if (false) { + GPU_blend(true); + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv((const float[4]){1, 1, 1, 0.5f}); + float s = 0.5f; + immRectf(pos, -s, -s, s, s); + immUnbindProgram(); + GPU_blend(false); + } + + if (select) { + /* expand for hotspot */ + const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2}; + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE) { + int scale_parts[] = { + ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y, + + ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y, + }; + for (int i = 0; i < ARRAY_SIZE(scale_parts); i++) { + GPU_select_load_id(select_id | scale_parts[i]); + cage2d_draw_box_interaction( + mpr->color, scale_parts[i], size, margin, mpr->line_width, true, draw_options); + } + } + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { + const int transform_part = ED_MANIPULATOR_CAGE2D_PART_TRANSLATE; + GPU_select_load_id(select_id | transform_part); + cage2d_draw_box_interaction( + mpr->color, transform_part, size, margin, mpr->line_width, true, draw_options); + } + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { + cage2d_draw_box_interaction( + mpr->color, ED_MANIPULATOR_CAGE2D_PART_ROTATE, size_real, margin, mpr->line_width, true, draw_options); + } + } + else { + const rctf r = { + .xmin = -size_real[0], + .ymin = -size_real[1], + .xmax = size_real[0], + .ymax = size_real[1], + }; + if (draw_style == ED_MANIPULATOR_CAGE2D_STYLE_BOX) { + /* corner manipulators */ + GPU_line_width(mpr->line_width + 3.0f); + cage2d_draw_box_corners(&r, margin, (const float[3]){0, 0, 0}); + + /* corner manipulators */ + float color[4]; + manipulator_color_get(mpr, highlight, color); + GPU_line_width(mpr->line_width); + cage2d_draw_box_corners(&r, margin, color); + + bool show = false; + if (mpr->highlight_part == ED_MANIPULATOR_CAGE2D_PART_TRANSLATE) { + /* Only show if we're drawing the center handle + * otherwise the entire rectangle is the hotspot. */ + if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { + show = true; + } + } + else { + show = true; + } + + if (show) { + cage2d_draw_box_interaction( + mpr->color, mpr->highlight_part, size_real, margin, mpr->line_width, false, draw_options); + } + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { + cage2d_draw_box_interaction( + mpr->color, ED_MANIPULATOR_CAGE2D_PART_ROTATE, size_real, margin, mpr->line_width, false, draw_options); + } + } + else if (draw_style == ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE) { + float color[4]; + manipulator_color_get(mpr, highlight, color); + + GPU_line_smooth(true); + GPU_blend(true); + + GPU_line_width(mpr->line_width + 3.0f); + cage2d_draw_circle_wire(&r, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options); + GPU_line_width(mpr->line_width); + cage2d_draw_circle_wire(&r, margin, color, transform_flag, draw_options); + + + /* corner manipulators */ + cage2d_draw_circle_handles(&r, margin, color, transform_flag, true); + cage2d_draw_circle_handles(&r, margin, (const float[3]){0, 0, 0}, transform_flag, false); + + GPU_blend(false); + GPU_line_smooth(false); + } + else { + BLI_assert(0); + } + } + + GPU_line_width(1.0); + gpuPopMatrix(); +} + +/** + * For when we want to draw 2d cage in 3d views. + */ +static void manipulator_cage2d_draw_select(const bContext *UNUSED(C), wmManipulator *mpr, int select_id) +{ + manipulator_cage2d_draw_intern(mpr, true, false, select_id); +} + +static void manipulator_cage2d_draw(const bContext *UNUSED(C), wmManipulator *mpr) +{ + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + manipulator_cage2d_draw_intern(mpr, false, is_highlight, -1); +} + +static int manipulator_cage2d_get_cursor(wmManipulator *mpr) +{ + int highlight_part = mpr->highlight_part; + + if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { + return BC_NSEW_SCROLLCURSOR; + } + + switch (highlight_part) { + case ED_MANIPULATOR_CAGE2D_PART_TRANSLATE: + return BC_NSEW_SCROLLCURSOR; + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X: + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X: + return CURSOR_X_MOVE; + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y: + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y: + return CURSOR_Y_MOVE; + + /* TODO diagonal cursor */ + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y: + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y: + return BC_NSEW_SCROLLCURSOR; + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y: + case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y: + return BC_NSEW_SCROLLCURSOR; + case ED_MANIPULATOR_CAGE2D_PART_ROTATE: + return BC_CROSSCURSOR; + default: + return CURSOR_STD; + } +} + +static int manipulator_cage2d_test_select( + bContext *C, wmManipulator *mpr, const wmEvent *event) +{ + float point_local[2]; + float dims[2]; + RNA_float_get_array(mpr->ptr, "dimensions", dims); + const float size_real[2] = {dims[0] / 2.0f, dims[1] / 2.0f}; + + if (manipulator_window_project_2d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false) + { + return -1; + } + + float margin[2]; + manipulator_calc_rect_view_margin(mpr, dims, margin); + /* expand for hotspot */ + const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2}; + + const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { + rctf r; + if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { + r.xmin = -margin[0] / 2; + r.ymin = -margin[1] / 2; + r.xmax = margin[0] / 2; + r.ymax = margin[1] / 2; + } + else { + r.xmin = -size[0] + margin[0]; + r.ymin = -size[1] + margin[1]; + r.xmax = size[0] - margin[0]; + r.ymax = size[1] - margin[1]; + }; + bool isect = BLI_rctf_isect_pt_v(&r, point_local); + if (isect) { + return ED_MANIPULATOR_CAGE2D_PART_TRANSLATE; + } + } + + /* if manipulator does not have a scale intersection, don't do it */ + if (transform_flag & (ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM)) { + const rctf r_xmin = {.xmin = -size[0], .ymin = -size[1], .xmax = -size[0] + margin[0], .ymax = size[1]}; + const rctf r_xmax = {.xmin = size[0] - margin[0], .ymin = -size[1], .xmax = size[0], .ymax = size[1]}; + const rctf r_ymin = {.xmin = -size[0], .ymin = -size[1], .xmax = size[0], .ymax = -size[1] + margin[1]}; + const rctf r_ymax = {.xmin = -size[0], .ymin = size[1] - margin[1], .xmax = size[0], .ymax = size[1]}; + + if (BLI_rctf_isect_pt_v(&r_xmin, point_local)) { + if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) { + return ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y; + } + if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) { + return ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y; + } + return ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X; + } + if (BLI_rctf_isect_pt_v(&r_xmax, point_local)) { + if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) { + return ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y; + } + if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) { + return ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y; + } + return ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X; + } + if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) { + return ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y; + } + if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) { + return ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y; + } + } + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { + /* Rotate: + * (*) <-- hot spot is here! + * +---+ + * | | + * +---+ */ + const float r_rotate_pt[2] = {0.0f, size_real[1] + (margin[1] * MANIPULATOR_MARGIN_OFFSET_SCALE)}; + const rctf r_rotate = { + .xmin = r_rotate_pt[0] - margin[0] / 2.0f, + .xmax = r_rotate_pt[0] + margin[0] / 2.0f, + .ymin = r_rotate_pt[1] - margin[1] / 2.0f, + .ymax = r_rotate_pt[1] + margin[1] / 2.0f, + }; + + if (BLI_rctf_isect_pt_v(&r_rotate, point_local)) { + return ED_MANIPULATOR_CAGE2D_PART_ROTATE; + } + } + + return -1; +} + +typedef struct RectTransformInteraction { + float orig_mouse[2]; + float orig_matrix_offset[4][4]; + float orig_matrix_final_no_offset[4][4]; + Dial *dial; +} RectTransformInteraction; + +static void manipulator_cage2d_setup(wmManipulator *mpr) +{ + mpr->flag |= WM_MANIPULATOR_DRAW_MODAL | WM_MANIPULATOR_DRAW_NO_SCALE; +} + +static int manipulator_cage2d_invoke( + bContext *C, wmManipulator *mpr, const wmEvent *event) +{ + RectTransformInteraction *data = MEM_callocN(sizeof(RectTransformInteraction), "cage_interaction"); + + copy_m4_m4(data->orig_matrix_offset, mpr->matrix_offset); + WM_manipulator_calc_matrix_final_no_offset(mpr, data->orig_matrix_final_no_offset); + + if (manipulator_window_project_2d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, false, data->orig_mouse) == 0) + { + zero_v2(data->orig_mouse); + } + + mpr->interaction_data = data; + + return OPERATOR_RUNNING_MODAL; +} + +static int manipulator_cage2d_modal( + bContext *C, wmManipulator *mpr, const wmEvent *event, + eWM_ManipulatorTweak UNUSED(tweak_flag)) +{ + /* For transform logic to be managable we operate in -0.5..0.5 2D space, + * no matter the size of the rectangle, mouse coorts are scaled to unit space. + * The mouse coords have been projected into the matrix so we don't need to worry about axis alignment. + * + * - The cursor offset are multiplied by 'dims'. + * - Matrix translation is also multiplied by 'dims'. + */ + RectTransformInteraction *data = mpr->interaction_data; + float point_local[2]; + + float dims[2]; + RNA_float_get_array(mpr->ptr, "dimensions", dims); + + { + float matrix_back[4][4]; + copy_m4_m4(matrix_back, mpr->matrix_offset); + copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); + + bool ok = manipulator_window_project_2d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, false, point_local); + copy_m4_m4(mpr->matrix_offset, matrix_back); + if (!ok) { + return OPERATOR_RUNNING_MODAL; + } + } + + const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); + wmManipulatorProperty *mpr_prop; + + mpr_prop = WM_manipulator_target_property_find(mpr, "matrix"); + if (mpr_prop->type != NULL) { + WM_manipulator_target_property_value_get_array(mpr, mpr_prop, &mpr->matrix_offset[0][0]); + } + + if (mpr->highlight_part == ED_MANIPULATOR_CAGE2D_PART_TRANSLATE) { + /* do this to prevent clamping from changing size */ + copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); + mpr->matrix_offset[3][0] = data->orig_matrix_offset[3][0] + (point_local[0] - data->orig_mouse[0]); + mpr->matrix_offset[3][1] = data->orig_matrix_offset[3][1] + (point_local[1] - data->orig_mouse[1]); + } + else if (mpr->highlight_part == ED_MANIPULATOR_CAGE2D_PART_ROTATE) { + +#define MUL_V2_V3_M4_FINAL(test_co, mouse_co) \ + mul_v3_m4v3(test_co, data->orig_matrix_final_no_offset, ((const float[3]){UNPACK2(mouse_co), 0.0})) + + float test_co[3]; + + if (data->dial == NULL) { + MUL_V2_V3_M4_FINAL(test_co, data->orig_matrix_offset[3]); + + data->dial = BLI_dial_initialize(test_co, FLT_EPSILON); + + MUL_V2_V3_M4_FINAL(test_co, data->orig_mouse); + BLI_dial_angle(data->dial, test_co); + } + + /* rotate */ + MUL_V2_V3_M4_FINAL(test_co, point_local); + const float angle = BLI_dial_angle(data->dial, test_co); + + float matrix_space_inv[4][4]; + float matrix_rotate[4][4]; + float pivot[3]; + + copy_v3_v3(pivot, data->orig_matrix_offset[3]); + + invert_m4_m4(matrix_space_inv, mpr->matrix_space); + + unit_m4(matrix_rotate); + mul_m4_m4m4(matrix_rotate, matrix_rotate, matrix_space_inv); + rotate_m4(matrix_rotate, 'Z', -angle); + mul_m4_m4m4(matrix_rotate, matrix_rotate, mpr->matrix_space); + + zero_v3(matrix_rotate[3]); + transform_pivot_set_m4(matrix_rotate, pivot); + + mul_m4_m4m4(mpr->matrix_offset, matrix_rotate, data->orig_matrix_offset); + +#undef MUL_V2_V3_M4_FINAL + } + else { + /* scale */ + copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); + float pivot[2]; + bool constrain_axis[2] = {false}; + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { + manipulator_rect_pivot_from_scale_part(mpr->highlight_part, pivot, constrain_axis); + } + else { + zero_v2(pivot); + } + + /* Cursor deltas scaled to (-0.5..0.5). */ + float delta_orig[2], delta_curr[2]; + for (int i = 0; i < 2; i++) { + delta_orig[i] = ((data->orig_mouse[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i]; + delta_curr[i] = ((point_local[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i]; + } + + float scale[2] = {1.0f, 1.0f}; + for (int i = 0; i < 2; i++) { + if (constrain_axis[i] == false) { + if (delta_orig[i] < 0.0f) { + delta_orig[i] *= -1.0f; + delta_curr[i] *= -1.0f; + } + const int sign = signum_i(scale[i]); + + scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i])); + + if ((transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_SIGNED) == 0) { + if (sign != signum_i(scale[i])) { + scale[i] = 0.0f; + } + } + } + } + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM) { + if (constrain_axis[0] == false && constrain_axis[1] == false) { + scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f; + } + else if (constrain_axis[0] == false) { + scale[1] = scale[0]; + } + else if (constrain_axis[1] == false) { + scale[0] = scale[1]; + } + else { + BLI_assert(0); + } + } + + /* scale around pivot */ + float matrix_scale[4][4]; + unit_m4(matrix_scale); + + mul_v3_fl(matrix_scale[0], scale[0]); + mul_v3_fl(matrix_scale[1], scale[1]); + + transform_pivot_set_m4(matrix_scale, (const float[3]){pivot[0] * dims[0], pivot[1] * dims[1], 0.0f}); + mul_m4_m4m4(mpr->matrix_offset, data->orig_matrix_offset, matrix_scale); + } + + if (mpr_prop->type != NULL) { + WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, &mpr->matrix_offset[0][0]); + } + + /* tag the region for redraw */ + ED_region_tag_redraw(CTX_wm_region(C)); + WM_event_add_mousemove(C); + + return OPERATOR_RUNNING_MODAL; +} + +static void manipulator_cage2d_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop) +{ + if (STREQ(mpr_prop->type->idname, "matrix")) { + if (WM_manipulator_target_property_array_length(mpr, mpr_prop) == 16) { + WM_manipulator_target_property_value_get_array(mpr, mpr_prop, &mpr->matrix_offset[0][0]); + } + else { + BLI_assert(0); + } + } + else { + BLI_assert(0); + } +} + +static void manipulator_cage2d_exit(bContext *C, wmManipulator *mpr, const bool cancel) +{ + RectTransformInteraction *data = mpr->interaction_data; + + MEM_SAFE_FREE(data->dial); + + if (!cancel) + return; + + wmManipulatorProperty *mpr_prop; + + /* reset properties */ + mpr_prop = WM_manipulator_target_property_find(mpr, "matrix"); + if (mpr_prop->type != NULL) { + WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, &data->orig_matrix_offset[0][0]); + } + + copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); +} + + +/* -------------------------------------------------------------------- */ +/** \name Cage Manipulator API + * + * \{ */ + +static void MANIPULATOR_WT_cage_2d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_cage_2d"; + + /* api callbacks */ + wt->draw = manipulator_cage2d_draw; + wt->draw_select = manipulator_cage2d_draw_select; + wt->test_select = manipulator_cage2d_test_select; + wt->setup = manipulator_cage2d_setup; + wt->invoke = manipulator_cage2d_invoke; + wt->property_update = manipulator_cage2d_property_update; + wt->modal = manipulator_cage2d_modal; + wt->exit = manipulator_cage2d_exit; + wt->cursor_get = manipulator_cage2d_get_cursor; + + wt->struct_size = sizeof(wmManipulator); + + /* rna */ + static EnumPropertyItem rna_enum_draw_style[] = { + {ED_MANIPULATOR_CAGE2D_STYLE_BOX, "BOX", 0, "Box", ""}, + {ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE, "CIRCLE", 0, "Circle", ""}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem rna_enum_transform[] = { + {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE, "TRANSLATE", 0, "Translate", ""}, + {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE, "ROTATE", 0, "Rotate", ""}, + {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE, "SCALE", 0, "Scale", ""}, + {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM, "SCALE_UNIFORM", 0, "Scale Uniform", ""}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem rna_enum_draw_options[] = { + {ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "XFORM_CENTER_HANDLE", 0, "Center Handle", ""}, + {0, NULL, 0, NULL, NULL} + }; + static float unit_v2[2] = {1.0f, 1.0f}; + RNA_def_float_vector(wt->srna, "dimensions", 2, unit_v2, 0, FLT_MAX, "Dimensions", "", 0.0f, FLT_MAX); + RNA_def_enum_flag(wt->srna, "transform", rna_enum_transform, 0, "Transform Options", ""); + RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE, "Draw Style", ""); + RNA_def_enum_flag( + wt->srna, "draw_options", rna_enum_draw_options, + ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "Draw Options", ""); + + WM_manipulatortype_target_property_def(wt, "matrix", PROP_FLOAT, 16); +} + +void ED_manipulatortypes_cage_2d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_cage_2d); +} + +/** \} */ diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c new file mode 100644 index 00000000000..0f3e67d7585 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c @@ -0,0 +1,692 @@ +/* + * ***** 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 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file cage3d_gizmo.c + * \ingroup wm + * + * \name Cage Manipulator + * + * 2D Manipulator + * + * \brief Rectangular manipulator acting as a 'cage' around its content. + * Interacting scales or translates the manipulator. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_rect.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" + +#include "GPU_matrix.h" +#include "GPU_shader.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_select.h" +#include "GPU_state.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_gizmo_library.h" + +/* own includes */ +#include "../gizmo_library_intern.h" + +#define MANIPULATOR_RESIZER_SIZE 10.0f +#define MANIPULATOR_MARGIN_OFFSET_SCALE 1.5f + +static void manipulator_calc_matrix_final_no_offset( + const wmManipulator *mpr, float orig_matrix_final_no_offset[4][4], bool use_space) +{ + float mat_identity[4][4]; + struct WM_ManipulatorMatrixParams params = {NULL}; + unit_m4(mat_identity); + if (use_space == false) { + params.matrix_basis = mat_identity; + } + params.matrix_offset = mat_identity; + WM_manipulator_calc_matrix_final_params(mpr, ¶ms, orig_matrix_final_no_offset); +} + +static void manipulator_calc_rect_view_scale( + const wmManipulator *mpr, const float dims[3], float scale[3]) +{ + UNUSED_VARS(dims); + + /* Unlike cage2d, no need to correct for aspect. */ + float matrix_final_no_offset[4][4]; + + float x_axis[3], y_axis[3], z_axis[3]; + manipulator_calc_matrix_final_no_offset(mpr, matrix_final_no_offset, false); + mul_v3_mat3_m4v3(x_axis, matrix_final_no_offset, mpr->matrix_offset[0]); + mul_v3_mat3_m4v3(y_axis, matrix_final_no_offset, mpr->matrix_offset[1]); + mul_v3_mat3_m4v3(z_axis, matrix_final_no_offset, mpr->matrix_offset[2]); + + scale[0] = 1.0f / len_v3(x_axis); + scale[1] = 1.0f / len_v3(y_axis); + scale[2] = 1.0f / len_v3(z_axis); +} + +static void manipulator_calc_rect_view_margin( + const wmManipulator *mpr, const float dims[3], float margin[3]) +{ + float handle_size; + if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { + handle_size = 0.15f; + } + else { + handle_size = MANIPULATOR_RESIZER_SIZE; + } + // XXX, the scale isn't taking offset into account, we need to calculate scale per handle! + // handle_size *= mpr->scale_final; + + float scale_xyz[3]; + manipulator_calc_rect_view_scale(mpr, dims, scale_xyz); + margin[0] = ((handle_size * scale_xyz[0])); + margin[1] = ((handle_size * scale_xyz[1])); + margin[2] = ((handle_size * scale_xyz[2])); +} + +/* -------------------------------------------------------------------- */ + +static void manipulator_rect_pivot_from_scale_part(int part, float r_pt[3], bool r_constrain_axis[3]) +{ + if (part >= ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z && + part <= ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z) + { + int index = (part - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z); + int range[3]; + range[2] = index % 3; + index = index / 3; + range[1] = index % 3; + index = index / 3; + range[0] = index % 3; + + const float sign[3] = {0.5f, 0.0f, -0.5f}; + for (int i = 0; i < 3; i++) { + r_pt[i] = sign[range[i]]; + r_constrain_axis[i] = (range[i] == 1); + } + } +} + +/* -------------------------------------------------------------------- */ +/** \name Box Draw Style + * + * Useful for 3D views, see: #ED_MANIPULATOR_CAGE2D_STYLE_BOX + * \{ */ + +static void cage3d_draw_box_corners( + const float r[3], const float margin[3], const float color[3]) +{ + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + UNUSED_VARS(margin); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3fv(color); + + imm_draw_cube_wire_3d(pos, (float[3]){0}, r); + + immUnbindProgram(); +} + +static void cage3d_draw_box_interaction( + const float color[4], const int highlighted, + const float size[3], const float margin[3]) +{ + if (highlighted >= ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z && + highlighted <= ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z) + { + int index = (highlighted - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z); + int range[3]; + range[2] = index % 3; + index = index / 3; + range[1] = index % 3; + index = index / 3; + range[0] = index % 3; + + const float sign[3] = {-1.0f, 0.0f, 1.0f}; + float co[3]; + + for (int i = 0; i < 3; i++) { + co[i] = size[i] * sign[range[i]]; + } + const float rad[3] = {margin[0] / 3, margin[1] / 3, margin[2] / 3}; + + { + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3fv(color); + imm_draw_cube_fill_3d(pos, co, rad); + immUnbindProgram(); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Circle Draw Style + * + * Useful for 2D views, see: #ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE + * \{ */ + +static void imm_draw_point_aspect_3d( + uint pos, const float co[3], const float rad[3], bool solid) +{ + if (solid) { + imm_draw_cube_fill_3d(pos, co, rad); + } + else { + imm_draw_cube_wire_3d(pos, co, rad); + } +} + +static void cage3d_draw_circle_wire( + const float r[3], const float margin[3], const float color[3], + const int transform_flag, const int draw_options) +{ + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3fv(color); + + imm_draw_cube_wire_3d(pos, (float[3]){0}, r); + +#if 0 + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { + if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { + const float rad[2] = {margin[0] / 2, margin[1] / 2}; + const float center[2] = {0.0f, 0.0f}; + + immBegin(GWN_PRIM_LINES, 4); + immVertex2f(pos, center[0] - rad[0], center[1] - rad[1]); + immVertex2f(pos, center[0] + rad[0], center[1] + rad[1]); + immVertex2f(pos, center[0] + rad[0], center[1] - rad[1]); + immVertex2f(pos, center[0] - rad[0], center[1] + rad[1]); + immEnd(); + } + } +#else + UNUSED_VARS(margin, transform_flag, draw_options); +#endif + + + immUnbindProgram(); +} + +static void cage3d_draw_circle_handles( + const RegionView3D *rv3d, const float matrix_final[4][4], + const float r[3], const float margin[3], const float color[3], + bool solid, float scale) +{ + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + const float rad[3] = {margin[0] / 3, margin[1] / 3, margin[2] / 3}; + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3fv(color); + + float sign[3] = {-1.0f, 0.0f, 1.0f}; + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 3; y++) { + for (int z = 0; z < 3; z++) { + if (x == 1 && y == 1 && z == 1) { + continue; + } + const float co[3] = {r[0] * sign[x], r[1] * sign[y], r[2] * sign[z]}; + float co_test[3]; + mul_v3_m4v3(co_test, matrix_final, co); + float rad_scale[3]; + mul_v3_v3fl(rad_scale, rad, ED_view3d_pixel_size(rv3d, co_test) * scale); + imm_draw_point_aspect_3d(pos, co, rad_scale, solid); + } + } + } + + immUnbindProgram(); +} + +/** \} */ + +static void manipulator_cage3d_draw_intern( + RegionView3D *rv3d, + wmManipulator *mpr, const bool select, const bool highlight, const int select_id) +{ + // const bool use_clamp = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) == 0; + float dims[3]; + RNA_float_get_array(mpr->ptr, "dimensions", dims); + float matrix_final[4][4]; + + const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); + const int draw_style = RNA_enum_get(mpr->ptr, "draw_style"); + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + + const float size_real[3] = {dims[0] / 2.0f, dims[1] / 2.0f, dims[2] / 2.0f}; + + WM_manipulator_calc_matrix_final(mpr, matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + float margin[3]; + manipulator_calc_rect_view_margin(mpr, dims, margin); + + /* Handy for quick testing draw (if it's outside bounds). */ + if (false) { + GPU_blend(true); + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv((const float[4]){1, 1, 1, 0.5f}); + float s = 0.5f; + immRectf(pos, -s, -s, s, s); + immUnbindProgram(); + GPU_blend(false); + } + + if (select) { + /* expand for hotspot */ +#if 0 + const float size[3] = { + size_real[0] + margin[0] / 2, + size_real[1] + margin[1] / 2, + size_real[2] + margin[2] / 2, + }; +#else + /* just use same value for now. */ + const float size[3] = {UNPACK3(size_real)}; +#endif + + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE) { + for (int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; + i <= ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z; + i++) + { + if (i == ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MID_Y_MID_Z) { + continue; + } + GPU_select_load_id(select_id | i); + cage3d_draw_box_interaction( + mpr->color, i, size, margin); + } + } + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { + const int transform_part = ED_MANIPULATOR_CAGE3D_PART_TRANSLATE; + GPU_select_load_id(select_id | transform_part); + cage3d_draw_box_interaction( + mpr->color, transform_part, size, margin); + } + } + else { +#if 0 + const rctf _r = { + .xmin = -size_real[0], + .ymin = -size_real[1], + .xmax = size_real[0], + .ymax = size_real[1], + }; +#endif + if (draw_style == ED_MANIPULATOR_CAGE2D_STYLE_BOX) { + /* corner manipulators */ + GPU_line_width(mpr->line_width + 3.0f); + cage3d_draw_box_corners(size_real, margin, (const float[3]){0, 0, 0}); + + /* corner manipulators */ + float color[4]; + manipulator_color_get(mpr, highlight, color); + GPU_line_width(mpr->line_width); + cage3d_draw_box_corners(size_real, margin, color); + + bool show = false; + if (mpr->highlight_part == ED_MANIPULATOR_CAGE3D_PART_TRANSLATE) { + /* Only show if we're drawing the center handle + * otherwise the entire rectangle is the hotspot. */ + if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { + show = true; + } + } + else { + show = true; + } + + if (show) { + cage3d_draw_box_interaction( + mpr->color, mpr->highlight_part, size_real, margin); + } + } + else if (draw_style == ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE) { + float color[4]; + manipulator_color_get(mpr, highlight, color); + + GPU_line_smooth(true); + GPU_polygon_smooth(true); + GPU_blend(true); + + GPU_line_width(mpr->line_width + 3.0f); + cage3d_draw_circle_wire(size_real, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options); + GPU_line_width(mpr->line_width); + cage3d_draw_circle_wire(size_real, margin, color, transform_flag, draw_options); + + /* corner manipulators */ + cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, (const float[3]){0, 0, 0}, true, 60); + cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, color, true, 40); + + GPU_blend(false); + GPU_polygon_smooth(false); + GPU_line_smooth(false); + } + else { + BLI_assert(0); + } + } + + GPU_line_width(1.0); + gpuPopMatrix(); +} + +/** + * For when we want to draw 3d cage in 3d views. + */ +static void manipulator_cage3d_draw_select(const bContext *C, wmManipulator *mpr, int select_id) +{ + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + manipulator_cage3d_draw_intern(rv3d, mpr, true, false, select_id); +} + +static void manipulator_cage3d_draw(const bContext *C, wmManipulator *mpr) +{ + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + manipulator_cage3d_draw_intern(rv3d, mpr, false, is_highlight, -1); +} + +static int manipulator_cage3d_get_cursor(wmManipulator *mpr) +{ + if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { + return BC_NSEW_SCROLLCURSOR; + } + + return CURSOR_STD; +} + +typedef struct RectTransformInteraction { + float orig_mouse[3]; + float orig_matrix_offset[4][4]; + float orig_matrix_final_no_offset[4][4]; +} RectTransformInteraction; + +static void manipulator_cage3d_setup(wmManipulator *mpr) +{ + mpr->flag |= /* WM_MANIPULATOR_DRAW_MODAL | */ /* TODO */ + WM_MANIPULATOR_DRAW_NO_SCALE; +} + +static int manipulator_cage3d_invoke( + bContext *C, wmManipulator *mpr, const wmEvent *event) +{ + RectTransformInteraction *data = MEM_callocN(sizeof(RectTransformInteraction), "cage_interaction"); + + copy_m4_m4(data->orig_matrix_offset, mpr->matrix_offset); + manipulator_calc_matrix_final_no_offset(mpr, data->orig_matrix_final_no_offset, true); + + if (manipulator_window_project_3d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, false, data->orig_mouse) == 0) + { + zero_v3(data->orig_mouse); + } + + mpr->interaction_data = data; + + return OPERATOR_RUNNING_MODAL; +} + +static int manipulator_cage3d_modal( + bContext *C, wmManipulator *mpr, const wmEvent *event, + eWM_ManipulatorTweak UNUSED(tweak_flag)) +{ + /* For transform logic to be managable we operate in -0.5..0.5 2D space, + * no matter the size of the rectangle, mouse coorts are scaled to unit space. + * The mouse coords have been projected into the matrix so we don't need to worry about axis alignment. + * + * - The cursor offset are multiplied by 'dims'. + * - Matrix translation is also multiplied by 'dims'. + */ + RectTransformInteraction *data = mpr->interaction_data; + float point_local[3]; + + float dims[3]; + RNA_float_get_array(mpr->ptr, "dimensions", dims); + + { + float matrix_back[4][4]; + copy_m4_m4(matrix_back, mpr->matrix_offset); + copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); + + bool ok = manipulator_window_project_3d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, false, point_local); + copy_m4_m4(mpr->matrix_offset, matrix_back); + if (!ok) { + return OPERATOR_RUNNING_MODAL; + } + } + + const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); + wmManipulatorProperty *mpr_prop; + + mpr_prop = WM_manipulator_target_property_find(mpr, "matrix"); + if (mpr_prop->type != NULL) { + WM_manipulator_target_property_value_get_array(mpr, mpr_prop, &mpr->matrix_offset[0][0]); + } + + if (mpr->highlight_part == ED_MANIPULATOR_CAGE3D_PART_TRANSLATE) { + /* do this to prevent clamping from changing size */ + copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); + mpr->matrix_offset[3][0] = data->orig_matrix_offset[3][0] + (point_local[0] - data->orig_mouse[0]); + mpr->matrix_offset[3][1] = data->orig_matrix_offset[3][1] + (point_local[1] - data->orig_mouse[1]); + mpr->matrix_offset[3][2] = data->orig_matrix_offset[3][2] + (point_local[2] - data->orig_mouse[2]); + } + else if (mpr->highlight_part == ED_MANIPULATOR_CAGE3D_PART_ROTATE) { + /* TODO (if needed) */ + } + else { + /* scale */ + copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); + float pivot[3]; + bool constrain_axis[3] = {false}; + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { + manipulator_rect_pivot_from_scale_part(mpr->highlight_part, pivot, constrain_axis); + } + else { + zero_v3(pivot); + } + + /* Cursor deltas scaled to (-0.5..0.5). */ + float delta_orig[3], delta_curr[3]; + + for (int i = 0; i < 3; i++) { + delta_orig[i] = ((data->orig_mouse[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i]; + delta_curr[i] = ((point_local[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i]; + } + + float scale[3] = {1.0f, 1.0f, 1.0f}; + for (int i = 0; i < 3; i++) { + if (constrain_axis[i] == false) { + if (delta_orig[i] < 0.0f) { + delta_orig[i] *= -1.0f; + delta_curr[i] *= -1.0f; + } + const int sign = signum_i(scale[i]); + + scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i])); + + if ((transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_SIGNED) == 0) { + if (sign != signum_i(scale[i])) { + scale[i] = 0.0f; + } + } + } + } + + if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM) { + if (constrain_axis[0] == false && constrain_axis[1] == false) { + scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f; + } + else if (constrain_axis[0] == false) { + scale[1] = scale[0]; + } + else if (constrain_axis[1] == false) { + scale[0] = scale[1]; + } + else { + BLI_assert(0); + } + } + + /* scale around pivot */ + float matrix_scale[4][4]; + unit_m4(matrix_scale); + + mul_v3_fl(matrix_scale[0], scale[0]); + mul_v3_fl(matrix_scale[1], scale[1]); + mul_v3_fl(matrix_scale[2], scale[2]); + + transform_pivot_set_m4( + matrix_scale, + (const float[3]){pivot[0] * dims[0], pivot[1] * dims[1], pivot[2] * dims[2]}); + mul_m4_m4m4(mpr->matrix_offset, data->orig_matrix_offset, matrix_scale); + } + + if (mpr_prop->type != NULL) { + WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, &mpr->matrix_offset[0][0]); + } + + /* tag the region for redraw */ + ED_region_tag_redraw(CTX_wm_region(C)); + WM_event_add_mousemove(C); + + return OPERATOR_RUNNING_MODAL; +} + +static void manipulator_cage3d_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop) +{ + if (STREQ(mpr_prop->type->idname, "matrix")) { + if (WM_manipulator_target_property_array_length(mpr, mpr_prop) == 16) { + WM_manipulator_target_property_value_get_array(mpr, mpr_prop, &mpr->matrix_offset[0][0]); + } + else { + BLI_assert(0); + } + } + else { + BLI_assert(0); + } +} + +static void manipulator_cage3d_exit(bContext *C, wmManipulator *mpr, const bool cancel) +{ + RectTransformInteraction *data = mpr->interaction_data; + + if (!cancel) + return; + + wmManipulatorProperty *mpr_prop; + + /* reset properties */ + mpr_prop = WM_manipulator_target_property_find(mpr, "matrix"); + if (mpr_prop->type != NULL) { + WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, &data->orig_matrix_offset[0][0]); + } + + copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); +} + + +/* -------------------------------------------------------------------- */ +/** \name Cage Manipulator API + * + * \{ */ + +static void MANIPULATOR_WT_cage_3d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_cage_3d"; + + /* api callbacks */ + wt->draw = manipulator_cage3d_draw; + wt->draw_select = manipulator_cage3d_draw_select; + wt->setup = manipulator_cage3d_setup; + wt->invoke = manipulator_cage3d_invoke; + wt->property_update = manipulator_cage3d_property_update; + wt->modal = manipulator_cage3d_modal; + wt->exit = manipulator_cage3d_exit; + wt->cursor_get = manipulator_cage3d_get_cursor; + + wt->struct_size = sizeof(wmManipulator); + + /* rna */ + static EnumPropertyItem rna_enum_draw_style[] = { + {ED_MANIPULATOR_CAGE2D_STYLE_BOX, "BOX", 0, "Box", ""}, + {ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE, "CIRCLE", 0, "Circle", ""}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem rna_enum_transform[] = { + {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE, "TRANSLATE", 0, "Translate", ""}, + {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE, "SCALE", 0, "Scale", ""}, + {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM, "SCALE_UNIFORM", 0, "Scale Uniform", ""}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem rna_enum_draw_options[] = { + {ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "XFORM_CENTER_HANDLE", 0, "Center Handle", ""}, + {0, NULL, 0, NULL, NULL} + }; + static float unit_v3[3] = {1.0f, 1.0f, 1.0f}; + RNA_def_float_vector(wt->srna, "dimensions", 3, unit_v3, 0, FLT_MAX, "Dimensions", "", 0.0f, FLT_MAX); + RNA_def_enum_flag(wt->srna, "transform", rna_enum_transform, 0, "Transform Options", ""); + RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE, "Draw Style", ""); + RNA_def_enum_flag( + wt->srna, "draw_options", rna_enum_draw_options, + ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "Draw Options", ""); + + WM_manipulatortype_target_property_def(wt, "matrix", PROP_FLOAT, 16); +} + +void ED_manipulatortypes_cage_3d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_cage_3d); +} + +/** \} */ diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c new file mode 100644 index 00000000000..8d0061f66c8 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c @@ -0,0 +1,487 @@ +/* + * ***** 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 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file dial3d_gizmo.c + * \ingroup wm + * + * \name Dial Manipulator + * + * 3D Manipulator + * + * \brief Circle shaped manipulator for circular interaction. + * Currently no own handling, use with operator only. + * + * - `matrix[0]` is derived from Y and Z. + * - `matrix[1]` is 'up' when DialManipulator.use_start_y_axis is set. + * - `matrix[2]` is the axis the dial rotates around (all dials). + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.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_select.h" +#include "GPU_state.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_gizmo_library.h" + +/* own includes */ +#include "../gizmo_geometry.h" +#include "../gizmo_library_intern.h" + +/* to use custom dials exported to geom_dial_manipulator.c */ +// #define USE_MANIPULATOR_CUSTOM_DIAL + +static int manipulator_dial_modal( + bContext *C, wmManipulator *mpr, const wmEvent *event, + eWM_ManipulatorTweak tweak_flag); + +typedef struct DialInteraction { + float init_mval[2]; + + /* only for when using properties */ + float init_prop_angle; + + /* cache the last angle to detect rotations bigger than -/+ PI */ + float last_angle; + /* number of full rotations */ + int rotations; + + /* final output values, used for drawing */ + struct { + float angle_ofs; + float angle_delta; + } output; +} DialInteraction; + +#define DIAL_WIDTH 1.0f +#define DIAL_RESOLUTION 48 + +/* Could make option, negative to clip more (don't show when view aligned). */ +#define DIAL_CLIP_BIAS 0.02 + +/** + * We can't use this for the #wmManipulatorType.matrix_basis_get callback, it conflicts with depth picking. + */ +static void dial_calc_matrix(const wmManipulator *mpr, float mat[4][4]) +{ + float rot[3][3]; + const float up[3] = {0.0f, 0.0f, 1.0f}; + + rotation_between_vecs_to_mat3(rot, up, mpr->matrix_basis[2]); + copy_m4_m3(mat, rot); + copy_v3_v3(mat[3], mpr->matrix_basis[3]); +} + +/* -------------------------------------------------------------------- */ + +static void dial_geom_draw( + const wmManipulator *mpr, const float color[4], const bool select, + float axis_modal_mat[4][4], float clip_plane[4]) +{ +#ifdef USE_MANIPULATOR_CUSTOM_DIAL + UNUSED_VARS(dial, col, axis_modal_mat, clip_plane); + wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_dial, select); +#else + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + const bool filled = (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL) != 0; + + GPU_line_width(mpr->line_width); + + Gwn_VertFormat *format = immVertexFormat(); + uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + if (clip_plane) { + immBindBuiltinProgram(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR); + float clip_plane_f[4] = {clip_plane[0], clip_plane[1], clip_plane[2], clip_plane[3]}; + immUniform4fv("ClipPlane", clip_plane_f); + immUniformMatrix4fv("ModelMatrix", axis_modal_mat); + } + else { + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + } + + immUniformColor4fv(color); + + if (filled) { + imm_draw_circle_fill_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION); + } + else { + imm_draw_circle_wire_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION); + } + + immUnbindProgram(); + + UNUSED_VARS(select); +#endif +} + +/** + * Draws a line from (0, 0, 0) to \a co_outer, at \a angle. + */ +static void dial_ghostarc_draw_helpline(const float angle, const float co_outer[3], const float color[4]) +{ + GPU_line_width(1.0f); + + gpuPushMatrix(); + gpuRotate3f(RAD2DEGF(angle), 0.0f, 0.0f, -1.0f); + + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + immUniformColor4fv(color); + + immBegin(GWN_PRIM_LINE_STRIP, 2); + immVertex3f(pos, 0.0f, 0.0f, 0.0f); + immVertex3fv(pos, co_outer); + immEnd(); + + immUnbindProgram(); + + gpuPopMatrix(); +} + +static void dial_ghostarc_draw( + const wmManipulator *mpr, const float angle_ofs, const float angle_delta, const float color[4]) +{ + const float width_inner = DIAL_WIDTH - mpr->line_width * 0.5f / U.manipulator_size; + + Gwn_VertFormat *format = immVertexFormat(); + uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor4fv(color); + imm_draw_disk_partial_fill_2d( + pos, 0, 0, 0.0, width_inner, DIAL_RESOLUTION, RAD2DEGF(angle_ofs), RAD2DEGF(angle_delta)); + immUnbindProgram(); +} + +static void dial_ghostarc_get_angles( + struct Depsgraph *depsgraph, + const wmManipulator *mpr, + const wmEvent *event, + const ARegion *ar, const View3D *v3d, + float mat[4][4], const float co_outer[3], + float *r_start, float *r_delta) +{ + DialInteraction *inter = mpr->interaction_data; + const RegionView3D *rv3d = ar->regiondata; + const float mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin}; + + /* we might need to invert the direction of the angles */ + float view_vec[3], axis_vec[3]; + ED_view3d_global_to_vector(rv3d, mpr->matrix_basis[3], view_vec); + normalize_v3_v3(axis_vec, mpr->matrix_basis[2]); + + float proj_outer_rel[3]; + mul_v3_project_m4_v3(proj_outer_rel, mat, co_outer); + sub_v3_v3(proj_outer_rel, mpr->matrix_basis[3]); + + float proj_mval_new_rel[3]; + float proj_mval_init_rel[3]; + float dial_plane[4]; + float ray_co[3], ray_no[3]; + float ray_lambda; + + plane_from_point_normal_v3(dial_plane, mpr->matrix_basis[3], axis_vec); + + if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, inter->init_mval, ray_co, ray_no, false) || + !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false)) + { + goto fail; + } + madd_v3_v3v3fl(proj_mval_init_rel, ray_co, ray_no, ray_lambda); + sub_v3_v3(proj_mval_init_rel, mpr->matrix_basis[3]); + + if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, mval, ray_co, ray_no, false) || + !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false)) + { + goto fail; + } + madd_v3_v3v3fl(proj_mval_new_rel, ray_co, ray_no, ray_lambda); + sub_v3_v3(proj_mval_new_rel, mpr->matrix_basis[3]); + + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + + /* Start direction from mouse or set by user */ + const float *proj_init_rel = + (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y) ? + mpr->matrix_basis[1] : proj_mval_init_rel; + + /* return angles */ + const float start = angle_wrap_rad(angle_signed_on_axis_v3v3_v3(proj_outer_rel, proj_init_rel, axis_vec)); + const float delta = angle_wrap_rad(angle_signed_on_axis_v3v3_v3(proj_mval_init_rel, proj_mval_new_rel, axis_vec)); + + /* Change of sign, we passed the 180 degree threshold. This means we need to add a turn + * to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2. + * Logic taken from BLI_dial_angle */ + if ((delta * inter->last_angle < 0.0f) && + (fabsf(inter->last_angle) > (float)M_PI_2)) + { + if (inter->last_angle < 0.0f) + inter->rotations--; + else + inter->rotations++; + } + inter->last_angle = delta; + + *r_start = start; + *r_delta = fmod(delta + 2.0f * (float)M_PI * inter->rotations, 2 * (float)M_PI); + return; + + /* If we can't project (unlikely). */ +fail: + *r_start = 0.0; + *r_delta = 0.0; +} + +static void dial_draw_intern( + const bContext *C, wmManipulator *mpr, + const bool select, const bool highlight, float clip_plane[4]) +{ + float matrix_basis_adjust[4][4]; + float matrix_final[4][4]; + float color[4]; + + BLI_assert(CTX_wm_area(C)->spacetype == SPACE_VIEW3D); + + manipulator_color_get(mpr, highlight, color); + + dial_calc_matrix(mpr, matrix_basis_adjust); + + WM_manipulator_calc_matrix_final_params( + mpr, &((struct WM_ManipulatorMatrixParams) { + .matrix_basis = (void *)matrix_basis_adjust, + }), matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + /* draw rotation indicator arc first */ + if ((mpr->flag & WM_MANIPULATOR_DRAW_VALUE) && + (mpr->state & WM_MANIPULATOR_STATE_MODAL)) + { + const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f}; /* coordinate at which the arc drawing will be started */ + + DialInteraction *inter = mpr->interaction_data; + + /* XXX, View3D rotation manipulator doesn't call modal. */ + if (!WM_manipulator_target_property_is_valid_any(mpr)) { + wmWindow *win = CTX_wm_window(C); + manipulator_dial_modal((bContext *)C, mpr, win->eventstate, 0); + } + + float angle_ofs = inter->output.angle_ofs; + float angle_delta = inter->output.angle_delta; + + /* draw! */ + for (int i = 0; i < 2; i++) { + GPU_polygon_smooth(false); + dial_ghostarc_draw(mpr, angle_ofs, angle_delta, (const float[4]){0.8f, 0.8f, 0.8f, 0.4f}); + GPU_polygon_smooth(true); + + dial_ghostarc_draw_helpline(angle_ofs, co_outer, color); /* starting position */ + dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer, color); /* starting position + current value */ + + if (i == 0) { + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + if ((draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR) == 0) { + break; + } + } + + angle_ofs += (float)M_PI; + } + } + + /* draw actual dial manipulator */ + dial_geom_draw(mpr, color, select, matrix_basis_adjust, clip_plane); + + gpuPopMatrix(); +} + +static void manipulator_dial_draw_select(const bContext *C, wmManipulator *mpr, int select_id) +{ + float clip_plane_buf[4]; + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + float *clip_plane = (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP) ? clip_plane_buf : NULL; + + /* enable clipping if needed */ + if (clip_plane) { + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + copy_v3_v3(clip_plane, rv3d->viewinv[2]); + clip_plane[3] = -dot_v3v3(rv3d->viewinv[2], mpr->matrix_basis[3]); + clip_plane[3] += DIAL_CLIP_BIAS * mpr->scale_final; + glEnable(GL_CLIP_DISTANCE0); + } + + GPU_select_load_id(select_id); + dial_draw_intern(C, mpr, true, false, clip_plane); + + if (clip_plane) { + glDisable(GL_CLIP_DISTANCE0); + } +} + +static void manipulator_dial_draw(const bContext *C, wmManipulator *mpr) +{ + const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL; + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + float clip_plane_buf[4]; + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + float *clip_plane = (!is_modal && (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP)) ? clip_plane_buf : NULL; + + /* enable clipping if needed */ + if (clip_plane) { + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + copy_v3_v3(clip_plane, rv3d->viewinv[2]); + clip_plane[3] = -dot_v3v3(rv3d->viewinv[2], mpr->matrix_basis[3]); + clip_plane[3] += DIAL_CLIP_BIAS * mpr->scale_final; + + glEnable(GL_CLIP_DISTANCE0); + } + + GPU_blend(true); + dial_draw_intern(C, mpr, false, is_highlight, clip_plane); + GPU_blend(false); + + if (clip_plane) { + glDisable(GL_CLIP_DISTANCE0); + } +} + +static int manipulator_dial_modal( + bContext *C, wmManipulator *mpr, const wmEvent *event, + eWM_ManipulatorTweak UNUSED(tweak_flag)) +{ + const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f}; /* coordinate at which the arc drawing will be started */ + float angle_ofs, angle_delta; + + float matrix[4][4]; + + dial_calc_matrix(mpr, matrix); + + dial_ghostarc_get_angles( + CTX_data_depsgraph(C), + mpr, event, CTX_wm_region(C), CTX_wm_view3d(C), matrix, co_outer, &angle_ofs, &angle_delta); + + DialInteraction *inter = mpr->interaction_data; + + inter->output.angle_delta = angle_delta; + inter->output.angle_ofs = angle_ofs; + + /* set the property for the operator and call its modal function */ + wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); + if (WM_manipulator_target_property_is_valid(mpr_prop)) { + WM_manipulator_target_property_value_set(C, mpr, mpr_prop, inter->init_prop_angle + angle_delta); + } + return OPERATOR_RUNNING_MODAL; +} + + +static void manipulator_dial_setup(wmManipulator *mpr) +{ + const float dir_default[3] = {0.0f, 0.0f, 1.0f}; + + /* defaults */ + copy_v3_v3(mpr->matrix_basis[2], dir_default); +} + +static int manipulator_dial_invoke( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) +{ + DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__); + + inter->init_mval[0] = event->mval[0]; + inter->init_mval[1] = event->mval[1]; + + wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); + if (WM_manipulator_target_property_is_valid(mpr_prop)) { + inter->init_prop_angle = WM_manipulator_target_property_value_get(mpr, mpr_prop); + } + + mpr->interaction_data = inter; + + return OPERATOR_RUNNING_MODAL; +} + +/* -------------------------------------------------------------------- */ +/** \name Dial Manipulator API + * + * \{ */ + +static void MANIPULATOR_WT_dial_3d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_dial_3d"; + + /* api callbacks */ + wt->draw = manipulator_dial_draw; + wt->draw_select = manipulator_dial_draw_select; + wt->setup = manipulator_dial_setup; + wt->invoke = manipulator_dial_invoke; + wt->modal = manipulator_dial_modal; + + wt->struct_size = sizeof(wmManipulator); + + /* rna */ + static EnumPropertyItem rna_enum_draw_options[] = { + {ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP, "CLIP", 0, "Clipped", ""}, + {ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""}, + {ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR, "ANGLE_MIRROR", 0, "Angle Mirror", ""}, + {ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y, "ANGLE_START_Y", 0, "Angle Start Y", ""}, + {0, NULL, 0, NULL, NULL} + }; + RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", ""); + + WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 1); +} + +void ED_manipulatortypes_dial_3d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_dial_3d); +} + +/** \} */ diff --git a/source/blender/editors/gizmo_library/gizmo_types/grab3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/grab3d_gizmo.c new file mode 100644 index 00000000000..e55b57327b6 --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/grab3d_gizmo.c @@ -0,0 +1,375 @@ +/* + * ***** 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 grab3d_gizmo.c + * \ingroup wm + * + * \name Grab Manipulator + * + * 3D Manipulator, also works in 2D views. + * + * \brief Simple manipulator to grab and translate. + * + * - `matrix[0]` is derived from Y and Z. + * - `matrix[1]` currently not used. + * - `matrix[2]` is the widget direction (for all manipulators). + * + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.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_select.h" +#include "GPU_state.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_gizmo_library.h" + +/* own includes */ +#include "../gizmo_geometry.h" +#include "../gizmo_library_intern.h" + +typedef struct GrabManipulator3D { + wmManipulator manipulator; + /* Added to 'matrix_basis' when calculating the matrix. */ + float prop_co[3]; +} GrabManipulator3D; + +static void manipulator_grab_matrix_basis_get(const wmManipulator *mpr, float r_matrix[4][4]) +{ + GrabManipulator3D *grab = (GrabManipulator3D *)mpr; + + copy_m4_m4(r_matrix, grab->manipulator.matrix_basis); + add_v3_v3(r_matrix[3], grab->prop_co); +} + +static int manipulator_grab_modal( + bContext *C, wmManipulator *mpr, const wmEvent *event, + eWM_ManipulatorTweak tweak_flag); + +typedef struct GrabInteraction { + float init_mval[2]; + + /* only for when using properties */ + float init_prop_co[3]; + + float init_matrix_final[4][4]; +} GrabInteraction; + +#define DIAL_RESOLUTION 32 + +/* -------------------------------------------------------------------- */ + +static void grab_geom_draw( + const wmManipulator *mpr, const float color[4], const bool select, const int draw_options) +{ +#ifdef USE_MANIPULATOR_CUSTOM_DIAL + UNUSED_VARS(grab3d, col, axis_modal_mat); + wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_grab3d, select); +#else + const int draw_style = RNA_enum_get(mpr->ptr, "draw_style"); + const bool filled = (draw_options & ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL) != 0; + + GPU_line_width(mpr->line_width); + + Gwn_VertFormat *format = immVertexFormat(); + uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + immUniformColor4fv(color); + + if (draw_style == ED_MANIPULATOR_GRAB_STYLE_RING_2D) { + if (filled) { + imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION); + } + else { + imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION); + } + } + else if (draw_style == ED_MANIPULATOR_GRAB_STYLE_CROSS_2D) { + immBegin(GWN_PRIM_LINES, 4); + immVertex2f(pos, 1.0f, 1.0f); + immVertex2f(pos, -1.0f, -1.0f); + + immVertex2f(pos, -1.0f, 1.0f); + immVertex2f(pos, 1.0f, -1.0f); + immEnd(); + } + else { + BLI_assert(0); + } + + immUnbindProgram(); + + UNUSED_VARS(select); +#endif +} + +static void grab3d_get_translate( + const wmManipulator *mpr, const wmEvent *event, const ARegion *ar, + float co_delta[3]) +{ + GrabInteraction *inter = mpr->interaction_data; + const float mval_delta[2] = { + event->mval[0] - inter->init_mval[0], + event->mval[1] - inter->init_mval[1], + }; + + RegionView3D *rv3d = ar->regiondata; + float co_ref[3]; + mul_v3_mat3_m4v3(co_ref, mpr->matrix_space, inter->init_prop_co); + const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL); + + ED_view3d_win_to_delta(ar, mval_delta, co_delta, zfac); + + float matrix_space_inv[3][3]; + copy_m3_m4(matrix_space_inv, mpr->matrix_space); + invert_m3(matrix_space_inv); + mul_m3_v3(matrix_space_inv, co_delta); +} + +static void grab3d_draw_intern( + const bContext *C, wmManipulator *mpr, + const bool select, const bool highlight) +{ + GrabInteraction *inter = mpr->interaction_data; + const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); + const bool align_view = (draw_options & ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW) != 0; + float color[4]; + float matrix_final[4][4]; + float matrix_align[4][4]; + + manipulator_color_get(mpr, highlight, color); + WM_manipulator_calc_matrix_final(mpr, matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + if (align_view) { + float matrix_final_unit[4][4]; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + normalize_m4_m4(matrix_final_unit, matrix_final); + mul_m4_m4m4(matrix_align, rv3d->viewmat, matrix_final_unit); + zero_v3(matrix_align[3]); + transpose_m4(matrix_align); + gpuMultMatrix(matrix_align); + } + + GPU_blend(true); + grab_geom_draw(mpr, color, select, draw_options); + GPU_blend(false); + gpuPopMatrix(); + + if (mpr->interaction_data) { + gpuPushMatrix(); + gpuMultMatrix(inter->init_matrix_final); + + if (align_view) { + gpuMultMatrix(matrix_align); + } + + GPU_blend(true); + grab_geom_draw(mpr, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}, select, draw_options); + GPU_blend(false); + gpuPopMatrix(); + } +} + +static void manipulator_grab_draw_select(const bContext *C, wmManipulator *mpr, int select_id) +{ + GPU_select_load_id(select_id); + grab3d_draw_intern(C, mpr, true, false); +} + +static void manipulator_grab_draw(const bContext *C, wmManipulator *mpr) +{ + const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL; + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + + (void)is_modal; + + GPU_blend(true); + grab3d_draw_intern(C, mpr, false, is_highlight); + GPU_blend(false); +} + +static int manipulator_grab_modal( + bContext *C, wmManipulator *mpr, const wmEvent *event, + eWM_ManipulatorTweak UNUSED(tweak_flag)) +{ + GrabManipulator3D *grab = (GrabManipulator3D *)mpr; + GrabInteraction *inter = mpr->interaction_data; + ARegion *ar = CTX_wm_region(C); + + float prop_delta[3]; + if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D) { + grab3d_get_translate(mpr, event, ar, prop_delta); + } + else { + float mval_proj_init[2], mval_proj_curr[2]; + if ((manipulator_window_project_2d( + C, mpr, inter->init_mval, 2, false, mval_proj_init) == false) || + (manipulator_window_project_2d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, false, mval_proj_curr) == false)) + { + return OPERATOR_RUNNING_MODAL; + } + sub_v2_v2v2(prop_delta, mval_proj_curr, mval_proj_init); + prop_delta[2] = 0.0f; + } + add_v3_v3v3(grab->prop_co, inter->init_prop_co, prop_delta); + + /* set the property for the operator and call its modal function */ + wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); + if (WM_manipulator_target_property_is_valid(mpr_prop)) { + WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, grab->prop_co); + } + else { + zero_v3(grab->prop_co); + } + + ED_region_tag_redraw(ar); + + return OPERATOR_RUNNING_MODAL; +} + +static int manipulator_grab_invoke( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) +{ + GrabInteraction *inter = MEM_callocN(sizeof(GrabInteraction), __func__); + + inter->init_mval[0] = event->mval[0]; + inter->init_mval[1] = event->mval[1]; + +#if 0 + copy_v3_v3(inter->init_prop_co, grab->prop_co); +#else + wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); + if (WM_manipulator_target_property_is_valid(mpr_prop)) { + WM_manipulator_target_property_value_get_array(mpr, mpr_prop, inter->init_prop_co); + } +#endif + + WM_manipulator_calc_matrix_final(mpr, inter->init_matrix_final); + + mpr->interaction_data = inter; + + return OPERATOR_RUNNING_MODAL; +} + + +static int manipulator_grab_test_select( + bContext *C, wmManipulator *mpr, const wmEvent *event) +{ + float point_local[2]; + + if (manipulator_window_project_2d( + C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false) + { + return -1; + } + + /* The 'mpr->scale_final' is already applied when projecting. */ + if (len_squared_v2(point_local) < 1.0f) { + return 0; + } + + return -1; +} + +static void manipulator_grab_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop) +{ + GrabManipulator3D *grab = (GrabManipulator3D *)mpr; + if (WM_manipulator_target_property_is_valid(mpr_prop)) { + WM_manipulator_target_property_value_get_array(mpr, mpr_prop, grab->prop_co); + } + else { + zero_v3(grab->prop_co); + } +} + +static int manipulator_grab_cursor_get(wmManipulator *UNUSED(mpr)) +{ + return BC_NSEW_SCROLLCURSOR; +} + +/* -------------------------------------------------------------------- */ +/** \name Grab Manipulator API + * + * \{ */ + +static void MANIPULATOR_WT_grab_3d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_grab_3d"; + + /* api callbacks */ + wt->draw = manipulator_grab_draw; + wt->draw_select = manipulator_grab_draw_select; + wt->test_select = manipulator_grab_test_select; + wt->matrix_basis_get = manipulator_grab_matrix_basis_get; + wt->invoke = manipulator_grab_invoke; + wt->property_update = manipulator_grab_property_update; + wt->modal = manipulator_grab_modal; + wt->cursor_get = manipulator_grab_cursor_get; + + wt->struct_size = sizeof(GrabManipulator3D); + + /* rna */ + static EnumPropertyItem rna_enum_draw_style[] = { + {ED_MANIPULATOR_GRAB_STYLE_RING_2D, "RING_2D", 0, "Ring", ""}, + {ED_MANIPULATOR_GRAB_STYLE_CROSS_2D, "CROSS_2D", 0, "Ring", ""}, + {0, NULL, 0, NULL, NULL} + }; + static EnumPropertyItem rna_enum_draw_options[] = { + {ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""}, + {ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW, "ALIGN_VIEW", 0, "Align View", ""}, + {0, NULL, 0, NULL, NULL} + }; + + RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_GRAB_STYLE_RING_2D, "Draw Style", ""); + RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", ""); + + WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 3); +} + +void ED_manipulatortypes_grab_3d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_grab_3d); +} + +/** \} */ // Grab Manipulator API diff --git a/source/blender/editors/gizmo_library/gizmo_types/primitive3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/primitive3d_gizmo.c new file mode 100644 index 00000000000..1331a4e983f --- /dev/null +++ b/source/blender/editors/gizmo_library/gizmo_types/primitive3d_gizmo.c @@ -0,0 +1,191 @@ +/* + * ***** 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 primitive3d_gizmo.c + * \ingroup wm + * + * \name Primitive Manipulator + * + * 3D Manipulator + * + * \brief Manipulator with primitive drawing type (plane, cube, etc.). + * Currently only plane primitive supported without own handling, use with operator only. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "DNA_view3d_types.h" + +#include "BKE_context.h" + +#include "BIF_gl.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_select.h" +#include "GPU_state.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_gizmo_library.h" + +/* own includes */ +#include "../gizmo_library_intern.h" + +static float verts_plane[4][3] = { + {-1, -1, 0}, + { 1, -1, 0}, + { 1, 1, 0}, + {-1, 1, 0}, +}; + + +/* -------------------------------------------------------------------- */ + +static void manipulator_primitive_draw_geom( + const float col_inner[4], const float col_outer[4], const int draw_style) +{ + float (*verts)[3]; + uint vert_count = 0; + + if (draw_style == ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE) { + verts = verts_plane; + vert_count = ARRAY_SIZE(verts_plane); + } + + if (vert_count > 0) { + uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + wm_manipulator_vec_draw(col_inner, verts, vert_count, pos, GWN_PRIM_TRI_FAN); + wm_manipulator_vec_draw(col_outer, verts, vert_count, pos, GWN_PRIM_LINE_LOOP); + immUnbindProgram(); + } +} + +static void manipulator_primitive_draw_intern( + wmManipulator *mpr, const bool UNUSED(select), + const bool highlight) +{ + float color_inner[4], color_outer[4]; + float matrix_final[4][4]; + const int draw_style = RNA_enum_get(mpr->ptr, "draw_style"); + + manipulator_color_get(mpr, highlight, color_outer); + copy_v4_v4(color_inner, color_outer); + color_inner[3] *= 0.5f; + + WM_manipulator_calc_matrix_final(mpr, matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + GPU_blend(true); + manipulator_primitive_draw_geom(color_inner, color_outer, draw_style); + GPU_blend(false); + + gpuPopMatrix(); + + if (mpr->interaction_data) { + ManipulatorInteraction *inter = mpr->interaction_data; + + copy_v4_fl(color_inner, 0.5f); + copy_v3_fl(color_outer, 0.5f); + color_outer[3] = 0.8f; + + gpuPushMatrix(); + gpuMultMatrix(inter->init_matrix_final); + + GPU_blend(true); + manipulator_primitive_draw_geom(color_inner, color_outer, draw_style); + GPU_blend(false); + + gpuPopMatrix(); + } +} + +static void manipulator_primitive_draw_select( + const bContext *UNUSED(C), wmManipulator *mpr, + int select_id) +{ + GPU_select_load_id(select_id); + manipulator_primitive_draw_intern(mpr, true, false); +} + +static void manipulator_primitive_draw(const bContext *UNUSED(C), wmManipulator *mpr) +{ + manipulator_primitive_draw_intern( + mpr, false, + (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT)); +} + +static void manipulator_primitive_setup(wmManipulator *mpr) +{ + mpr->flag |= WM_MANIPULATOR_DRAW_MODAL; +} + +static int manipulator_primitive_invoke( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *UNUSED(event)) +{ + ManipulatorInteraction *inter = MEM_callocN(sizeof(ManipulatorInteraction), __func__); + + WM_manipulator_calc_matrix_final(mpr, inter->init_matrix_final); + + mpr->interaction_data = inter; + + return OPERATOR_RUNNING_MODAL; +} + +/* -------------------------------------------------------------------- */ +/** \name Primitive Manipulator API + * + * \{ */ + +static void MANIPULATOR_WT_primitive_3d(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "MANIPULATOR_WT_primitive_3d"; + + /* api callbacks */ + wt->draw = manipulator_primitive_draw; + wt->draw_select = manipulator_primitive_draw_select; + wt->setup = manipulator_primitive_setup; + wt->invoke = manipulator_primitive_invoke; + + wt->struct_size = sizeof(wmManipulator); + + static EnumPropertyItem rna_enum_draw_style[] = { + {ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE, "PLANE", 0, "Plane", ""}, + {0, NULL, 0, NULL, NULL} + }; + RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE, "Draw Style", ""); +} + +void ED_manipulatortypes_primitive_3d(void) +{ + WM_manipulatortype_append(MANIPULATOR_WT_primitive_3d); +} + +/** \} */ diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h new file mode 100644 index 00000000000..b33fbf47630 --- /dev/null +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -0,0 +1,222 @@ +/* + * ***** 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 ED_gizmo_library.h + * \ingroup wm + * + * \name Generic Manipulators. + * + * This is exposes pre-defined manipulators for re-use. + */ + + +#ifndef __ED_GIZMO_LIBRARY_H__ +#define __ED_GIZMO_LIBRARY_H__ + +/* initialize manipulators */ +void ED_manipulatortypes_arrow_2d(void); +void ED_manipulatortypes_arrow_3d(void); +void ED_manipulatortypes_button_2d(void); +void ED_manipulatortypes_cage_2d(void); +void ED_manipulatortypes_cage_3d(void); +void ED_manipulatortypes_dial_3d(void); +void ED_manipulatortypes_grab_3d(void); +void ED_manipulatortypes_facemap_3d(void); +void ED_manipulatortypes_primitive_3d(void); + +struct wmManipulator; +struct wmManipulatorGroup; + + +/* -------------------------------------------------------------------- */ +/* Shape Presets + * + * Intended to be called by custom draw functions. + */ + +/* manipulator_library_presets.c */ +void ED_manipulator_draw_preset_box( + const struct wmManipulator *mpr, float mat[4][4], int select_id); +void ED_manipulator_draw_preset_arrow( + const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id); +void ED_manipulator_draw_preset_circle( + const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id); +void ED_manipulator_draw_preset_facemap( + const struct bContext *C, const struct wmManipulator *mpr, struct Scene *scene, + struct Object *ob, const int facemap, int select_id); + + +/* -------------------------------------------------------------------- */ +/* 3D Arrow Manipulator */ + +enum { + ED_MANIPULATOR_ARROW_STYLE_NORMAL = 0, + ED_MANIPULATOR_ARROW_STYLE_CROSS = 1, + ED_MANIPULATOR_ARROW_STYLE_BOX = 2, + ED_MANIPULATOR_ARROW_STYLE_CONE = 3, +}; + +/* transform */ +enum { + /* inverted offset during interaction - if set it also sets constrained below */ + ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED = (1 << 3), + /* clamp arrow interaction to property width */ + ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED = (1 << 4), +}; + +/* draw_options */ +enum { + /* Show arrow stem. */ + ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM = (1 << 0), +}; + +void ED_manipulator_arrow3d_set_ui_range(struct wmManipulator *mpr, const float min, const float max); +void ED_manipulator_arrow3d_set_range_fac(struct wmManipulator *mpr, const float range_fac); + +/* -------------------------------------------------------------------- */ +/* 2D Arrow Manipulator */ + +/* none */ + +/* -------------------------------------------------------------------- */ +/* Cage Manipulator */ + +enum { + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE = (1 << 0), /* Translates */ + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE = (1 << 1), /* Rotates */ + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE = (1 << 2), /* Scales */ + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM = (1 << 3), /* Scales uniformly */ + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_SIGNED = (1 << 4), /* Negative scale allowed */ +}; + +/* draw_style */ +enum { + ED_MANIPULATOR_CAGE2D_STYLE_BOX = 0, + ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE = 1, +}; + +/* draw_options */ +enum { + /** Draw a central handle (instead of having the entire area selectable) + * Needed for large rectangles that we don't want to swallow all events. */ + ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE = (1 << 0), +}; + +/** #wmManipulator.highlight_part */ +enum { + ED_MANIPULATOR_CAGE2D_PART_TRANSLATE = 0, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X = 1, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X = 2, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y = 3, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y = 4, + /* Corners */ + ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y = 5, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y = 6, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y = 7, + ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y = 8, + + ED_MANIPULATOR_CAGE2D_PART_ROTATE = 9, +}; + +/** #wmManipulator.highlight_part */ +enum { + /* ordered min/mid/max so we can loop over values (MIN/MID/MAX) on each axis. */ + ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z = 0, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MID_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MAX_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MID_Y_MIN_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MID_Y_MID_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MID_Y_MAX_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MAX_Y_MIN_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MAX_Y_MID_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MAX_Y_MAX_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MIN_Y_MIN_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MIN_Y_MID_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MIN_Y_MAX_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MID_Y_MIN_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MID_Y_MID_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MID_Y_MAX_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MAX_Y_MIN_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MAX_Y_MID_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MAX_Y_MAX_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MIN_Y_MIN_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MIN_Y_MID_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MIN_Y_MAX_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MID_Y_MIN_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MID_Y_MID_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MID_Y_MAX_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MIN_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MID_Z, + ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, + + ED_MANIPULATOR_CAGE3D_PART_TRANSLATE, + + ED_MANIPULATOR_CAGE3D_PART_ROTATE, +}; + +/* -------------------------------------------------------------------- */ +/* Dial Manipulator */ + +/* draw_options */ +enum { + ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP = 0, + ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP = (1 << 0), + ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL = (1 << 1), + ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR = (1 << 2), + ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y = (1 << 3), +}; + +/* -------------------------------------------------------------------- */ +/* Grab Manipulator */ + +/* draw_options */ +enum { + ED_MANIPULATOR_GRAB_DRAW_FLAG_NOP = 0, + /* only for solid shapes */ + ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL = (1 << 0), + ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW = (1 << 1), +}; + +enum { + ED_MANIPULATOR_GRAB_STYLE_RING_2D = 0, + ED_MANIPULATOR_GRAB_STYLE_CROSS_2D = 1, +}; + +/* -------------------------------------------------------------------- */ +/* Button Manipulator */ + +enum { + ED_MANIPULATOR_BUTTON_SHOW_OUTLINE = (1 << 0), + /** + * Draw a line from the origin to the offset (similar to an arrow) + * sometimes needed to show what the button edits. + */ + ED_MANIPULATOR_BUTTON_SHOW_HELPLINE = (1 << 1), +}; + + +/* -------------------------------------------------------------------- */ +/* Primitive Manipulator */ + +enum { + ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE = 0, +}; + +#endif /* __ED_GIZMO_LIBRARY_H__ */ diff --git a/source/blender/editors/include/ED_manipulator_library.h b/source/blender/editors/include/ED_manipulator_library.h deleted file mode 100644 index fca0f5c8806..00000000000 --- a/source/blender/editors/include/ED_manipulator_library.h +++ /dev/null @@ -1,222 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file ED_manipulator_library.h - * \ingroup wm - * - * \name Generic Manipulators. - * - * This is exposes pre-defined manipulators for re-use. - */ - - -#ifndef __ED_MANIPULATOR_LIBRARY_H__ -#define __ED_MANIPULATOR_LIBRARY_H__ - -/* initialize manipulators */ -void ED_manipulatortypes_arrow_2d(void); -void ED_manipulatortypes_arrow_3d(void); -void ED_manipulatortypes_button_2d(void); -void ED_manipulatortypes_cage_2d(void); -void ED_manipulatortypes_cage_3d(void); -void ED_manipulatortypes_dial_3d(void); -void ED_manipulatortypes_grab_3d(void); -void ED_manipulatortypes_facemap_3d(void); -void ED_manipulatortypes_primitive_3d(void); - -struct wmManipulator; -struct wmManipulatorGroup; - - -/* -------------------------------------------------------------------- */ -/* Shape Presets - * - * Intended to be called by custom draw functions. - */ - -/* manipulator_library_presets.c */ -void ED_manipulator_draw_preset_box( - const struct wmManipulator *mpr, float mat[4][4], int select_id); -void ED_manipulator_draw_preset_arrow( - const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id); -void ED_manipulator_draw_preset_circle( - const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id); -void ED_manipulator_draw_preset_facemap( - const struct bContext *C, const struct wmManipulator *mpr, struct Scene *scene, - struct Object *ob, const int facemap, int select_id); - - -/* -------------------------------------------------------------------- */ -/* 3D Arrow Manipulator */ - -enum { - ED_MANIPULATOR_ARROW_STYLE_NORMAL = 0, - ED_MANIPULATOR_ARROW_STYLE_CROSS = 1, - ED_MANIPULATOR_ARROW_STYLE_BOX = 2, - ED_MANIPULATOR_ARROW_STYLE_CONE = 3, -}; - -/* transform */ -enum { - /* inverted offset during interaction - if set it also sets constrained below */ - ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED = (1 << 3), - /* clamp arrow interaction to property width */ - ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED = (1 << 4), -}; - -/* draw_options */ -enum { - /* Show arrow stem. */ - ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM = (1 << 0), -}; - -void ED_manipulator_arrow3d_set_ui_range(struct wmManipulator *mpr, const float min, const float max); -void ED_manipulator_arrow3d_set_range_fac(struct wmManipulator *mpr, const float range_fac); - -/* -------------------------------------------------------------------- */ -/* 2D Arrow Manipulator */ - -/* none */ - -/* -------------------------------------------------------------------- */ -/* Cage Manipulator */ - -enum { - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE = (1 << 0), /* Translates */ - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE = (1 << 1), /* Rotates */ - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE = (1 << 2), /* Scales */ - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM = (1 << 3), /* Scales uniformly */ - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_SIGNED = (1 << 4), /* Negative scale allowed */ -}; - -/* draw_style */ -enum { - ED_MANIPULATOR_CAGE2D_STYLE_BOX = 0, - ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE = 1, -}; - -/* draw_options */ -enum { - /** Draw a central handle (instead of having the entire area selectable) - * Needed for large rectangles that we don't want to swallow all events. */ - ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE = (1 << 0), -}; - -/** #wmManipulator.highlight_part */ -enum { - ED_MANIPULATOR_CAGE2D_PART_TRANSLATE = 0, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X = 1, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X = 2, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y = 3, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y = 4, - /* Corners */ - ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y = 5, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y = 6, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y = 7, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y = 8, - - ED_MANIPULATOR_CAGE2D_PART_ROTATE = 9, -}; - -/** #wmManipulator.highlight_part */ -enum { - /* ordered min/mid/max so we can loop over values (MIN/MID/MAX) on each axis. */ - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z = 0, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MID_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MAX_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MID_Y_MIN_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MID_Y_MID_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MID_Y_MAX_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MAX_Y_MIN_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MAX_Y_MID_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MAX_Y_MAX_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MIN_Y_MIN_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MIN_Y_MID_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MIN_Y_MAX_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MID_Y_MIN_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MID_Y_MID_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MID_Y_MAX_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MAX_Y_MIN_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MAX_Y_MID_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MAX_Y_MAX_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MIN_Y_MIN_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MIN_Y_MID_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MIN_Y_MAX_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MID_Y_MIN_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MID_Y_MID_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MID_Y_MAX_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MIN_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MID_Z, - ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, - - ED_MANIPULATOR_CAGE3D_PART_TRANSLATE, - - ED_MANIPULATOR_CAGE3D_PART_ROTATE, -}; - -/* -------------------------------------------------------------------- */ -/* Dial Manipulator */ - -/* draw_options */ -enum { - ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP = 0, - ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP = (1 << 0), - ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL = (1 << 1), - ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR = (1 << 2), - ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y = (1 << 3), -}; - -/* -------------------------------------------------------------------- */ -/* Grab Manipulator */ - -/* draw_options */ -enum { - ED_MANIPULATOR_GRAB_DRAW_FLAG_NOP = 0, - /* only for solid shapes */ - ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL = (1 << 0), - ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW = (1 << 1), -}; - -enum { - ED_MANIPULATOR_GRAB_STYLE_RING_2D = 0, - ED_MANIPULATOR_GRAB_STYLE_CROSS_2D = 1, -}; - -/* -------------------------------------------------------------------- */ -/* Button Manipulator */ - -enum { - ED_MANIPULATOR_BUTTON_SHOW_OUTLINE = (1 << 0), - /** - * Draw a line from the origin to the offset (similar to an arrow) - * sometimes needed to show what the button edits. - */ - ED_MANIPULATOR_BUTTON_SHOW_HELPLINE = (1 << 1), -}; - - -/* -------------------------------------------------------------------- */ -/* Primitive Manipulator */ - -enum { - ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE = 0, -}; - -#endif /* __ED_MANIPULATOR_LIBRARY_H__ */ diff --git a/source/blender/editors/manipulator_library/CMakeLists.txt b/source/blender/editors/manipulator_library/CMakeLists.txt deleted file mode 100644 index 86e1bb3b6d7..00000000000 --- a/source/blender/editors/manipulator_library/CMakeLists.txt +++ /dev/null @@ -1,60 +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. -# -# ***** END GPL LICENSE BLOCK ***** - -set(INC - ../include - ../../blenkernel - ../../blenlib - ../../blentranslation - ../../bmesh - ../../depsgraph - ../../gpu - ../../makesdna - ../../makesrna - ../../windowmanager - ../../../../intern/guardedalloc - ../../../../intern/eigen - ../../../../intern/glew-mx -) - -set(INC_SYS - ${GLEW_INCLUDE_PATH} -) - -set(SRC - manipulator_draw_utils.c - manipulator_geometry.h - manipulator_library_intern.h - manipulator_library_presets.c - manipulator_library_utils.c - geometry/geom_arrow_manipulator.c - geometry/geom_cube_manipulator.c - geometry/geom_dial_manipulator.c - manipulator_types/arrow2d_manipulator.c - manipulator_types/arrow3d_manipulator.c - manipulator_types/button2d_manipulator.c - manipulator_types/cage2d_manipulator.c - manipulator_types/cage3d_manipulator.c - manipulator_types/dial3d_manipulator.c - manipulator_types/grab3d_manipulator.c - manipulator_types/primitive3d_manipulator.c -) - -add_definitions(${GL_DEFINITIONS}) - -blender_add_lib(bf_editor_manipulator_library "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/manipulator_library/geometry/geom_arrow_manipulator.c b/source/blender/editors/manipulator_library/geometry/geom_arrow_manipulator.c deleted file mode 100644 index 34f7d73589c..00000000000 --- a/source/blender/editors/manipulator_library/geometry/geom_arrow_manipulator.c +++ /dev/null @@ -1,141 +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) 2016 Blender Foundation. - * All rights reserved. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file geom_arrow_manipulator.c - * \ingroup wm - */ - -#include "../manipulator_geometry.h" - -static float verts[][3] = { - {-0.000000, 0.012320, 0.000000}, - {-0.000000, 0.012320, 0.974306}, - {0.008711, 0.008711, 0.000000}, - {0.008711, 0.008711, 0.974306}, - {0.012320, -0.000000, 0.000000}, - {0.012320, -0.000000, 0.974306}, - {0.008711, -0.008711, 0.000000}, - {0.008711, -0.008711, 0.974306}, - {-0.000000, -0.012320, 0.000000}, - {-0.000000, -0.012320, 0.974306}, - {-0.008711, -0.008711, 0.000000}, - {-0.008711, -0.008711, 0.974306}, - {-0.012320, 0.000000, 0.000000}, - {-0.012320, 0.000000, 0.974306}, - {-0.008711, 0.008711, 0.000000}, - {-0.008711, 0.008711, 0.974306}, - {0.000000, 0.072555, 0.974306}, - {0.051304, 0.051304, 0.974306}, - {0.072555, -0.000000, 0.974306}, - {0.051304, -0.051304, 0.974306}, - {-0.000000, -0.072555, 0.974306}, - {-0.051304, -0.051304, 0.974306}, - {-0.072555, 0.000000, 0.974306}, - {-0.051304, 0.051304, 0.974306}, - {0.000000, -0.000000, 1.268098}, -}; - -static float normals[][3] = { - {0.000000, 0.776360, -0.630238}, - {0.000000, 0.594348, -0.804163}, - {0.548967, 0.548967, -0.630238}, - {0.420270, 0.420270, -0.804163}, - {0.776360, 0.000000, -0.630238}, - {0.594378, 0.000000, -0.804163}, - {0.548967, -0.548967, -0.630238}, - {0.420270, -0.420270, -0.804163}, - {0.000000, -0.776360, -0.630238}, - {0.000000, -0.594378, -0.804163}, - {-0.548967, -0.548967, -0.630238}, - {-0.420270, -0.420270, -0.804163}, - {-0.776360, 0.000000, -0.630238}, - {-0.594378, 0.000000, -0.804163}, - {-0.548967, 0.548967, -0.630238}, - {-0.420270, 0.420270, -0.804163}, - {0.000000, 0.843226, -0.537492}, - {0.596271, 0.596271, -0.537492}, - {0.843226, 0.000000, -0.537492}, - {0.596271, -0.596271, -0.537492}, - {0.000000, -0.843226, -0.537492}, - {-0.596271, -0.596271, -0.537492}, - {-0.843226, 0.000000, -0.537492}, - {-0.596271, 0.596271, -0.537492}, - {0.000000, 0.000000, 1.000000}, -}; - -static unsigned short indices[] = { - 1, 3, 2, - 3, 5, 4, - 5, 7, 6, - 7, 9, 8, - 9, 11, 10, - 11, 13, 12, - 5, 18, 19, - 15, 1, 0, - 13, 15, 14, - 6, 10, 14, - 11, 21, 22, - 7, 19, 20, - 13, 22, 23, - 3, 17, 18, - 9, 20, 21, - 15, 23, 16, - 1, 16, 17, - 23, 22, 24, - 21, 20, 24, - 19, 18, 24, - 17, 16, 24, - 16, 23, 24, - 22, 21, 24, - 20, 19, 24, - 18, 17, 24, - 0, 1, 2, - 2, 3, 4, - 4, 5, 6, - 6, 7, 8, - 8, 9, 10, - 10, 11, 12, - 7, 5, 19, - 14, 15, 0, - 12, 13, 14, - 14, 0, 2, - 2, 4, 6, - 6, 8, 10, - 10, 12, 14, - 14, 2, 6, - 13, 11, 22, - 9, 7, 20, - 15, 13, 23, - 5, 3, 18, - 11, 9, 21, - 1, 15, 16, - 3, 1, 17, -}; - -ManipulatorGeomInfo wm_manipulator_geom_data_arrow = { - .nverts = 25, - .ntris = 46, - .verts = verts, - .normals = normals, - .indices = indices, -}; diff --git a/source/blender/editors/manipulator_library/geometry/geom_cube_manipulator.c b/source/blender/editors/manipulator_library/geometry/geom_cube_manipulator.c deleted file mode 100644 index cee8e1e22ee..00000000000 --- a/source/blender/editors/manipulator_library/geometry/geom_cube_manipulator.c +++ /dev/null @@ -1,75 +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) 2016 Blender Foundation. - * All rights reserved. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file geom_cube_manipulator.c - * \ingroup wm - */ - -#include "../manipulator_geometry.h" - -static const float verts[][3] = { - {1.000000, 1.000000, -1.000000}, - {1.000000, -1.000000, -1.000000}, - {-1.000000, -1.000000, -1.000000}, - {-1.000000, 1.000000, -1.000000}, - {1.000000, 1.000000, 1.000000}, - {0.999999, -1.000001, 1.000000}, - {-1.000000, -1.000000, 1.000000}, - {-1.000000, 1.000000, 1.000000}, -}; - -static const float normals[][3] = { - {0.577349, 0.577349, -0.577349}, - {0.577349, -0.577349, -0.577349}, - {-0.577349, -0.577349, -0.577349}, - {-0.577349, 0.577349, -0.577349}, - {0.577349, 0.577349, 0.577349}, - {0.577349, -0.577349, 0.577349}, - {-0.577349, -0.577349, 0.577349}, - {-0.577349, 0.577349, 0.577349}, -}; - -static const unsigned short indices[] = { - 1, 2, 3, - 7, 6, 5, - 4, 5, 1, - 5, 6, 2, - 2, 6, 7, - 0, 3, 7, - 0, 1, 3, - 4, 7, 5, - 0, 4, 1, - 1, 5, 2, - 3, 2, 7, - 4, 0, 7, -}; - -ManipulatorGeomInfo wm_manipulator_geom_data_cube = { - .nverts = 8, - .ntris = 12, - .verts = verts, - .normals = normals, - .indices = indices, -}; diff --git a/source/blender/editors/manipulator_library/geometry/geom_dial_manipulator.c b/source/blender/editors/manipulator_library/geometry/geom_dial_manipulator.c deleted file mode 100644 index 811fc872a81..00000000000 --- a/source/blender/editors/manipulator_library/geometry/geom_dial_manipulator.c +++ /dev/null @@ -1,813 +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) 2016 Blender Foundation. - * All rights reserved. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file geom_dial_manipulator.c - * \ingroup wm - */ - -#include "../manipulator_geometry.h" - -static const float verts[][3] = { - {1.034000, 0.000000, 0.000000}, - {1.017000, 0.000000, 0.029445}, - {0.983000, 0.000000, 0.029445}, - {0.966000, 0.000000, 0.000000}, - {0.983000, 0.000000, -0.029445}, - {1.017000, 0.000000, -0.029445}, - {1.014132, 0.201723, 0.000000}, - {0.997459, 0.198407, 0.029445}, - {0.964112, 0.191774, 0.029445}, - {0.947439, 0.188457, 0.000000}, - {0.964112, 0.191774, -0.029445}, - {0.997459, 0.198407, -0.029445}, - {0.955292, 0.395695, 0.000000}, - {0.939586, 0.389189, 0.029445}, - {0.908174, 0.376178, 0.029445}, - {0.892468, 0.369672, 0.000000}, - {0.908174, 0.376178, -0.029445}, - {0.939586, 0.389189, -0.029445}, - {0.859740, 0.574460, 0.000000}, - {0.845605, 0.565015, 0.029445}, - {0.817335, 0.546126, 0.029445}, - {0.803200, 0.536681, 0.000000}, - {0.817335, 0.546126, -0.029445}, - {0.845605, 0.565015, -0.029445}, - {0.731148, 0.731148, 0.000000}, - {0.719128, 0.719128, 0.029445}, - {0.695086, 0.695086, 0.029445}, - {0.683065, 0.683065, 0.000000}, - {0.695086, 0.695086, -0.029445}, - {0.719128, 0.719128, -0.029445}, - {0.574460, 0.859740, 0.000000}, - {0.565015, 0.845605, 0.029445}, - {0.546125, 0.817335, 0.029445}, - {0.536681, 0.803200, 0.000000}, - {0.546125, 0.817335, -0.029445}, - {0.565015, 0.845605, -0.029445}, - {0.395695, 0.955291, 0.000000}, - {0.389189, 0.939585, 0.029445}, - {0.376178, 0.908173, 0.029445}, - {0.369672, 0.892467, 0.000000}, - {0.376178, 0.908173, -0.029445}, - {0.389189, 0.939585, -0.029445}, - {0.201724, 1.014132, 0.000000}, - {0.198407, 0.997459, 0.029445}, - {0.191774, 0.964112, 0.029445}, - {0.188457, 0.947439, 0.000000}, - {0.191774, 0.964112, -0.029445}, - {0.198407, 0.997459, -0.029445}, - {0.000000, 1.034000, 0.000000}, - {0.000000, 1.017000, 0.029445}, - {0.000000, 0.983000, 0.029445}, - {0.000000, 0.966000, 0.000000}, - {0.000000, 0.983000, -0.029445}, - {0.000000, 1.017000, -0.029445}, - {-0.201723, 1.014132, 0.000000}, - {-0.198407, 0.997459, 0.029445}, - {-0.191774, 0.964112, 0.029445}, - {-0.188457, 0.947439, 0.000000}, - {-0.191774, 0.964112, -0.029445}, - {-0.198407, 0.997459, -0.029445}, - {-0.395695, 0.955291, 0.000000}, - {-0.389189, 0.939585, 0.029445}, - {-0.376178, 0.908174, 0.029445}, - {-0.369672, 0.892468, 0.000000}, - {-0.376178, 0.908174, -0.029445}, - {-0.389189, 0.939585, -0.029445}, - {-0.574459, 0.859740, 0.000000}, - {-0.565015, 0.845605, 0.029445}, - {-0.546125, 0.817335, 0.029445}, - {-0.536681, 0.803200, 0.000000}, - {-0.546125, 0.817335, -0.029445}, - {-0.565015, 0.845605, -0.029445}, - {-0.731149, 0.731148, 0.000000}, - {-0.719128, 0.719127, 0.029445}, - {-0.695086, 0.695086, 0.029445}, - {-0.683065, 0.683065, 0.000000}, - {-0.695086, 0.695086, -0.029445}, - {-0.719128, 0.719127, -0.029445}, - {-0.859740, 0.574460, 0.000000}, - {-0.845604, 0.565015, 0.029445}, - {-0.817335, 0.546126, 0.029445}, - {-0.803200, 0.536681, 0.000000}, - {-0.817335, 0.546126, -0.029445}, - {-0.845604, 0.565015, -0.029445}, - {-0.955291, 0.395695, 0.000000}, - {-0.939585, 0.389189, 0.029445}, - {-0.908173, 0.376178, 0.029445}, - {-0.892468, 0.369672, 0.000000}, - {-0.908173, 0.376178, -0.029445}, - {-0.939585, 0.389189, -0.029445}, - {-1.014132, 0.201723, 0.000000}, - {-0.997459, 0.198407, 0.029445}, - {-0.964112, 0.191774, 0.029445}, - {-0.947439, 0.188457, 0.000000}, - {-0.964112, 0.191774, -0.029445}, - {-0.997459, 0.198407, -0.029445}, - {-1.034000, 0.000000, 0.000000}, - {-1.017000, 0.000000, 0.029445}, - {-0.983000, 0.000000, 0.029445}, - {-0.966000, 0.000000, 0.000000}, - {-0.983000, 0.000000, -0.029445}, - {-1.017000, 0.000000, -0.029445}, - {-1.014132, -0.201723, 0.000000}, - {-0.997459, -0.198407, 0.029445}, - {-0.964112, -0.191774, 0.029445}, - {-0.947439, -0.188457, 0.000000}, - {-0.964112, -0.191774, -0.029445}, - {-0.997459, -0.198407, -0.029445}, - {-0.955292, -0.395694, 0.000000}, - {-0.939586, -0.389189, 0.029445}, - {-0.908174, -0.376177, 0.029445}, - {-0.892468, -0.369672, 0.000000}, - {-0.908174, -0.376177, -0.029445}, - {-0.939586, -0.389189, -0.029445}, - {-0.859740, -0.574460, 0.000000}, - {-0.845604, -0.565015, 0.029445}, - {-0.817335, -0.546126, 0.029445}, - {-0.803200, -0.536681, 0.000000}, - {-0.817335, -0.546126, -0.029445}, - {-0.845604, -0.565015, -0.029445}, - {-0.731149, -0.731148, 0.000000}, - {-0.719128, -0.719127, 0.029445}, - {-0.695086, -0.695086, 0.029445}, - {-0.683065, -0.683065, 0.000000}, - {-0.695086, -0.695086, -0.029445}, - {-0.719128, -0.719127, -0.029445}, - {-0.574460, -0.859739, 0.000000}, - {-0.565015, -0.845604, 0.029445}, - {-0.546126, -0.817334, 0.029445}, - {-0.536681, -0.803199, 0.000000}, - {-0.546126, -0.817334, -0.029445}, - {-0.565015, -0.845604, -0.029445}, - {-0.395695, -0.955291, 0.000000}, - {-0.389189, -0.939585, 0.029445}, - {-0.376178, -0.908174, 0.029445}, - {-0.369672, -0.892468, 0.000000}, - {-0.376178, -0.908174, -0.029445}, - {-0.389189, -0.939585, -0.029445}, - {-0.201724, -1.014132, 0.000000}, - {-0.198407, -0.997459, 0.029445}, - {-0.191774, -0.964112, 0.029445}, - {-0.188458, -0.947438, 0.000000}, - {-0.191774, -0.964112, -0.029445}, - {-0.198407, -0.997459, -0.029445}, - {0.000000, -1.034000, 0.000000}, - {0.000000, -1.017000, 0.029445}, - {0.000000, -0.983000, 0.029445}, - {0.000000, -0.966000, 0.000000}, - {0.000000, -0.983000, -0.029445}, - {0.000000, -1.017000, -0.029445}, - {0.201723, -1.014132, 0.000000}, - {0.198407, -0.997459, 0.029445}, - {0.191773, -0.964112, 0.029445}, - {0.188457, -0.947439, 0.000000}, - {0.191773, -0.964112, -0.029445}, - {0.198407, -0.997459, -0.029445}, - {0.395695, -0.955291, 0.000000}, - {0.389189, -0.939585, 0.029445}, - {0.376178, -0.908173, 0.029445}, - {0.369672, -0.892467, 0.000000}, - {0.376178, -0.908173, -0.029445}, - {0.389189, -0.939585, -0.029445}, - {0.574460, -0.859740, 0.000000}, - {0.565015, -0.845605, 0.029445}, - {0.546125, -0.817335, 0.029445}, - {0.536681, -0.803200, 0.000000}, - {0.546125, -0.817335, -0.029445}, - {0.565015, -0.845605, -0.029445}, - {0.731148, -0.731149, 0.000000}, - {0.719127, -0.719128, 0.029445}, - {0.695086, -0.695086, 0.029445}, - {0.683065, -0.683066, 0.000000}, - {0.695086, -0.695086, -0.029445}, - {0.719127, -0.719128, -0.029445}, - {0.859740, -0.574460, 0.000000}, - {0.845605, -0.565015, 0.029445}, - {0.817335, -0.546126, 0.029445}, - {0.803200, -0.536681, 0.000000}, - {0.817335, -0.546126, -0.029445}, - {0.845605, -0.565015, -0.029445}, - {0.955291, -0.395695, 0.000000}, - {0.939585, -0.389189, 0.029445}, - {0.908173, -0.376178, 0.029445}, - {0.892467, -0.369673, 0.000000}, - {0.908173, -0.376178, -0.029445}, - {0.939585, -0.389189, -0.029445}, - {1.014132, -0.201723, 0.000000}, - {0.997459, -0.198407, 0.029445}, - {0.964112, -0.191774, 0.029445}, - {0.947439, -0.188457, 0.000000}, - {0.964112, -0.191774, -0.029445}, - {0.997459, -0.198407, -0.029445}, -}; - -static const float normals[][3] = { - {1.000000, 0.000000, 0.000000}, - {0.522691, 0.000000, 0.852504}, - {-0.475845, 0.000000, 0.879513}, - {-1.000000, 0.000000, 0.000000}, - {-0.475845, 0.000000, -0.879513}, - {0.522691, 0.000000, -0.852504}, - {0.980773, 0.195074, 0.000000}, - {0.512650, 0.101962, 0.852504}, - {-0.466689, -0.092807, 0.879513}, - {-0.980773, -0.195074, 0.000000}, - {-0.466689, -0.092807, -0.879513}, - {0.512650, 0.101962, -0.852504}, - {0.923856, 0.382672, 0.000000}, - {0.482894, 0.200018, 0.852504}, - {-0.439619, -0.182073, 0.879513}, - {-0.923856, -0.382672, 0.000000}, - {-0.439619, -0.182073, -0.879513}, - {0.482894, 0.200018, -0.852504}, - {0.831446, 0.555559, 0.000000}, - {0.434614, 0.290384, 0.852504}, - {-0.395642, -0.264351, 0.879513}, - {-0.831446, -0.555559, 0.000000}, - {-0.395642, -0.264351, -0.879513}, - {0.434614, 0.290384, -0.852504}, - {0.707083, 0.707083, 0.000000}, - {0.369610, 0.369610, 0.852504}, - {-0.336467, -0.336467, 0.879513}, - {-0.707083, -0.707083, 0.000000}, - {-0.336467, -0.336467, -0.879513}, - {0.369610, 0.369610, -0.852504}, - {0.555559, 0.831446, 0.000000}, - {0.290384, 0.434614, 0.852504}, - {-0.264351, -0.395642, 0.879513}, - {-0.555559, -0.831446, 0.000000}, - {-0.264351, -0.395642, -0.879513}, - {0.290384, 0.434614, -0.852504}, - {0.382672, 0.923856, 0.000000}, - {0.200018, 0.482894, 0.852504}, - {-0.182073, -0.439619, 0.879513}, - {-0.382672, -0.923856, 0.000000}, - {-0.182073, -0.439619, -0.879513}, - {0.200018, 0.482894, -0.852504}, - {0.195074, 0.980773, 0.000000}, - {0.101962, 0.512650, 0.852504}, - {-0.092807, -0.466689, 0.879513}, - {-0.195074, -0.980773, 0.000000}, - {-0.092807, -0.466689, -0.879513}, - {0.101962, 0.512650, -0.852504}, - {0.000000, 1.000000, 0.000000}, - {0.000000, 0.522691, 0.852504}, - {0.000000, -0.475845, 0.879513}, - {0.000000, -1.000000, 0.000000}, - {0.000000, -0.475845, -0.879513}, - {0.000000, 0.522691, -0.852504}, - {-0.195074, 0.980773, 0.000000}, - {-0.101962, 0.512650, 0.852504}, - {0.092807, -0.466689, 0.879513}, - {0.195074, -0.980773, 0.000000}, - {0.092807, -0.466689, -0.879513}, - {-0.101962, 0.512650, -0.852504}, - {-0.382672, 0.923856, 0.000000}, - {-0.200018, 0.482894, 0.852504}, - {0.182073, -0.439619, 0.879513}, - {0.382672, -0.923856, 0.000000}, - {0.182073, -0.439619, -0.879513}, - {-0.200018, 0.482894, -0.852504}, - {-0.555559, 0.831446, 0.000000}, - {-0.290384, 0.434614, 0.852504}, - {0.264351, -0.395642, 0.879513}, - {0.555559, -0.831446, 0.000000}, - {0.264351, -0.395642, -0.879513}, - {-0.290384, 0.434614, -0.852504}, - {-0.707083, 0.707083, 0.000000}, - {-0.369610, 0.369610, 0.852504}, - {0.336467, -0.336467, 0.879513}, - {0.707083, -0.707083, 0.000000}, - {0.336467, -0.336467, -0.879513}, - {-0.369610, 0.369610, -0.852504}, - {-0.831446, 0.555559, 0.000000}, - {-0.434614, 0.290384, 0.852504}, - {0.395642, -0.264351, 0.879513}, - {0.831446, -0.555559, 0.000000}, - {0.395642, -0.264351, -0.879513}, - {-0.434614, 0.290384, -0.852504}, - {-0.923856, 0.382672, 0.000000}, - {-0.482894, 0.200018, 0.852504}, - {0.439619, -0.182073, 0.879513}, - {0.923856, -0.382672, 0.000000}, - {0.439619, -0.182073, -0.879513}, - {-0.482894, 0.200018, -0.852504}, - {-0.980773, 0.195074, 0.000000}, - {-0.512650, 0.101962, 0.852504}, - {0.466689, -0.092807, 0.879513}, - {0.980773, -0.195074, 0.000000}, - {0.466689, -0.092807, -0.879513}, - {-0.512650, 0.101962, -0.852504}, - {-1.000000, 0.000000, 0.000000}, - {-0.522691, 0.000000, 0.852504}, - {0.475845, 0.000000, 0.879513}, - {1.000000, 0.000000, 0.000000}, - {0.475845, 0.000000, -0.879513}, - {-0.522691, 0.000000, -0.852504}, - {-0.980773, -0.195074, 0.000000}, - {-0.512650, -0.101962, 0.852504}, - {0.466689, 0.092807, 0.879513}, - {0.980773, 0.195074, 0.000000}, - {0.466689, 0.092807, -0.879513}, - {-0.512650, -0.101962, -0.852504}, - {-0.923856, -0.382672, 0.000000}, - {-0.482894, -0.200018, 0.852504}, - {0.439619, 0.182073, 0.879513}, - {0.923856, 0.382672, 0.000000}, - {0.439619, 0.182073, -0.879513}, - {-0.482894, -0.200018, -0.852504}, - {-0.831446, -0.555559, 0.000000}, - {-0.434614, -0.290384, 0.852504}, - {0.395642, 0.264351, 0.879513}, - {0.831446, 0.555559, 0.000000}, - {0.395642, 0.264351, -0.879513}, - {-0.434614, -0.290384, -0.852504}, - {-0.707083, -0.707083, 0.000000}, - {-0.369610, -0.369610, 0.852504}, - {0.336467, 0.336467, 0.879513}, - {0.707083, 0.707083, 0.000000}, - {0.336467, 0.336467, -0.879513}, - {-0.369610, -0.369610, -0.852504}, - {-0.555559, -0.831446, 0.000000}, - {-0.290384, -0.434614, 0.852504}, - {0.264351, 0.395642, 0.879513}, - {0.555559, 0.831446, 0.000000}, - {0.264351, 0.395642, -0.879513}, - {-0.290384, -0.434614, -0.852504}, - {-0.382672, -0.923856, 0.000000}, - {-0.200018, -0.482894, 0.852504}, - {0.182073, 0.439619, 0.879513}, - {0.382672, 0.923856, 0.000000}, - {0.182073, 0.439619, -0.879513}, - {-0.200018, -0.482894, -0.852504}, - {-0.195074, -0.980773, 0.000000}, - {-0.101962, -0.512650, 0.852504}, - {0.092807, 0.466689, 0.879513}, - {0.195074, 0.980773, 0.000000}, - {0.092807, 0.466689, -0.879513}, - {-0.101962, -0.512650, -0.852504}, - {0.000000, -1.000000, 0.000000}, - {0.000000, -0.522691, 0.852504}, - {0.000000, 0.475845, 0.879513}, - {0.000000, 1.000000, 0.000000}, - {0.000000, 0.475845, -0.879513}, - {0.000000, -0.522691, -0.852504}, - {0.195074, -0.980773, 0.000000}, - {0.101962, -0.512650, 0.852504}, - {-0.092807, 0.466689, 0.879513}, - {-0.195074, 0.980773, 0.000000}, - {-0.092807, 0.466689, -0.879513}, - {0.101962, -0.512650, -0.852504}, - {0.382672, -0.923856, 0.000000}, - {0.200018, -0.482894, 0.852504}, - {-0.182073, 0.439619, 0.879513}, - {-0.382672, 0.923856, 0.000000}, - {-0.182073, 0.439619, -0.879513}, - {0.200018, -0.482894, -0.852504}, - {0.555559, -0.831446, 0.000000}, - {0.290384, -0.434614, 0.852504}, - {-0.264351, 0.395642, 0.879513}, - {-0.555559, 0.831446, 0.000000}, - {-0.264351, 0.395642, -0.879513}, - {0.290384, -0.434614, -0.852504}, - {0.707083, -0.707083, 0.000000}, - {0.369610, -0.369610, 0.852504}, - {-0.336467, 0.336467, 0.879513}, - {-0.707083, 0.707083, 0.000000}, - {-0.336467, 0.336467, -0.879513}, - {0.369610, -0.369610, -0.852504}, - {0.831446, -0.555559, 0.000000}, - {0.434614, -0.290384, 0.852504}, - {-0.395642, 0.264351, 0.879513}, - {-0.831446, 0.555559, 0.000000}, - {-0.395642, 0.264351, -0.879513}, - {0.434614, -0.290384, -0.852504}, - {0.923856, -0.382672, 0.000000}, - {0.482894, -0.200018, 0.852504}, - {-0.439619, 0.182073, 0.879513}, - {-0.923856, 0.382672, 0.000000}, - {-0.439619, 0.182073, -0.879513}, - {0.482894, -0.200018, -0.852504}, - {0.980773, -0.195074, 0.000000}, - {0.512650, -0.101962, 0.852504}, - {-0.466689, 0.092807, 0.879513}, - {-0.980773, 0.195074, 0.000000}, - {-0.466689, 0.092807, -0.879513}, - {0.512650, -0.101962, -0.852504}, -}; - -static const unsigned short indices[] = { - 6, 7, 1, - 7, 8, 2, - 8, 9, 3, - 9, 10, 4, - 10, 11, 5, - 5, 11, 6, - 12, 13, 7, - 13, 14, 8, - 14, 15, 9, - 15, 16, 10, - 16, 17, 11, - 11, 17, 12, - 18, 19, 13, - 13, 19, 20, - 20, 21, 15, - 15, 21, 22, - 22, 23, 17, - 17, 23, 18, - 24, 25, 19, - 19, 25, 26, - 26, 27, 21, - 21, 27, 28, - 28, 29, 23, - 23, 29, 24, - 30, 31, 25, - 25, 31, 32, - 26, 32, 33, - 27, 33, 34, - 34, 35, 29, - 29, 35, 30, - 36, 37, 31, - 31, 37, 38, - 38, 39, 33, - 39, 40, 34, - 40, 41, 35, - 35, 41, 36, - 36, 42, 43, - 43, 44, 38, - 44, 45, 39, - 45, 46, 40, - 46, 47, 41, - 47, 42, 36, - 48, 49, 43, - 49, 50, 44, - 50, 51, 45, - 51, 52, 46, - 52, 53, 47, - 47, 53, 48, - 54, 55, 49, - 49, 55, 56, - 50, 56, 57, - 57, 58, 52, - 58, 59, 53, - 53, 59, 54, - 60, 61, 55, - 55, 61, 62, - 56, 62, 63, - 63, 64, 58, - 64, 65, 59, - 59, 65, 60, - 66, 67, 61, - 61, 67, 68, - 68, 69, 63, - 69, 70, 64, - 70, 71, 65, - 71, 66, 60, - 72, 73, 67, - 73, 74, 68, - 68, 74, 75, - 75, 76, 70, - 76, 77, 71, - 71, 77, 72, - 78, 79, 73, - 79, 80, 74, - 74, 80, 81, - 81, 82, 76, - 82, 83, 77, - 83, 78, 72, - 78, 84, 85, - 85, 86, 80, - 80, 86, 87, - 87, 88, 82, - 82, 88, 89, - 89, 84, 78, - 90, 91, 85, - 91, 92, 86, - 86, 92, 93, - 93, 94, 88, - 88, 94, 95, - 95, 90, 84, - 96, 97, 91, - 97, 98, 92, - 98, 99, 93, - 99, 100, 94, - 100, 101, 95, - 101, 96, 90, - 102, 103, 97, - 103, 104, 98, - 104, 105, 99, - 99, 105, 106, - 106, 107, 101, - 101, 107, 102, - 108, 109, 103, - 103, 109, 110, - 110, 111, 105, - 105, 111, 112, - 112, 113, 107, - 107, 113, 108, - 114, 115, 109, - 115, 116, 110, - 116, 117, 111, - 111, 117, 118, - 112, 118, 119, - 113, 119, 114, - 114, 120, 121, - 121, 122, 116, - 122, 123, 117, - 117, 123, 124, - 124, 125, 119, - 125, 120, 114, - 126, 127, 121, - 121, 127, 128, - 128, 129, 123, - 123, 129, 130, - 130, 131, 125, - 125, 131, 126, - 132, 133, 127, - 133, 134, 128, - 128, 134, 135, - 135, 136, 130, - 136, 137, 131, - 131, 137, 132, - 132, 138, 139, - 133, 139, 140, - 134, 140, 141, - 141, 142, 136, - 142, 143, 137, - 143, 138, 132, - 138, 144, 145, - 139, 145, 146, - 146, 147, 141, - 141, 147, 148, - 148, 149, 143, - 149, 144, 138, - 144, 150, 151, - 151, 152, 146, - 146, 152, 153, - 153, 154, 148, - 154, 155, 149, - 155, 150, 144, - 156, 157, 151, - 151, 157, 158, - 158, 159, 153, - 159, 160, 154, - 160, 161, 155, - 155, 161, 156, - 156, 162, 163, - 163, 164, 158, - 158, 164, 165, - 165, 166, 160, - 160, 166, 167, - 167, 162, 156, - 162, 168, 169, - 169, 170, 164, - 164, 170, 171, - 165, 171, 172, - 166, 172, 173, - 173, 168, 162, - 174, 175, 169, - 175, 176, 170, - 170, 176, 177, - 177, 178, 172, - 172, 178, 179, - 173, 179, 174, - 174, 180, 181, - 181, 182, 176, - 176, 182, 183, - 183, 184, 178, - 178, 184, 185, - 179, 185, 180, - 186, 187, 181, - 187, 188, 182, - 188, 189, 183, - 183, 189, 190, - 190, 191, 185, - 191, 186, 180, - 0, 1, 187, - 1, 2, 188, - 2, 3, 189, - 3, 4, 190, - 190, 4, 5, - 191, 5, 0, - 0, 6, 1, - 1, 7, 2, - 2, 8, 3, - 3, 9, 4, - 4, 10, 5, - 0, 5, 6, - 6, 12, 7, - 7, 13, 8, - 8, 14, 9, - 9, 15, 10, - 10, 16, 11, - 6, 11, 12, - 12, 18, 13, - 14, 13, 20, - 14, 20, 15, - 16, 15, 22, - 16, 22, 17, - 12, 17, 18, - 18, 24, 19, - 20, 19, 26, - 20, 26, 21, - 22, 21, 28, - 22, 28, 23, - 18, 23, 24, - 24, 30, 25, - 26, 25, 32, - 27, 26, 33, - 28, 27, 34, - 28, 34, 29, - 24, 29, 30, - 30, 36, 31, - 32, 31, 38, - 32, 38, 33, - 33, 39, 34, - 34, 40, 35, - 30, 35, 36, - 37, 36, 43, - 37, 43, 38, - 38, 44, 39, - 39, 45, 40, - 40, 46, 41, - 41, 47, 36, - 42, 48, 43, - 43, 49, 44, - 44, 50, 45, - 45, 51, 46, - 46, 52, 47, - 42, 47, 48, - 48, 54, 49, - 50, 49, 56, - 51, 50, 57, - 51, 57, 52, - 52, 58, 53, - 48, 53, 54, - 54, 60, 55, - 56, 55, 62, - 57, 56, 63, - 57, 63, 58, - 58, 64, 59, - 54, 59, 60, - 60, 66, 61, - 62, 61, 68, - 62, 68, 63, - 63, 69, 64, - 64, 70, 65, - 65, 71, 60, - 66, 72, 67, - 67, 73, 68, - 69, 68, 75, - 69, 75, 70, - 70, 76, 71, - 66, 71, 72, - 72, 78, 73, - 73, 79, 74, - 75, 74, 81, - 75, 81, 76, - 76, 82, 77, - 77, 83, 72, - 79, 78, 85, - 79, 85, 80, - 81, 80, 87, - 81, 87, 82, - 83, 82, 89, - 83, 89, 78, - 84, 90, 85, - 85, 91, 86, - 87, 86, 93, - 87, 93, 88, - 89, 88, 95, - 89, 95, 84, - 90, 96, 91, - 91, 97, 92, - 92, 98, 93, - 93, 99, 94, - 94, 100, 95, - 95, 101, 90, - 96, 102, 97, - 97, 103, 98, - 98, 104, 99, - 100, 99, 106, - 100, 106, 101, - 96, 101, 102, - 102, 108, 103, - 104, 103, 110, - 104, 110, 105, - 106, 105, 112, - 106, 112, 107, - 102, 107, 108, - 108, 114, 109, - 109, 115, 110, - 110, 116, 111, - 112, 111, 118, - 113, 112, 119, - 108, 113, 114, - 115, 114, 121, - 115, 121, 116, - 116, 122, 117, - 118, 117, 124, - 118, 124, 119, - 119, 125, 114, - 120, 126, 121, - 122, 121, 128, - 122, 128, 123, - 124, 123, 130, - 124, 130, 125, - 120, 125, 126, - 126, 132, 127, - 127, 133, 128, - 129, 128, 135, - 129, 135, 130, - 130, 136, 131, - 126, 131, 132, - 133, 132, 139, - 134, 133, 140, - 135, 134, 141, - 135, 141, 136, - 136, 142, 137, - 137, 143, 132, - 139, 138, 145, - 140, 139, 146, - 140, 146, 141, - 142, 141, 148, - 142, 148, 143, - 143, 149, 138, - 145, 144, 151, - 145, 151, 146, - 147, 146, 153, - 147, 153, 148, - 148, 154, 149, - 149, 155, 144, - 150, 156, 151, - 152, 151, 158, - 152, 158, 153, - 153, 159, 154, - 154, 160, 155, - 150, 155, 156, - 157, 156, 163, - 157, 163, 158, - 159, 158, 165, - 159, 165, 160, - 161, 160, 167, - 161, 167, 156, - 163, 162, 169, - 163, 169, 164, - 165, 164, 171, - 166, 165, 172, - 167, 166, 173, - 167, 173, 162, - 168, 174, 169, - 169, 175, 170, - 171, 170, 177, - 171, 177, 172, - 173, 172, 179, - 168, 173, 174, - 175, 174, 181, - 175, 181, 176, - 177, 176, 183, - 177, 183, 178, - 179, 178, 185, - 174, 179, 180, - 180, 186, 181, - 181, 187, 182, - 182, 188, 183, - 184, 183, 190, - 184, 190, 185, - 185, 191, 180, - 186, 0, 187, - 187, 1, 188, - 188, 2, 189, - 189, 3, 190, - 191, 190, 5, - 186, 191, 0, -}; - -ManipulatorGeomInfo wm_manipulator_geom_data_dial = { - .nverts = 192, - .ntris = 384, - .verts = verts, - .normals = normals, - .indices = indices, -}; diff --git a/source/blender/editors/manipulator_library/manipulator_draw_utils.c b/source/blender/editors/manipulator_library/manipulator_draw_utils.c deleted file mode 100644 index 80181c57115..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_draw_utils.c +++ /dev/null @@ -1,121 +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 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file manipulator_draw_utils.c - * \ingroup wm - */ - -#include "BLI_listbase.h" -#include "BLI_ghash.h" -#include "BLI_math.h" -#include "BLI_string.h" -#include "BLI_string_utils.h" - -#include "BKE_context.h" - -#include "ED_screen.h" -#include "ED_view3d.h" - -#include "GPU_batch.h" -#include "GPU_glew.h" -#include "GPU_immediate.h" -#include "GPU_state.h" - -#include "MEM_guardedalloc.h" - -#include "RNA_access.h" - -#include "WM_api.h" -#include "WM_types.h" - -/* only for own init/exit calls (wm_manipulatortype_init/wm_manipulatortype_free) */ -#include "wm.h" - -/* own includes */ -#include "manipulator_library_intern.h" - -/** - * Main draw call for ManipulatorGeomInfo data - */ -void wm_manipulator_geometryinfo_draw(const ManipulatorGeomInfo *info, const bool UNUSED(select), const float color[4]) -{ - /* TODO store the Batches inside the ManipulatorGeomInfo and updated it when geom changes - * So we don't need to re-created and discard it every time */ - - Gwn_VertBuf *vbo; - Gwn_IndexBuf *el; - Gwn_Batch *batch; - Gwn_IndexBufBuilder elb = {0}; - - Gwn_VertFormat format = {0}; - uint pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - - /* Elements */ - GWN_indexbuf_init(&elb, GWN_PRIM_TRIS, info->ntris, info->nverts); - for (int i = 0; i < info->ntris; ++i) { - const unsigned short *idx = &info->indices[i * 3]; - GWN_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]); - } - el = GWN_indexbuf_build(&elb); - - vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, info->nverts); - - GWN_vertbuf_attr_fill(vbo, pos_id, info->verts); - - batch = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, el, GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); - GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); - - GWN_batch_uniform_4fv(batch, "color", color); - - /* We may want to re-visit this, for now disable - * since it causes issues leaving the GL state modified. */ -#if 0 - glEnable(GL_CULL_FACE); - GPU_depth_test(true); -#endif - - GWN_batch_draw(batch); - -#if 0 - GPU_depth_test(false); - glDisable(GL_CULL_FACE); -#endif - - - GWN_batch_discard(batch); -} - -void wm_manipulator_vec_draw( - const float color[4], const float (*verts)[3], uint vert_count, - uint pos, uint primitive_type) -{ - immUniformColor4fv(color); - immBegin(primitive_type, vert_count); - for (int i = 0; i < vert_count; i++) { - immVertex3fv(pos, verts[i]); - } - immEnd(); -} diff --git a/source/blender/editors/manipulator_library/manipulator_geometry.h b/source/blender/editors/manipulator_library/manipulator_geometry.h deleted file mode 100644 index 2083f9d4d31..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_geometry.h +++ /dev/null @@ -1,54 +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) 2016 Blender Foundation. - * All rights reserved. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file manipulator_geometry.h - * \ingroup wm - * - * \name Manipulator Geometry - * - * \brief Prototypes for arrays defining the manipulator geometry. The actual definitions can be found in files usually - * called geom_xxx_manipulator.c - */ - - -#ifndef __MANIPULATOR_GEOMETRY_H__ -#define __MANIPULATOR_GEOMETRY_H__ - -typedef struct ManipulatorGeomInfo { - int nverts; - int ntris; - const float (*verts)[3]; - const float (*normals)[3]; - const unsigned short *indices; -} ManipulatorGeomInfo; - -/* arrow manipulator */ -extern ManipulatorGeomInfo wm_manipulator_geom_data_arrow; - -/* cube manipulator */ -extern ManipulatorGeomInfo wm_manipulator_geom_data_cube; - -/* dial manipulator */ -extern ManipulatorGeomInfo wm_manipulator_geom_data_dial; - -#endif /* __MANIPULATOR_GEOMETRY_H__ */ diff --git a/source/blender/editors/manipulator_library/manipulator_library_intern.h b/source/blender/editors/manipulator_library/manipulator_library_intern.h deleted file mode 100644 index 55db99236e0..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_library_intern.h +++ /dev/null @@ -1,111 +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) 2016 Blender Foundation. - * All rights reserved. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file manipulator_library_intern.h - * \ingroup wm - */ - -#ifndef __MANIPULATOR_LIBRARY_INTERN_H__ -#define __MANIPULATOR_LIBRARY_INTERN_H__ - -/* distance around which manipulators respond to input (and get highlighted) */ -#define MANIPULATOR_HOTSPOT 14.0f - -/** - * Data for common interactions. Used in manipulator_library_utils.c functions. - */ -typedef struct ManipulatorCommonData { - int flag; - - float range_fac; /* factor for arrow min/max distance */ - float offset; - - /* property range for constrained manipulators */ - float range; - /* min/max value for constrained manipulators */ - float min, max; -} ManipulatorCommonData; - -typedef struct ManipulatorInteraction { - float init_value; /* initial property value */ - float init_mval[2]; - float init_offset; - float init_matrix_final[4][4]; - float init_matrix_basis[4][4]; - - /* offset of last handling step */ - float prev_offset; - /* Total offset added by precision tweaking. - * Needed to allow toggling precision on/off without causing jumps */ - float precision_offset; -} ManipulatorInteraction; - -/* ManipulatorCommonData->flag */ -enum { - MANIPULATOR_CUSTOM_RANGE_SET = (1 << 0), -}; - - -float manipulator_offset_from_value( - ManipulatorCommonData *data, const float value, - const bool constrained, const bool inverted); -float manipulator_value_from_offset( - ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset, - const bool constrained, const bool inverted, const bool use_precision); - -void manipulator_property_data_update( - struct wmManipulator *mpr, ManipulatorCommonData *data, wmManipulatorProperty *mpr_prop, - const bool constrained, const bool inverted); - -void manipulator_property_value_reset( - bContext *C, const struct wmManipulator *mpr, ManipulatorInteraction *inter, wmManipulatorProperty *mpr_prop); - - -/* -------------------------------------------------------------------- */ - -void manipulator_color_get( - const struct wmManipulator *mpr, const bool highlight, - float r_color[4]); - -bool manipulator_window_project_2d( - bContext *C, const struct wmManipulator *mpr, const float mval[2], int axis, bool use_offset, - float r_co[2]); - -bool manipulator_window_project_3d( - bContext *C, const struct wmManipulator *mpr, const float mval[2], bool use_offset, - float r_co[3]); - -/* -------------------------------------------------------------------- */ -/* Manipulator drawing */ - -#include "manipulator_geometry.h" - -void wm_manipulator_geometryinfo_draw(const struct ManipulatorGeomInfo *info, const bool select, const float color[4]); -void wm_manipulator_vec_draw( - const float color[4], const float (*verts)[3], uint vert_count, - uint pos, uint primitive_type); - - -#endif /* __MANIPULATOR_LIBRARY_INTERN_H__ */ diff --git a/source/blender/editors/manipulator_library/manipulator_library_presets.c b/source/blender/editors/manipulator_library/manipulator_library_presets.c deleted file mode 100644 index 12f07611722..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_library_presets.c +++ /dev/null @@ -1,150 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/manipulator_library/manipulator_library_presets.c - * \ingroup wm - * - * \name Manipulator Lib Presets - * - * \brief Preset shapes that can be drawn from any manipulator type. - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" - -#include "DNA_view3d_types.h" -#include "DNA_object_types.h" - -#include "BKE_context.h" - -#include "BIF_gl.h" - -#include "GPU_draw.h" -#include "GPU_immediate.h" -#include "GPU_immediate_util.h" -#include "GPU_matrix.h" -#include "GPU_select.h" - -#include "DEG_depsgraph.h" - -#include "RNA_access.h" - -#include "WM_types.h" -#include "WM_api.h" - -#include "ED_view3d.h" -#include "ED_screen.h" - -/* own includes */ -#include "ED_manipulator_library.h" /* own include */ -#include "manipulator_library_intern.h" /* own include */ - -/* TODO, this is to be used by RNA. might move to ED_manipulator_library */ - -/** - * Given a single axis, orient the matrix to a different direction. - */ -static void single_axis_convert( - int src_axis, float src_mat[4][4], - int dst_axis, float dst_mat[4][4]) -{ - copy_m4_m4(dst_mat, src_mat); - if (src_axis == dst_axis) { - return; - } - - float rotmat[3][3]; - mat3_from_axis_conversion_single(src_axis, dst_axis, rotmat); - transpose_m3(rotmat); - mul_m4_m4m3(dst_mat, src_mat, rotmat); -} - -/** - * Use for all geometry. - */ -static void ed_manipulator_draw_preset_geometry( - const struct wmManipulator *mpr, float mat[4][4], int select_id, - const ManipulatorGeomInfo *info) -{ - const bool is_select = (select_id != -1); - const bool is_highlight = is_select && (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; - - float color[4]; - manipulator_color_get(mpr, is_highlight, color); - - if (is_select) { - GPU_select_load_id(select_id); - } - - gpuPushMatrix(); - gpuMultMatrix(mat); - wm_manipulator_geometryinfo_draw(info, is_select, color); - gpuPopMatrix(); - - if (is_select) { - GPU_select_load_id(-1); - } -} - -void ED_manipulator_draw_preset_box( - const struct wmManipulator *mpr, float mat[4][4], int select_id) -{ - ed_manipulator_draw_preset_geometry(mpr, mat, select_id, &wm_manipulator_geom_data_cube); -} - -void ED_manipulator_draw_preset_arrow( - const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id) -{ - float mat_rotate[4][4]; - single_axis_convert(OB_POSZ, mat, axis, mat_rotate); - ed_manipulator_draw_preset_geometry(mpr, mat_rotate, select_id, &wm_manipulator_geom_data_arrow); -} - -void ED_manipulator_draw_preset_circle( - const struct wmManipulator *mpr, float mat[4][4], int axis, int select_id) -{ - float mat_rotate[4][4]; - single_axis_convert(OB_POSZ, mat, axis, mat_rotate); - ed_manipulator_draw_preset_geometry(mpr, mat_rotate, select_id, &wm_manipulator_geom_data_dial); -} - -void ED_manipulator_draw_preset_facemap( - const bContext *C, const struct wmManipulator *mpr, struct Scene *scene, Object *ob, const int facemap, int select_id) -{ - const bool is_select = (select_id != -1); - const bool is_highlight = is_select && (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; - - float color[4]; - manipulator_color_get(mpr, is_highlight, color); - - if (is_select) { - GPU_select_load_id(select_id); - } - - gpuPushMatrix(); - gpuMultMatrix(ob->obmat); - ED_draw_object_facemap(CTX_data_depsgraph(C), scene, ob, color, facemap); - gpuPopMatrix(); - - if (is_select) { - GPU_select_load_id(-1); - } -} diff --git a/source/blender/editors/manipulator_library/manipulator_library_utils.c b/source/blender/editors/manipulator_library/manipulator_library_utils.c deleted file mode 100644 index 957f0abdd71..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_library_utils.c +++ /dev/null @@ -1,256 +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) 2015 Blender Foundation. - * All rights reserved. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file manipulator_library_utils.c - * \ingroup wm - * - * \name Manipulator Library Utilities - * - * \brief This file contains functions for common behaviors of manipulators. - */ - -#include "BLI_math.h" -#include "BLI_listbase.h" - -#include "DNA_view3d_types.h" -#include "DNA_screen_types.h" - -#include "BKE_context.h" - -#include "RNA_access.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_view3d.h" - -/* own includes */ -#include "manipulator_library_intern.h" - -/* factor for precision tweaking */ -#define MANIPULATOR_PRECISION_FAC 0.05f - - -BLI_INLINE float manipulator_offset_from_value_constr( - const float range_fac, const float min, const float range, const float value, - const bool inverted) -{ - return inverted ? (range_fac * (min + range - value) / range) : (range_fac * (value / range)); -} - -BLI_INLINE float manipulator_value_from_offset_constr( - const float range_fac, const float min, const float range, const float value, - const bool inverted) -{ - return inverted ? (min + range - (value * range / range_fac)) : (value * range / range_fac); -} - -float manipulator_offset_from_value( - ManipulatorCommonData *data, const float value, const bool constrained, const bool inverted) -{ - if (constrained) - return manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted); - - return value; -} - -float manipulator_value_from_offset( - ManipulatorCommonData *data, ManipulatorInteraction *inter, const float offset, - const bool constrained, const bool inverted, const bool use_precision) -{ - const float max = data->min + data->range; - - if (use_precision) { - /* add delta offset of this step to total precision_offset */ - inter->precision_offset += offset - inter->prev_offset; - } - inter->prev_offset = offset; - - float ofs_new = inter->init_offset + offset - inter->precision_offset * (1.0f - MANIPULATOR_PRECISION_FAC); - float value; - - if (constrained) { - value = manipulator_value_from_offset_constr(data->range_fac, data->min, data->range, ofs_new, inverted); - } - else { - value = ofs_new; - } - - /* clamp to custom range */ - if (data->flag & MANIPULATOR_CUSTOM_RANGE_SET) { - CLAMP(value, data->min, max); - } - - return value; -} - -void manipulator_property_data_update( - wmManipulator *mpr, ManipulatorCommonData *data, wmManipulatorProperty *mpr_prop, - const bool constrained, const bool inverted) -{ - if (mpr_prop->custom_func.value_get_fn != NULL) { - /* pass */ - } - else if (mpr_prop->prop != NULL) { - /* pass */ - } - else { - data->offset = 0.0f; - return; - } - - float value = WM_manipulator_target_property_value_get(mpr, mpr_prop); - - if (constrained) { - if ((data->flag & MANIPULATOR_CUSTOM_RANGE_SET) == 0) { - float range[2]; - if (WM_manipulator_target_property_range_get(mpr, mpr_prop, range)) { - data->range = range[1] - range[0]; - data->min = range[0]; - } - else { - BLI_assert(0); - } - } - data->offset = manipulator_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted); - } - else { - data->offset = value; - } -} - -void manipulator_property_value_reset( - bContext *C, const wmManipulator *mpr, ManipulatorInteraction *inter, - wmManipulatorProperty *mpr_prop) -{ - WM_manipulator_target_property_value_set(C, mpr, mpr_prop, inter->init_value); -} - -/* -------------------------------------------------------------------- */ - -void manipulator_color_get( - const wmManipulator *mpr, const bool highlight, - float r_col[4]) -{ - if (highlight && !(mpr->flag & WM_MANIPULATOR_DRAW_HOVER)) { - copy_v4_v4(r_col, mpr->color_hi); - } - else { - copy_v4_v4(r_col, mpr->color); - } -} - -/* -------------------------------------------------------------------- */ - -/** - * Takes mouse coordinates and returns them in relation to the manipulator. - * Both 2D & 3D supported, use so we can use 2D manipulators in the 3D view. - */ -bool manipulator_window_project_2d( - bContext *C, const struct wmManipulator *mpr, const float mval[2], int axis, bool use_offset, - float r_co[2]) -{ - float mat[4][4]; - { - float mat_identity[4][4]; - struct WM_ManipulatorMatrixParams params = {NULL}; - if (use_offset == false) { - unit_m4(mat_identity); - params.matrix_offset = mat_identity; - } - WM_manipulator_calc_matrix_final_params(mpr, ¶ms, mat); - } - - /* rotate mouse in relation to the center and relocate it */ - if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { - /* For 3d views, transform 2D mouse pos onto plane. */ - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - - float plane[4]; - - plane_from_point_normal_v3(plane, mat[3], mat[2]); - - float ray_origin[3], ray_direction[3]; - - if (ED_view3d_win_to_ray(CTX_data_depsgraph(C), ar, v3d, mval, ray_origin, ray_direction, false)) { - float lambda; - if (isect_ray_plane_v3(ray_origin, ray_direction, plane, &lambda, true)) { - float co[3]; - madd_v3_v3v3fl(co, ray_origin, ray_direction, lambda); - float imat[4][4]; - invert_m4_m4(imat, mat); - mul_m4_v3(imat, co); - r_co[0] = co[(axis + 1) % 3]; - r_co[1] = co[(axis + 2) % 3]; - return true; - } - } - return false; - } - else { - float co[3] = {mval[0], mval[1], 0.0f}; - float imat[4][4]; - invert_m4_m4(imat, mat); - mul_mat3_m4_v3(imat, co); - copy_v2_v2(r_co, co); - return true; - } -} - -bool manipulator_window_project_3d( - bContext *C, const struct wmManipulator *mpr, const float mval[2], bool use_offset, - float r_co[3]) -{ - float mat[4][4]; - { - float mat_identity[4][4]; - struct WM_ManipulatorMatrixParams params = {NULL}; - if (use_offset == false) { - unit_m4(mat_identity); - params.matrix_offset = mat_identity; - } - WM_manipulator_calc_matrix_final_params(mpr, ¶ms, mat); - } - - if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - /* Note: we might want a custom reference point passed in, - * instead of the manipulator center. */ - ED_view3d_win_to_3d(v3d, ar, mat[3], mval, r_co); - invert_m4(mat); - mul_m4_v3(mat, r_co); - return true; - } - else { - float co[3] = {mval[0], mval[1], 0.0f}; - float imat[4][4]; - invert_m4_m4(imat, mat); - mul_m4_v3(imat, co); - copy_v2_v2(r_co, co); - return true; - } -} diff --git a/source/blender/editors/manipulator_library/manipulator_types/arrow2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/arrow2d_manipulator.c deleted file mode 100644 index 5acf1ab2d64..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_types/arrow2d_manipulator.c +++ /dev/null @@ -1,225 +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) 2016 Blender Foundation. - * All rights reserved. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file arrow2d_manipulator.c - * \ingroup wm - * - * \name 2D Arrow Manipulator - * - * \brief Simple arrow manipulator which is dragged into a certain direction. - */ - -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_rect.h" - -#include "DNA_windowmanager_types.h" - -#include "BKE_context.h" - -#include "BIF_gl.h" - -#include "GPU_draw.h" -#include "GPU_immediate.h" -#include "GPU_matrix.h" -#include "GPU_state.h" - -#include "MEM_guardedalloc.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_types.h" - -#include "ED_screen.h" -#include "ED_manipulator_library.h" - -/* own includes */ -#include "WM_api.h" - -#include "../manipulator_library_intern.h" - -static void arrow2d_draw_geom(wmManipulator *mpr, const float matrix[4][4], const float color[4]) -{ - const float size = 0.11f; - const float size_breadth = size / 2.0f; - const float size_length = size * 1.7f; - /* Subtract the length so the arrow fits in the hotspot. */ - const float arrow_length = RNA_float_get(mpr->ptr, "length") - size_length; - const float arrow_angle = RNA_float_get(mpr->ptr, "angle"); - - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - gpuPushMatrix(); - gpuMultMatrix(matrix); - gpuRotate2D(RAD2DEGF(arrow_angle)); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - immUniformColor4fv(color); - - immBegin(GWN_PRIM_LINES, 2); - immVertex2f(pos, 0.0f, 0.0f); - immVertex2f(pos, 0.0f, arrow_length); - immEnd(); - - immBegin(GWN_PRIM_TRIS, 3); - immVertex2f(pos, size_breadth, arrow_length); - immVertex2f(pos, -size_breadth, arrow_length); - immVertex2f(pos, 0.0f, arrow_length + size_length); - immEnd(); - - immUnbindProgram(); - - gpuPopMatrix(); -} - -static void manipulator_arrow2d_draw(const bContext *UNUSED(C), wmManipulator *mpr) -{ - float color[4]; - - float matrix_final[4][4]; - - manipulator_color_get(mpr, mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT, color); - - GPU_line_width(mpr->line_width); - - WM_manipulator_calc_matrix_final(mpr, matrix_final); - - GPU_blend(true); - arrow2d_draw_geom(mpr, matrix_final, color); - GPU_blend(false); - - if (mpr->interaction_data) { - ManipulatorInteraction *inter = mpr->interaction_data; - - GPU_blend(true); - arrow2d_draw_geom(mpr, inter->init_matrix_final, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}); - GPU_blend(false); - } -} - -static void manipulator_arrow2d_setup(wmManipulator *mpr) -{ - mpr->flag |= WM_MANIPULATOR_DRAW_MODAL; -} - -static int manipulator_arrow2d_invoke( - bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *UNUSED(event)) -{ - ManipulatorInteraction *inter = MEM_callocN(sizeof(ManipulatorInteraction), __func__); - - copy_m4_m4(inter->init_matrix_basis, mpr->matrix_basis); - WM_manipulator_calc_matrix_final(mpr, inter->init_matrix_final); - - mpr->interaction_data = inter; - - return OPERATOR_RUNNING_MODAL; -} - -static int manipulator_arrow2d_test_select( - bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) -{ - const float mval[2] = {event->mval[0], event->mval[1]}; - const float arrow_length = RNA_float_get(mpr->ptr, "length"); - const float arrow_angle = RNA_float_get(mpr->ptr, "angle"); - const float line_len = arrow_length * mpr->scale_final; - float mval_local[2]; - - copy_v2_v2(mval_local, mval); - sub_v2_v2(mval_local, mpr->matrix_basis[3]); - - float line[2][2]; - line[0][0] = line[0][1] = line[1][0] = 0.0f; - line[1][1] = line_len; - - /* rotate only if needed */ - if (arrow_angle != 0.0f) { - float rot_point[2]; - copy_v2_v2(rot_point, line[1]); - rotate_v2_v2fl(line[1], rot_point, arrow_angle); - } - - /* arrow line intersection check */ - float isect_1[2], isect_2[2]; - const int isect = isect_line_sphere_v2( - line[0], line[1], mval_local, MANIPULATOR_HOTSPOT + mpr->line_width * 0.5f, - isect_1, isect_2); - - if (isect > 0) { - float line_ext[2][2]; /* extended line for segment check including hotspot */ - copy_v2_v2(line_ext[0], line[0]); - line_ext[1][0] = line[1][0] + MANIPULATOR_HOTSPOT * ((line[1][0] - line[0][0]) / line_len); - line_ext[1][1] = line[1][1] + MANIPULATOR_HOTSPOT * ((line[1][1] - line[0][1]) / line_len); - - const float lambda_1 = line_point_factor_v2(isect_1, line_ext[0], line_ext[1]); - if (isect == 1) { - if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f)) { - return 0; - } - } - else { - BLI_assert(isect == 2); - const float lambda_2 = line_point_factor_v2(isect_2, line_ext[0], line_ext[1]); - if (IN_RANGE_INCL(lambda_1, 0.0f, 1.0f) && IN_RANGE_INCL(lambda_2, 0.0f, 1.0f)) { - return 0; - } - } - } - - return -1; -} - -/* -------------------------------------------------------------------- */ -/** \name 2D Arrow Manipulator API - * - * \{ */ - -static void MANIPULATOR_WT_arrow_2d(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "MANIPULATOR_WT_arrow_2d"; - - /* api callbacks */ - wt->draw = manipulator_arrow2d_draw; - wt->setup = manipulator_arrow2d_setup; - wt->invoke = manipulator_arrow2d_invoke; - wt->test_select = manipulator_arrow2d_test_select; - - wt->struct_size = sizeof(wmManipulator); - - /* rna */ - RNA_def_float(wt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX); - RNA_def_float_rotation( - wt->srna, "angle", 0, NULL, DEG2RADF(-360.0f), DEG2RADF(360.0f), - "Roll", "", DEG2RADF(-360.0f), DEG2RADF(360.0f)); -} - -void ED_manipulatortypes_arrow_2d(void) -{ - WM_manipulatortype_append(MANIPULATOR_WT_arrow_2d); -} - -/** \} */ diff --git a/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c deleted file mode 100644 index 0430a12bc99..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_types/arrow3d_manipulator.c +++ /dev/null @@ -1,492 +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 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file arrow3d_manipulator.c - * \ingroup wm - * - * \name Arrow Manipulator - * - * 3D Manipulator - * - * \brief Simple arrow manipulator which is dragged into a certain direction. - * The arrow head can have varying shapes, e.g. cone, box, etc. - * - * - `matrix[0]` is derived from Y and Z. - * - `matrix[1]` is 'up' for manipulator types that have an up. - * - `matrix[2]` is the arrow direction (for all arrowes). - */ - -#include "BIF_gl.h" - -#include "BLI_math.h" - -#include "DNA_view3d_types.h" - -#include "BKE_context.h" - -#include "GPU_draw.h" -#include "GPU_immediate.h" -#include "GPU_immediate_util.h" -#include "GPU_matrix.h" -#include "GPU_select.h" -#include "GPU_state.h" - -#include "MEM_guardedalloc.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_types.h" -#include "WM_api.h" - -#include "ED_view3d.h" -#include "ED_screen.h" -#include "ED_manipulator_library.h" - -/* own includes */ -#include "../manipulator_geometry.h" -#include "../manipulator_library_intern.h" - -/* to use custom arrows exported to geom_arrow_manipulator.c */ -//#define USE_MANIPULATOR_CUSTOM_ARROWS - -typedef struct ArrowManipulator3D { - wmManipulator manipulator; - ManipulatorCommonData data; -} ArrowManipulator3D; - - -/* -------------------------------------------------------------------- */ - -static void manipulator_arrow_matrix_basis_get(const wmManipulator *mpr, float r_matrix[4][4]) -{ - ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; - - copy_m4_m4(r_matrix, arrow->manipulator.matrix_basis); - madd_v3_v3fl(r_matrix[3], arrow->manipulator.matrix_basis[2], arrow->data.offset); -} - -static void arrow_draw_geom(const ArrowManipulator3D *arrow, const bool select, const float color[4]) -{ - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - bool unbind_shader = true; - const int draw_style = RNA_enum_get(arrow->manipulator.ptr, "draw_style"); - const int draw_options = RNA_enum_get(arrow->manipulator.ptr, "draw_options"); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - if (draw_style == ED_MANIPULATOR_ARROW_STYLE_CROSS) { - immUniformColor4fv(color); - - immBegin(GWN_PRIM_LINES, 4); - immVertex3f(pos, -1.0f, 0.0f, 0.0f); - immVertex3f(pos, 1.0f, 0.0f, 0.0f); - immVertex3f(pos, 0.0f, -1.0f, 0.0f); - immVertex3f(pos, 0.0f, 1.0f, 0.0f); - immEnd(); - } - else if (draw_style == ED_MANIPULATOR_ARROW_STYLE_CONE) { - float aspect[2]; - RNA_float_get_array(arrow->manipulator.ptr, "aspect", aspect); - const float unitx = aspect[0]; - const float unity = aspect[1]; - const float vec[4][3] = { - {-unitx, -unity, 0}, - { unitx, -unity, 0}, - { unitx, unity, 0}, - {-unitx, unity, 0}, - }; - - GPU_line_width(arrow->manipulator.line_width); - wm_manipulator_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GWN_PRIM_LINE_LOOP); - } - else { -#ifdef USE_MANIPULATOR_CUSTOM_ARROWS - wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_arrow, select, color); -#else - const float arrow_length = RNA_float_get(arrow->manipulator.ptr, "length"); - - const float vec[2][3] = { - {0.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, arrow_length}, - }; - - if (draw_options & ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM) { - GPU_line_width(arrow->manipulator.line_width); - wm_manipulator_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GWN_PRIM_LINE_STRIP); - } - else { - immUniformColor4fv(color); - } - - /* *** draw arrow head *** */ - - gpuPushMatrix(); - - if (draw_style == ED_MANIPULATOR_ARROW_STYLE_BOX) { - const float size = 0.05f; - - /* translate to line end with some extra offset so box starts exactly where line ends */ - gpuTranslate3f(0.0f, 0.0f, arrow_length + size); - /* scale down to box size */ - gpuScale3f(size, size, size); - - /* draw cube */ - immUnbindProgram(); - unbind_shader = false; - wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_cube, select, color); - } - else { - BLI_assert(draw_style == ED_MANIPULATOR_ARROW_STYLE_NORMAL); - - const float len = 0.25f; - const float width = 0.06f; - - /* translate to line end */ - gpuTranslate3f(0.0f, 0.0f, arrow_length); - - imm_draw_circle_fill_3d(pos, 0.0, 0.0, width, 8); - imm_draw_cylinder_fill_3d(pos, width, 0.0, len, 8, 1); - } - - gpuPopMatrix(); -#endif /* USE_MANIPULATOR_CUSTOM_ARROWS */ - } - - if (unbind_shader) { - immUnbindProgram(); - } -} - -static void arrow_draw_intern(ArrowManipulator3D *arrow, const bool select, const bool highlight) -{ - wmManipulator *mpr = &arrow->manipulator; - float color[4]; - float matrix_final[4][4]; - - manipulator_color_get(mpr, highlight, color); - - WM_manipulator_calc_matrix_final(mpr, matrix_final); - - gpuPushMatrix(); - gpuMultMatrix(matrix_final); - GPU_blend(true); - arrow_draw_geom(arrow, select, color); - GPU_blend(false); - - gpuPopMatrix(); - - if (mpr->interaction_data) { - ManipulatorInteraction *inter = mpr->interaction_data; - - gpuPushMatrix(); - gpuMultMatrix(inter->init_matrix_final); - - - GPU_blend(true); - arrow_draw_geom(arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}); - GPU_blend(false); - - gpuPopMatrix(); - } -} - -static void manipulator_arrow_draw_select( - const bContext *UNUSED(C), wmManipulator *mpr, - int select_id) -{ - GPU_select_load_id(select_id); - arrow_draw_intern((ArrowManipulator3D *)mpr, true, false); -} - -static void manipulator_arrow_draw(const bContext *UNUSED(C), wmManipulator *mpr) -{ - arrow_draw_intern((ArrowManipulator3D *)mpr, false, (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0); -} - -/** - * Calculate arrow offset independent from prop min value, - * meaning the range will not be offset by min value first. - */ -static int manipulator_arrow_modal( - bContext *C, wmManipulator *mpr, const wmEvent *event, - eWM_ManipulatorTweak tweak_flag) -{ - ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; - ManipulatorInteraction *inter = mpr->interaction_data; - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - - float offset[3]; - float facdir = 1.0f; - - /* (src, dst) */ - struct { - float mval[2]; - float ray_origin[3], ray_direction[3]; - float location[3]; - } proj[2] = { - {.mval = {UNPACK2(inter->init_mval)}}, - {.mval = {UNPACK2(event->mval)}}, - }; - - float arrow_co[3]; - float arrow_no[3]; - copy_v3_v3(arrow_co, inter->init_matrix_basis[3]); - normalize_v3_v3(arrow_no, arrow->manipulator.matrix_basis[2]); - - int ok = 0; - - for (int j = 0; j < 2; j++) { - if (ED_view3d_win_to_ray( - CTX_data_depsgraph(C), - ar, v3d, proj[j].mval, - proj[j].ray_origin, proj[j].ray_direction, false)) - { - /* Force Y axis if we're view aligned */ - if (j == 0) { - if (RAD2DEGF(acosf(dot_v3v3(proj[j].ray_direction, arrow->manipulator.matrix_basis[2]))) < 5.0f) { - normalize_v3_v3(arrow_no, rv3d->viewinv[1]); - } - } - - float arrow_no_proj[3]; - project_plane_v3_v3v3(arrow_no_proj, arrow_no, proj[j].ray_direction); - - normalize_v3(arrow_no_proj); - - float plane[4]; - plane_from_point_normal_v3(plane, proj[j].ray_origin, arrow_no_proj); - - float lambda; - if (isect_ray_plane_v3(arrow_co, arrow_no, plane, &lambda, false)) { - madd_v3_v3v3fl(proj[j].location, arrow_co, arrow_no, lambda); - ok++; - } - } - } - - if (ok != 2) { - return OPERATOR_RUNNING_MODAL; - } - - sub_v3_v3v3(offset, proj[1].location, proj[0].location); - facdir = dot_v3v3(arrow_no, offset) < 0.0f ? -1 : 1; - - ManipulatorCommonData *data = &arrow->data; - const float ofs_new = facdir * len_v3(offset); - - wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); - - /* set the property for the operator and call its modal function */ - if (WM_manipulator_target_property_is_valid(mpr_prop)) { - const int transform_flag = RNA_enum_get(arrow->manipulator.ptr, "transform"); - const bool constrained = (transform_flag & ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED) != 0; - const bool inverted = (transform_flag & ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED) != 0; - const bool use_precision = (tweak_flag & WM_MANIPULATOR_TWEAK_PRECISE) != 0; - float value = manipulator_value_from_offset(data, inter, ofs_new, constrained, inverted, use_precision); - - WM_manipulator_target_property_value_set(C, mpr, mpr_prop, value); - /* get clamped value */ - value = WM_manipulator_target_property_value_get(mpr, mpr_prop); - - data->offset = manipulator_offset_from_value(data, value, constrained, inverted); - } - else { - data->offset = ofs_new; - } - - /* tag the region for redraw */ - ED_region_tag_redraw(ar); - WM_event_add_mousemove(C); - - return OPERATOR_RUNNING_MODAL; -} - -static void manipulator_arrow_setup(wmManipulator *mpr) -{ - ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; - - arrow->manipulator.flag |= WM_MANIPULATOR_DRAW_MODAL; - - arrow->data.range_fac = 1.0f; -} - -static int manipulator_arrow_invoke( - bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) -{ - ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; - ManipulatorInteraction *inter = MEM_callocN(sizeof(ManipulatorInteraction), __func__); - wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); - - /* Some manipulators don't use properties. */ - if (WM_manipulator_target_property_is_valid(mpr_prop)) { - inter->init_value = WM_manipulator_target_property_value_get(mpr, mpr_prop); - } - - inter->init_offset = arrow->data.offset; - - inter->init_mval[0] = event->mval[0]; - inter->init_mval[1] = event->mval[1]; - - manipulator_arrow_matrix_basis_get(mpr, inter->init_matrix_basis); - WM_manipulator_calc_matrix_final(mpr, inter->init_matrix_final); - - mpr->interaction_data = inter; - - return OPERATOR_RUNNING_MODAL; -} - -static void manipulator_arrow_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop) -{ - ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; - const int transform_flag = RNA_enum_get(arrow->manipulator.ptr, "transform"); - const bool constrained = (transform_flag & ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED) != 0; - const bool inverted = (transform_flag & ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED) != 0; - manipulator_property_data_update(mpr, &arrow->data, mpr_prop, constrained, inverted); -} - -static void manipulator_arrow_exit(bContext *C, wmManipulator *mpr, const bool cancel) -{ - ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; - ManipulatorCommonData *data = &arrow->data; - wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); - const bool is_prop_valid = WM_manipulator_target_property_is_valid(mpr_prop); - - if (!cancel) { - /* Assign incase applying the opetration needs an updated offset - * editmesh bisect needs this. */ - if (is_prop_valid) { - data->offset = WM_manipulator_target_property_value_get(mpr, mpr_prop); - } - return; - } - - ManipulatorInteraction *inter = mpr->interaction_data; - if (is_prop_valid) { - manipulator_property_value_reset(C, mpr, inter, mpr_prop); - } - data->offset = inter->init_offset; -} - - -/* -------------------------------------------------------------------- */ -/** \name Arrow Manipulator API - * - * \{ */ - -/** - * Define a custom property UI range - * - * \note Needs to be called before WM_manipulator_target_property_def_rna! - */ -void ED_manipulator_arrow3d_set_ui_range(wmManipulator *mpr, const float min, const float max) -{ - ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; - - BLI_assert(min < max); - BLI_assert(!(WM_manipulator_target_property_is_valid(WM_manipulator_target_property_find(mpr, "offset")) && - "Make sure this function is called before WM_manipulator_target_property_def_rna")); - - arrow->data.range = max - min; - arrow->data.min = min; - arrow->data.flag |= MANIPULATOR_CUSTOM_RANGE_SET; -} - -/** - * Define a custom factor for arrow min/max distance - * - * \note Needs to be called before WM_manipulator_target_property_def_rna! - */ -void ED_manipulator_arrow3d_set_range_fac(wmManipulator *mpr, const float range_fac) -{ - ArrowManipulator3D *arrow = (ArrowManipulator3D *)mpr; - BLI_assert(!(WM_manipulator_target_property_is_valid(WM_manipulator_target_property_find(mpr, "offset")) && - "Make sure this function is called before WM_manipulator_target_property_def_rna")); - - arrow->data.range_fac = range_fac; -} - -static void MANIPULATOR_WT_arrow_3d(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "MANIPULATOR_WT_arrow_3d"; - - /* api callbacks */ - wt->draw = manipulator_arrow_draw; - wt->draw_select = manipulator_arrow_draw_select; - wt->matrix_basis_get = manipulator_arrow_matrix_basis_get; - wt->modal = manipulator_arrow_modal; - wt->setup = manipulator_arrow_setup; - wt->invoke = manipulator_arrow_invoke; - wt->property_update = manipulator_arrow_property_update; - wt->exit = manipulator_arrow_exit; - - wt->struct_size = sizeof(ArrowManipulator3D); - - /* rna */ - static EnumPropertyItem rna_enum_draw_style_items[] = { - {ED_MANIPULATOR_ARROW_STYLE_NORMAL, "NORMAL", 0, "Normal", ""}, - {ED_MANIPULATOR_ARROW_STYLE_CROSS, "CROSS", 0, "Cross", ""}, - {ED_MANIPULATOR_ARROW_STYLE_BOX, "BOX", 0, "Box", ""}, - {ED_MANIPULATOR_ARROW_STYLE_CONE, "CONE", 0, "Cone", ""}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem rna_enum_draw_options_items[] = { - {ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM, "STEM", 0, "Stem", ""}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem rna_enum_transform_items[] = { - {ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED, "INVERT", 0, "Inverted", ""}, - {ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED, "CONSTRAIN", 0, "Constrained", ""}, - {0, NULL, 0, NULL, NULL} - }; - - RNA_def_enum( - wt->srna, "draw_style", rna_enum_draw_style_items, - ED_MANIPULATOR_ARROW_STYLE_NORMAL, - "Draw Style", ""); - RNA_def_enum_flag( - wt->srna, "draw_options", rna_enum_draw_options_items, - ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM, - "Draw Options", ""); - RNA_def_enum_flag( - wt->srna, "transform", rna_enum_transform_items, - 0, - "Transform", ""); - - RNA_def_float(wt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX); - RNA_def_float_vector(wt->srna, "aspect", 2, NULL, 0, FLT_MAX, "Aspect", "Cone/box style only", 0.0f, FLT_MAX); - - WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 1); -} - -void ED_manipulatortypes_arrow_3d(void) -{ - WM_manipulatortype_append(MANIPULATOR_WT_arrow_3d); -} - -/** \} */ diff --git a/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c deleted file mode 100644 index db33f457056..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_types/button2d_manipulator.c +++ /dev/null @@ -1,322 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file button2d_manipulator.c - * \ingroup wm - * - * \name Button Manipulator - * - * 2D Manipulator, also works in 3D views. - * - * \brief Single click button action for use in manipulator groups. - * - * \note Currently only basic icon & vector-shape buttons are supported. - * - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.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_select.h" -#include "GPU_batch.h" -#include "GPU_state.h" - -#include "RNA_access.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_screen.h" -#include "ED_view3d.h" -#include "ED_manipulator_library.h" - -#include "UI_interface.h" -#include "UI_interface_icons.h" -#include "UI_resources.h" - -/* own includes */ -#include "../manipulator_geometry.h" -#include "../manipulator_library_intern.h" - -typedef struct ButtonManipulator2D { - wmManipulator manipulator; - bool is_init; - /* Use an icon or shape */ - int icon; - Gwn_Batch *shape_batch[2]; -} ButtonManipulator2D; - -#define CIRCLE_RESOLUTION 32 - -/* -------------------------------------------------------------------- */ - -static void button2d_geom_draw_backdrop( - const wmManipulator *mpr, const float color[4], const bool select) -{ - GPU_line_width(mpr->line_width); - - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - immUniformColor4fv(color); - - /* TODO, other draw styles */ - imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION); - - immUnbindProgram(); - - UNUSED_VARS(select); -} - -static void button2d_draw_intern( - const bContext *C, wmManipulator *mpr, - const bool select, const bool highlight) -{ - ButtonManipulator2D *button = (ButtonManipulator2D *)mpr; - - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - if (button->is_init == false) { - button->is_init = true; - PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "icon"); - if (RNA_property_is_set(mpr->ptr, prop)) { - button->icon = RNA_property_enum_get(mpr->ptr, prop); - } - else { - prop = RNA_struct_find_property(mpr->ptr, "shape"); - const uint polys_len = RNA_property_string_length(mpr->ptr, prop); - /* We shouldn't need the +1, but a NULL char is set. */ - char *polys = MEM_mallocN(polys_len + 1, __func__); - RNA_property_string_get(mpr->ptr, prop, polys); - button->shape_batch[0] = GPU_batch_tris_from_poly_2d_encoded((uchar *)polys, polys_len, NULL); - button->shape_batch[1] = GPU_batch_wire_from_poly_2d_encoded((uchar *)polys, polys_len, NULL); - MEM_freeN(polys); - } - } - - float color[4]; - float matrix_final[4][4]; - - manipulator_color_get(mpr, highlight, color); - WM_manipulator_calc_matrix_final(mpr, matrix_final); - - - bool is_3d = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) != 0; - - - if (draw_options & ED_MANIPULATOR_BUTTON_SHOW_HELPLINE) { - float matrix_final_no_offset[4][4]; - WM_manipulator_calc_matrix_final_no_offset(mpr, matrix_final_no_offset); - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformColor4fv(color); - GPU_line_width(mpr->line_width); - immUniformColor4fv(color); - immBegin(GWN_PRIM_LINE_STRIP, 2); - immVertex3fv(pos, matrix_final[3]); - immVertex3fv(pos, matrix_final_no_offset[3]); - immEnd(); - immUnbindProgram(); - } - - bool need_to_pop = true; - gpuPushMatrix(); - gpuMultMatrix(matrix_final); - - if (is_3d) { - RegionView3D *rv3d = CTX_wm_region_view3d(C); - float matrix_align[4][4]; - float matrix_final_unit[4][4]; - normalize_m4_m4(matrix_final_unit, matrix_final); - mul_m4_m4m4(matrix_align, rv3d->viewmat, matrix_final_unit); - zero_v3(matrix_align[3]); - transpose_m4(matrix_align); - gpuMultMatrix(matrix_align); - } - - if (select) { - BLI_assert(is_3d); - button2d_geom_draw_backdrop(mpr, color, select); - } - else { - - GPU_blend(true); - if (button->shape_batch[0] != NULL) { - GPU_line_smooth(true); - GPU_polygon_smooth(false); - GPU_line_width(1.0f); - for (uint i = 0; i < ARRAY_SIZE(button->shape_batch) && button->shape_batch[i]; i++) { - /* Invert line color for wire. */ - GWN_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR); - GWN_batch_uniform_4f(button->shape_batch[i], "color", UNPACK4(color)); - GWN_batch_draw(button->shape_batch[i]); - - if (draw_options & ED_MANIPULATOR_BUTTON_SHOW_OUTLINE) { - color[0] = 1.0f - color[0]; - color[1] = 1.0f - color[1]; - color[2] = 1.0f - color[2]; - } - } - GPU_line_smooth(false); - GPU_polygon_smooth(true); - } - else if (button->icon != ICON_NONE) { - button2d_geom_draw_backdrop(mpr, color, select); - float size[2]; - if (is_3d) { - const float fac = 2.0f; - gpuTranslate2f(-(fac / 2), -(fac / 2)); - gpuScale2f(fac / (ICON_DEFAULT_WIDTH * UI_DPI_FAC), fac / (ICON_DEFAULT_HEIGHT * UI_DPI_FAC)); - size[0] = 1.0f; - size[1] = 1.0f; - } - else { - size[0] = mpr->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * UI_DPI_FAC; - size[1] = mpr->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * UI_DPI_FAC; - gpuPopMatrix(); - need_to_pop = false; - } - UI_icon_draw(size[0], size[1], button->icon); - } - GPU_blend(false); - } - - if (need_to_pop) { - gpuPopMatrix(); - } -} - -static void manipulator_button2d_draw_select(const bContext *C, wmManipulator *mpr, int select_id) -{ - GPU_select_load_id(select_id); - button2d_draw_intern(C, mpr, true, false); -} - -static void manipulator_button2d_draw(const bContext *C, wmManipulator *mpr) -{ - const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; - - GPU_blend(true); - button2d_draw_intern(C, mpr, false, is_highlight); - GPU_blend(false); -} - -static int manipulator_button2d_test_select( - bContext *C, wmManipulator *mpr, const wmEvent *event) -{ - float point_local[2]; - - if (0) { - /* correct, but unnecessarily slow. */ - if (manipulator_window_project_2d( - C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false) - { - return -1; - } - } - else { - copy_v2_v2(point_local, (float[2]){UNPACK2(event->mval)}); - sub_v2_v2(point_local, mpr->matrix_basis[3]); - mul_v2_fl(point_local, 1.0f / (mpr->scale_basis * UI_DPI_FAC)); - } - /* The 'mpr->scale_final' is already applied when projecting. */ - if (len_squared_v2(point_local) < 1.0f) { - return 0; - } - - return -1; -} - -static int manipulator_button2d_cursor_get(wmManipulator *mpr) -{ - if (RNA_boolean_get(mpr->ptr, "show_drag")) { - return BC_NSEW_SCROLLCURSOR; - } - return CURSOR_STD; -} - -static void manipulator_button2d_free(wmManipulator *mpr) -{ - ButtonManipulator2D *shape = (ButtonManipulator2D *)mpr; - - for (uint i = 0; i < ARRAY_SIZE(shape->shape_batch); i++) { - GWN_BATCH_DISCARD_SAFE(shape->shape_batch[i]); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Button Manipulator API - * - * \{ */ - -static void MANIPULATOR_WT_button_2d(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "MANIPULATOR_WT_button_2d"; - - /* api callbacks */ - wt->draw = manipulator_button2d_draw; - wt->draw_select = manipulator_button2d_draw_select; - wt->test_select = manipulator_button2d_test_select; - wt->cursor_get = manipulator_button2d_cursor_get; - wt->free = manipulator_button2d_free; - - wt->struct_size = sizeof(ButtonManipulator2D); - - /* rna */ - static EnumPropertyItem rna_enum_draw_options[] = { - {ED_MANIPULATOR_BUTTON_SHOW_OUTLINE, "OUTLINE", 0, "Outline", ""}, - {ED_MANIPULATOR_BUTTON_SHOW_HELPLINE, "HELPLINE", 0, "Help Line", ""}, - {0, NULL, 0, NULL, NULL} - }; - PropertyRNA *prop; - - RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", ""); - - prop = RNA_def_property(wt->srna, "icon", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, rna_enum_icon_items); - - /* Passed to 'GPU_batch_tris_from_poly_2d_encoded' */ - RNA_def_property(wt->srna, "shape", PROP_STRING, PROP_BYTESTRING); - - /* Currently only used for cursor display. */ - RNA_def_boolean(wt->srna, "show_drag", true, "Show Drag", ""); -} - -void ED_manipulatortypes_button_2d(void) -{ - WM_manipulatortype_append(MANIPULATOR_WT_button_2d); -} - -/** \} */ // Button Manipulator API diff --git a/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c deleted file mode 100644 index b7b19ccd634..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_types/cage2d_manipulator.c +++ /dev/null @@ -1,1100 +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 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file cage2d_manipulator.c - * \ingroup wm - * - * \name Cage Manipulator - * - * 2D Manipulator - * - * \brief Rectangular manipulator acting as a 'cage' around its content. - * Interacting scales or translates the manipulator. - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" -#include "BLI_dial_2d.h" -#include "BLI_rect.h" - -#include "BKE_context.h" - -#include "BIF_gl.h" - -#include "GPU_matrix.h" -#include "GPU_shader.h" -#include "GPU_immediate.h" -#include "GPU_immediate_util.h" -#include "GPU_select.h" -#include "GPU_state.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_screen.h" -#include "ED_view3d.h" -#include "ED_manipulator_library.h" - -/* own includes */ -#include "../manipulator_library_intern.h" - -#define MANIPULATOR_RESIZER_SIZE 10.0f -#define MANIPULATOR_MARGIN_OFFSET_SCALE 1.5f - -static void manipulator_calc_rect_view_scale( - const wmManipulator *mpr, const float dims[2], float scale[2]) -{ - float matrix_final_no_offset[4][4]; - float asp[2] = {1.0f, 1.0f}; - if (dims[0] > dims[1]) { - asp[0] = dims[1] / dims[0]; - } - else { - asp[1] = dims[0] / dims[1]; - } - float x_axis[3], y_axis[3]; - WM_manipulator_calc_matrix_final_no_offset(mpr, matrix_final_no_offset); - mul_v3_mat3_m4v3(x_axis, matrix_final_no_offset, mpr->matrix_offset[0]); - mul_v3_mat3_m4v3(y_axis, matrix_final_no_offset, mpr->matrix_offset[1]); - - mul_v2_v2(x_axis, asp); - mul_v2_v2(y_axis, asp); - - scale[0] = 1.0f / len_v3(x_axis); - scale[1] = 1.0f / len_v3(y_axis); -} - -static void manipulator_calc_rect_view_margin( - const wmManipulator *mpr, const float dims[2], float margin[2]) -{ - float handle_size; - if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { - handle_size = 0.15f; - } - else { - handle_size = MANIPULATOR_RESIZER_SIZE; - } - handle_size *= mpr->scale_final; - float scale_xy[2]; - manipulator_calc_rect_view_scale(mpr, dims, scale_xy); - margin[0] = ((handle_size * scale_xy[0])); - margin[1] = ((handle_size * scale_xy[1])); -} - -/* -------------------------------------------------------------------- */ - -static void manipulator_rect_pivot_from_scale_part(int part, float r_pt[2], bool r_constrain_axis[2]) -{ - bool x = true, y = true; - switch (part) { - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X: { ARRAY_SET_ITEMS(r_pt, 0.5, 0.0); x = false; break; } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X: { ARRAY_SET_ITEMS(r_pt, -0.5, 0.0); x = false; break; } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y: { ARRAY_SET_ITEMS(r_pt, 0.0, 0.5); y = false; break; } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y: { ARRAY_SET_ITEMS(r_pt, 0.0, -0.5); y = false; break; } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y: { ARRAY_SET_ITEMS(r_pt, 0.5, 0.5); x = y = false; break; } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y: { ARRAY_SET_ITEMS(r_pt, 0.5, -0.5); x = y = false; break; } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y: { ARRAY_SET_ITEMS(r_pt, -0.5, 0.5); x = y = false; break; } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y: { ARRAY_SET_ITEMS(r_pt, -0.5, -0.5); x = y = false; break; } - default: BLI_assert(0); - } - r_constrain_axis[0] = x; - r_constrain_axis[1] = y; -} - -/* -------------------------------------------------------------------- */ -/** \name Box Draw Style - * - * Useful for 3D views, see: #ED_MANIPULATOR_CAGE2D_STYLE_BOX - * \{ */ - -static void cage2d_draw_box_corners( - const rctf *r, const float margin[2], const float color[3]) -{ - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor3fv(color); - - immBegin(GWN_PRIM_LINES, 16); - - immVertex2f(pos, r->xmin, r->ymin + margin[1]); - immVertex2f(pos, r->xmin, r->ymin); - immVertex2f(pos, r->xmin, r->ymin); - immVertex2f(pos, r->xmin + margin[0], r->ymin); - - immVertex2f(pos, r->xmax, r->ymin + margin[1]); - immVertex2f(pos, r->xmax, r->ymin); - immVertex2f(pos, r->xmax, r->ymin); - immVertex2f(pos, r->xmax - margin[0], r->ymin); - - immVertex2f(pos, r->xmax, r->ymax - margin[1]); - immVertex2f(pos, r->xmax, r->ymax); - immVertex2f(pos, r->xmax, r->ymax); - immVertex2f(pos, r->xmax - margin[0], r->ymax); - - immVertex2f(pos, r->xmin, r->ymax - margin[1]); - immVertex2f(pos, r->xmin, r->ymax); - immVertex2f(pos, r->xmin, r->ymax); - immVertex2f(pos, r->xmin + margin[0], r->ymax); - - immEnd(); - - immUnbindProgram(); -} - -static void cage2d_draw_box_interaction( - const float color[4], const int highlighted, - const float size[2], const float margin[2], - const float line_width, const bool is_solid, const int draw_options) -{ - /* 4 verts for translate, otherwise only 3 are used. */ - float verts[4][2]; - uint verts_len = 0; - Gwn_PrimType prim_type = GWN_PRIM_NONE; - - switch (highlighted) { - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X: - { - rctf r = { - .xmin = -size[0], .xmax = -size[0] + margin[0], - .ymin = -size[1] + margin[1], .ymax = size[1] - margin[1], - }; - ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin); - ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymax); - verts_len = 2; - if (is_solid) { - ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax); - ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymin); - verts_len += 2; - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINE_STRIP; - } - break; - } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X: - { - rctf r = { - .xmin = size[0] - margin[0], .xmax = size[0], - .ymin = -size[1] + margin[1], .ymax = size[1] - margin[1], - }; - ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymin); - ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax); - verts_len = 2; - if (is_solid) { - ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymax); - ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin); - verts_len += 2; - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINE_STRIP; - } - break; - } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y: - { - rctf r = { - .xmin = -size[0] + margin[0], .xmax = size[0] - margin[0], - .ymin = -size[1], .ymax = -size[1] + margin[1], - }; - ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin); - ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymin); - verts_len = 2; - if (is_solid) { - ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax); - ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymax); - verts_len += 2; - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINE_STRIP; - } - break; - } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y: - { - rctf r = { - .xmin = -size[0] + margin[0], .xmax = size[0] - margin[0], - .ymin = size[1] - margin[1], .ymax = size[1], - }; - ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymax); - ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax); - verts_len = 2; - if (is_solid) { - ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymin); - ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin); - verts_len += 2; - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINE_STRIP; - } - break; - } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y: - { - rctf r = { - .xmin = -size[0], .xmax = -size[0] + margin[0], - .ymin = -size[1], .ymax = -size[1] + margin[1], - }; - ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymin); - ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymax); - ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymax); - verts_len = 3; - if (is_solid) { - ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymin); - verts_len += 1; - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINE_STRIP; - } - break; - } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y: - { - rctf r = { - .xmin = -size[0], .xmax = -size[0] + margin[0], - .ymin = size[1] - margin[1], .ymax = size[1], - }; - ARRAY_SET_ITEMS(verts[0], r.xmax, r.ymax); - ARRAY_SET_ITEMS(verts[1], r.xmax, r.ymin); - ARRAY_SET_ITEMS(verts[2], r.xmin, r.ymin); - verts_len = 3; - if (is_solid) { - ARRAY_SET_ITEMS(verts[3], r.xmin, r.ymax); - verts_len += 1; - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINE_STRIP; - } - break; - } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y: - { - rctf r = { - .xmin = size[0] - margin[0], .xmax = size[0], - .ymin = -size[1], .ymax = -size[1] + margin[1], - }; - ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymin); - ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymax); - ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymax); - verts_len = 3; - if (is_solid) { - ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymin); - verts_len += 1; - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINE_STRIP; - } - break; - } - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y: - { - rctf r = { - .xmin = size[0] - margin[0], .xmax = size[0], - .ymin = size[1] - margin[1], .ymax = size[1], - }; - ARRAY_SET_ITEMS(verts[0], r.xmin, r.ymax); - ARRAY_SET_ITEMS(verts[1], r.xmin, r.ymin); - ARRAY_SET_ITEMS(verts[2], r.xmax, r.ymin); - verts_len = 3; - if (is_solid) { - ARRAY_SET_ITEMS(verts[3], r.xmax, r.ymax); - verts_len += 1; - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINE_STRIP; - } - break; - } - case ED_MANIPULATOR_CAGE2D_PART_ROTATE: - { - const float rotate_pt[2] = {0.0f, size[1] + margin[1]}; - const rctf r_rotate = { - .xmin = rotate_pt[0] - margin[0] / 2.0f, - .xmax = rotate_pt[0] + margin[0] / 2.0f, - .ymin = rotate_pt[1] - margin[1] / 2.0f, - .ymax = rotate_pt[1] + margin[1] / 2.0f, - }; - - ARRAY_SET_ITEMS(verts[0], r_rotate.xmin, r_rotate.ymin); - ARRAY_SET_ITEMS(verts[1], r_rotate.xmin, r_rotate.ymax); - ARRAY_SET_ITEMS(verts[2], r_rotate.xmax, r_rotate.ymax); - ARRAY_SET_ITEMS(verts[3], r_rotate.xmax, r_rotate.ymin); - verts_len = 4; - if (is_solid) { - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINE_STRIP; - } - break; - } - - case ED_MANIPULATOR_CAGE2D_PART_TRANSLATE: - if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { - ARRAY_SET_ITEMS(verts[0], -margin[0] / 2, -margin[1] / 2); - ARRAY_SET_ITEMS(verts[1], margin[0] / 2, margin[1] / 2); - ARRAY_SET_ITEMS(verts[2], -margin[0] / 2, margin[1] / 2); - ARRAY_SET_ITEMS(verts[3], margin[0] / 2, -margin[1] / 2); - verts_len = 4; - if (is_solid) { - prim_type = GWN_PRIM_TRI_FAN; - } - else { - prim_type = GWN_PRIM_LINES; - } - } - else { - /* Only used for 3D view selection, never displayed to the user. */ - ARRAY_SET_ITEMS(verts[0], -size[0], -size[1]); - ARRAY_SET_ITEMS(verts[1], -size[0], size[1]); - ARRAY_SET_ITEMS(verts[2], size[0], size[1]); - ARRAY_SET_ITEMS(verts[3], size[0], -size[1]); - verts_len = 4; - if (is_solid) { - prim_type = GWN_PRIM_TRI_FAN; - } - else { - /* unreachable */ - BLI_assert(0); - prim_type = GWN_PRIM_LINE_STRIP; - } - } - break; - default: - return; - } - - BLI_assert(prim_type != GWN_PRIM_NONE); - - Gwn_VertFormat *format = immVertexFormat(); - struct { - uint pos, col; - } attr_id = { - .pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT), - .col = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT), - }; - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - - { - if (is_solid) { - BLI_assert(ELEM(prim_type, GWN_PRIM_TRI_FAN)); - immBegin(prim_type, verts_len); - immAttrib3f(attr_id.col, 0.0f, 0.0f, 0.0f); - for (uint i = 0; i < verts_len; i++) { - immVertex2fv(attr_id.pos, verts[i]); - } - immEnd(); - } - else { - BLI_assert(ELEM(prim_type, GWN_PRIM_LINE_STRIP, GWN_PRIM_LINES)); - GPU_line_width(line_width + 3.0f); - - immBegin(prim_type, verts_len); - immAttrib3f(attr_id.col, 0.0f, 0.0f, 0.0f); - for (uint i = 0; i < verts_len; i++) { - immVertex2fv(attr_id.pos, verts[i]); - } - immEnd(); - - GPU_line_width(line_width); - - immBegin(prim_type, verts_len); - immAttrib3fv(attr_id.col, color); - for (uint i = 0; i < verts_len; i++) { - immVertex2fv(attr_id.pos, verts[i]); - } - immEnd(); - } - } - - immUnbindProgram(); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Circle Draw Style - * - * Useful for 2D views, see: #ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE - * \{ */ - -static void imm_draw_point_aspect_2d( - uint pos, float x, float y, float rad_x, float rad_y, bool solid) -{ - immBegin(solid ? GWN_PRIM_TRI_FAN : GWN_PRIM_LINE_LOOP, 4); - immVertex2f(pos, x - rad_x, y - rad_y); - immVertex2f(pos, x - rad_x, y + rad_y); - immVertex2f(pos, x + rad_x, y + rad_y); - immVertex2f(pos, x + rad_x, y - rad_y); - immEnd(); -} - -static void cage2d_draw_circle_wire( - const rctf *r, const float margin[2], const float color[3], - const int transform_flag, const int draw_options) -{ - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor3fv(color); - - immBegin(GWN_PRIM_LINE_LOOP, 4); - immVertex2f(pos, r->xmin, r->ymin); - immVertex2f(pos, r->xmax, r->ymin); - immVertex2f(pos, r->xmax, r->ymax); - immVertex2f(pos, r->xmin, r->ymax); - immEnd(); - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { - immBegin(GWN_PRIM_LINE_LOOP, 2); - immVertex2f(pos, BLI_rctf_cent_x(r), r->ymax); - immVertex2f(pos, BLI_rctf_cent_x(r), r->ymax + margin[1]); - immEnd(); - } - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { - if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { - const float rad[2] = {margin[0] / 2, margin[1] / 2}; - const float center[2] = {BLI_rctf_cent_x(r), BLI_rctf_cent_y(r)}; - - immBegin(GWN_PRIM_LINES, 4); - immVertex2f(pos, center[0] - rad[0], center[1] - rad[1]); - immVertex2f(pos, center[0] + rad[0], center[1] + rad[1]); - immVertex2f(pos, center[0] + rad[0], center[1] - rad[1]); - immVertex2f(pos, center[0] - rad[0], center[1] + rad[1]); - immEnd(); - } - } - - immUnbindProgram(); -} - -static void cage2d_draw_circle_handles( - const rctf *r, const float margin[2], const float color[3], - const int transform_flag, - bool solid) -{ - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - void (*circle_fn)(uint, float, float, float, float, int) = - (solid) ? imm_draw_circle_fill_aspect_2d : imm_draw_circle_wire_aspect_2d; - const int resolu = 12; - const float rad[2] = {margin[0] / 3, margin[1] / 3}; - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor3fv(color); - - /* should really divide by two, but looks too bulky. */ - { - imm_draw_point_aspect_2d(pos, r->xmin, r->ymin, rad[0], rad[1], solid); - imm_draw_point_aspect_2d(pos, r->xmax, r->ymin, rad[0], rad[1], solid); - imm_draw_point_aspect_2d(pos, r->xmax, r->ymax, rad[0], rad[1], solid); - imm_draw_point_aspect_2d(pos, r->xmin, r->ymax, rad[0], rad[1], solid); - } - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { - const float handle[2] = {BLI_rctf_cent_x(r), r->ymax + (margin[1] * MANIPULATOR_MARGIN_OFFSET_SCALE)}; - circle_fn(pos, handle[0], handle[1], rad[0], rad[1], resolu); - } - - immUnbindProgram(); -} - -/** \} */ - -static void manipulator_cage2d_draw_intern( - wmManipulator *mpr, const bool select, const bool highlight, const int select_id) -{ - // const bool use_clamp = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) == 0; - float dims[2]; - RNA_float_get_array(mpr->ptr, "dimensions", dims); - float matrix_final[4][4]; - - const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); - const int draw_style = RNA_enum_get(mpr->ptr, "draw_style"); - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - - const float size_real[2] = {dims[0] / 2.0f, dims[1] / 2.0f}; - - WM_manipulator_calc_matrix_final(mpr, matrix_final); - - gpuPushMatrix(); - gpuMultMatrix(matrix_final); - - float margin[2]; - manipulator_calc_rect_view_margin(mpr, dims, margin); - - /* Handy for quick testing draw (if it's outside bounds). */ - if (false) { - GPU_blend(true); - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4fv((const float[4]){1, 1, 1, 0.5f}); - float s = 0.5f; - immRectf(pos, -s, -s, s, s); - immUnbindProgram(); - GPU_blend(false); - } - - if (select) { - /* expand for hotspot */ - const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2}; - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE) { - int scale_parts[] = { - ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y, - - ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y, - ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y, - }; - for (int i = 0; i < ARRAY_SIZE(scale_parts); i++) { - GPU_select_load_id(select_id | scale_parts[i]); - cage2d_draw_box_interaction( - mpr->color, scale_parts[i], size, margin, mpr->line_width, true, draw_options); - } - } - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { - const int transform_part = ED_MANIPULATOR_CAGE2D_PART_TRANSLATE; - GPU_select_load_id(select_id | transform_part); - cage2d_draw_box_interaction( - mpr->color, transform_part, size, margin, mpr->line_width, true, draw_options); - } - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { - cage2d_draw_box_interaction( - mpr->color, ED_MANIPULATOR_CAGE2D_PART_ROTATE, size_real, margin, mpr->line_width, true, draw_options); - } - } - else { - const rctf r = { - .xmin = -size_real[0], - .ymin = -size_real[1], - .xmax = size_real[0], - .ymax = size_real[1], - }; - if (draw_style == ED_MANIPULATOR_CAGE2D_STYLE_BOX) { - /* corner manipulators */ - GPU_line_width(mpr->line_width + 3.0f); - cage2d_draw_box_corners(&r, margin, (const float[3]){0, 0, 0}); - - /* corner manipulators */ - float color[4]; - manipulator_color_get(mpr, highlight, color); - GPU_line_width(mpr->line_width); - cage2d_draw_box_corners(&r, margin, color); - - bool show = false; - if (mpr->highlight_part == ED_MANIPULATOR_CAGE2D_PART_TRANSLATE) { - /* Only show if we're drawing the center handle - * otherwise the entire rectangle is the hotspot. */ - if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { - show = true; - } - } - else { - show = true; - } - - if (show) { - cage2d_draw_box_interaction( - mpr->color, mpr->highlight_part, size_real, margin, mpr->line_width, false, draw_options); - } - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { - cage2d_draw_box_interaction( - mpr->color, ED_MANIPULATOR_CAGE2D_PART_ROTATE, size_real, margin, mpr->line_width, false, draw_options); - } - } - else if (draw_style == ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE) { - float color[4]; - manipulator_color_get(mpr, highlight, color); - - GPU_line_smooth(true); - GPU_blend(true); - - GPU_line_width(mpr->line_width + 3.0f); - cage2d_draw_circle_wire(&r, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options); - GPU_line_width(mpr->line_width); - cage2d_draw_circle_wire(&r, margin, color, transform_flag, draw_options); - - - /* corner manipulators */ - cage2d_draw_circle_handles(&r, margin, color, transform_flag, true); - cage2d_draw_circle_handles(&r, margin, (const float[3]){0, 0, 0}, transform_flag, false); - - GPU_blend(false); - GPU_line_smooth(false); - } - else { - BLI_assert(0); - } - } - - GPU_line_width(1.0); - gpuPopMatrix(); -} - -/** - * For when we want to draw 2d cage in 3d views. - */ -static void manipulator_cage2d_draw_select(const bContext *UNUSED(C), wmManipulator *mpr, int select_id) -{ - manipulator_cage2d_draw_intern(mpr, true, false, select_id); -} - -static void manipulator_cage2d_draw(const bContext *UNUSED(C), wmManipulator *mpr) -{ - const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; - manipulator_cage2d_draw_intern(mpr, false, is_highlight, -1); -} - -static int manipulator_cage2d_get_cursor(wmManipulator *mpr) -{ - int highlight_part = mpr->highlight_part; - - if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { - return BC_NSEW_SCROLLCURSOR; - } - - switch (highlight_part) { - case ED_MANIPULATOR_CAGE2D_PART_TRANSLATE: - return BC_NSEW_SCROLLCURSOR; - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X: - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X: - return CURSOR_X_MOVE; - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y: - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y: - return CURSOR_Y_MOVE; - - /* TODO diagonal cursor */ - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y: - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y: - return BC_NSEW_SCROLLCURSOR; - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y: - case ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y: - return BC_NSEW_SCROLLCURSOR; - case ED_MANIPULATOR_CAGE2D_PART_ROTATE: - return BC_CROSSCURSOR; - default: - return CURSOR_STD; - } -} - -static int manipulator_cage2d_test_select( - bContext *C, wmManipulator *mpr, const wmEvent *event) -{ - float point_local[2]; - float dims[2]; - RNA_float_get_array(mpr->ptr, "dimensions", dims); - const float size_real[2] = {dims[0] / 2.0f, dims[1] / 2.0f}; - - if (manipulator_window_project_2d( - C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false) - { - return -1; - } - - float margin[2]; - manipulator_calc_rect_view_margin(mpr, dims, margin); - /* expand for hotspot */ - const float size[2] = {size_real[0] + margin[0] / 2, size_real[1] + margin[1] / 2}; - - const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { - rctf r; - if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { - r.xmin = -margin[0] / 2; - r.ymin = -margin[1] / 2; - r.xmax = margin[0] / 2; - r.ymax = margin[1] / 2; - } - else { - r.xmin = -size[0] + margin[0]; - r.ymin = -size[1] + margin[1]; - r.xmax = size[0] - margin[0]; - r.ymax = size[1] - margin[1]; - }; - bool isect = BLI_rctf_isect_pt_v(&r, point_local); - if (isect) { - return ED_MANIPULATOR_CAGE2D_PART_TRANSLATE; - } - } - - /* if manipulator does not have a scale intersection, don't do it */ - if (transform_flag & (ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM)) { - const rctf r_xmin = {.xmin = -size[0], .ymin = -size[1], .xmax = -size[0] + margin[0], .ymax = size[1]}; - const rctf r_xmax = {.xmin = size[0] - margin[0], .ymin = -size[1], .xmax = size[0], .ymax = size[1]}; - const rctf r_ymin = {.xmin = -size[0], .ymin = -size[1], .xmax = size[0], .ymax = -size[1] + margin[1]}; - const rctf r_ymax = {.xmin = -size[0], .ymin = size[1] - margin[1], .xmax = size[0], .ymax = size[1]}; - - if (BLI_rctf_isect_pt_v(&r_xmin, point_local)) { - if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) { - return ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y; - } - if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) { - return ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y; - } - return ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X; - } - if (BLI_rctf_isect_pt_v(&r_xmax, point_local)) { - if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) { - return ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y; - } - if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) { - return ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y; - } - return ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X; - } - if (BLI_rctf_isect_pt_v(&r_ymin, point_local)) { - return ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y; - } - if (BLI_rctf_isect_pt_v(&r_ymax, point_local)) { - return ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y; - } - } - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE) { - /* Rotate: - * (*) <-- hot spot is here! - * +---+ - * | | - * +---+ */ - const float r_rotate_pt[2] = {0.0f, size_real[1] + (margin[1] * MANIPULATOR_MARGIN_OFFSET_SCALE)}; - const rctf r_rotate = { - .xmin = r_rotate_pt[0] - margin[0] / 2.0f, - .xmax = r_rotate_pt[0] + margin[0] / 2.0f, - .ymin = r_rotate_pt[1] - margin[1] / 2.0f, - .ymax = r_rotate_pt[1] + margin[1] / 2.0f, - }; - - if (BLI_rctf_isect_pt_v(&r_rotate, point_local)) { - return ED_MANIPULATOR_CAGE2D_PART_ROTATE; - } - } - - return -1; -} - -typedef struct RectTransformInteraction { - float orig_mouse[2]; - float orig_matrix_offset[4][4]; - float orig_matrix_final_no_offset[4][4]; - Dial *dial; -} RectTransformInteraction; - -static void manipulator_cage2d_setup(wmManipulator *mpr) -{ - mpr->flag |= WM_MANIPULATOR_DRAW_MODAL | WM_MANIPULATOR_DRAW_NO_SCALE; -} - -static int manipulator_cage2d_invoke( - bContext *C, wmManipulator *mpr, const wmEvent *event) -{ - RectTransformInteraction *data = MEM_callocN(sizeof(RectTransformInteraction), "cage_interaction"); - - copy_m4_m4(data->orig_matrix_offset, mpr->matrix_offset); - WM_manipulator_calc_matrix_final_no_offset(mpr, data->orig_matrix_final_no_offset); - - if (manipulator_window_project_2d( - C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, false, data->orig_mouse) == 0) - { - zero_v2(data->orig_mouse); - } - - mpr->interaction_data = data; - - return OPERATOR_RUNNING_MODAL; -} - -static int manipulator_cage2d_modal( - bContext *C, wmManipulator *mpr, const wmEvent *event, - eWM_ManipulatorTweak UNUSED(tweak_flag)) -{ - /* For transform logic to be managable we operate in -0.5..0.5 2D space, - * no matter the size of the rectangle, mouse coorts are scaled to unit space. - * The mouse coords have been projected into the matrix so we don't need to worry about axis alignment. - * - * - The cursor offset are multiplied by 'dims'. - * - Matrix translation is also multiplied by 'dims'. - */ - RectTransformInteraction *data = mpr->interaction_data; - float point_local[2]; - - float dims[2]; - RNA_float_get_array(mpr->ptr, "dimensions", dims); - - { - float matrix_back[4][4]; - copy_m4_m4(matrix_back, mpr->matrix_offset); - copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); - - bool ok = manipulator_window_project_2d( - C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, false, point_local); - copy_m4_m4(mpr->matrix_offset, matrix_back); - if (!ok) { - return OPERATOR_RUNNING_MODAL; - } - } - - const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); - wmManipulatorProperty *mpr_prop; - - mpr_prop = WM_manipulator_target_property_find(mpr, "matrix"); - if (mpr_prop->type != NULL) { - WM_manipulator_target_property_value_get_array(mpr, mpr_prop, &mpr->matrix_offset[0][0]); - } - - if (mpr->highlight_part == ED_MANIPULATOR_CAGE2D_PART_TRANSLATE) { - /* do this to prevent clamping from changing size */ - copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); - mpr->matrix_offset[3][0] = data->orig_matrix_offset[3][0] + (point_local[0] - data->orig_mouse[0]); - mpr->matrix_offset[3][1] = data->orig_matrix_offset[3][1] + (point_local[1] - data->orig_mouse[1]); - } - else if (mpr->highlight_part == ED_MANIPULATOR_CAGE2D_PART_ROTATE) { - -#define MUL_V2_V3_M4_FINAL(test_co, mouse_co) \ - mul_v3_m4v3(test_co, data->orig_matrix_final_no_offset, ((const float[3]){UNPACK2(mouse_co), 0.0})) - - float test_co[3]; - - if (data->dial == NULL) { - MUL_V2_V3_M4_FINAL(test_co, data->orig_matrix_offset[3]); - - data->dial = BLI_dial_initialize(test_co, FLT_EPSILON); - - MUL_V2_V3_M4_FINAL(test_co, data->orig_mouse); - BLI_dial_angle(data->dial, test_co); - } - - /* rotate */ - MUL_V2_V3_M4_FINAL(test_co, point_local); - const float angle = BLI_dial_angle(data->dial, test_co); - - float matrix_space_inv[4][4]; - float matrix_rotate[4][4]; - float pivot[3]; - - copy_v3_v3(pivot, data->orig_matrix_offset[3]); - - invert_m4_m4(matrix_space_inv, mpr->matrix_space); - - unit_m4(matrix_rotate); - mul_m4_m4m4(matrix_rotate, matrix_rotate, matrix_space_inv); - rotate_m4(matrix_rotate, 'Z', -angle); - mul_m4_m4m4(matrix_rotate, matrix_rotate, mpr->matrix_space); - - zero_v3(matrix_rotate[3]); - transform_pivot_set_m4(matrix_rotate, pivot); - - mul_m4_m4m4(mpr->matrix_offset, matrix_rotate, data->orig_matrix_offset); - -#undef MUL_V2_V3_M4_FINAL - } - else { - /* scale */ - copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); - float pivot[2]; - bool constrain_axis[2] = {false}; - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { - manipulator_rect_pivot_from_scale_part(mpr->highlight_part, pivot, constrain_axis); - } - else { - zero_v2(pivot); - } - - /* Cursor deltas scaled to (-0.5..0.5). */ - float delta_orig[2], delta_curr[2]; - for (int i = 0; i < 2; i++) { - delta_orig[i] = ((data->orig_mouse[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i]; - delta_curr[i] = ((point_local[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i]; - } - - float scale[2] = {1.0f, 1.0f}; - for (int i = 0; i < 2; i++) { - if (constrain_axis[i] == false) { - if (delta_orig[i] < 0.0f) { - delta_orig[i] *= -1.0f; - delta_curr[i] *= -1.0f; - } - const int sign = signum_i(scale[i]); - - scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i])); - - if ((transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_SIGNED) == 0) { - if (sign != signum_i(scale[i])) { - scale[i] = 0.0f; - } - } - } - } - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM) { - if (constrain_axis[0] == false && constrain_axis[1] == false) { - scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f; - } - else if (constrain_axis[0] == false) { - scale[1] = scale[0]; - } - else if (constrain_axis[1] == false) { - scale[0] = scale[1]; - } - else { - BLI_assert(0); - } - } - - /* scale around pivot */ - float matrix_scale[4][4]; - unit_m4(matrix_scale); - - mul_v3_fl(matrix_scale[0], scale[0]); - mul_v3_fl(matrix_scale[1], scale[1]); - - transform_pivot_set_m4(matrix_scale, (const float[3]){pivot[0] * dims[0], pivot[1] * dims[1], 0.0f}); - mul_m4_m4m4(mpr->matrix_offset, data->orig_matrix_offset, matrix_scale); - } - - if (mpr_prop->type != NULL) { - WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, &mpr->matrix_offset[0][0]); - } - - /* tag the region for redraw */ - ED_region_tag_redraw(CTX_wm_region(C)); - WM_event_add_mousemove(C); - - return OPERATOR_RUNNING_MODAL; -} - -static void manipulator_cage2d_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop) -{ - if (STREQ(mpr_prop->type->idname, "matrix")) { - if (WM_manipulator_target_property_array_length(mpr, mpr_prop) == 16) { - WM_manipulator_target_property_value_get_array(mpr, mpr_prop, &mpr->matrix_offset[0][0]); - } - else { - BLI_assert(0); - } - } - else { - BLI_assert(0); - } -} - -static void manipulator_cage2d_exit(bContext *C, wmManipulator *mpr, const bool cancel) -{ - RectTransformInteraction *data = mpr->interaction_data; - - MEM_SAFE_FREE(data->dial); - - if (!cancel) - return; - - wmManipulatorProperty *mpr_prop; - - /* reset properties */ - mpr_prop = WM_manipulator_target_property_find(mpr, "matrix"); - if (mpr_prop->type != NULL) { - WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, &data->orig_matrix_offset[0][0]); - } - - copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); -} - - -/* -------------------------------------------------------------------- */ -/** \name Cage Manipulator API - * - * \{ */ - -static void MANIPULATOR_WT_cage_2d(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "MANIPULATOR_WT_cage_2d"; - - /* api callbacks */ - wt->draw = manipulator_cage2d_draw; - wt->draw_select = manipulator_cage2d_draw_select; - wt->test_select = manipulator_cage2d_test_select; - wt->setup = manipulator_cage2d_setup; - wt->invoke = manipulator_cage2d_invoke; - wt->property_update = manipulator_cage2d_property_update; - wt->modal = manipulator_cage2d_modal; - wt->exit = manipulator_cage2d_exit; - wt->cursor_get = manipulator_cage2d_get_cursor; - - wt->struct_size = sizeof(wmManipulator); - - /* rna */ - static EnumPropertyItem rna_enum_draw_style[] = { - {ED_MANIPULATOR_CAGE2D_STYLE_BOX, "BOX", 0, "Box", ""}, - {ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE, "CIRCLE", 0, "Circle", ""}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem rna_enum_transform[] = { - {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE, "TRANSLATE", 0, "Translate", ""}, - {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE, "ROTATE", 0, "Rotate", ""}, - {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE, "SCALE", 0, "Scale", ""}, - {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM, "SCALE_UNIFORM", 0, "Scale Uniform", ""}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem rna_enum_draw_options[] = { - {ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "XFORM_CENTER_HANDLE", 0, "Center Handle", ""}, - {0, NULL, 0, NULL, NULL} - }; - static float unit_v2[2] = {1.0f, 1.0f}; - RNA_def_float_vector(wt->srna, "dimensions", 2, unit_v2, 0, FLT_MAX, "Dimensions", "", 0.0f, FLT_MAX); - RNA_def_enum_flag(wt->srna, "transform", rna_enum_transform, 0, "Transform Options", ""); - RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE, "Draw Style", ""); - RNA_def_enum_flag( - wt->srna, "draw_options", rna_enum_draw_options, - ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "Draw Options", ""); - - WM_manipulatortype_target_property_def(wt, "matrix", PROP_FLOAT, 16); -} - -void ED_manipulatortypes_cage_2d(void) -{ - WM_manipulatortype_append(MANIPULATOR_WT_cage_2d); -} - -/** \} */ diff --git a/source/blender/editors/manipulator_library/manipulator_types/cage3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/cage3d_manipulator.c deleted file mode 100644 index a907816b08f..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_types/cage3d_manipulator.c +++ /dev/null @@ -1,692 +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 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file cage3d_manipulator.c - * \ingroup wm - * - * \name Cage Manipulator - * - * 2D Manipulator - * - * \brief Rectangular manipulator acting as a 'cage' around its content. - * Interacting scales or translates the manipulator. - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" -#include "BLI_rect.h" - -#include "BKE_context.h" - -#include "BIF_gl.h" - -#include "GPU_matrix.h" -#include "GPU_shader.h" -#include "GPU_immediate.h" -#include "GPU_immediate_util.h" -#include "GPU_select.h" -#include "GPU_state.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_screen.h" -#include "ED_view3d.h" -#include "ED_manipulator_library.h" - -/* own includes */ -#include "../manipulator_library_intern.h" - -#define MANIPULATOR_RESIZER_SIZE 10.0f -#define MANIPULATOR_MARGIN_OFFSET_SCALE 1.5f - -static void manipulator_calc_matrix_final_no_offset( - const wmManipulator *mpr, float orig_matrix_final_no_offset[4][4], bool use_space) -{ - float mat_identity[4][4]; - struct WM_ManipulatorMatrixParams params = {NULL}; - unit_m4(mat_identity); - if (use_space == false) { - params.matrix_basis = mat_identity; - } - params.matrix_offset = mat_identity; - WM_manipulator_calc_matrix_final_params(mpr, ¶ms, orig_matrix_final_no_offset); -} - -static void manipulator_calc_rect_view_scale( - const wmManipulator *mpr, const float dims[3], float scale[3]) -{ - UNUSED_VARS(dims); - - /* Unlike cage2d, no need to correct for aspect. */ - float matrix_final_no_offset[4][4]; - - float x_axis[3], y_axis[3], z_axis[3]; - manipulator_calc_matrix_final_no_offset(mpr, matrix_final_no_offset, false); - mul_v3_mat3_m4v3(x_axis, matrix_final_no_offset, mpr->matrix_offset[0]); - mul_v3_mat3_m4v3(y_axis, matrix_final_no_offset, mpr->matrix_offset[1]); - mul_v3_mat3_m4v3(z_axis, matrix_final_no_offset, mpr->matrix_offset[2]); - - scale[0] = 1.0f / len_v3(x_axis); - scale[1] = 1.0f / len_v3(y_axis); - scale[2] = 1.0f / len_v3(z_axis); -} - -static void manipulator_calc_rect_view_margin( - const wmManipulator *mpr, const float dims[3], float margin[3]) -{ - float handle_size; - if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { - handle_size = 0.15f; - } - else { - handle_size = MANIPULATOR_RESIZER_SIZE; - } - // XXX, the scale isn't taking offset into account, we need to calculate scale per handle! - // handle_size *= mpr->scale_final; - - float scale_xyz[3]; - manipulator_calc_rect_view_scale(mpr, dims, scale_xyz); - margin[0] = ((handle_size * scale_xyz[0])); - margin[1] = ((handle_size * scale_xyz[1])); - margin[2] = ((handle_size * scale_xyz[2])); -} - -/* -------------------------------------------------------------------- */ - -static void manipulator_rect_pivot_from_scale_part(int part, float r_pt[3], bool r_constrain_axis[3]) -{ - if (part >= ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z && - part <= ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z) - { - int index = (part - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z); - int range[3]; - range[2] = index % 3; - index = index / 3; - range[1] = index % 3; - index = index / 3; - range[0] = index % 3; - - const float sign[3] = {0.5f, 0.0f, -0.5f}; - for (int i = 0; i < 3; i++) { - r_pt[i] = sign[range[i]]; - r_constrain_axis[i] = (range[i] == 1); - } - } -} - -/* -------------------------------------------------------------------- */ -/** \name Box Draw Style - * - * Useful for 3D views, see: #ED_MANIPULATOR_CAGE2D_STYLE_BOX - * \{ */ - -static void cage3d_draw_box_corners( - const float r[3], const float margin[3], const float color[3]) -{ - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - UNUSED_VARS(margin); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformColor3fv(color); - - imm_draw_cube_wire_3d(pos, (float[3]){0}, r); - - immUnbindProgram(); -} - -static void cage3d_draw_box_interaction( - const float color[4], const int highlighted, - const float size[3], const float margin[3]) -{ - if (highlighted >= ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z && - highlighted <= ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z) - { - int index = (highlighted - ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z); - int range[3]; - range[2] = index % 3; - index = index / 3; - range[1] = index % 3; - index = index / 3; - range[0] = index % 3; - - const float sign[3] = {-1.0f, 0.0f, 1.0f}; - float co[3]; - - for (int i = 0; i < 3; i++) { - co[i] = size[i] * sign[range[i]]; - } - const float rad[3] = {margin[0] / 3, margin[1] / 3, margin[2] / 3}; - - { - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformColor3fv(color); - imm_draw_cube_fill_3d(pos, co, rad); - immUnbindProgram(); - } - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Circle Draw Style - * - * Useful for 2D views, see: #ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE - * \{ */ - -static void imm_draw_point_aspect_3d( - uint pos, const float co[3], const float rad[3], bool solid) -{ - if (solid) { - imm_draw_cube_fill_3d(pos, co, rad); - } - else { - imm_draw_cube_wire_3d(pos, co, rad); - } -} - -static void cage3d_draw_circle_wire( - const float r[3], const float margin[3], const float color[3], - const int transform_flag, const int draw_options) -{ - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformColor3fv(color); - - imm_draw_cube_wire_3d(pos, (float[3]){0}, r); - -#if 0 - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { - if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { - const float rad[2] = {margin[0] / 2, margin[1] / 2}; - const float center[2] = {0.0f, 0.0f}; - - immBegin(GWN_PRIM_LINES, 4); - immVertex2f(pos, center[0] - rad[0], center[1] - rad[1]); - immVertex2f(pos, center[0] + rad[0], center[1] + rad[1]); - immVertex2f(pos, center[0] + rad[0], center[1] - rad[1]); - immVertex2f(pos, center[0] - rad[0], center[1] + rad[1]); - immEnd(); - } - } -#else - UNUSED_VARS(margin, transform_flag, draw_options); -#endif - - - immUnbindProgram(); -} - -static void cage3d_draw_circle_handles( - const RegionView3D *rv3d, const float matrix_final[4][4], - const float r[3], const float margin[3], const float color[3], - bool solid, float scale) -{ - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - const float rad[3] = {margin[0] / 3, margin[1] / 3, margin[2] / 3}; - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformColor3fv(color); - - float sign[3] = {-1.0f, 0.0f, 1.0f}; - for (int x = 0; x < 3; x++) { - for (int y = 0; y < 3; y++) { - for (int z = 0; z < 3; z++) { - if (x == 1 && y == 1 && z == 1) { - continue; - } - const float co[3] = {r[0] * sign[x], r[1] * sign[y], r[2] * sign[z]}; - float co_test[3]; - mul_v3_m4v3(co_test, matrix_final, co); - float rad_scale[3]; - mul_v3_v3fl(rad_scale, rad, ED_view3d_pixel_size(rv3d, co_test) * scale); - imm_draw_point_aspect_3d(pos, co, rad_scale, solid); - } - } - } - - immUnbindProgram(); -} - -/** \} */ - -static void manipulator_cage3d_draw_intern( - RegionView3D *rv3d, - wmManipulator *mpr, const bool select, const bool highlight, const int select_id) -{ - // const bool use_clamp = (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) == 0; - float dims[3]; - RNA_float_get_array(mpr->ptr, "dimensions", dims); - float matrix_final[4][4]; - - const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); - const int draw_style = RNA_enum_get(mpr->ptr, "draw_style"); - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - - const float size_real[3] = {dims[0] / 2.0f, dims[1] / 2.0f, dims[2] / 2.0f}; - - WM_manipulator_calc_matrix_final(mpr, matrix_final); - - gpuPushMatrix(); - gpuMultMatrix(matrix_final); - - float margin[3]; - manipulator_calc_rect_view_margin(mpr, dims, margin); - - /* Handy for quick testing draw (if it's outside bounds). */ - if (false) { - GPU_blend(true); - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformColor4fv((const float[4]){1, 1, 1, 0.5f}); - float s = 0.5f; - immRectf(pos, -s, -s, s, s); - immUnbindProgram(); - GPU_blend(false); - } - - if (select) { - /* expand for hotspot */ -#if 0 - const float size[3] = { - size_real[0] + margin[0] / 2, - size_real[1] + margin[1] / 2, - size_real[2] + margin[2] / 2, - }; -#else - /* just use same value for now. */ - const float size[3] = {UNPACK3(size_real)}; -#endif - - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE) { - for (int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; - i <= ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z; - i++) - { - if (i == ED_MANIPULATOR_CAGE3D_PART_SCALE_MID_X_MID_Y_MID_Z) { - continue; - } - GPU_select_load_id(select_id | i); - cage3d_draw_box_interaction( - mpr->color, i, size, margin); - } - } - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { - const int transform_part = ED_MANIPULATOR_CAGE3D_PART_TRANSLATE; - GPU_select_load_id(select_id | transform_part); - cage3d_draw_box_interaction( - mpr->color, transform_part, size, margin); - } - } - else { -#if 0 - const rctf _r = { - .xmin = -size_real[0], - .ymin = -size_real[1], - .xmax = size_real[0], - .ymax = size_real[1], - }; -#endif - if (draw_style == ED_MANIPULATOR_CAGE2D_STYLE_BOX) { - /* corner manipulators */ - GPU_line_width(mpr->line_width + 3.0f); - cage3d_draw_box_corners(size_real, margin, (const float[3]){0, 0, 0}); - - /* corner manipulators */ - float color[4]; - manipulator_color_get(mpr, highlight, color); - GPU_line_width(mpr->line_width); - cage3d_draw_box_corners(size_real, margin, color); - - bool show = false; - if (mpr->highlight_part == ED_MANIPULATOR_CAGE3D_PART_TRANSLATE) { - /* Only show if we're drawing the center handle - * otherwise the entire rectangle is the hotspot. */ - if (draw_options & ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE) { - show = true; - } - } - else { - show = true; - } - - if (show) { - cage3d_draw_box_interaction( - mpr->color, mpr->highlight_part, size_real, margin); - } - } - else if (draw_style == ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE) { - float color[4]; - manipulator_color_get(mpr, highlight, color); - - GPU_line_smooth(true); - GPU_polygon_smooth(true); - GPU_blend(true); - - GPU_line_width(mpr->line_width + 3.0f); - cage3d_draw_circle_wire(size_real, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options); - GPU_line_width(mpr->line_width); - cage3d_draw_circle_wire(size_real, margin, color, transform_flag, draw_options); - - /* corner manipulators */ - cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, (const float[3]){0, 0, 0}, true, 60); - cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, color, true, 40); - - GPU_blend(false); - GPU_polygon_smooth(false); - GPU_line_smooth(false); - } - else { - BLI_assert(0); - } - } - - GPU_line_width(1.0); - gpuPopMatrix(); -} - -/** - * For when we want to draw 3d cage in 3d views. - */ -static void manipulator_cage3d_draw_select(const bContext *C, wmManipulator *mpr, int select_id) -{ - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - manipulator_cage3d_draw_intern(rv3d, mpr, true, false, select_id); -} - -static void manipulator_cage3d_draw(const bContext *C, wmManipulator *mpr) -{ - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; - manipulator_cage3d_draw_intern(rv3d, mpr, false, is_highlight, -1); -} - -static int manipulator_cage3d_get_cursor(wmManipulator *mpr) -{ - if (mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_3D) { - return BC_NSEW_SCROLLCURSOR; - } - - return CURSOR_STD; -} - -typedef struct RectTransformInteraction { - float orig_mouse[3]; - float orig_matrix_offset[4][4]; - float orig_matrix_final_no_offset[4][4]; -} RectTransformInteraction; - -static void manipulator_cage3d_setup(wmManipulator *mpr) -{ - mpr->flag |= /* WM_MANIPULATOR_DRAW_MODAL | */ /* TODO */ - WM_MANIPULATOR_DRAW_NO_SCALE; -} - -static int manipulator_cage3d_invoke( - bContext *C, wmManipulator *mpr, const wmEvent *event) -{ - RectTransformInteraction *data = MEM_callocN(sizeof(RectTransformInteraction), "cage_interaction"); - - copy_m4_m4(data->orig_matrix_offset, mpr->matrix_offset); - manipulator_calc_matrix_final_no_offset(mpr, data->orig_matrix_final_no_offset, true); - - if (manipulator_window_project_3d( - C, mpr, (const float[2]){UNPACK2(event->mval)}, false, data->orig_mouse) == 0) - { - zero_v3(data->orig_mouse); - } - - mpr->interaction_data = data; - - return OPERATOR_RUNNING_MODAL; -} - -static int manipulator_cage3d_modal( - bContext *C, wmManipulator *mpr, const wmEvent *event, - eWM_ManipulatorTweak UNUSED(tweak_flag)) -{ - /* For transform logic to be managable we operate in -0.5..0.5 2D space, - * no matter the size of the rectangle, mouse coorts are scaled to unit space. - * The mouse coords have been projected into the matrix so we don't need to worry about axis alignment. - * - * - The cursor offset are multiplied by 'dims'. - * - Matrix translation is also multiplied by 'dims'. - */ - RectTransformInteraction *data = mpr->interaction_data; - float point_local[3]; - - float dims[3]; - RNA_float_get_array(mpr->ptr, "dimensions", dims); - - { - float matrix_back[4][4]; - copy_m4_m4(matrix_back, mpr->matrix_offset); - copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); - - bool ok = manipulator_window_project_3d( - C, mpr, (const float[2]){UNPACK2(event->mval)}, false, point_local); - copy_m4_m4(mpr->matrix_offset, matrix_back); - if (!ok) { - return OPERATOR_RUNNING_MODAL; - } - } - - const int transform_flag = RNA_enum_get(mpr->ptr, "transform"); - wmManipulatorProperty *mpr_prop; - - mpr_prop = WM_manipulator_target_property_find(mpr, "matrix"); - if (mpr_prop->type != NULL) { - WM_manipulator_target_property_value_get_array(mpr, mpr_prop, &mpr->matrix_offset[0][0]); - } - - if (mpr->highlight_part == ED_MANIPULATOR_CAGE3D_PART_TRANSLATE) { - /* do this to prevent clamping from changing size */ - copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); - mpr->matrix_offset[3][0] = data->orig_matrix_offset[3][0] + (point_local[0] - data->orig_mouse[0]); - mpr->matrix_offset[3][1] = data->orig_matrix_offset[3][1] + (point_local[1] - data->orig_mouse[1]); - mpr->matrix_offset[3][2] = data->orig_matrix_offset[3][2] + (point_local[2] - data->orig_mouse[2]); - } - else if (mpr->highlight_part == ED_MANIPULATOR_CAGE3D_PART_ROTATE) { - /* TODO (if needed) */ - } - else { - /* scale */ - copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); - float pivot[3]; - bool constrain_axis[3] = {false}; - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE) { - manipulator_rect_pivot_from_scale_part(mpr->highlight_part, pivot, constrain_axis); - } - else { - zero_v3(pivot); - } - - /* Cursor deltas scaled to (-0.5..0.5). */ - float delta_orig[3], delta_curr[3]; - - for (int i = 0; i < 3; i++) { - delta_orig[i] = ((data->orig_mouse[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i]; - delta_curr[i] = ((point_local[i] - data->orig_matrix_offset[3][i]) / dims[i]) - pivot[i]; - } - - float scale[3] = {1.0f, 1.0f, 1.0f}; - for (int i = 0; i < 3; i++) { - if (constrain_axis[i] == false) { - if (delta_orig[i] < 0.0f) { - delta_orig[i] *= -1.0f; - delta_curr[i] *= -1.0f; - } - const int sign = signum_i(scale[i]); - - scale[i] = 1.0f + ((delta_curr[i] - delta_orig[i]) / len_v3(data->orig_matrix_offset[i])); - - if ((transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_SIGNED) == 0) { - if (sign != signum_i(scale[i])) { - scale[i] = 0.0f; - } - } - } - } - - if (transform_flag & ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM) { - if (constrain_axis[0] == false && constrain_axis[1] == false) { - scale[1] = scale[0] = (scale[1] + scale[0]) / 2.0f; - } - else if (constrain_axis[0] == false) { - scale[1] = scale[0]; - } - else if (constrain_axis[1] == false) { - scale[0] = scale[1]; - } - else { - BLI_assert(0); - } - } - - /* scale around pivot */ - float matrix_scale[4][4]; - unit_m4(matrix_scale); - - mul_v3_fl(matrix_scale[0], scale[0]); - mul_v3_fl(matrix_scale[1], scale[1]); - mul_v3_fl(matrix_scale[2], scale[2]); - - transform_pivot_set_m4( - matrix_scale, - (const float[3]){pivot[0] * dims[0], pivot[1] * dims[1], pivot[2] * dims[2]}); - mul_m4_m4m4(mpr->matrix_offset, data->orig_matrix_offset, matrix_scale); - } - - if (mpr_prop->type != NULL) { - WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, &mpr->matrix_offset[0][0]); - } - - /* tag the region for redraw */ - ED_region_tag_redraw(CTX_wm_region(C)); - WM_event_add_mousemove(C); - - return OPERATOR_RUNNING_MODAL; -} - -static void manipulator_cage3d_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop) -{ - if (STREQ(mpr_prop->type->idname, "matrix")) { - if (WM_manipulator_target_property_array_length(mpr, mpr_prop) == 16) { - WM_manipulator_target_property_value_get_array(mpr, mpr_prop, &mpr->matrix_offset[0][0]); - } - else { - BLI_assert(0); - } - } - else { - BLI_assert(0); - } -} - -static void manipulator_cage3d_exit(bContext *C, wmManipulator *mpr, const bool cancel) -{ - RectTransformInteraction *data = mpr->interaction_data; - - if (!cancel) - return; - - wmManipulatorProperty *mpr_prop; - - /* reset properties */ - mpr_prop = WM_manipulator_target_property_find(mpr, "matrix"); - if (mpr_prop->type != NULL) { - WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, &data->orig_matrix_offset[0][0]); - } - - copy_m4_m4(mpr->matrix_offset, data->orig_matrix_offset); -} - - -/* -------------------------------------------------------------------- */ -/** \name Cage Manipulator API - * - * \{ */ - -static void MANIPULATOR_WT_cage_3d(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "MANIPULATOR_WT_cage_3d"; - - /* api callbacks */ - wt->draw = manipulator_cage3d_draw; - wt->draw_select = manipulator_cage3d_draw_select; - wt->setup = manipulator_cage3d_setup; - wt->invoke = manipulator_cage3d_invoke; - wt->property_update = manipulator_cage3d_property_update; - wt->modal = manipulator_cage3d_modal; - wt->exit = manipulator_cage3d_exit; - wt->cursor_get = manipulator_cage3d_get_cursor; - - wt->struct_size = sizeof(wmManipulator); - - /* rna */ - static EnumPropertyItem rna_enum_draw_style[] = { - {ED_MANIPULATOR_CAGE2D_STYLE_BOX, "BOX", 0, "Box", ""}, - {ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE, "CIRCLE", 0, "Circle", ""}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem rna_enum_transform[] = { - {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE, "TRANSLATE", 0, "Translate", ""}, - {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE, "SCALE", 0, "Scale", ""}, - {ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM, "SCALE_UNIFORM", 0, "Scale Uniform", ""}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem rna_enum_draw_options[] = { - {ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "XFORM_CENTER_HANDLE", 0, "Center Handle", ""}, - {0, NULL, 0, NULL, NULL} - }; - static float unit_v3[3] = {1.0f, 1.0f, 1.0f}; - RNA_def_float_vector(wt->srna, "dimensions", 3, unit_v3, 0, FLT_MAX, "Dimensions", "", 0.0f, FLT_MAX); - RNA_def_enum_flag(wt->srna, "transform", rna_enum_transform, 0, "Transform Options", ""); - RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_CAGE2D_STYLE_CIRCLE, "Draw Style", ""); - RNA_def_enum_flag( - wt->srna, "draw_options", rna_enum_draw_options, - ED_MANIPULATOR_CAGE2D_DRAW_FLAG_XFORM_CENTER_HANDLE, "Draw Options", ""); - - WM_manipulatortype_target_property_def(wt, "matrix", PROP_FLOAT, 16); -} - -void ED_manipulatortypes_cage_3d(void) -{ - WM_manipulatortype_append(MANIPULATOR_WT_cage_3d); -} - -/** \} */ diff --git a/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c deleted file mode 100644 index 74ba8bd77a9..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_types/dial3d_manipulator.c +++ /dev/null @@ -1,487 +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 Blender Foundation. - * All rights reserved. - * - * Contributor(s): Blender Foundation - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file dial3d_manipulator.c - * \ingroup wm - * - * \name Dial Manipulator - * - * 3D Manipulator - * - * \brief Circle shaped manipulator for circular interaction. - * Currently no own handling, use with operator only. - * - * - `matrix[0]` is derived from Y and Z. - * - `matrix[1]` is 'up' when DialManipulator.use_start_y_axis is set. - * - `matrix[2]` is the axis the dial rotates around (all dials). - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.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_select.h" -#include "GPU_state.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_screen.h" -#include "ED_view3d.h" -#include "ED_manipulator_library.h" - -/* own includes */ -#include "../manipulator_geometry.h" -#include "../manipulator_library_intern.h" - -/* to use custom dials exported to geom_dial_manipulator.c */ -// #define USE_MANIPULATOR_CUSTOM_DIAL - -static int manipulator_dial_modal( - bContext *C, wmManipulator *mpr, const wmEvent *event, - eWM_ManipulatorTweak tweak_flag); - -typedef struct DialInteraction { - float init_mval[2]; - - /* only for when using properties */ - float init_prop_angle; - - /* cache the last angle to detect rotations bigger than -/+ PI */ - float last_angle; - /* number of full rotations */ - int rotations; - - /* final output values, used for drawing */ - struct { - float angle_ofs; - float angle_delta; - } output; -} DialInteraction; - -#define DIAL_WIDTH 1.0f -#define DIAL_RESOLUTION 48 - -/* Could make option, negative to clip more (don't show when view aligned). */ -#define DIAL_CLIP_BIAS 0.02 - -/** - * We can't use this for the #wmManipulatorType.matrix_basis_get callback, it conflicts with depth picking. - */ -static void dial_calc_matrix(const wmManipulator *mpr, float mat[4][4]) -{ - float rot[3][3]; - const float up[3] = {0.0f, 0.0f, 1.0f}; - - rotation_between_vecs_to_mat3(rot, up, mpr->matrix_basis[2]); - copy_m4_m3(mat, rot); - copy_v3_v3(mat[3], mpr->matrix_basis[3]); -} - -/* -------------------------------------------------------------------- */ - -static void dial_geom_draw( - const wmManipulator *mpr, const float color[4], const bool select, - float axis_modal_mat[4][4], float clip_plane[4]) -{ -#ifdef USE_MANIPULATOR_CUSTOM_DIAL - UNUSED_VARS(dial, col, axis_modal_mat, clip_plane); - wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_dial, select); -#else - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - const bool filled = (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL) != 0; - - GPU_line_width(mpr->line_width); - - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - if (clip_plane) { - immBindBuiltinProgram(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR); - float clip_plane_f[4] = {clip_plane[0], clip_plane[1], clip_plane[2], clip_plane[3]}; - immUniform4fv("ClipPlane", clip_plane_f); - immUniformMatrix4fv("ModelMatrix", axis_modal_mat); - } - else { - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - } - - immUniformColor4fv(color); - - if (filled) { - imm_draw_circle_fill_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION); - } - else { - imm_draw_circle_wire_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION); - } - - immUnbindProgram(); - - UNUSED_VARS(select); -#endif -} - -/** - * Draws a line from (0, 0, 0) to \a co_outer, at \a angle. - */ -static void dial_ghostarc_draw_helpline(const float angle, const float co_outer[3], const float color[4]) -{ - GPU_line_width(1.0f); - - gpuPushMatrix(); - gpuRotate3f(RAD2DEGF(angle), 0.0f, 0.0f, -1.0f); - - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - immUniformColor4fv(color); - - immBegin(GWN_PRIM_LINE_STRIP, 2); - immVertex3f(pos, 0.0f, 0.0f, 0.0f); - immVertex3fv(pos, co_outer); - immEnd(); - - immUnbindProgram(); - - gpuPopMatrix(); -} - -static void dial_ghostarc_draw( - const wmManipulator *mpr, const float angle_ofs, const float angle_delta, const float color[4]) -{ - const float width_inner = DIAL_WIDTH - mpr->line_width * 0.5f / U.manipulator_size; - - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - immUniformColor4fv(color); - imm_draw_disk_partial_fill_2d( - pos, 0, 0, 0.0, width_inner, DIAL_RESOLUTION, RAD2DEGF(angle_ofs), RAD2DEGF(angle_delta)); - immUnbindProgram(); -} - -static void dial_ghostarc_get_angles( - struct Depsgraph *depsgraph, - const wmManipulator *mpr, - const wmEvent *event, - const ARegion *ar, const View3D *v3d, - float mat[4][4], const float co_outer[3], - float *r_start, float *r_delta) -{ - DialInteraction *inter = mpr->interaction_data; - const RegionView3D *rv3d = ar->regiondata; - const float mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin}; - - /* we might need to invert the direction of the angles */ - float view_vec[3], axis_vec[3]; - ED_view3d_global_to_vector(rv3d, mpr->matrix_basis[3], view_vec); - normalize_v3_v3(axis_vec, mpr->matrix_basis[2]); - - float proj_outer_rel[3]; - mul_v3_project_m4_v3(proj_outer_rel, mat, co_outer); - sub_v3_v3(proj_outer_rel, mpr->matrix_basis[3]); - - float proj_mval_new_rel[3]; - float proj_mval_init_rel[3]; - float dial_plane[4]; - float ray_co[3], ray_no[3]; - float ray_lambda; - - plane_from_point_normal_v3(dial_plane, mpr->matrix_basis[3], axis_vec); - - if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, inter->init_mval, ray_co, ray_no, false) || - !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false)) - { - goto fail; - } - madd_v3_v3v3fl(proj_mval_init_rel, ray_co, ray_no, ray_lambda); - sub_v3_v3(proj_mval_init_rel, mpr->matrix_basis[3]); - - if (!ED_view3d_win_to_ray(depsgraph, ar, v3d, mval, ray_co, ray_no, false) || - !isect_ray_plane_v3(ray_co, ray_no, dial_plane, &ray_lambda, false)) - { - goto fail; - } - madd_v3_v3v3fl(proj_mval_new_rel, ray_co, ray_no, ray_lambda); - sub_v3_v3(proj_mval_new_rel, mpr->matrix_basis[3]); - - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - - /* Start direction from mouse or set by user */ - const float *proj_init_rel = - (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y) ? - mpr->matrix_basis[1] : proj_mval_init_rel; - - /* return angles */ - const float start = angle_wrap_rad(angle_signed_on_axis_v3v3_v3(proj_outer_rel, proj_init_rel, axis_vec)); - const float delta = angle_wrap_rad(angle_signed_on_axis_v3v3_v3(proj_mval_init_rel, proj_mval_new_rel, axis_vec)); - - /* Change of sign, we passed the 180 degree threshold. This means we need to add a turn - * to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2. - * Logic taken from BLI_dial_angle */ - if ((delta * inter->last_angle < 0.0f) && - (fabsf(inter->last_angle) > (float)M_PI_2)) - { - if (inter->last_angle < 0.0f) - inter->rotations--; - else - inter->rotations++; - } - inter->last_angle = delta; - - *r_start = start; - *r_delta = fmod(delta + 2.0f * (float)M_PI * inter->rotations, 2 * (float)M_PI); - return; - - /* If we can't project (unlikely). */ -fail: - *r_start = 0.0; - *r_delta = 0.0; -} - -static void dial_draw_intern( - const bContext *C, wmManipulator *mpr, - const bool select, const bool highlight, float clip_plane[4]) -{ - float matrix_basis_adjust[4][4]; - float matrix_final[4][4]; - float color[4]; - - BLI_assert(CTX_wm_area(C)->spacetype == SPACE_VIEW3D); - - manipulator_color_get(mpr, highlight, color); - - dial_calc_matrix(mpr, matrix_basis_adjust); - - WM_manipulator_calc_matrix_final_params( - mpr, &((struct WM_ManipulatorMatrixParams) { - .matrix_basis = (void *)matrix_basis_adjust, - }), matrix_final); - - gpuPushMatrix(); - gpuMultMatrix(matrix_final); - - /* draw rotation indicator arc first */ - if ((mpr->flag & WM_MANIPULATOR_DRAW_VALUE) && - (mpr->state & WM_MANIPULATOR_STATE_MODAL)) - { - const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f}; /* coordinate at which the arc drawing will be started */ - - DialInteraction *inter = mpr->interaction_data; - - /* XXX, View3D rotation manipulator doesn't call modal. */ - if (!WM_manipulator_target_property_is_valid_any(mpr)) { - wmWindow *win = CTX_wm_window(C); - manipulator_dial_modal((bContext *)C, mpr, win->eventstate, 0); - } - - float angle_ofs = inter->output.angle_ofs; - float angle_delta = inter->output.angle_delta; - - /* draw! */ - for (int i = 0; i < 2; i++) { - GPU_polygon_smooth(false); - dial_ghostarc_draw(mpr, angle_ofs, angle_delta, (const float[4]){0.8f, 0.8f, 0.8f, 0.4f}); - GPU_polygon_smooth(true); - - dial_ghostarc_draw_helpline(angle_ofs, co_outer, color); /* starting position */ - dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer, color); /* starting position + current value */ - - if (i == 0) { - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - if ((draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR) == 0) { - break; - } - } - - angle_ofs += (float)M_PI; - } - } - - /* draw actual dial manipulator */ - dial_geom_draw(mpr, color, select, matrix_basis_adjust, clip_plane); - - gpuPopMatrix(); -} - -static void manipulator_dial_draw_select(const bContext *C, wmManipulator *mpr, int select_id) -{ - float clip_plane_buf[4]; - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - float *clip_plane = (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP) ? clip_plane_buf : NULL; - - /* enable clipping if needed */ - if (clip_plane) { - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - - copy_v3_v3(clip_plane, rv3d->viewinv[2]); - clip_plane[3] = -dot_v3v3(rv3d->viewinv[2], mpr->matrix_basis[3]); - clip_plane[3] += DIAL_CLIP_BIAS * mpr->scale_final; - glEnable(GL_CLIP_DISTANCE0); - } - - GPU_select_load_id(select_id); - dial_draw_intern(C, mpr, true, false, clip_plane); - - if (clip_plane) { - glDisable(GL_CLIP_DISTANCE0); - } -} - -static void manipulator_dial_draw(const bContext *C, wmManipulator *mpr) -{ - const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL; - const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; - float clip_plane_buf[4]; - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - float *clip_plane = (!is_modal && (draw_options & ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP)) ? clip_plane_buf : NULL; - - /* enable clipping if needed */ - if (clip_plane) { - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - - copy_v3_v3(clip_plane, rv3d->viewinv[2]); - clip_plane[3] = -dot_v3v3(rv3d->viewinv[2], mpr->matrix_basis[3]); - clip_plane[3] += DIAL_CLIP_BIAS * mpr->scale_final; - - glEnable(GL_CLIP_DISTANCE0); - } - - GPU_blend(true); - dial_draw_intern(C, mpr, false, is_highlight, clip_plane); - GPU_blend(false); - - if (clip_plane) { - glDisable(GL_CLIP_DISTANCE0); - } -} - -static int manipulator_dial_modal( - bContext *C, wmManipulator *mpr, const wmEvent *event, - eWM_ManipulatorTweak UNUSED(tweak_flag)) -{ - const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f}; /* coordinate at which the arc drawing will be started */ - float angle_ofs, angle_delta; - - float matrix[4][4]; - - dial_calc_matrix(mpr, matrix); - - dial_ghostarc_get_angles( - CTX_data_depsgraph(C), - mpr, event, CTX_wm_region(C), CTX_wm_view3d(C), matrix, co_outer, &angle_ofs, &angle_delta); - - DialInteraction *inter = mpr->interaction_data; - - inter->output.angle_delta = angle_delta; - inter->output.angle_ofs = angle_ofs; - - /* set the property for the operator and call its modal function */ - wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); - if (WM_manipulator_target_property_is_valid(mpr_prop)) { - WM_manipulator_target_property_value_set(C, mpr, mpr_prop, inter->init_prop_angle + angle_delta); - } - return OPERATOR_RUNNING_MODAL; -} - - -static void manipulator_dial_setup(wmManipulator *mpr) -{ - const float dir_default[3] = {0.0f, 0.0f, 1.0f}; - - /* defaults */ - copy_v3_v3(mpr->matrix_basis[2], dir_default); -} - -static int manipulator_dial_invoke( - bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) -{ - DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__); - - inter->init_mval[0] = event->mval[0]; - inter->init_mval[1] = event->mval[1]; - - wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); - if (WM_manipulator_target_property_is_valid(mpr_prop)) { - inter->init_prop_angle = WM_manipulator_target_property_value_get(mpr, mpr_prop); - } - - mpr->interaction_data = inter; - - return OPERATOR_RUNNING_MODAL; -} - -/* -------------------------------------------------------------------- */ -/** \name Dial Manipulator API - * - * \{ */ - -static void MANIPULATOR_WT_dial_3d(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "MANIPULATOR_WT_dial_3d"; - - /* api callbacks */ - wt->draw = manipulator_dial_draw; - wt->draw_select = manipulator_dial_draw_select; - wt->setup = manipulator_dial_setup; - wt->invoke = manipulator_dial_invoke; - wt->modal = manipulator_dial_modal; - - wt->struct_size = sizeof(wmManipulator); - - /* rna */ - static EnumPropertyItem rna_enum_draw_options[] = { - {ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP, "CLIP", 0, "Clipped", ""}, - {ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""}, - {ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR, "ANGLE_MIRROR", 0, "Angle Mirror", ""}, - {ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y, "ANGLE_START_Y", 0, "Angle Start Y", ""}, - {0, NULL, 0, NULL, NULL} - }; - RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", ""); - - WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 1); -} - -void ED_manipulatortypes_dial_3d(void) -{ - WM_manipulatortype_append(MANIPULATOR_WT_dial_3d); -} - -/** \} */ diff --git a/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c deleted file mode 100644 index 458dc2fd1c8..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_types/grab3d_manipulator.c +++ /dev/null @@ -1,375 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file grab3d_manipulator.c - * \ingroup wm - * - * \name Grab Manipulator - * - * 3D Manipulator, also works in 2D views. - * - * \brief Simple manipulator to grab and translate. - * - * - `matrix[0]` is derived from Y and Z. - * - `matrix[1]` currently not used. - * - `matrix[2]` is the widget direction (for all manipulators). - * - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.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_select.h" -#include "GPU_state.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_screen.h" -#include "ED_view3d.h" -#include "ED_manipulator_library.h" - -/* own includes */ -#include "../manipulator_geometry.h" -#include "../manipulator_library_intern.h" - -typedef struct GrabManipulator3D { - wmManipulator manipulator; - /* Added to 'matrix_basis' when calculating the matrix. */ - float prop_co[3]; -} GrabManipulator3D; - -static void manipulator_grab_matrix_basis_get(const wmManipulator *mpr, float r_matrix[4][4]) -{ - GrabManipulator3D *grab = (GrabManipulator3D *)mpr; - - copy_m4_m4(r_matrix, grab->manipulator.matrix_basis); - add_v3_v3(r_matrix[3], grab->prop_co); -} - -static int manipulator_grab_modal( - bContext *C, wmManipulator *mpr, const wmEvent *event, - eWM_ManipulatorTweak tweak_flag); - -typedef struct GrabInteraction { - float init_mval[2]; - - /* only for when using properties */ - float init_prop_co[3]; - - float init_matrix_final[4][4]; -} GrabInteraction; - -#define DIAL_RESOLUTION 32 - -/* -------------------------------------------------------------------- */ - -static void grab_geom_draw( - const wmManipulator *mpr, const float color[4], const bool select, const int draw_options) -{ -#ifdef USE_MANIPULATOR_CUSTOM_DIAL - UNUSED_VARS(grab3d, col, axis_modal_mat); - wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_grab3d, select); -#else - const int draw_style = RNA_enum_get(mpr->ptr, "draw_style"); - const bool filled = (draw_options & ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL) != 0; - - GPU_line_width(mpr->line_width); - - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - immUniformColor4fv(color); - - if (draw_style == ED_MANIPULATOR_GRAB_STYLE_RING_2D) { - if (filled) { - imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION); - } - else { - imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION); - } - } - else if (draw_style == ED_MANIPULATOR_GRAB_STYLE_CROSS_2D) { - immBegin(GWN_PRIM_LINES, 4); - immVertex2f(pos, 1.0f, 1.0f); - immVertex2f(pos, -1.0f, -1.0f); - - immVertex2f(pos, -1.0f, 1.0f); - immVertex2f(pos, 1.0f, -1.0f); - immEnd(); - } - else { - BLI_assert(0); - } - - immUnbindProgram(); - - UNUSED_VARS(select); -#endif -} - -static void grab3d_get_translate( - const wmManipulator *mpr, const wmEvent *event, const ARegion *ar, - float co_delta[3]) -{ - GrabInteraction *inter = mpr->interaction_data; - const float mval_delta[2] = { - event->mval[0] - inter->init_mval[0], - event->mval[1] - inter->init_mval[1], - }; - - RegionView3D *rv3d = ar->regiondata; - float co_ref[3]; - mul_v3_mat3_m4v3(co_ref, mpr->matrix_space, inter->init_prop_co); - const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL); - - ED_view3d_win_to_delta(ar, mval_delta, co_delta, zfac); - - float matrix_space_inv[3][3]; - copy_m3_m4(matrix_space_inv, mpr->matrix_space); - invert_m3(matrix_space_inv); - mul_m3_v3(matrix_space_inv, co_delta); -} - -static void grab3d_draw_intern( - const bContext *C, wmManipulator *mpr, - const bool select, const bool highlight) -{ - GrabInteraction *inter = mpr->interaction_data; - const int draw_options = RNA_enum_get(mpr->ptr, "draw_options"); - const bool align_view = (draw_options & ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW) != 0; - float color[4]; - float matrix_final[4][4]; - float matrix_align[4][4]; - - manipulator_color_get(mpr, highlight, color); - WM_manipulator_calc_matrix_final(mpr, matrix_final); - - gpuPushMatrix(); - gpuMultMatrix(matrix_final); - - if (align_view) { - float matrix_final_unit[4][4]; - RegionView3D *rv3d = CTX_wm_region_view3d(C); - normalize_m4_m4(matrix_final_unit, matrix_final); - mul_m4_m4m4(matrix_align, rv3d->viewmat, matrix_final_unit); - zero_v3(matrix_align[3]); - transpose_m4(matrix_align); - gpuMultMatrix(matrix_align); - } - - GPU_blend(true); - grab_geom_draw(mpr, color, select, draw_options); - GPU_blend(false); - gpuPopMatrix(); - - if (mpr->interaction_data) { - gpuPushMatrix(); - gpuMultMatrix(inter->init_matrix_final); - - if (align_view) { - gpuMultMatrix(matrix_align); - } - - GPU_blend(true); - grab_geom_draw(mpr, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}, select, draw_options); - GPU_blend(false); - gpuPopMatrix(); - } -} - -static void manipulator_grab_draw_select(const bContext *C, wmManipulator *mpr, int select_id) -{ - GPU_select_load_id(select_id); - grab3d_draw_intern(C, mpr, true, false); -} - -static void manipulator_grab_draw(const bContext *C, wmManipulator *mpr) -{ - const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL; - const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; - - (void)is_modal; - - GPU_blend(true); - grab3d_draw_intern(C, mpr, false, is_highlight); - GPU_blend(false); -} - -static int manipulator_grab_modal( - bContext *C, wmManipulator *mpr, const wmEvent *event, - eWM_ManipulatorTweak UNUSED(tweak_flag)) -{ - GrabManipulator3D *grab = (GrabManipulator3D *)mpr; - GrabInteraction *inter = mpr->interaction_data; - ARegion *ar = CTX_wm_region(C); - - float prop_delta[3]; - if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D) { - grab3d_get_translate(mpr, event, ar, prop_delta); - } - else { - float mval_proj_init[2], mval_proj_curr[2]; - if ((manipulator_window_project_2d( - C, mpr, inter->init_mval, 2, false, mval_proj_init) == false) || - (manipulator_window_project_2d( - C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, false, mval_proj_curr) == false)) - { - return OPERATOR_RUNNING_MODAL; - } - sub_v2_v2v2(prop_delta, mval_proj_curr, mval_proj_init); - prop_delta[2] = 0.0f; - } - add_v3_v3v3(grab->prop_co, inter->init_prop_co, prop_delta); - - /* set the property for the operator and call its modal function */ - wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); - if (WM_manipulator_target_property_is_valid(mpr_prop)) { - WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, grab->prop_co); - } - else { - zero_v3(grab->prop_co); - } - - ED_region_tag_redraw(ar); - - return OPERATOR_RUNNING_MODAL; -} - -static int manipulator_grab_invoke( - bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) -{ - GrabInteraction *inter = MEM_callocN(sizeof(GrabInteraction), __func__); - - inter->init_mval[0] = event->mval[0]; - inter->init_mval[1] = event->mval[1]; - -#if 0 - copy_v3_v3(inter->init_prop_co, grab->prop_co); -#else - wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset"); - if (WM_manipulator_target_property_is_valid(mpr_prop)) { - WM_manipulator_target_property_value_get_array(mpr, mpr_prop, inter->init_prop_co); - } -#endif - - WM_manipulator_calc_matrix_final(mpr, inter->init_matrix_final); - - mpr->interaction_data = inter; - - return OPERATOR_RUNNING_MODAL; -} - - -static int manipulator_grab_test_select( - bContext *C, wmManipulator *mpr, const wmEvent *event) -{ - float point_local[2]; - - if (manipulator_window_project_2d( - C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false) - { - return -1; - } - - /* The 'mpr->scale_final' is already applied when projecting. */ - if (len_squared_v2(point_local) < 1.0f) { - return 0; - } - - return -1; -} - -static void manipulator_grab_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop) -{ - GrabManipulator3D *grab = (GrabManipulator3D *)mpr; - if (WM_manipulator_target_property_is_valid(mpr_prop)) { - WM_manipulator_target_property_value_get_array(mpr, mpr_prop, grab->prop_co); - } - else { - zero_v3(grab->prop_co); - } -} - -static int manipulator_grab_cursor_get(wmManipulator *UNUSED(mpr)) -{ - return BC_NSEW_SCROLLCURSOR; -} - -/* -------------------------------------------------------------------- */ -/** \name Grab Manipulator API - * - * \{ */ - -static void MANIPULATOR_WT_grab_3d(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "MANIPULATOR_WT_grab_3d"; - - /* api callbacks */ - wt->draw = manipulator_grab_draw; - wt->draw_select = manipulator_grab_draw_select; - wt->test_select = manipulator_grab_test_select; - wt->matrix_basis_get = manipulator_grab_matrix_basis_get; - wt->invoke = manipulator_grab_invoke; - wt->property_update = manipulator_grab_property_update; - wt->modal = manipulator_grab_modal; - wt->cursor_get = manipulator_grab_cursor_get; - - wt->struct_size = sizeof(GrabManipulator3D); - - /* rna */ - static EnumPropertyItem rna_enum_draw_style[] = { - {ED_MANIPULATOR_GRAB_STYLE_RING_2D, "RING_2D", 0, "Ring", ""}, - {ED_MANIPULATOR_GRAB_STYLE_CROSS_2D, "CROSS_2D", 0, "Ring", ""}, - {0, NULL, 0, NULL, NULL} - }; - static EnumPropertyItem rna_enum_draw_options[] = { - {ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""}, - {ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW, "ALIGN_VIEW", 0, "Align View", ""}, - {0, NULL, 0, NULL, NULL} - }; - - RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_GRAB_STYLE_RING_2D, "Draw Style", ""); - RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", ""); - - WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 3); -} - -void ED_manipulatortypes_grab_3d(void) -{ - WM_manipulatortype_append(MANIPULATOR_WT_grab_3d); -} - -/** \} */ // Grab Manipulator API diff --git a/source/blender/editors/manipulator_library/manipulator_types/primitive3d_manipulator.c b/source/blender/editors/manipulator_library/manipulator_types/primitive3d_manipulator.c deleted file mode 100644 index 419873ccfff..00000000000 --- a/source/blender/editors/manipulator_library/manipulator_types/primitive3d_manipulator.c +++ /dev/null @@ -1,191 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file primitive3d_manipulator.c - * \ingroup wm - * - * \name Primitive Manipulator - * - * 3D Manipulator - * - * \brief Manipulator with primitive drawing type (plane, cube, etc.). - * Currently only plane primitive supported without own handling, use with operator only. - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" - -#include "DNA_view3d_types.h" - -#include "BKE_context.h" - -#include "BIF_gl.h" - -#include "GPU_immediate.h" -#include "GPU_matrix.h" -#include "GPU_select.h" -#include "GPU_state.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_manipulator_library.h" - -/* own includes */ -#include "../manipulator_library_intern.h" - -static float verts_plane[4][3] = { - {-1, -1, 0}, - { 1, -1, 0}, - { 1, 1, 0}, - {-1, 1, 0}, -}; - - -/* -------------------------------------------------------------------- */ - -static void manipulator_primitive_draw_geom( - const float col_inner[4], const float col_outer[4], const int draw_style) -{ - float (*verts)[3]; - uint vert_count = 0; - - if (draw_style == ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE) { - verts = verts_plane; - vert_count = ARRAY_SIZE(verts_plane); - } - - if (vert_count > 0) { - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - wm_manipulator_vec_draw(col_inner, verts, vert_count, pos, GWN_PRIM_TRI_FAN); - wm_manipulator_vec_draw(col_outer, verts, vert_count, pos, GWN_PRIM_LINE_LOOP); - immUnbindProgram(); - } -} - -static void manipulator_primitive_draw_intern( - wmManipulator *mpr, const bool UNUSED(select), - const bool highlight) -{ - float color_inner[4], color_outer[4]; - float matrix_final[4][4]; - const int draw_style = RNA_enum_get(mpr->ptr, "draw_style"); - - manipulator_color_get(mpr, highlight, color_outer); - copy_v4_v4(color_inner, color_outer); - color_inner[3] *= 0.5f; - - WM_manipulator_calc_matrix_final(mpr, matrix_final); - - gpuPushMatrix(); - gpuMultMatrix(matrix_final); - - GPU_blend(true); - manipulator_primitive_draw_geom(color_inner, color_outer, draw_style); - GPU_blend(false); - - gpuPopMatrix(); - - if (mpr->interaction_data) { - ManipulatorInteraction *inter = mpr->interaction_data; - - copy_v4_fl(color_inner, 0.5f); - copy_v3_fl(color_outer, 0.5f); - color_outer[3] = 0.8f; - - gpuPushMatrix(); - gpuMultMatrix(inter->init_matrix_final); - - GPU_blend(true); - manipulator_primitive_draw_geom(color_inner, color_outer, draw_style); - GPU_blend(false); - - gpuPopMatrix(); - } -} - -static void manipulator_primitive_draw_select( - const bContext *UNUSED(C), wmManipulator *mpr, - int select_id) -{ - GPU_select_load_id(select_id); - manipulator_primitive_draw_intern(mpr, true, false); -} - -static void manipulator_primitive_draw(const bContext *UNUSED(C), wmManipulator *mpr) -{ - manipulator_primitive_draw_intern( - mpr, false, - (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT)); -} - -static void manipulator_primitive_setup(wmManipulator *mpr) -{ - mpr->flag |= WM_MANIPULATOR_DRAW_MODAL; -} - -static int manipulator_primitive_invoke( - bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *UNUSED(event)) -{ - ManipulatorInteraction *inter = MEM_callocN(sizeof(ManipulatorInteraction), __func__); - - WM_manipulator_calc_matrix_final(mpr, inter->init_matrix_final); - - mpr->interaction_data = inter; - - return OPERATOR_RUNNING_MODAL; -} - -/* -------------------------------------------------------------------- */ -/** \name Primitive Manipulator API - * - * \{ */ - -static void MANIPULATOR_WT_primitive_3d(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "MANIPULATOR_WT_primitive_3d"; - - /* api callbacks */ - wt->draw = manipulator_primitive_draw; - wt->draw_select = manipulator_primitive_draw_select; - wt->setup = manipulator_primitive_setup; - wt->invoke = manipulator_primitive_invoke; - - wt->struct_size = sizeof(wmManipulator); - - static EnumPropertyItem rna_enum_draw_style[] = { - {ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE, "PLANE", 0, "Plane", ""}, - {0, NULL, 0, NULL, NULL} - }; - RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE, "Draw Style", ""); -} - -void ED_manipulatortypes_primitive_3d(void) -{ - WM_manipulatortype_append(MANIPULATOR_WT_primitive_3d); -} - -/** \} */ diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 5cd768b4fe3..81ec591fc89 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -44,7 +44,7 @@ set(INC_SYS set(SRC editface.c editmesh_add.c - editmesh_add_manipulator.c + editmesh_add_gizmo.c editmesh_bevel.c editmesh_bisect.c editmesh_extrude.c diff --git a/source/blender/editors/mesh/editmesh_add_gizmo.c b/source/blender/editors/mesh/editmesh_add_gizmo.c new file mode 100644 index 00000000000..3918d8847a6 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_add_gizmo.c @@ -0,0 +1,426 @@ +/* + * ***** 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/mesh/editmesh_add_gizmo.c + * \ingroup edmesh + * + * Creation manipulators. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_context.h" +#include "BKE_editmesh.h" + +#include "ED_gizmo_library.h" +#include "ED_mesh.h" +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_undo.h" +#include "ED_view3d.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_resources.h" + +#include "BLT_translation.h" + +#include "mesh_intern.h" /* own include */ + +/* -------------------------------------------------------------------- */ +/** \name Helper Functions + * \{ */ + +/** + * When we place a shape, pick a plane. + * + * We may base this choice on context, + * for now pick the "ground" based on the 3D cursor's dominant plane pointing down relative to the view. + */ +static void calc_initial_placement_point_from_view( + bContext *C, const float mval[2], + float r_location[3], float r_rotation[3][3]) +{ + + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + bool use_mouse_project = true; /* TODO: make optional */ + + float cursor_matrix[4][4]; + float orient_matrix[3][3]; + ED_view3d_cursor3d_calc_mat4(scene, v3d, cursor_matrix); + + float dots[3] = { + dot_v3v3(rv3d->viewinv[2], cursor_matrix[0]), + dot_v3v3(rv3d->viewinv[2], cursor_matrix[1]), + dot_v3v3(rv3d->viewinv[2], cursor_matrix[2]), + }; + const int axis = axis_dominant_v3_single(dots); + + copy_v3_v3(orient_matrix[0], cursor_matrix[(axis + 1) % 3]); + copy_v3_v3(orient_matrix[1], cursor_matrix[(axis + 2) % 3]); + copy_v3_v3(orient_matrix[2], cursor_matrix[axis]); + + if (dot_v3v3(rv3d->viewinv[2], orient_matrix[2]) < 0.0f) { + negate_v3(orient_matrix[2]); + } + if (is_negative_m3(orient_matrix)) { + swap_v3_v3(orient_matrix[0], orient_matrix[1]); + } + + if (use_mouse_project) { + float ray_co[3], ray_no[3]; + if (ED_view3d_win_to_ray( + CTX_data_depsgraph(C), + ar, v3d, mval, + ray_co, ray_no, false)) + { + float plane[4]; + plane_from_point_normal_v3(plane, cursor_matrix[3], orient_matrix[2]); + float lambda; + if (isect_ray_plane_v3(ray_co, ray_no, plane, &lambda, true)) { + madd_v3_v3v3fl(r_location, ray_co, ray_no, lambda); + copy_m3_m3(r_rotation, orient_matrix); + return; + } + } + } + + /* fallback */ + copy_v3_v3(r_location, cursor_matrix[3]); + copy_m3_m3(r_rotation, orient_matrix); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Placement Manipulator + * \{ */ + +typedef struct ManipulatorPlacementGroup { + struct wmManipulator *cage; + struct { + bContext *context; + wmOperator *op; + PropertyRNA *prop_matrix; + } data; +} ManipulatorPlacementGroup; + +/** + * \warning Calling redo from property updates is not great. + * This is needed because changing the RNA doesn't cause a redo + * and we're not using operator UI which does just this. + */ +static void manipulator_placement_exec(ManipulatorPlacementGroup *man) +{ + wmOperator *op = man->data.op; + if (op == WM_operator_last_redo((bContext *)man->data.context)) { + ED_undo_operator_repeat((bContext *)man->data.context, op); + } +} + +static void manipulator_mesh_placement_update_from_op(ManipulatorPlacementGroup *man) +{ + wmOperator *op = man->data.op; + UNUSED_VARS(op); + /* For now don't read back from the operator. */ +#if 0 + RNA_property_float_get_array(op->ptr, man->data.prop_matrix, &man->cage->matrix_offset[0][0]); +#endif +} + +/* translate callbacks */ +static void manipulator_placement_prop_matrix_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + ManipulatorPlacementGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + float *value = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + UNUSED_VARS_NDEBUG(mpr_prop); + + if (value_p != man->cage->matrix_offset) { + mul_m4_m4m4(value_p, man->cage->matrix_basis, man->cage->matrix_offset); + RNA_property_float_get_array(op->ptr, man->data.prop_matrix, value); + } +} + +static void manipulator_placement_prop_matrix_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value) +{ + ManipulatorPlacementGroup *man = mpr->parent_mgroup->customdata; + wmOperator *op = man->data.op; + + BLI_assert(mpr_prop->type->array_length == 16); + UNUSED_VARS_NDEBUG(mpr_prop); + + float mat[4][4]; + mul_m4_m4m4(mat, man->cage->matrix_basis, value); + + if (is_negative_m4(mat)) { + negate_mat3_m4(mat); + } + + RNA_property_float_set_array(op->ptr, man->data.prop_matrix, &mat[0][0]); + + manipulator_placement_exec(man); +} + +static bool manipulator_mesh_placement_poll(const bContext *C, wmManipulatorGroupType *wgt) +{ + wmOperator *op = WM_operator_last_redo(C); + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_manipulator")) { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; + } + return true; +} + +static void manipulator_mesh_placement_modal_from_setup( + const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorPlacementGroup *man = mgroup->customdata; + + /* Initial size. */ + { + wmManipulator *mpr = man->cage; + zero_m4(mpr->matrix_offset); + + /* TODO: support zero scaled matrix in 'MANIPULATOR_WT_cage_3d'. */ + mpr->matrix_offset[0][0] = 0.01; + mpr->matrix_offset[1][1] = 0.01; + mpr->matrix_offset[2][2] = 0.01; + mpr->matrix_offset[3][3] = 1.0f; + } + + /* Start off dragging. */ + { + wmWindow *win = CTX_wm_window(C); + ARegion *ar = CTX_wm_region(C); + wmManipulator *mpr = man->cage; + + { + float mat3[3][3]; + float location[3]; + calc_initial_placement_point_from_view( + (bContext *)C, (float[2]){ + win->eventstate->x - ar->winrct.xmin, + win->eventstate->y - ar->winrct.ymin, + }, + location, mat3); + copy_m4_m3(mpr->matrix_basis, mat3); + copy_v3_v3(mpr->matrix_basis[3], location); + } + + if (1) { + wmManipulatorMap *mmap = mgroup->parent_mmap; + WM_manipulator_modal_set_from_setup( + mmap, (bContext *)C, man->cage, ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, win->eventstate); + } + } +} + +static void manipulator_mesh_placement_setup(const bContext *C, wmManipulatorGroup *mgroup) +{ + wmOperator *op = WM_operator_last_redo(C); + + if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_manipulator")) { + return; + } + + struct ManipulatorPlacementGroup *man = MEM_callocN(sizeof(ManipulatorPlacementGroup), __func__); + mgroup->customdata = man; + + const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_3d", true); + + man->cage = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->cage->color); + + RNA_enum_set(man->cage->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_SIGNED); + + WM_manipulator_set_flag(man->cage, WM_MANIPULATOR_DRAW_VALUE, true); + + man->data.context = (bContext *)C; + man->data.op = op; + man->data.prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); + + manipulator_mesh_placement_update_from_op(man); + + /* Setup property callbacks */ + { + WM_manipulator_target_property_def_func( + man->cage, "matrix", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_placement_prop_matrix_get, + .value_set_fn = manipulator_placement_prop_matrix_set, + .range_get_fn = NULL, + .user_data = NULL, + }); + } + + manipulator_mesh_placement_modal_from_setup(C, mgroup); +} + +static void manipulator_mesh_placement_draw_prepare( + const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + ManipulatorPlacementGroup *man = mgroup->customdata; + if (man->data.op->next) { + man->data.op = WM_operator_last_redo((bContext *)man->data.context); + } + manipulator_mesh_placement_update_from_op(man); +} + +static void MESH_WGT_add_bounds(struct wmManipulatorGroupType *wgt) +{ + wgt->name = "Mesh Add Bounds"; + wgt->idname = "MESH_WGT_add_bounds"; + + wgt->flag = WM_MANIPULATORGROUPTYPE_3D; + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + + wgt->poll = manipulator_mesh_placement_poll; + wgt->setup = manipulator_mesh_placement_setup; + wgt->draw_prepare = manipulator_mesh_placement_draw_prepare; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Cube Manipulator-Operator + * + * For now we use a separate operator to add a cube, + * we can try to merge then however they are invoked differently + * and share the same BMesh creation code. + * \{ */ + + +static int add_primitive_cube_manipulator_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C);; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + float matrix[4][4]; + + /* Get the matrix that defines the cube bounds (as set by the manipulator cage). */ + { + PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); + if (RNA_property_is_set(op->ptr, prop_matrix)) { + RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]); + invert_m4_m4(obedit->imat, obedit->obmat); + mul_m4_m4m4(matrix, obedit->imat, matrix); + } + else { + /* For the first update the widget may not set the matrix. */ + return OPERATOR_FINISHED; + } + } + + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); + + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + + if (!EDBM_op_call_and_selectf( + em, op, "verts.out", false, + "create_cube matrix=%m4 size=%f calc_uvs=%b", + matrix, 1.0f, calc_uvs)) + { + return OPERATOR_CANCELLED; + } + + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); + EDBM_update_generic(em, true, true); + + return OPERATOR_FINISHED; +} + +static int add_primitive_cube_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + View3D *v3d = CTX_wm_view3d(C); + + int ret = add_primitive_cube_manipulator_exec(C, op); + if (ret & OPERATOR_FINISHED) { + /* Setup manipulators */ + if (v3d && ((v3d->mpr_flag & V3D_MANIPULATOR_HIDE) == 0)) { + ARegion *ar = CTX_wm_region(C); + wmManipulatorMap *mmap = ar->manipulator_map; + wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find("MESH_WGT_add_bounds", false); + wmManipulatorGroup *mgroup = WM_manipulatormap_group_find_ptr(mmap, wgt); + if (mgroup != NULL) { + ManipulatorPlacementGroup *man = mgroup->customdata; + man->data.op = op; + manipulator_mesh_placement_modal_from_setup(C, mgroup); + } + else { + WM_manipulator_group_type_ensure_ptr(wgt); + } + } + } + + return ret; +} + +void MESH_OT_primitive_cube_add_manipulator(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Cube"; + ot->description = "Construct a cube mesh"; + ot->idname = "MESH_OT_primitive_cube_add_manipulator"; + + /* api callbacks */ + ot->invoke = add_primitive_cube_manipulator_invoke; + ot->exec = add_primitive_cube_manipulator_exec; + ot->poll = ED_operator_editmesh_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ED_object_add_mesh_props(ot); + ED_object_add_generic_props(ot, true); + + /* hidden props */ + PropertyRNA *prop = RNA_def_float_matrix(ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + WM_manipulatorgrouptype_append(MESH_WGT_add_bounds); +} + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_add_manipulator.c b/source/blender/editors/mesh/editmesh_add_manipulator.c deleted file mode 100644 index f1704972e81..00000000000 --- a/source/blender/editors/mesh/editmesh_add_manipulator.c +++ /dev/null @@ -1,426 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/mesh/editmesh_add_manipulator.c - * \ingroup edmesh - * - * Creation manipulators. - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" - -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BKE_context.h" -#include "BKE_editmesh.h" - -#include "ED_manipulator_library.h" -#include "ED_mesh.h" -#include "ED_object.h" -#include "ED_screen.h" -#include "ED_undo.h" -#include "ED_view3d.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "UI_resources.h" - -#include "BLT_translation.h" - -#include "mesh_intern.h" /* own include */ - -/* -------------------------------------------------------------------- */ -/** \name Helper Functions - * \{ */ - -/** - * When we place a shape, pick a plane. - * - * We may base this choice on context, - * for now pick the "ground" based on the 3D cursor's dominant plane pointing down relative to the view. - */ -static void calc_initial_placement_point_from_view( - bContext *C, const float mval[2], - float r_location[3], float r_rotation[3][3]) -{ - - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - - bool use_mouse_project = true; /* TODO: make optional */ - - float cursor_matrix[4][4]; - float orient_matrix[3][3]; - ED_view3d_cursor3d_calc_mat4(scene, v3d, cursor_matrix); - - float dots[3] = { - dot_v3v3(rv3d->viewinv[2], cursor_matrix[0]), - dot_v3v3(rv3d->viewinv[2], cursor_matrix[1]), - dot_v3v3(rv3d->viewinv[2], cursor_matrix[2]), - }; - const int axis = axis_dominant_v3_single(dots); - - copy_v3_v3(orient_matrix[0], cursor_matrix[(axis + 1) % 3]); - copy_v3_v3(orient_matrix[1], cursor_matrix[(axis + 2) % 3]); - copy_v3_v3(orient_matrix[2], cursor_matrix[axis]); - - if (dot_v3v3(rv3d->viewinv[2], orient_matrix[2]) < 0.0f) { - negate_v3(orient_matrix[2]); - } - if (is_negative_m3(orient_matrix)) { - swap_v3_v3(orient_matrix[0], orient_matrix[1]); - } - - if (use_mouse_project) { - float ray_co[3], ray_no[3]; - if (ED_view3d_win_to_ray( - CTX_data_depsgraph(C), - ar, v3d, mval, - ray_co, ray_no, false)) - { - float plane[4]; - plane_from_point_normal_v3(plane, cursor_matrix[3], orient_matrix[2]); - float lambda; - if (isect_ray_plane_v3(ray_co, ray_no, plane, &lambda, true)) { - madd_v3_v3v3fl(r_location, ray_co, ray_no, lambda); - copy_m3_m3(r_rotation, orient_matrix); - return; - } - } - } - - /* fallback */ - copy_v3_v3(r_location, cursor_matrix[3]); - copy_m3_m3(r_rotation, orient_matrix); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Placement Manipulator - * \{ */ - -typedef struct ManipulatorPlacementGroup { - struct wmManipulator *cage; - struct { - bContext *context; - wmOperator *op; - PropertyRNA *prop_matrix; - } data; -} ManipulatorPlacementGroup; - -/** - * \warning Calling redo from property updates is not great. - * This is needed because changing the RNA doesn't cause a redo - * and we're not using operator UI which does just this. - */ -static void manipulator_placement_exec(ManipulatorPlacementGroup *man) -{ - wmOperator *op = man->data.op; - if (op == WM_operator_last_redo((bContext *)man->data.context)) { - ED_undo_operator_repeat((bContext *)man->data.context, op); - } -} - -static void manipulator_mesh_placement_update_from_op(ManipulatorPlacementGroup *man) -{ - wmOperator *op = man->data.op; - UNUSED_VARS(op); - /* For now don't read back from the operator. */ -#if 0 - RNA_property_float_get_array(op->ptr, man->data.prop_matrix, &man->cage->matrix_offset[0][0]); -#endif -} - -/* translate callbacks */ -static void manipulator_placement_prop_matrix_get( - const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, - void *value_p) -{ - ManipulatorPlacementGroup *man = mpr->parent_mgroup->customdata; - wmOperator *op = man->data.op; - float *value = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - UNUSED_VARS_NDEBUG(mpr_prop); - - if (value_p != man->cage->matrix_offset) { - mul_m4_m4m4(value_p, man->cage->matrix_basis, man->cage->matrix_offset); - RNA_property_float_get_array(op->ptr, man->data.prop_matrix, value); - } -} - -static void manipulator_placement_prop_matrix_set( - const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, - const void *value) -{ - ManipulatorPlacementGroup *man = mpr->parent_mgroup->customdata; - wmOperator *op = man->data.op; - - BLI_assert(mpr_prop->type->array_length == 16); - UNUSED_VARS_NDEBUG(mpr_prop); - - float mat[4][4]; - mul_m4_m4m4(mat, man->cage->matrix_basis, value); - - if (is_negative_m4(mat)) { - negate_mat3_m4(mat); - } - - RNA_property_float_set_array(op->ptr, man->data.prop_matrix, &mat[0][0]); - - manipulator_placement_exec(man); -} - -static bool manipulator_mesh_placement_poll(const bContext *C, wmManipulatorGroupType *wgt) -{ - wmOperator *op = WM_operator_last_redo(C); - if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_manipulator")) { - WM_manipulator_group_type_unlink_delayed_ptr(wgt); - return false; - } - return true; -} - -static void manipulator_mesh_placement_modal_from_setup( - const bContext *C, wmManipulatorGroup *mgroup) -{ - ManipulatorPlacementGroup *man = mgroup->customdata; - - /* Initial size. */ - { - wmManipulator *mpr = man->cage; - zero_m4(mpr->matrix_offset); - - /* TODO: support zero scaled matrix in 'MANIPULATOR_WT_cage_3d'. */ - mpr->matrix_offset[0][0] = 0.01; - mpr->matrix_offset[1][1] = 0.01; - mpr->matrix_offset[2][2] = 0.01; - mpr->matrix_offset[3][3] = 1.0f; - } - - /* Start off dragging. */ - { - wmWindow *win = CTX_wm_window(C); - ARegion *ar = CTX_wm_region(C); - wmManipulator *mpr = man->cage; - - { - float mat3[3][3]; - float location[3]; - calc_initial_placement_point_from_view( - (bContext *)C, (float[2]){ - win->eventstate->x - ar->winrct.xmin, - win->eventstate->y - ar->winrct.ymin, - }, - location, mat3); - copy_m4_m3(mpr->matrix_basis, mat3); - copy_v3_v3(mpr->matrix_basis[3], location); - } - - if (1) { - wmManipulatorMap *mmap = mgroup->parent_mmap; - WM_manipulator_modal_set_from_setup( - mmap, (bContext *)C, man->cage, ED_MANIPULATOR_CAGE3D_PART_SCALE_MAX_X_MAX_Y_MAX_Z, win->eventstate); - } - } -} - -static void manipulator_mesh_placement_setup(const bContext *C, wmManipulatorGroup *mgroup) -{ - wmOperator *op = WM_operator_last_redo(C); - - if (op == NULL || !STREQ(op->type->idname, "MESH_OT_primitive_cube_add_manipulator")) { - return; - } - - struct ManipulatorPlacementGroup *man = MEM_callocN(sizeof(ManipulatorPlacementGroup), __func__); - mgroup->customdata = man; - - const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_3d", true); - - man->cage = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); - - UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->cage->color); - - RNA_enum_set(man->cage->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_SIGNED); - - WM_manipulator_set_flag(man->cage, WM_MANIPULATOR_DRAW_VALUE, true); - - man->data.context = (bContext *)C; - man->data.op = op; - man->data.prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); - - manipulator_mesh_placement_update_from_op(man); - - /* Setup property callbacks */ - { - WM_manipulator_target_property_def_func( - man->cage, "matrix", - &(const struct wmManipulatorPropertyFnParams) { - .value_get_fn = manipulator_placement_prop_matrix_get, - .value_set_fn = manipulator_placement_prop_matrix_set, - .range_get_fn = NULL, - .user_data = NULL, - }); - } - - manipulator_mesh_placement_modal_from_setup(C, mgroup); -} - -static void manipulator_mesh_placement_draw_prepare( - const bContext *UNUSED(C), wmManipulatorGroup *mgroup) -{ - ManipulatorPlacementGroup *man = mgroup->customdata; - if (man->data.op->next) { - man->data.op = WM_operator_last_redo((bContext *)man->data.context); - } - manipulator_mesh_placement_update_from_op(man); -} - -static void MESH_WGT_add_bounds(struct wmManipulatorGroupType *wgt) -{ - wgt->name = "Mesh Add Bounds"; - wgt->idname = "MESH_WGT_add_bounds"; - - wgt->flag = WM_MANIPULATORGROUPTYPE_3D; - - wgt->mmap_params.spaceid = SPACE_VIEW3D; - wgt->mmap_params.regionid = RGN_TYPE_WINDOW; - - wgt->poll = manipulator_mesh_placement_poll; - wgt->setup = manipulator_mesh_placement_setup; - wgt->draw_prepare = manipulator_mesh_placement_draw_prepare; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Add Cube Manipulator-Operator - * - * For now we use a separate operator to add a cube, - * we can try to merge then however they are invoked differently - * and share the same BMesh creation code. - * \{ */ - - -static int add_primitive_cube_manipulator_exec(bContext *C, wmOperator *op) -{ - Object *obedit = CTX_data_edit_object(C);; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - float matrix[4][4]; - - /* Get the matrix that defines the cube bounds (as set by the manipulator cage). */ - { - PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix"); - if (RNA_property_is_set(op->ptr, prop_matrix)) { - RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]); - invert_m4_m4(obedit->imat, obedit->obmat); - mul_m4_m4m4(matrix, obedit->imat, matrix); - } - else { - /* For the first update the widget may not set the matrix. */ - return OPERATOR_FINISHED; - } - } - - const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); - - if (calc_uvs) { - ED_mesh_uv_texture_ensure(obedit->data, NULL); - } - - if (!EDBM_op_call_and_selectf( - em, op, "verts.out", false, - "create_cube matrix=%m4 size=%f calc_uvs=%b", - matrix, 1.0f, calc_uvs)) - { - return OPERATOR_CANCELLED; - } - - EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); - EDBM_update_generic(em, true, true); - - return OPERATOR_FINISHED; -} - -static int add_primitive_cube_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - View3D *v3d = CTX_wm_view3d(C); - - int ret = add_primitive_cube_manipulator_exec(C, op); - if (ret & OPERATOR_FINISHED) { - /* Setup manipulators */ - if (v3d && ((v3d->mpr_flag & V3D_MANIPULATOR_HIDE) == 0)) { - ARegion *ar = CTX_wm_region(C); - wmManipulatorMap *mmap = ar->manipulator_map; - wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find("MESH_WGT_add_bounds", false); - wmManipulatorGroup *mgroup = WM_manipulatormap_group_find_ptr(mmap, wgt); - if (mgroup != NULL) { - ManipulatorPlacementGroup *man = mgroup->customdata; - man->data.op = op; - manipulator_mesh_placement_modal_from_setup(C, mgroup); - } - else { - WM_manipulator_group_type_ensure_ptr(wgt); - } - } - } - - return ret; -} - -void MESH_OT_primitive_cube_add_manipulator(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Cube"; - ot->description = "Construct a cube mesh"; - ot->idname = "MESH_OT_primitive_cube_add_manipulator"; - - /* api callbacks */ - ot->invoke = add_primitive_cube_manipulator_invoke; - ot->exec = add_primitive_cube_manipulator_exec; - ot->poll = ED_operator_editmesh_view3d; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ED_object_add_mesh_props(ot); - ED_object_add_generic_props(ot, true); - - /* hidden props */ - PropertyRNA *prop = RNA_def_float_matrix(ot->srna, "matrix", 4, 4, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - - WM_manipulatorgrouptype_append(MESH_WGT_add_bounds); -} - -/** \} */ diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index 579cd5e4e08..87a65924979 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -57,7 +57,7 @@ #define USE_MANIPULATOR #ifdef USE_MANIPULATOR -#include "ED_manipulator_library.h" +#include "ED_gizmo_library.h" #include "ED_undo.h" #endif diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index be68bfda09c..b007bcf04ba 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -53,7 +53,7 @@ #include "ED_screen.h" #include "ED_transform.h" #include "ED_view3d.h" -#include "ED_manipulator_library.h" +#include "ED_gizmo_library.h" #include "UI_resources.h" diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index 5c1b9ccc178..74e2833b2d9 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -57,7 +57,7 @@ #define USE_MANIPULATOR #ifdef USE_MANIPULATOR -#include "ED_manipulator_library.h" +#include "ED_gizmo_library.h" #include "ED_undo.h" #endif diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 2ee791e81d6..37f5ed642fe 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -67,7 +67,7 @@ #include "ED_clip.h" #include "ED_mask.h" #include "ED_sequencer.h" -#include "ED_manipulator_library.h" +#include "ED_gizmo_library.h" #include "io_ops.h" diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 77b1351435b..06a00945452 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -48,7 +48,7 @@ set(SRC node_draw.c node_edit.c node_group.c - node_manipulators.c + node_gizmo.c node_ops.c node_relationships.c node_select.c diff --git a/source/blender/editors/space_node/node_gizmo.c b/source/blender/editors/space_node/node_gizmo.c new file mode 100644 index 00000000000..62b4a4b6583 --- /dev/null +++ b/source/blender/editors/space_node/node_gizmo.c @@ -0,0 +1,621 @@ +/* + * ***** 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_node/node_gizmo.c + * \ingroup spnode + */ + +#include + +#include "BLI_utildefines.h" +#include "BLI_math_matrix.h" +#include "BLI_math_vector.h" +#include "BLI_rect.h" + +#include "BKE_context.h" +#include "BKE_image.h" +#include "BKE_main.h" + +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +#include "IMB_imbuf_types.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "node_intern.h" + + +/* -------------------------------------------------------------------- */ + +/** \name Local Utilities + * \{ */ + +static void node_manipulator_calc_matrix_space( + const SpaceNode *snode, const ARegion *ar, float matrix_space[4][4]) +{ + unit_m4(matrix_space); + mul_v3_fl(matrix_space[0], snode->zoom); + mul_v3_fl(matrix_space[1], snode->zoom); + matrix_space[3][0] = (ar->winx / 2) + snode->xof; + matrix_space[3][1] = (ar->winy / 2) + snode->yof; +} + +static void node_manipulator_calc_matrix_space_with_image_dims( + const SpaceNode *snode, const ARegion *ar, const float image_dims[2], float matrix_space[4][4]) +{ + unit_m4(matrix_space); + mul_v3_fl(matrix_space[0], snode->zoom * image_dims[0]); + mul_v3_fl(matrix_space[1], snode->zoom * image_dims[1]); + matrix_space[3][0] = ((ar->winx / 2) + snode->xof) - ((image_dims[0] / 2.0f) * snode->zoom); + matrix_space[3][1] = ((ar->winy / 2) + snode->yof) - ((image_dims[1] / 2.0f) * snode->zoom); +} + +/** \} */ + + + +/* -------------------------------------------------------------------- */ + +/** \name Backdrop Manipulator + * \{ */ + +static void manipulator_node_backdrop_prop_matrix_get( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + void *value_p) +{ + float (*matrix)[4] = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + const SpaceNode *snode = mpr_prop->custom_func.user_data; + matrix[0][0] = snode->zoom; + matrix[1][1] = snode->zoom; + matrix[3][0] = snode->xof; + matrix[3][1] = snode->yof; +} + +static void manipulator_node_backdrop_prop_matrix_set( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + const float (*matrix)[4] = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + SpaceNode *snode = mpr_prop->custom_func.user_data; + snode->zoom = matrix[0][0]; + snode->zoom = matrix[1][1]; + snode->xof = matrix[3][0]; + snode->yof = matrix[3][1]; +} + +static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + SpaceNode *snode = CTX_wm_space_node(C); + + if ((snode->flag & SNODE_BACKDRAW) == 0) { + return false; + } + + if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) { + bNode *node = nodeGetActive(snode->edittree); + + if (node && ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { + return true; + } + } + + return false; +} + +static void WIDGETGROUP_node_transform_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); + + wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); + + RNA_enum_set(wwrapper->manipulator->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM); + + mgroup->customdata = wwrapper; +} + +static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + Main *bmain = CTX_data_main(C); + wmManipulator *cage = ((wmManipulatorWrapper *)mgroup->customdata)->manipulator; + const ARegion *ar = CTX_wm_region(C); + /* center is always at the origin */ + const float origin[3] = {ar->winx / 2, ar->winy / 2}; + + void *lock; + Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + + if (ibuf) { + const float dims[2] = { + (ibuf->x > 0) ? ibuf->x : 64.0f, + (ibuf->y > 0) ? ibuf->y : 64.0f, + }; + + RNA_float_set_array(cage->ptr, "dimensions", dims); + WM_manipulator_set_matrix_location(cage, origin); + WM_manipulator_set_flag(cage, WM_MANIPULATOR_HIDDEN, false); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + SpaceNode *snode = CTX_wm_space_node(C); +#if 0 + PointerRNA nodeptr; + RNA_pointer_create(snode->id, &RNA_SpaceNodeEditor, snode, &nodeptr); + WM_manipulator_target_property_def_rna(cage, "offset", &nodeptr, "backdrop_offset", -1); + WM_manipulator_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1); +#endif + + WM_manipulator_target_property_def_func( + cage, "matrix", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_node_backdrop_prop_matrix_get, + .value_set_fn = manipulator_node_backdrop_prop_matrix_set, + .range_get_fn = NULL, + .user_data = snode, + }); + } + else { + WM_manipulator_set_flag(cage, WM_MANIPULATOR_HIDDEN, true); + } + + BKE_image_release_ibuf(ima, ibuf, lock); +} + +void NODE_WGT_backdrop_transform(wmManipulatorGroupType *wgt) +{ + wgt->name = "Backdrop Transform Widget"; + wgt->idname = "NODE_WGT_backdrop_transform"; + + wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT; + + wgt->poll = WIDGETGROUP_node_transform_poll; + wgt->setup = WIDGETGROUP_node_transform_setup; + wgt->refresh = WIDGETGROUP_node_transform_refresh; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Crop Manipulator + * \{ */ + +struct NodeCropWidgetGroup { + wmManipulator *border; + + struct { + float dims[2]; + } state; + + struct { + PointerRNA ptr; + PropertyRNA *prop; + bContext *context; + } update_data; +}; + +static void manipulator_node_crop_update(struct NodeCropWidgetGroup *crop_group) +{ + RNA_property_update(crop_group->update_data.context, &crop_group->update_data.ptr, crop_group->update_data.prop); +} + +static void two_xy_to_rect(const NodeTwoXYs *nxy, rctf *rect, const float dims[2], bool is_relative) +{ + if (is_relative) { + rect->xmin = nxy->fac_x1; + rect->xmax = nxy->fac_x2; + rect->ymin = nxy->fac_y1; + rect->ymax = nxy->fac_y2; + } + else { + rect->xmin = nxy->x1 / dims[0]; + rect->xmax = nxy->x2 / dims[0]; + rect->ymin = nxy->y1 / dims[1]; + rect->ymax = nxy->y2 / dims[1]; + } +} + +static void two_xy_from_rect(NodeTwoXYs *nxy, const rctf *rect, const float dims[2], bool is_relative) +{ + if (is_relative) { + nxy->fac_x1 = rect->xmin; + nxy->fac_x2 = rect->xmax; + nxy->fac_y1 = rect->ymin; + nxy->fac_y2 = rect->ymax; + } + else { + nxy->x1 = rect->xmin * dims[0]; + nxy->x2 = rect->xmax * dims[0]; + nxy->y1 = rect->ymin * dims[1]; + nxy->y2 = rect->ymax * dims[1]; + } +} + +/* scale callbacks */ +static void manipulator_node_crop_prop_matrix_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + float (*matrix)[4] = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + struct NodeCropWidgetGroup *crop_group = mpr->parent_mgroup->customdata; + const float *dims = crop_group->state.dims; + const bNode *node = mpr_prop->custom_func.user_data; + const NodeTwoXYs *nxy = node->storage; + bool is_relative = (bool)node->custom2; + rctf rct; + two_xy_to_rect(nxy, &rct, dims, is_relative); + matrix[0][0] = BLI_rctf_size_x(&rct); + matrix[1][1] = BLI_rctf_size_y(&rct); + matrix[3][0] = (BLI_rctf_cent_x(&rct) - 0.5f) * dims[0]; + matrix[3][1] = (BLI_rctf_cent_y(&rct) - 0.5f) * dims[1]; +} + +static void manipulator_node_crop_prop_matrix_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + const float (*matrix)[4] = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + struct NodeCropWidgetGroup *crop_group = mpr->parent_mgroup->customdata; + const float *dims = crop_group->state.dims; + bNode *node = mpr_prop->custom_func.user_data; + NodeTwoXYs *nxy = node->storage; + bool is_relative = (bool)node->custom2; + rctf rct; + two_xy_to_rect(nxy, &rct, dims, is_relative); + BLI_rctf_resize(&rct, matrix[0][0], matrix[1][1]); + BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f); + BLI_rctf_isect(&(rctf){.xmin = 0, .ymin = 0, .xmax = 1, .ymax = 1}, &rct, &rct); + two_xy_from_rect(nxy, &rct, dims, is_relative); + manipulator_node_crop_update(crop_group); +} + +static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + SpaceNode *snode = CTX_wm_space_node(C); + + if ((snode->flag & SNODE_BACKDRAW) == 0) { + return false; + } + + if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) { + bNode *node = nodeGetActive(snode->edittree); + + if (node && ELEM(node->type, CMP_NODE_CROP)) { + /* ignore 'use_crop_size', we can't usefully edit the crop in this case. */ + if ((node->custom1 & (0 << 1)) == 0) { + return true; + } + } + } + + return false; +} + +static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct NodeCropWidgetGroup *crop_group = MEM_mallocN(sizeof(struct NodeCropWidgetGroup), __func__); + + crop_group->border = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); + + RNA_enum_set(crop_group->border->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE); + + mgroup->customdata = crop_group; +} + +static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + ARegion *ar = CTX_wm_region(C); + wmManipulator *mpr = mgroup->manipulators.first; + + SpaceNode *snode = CTX_wm_space_node(C); + + node_manipulator_calc_matrix_space(snode, ar, mpr->matrix_space); +} + +static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + Main *bmain = CTX_data_main(C); + struct NodeCropWidgetGroup *crop_group = mgroup->customdata; + wmManipulator *mpr = crop_group->border; + + void *lock; + Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + + if (ibuf) { + crop_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; + crop_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f; + + RNA_float_set_array(mpr->ptr, "dimensions", crop_group->state.dims); + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + SpaceNode *snode = CTX_wm_space_node(C); + bNode *node = nodeGetActive(snode->edittree); + + crop_group->update_data.context = (bContext *)C; + RNA_pointer_create((ID *)snode->edittree, &RNA_CompositorNodeCrop, node, &crop_group->update_data.ptr); + crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr, "relative"); + + WM_manipulator_target_property_def_func( + mpr, "matrix", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_node_crop_prop_matrix_get, + .value_set_fn = manipulator_node_crop_prop_matrix_set, + .range_get_fn = NULL, + .user_data = node, + }); + } + else { + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } + + BKE_image_release_ibuf(ima, ibuf, lock); +} + +void NODE_WGT_backdrop_crop(wmManipulatorGroupType *wgt) +{ + wgt->name = "Backdrop Crop Widget"; + wgt->idname = "NODE_WGT_backdrop_crop"; + + wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT; + + wgt->poll = WIDGETGROUP_node_crop_poll; + wgt->setup = WIDGETGROUP_node_crop_setup; + wgt->draw_prepare = WIDGETGROUP_node_crop_draw_prepare; + wgt->refresh = WIDGETGROUP_node_crop_refresh; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Sun Beams + * \{ */ + +struct NodeSunBeamsWidgetGroup { + wmManipulator *manipulator; + + struct { + float dims[2]; + } state; +}; + +static bool WIDGETGROUP_node_sbeam_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + SpaceNode *snode = CTX_wm_space_node(C); + + if ((snode->flag & SNODE_BACKDRAW) == 0) { + return false; + } + + if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) { + bNode *node = nodeGetActive(snode->edittree); + + if (node && ELEM(node->type, CMP_NODE_SUNBEAMS)) { + return true; + } + } + + return false; +} + +static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct NodeSunBeamsWidgetGroup *sbeam_group = MEM_mallocN(sizeof(struct NodeSunBeamsWidgetGroup), __func__); + + sbeam_group->manipulator = WM_manipulator_new("MANIPULATOR_WT_grab_3d", mgroup, NULL); + wmManipulator *mpr = sbeam_group->manipulator; + + RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_CROSS_2D); + + mpr->scale_basis = 0.05f; + + mgroup->customdata = sbeam_group; +} + +static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct NodeSunBeamsWidgetGroup *sbeam_group = mgroup->customdata; + ARegion *ar = CTX_wm_region(C); + wmManipulator *mpr = mgroup->manipulators.first; + + SpaceNode *snode = CTX_wm_space_node(C); + + node_manipulator_calc_matrix_space_with_image_dims(snode, ar, sbeam_group->state.dims, mpr->matrix_space); +} + +static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + Main *bmain = CTX_data_main(C); + struct NodeSunBeamsWidgetGroup *sbeam_group = mgroup->customdata; + wmManipulator *mpr = sbeam_group->manipulator; + + void *lock; + Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + + if (ibuf) { + sbeam_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; + sbeam_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f; + + SpaceNode *snode = CTX_wm_space_node(C); + bNode *node = nodeGetActive(snode->edittree); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + PointerRNA nodeptr; + RNA_pointer_create((ID *)snode->edittree, &RNA_CompositorNodeSunBeams, node, &nodeptr); + WM_manipulator_target_property_def_rna(mpr, "offset", &nodeptr, "source", -1); + + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_MODAL, true); + } + else { + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } + + BKE_image_release_ibuf(ima, ibuf, lock); +} + +void NODE_WGT_backdrop_sun_beams(wmManipulatorGroupType *wgt) +{ + wgt->name = "Sun Beams Widget"; + wgt->idname = "NODE_WGT_sbeam"; + + wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT; + + wgt->poll = WIDGETGROUP_node_sbeam_poll; + wgt->setup = WIDGETGROUP_node_sbeam_setup; + wgt->draw_prepare = WIDGETGROUP_node_sbeam_draw_prepare; + wgt->refresh = WIDGETGROUP_node_sbeam_refresh; +} + +/** \} */ + + + +/* -------------------------------------------------------------------- */ + +/** \name Corner Pin + * \{ */ + +struct NodeCornerPinWidgetGroup { + wmManipulator *manipulators[4]; + + struct { + float dims[2]; + } state; +}; + +static bool WIDGETGROUP_node_corner_pin_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + SpaceNode *snode = CTX_wm_space_node(C); + + if ((snode->flag & SNODE_BACKDRAW) == 0) { + return false; + } + + if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) { + bNode *node = nodeGetActive(snode->edittree); + + if (node && ELEM(node->type, CMP_NODE_CORNERPIN)) { + return true; + } + } + + return false; +} + +static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct NodeCornerPinWidgetGroup *cpin_group = MEM_mallocN(sizeof(struct NodeCornerPinWidgetGroup), __func__); + const wmManipulatorType *wt_grab_3d = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", false); + + for (int i = 0; i < 4; i++) { + cpin_group->manipulators[i] = WM_manipulator_new_ptr(wt_grab_3d, mgroup, NULL); + wmManipulator *mpr = cpin_group->manipulators[i]; + + RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_CROSS_2D); + + mpr->scale_basis = 0.01f; + } + + mgroup->customdata = cpin_group; +} + +static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct NodeCornerPinWidgetGroup *cpin_group = mgroup->customdata; + ARegion *ar = CTX_wm_region(C); + + SpaceNode *snode = CTX_wm_space_node(C); + + float matrix_space[4][4]; + node_manipulator_calc_matrix_space_with_image_dims(snode, ar, cpin_group->state.dims, matrix_space); + + for (int i = 0; i < 4; i++) { + wmManipulator *mpr = cpin_group->manipulators[i]; + copy_m4_m4(mpr->matrix_space, matrix_space); + } +} + +static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + Main *bmain = CTX_data_main(C); + struct NodeCornerPinWidgetGroup *cpin_group = mgroup->customdata; + + void *lock; + Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + + if (ibuf) { + cpin_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; + cpin_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f; + + SpaceNode *snode = CTX_wm_space_node(C); + bNode *node = nodeGetActive(snode->edittree); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + int i = 0; + for (bNodeSocket *sock = node->inputs.first; sock && i < 4; sock = sock->next) { + if (sock->type == SOCK_VECTOR) { + wmManipulator *mpr = cpin_group->manipulators[i++]; + + PointerRNA sockptr; + RNA_pointer_create((ID *)snode->edittree, &RNA_NodeSocket, sock, &sockptr); + WM_manipulator_target_property_def_rna(mpr, "offset", &sockptr, "default_value", -1); + + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_MODAL, true); + } + } + } + else { + for (int i = 0; i < 4; i++) { + wmManipulator *mpr = cpin_group->manipulators[i]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } + } + + BKE_image_release_ibuf(ima, ibuf, lock); +} + +void NODE_WGT_backdrop_corner_pin(wmManipulatorGroupType *wgt) +{ + wgt->name = "Corner Pin Widget"; + wgt->idname = "NODE_WGT_backdrop_corner_pin"; + + wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT; + + wgt->poll = WIDGETGROUP_node_corner_pin_poll; + wgt->setup = WIDGETGROUP_node_corner_pin_setup; + wgt->draw_prepare = WIDGETGROUP_node_corner_pin_draw_prepare; + wgt->refresh = WIDGETGROUP_node_corner_pin_refresh; +} + +/** \} */ diff --git a/source/blender/editors/space_node/node_manipulators.c b/source/blender/editors/space_node/node_manipulators.c deleted file mode 100644 index 851e3973288..00000000000 --- a/source/blender/editors/space_node/node_manipulators.c +++ /dev/null @@ -1,621 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_node/node_manipulators.c - * \ingroup spnode - */ - -#include - -#include "BLI_utildefines.h" -#include "BLI_math_matrix.h" -#include "BLI_math_vector.h" -#include "BLI_rect.h" - -#include "BKE_context.h" -#include "BKE_image.h" -#include "BKE_main.h" - -#include "ED_screen.h" -#include "ED_manipulator_library.h" - -#include "IMB_imbuf_types.h" - -#include "MEM_guardedalloc.h" - -#include "RNA_access.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "node_intern.h" - - -/* -------------------------------------------------------------------- */ - -/** \name Local Utilities - * \{ */ - -static void node_manipulator_calc_matrix_space( - const SpaceNode *snode, const ARegion *ar, float matrix_space[4][4]) -{ - unit_m4(matrix_space); - mul_v3_fl(matrix_space[0], snode->zoom); - mul_v3_fl(matrix_space[1], snode->zoom); - matrix_space[3][0] = (ar->winx / 2) + snode->xof; - matrix_space[3][1] = (ar->winy / 2) + snode->yof; -} - -static void node_manipulator_calc_matrix_space_with_image_dims( - const SpaceNode *snode, const ARegion *ar, const float image_dims[2], float matrix_space[4][4]) -{ - unit_m4(matrix_space); - mul_v3_fl(matrix_space[0], snode->zoom * image_dims[0]); - mul_v3_fl(matrix_space[1], snode->zoom * image_dims[1]); - matrix_space[3][0] = ((ar->winx / 2) + snode->xof) - ((image_dims[0] / 2.0f) * snode->zoom); - matrix_space[3][1] = ((ar->winy / 2) + snode->yof) - ((image_dims[1] / 2.0f) * snode->zoom); -} - -/** \} */ - - - -/* -------------------------------------------------------------------- */ - -/** \name Backdrop Manipulator - * \{ */ - -static void manipulator_node_backdrop_prop_matrix_get( - const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, - void *value_p) -{ - float (*matrix)[4] = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - const SpaceNode *snode = mpr_prop->custom_func.user_data; - matrix[0][0] = snode->zoom; - matrix[1][1] = snode->zoom; - matrix[3][0] = snode->xof; - matrix[3][1] = snode->yof; -} - -static void manipulator_node_backdrop_prop_matrix_set( - const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, - const void *value_p) -{ - const float (*matrix)[4] = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - SpaceNode *snode = mpr_prop->custom_func.user_data; - snode->zoom = matrix[0][0]; - snode->zoom = matrix[1][1]; - snode->xof = matrix[3][0]; - snode->yof = matrix[3][1]; -} - -static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - if ((snode->flag & SNODE_BACKDRAW) == 0) { - return false; - } - - if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) { - bNode *node = nodeGetActive(snode->edittree); - - if (node && ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { - return true; - } - } - - return false; -} - -static void WIDGETGROUP_node_transform_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) -{ - wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); - - wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); - - RNA_enum_set(wwrapper->manipulator->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM); - - mgroup->customdata = wwrapper; -} - -static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - Main *bmain = CTX_data_main(C); - wmManipulator *cage = ((wmManipulatorWrapper *)mgroup->customdata)->manipulator; - const ARegion *ar = CTX_wm_region(C); - /* center is always at the origin */ - const float origin[3] = {ar->winx / 2, ar->winy / 2}; - - void *lock; - Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); - - if (ibuf) { - const float dims[2] = { - (ibuf->x > 0) ? ibuf->x : 64.0f, - (ibuf->y > 0) ? ibuf->y : 64.0f, - }; - - RNA_float_set_array(cage->ptr, "dimensions", dims); - WM_manipulator_set_matrix_location(cage, origin); - WM_manipulator_set_flag(cage, WM_MANIPULATOR_HIDDEN, false); - - /* need to set property here for undo. TODO would prefer to do this in _init */ - SpaceNode *snode = CTX_wm_space_node(C); -#if 0 - PointerRNA nodeptr; - RNA_pointer_create(snode->id, &RNA_SpaceNodeEditor, snode, &nodeptr); - WM_manipulator_target_property_def_rna(cage, "offset", &nodeptr, "backdrop_offset", -1); - WM_manipulator_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1); -#endif - - WM_manipulator_target_property_def_func( - cage, "matrix", - &(const struct wmManipulatorPropertyFnParams) { - .value_get_fn = manipulator_node_backdrop_prop_matrix_get, - .value_set_fn = manipulator_node_backdrop_prop_matrix_set, - .range_get_fn = NULL, - .user_data = snode, - }); - } - else { - WM_manipulator_set_flag(cage, WM_MANIPULATOR_HIDDEN, true); - } - - BKE_image_release_ibuf(ima, ibuf, lock); -} - -void NODE_WGT_backdrop_transform(wmManipulatorGroupType *wgt) -{ - wgt->name = "Backdrop Transform Widget"; - wgt->idname = "NODE_WGT_backdrop_transform"; - - wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT; - - wgt->poll = WIDGETGROUP_node_transform_poll; - wgt->setup = WIDGETGROUP_node_transform_setup; - wgt->refresh = WIDGETGROUP_node_transform_refresh; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ - -/** \name Crop Manipulator - * \{ */ - -struct NodeCropWidgetGroup { - wmManipulator *border; - - struct { - float dims[2]; - } state; - - struct { - PointerRNA ptr; - PropertyRNA *prop; - bContext *context; - } update_data; -}; - -static void manipulator_node_crop_update(struct NodeCropWidgetGroup *crop_group) -{ - RNA_property_update(crop_group->update_data.context, &crop_group->update_data.ptr, crop_group->update_data.prop); -} - -static void two_xy_to_rect(const NodeTwoXYs *nxy, rctf *rect, const float dims[2], bool is_relative) -{ - if (is_relative) { - rect->xmin = nxy->fac_x1; - rect->xmax = nxy->fac_x2; - rect->ymin = nxy->fac_y1; - rect->ymax = nxy->fac_y2; - } - else { - rect->xmin = nxy->x1 / dims[0]; - rect->xmax = nxy->x2 / dims[0]; - rect->ymin = nxy->y1 / dims[1]; - rect->ymax = nxy->y2 / dims[1]; - } -} - -static void two_xy_from_rect(NodeTwoXYs *nxy, const rctf *rect, const float dims[2], bool is_relative) -{ - if (is_relative) { - nxy->fac_x1 = rect->xmin; - nxy->fac_x2 = rect->xmax; - nxy->fac_y1 = rect->ymin; - nxy->fac_y2 = rect->ymax; - } - else { - nxy->x1 = rect->xmin * dims[0]; - nxy->x2 = rect->xmax * dims[0]; - nxy->y1 = rect->ymin * dims[1]; - nxy->y2 = rect->ymax * dims[1]; - } -} - -/* scale callbacks */ -static void manipulator_node_crop_prop_matrix_get( - const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, - void *value_p) -{ - float (*matrix)[4] = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - struct NodeCropWidgetGroup *crop_group = mpr->parent_mgroup->customdata; - const float *dims = crop_group->state.dims; - const bNode *node = mpr_prop->custom_func.user_data; - const NodeTwoXYs *nxy = node->storage; - bool is_relative = (bool)node->custom2; - rctf rct; - two_xy_to_rect(nxy, &rct, dims, is_relative); - matrix[0][0] = BLI_rctf_size_x(&rct); - matrix[1][1] = BLI_rctf_size_y(&rct); - matrix[3][0] = (BLI_rctf_cent_x(&rct) - 0.5f) * dims[0]; - matrix[3][1] = (BLI_rctf_cent_y(&rct) - 0.5f) * dims[1]; -} - -static void manipulator_node_crop_prop_matrix_set( - const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, - const void *value_p) -{ - const float (*matrix)[4] = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - struct NodeCropWidgetGroup *crop_group = mpr->parent_mgroup->customdata; - const float *dims = crop_group->state.dims; - bNode *node = mpr_prop->custom_func.user_data; - NodeTwoXYs *nxy = node->storage; - bool is_relative = (bool)node->custom2; - rctf rct; - two_xy_to_rect(nxy, &rct, dims, is_relative); - BLI_rctf_resize(&rct, matrix[0][0], matrix[1][1]); - BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f); - BLI_rctf_isect(&(rctf){.xmin = 0, .ymin = 0, .xmax = 1, .ymax = 1}, &rct, &rct); - two_xy_from_rect(nxy, &rct, dims, is_relative); - manipulator_node_crop_update(crop_group); -} - -static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - if ((snode->flag & SNODE_BACKDRAW) == 0) { - return false; - } - - if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) { - bNode *node = nodeGetActive(snode->edittree); - - if (node && ELEM(node->type, CMP_NODE_CROP)) { - /* ignore 'use_crop_size', we can't usefully edit the crop in this case. */ - if ((node->custom1 & (0 << 1)) == 0) { - return true; - } - } - } - - return false; -} - -static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) -{ - struct NodeCropWidgetGroup *crop_group = MEM_mallocN(sizeof(struct NodeCropWidgetGroup), __func__); - - crop_group->border = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); - - RNA_enum_set(crop_group->border->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE); - - mgroup->customdata = crop_group; -} - -static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) -{ - ARegion *ar = CTX_wm_region(C); - wmManipulator *mpr = mgroup->manipulators.first; - - SpaceNode *snode = CTX_wm_space_node(C); - - node_manipulator_calc_matrix_space(snode, ar, mpr->matrix_space); -} - -static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - Main *bmain = CTX_data_main(C); - struct NodeCropWidgetGroup *crop_group = mgroup->customdata; - wmManipulator *mpr = crop_group->border; - - void *lock; - Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); - - if (ibuf) { - crop_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; - crop_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f; - - RNA_float_set_array(mpr->ptr, "dimensions", crop_group->state.dims); - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - - SpaceNode *snode = CTX_wm_space_node(C); - bNode *node = nodeGetActive(snode->edittree); - - crop_group->update_data.context = (bContext *)C; - RNA_pointer_create((ID *)snode->edittree, &RNA_CompositorNodeCrop, node, &crop_group->update_data.ptr); - crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr, "relative"); - - WM_manipulator_target_property_def_func( - mpr, "matrix", - &(const struct wmManipulatorPropertyFnParams) { - .value_get_fn = manipulator_node_crop_prop_matrix_get, - .value_set_fn = manipulator_node_crop_prop_matrix_set, - .range_get_fn = NULL, - .user_data = node, - }); - } - else { - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); - } - - BKE_image_release_ibuf(ima, ibuf, lock); -} - -void NODE_WGT_backdrop_crop(wmManipulatorGroupType *wgt) -{ - wgt->name = "Backdrop Crop Widget"; - wgt->idname = "NODE_WGT_backdrop_crop"; - - wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT; - - wgt->poll = WIDGETGROUP_node_crop_poll; - wgt->setup = WIDGETGROUP_node_crop_setup; - wgt->draw_prepare = WIDGETGROUP_node_crop_draw_prepare; - wgt->refresh = WIDGETGROUP_node_crop_refresh; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ - -/** \name Sun Beams - * \{ */ - -struct NodeSunBeamsWidgetGroup { - wmManipulator *manipulator; - - struct { - float dims[2]; - } state; -}; - -static bool WIDGETGROUP_node_sbeam_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - if ((snode->flag & SNODE_BACKDRAW) == 0) { - return false; - } - - if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) { - bNode *node = nodeGetActive(snode->edittree); - - if (node && ELEM(node->type, CMP_NODE_SUNBEAMS)) { - return true; - } - } - - return false; -} - -static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) -{ - struct NodeSunBeamsWidgetGroup *sbeam_group = MEM_mallocN(sizeof(struct NodeSunBeamsWidgetGroup), __func__); - - sbeam_group->manipulator = WM_manipulator_new("MANIPULATOR_WT_grab_3d", mgroup, NULL); - wmManipulator *mpr = sbeam_group->manipulator; - - RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_CROSS_2D); - - mpr->scale_basis = 0.05f; - - mgroup->customdata = sbeam_group; -} - -static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) -{ - struct NodeSunBeamsWidgetGroup *sbeam_group = mgroup->customdata; - ARegion *ar = CTX_wm_region(C); - wmManipulator *mpr = mgroup->manipulators.first; - - SpaceNode *snode = CTX_wm_space_node(C); - - node_manipulator_calc_matrix_space_with_image_dims(snode, ar, sbeam_group->state.dims, mpr->matrix_space); -} - -static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - Main *bmain = CTX_data_main(C); - struct NodeSunBeamsWidgetGroup *sbeam_group = mgroup->customdata; - wmManipulator *mpr = sbeam_group->manipulator; - - void *lock; - Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); - - if (ibuf) { - sbeam_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; - sbeam_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f; - - SpaceNode *snode = CTX_wm_space_node(C); - bNode *node = nodeGetActive(snode->edittree); - - /* need to set property here for undo. TODO would prefer to do this in _init */ - PointerRNA nodeptr; - RNA_pointer_create((ID *)snode->edittree, &RNA_CompositorNodeSunBeams, node, &nodeptr); - WM_manipulator_target_property_def_rna(mpr, "offset", &nodeptr, "source", -1); - - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_MODAL, true); - } - else { - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); - } - - BKE_image_release_ibuf(ima, ibuf, lock); -} - -void NODE_WGT_backdrop_sun_beams(wmManipulatorGroupType *wgt) -{ - wgt->name = "Sun Beams Widget"; - wgt->idname = "NODE_WGT_sbeam"; - - wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT; - - wgt->poll = WIDGETGROUP_node_sbeam_poll; - wgt->setup = WIDGETGROUP_node_sbeam_setup; - wgt->draw_prepare = WIDGETGROUP_node_sbeam_draw_prepare; - wgt->refresh = WIDGETGROUP_node_sbeam_refresh; -} - -/** \} */ - - - -/* -------------------------------------------------------------------- */ - -/** \name Corner Pin - * \{ */ - -struct NodeCornerPinWidgetGroup { - wmManipulator *manipulators[4]; - - struct { - float dims[2]; - } state; -}; - -static bool WIDGETGROUP_node_corner_pin_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) -{ - SpaceNode *snode = CTX_wm_space_node(C); - - if ((snode->flag & SNODE_BACKDRAW) == 0) { - return false; - } - - if (snode && snode->edittree && snode->edittree->type == NTREE_COMPOSIT) { - bNode *node = nodeGetActive(snode->edittree); - - if (node && ELEM(node->type, CMP_NODE_CORNERPIN)) { - return true; - } - } - - return false; -} - -static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) -{ - struct NodeCornerPinWidgetGroup *cpin_group = MEM_mallocN(sizeof(struct NodeCornerPinWidgetGroup), __func__); - const wmManipulatorType *wt_grab_3d = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", false); - - for (int i = 0; i < 4; i++) { - cpin_group->manipulators[i] = WM_manipulator_new_ptr(wt_grab_3d, mgroup, NULL); - wmManipulator *mpr = cpin_group->manipulators[i]; - - RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_CROSS_2D); - - mpr->scale_basis = 0.01f; - } - - mgroup->customdata = cpin_group; -} - -static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) -{ - struct NodeCornerPinWidgetGroup *cpin_group = mgroup->customdata; - ARegion *ar = CTX_wm_region(C); - - SpaceNode *snode = CTX_wm_space_node(C); - - float matrix_space[4][4]; - node_manipulator_calc_matrix_space_with_image_dims(snode, ar, cpin_group->state.dims, matrix_space); - - for (int i = 0; i < 4; i++) { - wmManipulator *mpr = cpin_group->manipulators[i]; - copy_m4_m4(mpr->matrix_space, matrix_space); - } -} - -static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - Main *bmain = CTX_data_main(C); - struct NodeCornerPinWidgetGroup *cpin_group = mgroup->customdata; - - void *lock; - Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); - - if (ibuf) { - cpin_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; - cpin_group->state.dims[1] = (ibuf->y > 0) ? ibuf->y : 64.0f; - - SpaceNode *snode = CTX_wm_space_node(C); - bNode *node = nodeGetActive(snode->edittree); - - /* need to set property here for undo. TODO would prefer to do this in _init */ - int i = 0; - for (bNodeSocket *sock = node->inputs.first; sock && i < 4; sock = sock->next) { - if (sock->type == SOCK_VECTOR) { - wmManipulator *mpr = cpin_group->manipulators[i++]; - - PointerRNA sockptr; - RNA_pointer_create((ID *)snode->edittree, &RNA_NodeSocket, sock, &sockptr); - WM_manipulator_target_property_def_rna(mpr, "offset", &sockptr, "default_value", -1); - - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_MODAL, true); - } - } - } - else { - for (int i = 0; i < 4; i++) { - wmManipulator *mpr = cpin_group->manipulators[i]; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); - } - } - - BKE_image_release_ibuf(ima, ibuf, lock); -} - -void NODE_WGT_backdrop_corner_pin(wmManipulatorGroupType *wgt) -{ - wgt->name = "Corner Pin Widget"; - wgt->idname = "NODE_WGT_backdrop_corner_pin"; - - wgt->flag |= WM_MANIPULATORGROUPTYPE_PERSISTENT; - - wgt->poll = WIDGETGROUP_node_corner_pin_poll; - wgt->setup = WIDGETGROUP_node_corner_pin_setup; - wgt->draw_prepare = WIDGETGROUP_node_corner_pin_draw_prepare; - wgt->refresh = WIDGETGROUP_node_corner_pin_refresh; -} - -/** \} */ diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index f8e38587117..b85525dd2ee 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -55,14 +55,14 @@ set(SRC view3d_walk.c view3d_header.c view3d_iterators.c - view3d_manipulator_armature.c - view3d_manipulator_camera.c - view3d_manipulator_empty.c - view3d_manipulator_forcefield.c - view3d_manipulator_lamp.c - view3d_manipulator_navigate.c - view3d_manipulator_navigate_type.c - view3d_manipulator_ruler.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_ops.c view3d_project.c view3d_ruler.c 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..16c7d574873 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c @@ -0,0 +1,228 @@ +/* + * ***** 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 Manipulator + * + * \{ */ + +/* + * 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 'b_bone_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 { + wmManipulator *manipulator; + 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 manipulator_bbone_offset_get( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + void *value_p) +{ + struct BoneSplineHandle *bh = mpr_prop->custom_func.user_data; + bPoseChannel *pchan = bh->pchan; + + float *value = value_p; + BLI_assert(mpr_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 manipulator_bbone_offset_set( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + struct BoneSplineHandle *bh = mpr_prop->custom_func.user_data; + bPoseChannel *pchan = bh->pchan; + + const float *value = value_p; + + BLI_assert(mpr_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, wmManipulatorGroupType *UNUSED(wgt)) +{ + 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) { + if (arm->act_bone && arm->act_bone->segments > 1) { + View3D *v3d = CTX_wm_view3d(C); + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_HIDE_CONTEXT))) + { + /* pass */ + } + else { + return true; + } + } + } + } + return false; +} + + +static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmManipulatorGroup *mgroup) +{ + Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + bPoseChannel *pchan = BKE_pose_channel_active(ob); + + const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", true); + + struct BoneSplineWidgetGroup *bspline_group = MEM_callocN(sizeof(struct BoneSplineWidgetGroup), __func__); + mgroup->customdata = bspline_group; + + /* Handles */ + for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) { + wmManipulator *mpr; + mpr = bspline_group->handles[i].manipulator = WM_manipulator_new_ptr(wt_grab, mgroup, NULL); + RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_RING_2D); + RNA_enum_set(mpr->ptr, "draw_options", + ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL | ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW); + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_VALUE, true); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); + + mpr->scale_basis = 0.06f; + + if (i == 0) { + copy_v3_v3(mpr->matrix_basis[3], pchan->loc); + } + } +} + +static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + + if (!mgroup->customdata) + return; + + struct BoneSplineWidgetGroup *bspline_group = mgroup->customdata; + bPoseChannel *pchan = BKE_pose_channel_active(ob); + + /* Handles */ + for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) { + wmManipulator *mpr = bspline_group->handles[i].manipulator; + 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(mpr->matrix_space, mat); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + WM_manipulator_target_property_def_func( + mpr, "offset", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_bbone_offset_get, + .value_set_fn = manipulator_bbone_offset_set, + .range_get_fn = NULL, + .user_data = &bspline_group->handles[i], + }); + } +} + +void VIEW3D_WGT_armature_spline(wmManipulatorGroupType *wgt) +{ + wgt->name = "Armature Spline Widgets"; + wgt->idname = "VIEW3D_WGT_armature_spline"; + + wgt->flag = (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_3D); + + wgt->poll = WIDGETGROUP_armature_spline_poll; + wgt->setup = WIDGETGROUP_armature_spline_setup; + wgt->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..0c97669a9af --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c @@ -0,0 +1,473 @@ +/* + * ***** 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 Manipulators + * \{ */ + +struct CameraWidgetGroup { + wmManipulator *dop_dist; + wmManipulator *focal_len; + wmManipulator *ortho_scale; +}; + +static bool WIDGETGROUP_camera_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_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, wmManipulatorGroup *mgroup) +{ + Object *ob = CTX_data_active_object(C); + float dir[3]; + + const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true); + + struct CameraWidgetGroup *camgroup = MEM_callocN(sizeof(struct CameraWidgetGroup), __func__); + mgroup->customdata = camgroup; + + negate_v3_v3(dir, ob->obmat[2]); + + /* dof distance */ + { + wmManipulator *mpr; + mpr = camgroup->dop_dist = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_CROSS); + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_HOVER, true); + + UI_GetThemeColor3fv(TH_MANIPULATOR_A, mpr->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); + } + + /* focal length + * - logic/calculations are similar to BKE_camera_view_frame_ex, better keep in sync */ + { + wmManipulator *mpr; + mpr = camgroup->focal_len = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + mpr->flag |= WM_MANIPULATOR_DRAW_NO_SCALE; + RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_CONE); + RNA_enum_set(mpr->ptr, "transform", ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); + + mpr = camgroup->ortho_scale = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + mpr->flag |= WM_MANIPULATOR_DRAW_NO_SCALE; + RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_CONE); + RNA_enum_set(mpr->ptr, "transform", ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); + } +} + +static void WIDGETGROUP_camera_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + if (!mgroup->customdata) + return; + + struct CameraWidgetGroup *camgroup = mgroup->customdata; + Object *ob = CTX_data_active_object(C); + Camera *ca = ob->data; + PointerRNA camera_ptr; + float dir[3]; + + 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; + + RNA_pointer_create(&ca->id, &RNA_Camera, ca, &camera_ptr); + + negate_v3_v3(dir, ob->obmat[2]); + + if (ca->flag & CAM_SHOWLIMITS) { + WM_manipulator_set_matrix_location(camgroup->dop_dist, ob->obmat[3]); + WM_manipulator_set_matrix_rotation_from_yz_axis(camgroup->dop_dist, ob->obmat[1], dir); + WM_manipulator_set_scale(camgroup->dop_dist, ca->drawsize); + WM_manipulator_set_flag(camgroup->dop_dist, WM_MANIPULATOR_HIDDEN, false); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + WM_manipulator_target_property_def_rna(camgroup->dop_dist, "offset", &camera_ptr, "dof_distance", -1); + } + else { + WM_manipulator_set_flag(camgroup->dop_dist, WM_MANIPULATOR_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); + wmManipulator *widget = is_ortho ? camgroup->ortho_scale : camgroup->focal_len; + float scale_matrix; + if (true) { + float offset[3]; + float aspect[2]; + + WM_manipulator_set_flag(widget, WM_MANIPULATOR_HIDDEN, false); + WM_manipulator_set_flag(is_ortho ? camgroup->focal_len : camgroup->ortho_scale, WM_MANIPULATOR_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_manipulator_set_matrix_location(widget, ob->obmat[3]); + WM_manipulator_set_matrix_rotation_from_yz_axis(widget, ob->obmat[1], dir); + + if (is_ortho) { + scale_matrix = ca->ortho_scale * 0.5f; + } + else { + scale_matrix = ca->drawsize / 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_manipulator_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 wmManipulatorPropertyType *mpr_prop_type = WM_manipulatortype_target_property_find(widget->type, "offset"); + + WM_manipulator_target_property_clear_rna_ptr(widget, mpr_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_manipulator_arrow3d_set_range_fac( + widget, is_ortho ? + (ca->drawsize * range) : + (scale_matrix * range / + /* Half sensor, intentionally use sensor from camera and not calculated above. */ + (0.5f * ((ca->sensor_fit == CAMERA_SENSOR_FIT_HOR) ? ca->sensor_x : ca->sensor_x)))); + + WM_manipulator_target_property_def_rna_ptr(widget, mpr_prop_type, &camera_ptr, prop, -1); + } + +} + +static void WIDGETGROUP_camera_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + ARegion *ar = CTX_wm_region(C); + Object *ob = CTX_data_active_object(C); + Camera *ca = ob->data; + + wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { + .owner = ar, + .user_data = mgroup->parent_mmap, + .notify = WM_manipulator_do_msg_notify_tag_refresh, + }; + + { + extern PropertyRNA rna_Camera_dof_distance; + extern PropertyRNA rna_Camera_draw_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_draw_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_mpr_tag_refresh, __func__); + } + } + + /* Subscribe to render settings */ + { + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_mpr_tag_refresh); + } +} + +void VIEW3D_WGT_camera(wmManipulatorGroupType *wgt) +{ + wgt->name = "Camera Widgets"; + wgt->idname = "VIEW3D_WGT_camera"; + + wgt->flag = (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_3D | + WM_MANIPULATORGROUPTYPE_DEPTH_3D); + + wgt->poll = WIDGETGROUP_camera_poll; + wgt->setup = WIDGETGROUP_camera_setup; + wgt->refresh = WIDGETGROUP_camera_refresh; + wgt->message_subscribe = WIDGETGROUP_camera_message_subscribe; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name CameraView Manipulators + * \{ */ + +struct CameraViewWidgetGroup { + wmManipulator *border; + + struct { + rctf *edit_border; + rctf view_border; + } state; +}; + +/* scale callbacks */ +static void manipulator_render_border_prop_matrix_get( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + void *value_p) +{ + float (*matrix)[4] = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + struct CameraViewWidgetGroup *viewgroup = mpr_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 manipulator_render_border_prop_matrix_set( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + const float (*matrix)[4] = value_p; + struct CameraViewWidgetGroup *viewgroup = mpr_prop->custom_func.user_data; + rctf *border = viewgroup->state.edit_border; + BLI_assert(mpr_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, wmManipulatorGroupType *UNUSED(wgt)) +{ + 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->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_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), wmManipulatorGroup *mgroup) +{ + struct CameraViewWidgetGroup *viewgroup = MEM_mallocN(sizeof(struct CameraViewWidgetGroup), __func__); + + viewgroup->border = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); + + RNA_enum_set(viewgroup->border->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE); + /* Box style is more subtle in this case. */ + RNA_enum_set(viewgroup->border->ptr, "draw_style", ED_MANIPULATOR_CAGE2D_STYLE_BOX); + + + mgroup->customdata = viewgroup; +} + +static void WIDGETGROUP_camera_view_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct CameraViewWidgetGroup *viewgroup = mgroup->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}; + } + + wmManipulator *mpr = viewgroup->border; + unit_m4(mpr->matrix_space); + mul_v3_fl(mpr->matrix_space[0], BLI_rctf_size_x(&viewgroup->state.view_border)); + mul_v3_fl(mpr->matrix_space[1], BLI_rctf_size_y(&viewgroup->state.view_border)); + mpr->matrix_space[3][0] = viewgroup->state.view_border.xmin; + mpr->matrix_space[3][1] = viewgroup->state.view_border.ymin; +} + +static void WIDGETGROUP_camera_view_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct CameraViewWidgetGroup *viewgroup = mgroup->customdata; + + View3D *v3d = CTX_wm_view3d(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + Scene *scene = CTX_data_scene(C); + + { + wmManipulator *mpr = viewgroup->border; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + RNA_enum_set(viewgroup->border->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_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_manipulator_target_property_def_func( + mpr, "matrix", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_render_border_prop_matrix_get, + .value_set_fn = manipulator_render_border_prop_matrix_set, + .range_get_fn = NULL, + .user_data = viewgroup, + }); + } + +} + +void VIEW3D_WGT_camera_view(wmManipulatorGroupType *wgt) +{ + wgt->name = "Camera View Widgets"; + wgt->idname = "VIEW3D_WGT_camera_view"; + + wgt->flag = (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_SCALE); + + wgt->poll = WIDGETGROUP_camera_view_poll; + wgt->setup = WIDGETGROUP_camera_view_setup; + wgt->draw_prepare = WIDGETGROUP_camera_view_draw_prepare; + wgt->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..89f55bc1d9a --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c @@ -0,0 +1,204 @@ +/* + * ***** 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 "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 Manipulators + * \{ */ + +struct EmptyImageWidgetGroup { + wmManipulator *manipulator; + struct { + Object *ob; + float dims[2]; + } state; +}; + +/* translate callbacks */ +static void manipulator_empty_image_prop_matrix_get( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + void *value_p) +{ + float (*matrix)[4] = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + struct EmptyImageWidgetGroup *imgroup = mpr_prop->custom_func.user_data; + const Object *ob = imgroup->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(mpr->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 manipulator_empty_image_prop_matrix_set( + const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + const float (*matrix)[4] = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + struct EmptyImageWidgetGroup *imgroup = mpr_prop->custom_func.user_data; + Object *ob = imgroup->state.ob; + + ob->empty_drawsize = matrix[0][0]; + + float dims[2]; + RNA_float_get_array(mpr->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, wmManipulatorGroupType *UNUSED(wgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_HIDE_CONTEXT))) + { + return false; + } + + Object *ob = CTX_data_active_object(C); + + if (ob && ob->type == OB_EMPTY) { + return (ob->empty_drawtype == OB_EMPTY_IMAGE); + } + return false; +} + +static void WIDGETGROUP_empty_image_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct EmptyImageWidgetGroup *imgroup = MEM_mallocN(sizeof(struct EmptyImageWidgetGroup), __func__); + imgroup->manipulator = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); + wmManipulator *mpr = imgroup->manipulator; + RNA_enum_set(mpr->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE); + + mgroup->customdata = imgroup; + + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_HOVER, true); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); +} + +static void WIDGETGROUP_empty_image_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct EmptyImageWidgetGroup *imgroup = mgroup->customdata; + Object *ob = CTX_data_active_object(C); + wmManipulator *mpr = imgroup->manipulator; + + copy_m4_m4(mpr->matrix_basis, ob->obmat); + + RNA_enum_set(mpr->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM); + + imgroup->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]); + imgroup->state.dims[0] = size[0] / dims_max; + imgroup->state.dims[1] = size[1] / dims_max; + } + else { + copy_v2_fl(imgroup->state.dims, 1.0f); + } + RNA_float_set_array(mpr->ptr, "dimensions", imgroup->state.dims); + + WM_manipulator_target_property_def_func( + mpr, "matrix", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_empty_image_prop_matrix_get, + .value_set_fn = manipulator_empty_image_prop_matrix_set, + .range_get_fn = NULL, + .user_data = imgroup, + }); +} + +void VIEW3D_WGT_empty_image(wmManipulatorGroupType *wgt) +{ + wgt->name = "Area Light Widgets"; + wgt->idname = "VIEW3D_WGT_empty_image"; + + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_3D | + WM_MANIPULATORGROUPTYPE_DEPTH_3D); + + wgt->poll = WIDGETGROUP_empty_image_poll; + wgt->setup = WIDGETGROUP_empty_image_setup; + wgt->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..db985c18c08 --- /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 Manipulators + * \{ */ + +static bool WIDGETGROUP_forcefield_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_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), wmManipulatorGroup *mgroup) +{ + /* only wind effector for now */ + wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); + mgroup->customdata = wwrapper; + + wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_arrow_3d", mgroup, NULL); + wmManipulator *mpr = wwrapper->manipulator; + RNA_enum_set(mpr->ptr, "transform", ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED); + ED_manipulator_arrow3d_set_ui_range(mpr, -200.0f, 200.0f); + ED_manipulator_arrow3d_set_range_fac(mpr, 6.0f); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); +} + +static void WIDGETGROUP_forcefield_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + wmManipulatorWrapper *wwrapper = mgroup->customdata; + wmManipulator *mpr = wwrapper->manipulator; + 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_manipulator_set_matrix_location(mpr, ob->obmat[3]); + WM_manipulator_set_matrix_rotation_from_z_axis(mpr, ob->obmat[2]); + WM_manipulator_set_matrix_offset_location(mpr, ofs); + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + WM_manipulator_target_property_def_rna(mpr, "offset", &field_ptr, "strength", -1); + } + else { + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } +} + +void VIEW3D_WGT_force_field(wmManipulatorGroupType *wgt) +{ + wgt->name = "Force Field Widgets"; + wgt->idname = "VIEW3D_WGT_force_field"; + + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_3D | + WM_MANIPULATORGROUPTYPE_SCALE | + WM_MANIPULATORGROUPTYPE_DEPTH_3D); + + wgt->poll = WIDGETGROUP_forcefield_poll; + wgt->setup = WIDGETGROUP_forcefield_setup; + wgt->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..8087fcbdddd --- /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 Manipulators + * \{ */ + +static bool WIDGETGROUP_lamp_spot_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_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), wmManipulatorGroup *mgroup) +{ + wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); + + wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_arrow_3d", mgroup, NULL); + wmManipulator *mpr = wwrapper->manipulator; + RNA_enum_set(mpr->ptr, "transform", ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED); + + mgroup->customdata = wwrapper; + + ED_manipulator_arrow3d_set_range_fac(mpr, 4.0f); + + UI_GetThemeColor3fv(TH_MANIPULATOR_SECONDARY, mpr->color); +} + +static void WIDGETGROUP_lamp_spot_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + wmManipulatorWrapper *wwrapper = mgroup->customdata; + wmManipulator *mpr = wwrapper->manipulator; + Object *ob = CTX_data_active_object(C); + Lamp *la = ob->data; + float dir[3]; + + negate_v3_v3(dir, ob->obmat[2]); + + WM_manipulator_set_matrix_rotation_from_z_axis(mpr, dir); + WM_manipulator_set_matrix_location(mpr, 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_manipulator_target_property_def_rna(mpr, "offset", &lamp_ptr, propname, -1); +} + +void VIEW3D_WGT_lamp_spot(wmManipulatorGroupType *wgt) +{ + wgt->name = "Spot Light Widgets"; + wgt->idname = "VIEW3D_WGT_lamp_spot"; + + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_3D | + WM_MANIPULATORGROUPTYPE_DEPTH_3D); + + wgt->poll = WIDGETGROUP_lamp_spot_poll; + wgt->setup = WIDGETGROUP_lamp_spot_setup; + wgt->refresh = WIDGETGROUP_lamp_spot_refresh; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Area Lamp Manipulators + * \{ */ + +/* scale callbacks */ +static void manipulator_area_lamp_prop_matrix_get( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + void *value_p) +{ + BLI_assert(mpr_prop->type->array_length == 16); + float (*matrix)[4] = value_p; + const Lamp *la = mpr_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 manipulator_area_lamp_prop_matrix_set( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + const float (*matrix)[4] = value_p; + BLI_assert(mpr_prop->type->array_length == 16); + Lamp *la = mpr_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, wmManipulatorGroupType *UNUSED(wgt)) +{ + 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), wmManipulatorGroup *mgroup) +{ + wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); + wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); + wmManipulator *mpr = wwrapper->manipulator; + RNA_enum_set(mpr->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE); + + mgroup->customdata = wwrapper; + + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_HOVER, true); + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); +} + +static void WIDGETGROUP_lamp_area_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + wmManipulatorWrapper *wwrapper = mgroup->customdata; + Object *ob = CTX_data_active_object(C); + Lamp *la = ob->data; + wmManipulator *mpr = wwrapper->manipulator; + + copy_m4_m4(mpr->matrix_basis, ob->obmat); + + int flag = ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE; + if (ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_DISK)) { + flag |= ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM; + } + RNA_enum_set(mpr->ptr, "transform", flag); + + /* need to set property here for undo. TODO would prefer to do this in _init */ + WM_manipulator_target_property_def_func( + mpr, "matrix", + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = manipulator_area_lamp_prop_matrix_get, + .value_set_fn = manipulator_area_lamp_prop_matrix_set, + .range_get_fn = NULL, + .user_data = la, + }); +} + +void VIEW3D_WGT_lamp_area(wmManipulatorGroupType *wgt) +{ + wgt->name = "Area Light Widgets"; + wgt->idname = "VIEW3D_WGT_lamp_area"; + + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_3D | + WM_MANIPULATORGROUPTYPE_DEPTH_3D); + + wgt->poll = WIDGETGROUP_lamp_area_poll; + wgt->setup = WIDGETGROUP_lamp_area_setup; + wgt->refresh = WIDGETGROUP_lamp_area_refresh; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Lamp Target Manipulator + * \{ */ + +static bool WIDGETGROUP_lamp_target_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + 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_HEMI, 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), wmManipulatorGroup *mgroup) +{ + wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); + wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_grab_3d", mgroup, NULL); + wmManipulator *mpr = wwrapper->manipulator; + + mgroup->customdata = wwrapper; + + UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); + UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); + + mpr->scale_basis = 0.06f; + + wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_transform_axis_target", true); + + RNA_enum_set(mpr->ptr, "draw_options", + ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL | ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW); + + WM_manipulator_operator_set(mpr, 0, ot, NULL); +} + +static void WIDGETGROUP_lamp_target_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + wmManipulatorWrapper *wwrapper = mgroup->customdata; + Object *ob = CTX_data_active_object(C); + wmManipulator *mpr = wwrapper->manipulator; + + copy_m4_m4(mpr->matrix_basis, ob->obmat); + unit_m4(mpr->matrix_offset); + mpr->matrix_offset[3][2] = -2.4f / mpr->scale_basis; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); +} + +void VIEW3D_WGT_lamp_target(wmManipulatorGroupType *wgt) +{ + wgt->name = "Target Light Widgets"; + wgt->idname = "VIEW3D_WGT_lamp_target"; + + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_3D); + + wgt->poll = WIDGETGROUP_lamp_target_poll; + wgt->setup = WIDGETGROUP_lamp_target_setup; + wgt->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..db4eeef18f7 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c @@ -0,0 +1,371 @@ +/* + * ***** 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 Manipulator Group + * \{ */ + +/* Offset from screen edge. */ +#define MANIPULATOR_OFFSET_FAC 1.5f +/* Size of main icon. */ +#define MANIPULATOR_SIZE 64 +/* Factor for size of smaller button. */ +#define MANIPULATOR_MINI_FAC 0.35f +/* How much mini buttons offset from the primary. */ +#define MANIPULATOR_MINI_OFFSET_FAC 0.42f + + +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, +}; + +/* Vector icons compatible with 'GPU_batch_from_poly_2d_encoded' */ +static const uchar shape_camera[] = { + 0xa3, 0x19, 0x78, 0x55, 0x4d, 0x19, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xa9, 0x19, + 0xa9, 0x19, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, + 0x4d, 0x19, 0x47, 0x19, 0x65, 0x55, 0x41, 0x55, 0x41, 0x9e, 0x43, 0xa8, 0x38, 0xb3, + 0x34, 0xc3, 0x38, 0xd2, 0x43, 0xdd, 0x53, 0xe1, 0x62, 0xdd, 0x6d, 0xd2, 0x72, 0xc3, + 0x78, 0xc3, 0x7c, 0xd2, 0x87, 0xdd, 0x96, 0xe1, 0xa6, 0xdd, 0xb1, 0xd2, 0xb5, 0xc3, + 0xb1, 0xb3, 0xa6, 0xa8, 0xa9, 0x9e, 0xa9, 0x8c, 0xbb, 0x8c, 0xbb, 0x86, 0xc7, 0x86, + 0xe0, 0x9e, 0xe0, 0x55, 0xc7, 0x6d, 0xbb, 0x6d, 0xbb, 0x67, 0xa9, 0x67, 0xa9, 0x55, + 0x8a, 0x55, 0xa9, 0x19, 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, + 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x4f, 0xf5, 0x7c, 0xb3, 0x78, 0xc3, + 0x72, 0xc3, 0x6d, 0xb3, 0x62, 0xa8, 0x53, 0xa4, 0x43, 0xa8, 0x41, 0x9e, 0xa9, 0x9e, + 0xa6, 0xa8, 0x96, 0xa4, 0x87, 0xa8, 0x87, 0xa8, +}; +static const uchar shape_ortho[] = { + 0x85, 0x15, 0x85, 0x7c, 0xde, 0xb3, 0xde, 0xb8, 0xd9, 0xba, 0x80, 0x85, 0x27, 0xba, + 0x22, 0xb8, 0x22, 0xb3, 0x7b, 0x7c, 0x7b, 0x15, 0x80, 0x12, 0x80, 0x12, 0x1d, 0xba, + 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, + 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x0d, 0x1d, 0x45, 0x1d, 0x45, 0xb0, 0x0a, + 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, + 0x80, 0xf2, 0xe3, 0xba, 0xe3, 0x45, 0x80, 0x0d, 0x7f, 0x00, 0x7f, 0x00, +}; +static const uchar shape_pan[] = { + 0xbf, 0x4c, 0xbf, 0x66, 0x99, 0x66, 0x99, 0x40, 0xb2, 0x40, 0x7f, 0x0d, 0x7f, 0x00, + 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, + 0x80, 0xff, 0x80, 0xf2, 0xb3, 0xbf, 0x99, 0xbf, 0x99, 0x99, 0xbf, 0x99, 0xbf, 0xb2, + 0xf2, 0x7f, 0xf2, 0x7f, 0x40, 0xb3, 0x40, 0x99, 0x66, 0x99, 0x66, 0xbf, 0x4d, 0xbf, + 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, + 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x7f, 0x0d, 0x4c, 0x40, 0x66, 0x40, 0x66, 0x66, + 0x40, 0x66, 0x40, 0x4d, 0x0d, 0x80, 0x0d, 0x80, +}; +static const uchar shape_persp[] = { + 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, + 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x07, 0x30, 0x50, 0x18, 0xbd, + 0x80, 0xdb, 0xe8, 0xbd, 0xf5, 0xb0, 0xf5, 0xb0, 0x83, 0x0f, 0x87, 0x7b, 0xe2, 0xb7, + 0xe3, 0xba, 0xe0, 0xbb, 0x80, 0x87, 0x20, 0xbb, 0x1d, 0xba, 0x1d, 0xb7, 0x78, 0x7b, + 0x7d, 0x0f, 0x80, 0x0c, 0x80, 0x0c, 0xd0, 0x50, 0x80, 0x07, 0x7f, 0x00, 0xb0, 0x0a, + 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xe8, 0xbd, 0xe8, 0xbd, +}; +static const uchar shape_zoom[] = { + 0xad, 0x7f, 0xf1, 0x7f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, + 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0d, 0x7f, 0x52, 0x7f, 0x69, 0xb7, + 0x48, 0xb7, 0x80, 0xd8, 0xb8, 0xb7, 0x96, 0xb7, 0x96, 0xb7, 0x7f, 0x2f, 0x0d, 0x7f, + 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xda, 0x25, + 0xf5, 0x4f, 0xff, 0x80, 0xf1, 0x7f, 0xf1, 0x7f, +}; + + +struct NavigateManipulatorInfo { + const char *opname; + const char *manipulator; + const unsigned char *shape; + uint shape_size; +}; + +#define SHAPE_VARS(shape_id) shape = shape_id, .shape_size = ARRAY_SIZE(shape_id) + +struct NavigateManipulatorInfo g_navigate_params[MPR_TOTAL] = { + { + .opname = "VIEW3D_OT_move", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_pan), + }, { + .opname = "VIEW3D_OT_rotate", + .manipulator = "VIEW3D_WT_navigate_rotate", + .shape = NULL, + .shape_size = 0, + }, { + .opname = "VIEW3D_OT_zoom", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_zoom), + }, { + .opname = "VIEW3D_OT_view_persportho", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_persp), + }, { + .opname = "VIEW3D_OT_view_persportho", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_ortho), + }, { + .opname = "VIEW3D_OT_view_camera", + .manipulator = "MANIPULATOR_WT_button_2d", + .SHAPE_VARS(shape_camera), + }, +}; + +#undef SHAPE_VARS + +struct NavigateWidgetGroup { + wmManipulator *mpr_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, wmManipulatorGroupType *UNUSED(wgt)) +{ + View3D *v3d = CTX_wm_view3d(C); + if (((U.uiflag & USER_SHOW_MANIPULATOR_AXIS) == 0) || + (v3d->flag2 & V3D_RENDER_OVERRIDE) || + (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_HIDE_NAVIGATE))) + { + return false; + } + return true; + +} + +static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + 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 NavigateManipulatorInfo *info = &g_navigate_params[i]; + navgroup->mpr_array[i] = WM_manipulator_new(info->manipulator, mgroup, NULL); + wmManipulator *mpr = navgroup->mpr_array[i]; + mpr->flag |= WM_MANIPULATOR_GRAB_CURSOR | WM_MANIPULATOR_DRAW_MODAL; + mpr->color[3] = 0.2f; + mpr->color_hi[3] = 0.4f; + + /* may be overwritten later */ + mpr->scale_basis = (MANIPULATOR_SIZE * MANIPULATOR_MINI_FAC) / 2; + if (info->shape != NULL) { + PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "shape"); + RNA_property_string_set_bytes( + mpr->ptr, prop, + (const char *)info->shape, info->shape_size); + RNA_enum_set(mpr->ptr, "draw_options", ED_MANIPULATOR_BUTTON_SHOW_OUTLINE); + } + + wmOperatorType *ot = WM_operatortype_find(info->opname, true); + WM_manipulator_operator_set(mpr, 0, ot, NULL); + } + + { + wmManipulator *mpr = navgroup->mpr_array[MPR_CAMERA]; + WM_manipulator_operator_set(mpr, 0, ot_view_camera, NULL); + } + + /* Click only buttons (not modal). */ + { + int mpr_ids[] = {MPR_PERSP, MPR_ORTHO, MPR_CAMERA}; + for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { + wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; + RNA_boolean_set(mpr->ptr, "show_drag", false); + } + } + + /* Modal operators, don't use initial mouse location since we're clicking on a button. */ + { + int mpr_ids[] = {MPR_MOVE, MPR_ROTATE, MPR_ZOOM}; + for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { + wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; + wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, 0); + RNA_boolean_set(&mpop->ptr, "use_mouse_init", false); + } + } + + { + wmManipulator *mpr = navgroup->mpr_array[MPR_ROTATE]; + mpr->scale_basis = MANIPULATOR_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_manipulator_operator_set(mpr, part_index + 1, ot_view_axis, NULL); + RNA_enum_set(ptr, "type", mapping[part_index]); + } + + /* When dragging an axis, use this instead. */ + mpr->drag_part = 0; + } + + mgroup->customdata = navgroup; +} + +static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct NavigateWidgetGroup *navgroup = mgroup->customdata; + ARegion *ar = CTX_wm_region(C); + const RegionView3D *rv3d = ar->regiondata; + + for (int i = 0; i < 3; i++) { + copy_v3_v3(navgroup->mpr_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 = MANIPULATOR_SIZE; + const float icon_offset = (icon_size * 0.52f) * MANIPULATOR_OFFSET_FAC * UI_DPI_FAC; + const float icon_offset_mini = icon_size * MANIPULATOR_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, + }; + + wmManipulator *mpr; + + for (uint i = 0; i < ARRAY_SIZE(navgroup->mpr_array); i++) { + mpr = navgroup->mpr_array[i]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } + + /* RV3D_LOCKED or Camera: only show supported buttons. */ + if (show_rotate) { + mpr = navgroup->mpr_array[MPR_ROTATE]; + mpr->matrix_basis[3][0] = co_rotate[0]; + mpr->matrix_basis[3][1] = co_rotate[1]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + } + + int icon_mini_slot = 0; + + mpr = navgroup->mpr_array[MPR_ZOOM]; + mpr->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); + mpr->matrix_basis[3][1] = co[1]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + mpr = navgroup->mpr_array[MPR_MOVE]; + mpr->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); + mpr->matrix_basis[3][1] = co[1]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + if ((rv3d->viewlock & RV3D_LOCKED) == 0) { + mpr = navgroup->mpr_array[MPR_CAMERA]; + mpr->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); + mpr->matrix_basis[3][1] = co[1]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + + if (navgroup->state.rv3d.is_camera == false) { + mpr = navgroup->mpr_array[rv3d->is_persp ? MPR_PERSP : MPR_ORTHO]; + mpr->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); + mpr->matrix_basis[3][1] = co[1]; + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + } + } +} + +void VIEW3D_WGT_navigate(wmManipulatorGroupType *wgt) +{ + wgt->name = "View3D Navigate"; + wgt->idname = "VIEW3D_WGT_navigate"; + + wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | + WM_MANIPULATORGROUPTYPE_SCALE | + WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL); + + wgt->poll = WIDGETGROUP_navigate_poll; + wgt->setup = WIDGETGROUP_navigate_setup; + wgt->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..072f2ee4583 --- /dev/null +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c @@ -0,0 +1,310 @@ +/* + * ***** 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 Manipulator for the 3D View + * + * \brief Simple manipulator 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 "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 DIAL_RESOLUTION 32 + +#define HANDLE_SIZE 0.33 + +static void axis_geom_draw( + const wmManipulator *mpr, const float color[4], const bool UNUSED(select)) +{ + GPU_line_width(mpr->line_width); + + Gwn_VertFormat *format = immVertexFormat(); + const uint pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + /* flip z for reverse */ + const float cone_coords[5][3] = { + {-1, -1, 4}, + {-1, +1, 4}, + {+1, +1, 4}, + {+1, -1, 4}, + {0, 0, 2}, + }; + + struct { + float depth; + char index; + char axis; + char is_pos; + } axis_order[6] = { + {-mpr->matrix_offset[0][2], 0, 0, false}, + {+mpr->matrix_offset[0][2], 1, 0, true}, + {-mpr->matrix_offset[1][2], 2, 1, false}, + {+mpr->matrix_offset[1][2], 3, 1, true}, + {-mpr->matrix_offset[2][2], 4, 2, false}, + {+mpr->matrix_offset[2][2], 5, 2, true}, + }; + qsort(&axis_order, ARRAY_SIZE(axis_order), sizeof(axis_order[0]), BLI_sortutil_cmp_float); + + const float scale_axis = 0.25f; + static const float axis_highlight[4] = {1, 1, 1, 1}; + static const float axis_nop[4] = {1, 1, 1, 0}; + static const float axis_black[4] = {0, 0, 0, 1}; + static float axis_color[3][4]; + gpuPushMatrix(); + gpuMultMatrix(mpr->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; + + /* Draw slightly before, so axis aligned arrows draw ontop. */ + if ((draw_center_done == false) && (axis_order[axis_index].depth > -0.01f)) { + + /* Circle defining active area (revert back to 2D space). */ + { + gpuPopMatrix(); + immUniformColor4fv(color); + imm_draw_circle_fill_3d(pos_id, 0, 0, 1.0f, DIAL_RESOLUTION); + gpuPushMatrix(); + gpuMultMatrix(mpr->matrix_offset); + } + + /* Center cube. */ + { + float center[3], size[3]; + + zero_v3(center); + copy_v3_fl(size, HANDLE_SIZE); + + GPU_depth_test(true); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LEQUAL); + GPU_blend_set_func(GPU_ONE, GPU_ZERO); + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + GPU_line_smooth(true); + GPU_blend(true); + GPU_line_width(1.0f); + /* Just draw depth values. */ + immUniformColor4fv(axis_nop); + imm_draw_cube_fill_3d(pos_id, center, size); + immUniformColor4fv(axis_black); + madd_v3_v3fl( + center, + (float[3]){ + mpr->matrix_offset[0][2], + mpr->matrix_offset[1][2], + mpr->matrix_offset[2][2], + }, + 0.08f); + imm_draw_cube_wire_3d(pos_id, center, size); + GPU_blend(false); + GPU_line_smooth(false); + GPU_depth_test(false); + } + + 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; + +#define ROTATED_VERT(v_orig) \ + { \ + float v[3]; \ + copy_v3_v3(v, v_orig); \ + if (is_pos == 0) { \ + v[2] *= -1.0f; \ + } \ + immVertex3f(pos_id, v[index_x] * scale_axis, v[index_y] * scale_axis, v[index_z] * scale_axis); \ + } ((void)0) + + bool ok = true; + + /* skip view align axis */ + if (len_squared_v2(mpr->matrix_offset[axis]) < 1e-6f && (mpr->matrix_offset[axis][2] > 0.0f) == is_pos) { + ok = false; + } + if (ok) { + immUniformColor4fv(index + 1 == mpr->highlight_part ? axis_highlight : axis_color[axis]); + immBegin(GWN_PRIM_TRI_FAN, 6); + ROTATED_VERT(cone_coords[4]); + for (int j = 0; j <= 4; j++) { + ROTATED_VERT(cone_coords[j % 4]); + } + immEnd(); + } + +#undef ROTATED_VERT + } + + gpuPopMatrix(); + immUnbindProgram(); +} + +static void axis3d_draw_intern( + const bContext *UNUSED(C), wmManipulator *mpr, + const bool select, const bool highlight) +{ + const float *color = highlight ? mpr->color_hi : mpr->color; + float matrix_final[4][4]; + float matrix_unit[4][4]; + + unit_m4(matrix_unit); + + WM_manipulator_calc_matrix_final_params( + mpr, + &((struct WM_ManipulatorMatrixParams) { + .matrix_offset = matrix_unit, + }), matrix_final); + + gpuPushMatrix(); + gpuMultMatrix(matrix_final); + + GPU_blend(true); + axis_geom_draw(mpr, color, select); + GPU_blend(false); + gpuPopMatrix(); +} + +static void manipulator_axis_draw(const bContext *C, wmManipulator *mpr) +{ + const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL; + const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; + + (void)is_modal; + + GPU_blend(true); + axis3d_draw_intern(C, mpr, false, is_highlight); + GPU_blend(false); +} + +static int manipulator_axis_test_select( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) +{ + float point_local[2] = {UNPACK2(event->mval)}; + sub_v2_v2(point_local, mpr->matrix_basis[3]); + mul_v2_fl(point_local, 1.0f / (mpr->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] = { + mpr->matrix_offset[i][0] * (is_pos ? 1 : -1), + mpr->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 && (mpr->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 'mpr->scale_final' is already applied when projecting. */ + if (len_sq < 1.0f) { + return 0; + } + + return -1; +} + +static int manipulator_axis_cursor_get(wmManipulator *mpr) +{ + if (mpr->highlight_part > 0) { + return CURSOR_EDIT; + } + return BC_NSEW_SCROLLCURSOR; +} + +void VIEW3D_WT_navigate_rotate(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "VIEW3D_WT_navigate_rotate"; + + /* api callbacks */ + wt->draw = manipulator_axis_draw; + wt->test_select = manipulator_axis_test_select; + wt->cursor_get = manipulator_axis_cursor_get; + + wt->struct_size = sizeof(wmManipulator); +} 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..c29b07e4147 --- /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_object.h" +#include "BKE_unit.h" + +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_view3d_types.h" + +#include "BIF_gl.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_wgt_ruler_id = "VIEW3D_WGT_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 (wmManipulatorGroup 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 { + wmManipulator mpr; + + /* 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(wmManipulatorGroup *mgroup) +{ + /* could pass this as an arg */ + const wmManipulatorType *wt_ruler = WM_manipulatortype_find("VIEW3D_WT_ruler_item", true); + RulerItem *ruler_item = (RulerItem *)WM_manipulator_new_ptr(wt_ruler, mgroup, NULL); + WM_manipulator_set_flag(&ruler_item->mpr, WM_MANIPULATOR_DRAW_MODAL, true); + return ruler_item; +} + +static void ruler_item_remove(bContext *C, wmManipulatorGroup *mgroup, RulerItem *ruler_item) +{ + WM_manipulator_unlink(&mgroup->manipulators, mgroup->parent_mmap, &ruler_item->mpr, C); +} + +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( + wmManipulatorGroup *mgroup, RulerItem *ruler_item, const float mval[2], + int *r_co_index) +{ + RulerInfo *ruler_info = mgroup->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) +{ + RulerInteraction *inter = ruler_item->mpr.interaction_data; + 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) { + 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, wmManipulatorGroup *mgroup) +{ + // RulerInfo *ruler_info = mgroup->customdata; + 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 = mgroup->manipulators.first; ruler_item; ruler_item = (RulerItem *)ruler_item->mpr.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(const bContext *C, wmManipulatorGroup *mgroup) +{ + 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; + RulerItem *ruler_item = NULL; + if (gps->totpoints == 3) { + ruler_item = ruler_item_add(mgroup); + 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(mgroup); + for (j = 0; j < 3; j += 2) { + copy_v3_v3(ruler_item->co[j], &pt->x); + pt++; + } + changed = true; + } + } + } + } + } + + return changed; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Ruler Item Manipulator Type + * \{ */ + +static void manipulator_ruler_draw(const bContext *C, wmManipulator *mpr) +{ + Scene *scene = CTX_data_scene(C); + UnitSettings *unit = &scene->unit; + RulerInfo *ruler_info = mpr->parent_mgroup->customdata; + RulerItem *ruler_item = (RulerItem *)mpr; + 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 bg_radius = 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); + + 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); + + const bool is_act = (mpr->flag & WM_MANIPULATOR_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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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(GWN_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(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(GWN_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(GWN_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); + } + + immUnbindProgram(); + + /* 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) */ + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa( + true, + posit[0] - bg_margin, posit[1] - bg_margin, + posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1], + bg_radius, color_back); + /* 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(GWN_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(GWN_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); + } + + immUnbindProgram(); + + /* 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) */ + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa( + true, + posit[0] - bg_margin, posit[1] - bg_margin, + posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1], + bg_radius, color_back); + /* 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->mpr.interaction_data != NULL)) + { + RulerInteraction *inter = ruler_item->mpr.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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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 manipulator_ruler_test_select( + bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) +{ + RulerItem *ruler_item_pick = (RulerItem *)mpr; + float mval_fl[2] = {UNPACK2(event->mval)}; + int co_index; + + /* select and drag */ + if (view3d_ruler_pick(mpr->parent_mgroup, 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 manipulator_ruler_modal( + bContext *C, wmManipulator *mpr, const wmEvent *event, + eWM_ManipulatorTweak UNUSED(tweak_flag)) +{ + bool do_draw = false; + int exit_code = OPERATOR_RUNNING_MODAL; + RulerInfo *ruler_info = mpr->parent_mgroup->customdata; + RulerItem *ruler_item = (RulerItem *)mpr; + RulerInteraction *inter = ruler_item->mpr.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 manipulator_ruler_invoke( + bContext *C, wmManipulator *mpr, const wmEvent *event) +{ + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + RulerInfo *ruler_info = mgroup->customdata; + RulerItem *ruler_item_pick = (RulerItem *)mpr; + RulerInteraction *inter = MEM_callocN(sizeof(RulerInteraction), __func__); + mpr->interaction_data = inter; + + ARegion *ar = ruler_info->ar; + + const float mval_fl[2] = {UNPACK2(event->mval)}; + + /* select and drag */ + if (mpr->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 = mpr->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]); + } + + return OPERATOR_RUNNING_MODAL; +} + +static void manipulator_ruler_exit(bContext *C, wmManipulator *mpr, const bool cancel) +{ + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + RulerInfo *ruler_info = mgroup->customdata; + + if (!cancel) { + if (ruler_info->state == RULER_STATE_DRAG) { + RulerItem *ruler_item = (RulerItem *)mpr; + RulerInteraction *inter = mpr->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, mgroup, ruler_item); + ruler_item = NULL; + mpr = 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 manipulator, for now just re-generate. */ + view3d_ruler_to_gpencil(C, mgroup); + } + + if (mpr) { + MEM_SAFE_FREE(mpr->interaction_data); + } + + ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); +} + +static int manipulator_ruler_cursor_get(wmManipulator *mpr) +{ + if (mpr->highlight_part == PART_LINE) { + return BC_CROSSCURSOR; + } + return BC_NSEW_SCROLLCURSOR; +} + +void VIEW3D_WT_ruler_item(wmManipulatorType *wt) +{ + /* identifiers */ + wt->idname = "VIEW3D_WT_ruler_item"; + + /* api callbacks */ + wt->draw = manipulator_ruler_draw; + wt->test_select = manipulator_ruler_test_select; + wt->modal = manipulator_ruler_modal; + wt->invoke = manipulator_ruler_invoke; + wt->exit = manipulator_ruler_exit; + wt->cursor_get = manipulator_ruler_cursor_get; + + wt->struct_size = sizeof(RulerItem); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Ruler Manipulator Group + * \{ */ + +static bool WIDGETGROUP_ruler_poll(const bContext *C, wmManipulatorGroupType *wgt) +{ + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); + if ((tref_rt == NULL) || + !STREQ(wgt->idname, tref_rt->manipulator_group)) + { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; + } + return true; +} + +static void WIDGETGROUP_ruler_setup(const bContext *C, wmManipulatorGroup *mgroup) +{ + RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__); + + if (view3d_ruler_from_gpencil(C, mgroup)) { + /* 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; + + mgroup->customdata = ruler_info; +} + +void VIEW3D_WGT_ruler(wmManipulatorGroupType *wgt) +{ + wgt->name = "Ruler Widgets"; + wgt->idname = view3d_wgt_ruler_id; + + wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE | WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL; + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + + wgt->poll = WIDGETGROUP_ruler_poll; + wgt->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_wgt_ruler_id, tref_rt->manipulator_group) || + CTX_wm_region_view3d(C) == NULL) + { + return false; + } + return true; +} + +static int view3d_ruler_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d = ar->regiondata; + + wmManipulatorMap *mmap = ar->manipulator_map; + wmManipulatorGroup *mgroup = WM_manipulatormap_group_find(mmap, view3d_wgt_ruler_id); + const bool use_depth = (v3d->drawtype >= OB_SOLID); + + /* Create new line */ + RulerItem *ruler_item; + ruler_item = ruler_item_add(mgroup); + + /* This is a little weak, but there is no real good way to tweak directly. */ + WM_manipulator_highlight_set(mmap, &ruler_item->mpr); + if (WM_operator_name_call( + C, "MANIPULATORGROUP_OT_manipulator_tweak", + WM_OP_INVOKE_REGION_WIN, NULL) == OPERATOR_RUNNING_MODAL) + { + RulerInfo *ruler_info = mgroup->customdata; + RulerInteraction *inter = ruler_item->mpr.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->mpr.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->description = ""; + + 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_manipulator_armature.c b/source/blender/editors/space_view3d/view3d_manipulator_armature.c deleted file mode 100644 index 17dc4d8eb4a..00000000000 --- a/source/blender/editors/space_view3d/view3d_manipulator_armature.c +++ /dev/null @@ -1,228 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/view3d_manipulator_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_manipulator_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 Manipulator - * - * \{ */ - -/* - * 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 'b_bone_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 { - wmManipulator *manipulator; - 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 manipulator_bbone_offset_get( - const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, - void *value_p) -{ - struct BoneSplineHandle *bh = mpr_prop->custom_func.user_data; - bPoseChannel *pchan = bh->pchan; - - float *value = value_p; - BLI_assert(mpr_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 manipulator_bbone_offset_set( - const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, - const void *value_p) -{ - struct BoneSplineHandle *bh = mpr_prop->custom_func.user_data; - bPoseChannel *pchan = bh->pchan; - - const float *value = value_p; - - BLI_assert(mpr_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, wmManipulatorGroupType *UNUSED(wgt)) -{ - 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) { - if (arm->act_bone && arm->act_bone->segments > 1) { - View3D *v3d = CTX_wm_view3d(C); - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || - (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_HIDE_CONTEXT))) - { - /* pass */ - } - else { - return true; - } - } - } - } - return false; -} - - -static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmManipulatorGroup *mgroup) -{ - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bPoseChannel *pchan = BKE_pose_channel_active(ob); - - const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", true); - - struct BoneSplineWidgetGroup *bspline_group = MEM_callocN(sizeof(struct BoneSplineWidgetGroup), __func__); - mgroup->customdata = bspline_group; - - /* Handles */ - for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) { - wmManipulator *mpr; - mpr = bspline_group->handles[i].manipulator = WM_manipulator_new_ptr(wt_grab, mgroup, NULL); - RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_RING_2D); - RNA_enum_set(mpr->ptr, "draw_options", - ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL | ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW); - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_VALUE, true); - - UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); - UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); - - mpr->scale_basis = 0.06f; - - if (i == 0) { - copy_v3_v3(mpr->matrix_basis[3], pchan->loc); - } - } -} - -static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - - if (!mgroup->customdata) - return; - - struct BoneSplineWidgetGroup *bspline_group = mgroup->customdata; - bPoseChannel *pchan = BKE_pose_channel_active(ob); - - /* Handles */ - for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) { - wmManipulator *mpr = bspline_group->handles[i].manipulator; - 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(mpr->matrix_space, mat); - - /* need to set property here for undo. TODO would prefer to do this in _init */ - WM_manipulator_target_property_def_func( - mpr, "offset", - &(const struct wmManipulatorPropertyFnParams) { - .value_get_fn = manipulator_bbone_offset_get, - .value_set_fn = manipulator_bbone_offset_set, - .range_get_fn = NULL, - .user_data = &bspline_group->handles[i], - }); - } -} - -void VIEW3D_WGT_armature_spline(wmManipulatorGroupType *wgt) -{ - wgt->name = "Armature Spline Widgets"; - wgt->idname = "VIEW3D_WGT_armature_spline"; - - wgt->flag = (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_3D); - - wgt->poll = WIDGETGROUP_armature_spline_poll; - wgt->setup = WIDGETGROUP_armature_spline_setup; - wgt->refresh = WIDGETGROUP_armature_spline_refresh; -} - -/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c deleted file mode 100644 index 29f380c6334..00000000000 --- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c +++ /dev/null @@ -1,473 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/view3d_manipulator_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_manipulator_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 Manipulators - * \{ */ - -struct CameraWidgetGroup { - wmManipulator *dop_dist; - wmManipulator *focal_len; - wmManipulator *ortho_scale; -}; - -static bool WIDGETGROUP_camera_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) -{ - View3D *v3d = CTX_wm_view3d(C); - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || - (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_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, wmManipulatorGroup *mgroup) -{ - Object *ob = CTX_data_active_object(C); - float dir[3]; - - const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true); - - struct CameraWidgetGroup *camgroup = MEM_callocN(sizeof(struct CameraWidgetGroup), __func__); - mgroup->customdata = camgroup; - - negate_v3_v3(dir, ob->obmat[2]); - - /* dof distance */ - { - wmManipulator *mpr; - mpr = camgroup->dop_dist = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); - RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_CROSS); - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_HOVER, true); - - UI_GetThemeColor3fv(TH_MANIPULATOR_A, mpr->color); - UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); - } - - /* focal length - * - logic/calculations are similar to BKE_camera_view_frame_ex, better keep in sync */ - { - wmManipulator *mpr; - mpr = camgroup->focal_len = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); - mpr->flag |= WM_MANIPULATOR_DRAW_NO_SCALE; - RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_CONE); - RNA_enum_set(mpr->ptr, "transform", ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED); - - UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); - UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); - - mpr = camgroup->ortho_scale = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); - mpr->flag |= WM_MANIPULATOR_DRAW_NO_SCALE; - RNA_enum_set(mpr->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_CONE); - RNA_enum_set(mpr->ptr, "transform", ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED); - - UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); - UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); - } -} - -static void WIDGETGROUP_camera_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - if (!mgroup->customdata) - return; - - struct CameraWidgetGroup *camgroup = mgroup->customdata; - Object *ob = CTX_data_active_object(C); - Camera *ca = ob->data; - PointerRNA camera_ptr; - float dir[3]; - - 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; - - RNA_pointer_create(&ca->id, &RNA_Camera, ca, &camera_ptr); - - negate_v3_v3(dir, ob->obmat[2]); - - if (ca->flag & CAM_SHOWLIMITS) { - WM_manipulator_set_matrix_location(camgroup->dop_dist, ob->obmat[3]); - WM_manipulator_set_matrix_rotation_from_yz_axis(camgroup->dop_dist, ob->obmat[1], dir); - WM_manipulator_set_scale(camgroup->dop_dist, ca->drawsize); - WM_manipulator_set_flag(camgroup->dop_dist, WM_MANIPULATOR_HIDDEN, false); - - /* need to set property here for undo. TODO would prefer to do this in _init */ - WM_manipulator_target_property_def_rna(camgroup->dop_dist, "offset", &camera_ptr, "dof_distance", -1); - } - else { - WM_manipulator_set_flag(camgroup->dop_dist, WM_MANIPULATOR_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); - wmManipulator *widget = is_ortho ? camgroup->ortho_scale : camgroup->focal_len; - float scale_matrix; - if (true) { - float offset[3]; - float aspect[2]; - - WM_manipulator_set_flag(widget, WM_MANIPULATOR_HIDDEN, false); - WM_manipulator_set_flag(is_ortho ? camgroup->focal_len : camgroup->ortho_scale, WM_MANIPULATOR_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_manipulator_set_matrix_location(widget, ob->obmat[3]); - WM_manipulator_set_matrix_rotation_from_yz_axis(widget, ob->obmat[1], dir); - - if (is_ortho) { - scale_matrix = ca->ortho_scale * 0.5f; - } - else { - scale_matrix = ca->drawsize / 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_manipulator_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 wmManipulatorPropertyType *mpr_prop_type = WM_manipulatortype_target_property_find(widget->type, "offset"); - - WM_manipulator_target_property_clear_rna_ptr(widget, mpr_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_manipulator_arrow3d_set_range_fac( - widget, is_ortho ? - (ca->drawsize * range) : - (scale_matrix * range / - /* Half sensor, intentionally use sensor from camera and not calculated above. */ - (0.5f * ((ca->sensor_fit == CAMERA_SENSOR_FIT_HOR) ? ca->sensor_x : ca->sensor_x)))); - - WM_manipulator_target_property_def_rna_ptr(widget, mpr_prop_type, &camera_ptr, prop, -1); - } - -} - -static void WIDGETGROUP_camera_message_subscribe( - const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) -{ - ARegion *ar = CTX_wm_region(C); - Object *ob = CTX_data_active_object(C); - Camera *ca = ob->data; - - wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { - .owner = ar, - .user_data = mgroup->parent_mmap, - .notify = WM_manipulator_do_msg_notify_tag_refresh, - }; - - { - extern PropertyRNA rna_Camera_dof_distance; - extern PropertyRNA rna_Camera_draw_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_draw_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_mpr_tag_refresh, __func__); - } - } - - /* Subscribe to render settings */ - { - WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_mpr_tag_refresh); - WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_mpr_tag_refresh); - WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_mpr_tag_refresh); - WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_mpr_tag_refresh); - } -} - -void VIEW3D_WGT_camera(wmManipulatorGroupType *wgt) -{ - wgt->name = "Camera Widgets"; - wgt->idname = "VIEW3D_WGT_camera"; - - wgt->flag = (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_3D | - WM_MANIPULATORGROUPTYPE_DEPTH_3D); - - wgt->poll = WIDGETGROUP_camera_poll; - wgt->setup = WIDGETGROUP_camera_setup; - wgt->refresh = WIDGETGROUP_camera_refresh; - wgt->message_subscribe = WIDGETGROUP_camera_message_subscribe; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ - -/** \name CameraView Manipulators - * \{ */ - -struct CameraViewWidgetGroup { - wmManipulator *border; - - struct { - rctf *edit_border; - rctf view_border; - } state; -}; - -/* scale callbacks */ -static void manipulator_render_border_prop_matrix_get( - const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, - void *value_p) -{ - float (*matrix)[4] = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - struct CameraViewWidgetGroup *viewgroup = mpr_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 manipulator_render_border_prop_matrix_set( - const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, - const void *value_p) -{ - const float (*matrix)[4] = value_p; - struct CameraViewWidgetGroup *viewgroup = mpr_prop->custom_func.user_data; - rctf *border = viewgroup->state.edit_border; - BLI_assert(mpr_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, wmManipulatorGroupType *UNUSED(wgt)) -{ - 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->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_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), wmManipulatorGroup *mgroup) -{ - struct CameraViewWidgetGroup *viewgroup = MEM_mallocN(sizeof(struct CameraViewWidgetGroup), __func__); - - viewgroup->border = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); - - RNA_enum_set(viewgroup->border->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE); - /* Box style is more subtle in this case. */ - RNA_enum_set(viewgroup->border->ptr, "draw_style", ED_MANIPULATOR_CAGE2D_STYLE_BOX); - - - mgroup->customdata = viewgroup; -} - -static void WIDGETGROUP_camera_view_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) -{ - struct CameraViewWidgetGroup *viewgroup = mgroup->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}; - } - - wmManipulator *mpr = viewgroup->border; - unit_m4(mpr->matrix_space); - mul_v3_fl(mpr->matrix_space[0], BLI_rctf_size_x(&viewgroup->state.view_border)); - mul_v3_fl(mpr->matrix_space[1], BLI_rctf_size_y(&viewgroup->state.view_border)); - mpr->matrix_space[3][0] = viewgroup->state.view_border.xmin; - mpr->matrix_space[3][1] = viewgroup->state.view_border.ymin; -} - -static void WIDGETGROUP_camera_view_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - struct CameraViewWidgetGroup *viewgroup = mgroup->customdata; - - View3D *v3d = CTX_wm_view3d(C); - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - Scene *scene = CTX_data_scene(C); - - { - wmManipulator *mpr = viewgroup->border; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - - RNA_enum_set(viewgroup->border->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | ED_MANIPULATOR_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_manipulator_target_property_def_func( - mpr, "matrix", - &(const struct wmManipulatorPropertyFnParams) { - .value_get_fn = manipulator_render_border_prop_matrix_get, - .value_set_fn = manipulator_render_border_prop_matrix_set, - .range_get_fn = NULL, - .user_data = viewgroup, - }); - } - -} - -void VIEW3D_WGT_camera_view(wmManipulatorGroupType *wgt) -{ - wgt->name = "Camera View Widgets"; - wgt->idname = "VIEW3D_WGT_camera_view"; - - wgt->flag = (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_SCALE); - - wgt->poll = WIDGETGROUP_camera_view_poll; - wgt->setup = WIDGETGROUP_camera_view_setup; - wgt->draw_prepare = WIDGETGROUP_camera_view_draw_prepare; - wgt->refresh = WIDGETGROUP_camera_view_refresh; -} - -/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_empty.c b/source/blender/editors/space_view3d/view3d_manipulator_empty.c deleted file mode 100644 index 16424c39bb8..00000000000 --- a/source/blender/editors/space_view3d/view3d_manipulator_empty.c +++ /dev/null @@ -1,204 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/view3d_manipulator_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 "DNA_object_types.h" -#include "DNA_lamp_types.h" - -#include "ED_screen.h" -#include "ED_manipulator_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 Manipulators - * \{ */ - -struct EmptyImageWidgetGroup { - wmManipulator *manipulator; - struct { - Object *ob; - float dims[2]; - } state; -}; - -/* translate callbacks */ -static void manipulator_empty_image_prop_matrix_get( - const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, - void *value_p) -{ - float (*matrix)[4] = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - struct EmptyImageWidgetGroup *imgroup = mpr_prop->custom_func.user_data; - const Object *ob = imgroup->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(mpr->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 manipulator_empty_image_prop_matrix_set( - const wmManipulator *mpr, wmManipulatorProperty *mpr_prop, - const void *value_p) -{ - const float (*matrix)[4] = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - struct EmptyImageWidgetGroup *imgroup = mpr_prop->custom_func.user_data; - Object *ob = imgroup->state.ob; - - ob->empty_drawsize = matrix[0][0]; - - float dims[2]; - RNA_float_get_array(mpr->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, wmManipulatorGroupType *UNUSED(wgt)) -{ - View3D *v3d = CTX_wm_view3d(C); - - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || - (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_HIDE_CONTEXT))) - { - return false; - } - - Object *ob = CTX_data_active_object(C); - - if (ob && ob->type == OB_EMPTY) { - return (ob->empty_drawtype == OB_EMPTY_IMAGE); - } - return false; -} - -static void WIDGETGROUP_empty_image_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) -{ - struct EmptyImageWidgetGroup *imgroup = MEM_mallocN(sizeof(struct EmptyImageWidgetGroup), __func__); - imgroup->manipulator = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); - wmManipulator *mpr = imgroup->manipulator; - RNA_enum_set(mpr->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE); - - mgroup->customdata = imgroup; - - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_HOVER, true); - - UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); - UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); -} - -static void WIDGETGROUP_empty_image_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - struct EmptyImageWidgetGroup *imgroup = mgroup->customdata; - Object *ob = CTX_data_active_object(C); - wmManipulator *mpr = imgroup->manipulator; - - copy_m4_m4(mpr->matrix_basis, ob->obmat); - - RNA_enum_set(mpr->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM); - - imgroup->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]); - imgroup->state.dims[0] = size[0] / dims_max; - imgroup->state.dims[1] = size[1] / dims_max; - } - else { - copy_v2_fl(imgroup->state.dims, 1.0f); - } - RNA_float_set_array(mpr->ptr, "dimensions", imgroup->state.dims); - - WM_manipulator_target_property_def_func( - mpr, "matrix", - &(const struct wmManipulatorPropertyFnParams) { - .value_get_fn = manipulator_empty_image_prop_matrix_get, - .value_set_fn = manipulator_empty_image_prop_matrix_set, - .range_get_fn = NULL, - .user_data = imgroup, - }); -} - -void VIEW3D_WGT_empty_image(wmManipulatorGroupType *wgt) -{ - wgt->name = "Area Light Widgets"; - wgt->idname = "VIEW3D_WGT_empty_image"; - - wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_3D | - WM_MANIPULATORGROUPTYPE_DEPTH_3D); - - wgt->poll = WIDGETGROUP_empty_image_poll; - wgt->setup = WIDGETGROUP_empty_image_setup; - wgt->refresh = WIDGETGROUP_empty_image_refresh; -} - -/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c b/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c deleted file mode 100644 index e4535004c8f..00000000000 --- a/source/blender/editors/space_view3d/view3d_manipulator_forcefield.c +++ /dev/null @@ -1,125 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/view3d_manipulator_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_manipulator_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 Manipulators - * \{ */ - -static bool WIDGETGROUP_forcefield_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) -{ - View3D *v3d = CTX_wm_view3d(C); - - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || - (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_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), wmManipulatorGroup *mgroup) -{ - /* only wind effector for now */ - wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); - mgroup->customdata = wwrapper; - - wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_arrow_3d", mgroup, NULL); - wmManipulator *mpr = wwrapper->manipulator; - RNA_enum_set(mpr->ptr, "transform", ED_MANIPULATOR_ARROW_XFORM_FLAG_CONSTRAINED); - ED_manipulator_arrow3d_set_ui_range(mpr, -200.0f, 200.0f); - ED_manipulator_arrow3d_set_range_fac(mpr, 6.0f); - - UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); - UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); -} - -static void WIDGETGROUP_forcefield_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - wmManipulatorWrapper *wwrapper = mgroup->customdata; - wmManipulator *mpr = wwrapper->manipulator; - 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_manipulator_set_matrix_location(mpr, ob->obmat[3]); - WM_manipulator_set_matrix_rotation_from_z_axis(mpr, ob->obmat[2]); - WM_manipulator_set_matrix_offset_location(mpr, ofs); - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - WM_manipulator_target_property_def_rna(mpr, "offset", &field_ptr, "strength", -1); - } - else { - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); - } -} - -void VIEW3D_WGT_force_field(wmManipulatorGroupType *wgt) -{ - wgt->name = "Force Field Widgets"; - wgt->idname = "VIEW3D_WGT_force_field"; - - wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_3D | - WM_MANIPULATORGROUPTYPE_SCALE | - WM_MANIPULATORGROUPTYPE_DEPTH_3D); - - wgt->poll = WIDGETGROUP_forcefield_poll; - wgt->setup = WIDGETGROUP_forcefield_setup; - wgt->refresh = WIDGETGROUP_forcefield_refresh; -} - -/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_lamp.c b/source/blender/editors/space_view3d/view3d_manipulator_lamp.c deleted file mode 100644 index 39e908ec99d..00000000000 --- a/source/blender/editors/space_view3d/view3d_manipulator_lamp.c +++ /dev/null @@ -1,307 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/view3d_manipulator_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_manipulator_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 Manipulators - * \{ */ - -static bool WIDGETGROUP_lamp_spot_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) -{ - View3D *v3d = CTX_wm_view3d(C); - if ((v3d->flag2 & V3D_RENDER_OVERRIDE) || - (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_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), wmManipulatorGroup *mgroup) -{ - wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); - - wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_arrow_3d", mgroup, NULL); - wmManipulator *mpr = wwrapper->manipulator; - RNA_enum_set(mpr->ptr, "transform", ED_MANIPULATOR_ARROW_XFORM_FLAG_INVERTED); - - mgroup->customdata = wwrapper; - - ED_manipulator_arrow3d_set_range_fac(mpr, 4.0f); - - UI_GetThemeColor3fv(TH_MANIPULATOR_SECONDARY, mpr->color); -} - -static void WIDGETGROUP_lamp_spot_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - wmManipulatorWrapper *wwrapper = mgroup->customdata; - wmManipulator *mpr = wwrapper->manipulator; - Object *ob = CTX_data_active_object(C); - Lamp *la = ob->data; - float dir[3]; - - negate_v3_v3(dir, ob->obmat[2]); - - WM_manipulator_set_matrix_rotation_from_z_axis(mpr, dir); - WM_manipulator_set_matrix_location(mpr, 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_manipulator_target_property_def_rna(mpr, "offset", &lamp_ptr, propname, -1); -} - -void VIEW3D_WGT_lamp_spot(wmManipulatorGroupType *wgt) -{ - wgt->name = "Spot Light Widgets"; - wgt->idname = "VIEW3D_WGT_lamp_spot"; - - wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_3D | - WM_MANIPULATORGROUPTYPE_DEPTH_3D); - - wgt->poll = WIDGETGROUP_lamp_spot_poll; - wgt->setup = WIDGETGROUP_lamp_spot_setup; - wgt->refresh = WIDGETGROUP_lamp_spot_refresh; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ - -/** \name Area Lamp Manipulators - * \{ */ - -/* scale callbacks */ -static void manipulator_area_lamp_prop_matrix_get( - const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, - void *value_p) -{ - BLI_assert(mpr_prop->type->array_length == 16); - float (*matrix)[4] = value_p; - const Lamp *la = mpr_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 manipulator_area_lamp_prop_matrix_set( - const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, - const void *value_p) -{ - const float (*matrix)[4] = value_p; - BLI_assert(mpr_prop->type->array_length == 16); - Lamp *la = mpr_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, wmManipulatorGroupType *UNUSED(wgt)) -{ - 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), wmManipulatorGroup *mgroup) -{ - wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); - wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_cage_2d", mgroup, NULL); - wmManipulator *mpr = wwrapper->manipulator; - RNA_enum_set(mpr->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE); - - mgroup->customdata = wwrapper; - - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_HOVER, true); - - UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); - UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); -} - -static void WIDGETGROUP_lamp_area_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - wmManipulatorWrapper *wwrapper = mgroup->customdata; - Object *ob = CTX_data_active_object(C); - Lamp *la = ob->data; - wmManipulator *mpr = wwrapper->manipulator; - - copy_m4_m4(mpr->matrix_basis, ob->obmat); - - int flag = ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE; - if (ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_DISK)) { - flag |= ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE_UNIFORM; - } - RNA_enum_set(mpr->ptr, "transform", flag); - - /* need to set property here for undo. TODO would prefer to do this in _init */ - WM_manipulator_target_property_def_func( - mpr, "matrix", - &(const struct wmManipulatorPropertyFnParams) { - .value_get_fn = manipulator_area_lamp_prop_matrix_get, - .value_set_fn = manipulator_area_lamp_prop_matrix_set, - .range_get_fn = NULL, - .user_data = la, - }); -} - -void VIEW3D_WGT_lamp_area(wmManipulatorGroupType *wgt) -{ - wgt->name = "Area Light Widgets"; - wgt->idname = "VIEW3D_WGT_lamp_area"; - - wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_3D | - WM_MANIPULATORGROUPTYPE_DEPTH_3D); - - wgt->poll = WIDGETGROUP_lamp_area_poll; - wgt->setup = WIDGETGROUP_lamp_area_setup; - wgt->refresh = WIDGETGROUP_lamp_area_refresh; -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Lamp Target Manipulator - * \{ */ - -static bool WIDGETGROUP_lamp_target_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) -{ - 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_HEMI, 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), wmManipulatorGroup *mgroup) -{ - wmManipulatorWrapper *wwrapper = MEM_mallocN(sizeof(wmManipulatorWrapper), __func__); - wwrapper->manipulator = WM_manipulator_new("MANIPULATOR_WT_grab_3d", mgroup, NULL); - wmManipulator *mpr = wwrapper->manipulator; - - mgroup->customdata = wwrapper; - - UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, mpr->color); - UI_GetThemeColor3fv(TH_MANIPULATOR_HI, mpr->color_hi); - - mpr->scale_basis = 0.06f; - - wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_transform_axis_target", true); - - RNA_enum_set(mpr->ptr, "draw_options", - ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL | ED_MANIPULATOR_GRAB_DRAW_FLAG_ALIGN_VIEW); - - WM_manipulator_operator_set(mpr, 0, ot, NULL); -} - -static void WIDGETGROUP_lamp_target_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) -{ - wmManipulatorWrapper *wwrapper = mgroup->customdata; - Object *ob = CTX_data_active_object(C); - wmManipulator *mpr = wwrapper->manipulator; - - copy_m4_m4(mpr->matrix_basis, ob->obmat); - unit_m4(mpr->matrix_offset); - mpr->matrix_offset[3][2] = -2.4f / mpr->scale_basis; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); -} - -void VIEW3D_WGT_lamp_target(wmManipulatorGroupType *wgt) -{ - wgt->name = "Target Light Widgets"; - wgt->idname = "VIEW3D_WGT_lamp_target"; - - wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_3D); - - wgt->poll = WIDGETGROUP_lamp_target_poll; - wgt->setup = WIDGETGROUP_lamp_target_setup; - wgt->draw_prepare = WIDGETGROUP_lamp_target_draw_prepare; -} - -/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate.c deleted file mode 100644 index 465faf70fcd..00000000000 --- a/source/blender/editors/space_view3d/view3d_manipulator_navigate.c +++ /dev/null @@ -1,371 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/view3d_manipulator_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_manipulator_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 Manipulator Group - * \{ */ - -/* Offset from screen edge. */ -#define MANIPULATOR_OFFSET_FAC 1.5f -/* Size of main icon. */ -#define MANIPULATOR_SIZE 64 -/* Factor for size of smaller button. */ -#define MANIPULATOR_MINI_FAC 0.35f -/* How much mini buttons offset from the primary. */ -#define MANIPULATOR_MINI_OFFSET_FAC 0.42f - - -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, -}; - -/* Vector icons compatible with 'GPU_batch_from_poly_2d_encoded' */ -static const uchar shape_camera[] = { - 0xa3, 0x19, 0x78, 0x55, 0x4d, 0x19, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xa9, 0x19, - 0xa9, 0x19, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, - 0x4d, 0x19, 0x47, 0x19, 0x65, 0x55, 0x41, 0x55, 0x41, 0x9e, 0x43, 0xa8, 0x38, 0xb3, - 0x34, 0xc3, 0x38, 0xd2, 0x43, 0xdd, 0x53, 0xe1, 0x62, 0xdd, 0x6d, 0xd2, 0x72, 0xc3, - 0x78, 0xc3, 0x7c, 0xd2, 0x87, 0xdd, 0x96, 0xe1, 0xa6, 0xdd, 0xb1, 0xd2, 0xb5, 0xc3, - 0xb1, 0xb3, 0xa6, 0xa8, 0xa9, 0x9e, 0xa9, 0x8c, 0xbb, 0x8c, 0xbb, 0x86, 0xc7, 0x86, - 0xe0, 0x9e, 0xe0, 0x55, 0xc7, 0x6d, 0xbb, 0x6d, 0xbb, 0x67, 0xa9, 0x67, 0xa9, 0x55, - 0x8a, 0x55, 0xa9, 0x19, 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, - 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x4f, 0xf5, 0x7c, 0xb3, 0x78, 0xc3, - 0x72, 0xc3, 0x6d, 0xb3, 0x62, 0xa8, 0x53, 0xa4, 0x43, 0xa8, 0x41, 0x9e, 0xa9, 0x9e, - 0xa6, 0xa8, 0x96, 0xa4, 0x87, 0xa8, 0x87, 0xa8, -}; -static const uchar shape_ortho[] = { - 0x85, 0x15, 0x85, 0x7c, 0xde, 0xb3, 0xde, 0xb8, 0xd9, 0xba, 0x80, 0x85, 0x27, 0xba, - 0x22, 0xb8, 0x22, 0xb3, 0x7b, 0x7c, 0x7b, 0x15, 0x80, 0x12, 0x80, 0x12, 0x1d, 0xba, - 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, - 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x0d, 0x1d, 0x45, 0x1d, 0x45, 0xb0, 0x0a, - 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, - 0x80, 0xf2, 0xe3, 0xba, 0xe3, 0x45, 0x80, 0x0d, 0x7f, 0x00, 0x7f, 0x00, -}; -static const uchar shape_pan[] = { - 0xbf, 0x4c, 0xbf, 0x66, 0x99, 0x66, 0x99, 0x40, 0xb2, 0x40, 0x7f, 0x0d, 0x7f, 0x00, - 0xb0, 0x0a, 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, - 0x80, 0xff, 0x80, 0xf2, 0xb3, 0xbf, 0x99, 0xbf, 0x99, 0x99, 0xbf, 0x99, 0xbf, 0xb2, - 0xf2, 0x7f, 0xf2, 0x7f, 0x40, 0xb3, 0x40, 0x99, 0x66, 0x99, 0x66, 0xbf, 0x4d, 0xbf, - 0x80, 0xf2, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0a, 0x4f, - 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x7f, 0x0d, 0x4c, 0x40, 0x66, 0x40, 0x66, 0x66, - 0x40, 0x66, 0x40, 0x4d, 0x0d, 0x80, 0x0d, 0x80, -}; -static const uchar shape_persp[] = { - 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, - 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0x80, 0x07, 0x30, 0x50, 0x18, 0xbd, - 0x80, 0xdb, 0xe8, 0xbd, 0xf5, 0xb0, 0xf5, 0xb0, 0x83, 0x0f, 0x87, 0x7b, 0xe2, 0xb7, - 0xe3, 0xba, 0xe0, 0xbb, 0x80, 0x87, 0x20, 0xbb, 0x1d, 0xba, 0x1d, 0xb7, 0x78, 0x7b, - 0x7d, 0x0f, 0x80, 0x0c, 0x80, 0x0c, 0xd0, 0x50, 0x80, 0x07, 0x7f, 0x00, 0xb0, 0x0a, - 0xda, 0x25, 0xf5, 0x4f, 0xff, 0x80, 0xf5, 0xb0, 0xe8, 0xbd, 0xe8, 0xbd, -}; -static const uchar shape_zoom[] = { - 0xad, 0x7f, 0xf1, 0x7f, 0xff, 0x80, 0xf5, 0xb0, 0xda, 0xda, 0xb0, 0xf5, 0x80, 0xff, - 0x4f, 0xf5, 0x25, 0xda, 0x0a, 0xb0, 0x00, 0x7f, 0x0d, 0x7f, 0x52, 0x7f, 0x69, 0xb7, - 0x48, 0xb7, 0x80, 0xd8, 0xb8, 0xb7, 0x96, 0xb7, 0x96, 0xb7, 0x7f, 0x2f, 0x0d, 0x7f, - 0x00, 0x7f, 0x0a, 0x4f, 0x25, 0x25, 0x4f, 0x0a, 0x7f, 0x00, 0xb0, 0x0a, 0xda, 0x25, - 0xf5, 0x4f, 0xff, 0x80, 0xf1, 0x7f, 0xf1, 0x7f, -}; - - -struct NavigateManipulatorInfo { - const char *opname; - const char *manipulator; - const unsigned char *shape; - uint shape_size; -}; - -#define SHAPE_VARS(shape_id) shape = shape_id, .shape_size = ARRAY_SIZE(shape_id) - -struct NavigateManipulatorInfo g_navigate_params[MPR_TOTAL] = { - { - .opname = "VIEW3D_OT_move", - .manipulator = "MANIPULATOR_WT_button_2d", - .SHAPE_VARS(shape_pan), - }, { - .opname = "VIEW3D_OT_rotate", - .manipulator = "VIEW3D_WT_navigate_rotate", - .shape = NULL, - .shape_size = 0, - }, { - .opname = "VIEW3D_OT_zoom", - .manipulator = "MANIPULATOR_WT_button_2d", - .SHAPE_VARS(shape_zoom), - }, { - .opname = "VIEW3D_OT_view_persportho", - .manipulator = "MANIPULATOR_WT_button_2d", - .SHAPE_VARS(shape_persp), - }, { - .opname = "VIEW3D_OT_view_persportho", - .manipulator = "MANIPULATOR_WT_button_2d", - .SHAPE_VARS(shape_ortho), - }, { - .opname = "VIEW3D_OT_view_camera", - .manipulator = "MANIPULATOR_WT_button_2d", - .SHAPE_VARS(shape_camera), - }, -}; - -#undef SHAPE_VARS - -struct NavigateWidgetGroup { - wmManipulator *mpr_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, wmManipulatorGroupType *UNUSED(wgt)) -{ - View3D *v3d = CTX_wm_view3d(C); - if (((U.uiflag & USER_SHOW_MANIPULATOR_AXIS) == 0) || - (v3d->flag2 & V3D_RENDER_OVERRIDE) || - (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_HIDE_NAVIGATE))) - { - return false; - } - return true; - -} - -static void WIDGETGROUP_navigate_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) -{ - 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 NavigateManipulatorInfo *info = &g_navigate_params[i]; - navgroup->mpr_array[i] = WM_manipulator_new(info->manipulator, mgroup, NULL); - wmManipulator *mpr = navgroup->mpr_array[i]; - mpr->flag |= WM_MANIPULATOR_GRAB_CURSOR | WM_MANIPULATOR_DRAW_MODAL; - mpr->color[3] = 0.2f; - mpr->color_hi[3] = 0.4f; - - /* may be overwritten later */ - mpr->scale_basis = (MANIPULATOR_SIZE * MANIPULATOR_MINI_FAC) / 2; - if (info->shape != NULL) { - PropertyRNA *prop = RNA_struct_find_property(mpr->ptr, "shape"); - RNA_property_string_set_bytes( - mpr->ptr, prop, - (const char *)info->shape, info->shape_size); - RNA_enum_set(mpr->ptr, "draw_options", ED_MANIPULATOR_BUTTON_SHOW_OUTLINE); - } - - wmOperatorType *ot = WM_operatortype_find(info->opname, true); - WM_manipulator_operator_set(mpr, 0, ot, NULL); - } - - { - wmManipulator *mpr = navgroup->mpr_array[MPR_CAMERA]; - WM_manipulator_operator_set(mpr, 0, ot_view_camera, NULL); - } - - /* Click only buttons (not modal). */ - { - int mpr_ids[] = {MPR_PERSP, MPR_ORTHO, MPR_CAMERA}; - for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { - wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; - RNA_boolean_set(mpr->ptr, "show_drag", false); - } - } - - /* Modal operators, don't use initial mouse location since we're clicking on a button. */ - { - int mpr_ids[] = {MPR_MOVE, MPR_ROTATE, MPR_ZOOM}; - for (int i = 0; i < ARRAY_SIZE(mpr_ids); i++) { - wmManipulator *mpr = navgroup->mpr_array[mpr_ids[i]]; - wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, 0); - RNA_boolean_set(&mpop->ptr, "use_mouse_init", false); - } - } - - { - wmManipulator *mpr = navgroup->mpr_array[MPR_ROTATE]; - mpr->scale_basis = MANIPULATOR_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_manipulator_operator_set(mpr, part_index + 1, ot_view_axis, NULL); - RNA_enum_set(ptr, "type", mapping[part_index]); - } - - /* When dragging an axis, use this instead. */ - mpr->drag_part = 0; - } - - mgroup->customdata = navgroup; -} - -static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) -{ - struct NavigateWidgetGroup *navgroup = mgroup->customdata; - ARegion *ar = CTX_wm_region(C); - const RegionView3D *rv3d = ar->regiondata; - - for (int i = 0; i < 3; i++) { - copy_v3_v3(navgroup->mpr_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 = MANIPULATOR_SIZE; - const float icon_offset = (icon_size * 0.52f) * MANIPULATOR_OFFSET_FAC * UI_DPI_FAC; - const float icon_offset_mini = icon_size * MANIPULATOR_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, - }; - - wmManipulator *mpr; - - for (uint i = 0; i < ARRAY_SIZE(navgroup->mpr_array); i++) { - mpr = navgroup->mpr_array[i]; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); - } - - /* RV3D_LOCKED or Camera: only show supported buttons. */ - if (show_rotate) { - mpr = navgroup->mpr_array[MPR_ROTATE]; - mpr->matrix_basis[3][0] = co_rotate[0]; - mpr->matrix_basis[3][1] = co_rotate[1]; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - } - - int icon_mini_slot = 0; - - mpr = navgroup->mpr_array[MPR_ZOOM]; - mpr->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); - mpr->matrix_basis[3][1] = co[1]; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - - mpr = navgroup->mpr_array[MPR_MOVE]; - mpr->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); - mpr->matrix_basis[3][1] = co[1]; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - - if ((rv3d->viewlock & RV3D_LOCKED) == 0) { - mpr = navgroup->mpr_array[MPR_CAMERA]; - mpr->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); - mpr->matrix_basis[3][1] = co[1]; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - - if (navgroup->state.rv3d.is_camera == false) { - mpr = navgroup->mpr_array[rv3d->is_persp ? MPR_PERSP : MPR_ORTHO]; - mpr->matrix_basis[3][0] = co[0] - (icon_offset_mini * icon_mini_slot++); - mpr->matrix_basis[3][1] = co[1]; - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - } - } -} - -void VIEW3D_WGT_navigate(wmManipulatorGroupType *wgt) -{ - wgt->name = "View3D Navigate"; - wgt->idname = "VIEW3D_WGT_navigate"; - - wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT | - WM_MANIPULATORGROUPTYPE_SCALE | - WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL); - - wgt->poll = WIDGETGROUP_navigate_poll; - wgt->setup = WIDGETGROUP_navigate_setup; - wgt->draw_prepare = WIDGETGROUP_navigate_draw_prepare; -} - -/** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c b/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c deleted file mode 100644 index 996da2a1475..00000000000 --- a/source/blender/editors/space_view3d/view3d_manipulator_navigate_type.c +++ /dev/null @@ -1,310 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file view3d_manipulator_navigate_type.c - * \ingroup wm - * - * \name Custom Orientation/Navigation Manipulator for the 3D View - * - * \brief Simple manipulator 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 "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 DIAL_RESOLUTION 32 - -#define HANDLE_SIZE 0.33 - -static void axis_geom_draw( - const wmManipulator *mpr, const float color[4], const bool UNUSED(select)) -{ - GPU_line_width(mpr->line_width); - - Gwn_VertFormat *format = immVertexFormat(); - const uint pos_id = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - - /* flip z for reverse */ - const float cone_coords[5][3] = { - {-1, -1, 4}, - {-1, +1, 4}, - {+1, +1, 4}, - {+1, -1, 4}, - {0, 0, 2}, - }; - - struct { - float depth; - char index; - char axis; - char is_pos; - } axis_order[6] = { - {-mpr->matrix_offset[0][2], 0, 0, false}, - {+mpr->matrix_offset[0][2], 1, 0, true}, - {-mpr->matrix_offset[1][2], 2, 1, false}, - {+mpr->matrix_offset[1][2], 3, 1, true}, - {-mpr->matrix_offset[2][2], 4, 2, false}, - {+mpr->matrix_offset[2][2], 5, 2, true}, - }; - qsort(&axis_order, ARRAY_SIZE(axis_order), sizeof(axis_order[0]), BLI_sortutil_cmp_float); - - const float scale_axis = 0.25f; - static const float axis_highlight[4] = {1, 1, 1, 1}; - static const float axis_nop[4] = {1, 1, 1, 0}; - static const float axis_black[4] = {0, 0, 0, 1}; - static float axis_color[3][4]; - gpuPushMatrix(); - gpuMultMatrix(mpr->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; - - /* Draw slightly before, so axis aligned arrows draw ontop. */ - if ((draw_center_done == false) && (axis_order[axis_index].depth > -0.01f)) { - - /* Circle defining active area (revert back to 2D space). */ - { - gpuPopMatrix(); - immUniformColor4fv(color); - imm_draw_circle_fill_3d(pos_id, 0, 0, 1.0f, DIAL_RESOLUTION); - gpuPushMatrix(); - gpuMultMatrix(mpr->matrix_offset); - } - - /* Center cube. */ - { - float center[3], size[3]; - - zero_v3(center); - copy_v3_fl(size, HANDLE_SIZE); - - GPU_depth_test(true); - glDepthMask(GL_TRUE); - glDepthFunc(GL_LEQUAL); - GPU_blend_set_func(GPU_ONE, GPU_ZERO); - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - - GPU_line_smooth(true); - GPU_blend(true); - GPU_line_width(1.0f); - /* Just draw depth values. */ - immUniformColor4fv(axis_nop); - imm_draw_cube_fill_3d(pos_id, center, size); - immUniformColor4fv(axis_black); - madd_v3_v3fl( - center, - (float[3]){ - mpr->matrix_offset[0][2], - mpr->matrix_offset[1][2], - mpr->matrix_offset[2][2], - }, - 0.08f); - imm_draw_cube_wire_3d(pos_id, center, size); - GPU_blend(false); - GPU_line_smooth(false); - GPU_depth_test(false); - } - - 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; - -#define ROTATED_VERT(v_orig) \ - { \ - float v[3]; \ - copy_v3_v3(v, v_orig); \ - if (is_pos == 0) { \ - v[2] *= -1.0f; \ - } \ - immVertex3f(pos_id, v[index_x] * scale_axis, v[index_y] * scale_axis, v[index_z] * scale_axis); \ - } ((void)0) - - bool ok = true; - - /* skip view align axis */ - if (len_squared_v2(mpr->matrix_offset[axis]) < 1e-6f && (mpr->matrix_offset[axis][2] > 0.0f) == is_pos) { - ok = false; - } - if (ok) { - immUniformColor4fv(index + 1 == mpr->highlight_part ? axis_highlight : axis_color[axis]); - immBegin(GWN_PRIM_TRI_FAN, 6); - ROTATED_VERT(cone_coords[4]); - for (int j = 0; j <= 4; j++) { - ROTATED_VERT(cone_coords[j % 4]); - } - immEnd(); - } - -#undef ROTATED_VERT - } - - gpuPopMatrix(); - immUnbindProgram(); -} - -static void axis3d_draw_intern( - const bContext *UNUSED(C), wmManipulator *mpr, - const bool select, const bool highlight) -{ - const float *color = highlight ? mpr->color_hi : mpr->color; - float matrix_final[4][4]; - float matrix_unit[4][4]; - - unit_m4(matrix_unit); - - WM_manipulator_calc_matrix_final_params( - mpr, - &((struct WM_ManipulatorMatrixParams) { - .matrix_offset = matrix_unit, - }), matrix_final); - - gpuPushMatrix(); - gpuMultMatrix(matrix_final); - - GPU_blend(true); - axis_geom_draw(mpr, color, select); - GPU_blend(false); - gpuPopMatrix(); -} - -static void manipulator_axis_draw(const bContext *C, wmManipulator *mpr) -{ - const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL; - const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0; - - (void)is_modal; - - GPU_blend(true); - axis3d_draw_intern(C, mpr, false, is_highlight); - GPU_blend(false); -} - -static int manipulator_axis_test_select( - bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) -{ - float point_local[2] = {UNPACK2(event->mval)}; - sub_v2_v2(point_local, mpr->matrix_basis[3]); - mul_v2_fl(point_local, 1.0f / (mpr->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] = { - mpr->matrix_offset[i][0] * (is_pos ? 1 : -1), - mpr->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 && (mpr->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 'mpr->scale_final' is already applied when projecting. */ - if (len_sq < 1.0f) { - return 0; - } - - return -1; -} - -static int manipulator_axis_cursor_get(wmManipulator *mpr) -{ - if (mpr->highlight_part > 0) { - return CURSOR_EDIT; - } - return BC_NSEW_SCROLLCURSOR; -} - -void VIEW3D_WT_navigate_rotate(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "VIEW3D_WT_navigate_rotate"; - - /* api callbacks */ - wt->draw = manipulator_axis_draw; - wt->test_select = manipulator_axis_test_select; - wt->cursor_get = manipulator_axis_cursor_get; - - wt->struct_size = sizeof(wmManipulator); -} diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c deleted file mode 100644 index d102fdc6e04..00000000000 --- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c +++ /dev/null @@ -1,1101 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/space_view3d/view3d_manipulator_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_object.h" -#include "BKE_unit.h" - -#include "DNA_object_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_view3d_types.h" - -#include "BIF_gl.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_wgt_ruler_id = "VIEW3D_WGT_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 (wmManipulatorGroup 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 { - wmManipulator mpr; - - /* 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(wmManipulatorGroup *mgroup) -{ - /* could pass this as an arg */ - const wmManipulatorType *wt_ruler = WM_manipulatortype_find("VIEW3D_WT_ruler_item", true); - RulerItem *ruler_item = (RulerItem *)WM_manipulator_new_ptr(wt_ruler, mgroup, NULL); - WM_manipulator_set_flag(&ruler_item->mpr, WM_MANIPULATOR_DRAW_MODAL, true); - return ruler_item; -} - -static void ruler_item_remove(bContext *C, wmManipulatorGroup *mgroup, RulerItem *ruler_item) -{ - WM_manipulator_unlink(&mgroup->manipulators, mgroup->parent_mmap, &ruler_item->mpr, C); -} - -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( - wmManipulatorGroup *mgroup, RulerItem *ruler_item, const float mval[2], - int *r_co_index) -{ - RulerInfo *ruler_info = mgroup->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) -{ - RulerInteraction *inter = ruler_item->mpr.interaction_data; - 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) { - 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, wmManipulatorGroup *mgroup) -{ - // RulerInfo *ruler_info = mgroup->customdata; - 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 = mgroup->manipulators.first; ruler_item; ruler_item = (RulerItem *)ruler_item->mpr.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(const bContext *C, wmManipulatorGroup *mgroup) -{ - 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; - RulerItem *ruler_item = NULL; - if (gps->totpoints == 3) { - ruler_item = ruler_item_add(mgroup); - 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(mgroup); - for (j = 0; j < 3; j += 2) { - copy_v3_v3(ruler_item->co[j], &pt->x); - pt++; - } - changed = true; - } - } - } - } - } - - return changed; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Ruler Item Manipulator Type - * \{ */ - -static void manipulator_ruler_draw(const bContext *C, wmManipulator *mpr) -{ - Scene *scene = CTX_data_scene(C); - UnitSettings *unit = &scene->unit; - RulerInfo *ruler_info = mpr->parent_mgroup->customdata; - RulerItem *ruler_item = (RulerItem *)mpr; - 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 bg_radius = 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); - - 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); - - const bool is_act = (mpr->flag & WM_MANIPULATOR_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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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(GWN_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(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(GWN_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(GWN_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); - } - - immUnbindProgram(); - - /* 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) */ - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa( - true, - posit[0] - bg_margin, posit[1] - bg_margin, - posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1], - bg_radius, color_back); - /* 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(GWN_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(GWN_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); - } - - immUnbindProgram(); - - /* 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) */ - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa( - true, - posit[0] - bg_margin, posit[1] - bg_margin, - posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1], - bg_radius, color_back); - /* 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->mpr.interaction_data != NULL)) - { - RulerInteraction *inter = ruler_item->mpr.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 = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_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 manipulator_ruler_test_select( - bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event) -{ - RulerItem *ruler_item_pick = (RulerItem *)mpr; - float mval_fl[2] = {UNPACK2(event->mval)}; - int co_index; - - /* select and drag */ - if (view3d_ruler_pick(mpr->parent_mgroup, 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 manipulator_ruler_modal( - bContext *C, wmManipulator *mpr, const wmEvent *event, - eWM_ManipulatorTweak UNUSED(tweak_flag)) -{ - bool do_draw = false; - int exit_code = OPERATOR_RUNNING_MODAL; - RulerInfo *ruler_info = mpr->parent_mgroup->customdata; - RulerItem *ruler_item = (RulerItem *)mpr; - RulerInteraction *inter = ruler_item->mpr.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 manipulator_ruler_invoke( - bContext *C, wmManipulator *mpr, const wmEvent *event) -{ - wmManipulatorGroup *mgroup = mpr->parent_mgroup; - RulerInfo *ruler_info = mgroup->customdata; - RulerItem *ruler_item_pick = (RulerItem *)mpr; - RulerInteraction *inter = MEM_callocN(sizeof(RulerInteraction), __func__); - mpr->interaction_data = inter; - - ARegion *ar = ruler_info->ar; - - const float mval_fl[2] = {UNPACK2(event->mval)}; - - /* select and drag */ - if (mpr->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 = mpr->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]); - } - - return OPERATOR_RUNNING_MODAL; -} - -static void manipulator_ruler_exit(bContext *C, wmManipulator *mpr, const bool cancel) -{ - wmManipulatorGroup *mgroup = mpr->parent_mgroup; - RulerInfo *ruler_info = mgroup->customdata; - - if (!cancel) { - if (ruler_info->state == RULER_STATE_DRAG) { - RulerItem *ruler_item = (RulerItem *)mpr; - RulerInteraction *inter = mpr->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, mgroup, ruler_item); - ruler_item = NULL; - mpr = 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 manipulator, for now just re-generate. */ - view3d_ruler_to_gpencil(C, mgroup); - } - - if (mpr) { - MEM_SAFE_FREE(mpr->interaction_data); - } - - ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); -} - -static int manipulator_ruler_cursor_get(wmManipulator *mpr) -{ - if (mpr->highlight_part == PART_LINE) { - return BC_CROSSCURSOR; - } - return BC_NSEW_SCROLLCURSOR; -} - -void VIEW3D_WT_ruler_item(wmManipulatorType *wt) -{ - /* identifiers */ - wt->idname = "VIEW3D_WT_ruler_item"; - - /* api callbacks */ - wt->draw = manipulator_ruler_draw; - wt->test_select = manipulator_ruler_test_select; - wt->modal = manipulator_ruler_modal; - wt->invoke = manipulator_ruler_invoke; - wt->exit = manipulator_ruler_exit; - wt->cursor_get = manipulator_ruler_cursor_get; - - wt->struct_size = sizeof(RulerItem); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Ruler Manipulator Group - * \{ */ - -static bool WIDGETGROUP_ruler_poll(const bContext *C, wmManipulatorGroupType *wgt) -{ - bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); - if ((tref_rt == NULL) || - !STREQ(wgt->idname, tref_rt->manipulator_group)) - { - WM_manipulator_group_type_unlink_delayed_ptr(wgt); - return false; - } - return true; -} - -static void WIDGETGROUP_ruler_setup(const bContext *C, wmManipulatorGroup *mgroup) -{ - RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__); - - if (view3d_ruler_from_gpencil(C, mgroup)) { - /* 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; - - mgroup->customdata = ruler_info; -} - -void VIEW3D_WGT_ruler(wmManipulatorGroupType *wgt) -{ - wgt->name = "Ruler Widgets"; - wgt->idname = view3d_wgt_ruler_id; - - wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE | WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL; - - wgt->mmap_params.spaceid = SPACE_VIEW3D; - wgt->mmap_params.regionid = RGN_TYPE_WINDOW; - - wgt->poll = WIDGETGROUP_ruler_poll; - wgt->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_wgt_ruler_id, tref_rt->manipulator_group) || - CTX_wm_region_view3d(C) == NULL) - { - return false; - } - return true; -} - -static int view3d_ruler_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = ar->regiondata; - - wmManipulatorMap *mmap = ar->manipulator_map; - wmManipulatorGroup *mgroup = WM_manipulatormap_group_find(mmap, view3d_wgt_ruler_id); - const bool use_depth = (v3d->drawtype >= OB_SOLID); - - /* Create new line */ - RulerItem *ruler_item; - ruler_item = ruler_item_add(mgroup); - - /* This is a little weak, but there is no real good way to tweak directly. */ - WM_manipulator_highlight_set(mmap, &ruler_item->mpr); - if (WM_operator_name_call( - C, "MANIPULATORGROUP_OT_manipulator_tweak", - WM_OP_INVOKE_REGION_WIN, NULL) == OPERATOR_RUNNING_MODAL) - { - RulerInfo *ruler_info = mgroup->customdata; - RulerInteraction *inter = ruler_item->mpr.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->mpr.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->description = ""; - - ot->invoke = view3d_ruler_add_invoke; - ot->poll = view3d_ruler_poll; - - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; -} - -/** \} */ diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 3e132192875..45055eb1225 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -46,8 +46,8 @@ set(SRC transform_conversions.c transform_generics.c transform_input.c - transform_manipulator_2d.c - transform_manipulator_3d.c + transform_gizmo_2d.c + transform_gizmo_3d.c transform_ops.c transform_orientations.c transform_snap.c diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c new file mode 100644 index 00000000000..5d5d55de848 --- /dev/null +++ b/source/blender/editors/transform/transform_gizmo_2d.c @@ -0,0 +1,382 @@ +/* + * ***** 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/transform/transform_gizmo_2d.c + * \ingroup edtransform + * + * \name 2D Transform Manipulator + * + * Used for UV/Image Editor + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_context.h" +#include "BKE_editmesh.h" + +#include "RNA_access.h" + +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm.h" /* XXX */ + +#include "ED_image.h" +#include "ED_screen.h" +#include "ED_uvedit.h" +#include "ED_gizmo_library.h" + +#include "transform.h" /* own include */ + +/* axes as index */ +enum { + MAN2D_AXIS_TRANS_X = 0, + MAN2D_AXIS_TRANS_Y, + + MAN2D_AXIS_LAST, +}; + +typedef struct ManipulatorGroup2D { + wmManipulator *translate_x, + *translate_y; + + wmManipulator *cage; + + /* Current origin in view space, used to update widget origin for possible view changes */ + float origin[2]; + float min[2]; + float max[2]; + +} ManipulatorGroup2D; + + +/* **************** Utilities **************** */ + +/* loop over axes */ +#define MAN2D_ITER_AXES_BEGIN(axis, axis_idx) \ + { \ + wmManipulator *axis; \ + int axis_idx; \ + for (axis_idx = 0; axis_idx < MAN2D_AXIS_LAST; axis_idx++) { \ + axis = manipulator2d_get_axis_from_index(man, axis_idx); + +#define MAN2D_ITER_AXES_END \ + } \ + } ((void)0) + +static wmManipulator *manipulator2d_get_axis_from_index(const ManipulatorGroup2D *man, const short axis_idx) +{ + BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN2D_AXIS_TRANS_X, (float)MAN2D_AXIS_TRANS_Y)); + + switch (axis_idx) { + case MAN2D_AXIS_TRANS_X: + return man->translate_x; + case MAN2D_AXIS_TRANS_Y: + return man->translate_y; + } + + return NULL; +} + +static void manipulator2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi) +{ + const float alpha = 0.6f; + const float alpha_hi = 1.0f; + int col_id; + + switch (axis_idx) { + case MAN2D_AXIS_TRANS_X: + col_id = TH_AXIS_X; + break; + case MAN2D_AXIS_TRANS_Y: + col_id = TH_AXIS_Y; + break; + } + + UI_GetThemeColor4fv(col_id, r_col); + + copy_v4_v4(r_col_hi, r_col); + r_col[3] *= alpha; + r_col_hi[3] *= alpha_hi; +} + +static ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup) +{ + const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_2d", true); + const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_2d", true); + + ManipulatorGroup2D *man = MEM_callocN(sizeof(ManipulatorGroup2D), __func__); + + man->translate_x = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + man->translate_y = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); + man->cage = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); + + RNA_enum_set(man->cage->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE); + + return man; +} + +/** + * Calculates origin in view space, use with #manipulator2d_origin_to_region. + */ +static void manipulator2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Image *ima = ED_space_image(sima); + + float min_buf[2], max_buf[2]; + if (r_min == NULL) { + r_min = min_buf; + } + if (r_max == NULL) { + r_max = max_buf; + } + + if (!ED_uvedit_minmax(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_min, r_max)) { + zero_v2(r_min); + zero_v2(r_max); + } + mid_v2_v2v2(r_center, r_min, r_max); +} + +/** + * Convert origin (or any other point) from view to region space. + */ +BLI_INLINE void manipulator2d_origin_to_region(ARegion *ar, float *r_origin) +{ + UI_view2d_view_to_region_fl(&ar->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]); +} + +/** + * Custom handler for manipulator widgets + */ +static int manipulator2d_modal( + bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), + eWM_ManipulatorTweak UNUSED(tweak_flag)) +{ + ARegion *ar = CTX_wm_region(C); + float origin[3]; + + manipulator2d_calc_bounds(C, origin, NULL, NULL); + manipulator2d_origin_to_region(ar, origin); + WM_manipulator_set_matrix_location(widget, origin); + + ED_region_tag_redraw(ar); + + return OPERATOR_RUNNING_MODAL; +} + +void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true); + ManipulatorGroup2D *man = manipulatorgroup2d_init(mgroup); + mgroup->customdata = man; + + MAN2D_ITER_AXES_BEGIN(axis, axis_idx) + { + const float offset[3] = {0.0f, 0.2f}; + + float color[4], color_hi[4]; + manipulator2d_get_axis_color(axis_idx, color, color_hi); + + /* custom handler! */ + WM_manipulator_set_fn_custom_modal(axis, manipulator2d_modal); + /* set up widget data */ + RNA_float_set(axis->ptr, "angle", -M_PI_2 * axis_idx); + RNA_float_set(axis->ptr, "length", 0.8f); + WM_manipulator_set_matrix_offset_location(axis, offset); + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); + WM_manipulator_set_scale(axis, U.manipulator_size); + WM_manipulator_set_color(axis, color); + WM_manipulator_set_color_highlight(axis, color_hi); + + /* assign operator */ + PointerRNA *ptr = WM_manipulator_operator_set(axis, 0, ot_translate, NULL); + bool constraint[3] = {0}; + constraint[(axis_idx + 1) % 2] = 1; + if (RNA_struct_find_property(ptr, "constraint_axis")) + RNA_boolean_set_array(ptr, "constraint_axis", constraint); + RNA_boolean_set(ptr, "release_confirm", 1); + } + MAN2D_ITER_AXES_END; + + { + wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true); + wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true); + PointerRNA *ptr; + + /* assign operator */ + ptr = WM_manipulator_operator_set(man->cage, 0, ot_translate, NULL); + RNA_boolean_set(ptr, "release_confirm", 1); + + bool constraint_x[3] = {1, 0, 0}; + bool constraint_y[3] = {0, 1, 0}; + + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL); + PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm"); + PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis"); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE, ot_rotate, NULL); + RNA_property_boolean_set(ptr, prop_release_confirm, true); + } +} + +void ED_widgetgroup_manipulator2d_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorGroup2D *man = mgroup->customdata; + float origin[3]; + manipulator2d_calc_bounds(C, origin, man->min, man->max); + copy_v2_v2(man->origin, origin); + bool show_cage = !equals_v2v2(man->min, man->max); + + if (show_cage) { + man->cage->flag &= ~WM_MANIPULATOR_HIDDEN; + man->translate_x->flag |= WM_MANIPULATOR_HIDDEN; + man->translate_y->flag |= WM_MANIPULATOR_HIDDEN; + } + else { + man->cage->flag |= WM_MANIPULATOR_HIDDEN; + man->translate_x->flag &= ~WM_MANIPULATOR_HIDDEN; + man->translate_y->flag &= ~WM_MANIPULATOR_HIDDEN; + } + + if (show_cage) { + wmManipulatorOpElem *mpop; + float mid[2]; + const float *min = man->min; + const float *max = man->max; + mid_v2_v2v2(mid, min, max); + + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X); + PropertyRNA *prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override"); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f}); + + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f}); + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f}); + + mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f}); + } +} + +void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + ARegion *ar = CTX_wm_region(C); + ManipulatorGroup2D *man = mgroup->customdata; + float origin[3] = {UNPACK2(man->origin), 0.0f}; + float origin_aa[3] = {UNPACK2(man->origin), 0.0f}; + + manipulator2d_origin_to_region(ar, origin); + + MAN2D_ITER_AXES_BEGIN(axis, axis_idx) + { + WM_manipulator_set_matrix_location(axis, origin); + } + MAN2D_ITER_AXES_END; + + UI_view2d_view_to_region_m4(&ar->v2d, man->cage->matrix_space); + WM_manipulator_set_matrix_offset_location(man->cage, origin_aa); + man->cage->matrix_offset[0][0] = (man->max[0] - man->min[0]); + man->cage->matrix_offset[1][1] = (man->max[1] - man->min[1]); +} + +/* TODO (Julian) + * - Called on every redraw, better to do a more simple poll and check for selection in _refresh + * - UV editing only, could be expanded for other things. + */ +bool ED_widgetgroup_manipulator2d_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) +{ + if ((U.manipulator_flag & USER_MANIPULATOR_DRAW) == 0) { + return false; + } + + SpaceImage *sima = CTX_wm_space_image(C); + Object *obedit = CTX_data_edit_object(C); + + if (ED_space_image_show_uvedit(sima, obedit)) { + Image *ima = ED_space_image(sima); + Scene *scene = CTX_data_scene(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* check if there's a selected poly */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, obedit, ima, efa)) + continue; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + return true; + } + } + } + } + + return false; +} diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c new file mode 100644 index 00000000000..1a30bd1cdcb --- /dev/null +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -0,0 +1,1790 @@ +/* + * ***** 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/transform/transform_gizmo_3d.c + * \ingroup edtransform + * + * \name 3D Transform Manipulator + * + * Used for 3D View + */ + +#include +#include +#include +#include + +#include "DNA_armature_types.h" +#include "DNA_curve_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_lattice_types.h" +#include "DNA_meta_types.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_view3d_types.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "RNA_access.h" + +#include "BKE_action.h" +#include "BKE_context.h" +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_particle.h" +#include "BKE_pointcache.h" +#include "BKE_editmesh.h" +#include "BKE_lattice.h" +#include "BKE_gpencil.h" +#include "BKE_scene.h" +#include "BKE_workspace.h" + +#include "BIF_gl.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "WM_message.h" +#include "WM_toolsystem.h" + +#include "ED_armature.h" +#include "ED_curve.h" +#include "ED_object.h" +#include "ED_particle.h" +#include "ED_view3d.h" +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_gizmo_library.h" + +#include "UI_resources.h" + +/* local module include */ +#include "transform.h" + +#include "MEM_guardedalloc.h" + +#include "GPU_select.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" + +#include "DEG_depsgraph_query.h" + +/* return codes for select, and drawing flags */ + +#define MAN_TRANS_X (1 << 0) +#define MAN_TRANS_Y (1 << 1) +#define MAN_TRANS_Z (1 << 2) +#define MAN_TRANS_C (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z) + +#define MAN_ROT_X (1 << 3) +#define MAN_ROT_Y (1 << 4) +#define MAN_ROT_Z (1 << 5) +#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z) + +#define MAN_SCALE_X (1 << 8) +#define MAN_SCALE_Y (1 << 9) +#define MAN_SCALE_Z (1 << 10) +#define MAN_SCALE_C (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z) + +/* threshold for testing view aligned manipulator axis */ +struct { + float min, max; +} g_tw_axis_range[2] = { + /* Regular range */ + {0.02f, 0.1f}, + /* Use a different range because we flip the dot product, + * also the view aligned planes are harder to see so hiding early is preferred. */ + {0.175f, 0.25f}, +}; + +/* axes as index */ +enum { + MAN_AXIS_TRANS_X = 0, + MAN_AXIS_TRANS_Y, + MAN_AXIS_TRANS_Z, + MAN_AXIS_TRANS_C, + + MAN_AXIS_TRANS_XY, + MAN_AXIS_TRANS_YZ, + MAN_AXIS_TRANS_ZX, +#define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X +#define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1) + + MAN_AXIS_ROT_X, + MAN_AXIS_ROT_Y, + MAN_AXIS_ROT_Z, + MAN_AXIS_ROT_C, + MAN_AXIS_ROT_T, /* trackball rotation */ +#define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X +#define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1) + + MAN_AXIS_SCALE_X, + MAN_AXIS_SCALE_Y, + MAN_AXIS_SCALE_Z, + MAN_AXIS_SCALE_C, + MAN_AXIS_SCALE_XY, + MAN_AXIS_SCALE_YZ, + MAN_AXIS_SCALE_ZX, +#define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X +#define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1) + + MAN_AXIS_LAST = MAN_AXIS_RANGE_SCALE_END, +}; + +/* axis types */ +enum { + MAN_AXES_ALL = 0, + MAN_AXES_TRANSLATE, + MAN_AXES_ROTATE, + MAN_AXES_SCALE, +}; + +typedef struct ManipulatorGroup { + bool all_hidden; + int twtype; + + /* Users may change the twtype, detect changes to re-setup manipulator options. */ + int twtype_init; + int twtype_prev; + int use_twtype_refresh; + + struct wmManipulator *manipulators[MAN_AXIS_LAST]; +} ManipulatorGroup; + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +/* loop over axes */ +#define MAN_ITER_AXES_BEGIN(axis, axis_idx) \ + { \ + wmManipulator *axis; \ + int axis_idx; \ + for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \ + axis = manipulator_get_axis_from_index(man, axis_idx); + +#define MAN_ITER_AXES_END \ + } \ + } ((void)0) + +static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx) +{ + BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST)); + return man->manipulators[axis_idx]; +} + +static short manipulator_get_axis_type(const int axis_idx) +{ + if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { + return MAN_AXES_TRANSLATE; + } + if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) { + return MAN_AXES_ROTATE; + } + if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) { + return MAN_AXES_SCALE; + } + BLI_assert(0); + return -1; +} + +static uint manipulator_orientation_axis(const int axis_idx, bool *r_is_plane) +{ + switch (axis_idx) { + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + return 0; + + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + return 1; + + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + if (r_is_plane) { + *r_is_plane = true; + } + ATTR_FALLTHROUGH; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + return 2; + } + return 3; +} + +static bool manipulator_is_axis_visible( + const RegionView3D *rv3d, const int twtype, + const float idot[3], const int axis_type, const int axis_idx) +{ + if ((axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) == 0) { + bool is_plane = false; + const uint aidx_norm = manipulator_orientation_axis(axis_idx, &is_plane); + /* don't draw axis perpendicular to the view */ + if (aidx_norm < 3) { + float idot_axis = idot[aidx_norm]; + if (is_plane) { + idot_axis = 1.0f - idot_axis; + } + if (idot_axis < g_tw_axis_range[is_plane].min) { + return false; + } + } + } + + if ((axis_type == MAN_AXES_TRANSLATE && !(twtype & SCE_MANIP_TRANSLATE)) || + (axis_type == MAN_AXES_ROTATE && !(twtype & SCE_MANIP_ROTATE)) || + (axis_type == MAN_AXES_SCALE && !(twtype & SCE_MANIP_SCALE))) + { + return false; + } + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + return (rv3d->twdrawflag & MAN_TRANS_X); + case MAN_AXIS_TRANS_Y: + return (rv3d->twdrawflag & MAN_TRANS_Y); + case MAN_AXIS_TRANS_Z: + return (rv3d->twdrawflag & MAN_TRANS_Z); + case MAN_AXIS_TRANS_C: + return (rv3d->twdrawflag & MAN_TRANS_C); + case MAN_AXIS_ROT_X: + return (rv3d->twdrawflag & MAN_ROT_X); + case MAN_AXIS_ROT_Y: + return (rv3d->twdrawflag & MAN_ROT_Y); + case MAN_AXIS_ROT_Z: + return (rv3d->twdrawflag & MAN_ROT_Z); + case MAN_AXIS_ROT_C: + case MAN_AXIS_ROT_T: + return (rv3d->twdrawflag & MAN_ROT_C); + case MAN_AXIS_SCALE_X: + return (rv3d->twdrawflag & MAN_SCALE_X); + case MAN_AXIS_SCALE_Y: + return (rv3d->twdrawflag & MAN_SCALE_Y); + case MAN_AXIS_SCALE_Z: + return (rv3d->twdrawflag & MAN_SCALE_Z); + case MAN_AXIS_SCALE_C: + return (rv3d->twdrawflag & MAN_SCALE_C && (twtype & SCE_MANIP_TRANSLATE) == 0); + case MAN_AXIS_TRANS_XY: + return (rv3d->twdrawflag & MAN_TRANS_X && + rv3d->twdrawflag & MAN_TRANS_Y && + (twtype & SCE_MANIP_ROTATE) == 0); + case MAN_AXIS_TRANS_YZ: + return (rv3d->twdrawflag & MAN_TRANS_Y && + rv3d->twdrawflag & MAN_TRANS_Z && + (twtype & SCE_MANIP_ROTATE) == 0); + case MAN_AXIS_TRANS_ZX: + return (rv3d->twdrawflag & MAN_TRANS_Z && + rv3d->twdrawflag & MAN_TRANS_X && + (twtype & SCE_MANIP_ROTATE) == 0); + case MAN_AXIS_SCALE_XY: + return (rv3d->twdrawflag & MAN_SCALE_X && + rv3d->twdrawflag & MAN_SCALE_Y && + (twtype & SCE_MANIP_TRANSLATE) == 0 && + (twtype & SCE_MANIP_ROTATE) == 0); + case MAN_AXIS_SCALE_YZ: + return (rv3d->twdrawflag & MAN_SCALE_Y && + rv3d->twdrawflag & MAN_SCALE_Z && + (twtype & SCE_MANIP_TRANSLATE) == 0 && + (twtype & SCE_MANIP_ROTATE) == 0); + case MAN_AXIS_SCALE_ZX: + return (rv3d->twdrawflag & MAN_SCALE_Z && + rv3d->twdrawflag & MAN_SCALE_X && + (twtype & SCE_MANIP_TRANSLATE) == 0 && + (twtype & SCE_MANIP_ROTATE) == 0); + } + return false; +} + +static void manipulator_get_axis_color( + const int axis_idx, const float idot[3], + float r_col[4], float r_col_hi[4]) +{ + /* alpha values for normal/highlighted states */ + const float alpha = 0.6f; + const float alpha_hi = 1.0f; + float alpha_fac; + + if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) { + /* Never fade rotation rings. */ + /* trackball rotation axis is a special case, we only draw a slight overlay */ + alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f; + } + else { + bool is_plane = false; + const int axis_idx_norm = manipulator_orientation_axis(axis_idx, &is_plane); + /* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */ + if (axis_idx_norm < 3) { + const float idot_min = g_tw_axis_range[is_plane].min; + const float idot_max = g_tw_axis_range[is_plane].max; + float idot_axis = idot[axis_idx_norm]; + if (is_plane) { + idot_axis = 1.0f - idot_axis; + } + alpha_fac = ( + (idot_axis > idot_max) ? + 1.0f : (idot_axis < idot_min) ? + 0.0f : ((idot_axis - idot_min) / (idot_max - idot_min))); + } + else { + alpha_fac = 1.0f; + } + } + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + UI_GetThemeColor4fv(TH_AXIS_X, r_col); + break; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + UI_GetThemeColor4fv(TH_AXIS_Y, r_col); + break; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + UI_GetThemeColor4fv(TH_AXIS_Z, r_col); + break; + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + copy_v4_fl(r_col, 1.0f); + break; + } + + copy_v4_v4(r_col_hi, r_col); + + r_col[3] = alpha * alpha_fac; + r_col_hi[3] = alpha_hi * alpha_fac; +} + +static void manipulator_get_axis_constraint(const int axis_idx, bool r_axis[3]) +{ + ARRAY_SET_ITEMS(r_axis, 0, 0, 0); + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_ROT_X: + case MAN_AXIS_SCALE_X: + r_axis[0] = 1; + break; + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_SCALE_Y: + r_axis[1] = 1; + break; + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_ROT_Z: + case MAN_AXIS_SCALE_Z: + r_axis[2] = 1; + break; + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_SCALE_XY: + r_axis[0] = r_axis[1] = 1; + break; + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_SCALE_YZ: + r_axis[1] = r_axis[2] = 1; + break; + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_ZX: + r_axis[2] = r_axis[0] = 1; + break; + default: + break; + } +} + + +/* **************** Preparation Stuff **************** */ + +/* transform widget center calc helper for below */ +static void calc_tw_center(struct TransformBounds *tbounds, const float co[3]) +{ + minmax_v3v3_v3(tbounds->min, tbounds->max, co); + add_v3_v3(tbounds->center, co); + + for (int i = 0; i < 3; i++) { + const float d = dot_v3v3(tbounds->axis[i], co); + tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]); + tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]); + } +} + +static void protectflag_to_drawflags(short protectflag, short *drawflags) +{ + if (protectflag & OB_LOCK_LOCX) + *drawflags &= ~MAN_TRANS_X; + if (protectflag & OB_LOCK_LOCY) + *drawflags &= ~MAN_TRANS_Y; + if (protectflag & OB_LOCK_LOCZ) + *drawflags &= ~MAN_TRANS_Z; + + if (protectflag & OB_LOCK_ROTX) + *drawflags &= ~MAN_ROT_X; + if (protectflag & OB_LOCK_ROTY) + *drawflags &= ~MAN_ROT_Y; + if (protectflag & OB_LOCK_ROTZ) + *drawflags &= ~MAN_ROT_Z; + + if (protectflag & OB_LOCK_SCALEX) + *drawflags &= ~MAN_SCALE_X; + if (protectflag & OB_LOCK_SCALEY) + *drawflags &= ~MAN_SCALE_Y; + if (protectflag & OB_LOCK_SCALEZ) + *drawflags &= ~MAN_SCALE_Z; +} + +/* for pose mode */ +static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan) +{ + protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); +} + +/* for editmode*/ +static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo) +{ + if (ebo->flag & BONE_EDITMODE_LOCKED) { + protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag); + } +} + +/* could move into BLI_math however this is only useful for display/editing purposes */ +static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle) +{ + /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */ + + float cross_vec[3]; + float quat[4]; + + /* this is an un-scientific method to get a vector to cross with + * XYZ intentionally YZX */ + cross_vec[0] = axis[1]; + cross_vec[1] = axis[2]; + cross_vec[2] = axis[0]; + + /* X-axis */ + cross_v3_v3v3(gmat[0], cross_vec, axis); + normalize_v3(gmat[0]); + axis_angle_to_quat(quat, axis, angle); + mul_qt_v3(quat, gmat[0]); + + /* Y-axis */ + axis_angle_to_quat(quat, axis, M_PI_2); + copy_v3_v3(gmat[1], gmat[0]); + mul_qt_v3(quat, gmat[1]); + + /* Z-axis */ + copy_v3_v3(gmat[2], axis); + + normalize_m3(gmat); +} + + +static bool test_rotmode_euler(short rotmode) +{ + return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1; +} + +bool gimbal_axis(Object *ob, float gmat[3][3]) +{ + if (ob->mode & OB_MODE_POSE) { + bPoseChannel *pchan = BKE_pose_channel_active(ob); + + if (pchan) { + float mat[3][3], tmat[3][3], obmat[3][3]; + if (test_rotmode_euler(pchan->rotmode)) { + eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode); + } + else if (pchan->rotmode == ROT_MODE_AXISANGLE) { + axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle); + } + else { /* quat */ + return 0; + } + + + /* apply bone transformation */ + mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat); + + if (pchan->parent) { + float parent_mat[3][3]; + + copy_m3_m4(parent_mat, pchan->parent->pose_mat); + mul_m3_m3m3(mat, parent_mat, tmat); + + /* needed if object transformation isn't identity */ + copy_m3_m4(obmat, ob->obmat); + mul_m3_m3m3(gmat, obmat, mat); + } + else { + /* needed if object transformation isn't identity */ + copy_m3_m4(obmat, ob->obmat); + mul_m3_m3m3(gmat, obmat, tmat); + } + + normalize_m3(gmat); + return 1; + } + } + else { + if (test_rotmode_euler(ob->rotmode)) { + eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode); + } + else if (ob->rotmode == ROT_MODE_AXISANGLE) { + axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle); + } + else { /* quat */ + return 0; + } + + if (ob->parent) { + float parent_mat[3][3]; + copy_m3_m4(parent_mat, ob->parent->obmat); + normalize_m3(parent_mat); + mul_m3_m3m3(gmat, parent_mat, gmat); + } + return 1; + } + + return 0; +} + + +/* centroid, boundbox, of selection */ +/* returns total items selected */ +int ED_transform_calc_manipulator_stats( + const bContext *C, + const struct TransformCalcParams *params, + struct TransformBounds *tbounds) +{ + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obedit = CTX_data_edit_object(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + Base *base; + Object *ob = OBACT(view_layer); + bGPdata *gpd = CTX_data_gpencil_data(C); + const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); + int a, totsel = 0; + const int pivot_point = scene->toolsettings->transform_pivot_point; + + /* transform widget matrix */ + unit_m4(rv3d->twmat); + + unit_m3(rv3d->tw_axis_matrix); + zero_v3(rv3d->tw_axis_min); + zero_v3(rv3d->tw_axis_max); + + rv3d->twdrawflag = 0xFFFF; + + /* global, local or normal orientation? + * if we could check 'totsel' now, this should be skipped with no selection. */ + if (ob && !is_gp_edit) { + const short orientation_type = params->orientation_type ? (params->orientation_type - 1) : scene->orientation_type; + + switch (orientation_type) { + + case V3D_MANIP_GLOBAL: + { + break; /* nothing to do */ + } + case V3D_MANIP_GIMBAL: + { + float mat[3][3]; + if (gimbal_axis(ob, mat)) { + copy_m4_m3(rv3d->twmat, mat); + break; + } + /* if not gimbal, fall through to normal */ + ATTR_FALLTHROUGH; + } + case V3D_MANIP_NORMAL: + { + if (obedit || ob->mode & OB_MODE_POSE) { + float mat[3][3]; + ED_getTransformOrientationMatrix(C, mat, pivot_point); + copy_m4_m3(rv3d->twmat, mat); + break; + } + /* no break we define 'normal' as 'local' in Object mode */ + ATTR_FALLTHROUGH; + } + case V3D_MANIP_LOCAL: + { + if (ob->mode & OB_MODE_POSE) { + /* each bone moves on its own local axis, but to avoid confusion, + * use the active pones axis for display [#33575], this works as expected on a single bone + * and users who select many bones will understand whats going on and what local means + * when they start transforming */ + float mat[3][3]; + ED_getTransformOrientationMatrix(C, mat, pivot_point); + copy_m4_m3(rv3d->twmat, mat); + break; + } + copy_m4_m4(rv3d->twmat, ob->obmat); + normalize_m4(rv3d->twmat); + break; + } + case V3D_MANIP_VIEW: + { + float mat[3][3]; + copy_m3_m4(mat, rv3d->viewinv); + normalize_m3(mat); + copy_m4_m3(rv3d->twmat, mat); + break; + } + case V3D_MANIP_CURSOR: + { + float mat[3][3]; + ED_view3d_cursor3d_calc_mat3(scene, v3d, mat); + copy_m4_m3(rv3d->twmat, mat); + break; + } + case V3D_MANIP_CUSTOM: + { + TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find( + scene, scene->orientation_index_custom); + float mat[3][3]; + + if (applyTransformOrientation(custom_orientation, mat, NULL)) { + copy_m4_m3(rv3d->twmat, mat); + } + break; + } + } + } + + /* transform widget centroid/center */ + INIT_MINMAX(tbounds->min, tbounds->max); + zero_v3(tbounds->center); + + copy_m3_m4(tbounds->axis, rv3d->twmat); + if (params->use_local_axis && (ob && ob->mode & OB_MODE_EDIT)) { + float diff_mat[3][3]; + copy_m3_m4(diff_mat, ob->obmat); + normalize_m3(diff_mat); + invert_m3(diff_mat); + mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat); + normalize_m3(tbounds->axis); + } + + for (int i = 0; i < 3; i++) { + tbounds->axis_min[i] = +FLT_MAX; + tbounds->axis_max[i] = -FLT_MAX; + } + + if (is_gp_edit) { + float diff_mat[4][4]; + float fpt[3]; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* only editable and visible layers are considered */ + if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + + /* calculate difference matrix if parent object */ + if (gpl->parent != NULL) { + ED_gpencil_parent_location(gpl, diff_mat); + } + + for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + + /* we're only interested in selected points here... */ + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + + /* Change selection status of all points, then make the stroke match */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + if (gpl->parent == NULL) { + calc_tw_center(tbounds, &pt->x); + totsel++; + } + else { + mul_v3_m4v3(fpt, diff_mat, &pt->x); + calc_tw_center(tbounds, fpt); + totsel++; + } + } + } + } + } + } + } + + + /* selection center */ + if (totsel) { + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ + } + } + else if (obedit) { + ob = obedit; + if (obedit->type == OB_MESH) { + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMEditSelection ese; + float vec[3] = {0, 0, 0}; + + /* USE LAST SELECTE WITH ACTIVE */ + if ((pivot_point == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) { + BM_editselection_center(&ese, vec); + calc_tw_center(tbounds, vec); + totsel = 1; + } + else { + BMesh *bm = em->bm; + BMVert *eve; + + BMIter iter; + + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + totsel++; + calc_tw_center(tbounds, eve->co); + } + } + } + } + } /* end editmesh */ + else if (obedit->type == OB_ARMATURE) { + bArmature *arm = obedit->data; + EditBone *ebo; + + if ((pivot_point == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) { + /* doesn't check selection or visibility intentionally */ + if (ebo->flag & BONE_TIPSEL) { + calc_tw_center(tbounds, ebo->tail); + totsel++; + } + if ((ebo->flag & BONE_ROOTSEL) || + ((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */ + { + calc_tw_center(tbounds, ebo->head); + totsel++; + } + protectflag_to_drawflags_ebone(rv3d, ebo); + } + else { + for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { + if (EBONE_VISIBLE(arm, ebo)) { + if (ebo->flag & BONE_TIPSEL) { + calc_tw_center(tbounds, ebo->tail); + totsel++; + } + if ((ebo->flag & BONE_ROOTSEL) && + /* don't include same point multiple times */ + ((ebo->flag & BONE_CONNECTED) && + (ebo->parent != NULL) && + (ebo->parent->flag & BONE_TIPSEL) && + EBONE_VISIBLE(arm, ebo->parent)) == 0) + { + calc_tw_center(tbounds, ebo->head); + totsel++; + } + if (ebo->flag & BONE_SELECTED) { + protectflag_to_drawflags_ebone(rv3d, ebo); + } + } + } + } + } + else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { + Curve *cu = obedit->data; + float center[3]; + + if ((pivot_point == V3D_AROUND_ACTIVE) && ED_curve_active_center(cu, center)) { + calc_tw_center(tbounds, center); + totsel++; + } + else { + Nurb *nu; + BezTriple *bezt; + BPoint *bp; + ListBase *nurbs = BKE_curve_editNurbs_get(cu); + + nu = nurbs->first; + while (nu) { + if (nu->type == CU_BEZIER) { + bezt = nu->bezt; + a = nu->pntsu; + while (a--) { + /* exceptions + * if handles are hidden then only check the center points. + * If the center knot is selected then only use this as the center point. + */ + if (cu->drawflag & CU_HIDE_HANDLES) { + if (bezt->f2 & SELECT) { + calc_tw_center(tbounds, bezt->vec[1]); + totsel++; + } + } + else if (bezt->f2 & SELECT) { + calc_tw_center(tbounds, bezt->vec[1]); + totsel++; + } + else { + if (bezt->f1 & SELECT) { + calc_tw_center( + tbounds, bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); + totsel++; + } + if (bezt->f3 & SELECT) { + calc_tw_center( + tbounds, bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); + totsel++; + } + } + bezt++; + } + } + else { + bp = nu->bp; + a = nu->pntsu * nu->pntsv; + while (a--) { + if (bp->f1 & SELECT) { + calc_tw_center(tbounds, bp->vec); + totsel++; + } + bp++; + } + } + nu = nu->next; + } + } + } + else if (obedit->type == OB_MBALL) { + MetaBall *mb = (MetaBall *)obedit->data; + MetaElem *ml; + + if ((pivot_point == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) { + calc_tw_center(tbounds, &ml->x); + totsel++; + } + else { + for (ml = mb->editelems->first; ml; ml = ml->next) { + if (ml->flag & SELECT) { + calc_tw_center(tbounds, &ml->x); + totsel++; + } + } + } + } + else if (obedit->type == OB_LATTICE) { + Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt; + BPoint *bp; + + if ((pivot_point == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) { + calc_tw_center(tbounds, bp->vec); + totsel++; + } + else { + bp = lt->def; + a = lt->pntsu * lt->pntsv * lt->pntsw; + while (a--) { + if (bp->f1 & SELECT) { + calc_tw_center(tbounds, bp->vec); + totsel++; + } + bp++; + } + } + } + + /* selection center */ + if (totsel) { + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! + mul_m4_v3(obedit->obmat, tbounds->center); + mul_m4_v3(obedit->obmat, tbounds->min); + mul_m4_v3(obedit->obmat, tbounds->max); + } + } + else if (ob && (ob->mode & OB_MODE_POSE)) { + bPoseChannel *pchan; + int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed + bool ok = false; + + if ((pivot_point == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) { + /* doesn't check selection or visibility intentionally */ + Bone *bone = pchan->bone; + if (bone) { + calc_tw_center(tbounds, pchan->pose_head); + protectflag_to_drawflags_pchan(rv3d, pchan); + totsel = 1; + ok = true; + } + } + else { + totsel = count_set_pose_transflags(ob, mode, V3D_AROUND_CENTER_BOUNDS, NULL); + + if (totsel) { + /* use channels to get stats */ + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + Bone *bone = pchan->bone; + if (bone && (bone->flag & BONE_TRANSFORM)) { + calc_tw_center(tbounds, pchan->pose_head); + protectflag_to_drawflags_pchan(rv3d, pchan); + } + } + ok = true; + } + } + + if (ok) { + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! + mul_m4_v3(ob->obmat, tbounds->center); + mul_m4_v3(ob->obmat, tbounds->min); + mul_m4_v3(ob->obmat, tbounds->max); + } + } + else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { + /* pass */ + } + else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) { + PTCacheEdit *edit = PE_get_current(scene, ob); + PTCacheEditPoint *point; + PTCacheEditKey *ek; + int k; + + if (edit) { + point = edit->points; + for (a = 0; a < edit->totpoint; a++, point++) { + if (point->flag & PEP_HIDE) continue; + + for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) { + if (ek->flag & PEK_SELECT) { + calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); + totsel++; + } + } + } + + /* selection center */ + if (totsel) + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! + } + } + else { + + /* we need the one selected object, if its not active */ + base = BASACT(view_layer); + ob = OBACT(view_layer); + if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL; + + for (base = view_layer->object_bases.first; base; base = base->next) { + if (!TESTBASELIB(base)) { + continue; + } + if (ob == NULL) { + ob = base->object; + } + if (params->use_only_center || base->object->bb == NULL) { + calc_tw_center(tbounds, base->object->obmat[3]); + } + else { + for (uint j = 0; j < 8; j++) { + float co[3]; + mul_v3_m4v3(co, base->object->obmat, base->object->bb->vec[j]); + calc_tw_center(tbounds, co); + } + } + protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); + totsel++; + } + + /* selection center */ + if (totsel) { + mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! + } + } + + if (totsel == 0) { + unit_m4(rv3d->twmat); + } + else { + copy_v3_v3(rv3d->tw_axis_min, tbounds->axis_min); + copy_v3_v3(rv3d->tw_axis_max, tbounds->axis_max); + copy_m3_m3(rv3d->tw_axis_matrix, tbounds->axis); + } + + return totsel; +} + +static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3]) +{ + float view_vec[3], axis_vec[3]; + ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec); + for (int i = 0; i < 3; i++) { + normalize_v3_v3(axis_vec, rv3d->twmat[i]); + r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec)); + } +} + +static void manipulator_prepare_mat( + const bContext *C, View3D *v3d, RegionView3D *rv3d, const struct TransformBounds *tbounds) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + switch (scene->toolsettings->transform_pivot_point) { + case V3D_AROUND_CENTER_BOUNDS: + case V3D_AROUND_ACTIVE: + { + bGPdata *gpd = CTX_data_gpencil_data(C); + Object *ob = OBACT(view_layer); + + if (((scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) && + (OBEDIT_FROM_OBACT(ob) == NULL)) && + ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && + (!(ob->mode & OB_MODE_POSE))) + { + copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); + } + else { + mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max); + } + break; + } + case V3D_AROUND_LOCAL_ORIGINS: + case V3D_AROUND_CENTER_MEAN: + copy_v3_v3(rv3d->twmat[3], tbounds->center); + break; + case V3D_AROUND_CURSOR: + copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)->location); + break; + } +} + +/** + * Sets up \a r_start and \a r_len to define arrow line range. + * Needed to adjust line drawing for combined manipulator axis types. + */ +static void manipulator_line_range(const int twtype, const short axis_type, float *r_start, float *r_len) +{ + const float ofs = 0.2f; + + *r_start = 0.2f; + *r_len = 1.0f; + + switch (axis_type) { + case MAN_AXES_TRANSLATE: + if (twtype & SCE_MANIP_SCALE) { + *r_start = *r_len - ofs + 0.075f; + } + if (twtype & SCE_MANIP_ROTATE) { + *r_len += ofs; + } + break; + case MAN_AXES_SCALE: + if (twtype & (SCE_MANIP_TRANSLATE | SCE_MANIP_ROTATE)) { + *r_len -= ofs + 0.025f; + } + break; + } + + *r_len -= *r_start; +} + +static void manipulator_xform_message_subscribe( + wmManipulatorGroup *mgroup, struct wmMsgBus *mbus, + Scene *scene, bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar, const void *type_fn) +{ + /* Subscribe to view properties */ + wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { + .owner = ar, + .user_data = mgroup->parent_mmap, + .notify = WM_manipulator_do_msg_notify_tag_refresh, + }; + + PointerRNA scene_ptr; + RNA_id_pointer_create(&scene->id, &scene_ptr); + + { + extern PropertyRNA rna_Scene_transform_orientation; + extern PropertyRNA rna_Scene_cursor_location; + const PropertyRNA *props[] = { + &rna_Scene_transform_orientation, + (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) ? &rna_Scene_cursor_location : NULL, + }; + for (int i = 0; i < ARRAY_SIZE(props); i++) { + if (props[i]) { + WM_msg_subscribe_rna(mbus, &scene_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); + } + } + } + + PointerRNA toolsettings_ptr; + RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr); + + if (type_fn == TRANSFORM_WGT_manipulator) { + extern PropertyRNA rna_ToolSettings_transform_pivot_point; + extern PropertyRNA rna_ToolSettings_use_manipulator_mode; + const PropertyRNA *props[] = { + &rna_ToolSettings_transform_pivot_point, + &rna_ToolSettings_use_manipulator_mode, + }; + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &toolsettings_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); + } + } + else if (type_fn == VIEW3D_WGT_xform_cage) { + /* pass */ + } + else { + BLI_assert(0); + } + + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_mpr_tag_refresh); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Transform Manipulator + * \{ */ + +static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man; + + man = MEM_callocN(sizeof(ManipulatorGroup), "manipulator_data"); + + const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true); + const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true); + const wmManipulatorType *wt_prim = WM_manipulatortype_find("MANIPULATOR_WT_primitive_3d", true); + +#define MANIPULATOR_NEW_ARROW(v, draw_style) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ +} ((void)0) +#define MANIPULATOR_NEW_DIAL(v, draw_options) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \ +} ((void)0) +#define MANIPULATOR_NEW_PRIM(v, draw_style) { \ + man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \ + RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ +} ((void)0) + + /* add/init widgets - order matters! */ + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_T, ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL); + + MANIPULATOR_NEW_DIAL(MAN_AXIS_SCALE_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); + + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_X, ED_MANIPULATOR_ARROW_STYLE_BOX); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_MANIPULATOR_ARROW_STYLE_BOX); + MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_MANIPULATOR_ARROW_STYLE_BOX); + + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_X, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Y, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Z, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); + + /* init screen aligned widget last here, looks better, behaves better */ + MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); + + MANIPULATOR_NEW_DIAL(MAN_AXIS_TRANS_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); + + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_X, ED_MANIPULATOR_ARROW_STYLE_NORMAL); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_MANIPULATOR_ARROW_STYLE_NORMAL); + MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_MANIPULATOR_ARROW_STYLE_NORMAL); + + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); + + man->manipulators[MAN_AXIS_ROT_T]->flag |= WM_MANIPULATOR_SELECT_BACKGROUND; + + return man; +} + +/** + * Custom handler for manipulator widgets + */ +static int manipulator_modal( + bContext *C, wmManipulator *widget, const wmEvent *event, + eWM_ManipulatorTweak UNUSED(tweak_flag)) +{ + /* Avoid unnecessary updates, partially address: T55458. */ + if (ELEM(event->type, TIMER, INBETWEEN_MOUSEMOVE)) { + return OPERATOR_RUNNING_MODAL; + } + + const ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + struct TransformBounds tbounds; + + + if (ED_transform_calc_manipulator_stats( + C, &(struct TransformCalcParams){ + .use_only_center = true, + }, &tbounds)) + { + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); + WM_manipulator_set_matrix_location(widget, rv3d->twmat[3]); + } + + ED_region_tag_redraw(ar); + + return OPERATOR_RUNNING_MODAL; +} + +static void manipulatorgroup_init_properties_from_twtype(wmManipulatorGroup *mgroup) +{ + struct { + wmOperatorType *translate, *rotate, *trackball, *resize; + } ot_store = {NULL}; + ManipulatorGroup *man = mgroup->customdata; + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + const short axis_type = manipulator_get_axis_type(axis_idx); + bool constraint_axis[3] = {1, 0, 0}; + PointerRNA *ptr; + + manipulator_get_axis_constraint(axis_idx, constraint_axis); + + /* custom handler! */ + WM_manipulator_set_fn_custom_modal(axis, manipulator_modal); + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_SCALE_X: + case MAN_AXIS_SCALE_Y: + case MAN_AXIS_SCALE_Z: + if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { + int draw_options = 0; + if ((man->twtype & (SCE_MANIP_ROTATE | SCE_MANIP_SCALE)) == 0) { + draw_options |= ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM; + } + RNA_enum_set(axis->ptr, "draw_options", draw_options); + } + + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); + break; + case MAN_AXIS_ROT_X: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_ROT_Z: + /* increased line width for better display */ + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH + 1.0f); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true); + break; + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_XY: + case MAN_AXIS_SCALE_YZ: + case MAN_AXIS_SCALE_ZX: + { + const float ofs_ax = 7.0f; + const float ofs[3] = {ofs_ax, ofs_ax, 0.0f}; + WM_manipulator_set_scale(axis, 0.07f); + WM_manipulator_set_matrix_offset_location(axis, ofs); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); + break; + } + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); + if (axis_idx == MAN_AXIS_ROT_T) { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_HOVER, true); + } + else if (axis_idx == MAN_AXIS_ROT_C) { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true); + WM_manipulator_set_scale(axis, 1.2f); + } + else { + WM_manipulator_set_scale(axis, 0.2f); + } + break; + } + + switch (axis_type) { + case MAN_AXES_TRANSLATE: + if (ot_store.translate == NULL) { + ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true); + } + ptr = WM_manipulator_operator_set(axis, 0, ot_store.translate, NULL); + break; + case MAN_AXES_ROTATE: + { + wmOperatorType *ot_rotate; + if (axis_idx == MAN_AXIS_ROT_T) { + if (ot_store.trackball == NULL) { + ot_store.trackball = WM_operatortype_find("TRANSFORM_OT_trackball", true); + } + ot_rotate = ot_store.trackball; + } + else { + if (ot_store.rotate == NULL) { + ot_store.rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true); + } + ot_rotate = ot_store.rotate; + } + ptr = WM_manipulator_operator_set(axis, 0, ot_rotate, NULL); + break; + } + case MAN_AXES_SCALE: + { + if (ot_store.resize == NULL) { + ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true); + } + ptr = WM_manipulator_operator_set(axis, 0, ot_store.resize, NULL); + break; + } + } + + { + PropertyRNA *prop; + if ((prop = RNA_struct_find_property(ptr, "constraint_axis"))) { + RNA_property_boolean_set_array(ptr, prop, constraint_axis); + } + } + + RNA_boolean_set(ptr, "release_confirm", 1); + } + MAN_ITER_AXES_END; +} + +static void WIDGETGROUP_manipulator_setup(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man = manipulatorgroup_init(mgroup); + + mgroup->customdata = man; + + { + man->twtype = 0; + ScrArea *sa = CTX_wm_area(C); + const bToolRef *tref = sa->runtime.tool; + + if (tref == NULL || STREQ(tref->idname, "Transform")) { + /* Setup all manipulators, they can be toggled via 'ToolSettings.manipulator_flag' */ + man->twtype = SCE_MANIP_TRANSLATE | SCE_MANIP_ROTATE | SCE_MANIP_SCALE; + man->use_twtype_refresh = true; + } + else if (STREQ(tref->idname, "Grab")) { + man->twtype |= SCE_MANIP_TRANSLATE; + } + else if (STREQ(tref->idname, "Rotate")) { + man->twtype |= SCE_MANIP_ROTATE; + } + else if (STREQ(tref->idname, "Scale")) { + man->twtype |= SCE_MANIP_SCALE; + } + BLI_assert(man->twtype != 0); + man->twtype_init = man->twtype; + } + + /* *** set properties for axes *** */ + manipulatorgroup_init_properties_from_twtype(mgroup); +} + +static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man = mgroup->customdata; + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + struct TransformBounds tbounds; + + if (man->use_twtype_refresh) { + Scene *scene = CTX_data_scene(C); + man->twtype = scene->toolsettings->manipulator_flag & man->twtype_init; + if (man->twtype != man->twtype_prev) { + man->twtype_prev = man->twtype; + manipulatorgroup_init_properties_from_twtype(mgroup); + } + } + + /* skip, we don't draw anything anyway */ + if ((man->all_hidden = + (ED_transform_calc_manipulator_stats( + C, &(struct TransformCalcParams){ + .use_only_center = true, + }, &tbounds) == 0))) + { + return; + } + + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); + + /* *** set properties for axes *** */ + + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + const short axis_type = manipulator_get_axis_type(axis_idx); + const int aidx_norm = manipulator_orientation_axis(axis_idx, NULL); + + WM_manipulator_set_matrix_location(axis, rv3d->twmat[3]); + + switch (axis_idx) { + case MAN_AXIS_TRANS_X: + case MAN_AXIS_TRANS_Y: + case MAN_AXIS_TRANS_Z: + case MAN_AXIS_SCALE_X: + case MAN_AXIS_SCALE_Y: + case MAN_AXIS_SCALE_Z: + { + float start_co[3] = {0.0f, 0.0f, 0.0f}; + float len; + + manipulator_line_range(man->twtype, axis_type, &start_co[2], &len); + + WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); + RNA_float_set(axis->ptr, "length", len); + + if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { + if (man->twtype & SCE_MANIP_ROTATE) { + /* Avoid rotate and translate arrows overlap. */ + start_co[2] += 0.215f; + } + } + WM_manipulator_set_matrix_offset_location(axis, start_co); + WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); + break; + } + case MAN_AXIS_ROT_X: + case MAN_AXIS_ROT_Y: + case MAN_AXIS_ROT_Z: + WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); + break; + case MAN_AXIS_TRANS_XY: + case MAN_AXIS_TRANS_YZ: + case MAN_AXIS_TRANS_ZX: + case MAN_AXIS_SCALE_XY: + case MAN_AXIS_SCALE_YZ: + case MAN_AXIS_SCALE_ZX: + { + const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1]; + const float *z_axis = rv3d->twmat[aidx_norm]; + WM_manipulator_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis); + break; + } + } + } + MAN_ITER_AXES_END; +} + +static void WIDGETGROUP_manipulator_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + Scene *scene = CTX_data_scene(C); + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + manipulator_xform_message_subscribe(mgroup, mbus, scene, screen, sa, ar, TRANSFORM_WGT_manipulator); +} + +static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + ManipulatorGroup *man = mgroup->customdata; + // ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + // View3D *v3d = sa->spacedata.first; + RegionView3D *rv3d = ar->regiondata; + float idot[3]; + + /* when looking through a selected camera, the manipulator can be at the + * exact same position as the view, skip so we don't break selection */ + if (man->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) { + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true); + } + MAN_ITER_AXES_END; + return; + } + manipulator_get_idot(rv3d, idot); + + /* *** set properties for axes *** */ + + MAN_ITER_AXES_BEGIN(axis, axis_idx) + { + const short axis_type = manipulator_get_axis_type(axis_idx); + /* XXX maybe unset _HIDDEN flag on redraw? */ + if (manipulator_is_axis_visible(rv3d, man->twtype, idot, axis_type, axis_idx)) { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false); + } + else { + WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true); + continue; + } + + float color[4], color_hi[4]; + manipulator_get_axis_color(axis_idx, idot, color, color_hi); + WM_manipulator_set_color(axis, color); + WM_manipulator_set_color_highlight(axis, color_hi); + + switch (axis_idx) { + case MAN_AXIS_TRANS_C: + case MAN_AXIS_ROT_C: + case MAN_AXIS_SCALE_C: + case MAN_AXIS_ROT_T: + WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]); + break; + } + } + MAN_ITER_AXES_END; +} + +static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *wgt) +{ + /* it's a given we only use this in 3D view */ + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); + if ((tref_rt == NULL) || + !STREQ(wgt->idname, tref_rt->manipulator_group)) + { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; + } + + View3D *v3d = CTX_wm_view3d(C); + if (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_HIDE_TOOL)) { + return false; + } + return true; +} + +void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt) +{ + wgt->name = "Transform Manipulator"; + wgt->idname = "TRANSFORM_WGT_manipulator"; + + wgt->flag |= WM_MANIPULATORGROUPTYPE_3D; + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + + wgt->poll = WIDGETGROUP_manipulator_poll; + wgt->setup = WIDGETGROUP_manipulator_setup; + wgt->refresh = WIDGETGROUP_manipulator_refresh; + wgt->message_subscribe = WIDGETGROUP_manipulator_message_subscribe; + wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/** \name Scale Cage Manipulator + * \{ */ + +struct XFormCageWidgetGroup { + wmManipulator *manipulator; +}; + +static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmManipulatorGroupType *wgt) +{ + bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); + if (!STREQ(wgt->idname, tref_rt->manipulator_group)) { + WM_manipulator_group_type_unlink_delayed_ptr(wgt); + return false; + } + return true; +} + +static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) +{ + struct XFormCageWidgetGroup *xmgroup = MEM_mallocN(sizeof(struct XFormCageWidgetGroup), __func__); + const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_3d", true); + xmgroup->manipulator = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); + wmManipulator *mpr = xmgroup->manipulator; + + RNA_enum_set(mpr->ptr, "transform", + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | + ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE); + + mpr->color[0] = 1; + mpr->color_hi[0] = 1; + + mgroup->customdata = xmgroup; + + { + wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true); + PointerRNA *ptr; + + /* assign operator */ + PropertyRNA *prop_release_confirm = NULL; + PropertyRNA *prop_constraint_axis = NULL; + + int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; + for (int x = 0; x < 3; x++) { + for (int y = 0; y < 3; y++) { + for (int z = 0; z < 3; z++) { + bool constraint[3] = {x != 1, y != 1, z != 1}; + ptr = WM_manipulator_operator_set(mpr, i, ot_resize, NULL); + if (prop_release_confirm == NULL) { + prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm"); + prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis"); + } + RNA_property_boolean_set(ptr, prop_release_confirm, true); + RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint); + i++; + } + } + } + } +} + +static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup *mgroup) +{ + ScrArea *sa = CTX_wm_area(C); + View3D *v3d = sa->spacedata.first; + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; + wmManipulator *mpr = xmgroup->manipulator; + + struct TransformBounds tbounds; + + if ((ED_transform_calc_manipulator_stats( + C, &(struct TransformCalcParams) { + .use_local_axis = true, + }, &tbounds) == 0) || + equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) + { + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); + } + else { + manipulator_prepare_mat(C, v3d, rv3d, &tbounds); + + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); + WM_manipulator_set_flag(mpr, WM_MANIPULATOR_GRAB_CURSOR, true); + + float dims[3]; + sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min); + RNA_float_set_array(mpr->ptr, "dimensions", dims); + mul_v3_fl(dims, 0.5f); + + copy_m4_m3(mpr->matrix_offset, rv3d->tw_axis_matrix); + mid_v3_v3v3(mpr->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min); + mul_m3_v3(rv3d->tw_axis_matrix, mpr->matrix_offset[3]); + + PropertyRNA *prop_center_override = NULL; + float center[3]; + float center_global[3]; + int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; + for (int x = 0; x < 3; x++) { + center[0] = (float)(1 - x) * dims[0]; + for (int y = 0; y < 3; y++) { + center[1] = (float)(1 - y) * dims[1]; + for (int z = 0; z < 3; z++) { + center[2] = (float)(1 - z) * dims[2]; + struct wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, i); + if (prop_center_override == NULL) { + prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override"); + } + mul_v3_m4v3(center_global, mpr->matrix_offset, center); + RNA_property_float_set_array(&mpop->ptr, prop_center_override, center_global); + i++; + } + } + } + } +} + +static void WIDGETGROUP_xform_cage_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + Scene *scene = CTX_data_scene(C); + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + manipulator_xform_message_subscribe(mgroup, mbus, scene, screen, sa, ar, VIEW3D_WGT_xform_cage); +} + +static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) +{ + struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; + wmManipulator *mpr = xmgroup->manipulator; + + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + if (ob && ob->mode & OB_MODE_EDIT) { + copy_m4_m4(mpr->matrix_space, ob->obmat); + } + else { + unit_m4(mpr->matrix_space); + } +} + +void VIEW3D_WGT_xform_cage(wmManipulatorGroupType *wgt) +{ + wgt->name = "Transform Cage"; + wgt->idname = "VIEW3D_WGT_xform_cage"; + + wgt->flag |= WM_MANIPULATORGROUPTYPE_3D; + + wgt->mmap_params.spaceid = SPACE_VIEW3D; + wgt->mmap_params.regionid = RGN_TYPE_WINDOW; + + wgt->poll = WIDGETGROUP_xform_cage_poll; + wgt->setup = WIDGETGROUP_xform_cage_setup; + wgt->refresh = WIDGETGROUP_xform_cage_refresh; + wgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe; + wgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare; +} + +/** \} */ diff --git a/source/blender/editors/transform/transform_manipulator_2d.c b/source/blender/editors/transform/transform_manipulator_2d.c deleted file mode 100644 index fd6e7ed5442..00000000000 --- a/source/blender/editors/transform/transform_manipulator_2d.c +++ /dev/null @@ -1,382 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/transform/transform_manipulator_2d.c - * \ingroup edtransform - * - * \name 2D Transform Manipulator - * - * Used for UV/Image Editor - */ - -#include "MEM_guardedalloc.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" - -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_view3d_types.h" - -#include "BKE_context.h" -#include "BKE_editmesh.h" - -#include "RNA_access.h" - -#include "UI_resources.h" -#include "UI_view2d.h" - -#include "WM_api.h" -#include "WM_types.h" -#include "wm.h" /* XXX */ - -#include "ED_image.h" -#include "ED_screen.h" -#include "ED_uvedit.h" -#include "ED_manipulator_library.h" - -#include "transform.h" /* own include */ - -/* axes as index */ -enum { - MAN2D_AXIS_TRANS_X = 0, - MAN2D_AXIS_TRANS_Y, - - MAN2D_AXIS_LAST, -}; - -typedef struct ManipulatorGroup2D { - wmManipulator *translate_x, - *translate_y; - - wmManipulator *cage; - - /* Current origin in view space, used to update widget origin for possible view changes */ - float origin[2]; - float min[2]; - float max[2]; - -} ManipulatorGroup2D; - - -/* **************** Utilities **************** */ - -/* loop over axes */ -#define MAN2D_ITER_AXES_BEGIN(axis, axis_idx) \ - { \ - wmManipulator *axis; \ - int axis_idx; \ - for (axis_idx = 0; axis_idx < MAN2D_AXIS_LAST; axis_idx++) { \ - axis = manipulator2d_get_axis_from_index(man, axis_idx); - -#define MAN2D_ITER_AXES_END \ - } \ - } ((void)0) - -static wmManipulator *manipulator2d_get_axis_from_index(const ManipulatorGroup2D *man, const short axis_idx) -{ - BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN2D_AXIS_TRANS_X, (float)MAN2D_AXIS_TRANS_Y)); - - switch (axis_idx) { - case MAN2D_AXIS_TRANS_X: - return man->translate_x; - case MAN2D_AXIS_TRANS_Y: - return man->translate_y; - } - - return NULL; -} - -static void manipulator2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi) -{ - const float alpha = 0.6f; - const float alpha_hi = 1.0f; - int col_id; - - switch (axis_idx) { - case MAN2D_AXIS_TRANS_X: - col_id = TH_AXIS_X; - break; - case MAN2D_AXIS_TRANS_Y: - col_id = TH_AXIS_Y; - break; - } - - UI_GetThemeColor4fv(col_id, r_col); - - copy_v4_v4(r_col_hi, r_col); - r_col[3] *= alpha; - r_col_hi[3] *= alpha_hi; -} - -static ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup) -{ - const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_2d", true); - const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_2d", true); - - ManipulatorGroup2D *man = MEM_callocN(sizeof(ManipulatorGroup2D), __func__); - - man->translate_x = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); - man->translate_y = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); - man->cage = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); - - RNA_enum_set(man->cage->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE | - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE); - - return man; -} - -/** - * Calculates origin in view space, use with #manipulator2d_origin_to_region. - */ -static void manipulator2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max) -{ - SpaceImage *sima = CTX_wm_space_image(C); - Image *ima = ED_space_image(sima); - - float min_buf[2], max_buf[2]; - if (r_min == NULL) { - r_min = min_buf; - } - if (r_max == NULL) { - r_max = max_buf; - } - - if (!ED_uvedit_minmax(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_min, r_max)) { - zero_v2(r_min); - zero_v2(r_max); - } - mid_v2_v2v2(r_center, r_min, r_max); -} - -/** - * Convert origin (or any other point) from view to region space. - */ -BLI_INLINE void manipulator2d_origin_to_region(ARegion *ar, float *r_origin) -{ - UI_view2d_view_to_region_fl(&ar->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]); -} - -/** - * Custom handler for manipulator widgets - */ -static int manipulator2d_modal( - bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event), - eWM_ManipulatorTweak UNUSED(tweak_flag)) -{ - ARegion *ar = CTX_wm_region(C); - float origin[3]; - - manipulator2d_calc_bounds(C, origin, NULL, NULL); - manipulator2d_origin_to_region(ar, origin); - WM_manipulator_set_matrix_location(widget, origin); - - ED_region_tag_redraw(ar); - - return OPERATOR_RUNNING_MODAL; -} - -void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) -{ - wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true); - ManipulatorGroup2D *man = manipulatorgroup2d_init(mgroup); - mgroup->customdata = man; - - MAN2D_ITER_AXES_BEGIN(axis, axis_idx) - { - const float offset[3] = {0.0f, 0.2f}; - - float color[4], color_hi[4]; - manipulator2d_get_axis_color(axis_idx, color, color_hi); - - /* custom handler! */ - WM_manipulator_set_fn_custom_modal(axis, manipulator2d_modal); - /* set up widget data */ - RNA_float_set(axis->ptr, "angle", -M_PI_2 * axis_idx); - RNA_float_set(axis->ptr, "length", 0.8f); - WM_manipulator_set_matrix_offset_location(axis, offset); - WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); - WM_manipulator_set_scale(axis, U.manipulator_size); - WM_manipulator_set_color(axis, color); - WM_manipulator_set_color_highlight(axis, color_hi); - - /* assign operator */ - PointerRNA *ptr = WM_manipulator_operator_set(axis, 0, ot_translate, NULL); - bool constraint[3] = {0}; - constraint[(axis_idx + 1) % 2] = 1; - if (RNA_struct_find_property(ptr, "constraint_axis")) - RNA_boolean_set_array(ptr, "constraint_axis", constraint); - RNA_boolean_set(ptr, "release_confirm", 1); - } - MAN2D_ITER_AXES_END; - - { - wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true); - wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true); - PointerRNA *ptr; - - /* assign operator */ - ptr = WM_manipulator_operator_set(man->cage, 0, ot_translate, NULL); - RNA_boolean_set(ptr, "release_confirm", 1); - - bool constraint_x[3] = {1, 0, 0}; - bool constraint_y[3] = {0, 1, 0}; - - ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL); - PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm"); - PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis"); - RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x); - RNA_property_boolean_set(ptr, prop_release_confirm, true); - ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL); - RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x); - RNA_property_boolean_set(ptr, prop_release_confirm, true); - ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL); - RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y); - RNA_property_boolean_set(ptr, prop_release_confirm, true); - ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL); - RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y); - RNA_property_boolean_set(ptr, prop_release_confirm, true); - - ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL); - RNA_property_boolean_set(ptr, prop_release_confirm, true); - ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, NULL); - RNA_property_boolean_set(ptr, prop_release_confirm, true); - ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, NULL); - RNA_property_boolean_set(ptr, prop_release_confirm, true); - ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, NULL); - RNA_property_boolean_set(ptr, prop_release_confirm, true); - ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE, ot_rotate, NULL); - RNA_property_boolean_set(ptr, prop_release_confirm, true); - } -} - -void ED_widgetgroup_manipulator2d_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - ManipulatorGroup2D *man = mgroup->customdata; - float origin[3]; - manipulator2d_calc_bounds(C, origin, man->min, man->max); - copy_v2_v2(man->origin, origin); - bool show_cage = !equals_v2v2(man->min, man->max); - - if (show_cage) { - man->cage->flag &= ~WM_MANIPULATOR_HIDDEN; - man->translate_x->flag |= WM_MANIPULATOR_HIDDEN; - man->translate_y->flag |= WM_MANIPULATOR_HIDDEN; - } - else { - man->cage->flag |= WM_MANIPULATOR_HIDDEN; - man->translate_x->flag &= ~WM_MANIPULATOR_HIDDEN; - man->translate_y->flag &= ~WM_MANIPULATOR_HIDDEN; - } - - if (show_cage) { - wmManipulatorOpElem *mpop; - float mid[2]; - const float *min = man->min; - const float *max = man->max; - mid_v2_v2v2(mid, min, max); - - mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X); - PropertyRNA *prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override"); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f}); - mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f}); - mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f}); - mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f}); - - mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f}); - mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f}); - mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f}); - mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f}); - - mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f}); - } -} - -void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) -{ - ARegion *ar = CTX_wm_region(C); - ManipulatorGroup2D *man = mgroup->customdata; - float origin[3] = {UNPACK2(man->origin), 0.0f}; - float origin_aa[3] = {UNPACK2(man->origin), 0.0f}; - - manipulator2d_origin_to_region(ar, origin); - - MAN2D_ITER_AXES_BEGIN(axis, axis_idx) - { - WM_manipulator_set_matrix_location(axis, origin); - } - MAN2D_ITER_AXES_END; - - UI_view2d_view_to_region_m4(&ar->v2d, man->cage->matrix_space); - WM_manipulator_set_matrix_offset_location(man->cage, origin_aa); - man->cage->matrix_offset[0][0] = (man->max[0] - man->min[0]); - man->cage->matrix_offset[1][1] = (man->max[1] - man->min[1]); -} - -/* TODO (Julian) - * - Called on every redraw, better to do a more simple poll and check for selection in _refresh - * - UV editing only, could be expanded for other things. - */ -bool ED_widgetgroup_manipulator2d_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt)) -{ - if ((U.manipulator_flag & USER_MANIPULATOR_DRAW) == 0) { - return false; - } - - SpaceImage *sima = CTX_wm_space_image(C); - Object *obedit = CTX_data_edit_object(C); - - if (ED_space_image_show_uvedit(sima, obedit)) { - Image *ima = ED_space_image(sima); - Scene *scene = CTX_data_scene(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* check if there's a selected poly */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, obedit, ima, efa)) - continue; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - return true; - } - } - } - } - - return false; -} diff --git a/source/blender/editors/transform/transform_manipulator_3d.c b/source/blender/editors/transform/transform_manipulator_3d.c deleted file mode 100644 index 7dc72ddff6f..00000000000 --- a/source/blender/editors/transform/transform_manipulator_3d.c +++ /dev/null @@ -1,1790 +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. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/transform/transform_manipulator_3d.c - * \ingroup edtransform - * - * \name 3D Transform Manipulator - * - * Used for 3D View - */ - -#include -#include -#include -#include - -#include "DNA_armature_types.h" -#include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_lattice_types.h" -#include "DNA_meta_types.h" -#include "DNA_screen_types.h" -#include "DNA_scene_types.h" -#include "DNA_view3d_types.h" - -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "RNA_access.h" - -#include "BKE_action.h" -#include "BKE_context.h" -#include "BKE_curve.h" -#include "BKE_global.h" -#include "BKE_particle.h" -#include "BKE_pointcache.h" -#include "BKE_editmesh.h" -#include "BKE_lattice.h" -#include "BKE_gpencil.h" -#include "BKE_scene.h" -#include "BKE_workspace.h" - -#include "BIF_gl.h" - -#include "DEG_depsgraph.h" - -#include "WM_api.h" -#include "WM_types.h" -#include "WM_message.h" -#include "WM_toolsystem.h" - -#include "ED_armature.h" -#include "ED_curve.h" -#include "ED_object.h" -#include "ED_particle.h" -#include "ED_view3d.h" -#include "ED_gpencil.h" -#include "ED_screen.h" -#include "ED_manipulator_library.h" - -#include "UI_resources.h" - -/* local module include */ -#include "transform.h" - -#include "MEM_guardedalloc.h" - -#include "GPU_select.h" -#include "GPU_immediate.h" -#include "GPU_matrix.h" - -#include "DEG_depsgraph_query.h" - -/* return codes for select, and drawing flags */ - -#define MAN_TRANS_X (1 << 0) -#define MAN_TRANS_Y (1 << 1) -#define MAN_TRANS_Z (1 << 2) -#define MAN_TRANS_C (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z) - -#define MAN_ROT_X (1 << 3) -#define MAN_ROT_Y (1 << 4) -#define MAN_ROT_Z (1 << 5) -#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z) - -#define MAN_SCALE_X (1 << 8) -#define MAN_SCALE_Y (1 << 9) -#define MAN_SCALE_Z (1 << 10) -#define MAN_SCALE_C (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z) - -/* threshold for testing view aligned manipulator axis */ -struct { - float min, max; -} g_tw_axis_range[2] = { - /* Regular range */ - {0.02f, 0.1f}, - /* Use a different range because we flip the dot product, - * also the view aligned planes are harder to see so hiding early is preferred. */ - {0.175f, 0.25f}, -}; - -/* axes as index */ -enum { - MAN_AXIS_TRANS_X = 0, - MAN_AXIS_TRANS_Y, - MAN_AXIS_TRANS_Z, - MAN_AXIS_TRANS_C, - - MAN_AXIS_TRANS_XY, - MAN_AXIS_TRANS_YZ, - MAN_AXIS_TRANS_ZX, -#define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X -#define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1) - - MAN_AXIS_ROT_X, - MAN_AXIS_ROT_Y, - MAN_AXIS_ROT_Z, - MAN_AXIS_ROT_C, - MAN_AXIS_ROT_T, /* trackball rotation */ -#define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X -#define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1) - - MAN_AXIS_SCALE_X, - MAN_AXIS_SCALE_Y, - MAN_AXIS_SCALE_Z, - MAN_AXIS_SCALE_C, - MAN_AXIS_SCALE_XY, - MAN_AXIS_SCALE_YZ, - MAN_AXIS_SCALE_ZX, -#define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X -#define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1) - - MAN_AXIS_LAST = MAN_AXIS_RANGE_SCALE_END, -}; - -/* axis types */ -enum { - MAN_AXES_ALL = 0, - MAN_AXES_TRANSLATE, - MAN_AXES_ROTATE, - MAN_AXES_SCALE, -}; - -typedef struct ManipulatorGroup { - bool all_hidden; - int twtype; - - /* Users may change the twtype, detect changes to re-setup manipulator options. */ - int twtype_init; - int twtype_prev; - int use_twtype_refresh; - - struct wmManipulator *manipulators[MAN_AXIS_LAST]; -} ManipulatorGroup; - -/* -------------------------------------------------------------------- */ -/** \name Utilities - * \{ */ - -/* loop over axes */ -#define MAN_ITER_AXES_BEGIN(axis, axis_idx) \ - { \ - wmManipulator *axis; \ - int axis_idx; \ - for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \ - axis = manipulator_get_axis_from_index(man, axis_idx); - -#define MAN_ITER_AXES_END \ - } \ - } ((void)0) - -static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx) -{ - BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST)); - return man->manipulators[axis_idx]; -} - -static short manipulator_get_axis_type(const int axis_idx) -{ - if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { - return MAN_AXES_TRANSLATE; - } - if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) { - return MAN_AXES_ROTATE; - } - if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) { - return MAN_AXES_SCALE; - } - BLI_assert(0); - return -1; -} - -static uint manipulator_orientation_axis(const int axis_idx, bool *r_is_plane) -{ - switch (axis_idx) { - case MAN_AXIS_TRANS_YZ: - case MAN_AXIS_SCALE_YZ: - if (r_is_plane) { - *r_is_plane = true; - } - ATTR_FALLTHROUGH; - case MAN_AXIS_TRANS_X: - case MAN_AXIS_ROT_X: - case MAN_AXIS_SCALE_X: - return 0; - - case MAN_AXIS_TRANS_ZX: - case MAN_AXIS_SCALE_ZX: - if (r_is_plane) { - *r_is_plane = true; - } - ATTR_FALLTHROUGH; - case MAN_AXIS_TRANS_Y: - case MAN_AXIS_ROT_Y: - case MAN_AXIS_SCALE_Y: - return 1; - - case MAN_AXIS_TRANS_XY: - case MAN_AXIS_SCALE_XY: - if (r_is_plane) { - *r_is_plane = true; - } - ATTR_FALLTHROUGH; - case MAN_AXIS_TRANS_Z: - case MAN_AXIS_ROT_Z: - case MAN_AXIS_SCALE_Z: - return 2; - } - return 3; -} - -static bool manipulator_is_axis_visible( - const RegionView3D *rv3d, const int twtype, - const float idot[3], const int axis_type, const int axis_idx) -{ - if ((axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) == 0) { - bool is_plane = false; - const uint aidx_norm = manipulator_orientation_axis(axis_idx, &is_plane); - /* don't draw axis perpendicular to the view */ - if (aidx_norm < 3) { - float idot_axis = idot[aidx_norm]; - if (is_plane) { - idot_axis = 1.0f - idot_axis; - } - if (idot_axis < g_tw_axis_range[is_plane].min) { - return false; - } - } - } - - if ((axis_type == MAN_AXES_TRANSLATE && !(twtype & SCE_MANIP_TRANSLATE)) || - (axis_type == MAN_AXES_ROTATE && !(twtype & SCE_MANIP_ROTATE)) || - (axis_type == MAN_AXES_SCALE && !(twtype & SCE_MANIP_SCALE))) - { - return false; - } - - switch (axis_idx) { - case MAN_AXIS_TRANS_X: - return (rv3d->twdrawflag & MAN_TRANS_X); - case MAN_AXIS_TRANS_Y: - return (rv3d->twdrawflag & MAN_TRANS_Y); - case MAN_AXIS_TRANS_Z: - return (rv3d->twdrawflag & MAN_TRANS_Z); - case MAN_AXIS_TRANS_C: - return (rv3d->twdrawflag & MAN_TRANS_C); - case MAN_AXIS_ROT_X: - return (rv3d->twdrawflag & MAN_ROT_X); - case MAN_AXIS_ROT_Y: - return (rv3d->twdrawflag & MAN_ROT_Y); - case MAN_AXIS_ROT_Z: - return (rv3d->twdrawflag & MAN_ROT_Z); - case MAN_AXIS_ROT_C: - case MAN_AXIS_ROT_T: - return (rv3d->twdrawflag & MAN_ROT_C); - case MAN_AXIS_SCALE_X: - return (rv3d->twdrawflag & MAN_SCALE_X); - case MAN_AXIS_SCALE_Y: - return (rv3d->twdrawflag & MAN_SCALE_Y); - case MAN_AXIS_SCALE_Z: - return (rv3d->twdrawflag & MAN_SCALE_Z); - case MAN_AXIS_SCALE_C: - return (rv3d->twdrawflag & MAN_SCALE_C && (twtype & SCE_MANIP_TRANSLATE) == 0); - case MAN_AXIS_TRANS_XY: - return (rv3d->twdrawflag & MAN_TRANS_X && - rv3d->twdrawflag & MAN_TRANS_Y && - (twtype & SCE_MANIP_ROTATE) == 0); - case MAN_AXIS_TRANS_YZ: - return (rv3d->twdrawflag & MAN_TRANS_Y && - rv3d->twdrawflag & MAN_TRANS_Z && - (twtype & SCE_MANIP_ROTATE) == 0); - case MAN_AXIS_TRANS_ZX: - return (rv3d->twdrawflag & MAN_TRANS_Z && - rv3d->twdrawflag & MAN_TRANS_X && - (twtype & SCE_MANIP_ROTATE) == 0); - case MAN_AXIS_SCALE_XY: - return (rv3d->twdrawflag & MAN_SCALE_X && - rv3d->twdrawflag & MAN_SCALE_Y && - (twtype & SCE_MANIP_TRANSLATE) == 0 && - (twtype & SCE_MANIP_ROTATE) == 0); - case MAN_AXIS_SCALE_YZ: - return (rv3d->twdrawflag & MAN_SCALE_Y && - rv3d->twdrawflag & MAN_SCALE_Z && - (twtype & SCE_MANIP_TRANSLATE) == 0 && - (twtype & SCE_MANIP_ROTATE) == 0); - case MAN_AXIS_SCALE_ZX: - return (rv3d->twdrawflag & MAN_SCALE_Z && - rv3d->twdrawflag & MAN_SCALE_X && - (twtype & SCE_MANIP_TRANSLATE) == 0 && - (twtype & SCE_MANIP_ROTATE) == 0); - } - return false; -} - -static void manipulator_get_axis_color( - const int axis_idx, const float idot[3], - float r_col[4], float r_col_hi[4]) -{ - /* alpha values for normal/highlighted states */ - const float alpha = 0.6f; - const float alpha_hi = 1.0f; - float alpha_fac; - - if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) { - /* Never fade rotation rings. */ - /* trackball rotation axis is a special case, we only draw a slight overlay */ - alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f; - } - else { - bool is_plane = false; - const int axis_idx_norm = manipulator_orientation_axis(axis_idx, &is_plane); - /* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */ - if (axis_idx_norm < 3) { - const float idot_min = g_tw_axis_range[is_plane].min; - const float idot_max = g_tw_axis_range[is_plane].max; - float idot_axis = idot[axis_idx_norm]; - if (is_plane) { - idot_axis = 1.0f - idot_axis; - } - alpha_fac = ( - (idot_axis > idot_max) ? - 1.0f : (idot_axis < idot_min) ? - 0.0f : ((idot_axis - idot_min) / (idot_max - idot_min))); - } - else { - alpha_fac = 1.0f; - } - } - - switch (axis_idx) { - case MAN_AXIS_TRANS_X: - case MAN_AXIS_ROT_X: - case MAN_AXIS_SCALE_X: - case MAN_AXIS_TRANS_YZ: - case MAN_AXIS_SCALE_YZ: - UI_GetThemeColor4fv(TH_AXIS_X, r_col); - break; - case MAN_AXIS_TRANS_Y: - case MAN_AXIS_ROT_Y: - case MAN_AXIS_SCALE_Y: - case MAN_AXIS_TRANS_ZX: - case MAN_AXIS_SCALE_ZX: - UI_GetThemeColor4fv(TH_AXIS_Y, r_col); - break; - case MAN_AXIS_TRANS_Z: - case MAN_AXIS_ROT_Z: - case MAN_AXIS_SCALE_Z: - case MAN_AXIS_TRANS_XY: - case MAN_AXIS_SCALE_XY: - UI_GetThemeColor4fv(TH_AXIS_Z, r_col); - break; - case MAN_AXIS_TRANS_C: - case MAN_AXIS_ROT_C: - case MAN_AXIS_SCALE_C: - case MAN_AXIS_ROT_T: - copy_v4_fl(r_col, 1.0f); - break; - } - - copy_v4_v4(r_col_hi, r_col); - - r_col[3] = alpha * alpha_fac; - r_col_hi[3] = alpha_hi * alpha_fac; -} - -static void manipulator_get_axis_constraint(const int axis_idx, bool r_axis[3]) -{ - ARRAY_SET_ITEMS(r_axis, 0, 0, 0); - - switch (axis_idx) { - case MAN_AXIS_TRANS_X: - case MAN_AXIS_ROT_X: - case MAN_AXIS_SCALE_X: - r_axis[0] = 1; - break; - case MAN_AXIS_TRANS_Y: - case MAN_AXIS_ROT_Y: - case MAN_AXIS_SCALE_Y: - r_axis[1] = 1; - break; - case MAN_AXIS_TRANS_Z: - case MAN_AXIS_ROT_Z: - case MAN_AXIS_SCALE_Z: - r_axis[2] = 1; - break; - case MAN_AXIS_TRANS_XY: - case MAN_AXIS_SCALE_XY: - r_axis[0] = r_axis[1] = 1; - break; - case MAN_AXIS_TRANS_YZ: - case MAN_AXIS_SCALE_YZ: - r_axis[1] = r_axis[2] = 1; - break; - case MAN_AXIS_TRANS_ZX: - case MAN_AXIS_SCALE_ZX: - r_axis[2] = r_axis[0] = 1; - break; - default: - break; - } -} - - -/* **************** Preparation Stuff **************** */ - -/* transform widget center calc helper for below */ -static void calc_tw_center(struct TransformBounds *tbounds, const float co[3]) -{ - minmax_v3v3_v3(tbounds->min, tbounds->max, co); - add_v3_v3(tbounds->center, co); - - for (int i = 0; i < 3; i++) { - const float d = dot_v3v3(tbounds->axis[i], co); - tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]); - tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]); - } -} - -static void protectflag_to_drawflags(short protectflag, short *drawflags) -{ - if (protectflag & OB_LOCK_LOCX) - *drawflags &= ~MAN_TRANS_X; - if (protectflag & OB_LOCK_LOCY) - *drawflags &= ~MAN_TRANS_Y; - if (protectflag & OB_LOCK_LOCZ) - *drawflags &= ~MAN_TRANS_Z; - - if (protectflag & OB_LOCK_ROTX) - *drawflags &= ~MAN_ROT_X; - if (protectflag & OB_LOCK_ROTY) - *drawflags &= ~MAN_ROT_Y; - if (protectflag & OB_LOCK_ROTZ) - *drawflags &= ~MAN_ROT_Z; - - if (protectflag & OB_LOCK_SCALEX) - *drawflags &= ~MAN_SCALE_X; - if (protectflag & OB_LOCK_SCALEY) - *drawflags &= ~MAN_SCALE_Y; - if (protectflag & OB_LOCK_SCALEZ) - *drawflags &= ~MAN_SCALE_Z; -} - -/* for pose mode */ -static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan) -{ - protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); -} - -/* for editmode*/ -static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo) -{ - if (ebo->flag & BONE_EDITMODE_LOCKED) { - protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag); - } -} - -/* could move into BLI_math however this is only useful for display/editing purposes */ -static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle) -{ - /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */ - - float cross_vec[3]; - float quat[4]; - - /* this is an un-scientific method to get a vector to cross with - * XYZ intentionally YZX */ - cross_vec[0] = axis[1]; - cross_vec[1] = axis[2]; - cross_vec[2] = axis[0]; - - /* X-axis */ - cross_v3_v3v3(gmat[0], cross_vec, axis); - normalize_v3(gmat[0]); - axis_angle_to_quat(quat, axis, angle); - mul_qt_v3(quat, gmat[0]); - - /* Y-axis */ - axis_angle_to_quat(quat, axis, M_PI_2); - copy_v3_v3(gmat[1], gmat[0]); - mul_qt_v3(quat, gmat[1]); - - /* Z-axis */ - copy_v3_v3(gmat[2], axis); - - normalize_m3(gmat); -} - - -static bool test_rotmode_euler(short rotmode) -{ - return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1; -} - -bool gimbal_axis(Object *ob, float gmat[3][3]) -{ - if (ob->mode & OB_MODE_POSE) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); - - if (pchan) { - float mat[3][3], tmat[3][3], obmat[3][3]; - if (test_rotmode_euler(pchan->rotmode)) { - eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode); - } - else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle); - } - else { /* quat */ - return 0; - } - - - /* apply bone transformation */ - mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat); - - if (pchan->parent) { - float parent_mat[3][3]; - - copy_m3_m4(parent_mat, pchan->parent->pose_mat); - mul_m3_m3m3(mat, parent_mat, tmat); - - /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); - mul_m3_m3m3(gmat, obmat, mat); - } - else { - /* needed if object transformation isn't identity */ - copy_m3_m4(obmat, ob->obmat); - mul_m3_m3m3(gmat, obmat, tmat); - } - - normalize_m3(gmat); - return 1; - } - } - else { - if (test_rotmode_euler(ob->rotmode)) { - eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode); - } - else if (ob->rotmode == ROT_MODE_AXISANGLE) { - axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle); - } - else { /* quat */ - return 0; - } - - if (ob->parent) { - float parent_mat[3][3]; - copy_m3_m4(parent_mat, ob->parent->obmat); - normalize_m3(parent_mat); - mul_m3_m3m3(gmat, parent_mat, gmat); - } - return 1; - } - - return 0; -} - - -/* centroid, boundbox, of selection */ -/* returns total items selected */ -int ED_transform_calc_manipulator_stats( - const bContext *C, - const struct TransformCalcParams *params, - struct TransformBounds *tbounds) -{ - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); - View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; - Base *base; - Object *ob = OBACT(view_layer); - bGPdata *gpd = CTX_data_gpencil_data(C); - const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); - int a, totsel = 0; - const int pivot_point = scene->toolsettings->transform_pivot_point; - - /* transform widget matrix */ - unit_m4(rv3d->twmat); - - unit_m3(rv3d->tw_axis_matrix); - zero_v3(rv3d->tw_axis_min); - zero_v3(rv3d->tw_axis_max); - - rv3d->twdrawflag = 0xFFFF; - - /* global, local or normal orientation? - * if we could check 'totsel' now, this should be skipped with no selection. */ - if (ob && !is_gp_edit) { - const short orientation_type = params->orientation_type ? (params->orientation_type - 1) : scene->orientation_type; - - switch (orientation_type) { - - case V3D_MANIP_GLOBAL: - { - break; /* nothing to do */ - } - case V3D_MANIP_GIMBAL: - { - float mat[3][3]; - if (gimbal_axis(ob, mat)) { - copy_m4_m3(rv3d->twmat, mat); - break; - } - /* if not gimbal, fall through to normal */ - ATTR_FALLTHROUGH; - } - case V3D_MANIP_NORMAL: - { - if (obedit || ob->mode & OB_MODE_POSE) { - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, pivot_point); - copy_m4_m3(rv3d->twmat, mat); - break; - } - /* no break we define 'normal' as 'local' in Object mode */ - ATTR_FALLTHROUGH; - } - case V3D_MANIP_LOCAL: - { - if (ob->mode & OB_MODE_POSE) { - /* each bone moves on its own local axis, but to avoid confusion, - * use the active pones axis for display [#33575], this works as expected on a single bone - * and users who select many bones will understand whats going on and what local means - * when they start transforming */ - float mat[3][3]; - ED_getTransformOrientationMatrix(C, mat, pivot_point); - copy_m4_m3(rv3d->twmat, mat); - break; - } - copy_m4_m4(rv3d->twmat, ob->obmat); - normalize_m4(rv3d->twmat); - break; - } - case V3D_MANIP_VIEW: - { - float mat[3][3]; - copy_m3_m4(mat, rv3d->viewinv); - normalize_m3(mat); - copy_m4_m3(rv3d->twmat, mat); - break; - } - case V3D_MANIP_CURSOR: - { - float mat[3][3]; - ED_view3d_cursor3d_calc_mat3(scene, v3d, mat); - copy_m4_m3(rv3d->twmat, mat); - break; - } - case V3D_MANIP_CUSTOM: - { - TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find( - scene, scene->orientation_index_custom); - float mat[3][3]; - - if (applyTransformOrientation(custom_orientation, mat, NULL)) { - copy_m4_m3(rv3d->twmat, mat); - } - break; - } - } - } - - /* transform widget centroid/center */ - INIT_MINMAX(tbounds->min, tbounds->max); - zero_v3(tbounds->center); - - copy_m3_m4(tbounds->axis, rv3d->twmat); - if (params->use_local_axis && (ob && ob->mode & OB_MODE_EDIT)) { - float diff_mat[3][3]; - copy_m3_m4(diff_mat, ob->obmat); - normalize_m3(diff_mat); - invert_m3(diff_mat); - mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat); - normalize_m3(tbounds->axis); - } - - for (int i = 0; i < 3; i++) { - tbounds->axis_min[i] = +FLT_MAX; - tbounds->axis_max[i] = -FLT_MAX; - } - - if (is_gp_edit) { - float diff_mat[4][4]; - float fpt[3]; - - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { - - /* calculate difference matrix if parent object */ - if (gpl->parent != NULL) { - ED_gpencil_parent_location(gpl, diff_mat); - } - - for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - - /* we're only interested in selected points here... */ - if (gps->flag & GP_STROKE_SELECT) { - bGPDspoint *pt; - int i; - - /* Change selection status of all points, then make the stroke match */ - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if (pt->flag & GP_SPOINT_SELECT) { - if (gpl->parent == NULL) { - calc_tw_center(tbounds, &pt->x); - totsel++; - } - else { - mul_v3_m4v3(fpt, diff_mat, &pt->x); - calc_tw_center(tbounds, fpt); - totsel++; - } - } - } - } - } - } - } - - - /* selection center */ - if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); /* centroid! */ - } - } - else if (obedit) { - ob = obedit; - if (obedit->type == OB_MESH) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMEditSelection ese; - float vec[3] = {0, 0, 0}; - - /* USE LAST SELECTE WITH ACTIVE */ - if ((pivot_point == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) { - BM_editselection_center(&ese, vec); - calc_tw_center(tbounds, vec); - totsel = 1; - } - else { - BMesh *bm = em->bm; - BMVert *eve; - - BMIter iter; - - BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - totsel++; - calc_tw_center(tbounds, eve->co); - } - } - } - } - } /* end editmesh */ - else if (obedit->type == OB_ARMATURE) { - bArmature *arm = obedit->data; - EditBone *ebo; - - if ((pivot_point == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) { - /* doesn't check selection or visibility intentionally */ - if (ebo->flag & BONE_TIPSEL) { - calc_tw_center(tbounds, ebo->tail); - totsel++; - } - if ((ebo->flag & BONE_ROOTSEL) || - ((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */ - { - calc_tw_center(tbounds, ebo->head); - totsel++; - } - protectflag_to_drawflags_ebone(rv3d, ebo); - } - else { - for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { - if (EBONE_VISIBLE(arm, ebo)) { - if (ebo->flag & BONE_TIPSEL) { - calc_tw_center(tbounds, ebo->tail); - totsel++; - } - if ((ebo->flag & BONE_ROOTSEL) && - /* don't include same point multiple times */ - ((ebo->flag & BONE_CONNECTED) && - (ebo->parent != NULL) && - (ebo->parent->flag & BONE_TIPSEL) && - EBONE_VISIBLE(arm, ebo->parent)) == 0) - { - calc_tw_center(tbounds, ebo->head); - totsel++; - } - if (ebo->flag & BONE_SELECTED) { - protectflag_to_drawflags_ebone(rv3d, ebo); - } - } - } - } - } - else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { - Curve *cu = obedit->data; - float center[3]; - - if ((pivot_point == V3D_AROUND_ACTIVE) && ED_curve_active_center(cu, center)) { - calc_tw_center(tbounds, center); - totsel++; - } - else { - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - ListBase *nurbs = BKE_curve_editNurbs_get(cu); - - nu = nurbs->first; - while (nu) { - if (nu->type == CU_BEZIER) { - bezt = nu->bezt; - a = nu->pntsu; - while (a--) { - /* exceptions - * if handles are hidden then only check the center points. - * If the center knot is selected then only use this as the center point. - */ - if (cu->drawflag & CU_HIDE_HANDLES) { - if (bezt->f2 & SELECT) { - calc_tw_center(tbounds, bezt->vec[1]); - totsel++; - } - } - else if (bezt->f2 & SELECT) { - calc_tw_center(tbounds, bezt->vec[1]); - totsel++; - } - else { - if (bezt->f1 & SELECT) { - calc_tw_center( - tbounds, bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); - totsel++; - } - if (bezt->f3 & SELECT) { - calc_tw_center( - tbounds, bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); - totsel++; - } - } - bezt++; - } - } - else { - bp = nu->bp; - a = nu->pntsu * nu->pntsv; - while (a--) { - if (bp->f1 & SELECT) { - calc_tw_center(tbounds, bp->vec); - totsel++; - } - bp++; - } - } - nu = nu->next; - } - } - } - else if (obedit->type == OB_MBALL) { - MetaBall *mb = (MetaBall *)obedit->data; - MetaElem *ml; - - if ((pivot_point == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) { - calc_tw_center(tbounds, &ml->x); - totsel++; - } - else { - for (ml = mb->editelems->first; ml; ml = ml->next) { - if (ml->flag & SELECT) { - calc_tw_center(tbounds, &ml->x); - totsel++; - } - } - } - } - else if (obedit->type == OB_LATTICE) { - Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt; - BPoint *bp; - - if ((pivot_point == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) { - calc_tw_center(tbounds, bp->vec); - totsel++; - } - else { - bp = lt->def; - a = lt->pntsu * lt->pntsv * lt->pntsw; - while (a--) { - if (bp->f1 & SELECT) { - calc_tw_center(tbounds, bp->vec); - totsel++; - } - bp++; - } - } - } - - /* selection center */ - if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! - mul_m4_v3(obedit->obmat, tbounds->center); - mul_m4_v3(obedit->obmat, tbounds->min); - mul_m4_v3(obedit->obmat, tbounds->max); - } - } - else if (ob && (ob->mode & OB_MODE_POSE)) { - bPoseChannel *pchan; - int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed - bool ok = false; - - if ((pivot_point == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) { - /* doesn't check selection or visibility intentionally */ - Bone *bone = pchan->bone; - if (bone) { - calc_tw_center(tbounds, pchan->pose_head); - protectflag_to_drawflags_pchan(rv3d, pchan); - totsel = 1; - ok = true; - } - } - else { - totsel = count_set_pose_transflags(ob, mode, V3D_AROUND_CENTER_BOUNDS, NULL); - - if (totsel) { - /* use channels to get stats */ - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - Bone *bone = pchan->bone; - if (bone && (bone->flag & BONE_TRANSFORM)) { - calc_tw_center(tbounds, pchan->pose_head); - protectflag_to_drawflags_pchan(rv3d, pchan); - } - } - ok = true; - } - } - - if (ok) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! - mul_m4_v3(ob->obmat, tbounds->center); - mul_m4_v3(ob->obmat, tbounds->min); - mul_m4_v3(ob->obmat, tbounds->max); - } - } - else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) { - /* pass */ - } - else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) { - PTCacheEdit *edit = PE_get_current(scene, ob); - PTCacheEditPoint *point; - PTCacheEditKey *ek; - int k; - - if (edit) { - point = edit->points; - for (a = 0; a < edit->totpoint; a++, point++) { - if (point->flag & PEP_HIDE) continue; - - for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) { - if (ek->flag & PEK_SELECT) { - calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co); - totsel++; - } - } - } - - /* selection center */ - if (totsel) - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! - } - } - else { - - /* we need the one selected object, if its not active */ - base = BASACT(view_layer); - ob = OBACT(view_layer); - if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL; - - for (base = view_layer->object_bases.first; base; base = base->next) { - if (!TESTBASELIB(base)) { - continue; - } - if (ob == NULL) { - ob = base->object; - } - if (params->use_only_center || base->object->bb == NULL) { - calc_tw_center(tbounds, base->object->obmat[3]); - } - else { - for (uint j = 0; j < 8; j++) { - float co[3]; - mul_v3_m4v3(co, base->object->obmat, base->object->bb->vec[j]); - calc_tw_center(tbounds, co); - } - } - protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); - totsel++; - } - - /* selection center */ - if (totsel) { - mul_v3_fl(tbounds->center, 1.0f / (float)totsel); // centroid! - } - } - - if (totsel == 0) { - unit_m4(rv3d->twmat); - } - else { - copy_v3_v3(rv3d->tw_axis_min, tbounds->axis_min); - copy_v3_v3(rv3d->tw_axis_max, tbounds->axis_max); - copy_m3_m3(rv3d->tw_axis_matrix, tbounds->axis); - } - - return totsel; -} - -static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3]) -{ - float view_vec[3], axis_vec[3]; - ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec); - for (int i = 0; i < 3; i++) { - normalize_v3_v3(axis_vec, rv3d->twmat[i]); - r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec)); - } -} - -static void manipulator_prepare_mat( - const bContext *C, View3D *v3d, RegionView3D *rv3d, const struct TransformBounds *tbounds) -{ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - switch (scene->toolsettings->transform_pivot_point) { - case V3D_AROUND_CENTER_BOUNDS: - case V3D_AROUND_ACTIVE: - { - bGPdata *gpd = CTX_data_gpencil_data(C); - Object *ob = OBACT(view_layer); - - if (((scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) && - (OBEDIT_FROM_OBACT(ob) == NULL)) && - ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && - (!(ob->mode & OB_MODE_POSE))) - { - copy_v3_v3(rv3d->twmat[3], ob->obmat[3]); - } - else { - mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max); - } - break; - } - case V3D_AROUND_LOCAL_ORIGINS: - case V3D_AROUND_CENTER_MEAN: - copy_v3_v3(rv3d->twmat[3], tbounds->center); - break; - case V3D_AROUND_CURSOR: - copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)->location); - break; - } -} - -/** - * Sets up \a r_start and \a r_len to define arrow line range. - * Needed to adjust line drawing for combined manipulator axis types. - */ -static void manipulator_line_range(const int twtype, const short axis_type, float *r_start, float *r_len) -{ - const float ofs = 0.2f; - - *r_start = 0.2f; - *r_len = 1.0f; - - switch (axis_type) { - case MAN_AXES_TRANSLATE: - if (twtype & SCE_MANIP_SCALE) { - *r_start = *r_len - ofs + 0.075f; - } - if (twtype & SCE_MANIP_ROTATE) { - *r_len += ofs; - } - break; - case MAN_AXES_SCALE: - if (twtype & (SCE_MANIP_TRANSLATE | SCE_MANIP_ROTATE)) { - *r_len -= ofs + 0.025f; - } - break; - } - - *r_len -= *r_start; -} - -static void manipulator_xform_message_subscribe( - wmManipulatorGroup *mgroup, struct wmMsgBus *mbus, - Scene *scene, bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar, const void *type_fn) -{ - /* Subscribe to view properties */ - wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { - .owner = ar, - .user_data = mgroup->parent_mmap, - .notify = WM_manipulator_do_msg_notify_tag_refresh, - }; - - PointerRNA scene_ptr; - RNA_id_pointer_create(&scene->id, &scene_ptr); - - { - extern PropertyRNA rna_Scene_transform_orientation; - extern PropertyRNA rna_Scene_cursor_location; - const PropertyRNA *props[] = { - &rna_Scene_transform_orientation, - (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) ? &rna_Scene_cursor_location : NULL, - }; - for (int i = 0; i < ARRAY_SIZE(props); i++) { - if (props[i]) { - WM_msg_subscribe_rna(mbus, &scene_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); - } - } - } - - PointerRNA toolsettings_ptr; - RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr); - - if (type_fn == TRANSFORM_WGT_manipulator) { - extern PropertyRNA rna_ToolSettings_transform_pivot_point; - extern PropertyRNA rna_ToolSettings_use_manipulator_mode; - const PropertyRNA *props[] = { - &rna_ToolSettings_transform_pivot_point, - &rna_ToolSettings_use_manipulator_mode, - }; - for (int i = 0; i < ARRAY_SIZE(props); i++) { - WM_msg_subscribe_rna(mbus, &toolsettings_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); - } - } - else if (type_fn == VIEW3D_WGT_xform_cage) { - /* pass */ - } - else { - BLI_assert(0); - } - - WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_mpr_tag_refresh); -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ -/** \name Transform Manipulator - * \{ */ - -static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup) -{ - ManipulatorGroup *man; - - man = MEM_callocN(sizeof(ManipulatorGroup), "manipulator_data"); - - const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true); - const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true); - const wmManipulatorType *wt_prim = WM_manipulatortype_find("MANIPULATOR_WT_primitive_3d", true); - -#define MANIPULATOR_NEW_ARROW(v, draw_style) { \ - man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \ - RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ -} ((void)0) -#define MANIPULATOR_NEW_DIAL(v, draw_options) { \ - man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \ - RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \ -} ((void)0) -#define MANIPULATOR_NEW_PRIM(v, draw_style) { \ - man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \ - RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \ -} ((void)0) - - /* add/init widgets - order matters! */ - MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_T, ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL); - - MANIPULATOR_NEW_DIAL(MAN_AXIS_SCALE_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - - MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_X, ED_MANIPULATOR_ARROW_STYLE_BOX); - MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_MANIPULATOR_ARROW_STYLE_BOX); - MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_MANIPULATOR_ARROW_STYLE_BOX); - - MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - - MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_X, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); - MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Y, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); - MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Z, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP); - - /* init screen aligned widget last here, looks better, behaves better */ - MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - - MANIPULATOR_NEW_DIAL(MAN_AXIS_TRANS_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP); - - MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_X, ED_MANIPULATOR_ARROW_STYLE_NORMAL); - MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_MANIPULATOR_ARROW_STYLE_NORMAL); - MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_MANIPULATOR_ARROW_STYLE_NORMAL); - - MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE); - - man->manipulators[MAN_AXIS_ROT_T]->flag |= WM_MANIPULATOR_SELECT_BACKGROUND; - - return man; -} - -/** - * Custom handler for manipulator widgets - */ -static int manipulator_modal( - bContext *C, wmManipulator *widget, const wmEvent *event, - eWM_ManipulatorTweak UNUSED(tweak_flag)) -{ - /* Avoid unnecessary updates, partially address: T55458. */ - if (ELEM(event->type, TIMER, INBETWEEN_MOUSEMOVE)) { - return OPERATOR_RUNNING_MODAL; - } - - const ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; - struct TransformBounds tbounds; - - - if (ED_transform_calc_manipulator_stats( - C, &(struct TransformCalcParams){ - .use_only_center = true, - }, &tbounds)) - { - manipulator_prepare_mat(C, v3d, rv3d, &tbounds); - WM_manipulator_set_matrix_location(widget, rv3d->twmat[3]); - } - - ED_region_tag_redraw(ar); - - return OPERATOR_RUNNING_MODAL; -} - -static void manipulatorgroup_init_properties_from_twtype(wmManipulatorGroup *mgroup) -{ - struct { - wmOperatorType *translate, *rotate, *trackball, *resize; - } ot_store = {NULL}; - ManipulatorGroup *man = mgroup->customdata; - MAN_ITER_AXES_BEGIN(axis, axis_idx) - { - const short axis_type = manipulator_get_axis_type(axis_idx); - bool constraint_axis[3] = {1, 0, 0}; - PointerRNA *ptr; - - manipulator_get_axis_constraint(axis_idx, constraint_axis); - - /* custom handler! */ - WM_manipulator_set_fn_custom_modal(axis, manipulator_modal); - - switch (axis_idx) { - case MAN_AXIS_TRANS_X: - case MAN_AXIS_TRANS_Y: - case MAN_AXIS_TRANS_Z: - case MAN_AXIS_SCALE_X: - case MAN_AXIS_SCALE_Y: - case MAN_AXIS_SCALE_Z: - if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { - int draw_options = 0; - if ((man->twtype & (SCE_MANIP_ROTATE | SCE_MANIP_SCALE)) == 0) { - draw_options |= ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM; - } - RNA_enum_set(axis->ptr, "draw_options", draw_options); - } - - WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); - break; - case MAN_AXIS_ROT_X: - case MAN_AXIS_ROT_Y: - case MAN_AXIS_ROT_Z: - /* increased line width for better display */ - WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH + 1.0f); - WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true); - break; - case MAN_AXIS_TRANS_XY: - case MAN_AXIS_TRANS_YZ: - case MAN_AXIS_TRANS_ZX: - case MAN_AXIS_SCALE_XY: - case MAN_AXIS_SCALE_YZ: - case MAN_AXIS_SCALE_ZX: - { - const float ofs_ax = 7.0f; - const float ofs[3] = {ofs_ax, ofs_ax, 0.0f}; - WM_manipulator_set_scale(axis, 0.07f); - WM_manipulator_set_matrix_offset_location(axis, ofs); - WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); - break; - } - case MAN_AXIS_TRANS_C: - case MAN_AXIS_ROT_C: - case MAN_AXIS_SCALE_C: - case MAN_AXIS_ROT_T: - WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH); - if (axis_idx == MAN_AXIS_ROT_T) { - WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_HOVER, true); - } - else if (axis_idx == MAN_AXIS_ROT_C) { - WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true); - WM_manipulator_set_scale(axis, 1.2f); - } - else { - WM_manipulator_set_scale(axis, 0.2f); - } - break; - } - - switch (axis_type) { - case MAN_AXES_TRANSLATE: - if (ot_store.translate == NULL) { - ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true); - } - ptr = WM_manipulator_operator_set(axis, 0, ot_store.translate, NULL); - break; - case MAN_AXES_ROTATE: - { - wmOperatorType *ot_rotate; - if (axis_idx == MAN_AXIS_ROT_T) { - if (ot_store.trackball == NULL) { - ot_store.trackball = WM_operatortype_find("TRANSFORM_OT_trackball", true); - } - ot_rotate = ot_store.trackball; - } - else { - if (ot_store.rotate == NULL) { - ot_store.rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true); - } - ot_rotate = ot_store.rotate; - } - ptr = WM_manipulator_operator_set(axis, 0, ot_rotate, NULL); - break; - } - case MAN_AXES_SCALE: - { - if (ot_store.resize == NULL) { - ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true); - } - ptr = WM_manipulator_operator_set(axis, 0, ot_store.resize, NULL); - break; - } - } - - { - PropertyRNA *prop; - if ((prop = RNA_struct_find_property(ptr, "constraint_axis"))) { - RNA_property_boolean_set_array(ptr, prop, constraint_axis); - } - } - - RNA_boolean_set(ptr, "release_confirm", 1); - } - MAN_ITER_AXES_END; -} - -static void WIDGETGROUP_manipulator_setup(const bContext *C, wmManipulatorGroup *mgroup) -{ - ManipulatorGroup *man = manipulatorgroup_init(mgroup); - - mgroup->customdata = man; - - { - man->twtype = 0; - ScrArea *sa = CTX_wm_area(C); - const bToolRef *tref = sa->runtime.tool; - - if (tref == NULL || STREQ(tref->idname, "Transform")) { - /* Setup all manipulators, they can be toggled via 'ToolSettings.manipulator_flag' */ - man->twtype = SCE_MANIP_TRANSLATE | SCE_MANIP_ROTATE | SCE_MANIP_SCALE; - man->use_twtype_refresh = true; - } - else if (STREQ(tref->idname, "Grab")) { - man->twtype |= SCE_MANIP_TRANSLATE; - } - else if (STREQ(tref->idname, "Rotate")) { - man->twtype |= SCE_MANIP_ROTATE; - } - else if (STREQ(tref->idname, "Scale")) { - man->twtype |= SCE_MANIP_SCALE; - } - BLI_assert(man->twtype != 0); - man->twtype_init = man->twtype; - } - - /* *** set properties for axes *** */ - manipulatorgroup_init_properties_from_twtype(mgroup); -} - -static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - ManipulatorGroup *man = mgroup->customdata; - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; - struct TransformBounds tbounds; - - if (man->use_twtype_refresh) { - Scene *scene = CTX_data_scene(C); - man->twtype = scene->toolsettings->manipulator_flag & man->twtype_init; - if (man->twtype != man->twtype_prev) { - man->twtype_prev = man->twtype; - manipulatorgroup_init_properties_from_twtype(mgroup); - } - } - - /* skip, we don't draw anything anyway */ - if ((man->all_hidden = - (ED_transform_calc_manipulator_stats( - C, &(struct TransformCalcParams){ - .use_only_center = true, - }, &tbounds) == 0))) - { - return; - } - - manipulator_prepare_mat(C, v3d, rv3d, &tbounds); - - /* *** set properties for axes *** */ - - MAN_ITER_AXES_BEGIN(axis, axis_idx) - { - const short axis_type = manipulator_get_axis_type(axis_idx); - const int aidx_norm = manipulator_orientation_axis(axis_idx, NULL); - - WM_manipulator_set_matrix_location(axis, rv3d->twmat[3]); - - switch (axis_idx) { - case MAN_AXIS_TRANS_X: - case MAN_AXIS_TRANS_Y: - case MAN_AXIS_TRANS_Z: - case MAN_AXIS_SCALE_X: - case MAN_AXIS_SCALE_Y: - case MAN_AXIS_SCALE_Z: - { - float start_co[3] = {0.0f, 0.0f, 0.0f}; - float len; - - manipulator_line_range(man->twtype, axis_type, &start_co[2], &len); - - WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); - RNA_float_set(axis->ptr, "length", len); - - if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) { - if (man->twtype & SCE_MANIP_ROTATE) { - /* Avoid rotate and translate arrows overlap. */ - start_co[2] += 0.215f; - } - } - WM_manipulator_set_matrix_offset_location(axis, start_co); - WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true); - break; - } - case MAN_AXIS_ROT_X: - case MAN_AXIS_ROT_Y: - case MAN_AXIS_ROT_Z: - WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]); - break; - case MAN_AXIS_TRANS_XY: - case MAN_AXIS_TRANS_YZ: - case MAN_AXIS_TRANS_ZX: - case MAN_AXIS_SCALE_XY: - case MAN_AXIS_SCALE_YZ: - case MAN_AXIS_SCALE_ZX: - { - const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1]; - const float *z_axis = rv3d->twmat[aidx_norm]; - WM_manipulator_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis); - break; - } - } - } - MAN_ITER_AXES_END; -} - -static void WIDGETGROUP_manipulator_message_subscribe( - const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) -{ - Scene *scene = CTX_data_scene(C); - bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - manipulator_xform_message_subscribe(mgroup, mbus, scene, screen, sa, ar, TRANSFORM_WGT_manipulator); -} - -static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) -{ - ManipulatorGroup *man = mgroup->customdata; - // ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - // View3D *v3d = sa->spacedata.first; - RegionView3D *rv3d = ar->regiondata; - float idot[3]; - - /* when looking through a selected camera, the manipulator can be at the - * exact same position as the view, skip so we don't break selection */ - if (man->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) { - MAN_ITER_AXES_BEGIN(axis, axis_idx) - { - WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true); - } - MAN_ITER_AXES_END; - return; - } - manipulator_get_idot(rv3d, idot); - - /* *** set properties for axes *** */ - - MAN_ITER_AXES_BEGIN(axis, axis_idx) - { - const short axis_type = manipulator_get_axis_type(axis_idx); - /* XXX maybe unset _HIDDEN flag on redraw? */ - if (manipulator_is_axis_visible(rv3d, man->twtype, idot, axis_type, axis_idx)) { - WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false); - } - else { - WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true); - continue; - } - - float color[4], color_hi[4]; - manipulator_get_axis_color(axis_idx, idot, color, color_hi); - WM_manipulator_set_color(axis, color); - WM_manipulator_set_color_highlight(axis, color_hi); - - switch (axis_idx) { - case MAN_AXIS_TRANS_C: - case MAN_AXIS_ROT_C: - case MAN_AXIS_SCALE_C: - case MAN_AXIS_ROT_T: - WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]); - break; - } - } - MAN_ITER_AXES_END; -} - -static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *wgt) -{ - /* it's a given we only use this in 3D view */ - bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); - if ((tref_rt == NULL) || - !STREQ(wgt->idname, tref_rt->manipulator_group)) - { - WM_manipulator_group_type_unlink_delayed_ptr(wgt); - return false; - } - - View3D *v3d = CTX_wm_view3d(C); - if (v3d->mpr_flag & (V3D_MANIPULATOR_HIDE | V3D_MANIPULATOR_HIDE_TOOL)) { - return false; - } - return true; -} - -void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt) -{ - wgt->name = "Transform Manipulator"; - wgt->idname = "TRANSFORM_WGT_manipulator"; - - wgt->flag |= WM_MANIPULATORGROUPTYPE_3D; - - wgt->mmap_params.spaceid = SPACE_VIEW3D; - wgt->mmap_params.regionid = RGN_TYPE_WINDOW; - - wgt->poll = WIDGETGROUP_manipulator_poll; - wgt->setup = WIDGETGROUP_manipulator_setup; - wgt->refresh = WIDGETGROUP_manipulator_refresh; - wgt->message_subscribe = WIDGETGROUP_manipulator_message_subscribe; - wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare; -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ -/** \name Scale Cage Manipulator - * \{ */ - -struct XFormCageWidgetGroup { - wmManipulator *manipulator; -}; - -static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmManipulatorGroupType *wgt) -{ - bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); - if (!STREQ(wgt->idname, tref_rt->manipulator_group)) { - WM_manipulator_group_type_unlink_delayed_ptr(wgt); - return false; - } - return true; -} - -static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup) -{ - struct XFormCageWidgetGroup *xmgroup = MEM_mallocN(sizeof(struct XFormCageWidgetGroup), __func__); - const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_3d", true); - xmgroup->manipulator = WM_manipulator_new_ptr(wt_cage, mgroup, NULL); - wmManipulator *mpr = xmgroup->manipulator; - - RNA_enum_set(mpr->ptr, "transform", - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE | - ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE); - - mpr->color[0] = 1; - mpr->color_hi[0] = 1; - - mgroup->customdata = xmgroup; - - { - wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true); - PointerRNA *ptr; - - /* assign operator */ - PropertyRNA *prop_release_confirm = NULL; - PropertyRNA *prop_constraint_axis = NULL; - - int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; - for (int x = 0; x < 3; x++) { - for (int y = 0; y < 3; y++) { - for (int z = 0; z < 3; z++) { - bool constraint[3] = {x != 1, y != 1, z != 1}; - ptr = WM_manipulator_operator_set(mpr, i, ot_resize, NULL); - if (prop_release_confirm == NULL) { - prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm"); - prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis"); - } - RNA_property_boolean_set(ptr, prop_release_confirm, true); - RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint); - i++; - } - } - } - } -} - -static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup *mgroup) -{ - ScrArea *sa = CTX_wm_area(C); - View3D *v3d = sa->spacedata.first; - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - - struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; - wmManipulator *mpr = xmgroup->manipulator; - - struct TransformBounds tbounds; - - if ((ED_transform_calc_manipulator_stats( - C, &(struct TransformCalcParams) { - .use_local_axis = true, - }, &tbounds) == 0) || - equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max)) - { - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true); - } - else { - manipulator_prepare_mat(C, v3d, rv3d, &tbounds); - - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false); - WM_manipulator_set_flag(mpr, WM_MANIPULATOR_GRAB_CURSOR, true); - - float dims[3]; - sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min); - RNA_float_set_array(mpr->ptr, "dimensions", dims); - mul_v3_fl(dims, 0.5f); - - copy_m4_m3(mpr->matrix_offset, rv3d->tw_axis_matrix); - mid_v3_v3v3(mpr->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min); - mul_m3_v3(rv3d->tw_axis_matrix, mpr->matrix_offset[3]); - - PropertyRNA *prop_center_override = NULL; - float center[3]; - float center_global[3]; - int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z; - for (int x = 0; x < 3; x++) { - center[0] = (float)(1 - x) * dims[0]; - for (int y = 0; y < 3; y++) { - center[1] = (float)(1 - y) * dims[1]; - for (int z = 0; z < 3; z++) { - center[2] = (float)(1 - z) * dims[2]; - struct wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, i); - if (prop_center_override == NULL) { - prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override"); - } - mul_v3_m4v3(center_global, mpr->matrix_offset, center); - RNA_property_float_set_array(&mpop->ptr, prop_center_override, center_global); - i++; - } - } - } - } -} - -static void WIDGETGROUP_xform_cage_message_subscribe( - const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) -{ - Scene *scene = CTX_data_scene(C); - bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - manipulator_xform_message_subscribe(mgroup, mbus, scene, screen, sa, ar, VIEW3D_WGT_xform_cage); -} - -static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) -{ - struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; - wmManipulator *mpr = xmgroup->manipulator; - - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - if (ob && ob->mode & OB_MODE_EDIT) { - copy_m4_m4(mpr->matrix_space, ob->obmat); - } - else { - unit_m4(mpr->matrix_space); - } -} - -void VIEW3D_WGT_xform_cage(wmManipulatorGroupType *wgt) -{ - wgt->name = "Transform Cage"; - wgt->idname = "VIEW3D_WGT_xform_cage"; - - wgt->flag |= WM_MANIPULATORGROUPTYPE_3D; - - wgt->mmap_params.spaceid = SPACE_VIEW3D; - wgt->mmap_params.regionid = RGN_TYPE_WINDOW; - - wgt->poll = WIDGETGROUP_xform_cage_poll; - wgt->setup = WIDGETGROUP_xform_cage_setup; - wgt->refresh = WIDGETGROUP_xform_cage_refresh; - wgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe; - wgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare; -} - -/** \} */ diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index fa21facefc2..97ea0da6007 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -63,7 +63,7 @@ set(SRC ../include/ED_lattice.h ../include/ED_logic.h ../include/ED_markers.h - ../include/ED_manipulator_library.h + ../include/ED_gizmo_library.h ../include/ED_mask.h ../include/ED_mball.h ../include/ED_mesh.h -- cgit v1.2.3