Skip to content

Commit 49987e1

Browse files
chambartKeryan-dev
andauthored
Saucisse (#147)
* Saucisse * Backward compatibility --------- Co-authored-by: Keryan Didier <[email protected]>
1 parent 0fe51c1 commit 49987e1

File tree

3 files changed

+326
-0
lines changed

3 files changed

+326
-0
lines changed

examples/configure.ml

+1
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,4 @@ let () =
6969
add_executable "demo4" [];
7070
add_executable "demo5" [];
7171
add_executable "demo6" [];
72+
add_executable "saucisse" [];

examples/dune.inc

+8
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,11 @@
222222
(modules demo6)
223223
(libraries ocaml-canvas react))
224224

225+
226+
(executable
227+
(name saucisse)
228+
(public_name ocaml-canvas-saucisse)
229+
(modes byte_complete native js)
230+
(modules saucisse)
231+
(libraries ocaml-canvas react))
232+

examples/saucisse.ml

+317
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
open OcamlCanvas.V1
2+
3+
let option_iter f o = match o with None -> () | Some e -> f e
4+
5+
let sw = 800
6+
let sh = 800
7+
8+
let base_y = 300.
9+
let p1 : Point.t = (200., base_y)
10+
let p2 : Point.t = (600., base_y)
11+
12+
let oeuil_y = base_y -. 200.
13+
14+
let o1 = (300., oeuil_y)
15+
let o2 = (500., oeuil_y)
16+
17+
let saucisse_width = 30.
18+
let saucisse_color = Color.orange
19+
20+
let mid = Point.barycenter 1. p1 1. p2
21+
22+
let p3 : Point.t ref = ref (fst mid, 300.)
23+
24+
let () =
25+
Backend.init ()
26+
27+
let c =
28+
Canvas.createOnscreen ~title:"Saucisse"
29+
~pos:(0, 0) ~size:(sw, sh) ()
30+
31+
let rot (x, y) = (-.y, x)
32+
33+
let (++) (x1, y1) (x2, y2) = x1 +. x2, y1 +. y2
34+
let (--) (x1, y1) (x2, y2) = x1 -. x2, y1 -. y2
35+
let normalize (x, y) =
36+
let norm = sqrt (x *. x +. y *. y) in
37+
x /. norm, y /. norm
38+
let dir p1 p2 =
39+
normalize (p2 -- p1)
40+
let scale v (x, y) =
41+
v *. x, v *. y
42+
43+
let disc ?color ?gradient center radius =
44+
option_iter (Canvas.setFillColor c) color;
45+
option_iter (Canvas.setFillGradient c) gradient;
46+
Canvas.clearPath c;
47+
Canvas.arc c ~center
48+
~radius ~theta1:0.0 ~theta2:(2.0 *. Const.pi) ~ccw:false;
49+
Canvas.fill c ~nonzero:false
50+
51+
let circle ~color center radius =
52+
Canvas.setStrokeColor c color;
53+
Canvas.clearPath c;
54+
Canvas.arc c ~center
55+
~radius ~theta1:0.0 ~theta2:(2.0 *. Const.pi) ~ccw:false;
56+
Canvas.stroke c
57+
58+
let point ?(color=Color.red) center =
59+
disc ~color center 5.0
60+
61+
let taille_oeuil = 30.
62+
let taille_pupille = 10.
63+
let cursor_z = 100.
64+
65+
let gray n = Color.of_rgb n n n
66+
67+
let sourcil pos dir ratio =
68+
let w = 50. in
69+
let p0 = pos ++ (-.w, 0.) in
70+
let p2 = pos ++ (w, 0.) in
71+
let dy =
72+
ratio *. 20.
73+
in
74+
let p0, p2 =
75+
if dir then
76+
p0, p2 ++ (0., dy)
77+
else
78+
p0 ++ (0., dy), p2
79+
in
80+
let ratio = if dir then ratio else 1. -. ratio in
81+
let b = Point.barycenter ratio p0 (1. -. ratio) p2 in
82+
let p1 = b ++ (0., -.20.) in
83+
let p3 = b ++ (0., -.5.) in
84+
let pa = Path.create () in
85+
Path.moveTo pa p0;
86+
Path.lineTo pa p1;
87+
Path.lineTo pa p2;
88+
Path.lineTo pa p3;
89+
Path.close pa;
90+
Canvas.setFillColor c Color.black;
91+
Canvas.setStrokeColor c Color.black;
92+
Canvas.fillPath c pa ~nonzero:false;
93+
Canvas.strokePath c pa;
94+
()
95+
96+
let oeuil pos dir is_left sourcil_ratio =
97+
let g =
98+
Gradient.createRadial
99+
~center1:(pos ++ (-.15., 10.))
100+
~rad1:1.
101+
~center2:pos
102+
~rad2:30.
103+
in
104+
Gradient.addColorStop g Color.white 0.;
105+
Gradient.addColorStop g (gray 235) 0.2;
106+
Gradient.addColorStop g (gray 230) 0.85;
107+
Gradient.addColorStop g (gray 100) 1.;
108+
disc ~gradient:g pos taille_oeuil;
109+
circle ~color:Color.black pos taille_oeuil;
110+
let pup =
111+
let (x, y) = dir -- pos in
112+
let ax = atan2 cursor_z x in
113+
let ay = atan2 cursor_z y in
114+
let x = cos ax in
115+
let y = cos ay in
116+
let o = (x, y) in
117+
scale 20. o ++ pos
118+
in
119+
disc ~color:Color.black pup taille_pupille;
120+
sourcil (pos -- (0., 50.)) is_left sourcil_ratio
121+
122+
let controls a b =
123+
let v = scale saucisse_width (dir a b) in
124+
let p1 = b ++ rot v in
125+
let p2 = b ++ v ++ rot v in
126+
let p3 = b ++ v in
127+
let p4 = b ++ v -- rot v in
128+
let p5 = b -- rot v in
129+
v, p1, p2, p3, p4, p5
130+
131+
let bout path a b =
132+
let _v, _p1, p2, p3, p4, p5 = controls a b in
133+
Path.arcTo path ~p1:p2 ~p2:p3 ~radius:saucisse_width;
134+
Path.arcTo path ~p1:p4 ~p2:p5 ~radius:saucisse_width;
135+
()
136+
137+
let bouboule_radius = 10.
138+
139+
let bouboule v p =
140+
let v = normalize v in
141+
let center = p ++ (scale (saucisse_width +. bouboule_radius) v) in
142+
disc ~color:saucisse_color center bouboule_radius;
143+
circle ~color:Color.black center bouboule_radius
144+
145+
let tri v p =
146+
let v = normalize v in
147+
let center = p ++ (scale (saucisse_width +. bouboule_radius) v) in
148+
let size_bout = 30. in
149+
let p1 = center ++ (scale size_bout v) ++ (scale 15. (rot v)) in
150+
let p2 = center ++ (scale size_bout v) -- (scale 15. (rot v)) in
151+
let pa = Path.create () in
152+
Path.moveTo pa center;
153+
Path.lineTo pa p1;
154+
Path.lineTo pa p2;
155+
Path.close pa;
156+
Canvas.setFillColor c saucisse_color;
157+
Canvas.fillPath c pa ~nonzero:false;
158+
Canvas.setStrokeColor c Color.black;
159+
Canvas.strokePath c pa;
160+
161+
bouboule v p;
162+
()
163+
164+
module F = struct
165+
type 'a t = {
166+
c : 'a list;
167+
s : int;
168+
}
169+
170+
let make v s = { c = [v]; s }
171+
172+
let push v s =
173+
let l = List.length s.c in
174+
let c =
175+
if l >= s.s then
176+
List.rev (List.tl (List.rev s.c))
177+
else
178+
s.c
179+
in
180+
{ s with c = v :: c }
181+
182+
let mean s =
183+
List.fold_left (fun acc v -> acc +. v) 0. s.c /. (float s.s)
184+
end
185+
186+
let time () =
187+
(Int64.to_float @@ Backend.getCurrentTimestamp ()) /. 1_000_000.
188+
189+
let last_frame_time = ref (time ())
190+
let frame_time : float F.t ref = ref (F.make 100. 30)
191+
let push_time t =
192+
let dt = t -. !last_frame_time in
193+
last_frame_time := t;
194+
frame_time := F.push dt !frame_time
195+
let fps () = 1. /. F.mean !frame_time
196+
197+
let draw () =
198+
199+
let t = time () in
200+
201+
let truc = 20. in
202+
203+
let p1 = p1 ++ (truc *. 2.1 *. sin (3.1 *. t) , truc *. 2. *. cos (4. *. t)) in
204+
let p2 = p2 ++ (truc *. 2.1 *. sin (5.1 *. t) , truc *. 2.3 *. cos (4.2 *. t)) in
205+
206+
let p3 = !p3 in
207+
let p3_oeuil = p3 in
208+
let p3 =
209+
let o = 40. in
210+
let x = max (fst p1 +. o) (min (fst p2 -. o) (fst p3)) in
211+
(x, snd p3)
212+
in
213+
Canvas.setFillColor c saucisse_color;
214+
let path = Path.create () in
215+
let v1, x, _, _, _, a = controls p3 p1 in
216+
Path.moveTo path x;
217+
bout path p3 p1;
218+
let v2, b, _, _, _, a2 = controls p3 p2 in
219+
let v = (0., saucisse_width) in
220+
221+
let ratio = 0.8 +. 0.3 *. sin (2. *. t) in
222+
223+
let pos a cont =
224+
a ++ (scale ratio (cont -- a))
225+
in
226+
227+
let d = p3 ++ v in
228+
Path.bezierCurveTo path
229+
~cp1:(pos a d)
230+
~cp2:(pos b d)
231+
~p:b;
232+
233+
bout path p3 p2;
234+
235+
let u = p3 -- v in
236+
Path.bezierCurveTo path
237+
~cp1:(pos a2 u)
238+
~cp2:(pos x u)
239+
~p:x;
240+
Path.close path;
241+
Canvas.setFillColor c saucisse_color;
242+
Canvas.fillPath c path ~nonzero:false;
243+
Canvas.setStrokeColor c Color.black;
244+
Canvas.strokePath c path;
245+
246+
tri v1 p1;
247+
tri v2 p2;
248+
249+
let sourcil_ratio =
250+
let r =
251+
let dy = snd p3 -. (base_y +. 200.) in
252+
-. (dy /. 400.)
253+
in
254+
min 0.95 (max 0.05 r)
255+
in
256+
257+
oeuil o1 p3_oeuil true sourcil_ratio;
258+
oeuil o2 p3_oeuil false sourcil_ratio;
259+
260+
push_time (time ());
261+
262+
let fps_s = Printf.sprintf "%0.2f" (fps ()) in
263+
Canvas.setFillColor c Color.black;
264+
Canvas.fillText c fps_s (10., 10.);
265+
266+
Canvas.show c
267+
268+
let () =
269+
draw ()
270+
271+
let e_move =
272+
React.E.map (fun { Event.canvas = _; timestamp = _; data = (x, y) } ->
273+
p3 := (float_of_int x, float_of_int y)
274+
) Event.mouse_move
275+
276+
let e1 =
277+
React.E.map (fun { Event.canvas = _; timestamp = _; data = () } ->
278+
Backend.stop ()
279+
) Event.close
280+
281+
let e2 =
282+
React.E.map (fun { Event.canvas = _; timestamp = _;
283+
data = { Event.key; char = _; flags = _ }; _ } ->
284+
if key = KeyEscape then
285+
Backend.stop ()
286+
) Event.key_down
287+
288+
let e3 =
289+
React.E.map (fun { Event.canvas = _; timestamp = _;
290+
data = { Event.position = (x, y); _ } } ->
291+
point (float_of_int x, float_of_int y);
292+
) Event.button_down
293+
294+
let frames = ref 0L
295+
296+
let e_frame =
297+
React.E.map (fun { Event.canvas = _; timestamp = _; _ } ->
298+
Canvas.setFillColor c Color.white;
299+
Canvas.fillRect c ~pos:(0.0, 0.0) ~size:(float_of_int sw, float_of_int sh);
300+
301+
draw ();
302+
frames := Int64.add !frames Int64.one
303+
) Event.frame
304+
305+
let () =
306+
if Array.length Sys.argv >= 2 && Sys.argv.(1) = "bench" then
307+
for _ = 0 to 1_000 do
308+
draw ();
309+
done
310+
else
311+
Backend.run (fun () ->
312+
ignore (Sys.opaque_identity e_frame);
313+
ignore (Sys.opaque_identity e_move);
314+
ignore (Sys.opaque_identity (e1, e2));
315+
ignore (Sys.opaque_identity (e3));
316+
Printf.printf "\nDisplayed %Ld frames. Goodbye !\n" !frames)
317+

0 commit comments

Comments
 (0)