PreviousUpNext

15.4.1368  src/lib/x-kit/tut/bouncing-heads/bouncing-head.pkg

## bouncing-head.pkg

# Compiled by:
#     src/lib/x-kit/tut/bouncing-heads/bouncing-heads-app.lib

stipulate
    include package   threadkit;                # threadkit             is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    package g2d=  geometry2d;                   # geometry2d            is from   src/lib/std/2d/geometry2d.pkg
    package xc =  xclient;                      # xclient               is from   src/lib/x-kit/xclient/xclient.pkg
    #
    package bd =  bounce_drawmaster;            # bounce_drawmaster     is from   src/lib/x-kit/tut/bouncing-heads/bounce-drawmaster.pkg
    package hd =  head_pixmaps;                 # head_pixmaps          is from   src/lib/x-kit/tut/bouncing-heads/head-pixmaps.pkg
herein

    package bouncing_head {
        #
        Plea_Mail
          = KILL               g2d::Point
          | REDRAW_BALL  (Int, g2d::Size)
          | KILL_ALL
          ;

        updates_per_sec = 10.0;

        stipulate

            # Clip a point to keep a ball in the window.
            # If we hit a wall then we adjust the velocity vector.
            #
            # The clipped point should be computed to lie
            # on the vector, but for now we assume small
            # vectors and just truncate the coordinates. 
            #
            fun clip
                ( ball_radius,
                  { wide, high }                        # Window size in pixels.
                )
                =
                {   max_x = wide - ball_radius;
                    max_y = high - ball_radius;

                    fun clip_coord (coord:  Int, delta, min_coord, max_coord)
                        = 
                        if   (coord <= min_coord)   (min_coord, -delta);
                        elif (coord >= max_coord)   (max_coord, -delta);
                        else                        (    coord,  delta);
                        fi;

                    fun clip'
                        ( { col=>x0,  row=>y0 },
                          { col=>dx0, row=>dy0 }
                        )
                        =
                        {   my (x1, dx1) =  clip_coord (x0+dx0, dx0, ball_radius, max_x);
                            my (y1, dy1) =  clip_coord (y0+dy0, dy0, ball_radius, max_y);

                            ( { col=>x1,  row=>y1 },
                              { col=>dx1, row=>dy1 }
                            );
                        };

                    clip';
                };

            fun make_icon_fn window
                =
                {   ball_icons
                        =
                        map (xc::make_readonly_pixmap_from_clientside_pixmap (xc::screen_of_window  window))
                            hd::head_data_list;

                    n    = list::length ball_icons;

                    slot = make_mailslot ();

                    fun loop i
                        =
                        if (i == n)
                            #
                            loop 0;
                        else
                            put_in_mailslot (slot, list::nth (ball_icons, i));
                            loop (i+1);
                        fi;

                    xlogger::make_thread  "make_icon"  {. loop 0; };

                    {.  take_from_mailslot slot;  };
                };

            delay' =  timeout_in'  (1000000.0 / updates_per_sec);
        herein

            fun make_ball (window, mailcaster, draw_slot)
                =
                make_ball'
                where 

                  new_icon = make_icon_fn  window;

                  fun make_ball'
                      ( seqn,
                        position,                               # Ball position on window in pixels.
                        velocity,                               # Ball veloity  on window in pixels.
                        window_size                             # Drawing window size in pixels.
                      )
                      =
                      {   ball_icon = new_icon ();

                          ball_radius
                              =
                              {   my { size => { wide, ... }, ... }
                                      =
                                      xc::shape_of_ro_pixmap
                                          ball_icon;

                                  wide / 2;
                              };

                          offset = { col => ball_radius,
                                     row => ball_radius
                                   };

                          fun draw_ball (seqn, position)
                              =
                              put_in_mailslot (draw_slot, bd::DRAW_BALL (seqn, ball_icon, g2d::point::subtract (position, offset)));

                          fun move_ball (seqn, old_position, new_position)
                              =
                              {   draw_ball (seqn, old_position);
                                  draw_ball (seqn, new_position);
                              };

                          clip_fn = clip (ball_radius, window_size);

                          fun ball (from_mailcaster', position, velocity, clip_fn)
                              =
                              {   draw_ball (seqn, position);

                                  loop (seqn, position, velocity, clip_fn);
                              }
                              where
                                  fun loop (seqn, position, velocity, clip_fn)
                                       =
                                       do_one_mailop [

                                           delay'
                                               ==>
                                              {.   my (new_position, new_velocity)
                                                       =
                                                       clip_fn (position, velocity);

                                                   if (position != new_position)
                                                       #
                                                       move_ball (seqn, position, new_position);
                                                   fi;

                                                   loop (seqn, new_position, new_velocity, clip_fn);
                                               },


                                           from_mailcaster'
                                               ==>
                                               \\ (KILL ({ col, row } ))
                                                       =>
                                                       {   death_zone
                                                               =
                                                               { col  =>  col - ball_radius,
                                                                 row  =>  row - ball_radius,
                                                                 #
                                                                 wide =>  2 * ball_radius,
                                                                 high =>  2 * ball_radius
                                                               };

                                                           if (g2d::point::in_box (position, death_zone))   draw_ball (seqn, position);
                                                           else                                            loop (seqn, position, velocity, clip_fn);
                                                           fi;
                                                       };

                                                  (REDRAW_BALL (seqn', new_sz))
                                                      =>
                                                      {   clip_fn = clip (ball_radius, new_sz);

                                                          my (new_position, _)
                                                              =
                                                              clip_fn (position, { col=>0, row=>0 } );

                                                          draw_ball (seqn', position);

                                                          loop (seqn', new_position, velocity, clip_fn);
                                                     };

                                                  KILL_ALL
                                                      =>
                                                      draw_ball (seqn, position);
                                               end
                                      ];

                              end;

                            xlogger::make_thread  "Ball"  {.
                                #
                                ball (receive' (make_readqueue  mailcaster), position, velocity, clip_fn);
                            };

                            ();
                        };                                      # fun make_ball'

                  end;

        end;                            # stipulate
    };                                  # package ball 

end;


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext