From 78dfc33668fefcbf5431c34ab6c688e0780bf10b Mon Sep 17 00:00:00 2001 From: Michael Dales Date: Thu, 28 Aug 2025 07:24:13 +0100 Subject: [PATCH] Add flying camels example --- README.md | 1 + flying_camels/README.md | 1 + flying_camels/bin/dune | 4 +++ flying_camels/bin/main.ml | 56 ++++++++++++++++++++++++++++++++ flying_camels/images/logo48.png | Bin 0 -> 1698 bytes 5 files changed, 62 insertions(+) create mode 100644 flying_camels/README.md create mode 100644 flying_camels/bin/dune create mode 100644 flying_camels/bin/main.ml create mode 100644 flying_camels/images/logo48.png diff --git a/README.md b/README.md index 1bd4db6..8cb7586 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ To run these you will need to install Claudius via opam, and then you can `dune These examples just show a single feature of Claudius, and are a good place to start if you're trying to understand how Claudius works. * [Bounce](/bounce/) - example of a bouncing ball made from ellipses. +* [Flying Camels](/flying_camels/) - example of using image files to recreate a classic screen saver effect. * [Polygons](/polygons/) - rotating filled polygons. * [Red Hexagon](/red_hexagon/) - a different style of rotating polyons. * [Screen saver](/screen_saver/) - a recreation of a classic screen saver effect from the early Macintosh era. diff --git a/flying_camels/README.md b/flying_camels/README.md new file mode 100644 index 0000000..59b30e4 --- /dev/null +++ b/flying_camels/README.md @@ -0,0 +1 @@ +This example uses the ability to load images as a Picture.t in Claudius to recreate the old [Flying Windows Screensaver](https://microsoft.fandom.com/wiki/Flying_Windows). \ No newline at end of file diff --git a/flying_camels/bin/dune b/flying_camels/bin/dune new file mode 100644 index 0000000..05b29f1 --- /dev/null +++ b/flying_camels/bin/dune @@ -0,0 +1,4 @@ +(executable + (public_name flying_camels) + (name main) + (libraries claudius)) diff --git a/flying_camels/bin/main.ml b/flying_camels/bin/main.ml new file mode 100644 index 0000000..c8c53ad --- /dev/null +++ b/flying_camels/bin/main.ml @@ -0,0 +1,56 @@ +open Claudius + +type point = { x : float; y : float } + +let generate_points dimensions = + let width, height = dimensions in + let f_width, f_height = (float_of_int width, float_of_int height) in + Random.init 42; + List.init 42 (fun _i -> + let x = Random.float f_width -. (f_width /. 2.) + and y = Random.float f_height -. (f_height /. 2.) in + { x; y }) + +let move_points t points = + let ft = float_of_int t in + List.map + (fun p -> + let distance = Float.sqrt ((p.x *. p.x) +. (p.y *. p.y)) in + let angle = Float.atan2 p.y p.x in + let new_distance = distance +. ft in + let i_dist = int_of_float new_distance in + let wrapped_dist = i_dist mod 300 in + let f_wrapped_dist = float_of_int wrapped_dist in + let f_wrapped_dist = f_wrapped_dist *. f_wrapped_dist /. 100. in + let x = f_wrapped_dist *. Float.cos angle + and y = f_wrapped_dist *. Float.sin angle in + { x; y }) + points + +let tick t s _f _e = + let fb = Framebuffer.init (Screen.dimensions s) (fun _ _ -> 0) in + let img = (Screen.pictures s).(0) in + let w, h = Screen.dimensions s in + let img_w = Picture.original_width img + and img_h = Picture.original_height img in + + let points = generate_points (Screen.dimensions s) |> move_points t in + + List.iter + (fun p -> + let x, y = (int_of_float p.x, int_of_float p.y) in + let distance_from_origin = Float.sqrt ((p.x *. p.x) +. (p.y *. p.y)) in + let scale = distance_from_origin /. 200. in + Framebuffer.draw_picture img ~scale + (x - (img_w / 2) + (w / 2)) + (y - (img_h / 2) + (h / 2)) + fb) + points; + + fb + +let () = + let image_filenames = [ "flying_camels/images/logo48.png" ] in + Palette.generate_classic_vga_palette () + |> Screen.create ~image_filenames 640 480 1 + |> Base.run "Flying camels" None tick diff --git a/flying_camels/images/logo48.png b/flying_camels/images/logo48.png new file mode 100644 index 0000000000000000000000000000000000000000..d5414e417844d6127e064ccdb5fd8b400422f834 GIT binary patch literal 1698 zcmV;T23`4yP)cH#H#~_G}u0%im75^2niUIs?c?a4-9GJ%b2D<6i|>RP^$?+NmE5E22onq zw9QBxQryHLw)f$7CJl)bAO$|`udB-U+;h+U`P}P!Z-cQvyaTU|a55i%)eNyBK$KoJ z!!*5i8G7x22s!ekf>C(ZvK>Uu+($hZ!oxRXTy+a-b=H*tFz#rQg_)XYBD#`Ob4XuO z2LQT-D@V?JEKZC>)0j4Xhn}@2i}(EI8De@eWn|$JeaY%6E2+<2-4yL-sM_+x(@bYA z+c6U~(|~3z-3Wjw)eOsW-GW+$l{C}S_$oftWEH4~)?^hJDjQJ2s8km#p>)o)z8BM$ zUA;HNI%GkbwRB@l6Q&{ci#7zhTUBTZcm9THNK`eh*bV?7OJVPw;O#4X-yhNIAzD-5 zxvQHnf{KMT7MSX7hRO#0+qF;k%v$zQA{qcNuG*u}M7;-2nrY*T?FHM;CrU6bg=Ir! zLxyE}+~y3+a^s5afW=8Tt~2Ns)JkDFZqb@7D!4eQ*Du=ebT0tFv)}!EDxc3TL)8|X z#Gba}B&IdJ8MlihilMvLLwBz~_V&khz+_o|J{lz6Z6E9S2ECl3j5n5=H~%!}xujqjt9CxceeuEX2U7|7q8U;oM+9N8 zPYgcLnk+GU1OSYl+Zh_@Ng5;#8B&B1RH82<@^B;-8l;zTxcVn7A7|rFAXyB1fB6CcH2T>9AoBkR94GSekE*1?WLcIY!tm)2rLb4A;$%K) zF4gAGCvxU$O%^=EKp67T0m8fOk9sc5TDlS4oR9_%FPDTgY#$nZ0RaGkzs^a)X)h!N zM?&{TLieVs+SyC;KWWAYig(+`9Zdi*?&yt-4=HC3Mwmf(&XmLm=iT-|cdHx$m6B8Y zHAYZUn16W1ru3Y+ahi8eEfK<)wvPjk9wV-l+u6jmU!~v(h>}vq9Zgc02LRGsnl2zB z(M3rSx}AkbnK;+6h!nhiRbNu4&7Uu)V-0~G@I)6HR4@wHSt zRcW9BfTSB^PR$`)XF!KhT;k9`j}#1$X4+7`COtrsAgdH~(dPTwRYC;sb^}0m_1^RV zsW;0~Bs|La|NKz}8qFF`X3jVeHD?Y^>c=k~SKss|nH#*@j_V9WZebdLWI;|;NOP$a z3`{aNl1A~hHG?c=(q(A?Qfbp!SB8ff6=J1C#)d=vJ?KCG7ZfH6kHSN@g!|4=|22W* zB4fh>bWm{}E+G;&=^e9D9f*?>7g_=;8Q?0F??d=T10086h&{nJRaN^|m zF9alsA_|0NqG%85 z^i@_>0RWmiNfdjXPC*b_Y&M#vPqilet*EG|D8+Y60`%qn{Qz*Vv2pXJO^nC0YtNqS z?CirwjsU>!hK3FG^#>ap|Gsq#A?|KyNIDoz(~QT{+0mimljO7a`~BTrT>wy2RJ6FP z3>jIL?Q^-+N&7P