1 # SPDX-FileCopyrightText: 2010-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
8 from gpu_extras
.batch
import batch_for_shader
11 from mathutils
import Vector
13 SpaceView3D
= bpy
.types
.SpaceView3D
16 if not bpy
.app
.background
:
17 single_color_shader
= gpu
.shader
.from_builtin('UNIFORM_COLOR')
18 smooth_color_shader
= gpu
.shader
.from_builtin('SMOOTH_COLOR')
20 single_color_shader
= None
21 smooth_color_shader
= None
23 COLOR_POINT
= (1.0, 0.0, 1.0, 1)
24 COLOR_LINE
= (0.5, 0.5, 1, 1)
25 COLOR_LINE_ACTIVE
= (1.0, 1.0, 0.5, 1)
26 COLOR_BOUNDING_BOX
= (1.0, 1.0, 1.0, 1.0)
27 COLOR_BOUNDING_BOX_ACTIVE
= (1.0, 0.5, 0.0, 1.0)
30 def tag_redraw_areas():
33 # Py can't access notifers
34 for window
in context
.window_manager
.windows
:
35 for area
in window
.screen
.areas
:
36 if area
.type in ['VIEW_3D', 'PROPERTIES']:
40 def callback_enable():
44 handle_pixel
= SpaceView3D
.draw_handler_add(draw_callback_px
, (), 'WINDOW', 'POST_PIXEL')
45 handle_view
= SpaceView3D
.draw_handler_add(draw_callback_view
, (), 'WINDOW', 'POST_VIEW')
46 callback_handle
[:] = handle_pixel
, handle_view
51 def callback_disable():
52 if not callback_handle
:
55 handle_pixel
, handle_view
= callback_handle
56 SpaceView3D
.draw_handler_remove(handle_pixel
, 'WINDOW')
57 SpaceView3D
.draw_handler_remove(handle_view
, 'WINDOW')
58 callback_handle
[:] = []
63 def draw_callback_px():
66 if context
.window_manager
.MathVisProp
.name_hide
:
70 ui_scale
= context
.preferences
.system
.ui_scale
71 blf
.size(font_id
, round(12 * ui_scale
))
73 data_matrix
, data_quat
, data_euler
, data_vector
, data_vector_array
= utils
.console_math_data()
74 if not data_matrix
and not data_quat
and not data_euler
and not data_vector
and not data_vector_array
:
77 region
= context
.region
78 region3d
= context
.space_data
.region_3d
80 region_mid_width
= region
.width
/ 2.0
81 region_mid_height
= region
.height
/ 2.0
83 perspective_matrix
= region3d
.perspective_matrix
.copy()
85 def draw_text(text
, vec
, dx
=3.0, dy
=-4.0):
86 vec_4d
= perspective_matrix
@ vec
.to_4d()
88 x
= region_mid_width
+ region_mid_width
* (vec_4d
.x
/ vec_4d
.w
)
89 y
= region_mid_height
+ region_mid_height
* (vec_4d
.y
/ vec_4d
.w
)
91 blf
.position(font_id
, x
+ dx
, y
+ dy
, 0.0)
92 blf
.draw(font_id
, text
)
95 for key
, vec
in data_vector
.items():
99 for key
, vec
in data_vector_array
.items():
101 draw_text(key
, vec
[0])
104 for key
, mat
in data_matrix
.items():
105 loc
= Vector((mat
[0][3], mat
[1][3], mat
[2][3]))
106 draw_text(key
, loc
, dx
=10, dy
=-20)
110 loc
= context
.scene
.cursor
.location
.copy()
111 for key
, mat
in data_quat
.items():
112 draw_text(key
, loc
, dy
=-offset_y
)
116 loc
= context
.scene
.cursor
.location
.copy()
117 for key
, mat
in data_euler
.items():
118 draw_text(key
, loc
, dy
=-offset_y
)
122 def draw_callback_view():
123 settings
= bpy
.context
.window_manager
.MathVisProp
124 prop_states
= bpy
.context
.window_manager
.MathVisStatePropList
126 scale
= settings
.bbox_scale
127 with_bounding_box
= not settings
.bbox_hide
129 if settings
.in_front
:
130 gpu
.state
.depth_test_set('ALWAYS')
132 gpu
.state
.depth_test_set('LESS')
134 data_matrix
, data_quat
, data_euler
, data_vector
, data_vector_array
= utils
.console_math_data()
135 if settings
.index
in range(0,len(prop_states
)):
136 active_index
= settings
.index
137 active_key
= prop_states
[active_index
].name
143 coords
= [tuple(vec
.to_3d()) for vec
in data_vector
.values()]
146 if data_vector_array
:
147 for key
, line
in data_vector_array
.items():
148 coords
= [tuple(vec
.to_3d()) for vec
in line
]
149 if key
== active_key
:
150 draw_line(coords
, COLOR_LINE_ACTIVE
)
152 draw_line(coords
, COLOR_LINE
)
155 draw_matrices(data_matrix
, scale
, with_bounding_box
, active_key
)
157 if data_euler
or data_quat
:
158 cursor
= bpy
.context
.scene
.cursor
.location
.copy()
159 derived_matrices
= dict()
160 for key
, quat
in data_quat
.items():
161 matrix
= quat
.to_matrix().to_4x4()
162 matrix
.translation
= cursor
163 derived_matrices
[key
] = matrix
164 for key
, eul
in data_euler
.items():
165 matrix
= eul
.to_matrix().to_4x4()
166 matrix
.translation
= cursor
167 derived_matrices
[key
] = matrix
168 draw_matrices(derived_matrices
, scale
, with_bounding_box
, active_key
)
171 def draw_points(points
):
172 batch
= batch_from_points(points
, "POINTS")
173 single_color_shader
.bind()
174 single_color_shader
.uniform_float("color", COLOR_POINT
)
175 batch
.draw(single_color_shader
)
178 def draw_line(points
, color
):
179 batch
= batch_from_points(points
, "LINE_STRIP")
180 single_color_shader
.bind()
181 single_color_shader
.uniform_float("color", color
)
182 batch
.draw(single_color_shader
)
185 def batch_from_points(points
, type):
186 return batch_for_shader(single_color_shader
, type, {"pos": points
})
189 def draw_matrices(matrices
, scale
, with_bounding_box
, active_key
):
190 x_p
= Vector((scale
, 0.0, 0.0))
191 x_n
= Vector((-scale
, 0.0, 0.0))
192 y_p
= Vector((0.0, scale
, 0.0))
193 y_n
= Vector((0.0, -scale
, 0.0))
194 z_p
= Vector((0.0, 0.0, scale
))
195 z_n
= Vector((0.0, 0.0, -scale
))
197 red_dark
= (0.2, 0.0, 0.0, 1.0)
198 red_light
= (1.0, 0.2, 0.2, 1.0)
199 green_dark
= (0.0, 0.2, 0.0, 1.0)
200 green_light
= (0.2, 1.0, 0.2, 1.0)
201 blue_dark
= (0.0, 0.0, 0.2, 1.0)
202 blue_light
= (0.4, 0.4, 1.0, 1.0)
208 for key
, matrix
in matrices
.items():
209 coords
.append(matrix
@ x_n
)
210 coords
.append(matrix
@ x_p
)
211 colors
.extend((red_dark
, red_light
))
212 coords
.append(matrix
@ y_n
)
213 coords
.append(matrix
@ y_p
)
214 colors
.extend((green_dark
, green_light
))
215 coords
.append(matrix
@ z_n
)
216 coords
.append(matrix
@ z_p
)
217 colors
.extend((blue_dark
, blue_light
))
218 if key
== active_key
:
219 active
.append(matrix
)
221 selected
.append(matrix
)
223 batch
= batch_for_shader(smooth_color_shader
, "LINES", {
227 batch
.draw(smooth_color_shader
)
229 if with_bounding_box
:
231 draw_bounding_boxes(selected
, scale
, COLOR_BOUNDING_BOX
)
233 draw_bounding_boxes(active
, scale
, COLOR_BOUNDING_BOX_ACTIVE
)
236 def draw_bounding_boxes(matrices
, scale
, color
):
238 for x
in (-scale
, scale
):
239 for y
in (-scale
, scale
):
240 for z
in (-scale
, scale
):
241 boundbox_points
.append(Vector((x
, y
, z
)))
244 (0, 1), (1, 3), (3, 2), (2, 0), (0, 4), (4, 5),
245 (5, 7), (7, 6), (6, 4), (1, 5), (2, 6), (3, 7)
249 for matrix
in matrices
:
250 for v1
, v2
in boundbox_lines
:
251 points
.append(matrix
@ boundbox_points
[v1
])
252 points
.append(matrix
@ boundbox_points
[v2
])
254 batch
= batch_from_points(points
, "LINES")
256 single_color_shader
.bind()
257 single_color_shader
.uniform_float("color", color
)
258 batch
.draw(single_color_shader
)