11"""Viewport decorations"""
22import math
3+ from functools import reduce
34from bpy .types import SpaceView3D
45from mathutils import Vector
56import bpy
67import blf
78from bpy_extras .view3d_utils import location_3d_to_region_2d
9+ import gpu
10+ import bgl
11+ from gpu .types import GPUShader , GPUBatch , GPUIndexBuf , GPUVertBuf , GPUVertFormat
12+ from gpu_extras .batch import batch_for_shader
813
914
1015class ViewDecorator (object ):
@@ -31,11 +36,81 @@ class DimensionDecorator(ViewDecorator):
3136 - puts metric text next to each segment
3237 """
3338
39+ VERT_GLSL = """
40+ uniform mat4 viewMatrix;
41+ in vec3 pos;
42+ out vec4 gl_Position;
43+
44+ void main() {
45+ gl_Position = viewMatrix * vec4(pos, 1.0);
46+ }
47+ """
48+ GEOM_GLSL = """
49+ layout(lines) in;
50+ layout(line_strip, max_vertices=8) out;
51+
52+ uniform float angle;
53+ uniform float length;
54+
55+ void main() {
56+ vec4 p0 = gl_in[0].gl_Position, p1 = gl_in[1].gl_Position;
57+ float c = cos(angle), s = sin(angle);
58+ mat4 rot_a = mat4( c, -s, 0, 0,
59+ +s, c, 0, 0,
60+ 0, 0, 1, 0,
61+ 0, 0, 0, 1);
62+ mat4 rot_b = mat4( c, +s, 0, 0,
63+ -s, c, 0, 0,
64+ 0, 0, 1, 0,
65+ 0, 0, 0, 1);
66+
67+ vec4 dir = normalize(p1 - p0);
68+
69+ vec4 arr_a = rot_a * dir * length;
70+ vec4 arr_b = rot_b * dir * length;
71+
72+ gl_Position = p0;
73+ EmitVertex();
74+ gl_Position = p1;
75+ EmitVertex();
76+ EndPrimitive();
77+
78+ gl_Position = p0 + arr_a;
79+ EmitVertex();
80+ gl_Position = p0;
81+ EmitVertex();
82+ gl_Position = p0 + arr_b;
83+ EmitVertex();
84+ EndPrimitive();
85+
86+ gl_Position = p1 - arr_a;
87+ EmitVertex();
88+ gl_Position = p1;
89+ EmitVertex();
90+ gl_Position = p1 - arr_b;
91+ EmitVertex();
92+ EndPrimitive();
93+ }
94+ """
95+ FRAG_GLSL = """
96+ uniform vec3 color;
97+ out vec4 fragColor;
98+
99+ void main() {
100+ fragColor = vec4(color, 1.0);
101+ }
102+ """
103+
34104 def __init__ (self , props , context ):
35105 self .context = context
36106 self .props = props
37107 self .font_id = 0 # TODO: take font from styles
38108 self .dpi = context .preferences .system .dpi
109+ self .shader = self .create_shader ()
110+
111+ @classmethod
112+ def create_shader (cls ):
113+ return GPUShader (vertexcode = cls .VERT_GLSL , fragcode = cls .FRAG_GLSL , geocode = cls .GEOM_GLSL )
39114
40115 def __call__ (self ):
41116 # get active drawing, if any
@@ -48,9 +123,10 @@ def __call__(self):
48123 return
49124 curve = collection .all_objects ['IfcAnnotation/Dimension' ]
50125
51- for segm in self .iter_segments (curve ):
126+ segments = list (self .iter_segments (curve ))
127+ self .draw_arrows (segments )
128+ for segm in segments :
52129 self .draw_label (segm )
53- self .draw_arrow (segm )
54130
55131 def iter_segments (self , curve ):
56132 """Yields each segment converted to world coords
@@ -105,5 +181,18 @@ def draw_label(self, segm):
105181 blf .draw (self .font_id , text )
106182 blf .disable (self .font_id , blf .ROTATION )
107183
108- def draw_arrow (self , segm ):
109- pass
184+ def draw_arrows (self , segments ):
185+ def coords (segm ):
186+ return [(segm [0 ].x , segm [0 ].y , segm [0 ].z ),
187+ (segm [1 ].x , segm [1 ].y , segm [1 ].z )]
188+ points = list (reduce (lambda points , segm : points + coords (segm ),
189+ segments , []))
190+ batch = batch_for_shader (self .shader , 'LINES' , {'pos' : points })
191+ self .shader .bind ()
192+ matrix = self .context .region_data .perspective_matrix
193+ self .shader .uniform_float ("viewMatrix" , matrix )
194+ # TODO: get everything from styles
195+ self .shader .uniform_float ('color' , (1.0 , 1.0 , 1.0 ))
196+ self .shader .uniform_float ('angle' , math .pi / 12 )
197+ self .shader .uniform_float ('length' , 0.05 )
198+ batch .draw (self .shader )
0 commit comments