1use {
2 crate::{
3 makepad_platform::*,
4 cx_2d::Cx2d,
7 DrawQuad
9 },
10};
11
12live_design! {
13 use makepad_draw::shader::std::*;
14 DrawLine= {{DrawLine}} {
15
16 fn stroke(self, side:float, progress: float) -> vec4{
17 return self.color;
18 }
19
20 fn pixel(self) -> vec4 {
21 let p = self.pos * self.rect_size;
22 let b = self.line_end;
23 let a = self.line_start;
24
25 let ba = b-a;
26 let pa = p-a;
27 let h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
28 let dist= length(pa-h*ba)
29
30 let linemult = smoothstep(self.half_line_width-1., self.half_line_width, dist);
31 let C = self.stroke(dist, h);
32 return vec4(C.xyz*(1.-linemult),(1.0-linemult)*C.a);
33 }
34 }
35}
36
37#[derive(Live, LiveHook, LiveRegister)]
38#[repr(C)]
39pub struct DrawLine {
40 #[deref] pub draw_super: DrawQuad,
41 #[calc] pub line_start: Vec2,
42 #[calc] pub line_end: Vec2,
43 #[calc] pub half_line_width: f32,
44 #[calc] pub color: Vec4,
45}
46
47impl DrawLine
48{
49 pub fn get_bezier_point(&mut self,t: f64, control_points: &Vec<DVec2>,index: usize, count: usize) -> DVec2
50 {
51 if count == 1
52 {
53 return control_points[index];
54 }
55 let p0 = self.get_bezier_point(t, control_points, index, count - 1);
56 let p1 = self.get_bezier_point(t, control_points, index + 1, count - 1);
57 return p0*t + p1*(1.0-t);
58 }
59
60
61 pub fn draw_bezier_abs(&mut self, cx: &mut Cx2d, points: &Vec<DVec2>, color: Vec4, line_width: f64 )
62 {
63 let step = 0.01;
64 let mut t = 0.0;
65 let mut from = points[points.len()-1];
67 while t< 1.
68 {
69 let nextt = t + step;
70 let next = self.get_bezier_point(nextt, &points, 0 , points.len()) ;
72
73 self.draw_line_abs(cx, from, next, color, line_width);
74 from = next;
75 t = nextt;
77 }
78
79 }
80
81 pub fn draw_line_abs(&mut self, cx: &mut Cx2d, line_start: DVec2, line_end: DVec2, color: Vec4, line_width: f64 )
82 {
83 let maxpixels = 300. as f64;
84
85 let hw = line_width / 2.;
86
87 self.half_line_width = hw as f32;
88 self.color = color;
89
90
91 let linerect = line_end - line_start;
92 if (line_start.y - line_end.y).abs().floor() == 0.0
93 || (line_start.x - line_end.x).abs().floor() == 0.0
94 {
95 let r = Rect {
96 pos: dvec2(
97 min(line_start.x, line_end.x) - hw,
98 min(line_start.y, line_end.y) - hw,
99 ),
100 size: dvec2(
101 linerect.x.abs() + line_width,
102 linerect.y.abs() + line_width,
103 ),
104 };
105
106 self.line_start = (line_start - r.pos).into_vec2();
107 self.line_end = (line_end - r.pos).into_vec2();
108
109 self.draw_abs(cx, r);
110
111 return;
112 }
113
114 if linerect.x.abs() > linerect.y.abs()
115 {
117 let mut actualstart = line_start;
118 let mut actualend = line_end;
119
120 if actualend.x < actualstart.x {
121 std::mem::swap(&mut actualstart, &mut actualend);
122 }
123
124 let delta = actualend - actualstart;
125 let normalizedelta = delta.normalize();
126 let xnormalizedelta = delta.normalize_to_x();
127 let normalizedarea = (xnormalizedelta.x * xnormalizedelta.y).abs();
128 let scaledup = (maxpixels / normalizedarea).sqrt();
129
130 let angle = delta.angle_in_radians();
131 let tanangle = angle.tan();
132
133 let clocktang = normalizedelta.clockwise_tangent();
134
135 let circlepoint = clocktang * hw;
136 let overside = hw - circlepoint.y;
137 let aanliggend = overside / tanangle;
138 let backoffset = circlepoint.x.abs() - aanliggend.abs();
139
140
141 let rectstart = Rect {
142 pos: actualstart - dvec2(hw, hw),
143 size: dvec2(hw - backoffset, line_width),
144 };
145
146 let rectend = Rect {
147 pos: actualend - dvec2(-backoffset, hw),
148 size: dvec2(hw - backoffset, line_width),
149 };
150
151 let miny = min(rectstart.pos.y, rectend.pos.y);
152 let maxy = max(
153 rectend.pos.y + rectend.size.y,
154 rectstart.pos.y + rectstart.size.y,
155 );
156
157 let innerwidth = rectend.pos.x - (rectstart.pos.x + rectstart.size.x);
158 let numblocks = (innerwidth / scaledup).ceil();
159 let blockwidth = innerwidth / (numblocks as f64);
160
161 let step = dvec2(blockwidth, xnormalizedelta.y * blockwidth);
162 let mut adjust = -backoffset * 2. * xnormalizedelta.y;
163 if step.y < 0. {
164 adjust = step.y;
165 }
166 let blockheight = line_width / angle.cos() + step.y.abs();
167
168 let segmentstart = dvec2(rectstart.pos.x + rectstart.size.x, rectstart.pos.y + adjust);
169
170 for i in 0..(numblocks as i32) as i32 {
171 let mut r = Rect {
172 pos: segmentstart + step * (i as f64),
173 size: dvec2(blockwidth, blockheight),
174 };
175 r.clip_y_between(miny, maxy);
176
177 self.line_start = (actualstart - r.pos).into_vec2();
178 self.line_end = (actualend - r.pos).into_vec2();
179
180 self.draw_abs(cx, r);
181 }
182
183 self.line_start = (actualstart - rectstart.pos).into_vec2();
184 self.line_end = (actualend - rectstart.pos).into_vec2();
185
186 self.draw_abs(cx, rectstart);
187
188 self.line_start = (actualstart - rectend.pos).into_vec2();
189 self.line_end = (actualend - rectend.pos).into_vec2();
190
191 self.draw_abs(cx, rectend);
192
193
194 } else {
195 let mut actualstart = line_start;
196 let mut actualend: DVec2 = line_end;
197
198 if actualend.y < actualstart.y {
199 std::mem::swap(&mut actualstart, &mut actualend);
200 }
201 let delta = actualend - actualstart;
202 let normalizedelta = delta.normalize();
203 let ynormalizedelta = delta.normalize_to_y();
204 let normalizedarea = (ynormalizedelta.x * ynormalizedelta.y).abs();
205 let scaledup = (maxpixels / normalizedarea).sqrt();
206 let angle = delta.angle_in_radians() - std::f64::consts::PI/2.;
207 let tanangle = angle.tan();
208 let circlepoint = normalizedelta * hw;
209 let overside = hw - circlepoint.y;
210 let aanliggend = overside / tanangle;
211 let backoffset = circlepoint.x.abs() - aanliggend.abs();
212
213 let rectstart = Rect {
214 pos: actualstart - dvec2(hw, hw),
215 size: dvec2(line_width, hw - backoffset),
216 };
217 let rectend = Rect {
218 pos: actualend - dvec2(hw, -backoffset),
219 size: dvec2(line_width, hw - backoffset),
220 };
221 let minx = min(rectstart.pos.x, rectend.pos.x);
222 let maxx = max(
223 rectend.pos.x + rectend.size.x,
224 rectstart.pos.x + rectstart.size.x,
225 );
226
227 let innerheight = rectend.pos.y - (rectstart.pos.y + rectstart.size.y);
228 let numblocks = (innerheight / scaledup).ceil();
229 let blockheight = innerheight / (numblocks as f64);
230
231 let step = dvec2( ynormalizedelta.x * blockheight, blockheight);
232 let mut adjust = -backoffset * 2. * ynormalizedelta.x;
233 if step.x < 0. {
234 adjust = step.x;
235 }
236 let blockwidth = line_width / angle.cos() + step.x.abs();
237
238
239
240 let segmentstart = dvec2(rectstart.pos.x + adjust, rectstart.pos.y + rectstart.size.y);
241
242
243 for i in 0..(numblocks as i32) as i32 {
244 let mut r = Rect {
245 pos: segmentstart + step * (i as f64),
246 size: dvec2(blockwidth, blockheight),
247 };
248 r.clip_x_between(minx, maxx);
249
250 self.line_start = (actualstart - r.pos).into_vec2();
251 self.line_end = (actualend - r.pos).into_vec2();
252
253 self.draw_abs(cx, r);
254 }
255
256 self.line_start = (actualstart - rectstart.pos).into_vec2();
257 self.line_end = (actualend - rectstart.pos).into_vec2();
258
259 self.draw_abs(cx, rectstart);
260
261 self.line_start = (actualstart - rectend.pos).into_vec2();
262 self.line_end = (actualend - rectend.pos).into_vec2();
263
264 self.draw_abs(cx, rectend);
265
266
267 }
268 }
269
270}