1. -- 
  2. -- Jan & Uwe R. Zimmer, Australia, July 2019 
  3. -- 
  4.  
  5. with Ada.Numerics.Float_Random;         use Ada.Numerics.Float_Random; 
  6. with Ada.Real_Time;                     use Ada.Real_Time; 
  7. with Exceptions;                        use Exceptions;                        pragma Elaborate_All (Exceptions); 
  8. with Real_Type;                         use Real_Type; 
  9. with Generic_Sliding_Statistics;                                               pragma Elaborate_All (Generic_Sliding_Statistics); 
  10. with Graphics_Configuration;            use Graphics_Configuration; 
  11. with Graphics_Data;                     use Graphics_Data; 
  12. with Graphics_FrameRates;               use Graphics_FrameRates; 
  13. with Graphics_OpenGL;                   use Graphics_OpenGL; 
  14. with Graphics_Structures;               use Graphics_Structures; 
  15. with Keyboard;                          use Keyboard; 
  16. with Models;                            use Models; 
  17. with Rotations;                         use Rotations; 
  18. with Screenshots;                       use Screenshots; 
  19. with Swarm_Configuration;               use Swarm_Configuration; 
  20. with Swarm_Configurations;              use Swarm_Configurations; 
  21. with Swarm_Control;                     use Swarm_Control;                     pragma Elaborate_All (Swarm_Control); 
  22. with Swarm_Control_Concurrent_Generic;                                         pragma Elaborate_All (Swarm_Control_Concurrent_Generic); 
  23. with Swarm_Data;                        use Swarm_Data; 
  24. with Swarm_Structures;                  use Swarm_Structures; 
  25. with Swarm_Structures_Base;             use Swarm_Structures_Base; 
  26. with Vectors_3D;                        use Vectors_3D; 
  27.  
  28. package body Callback_Procedures is 
  29.  
  30.    Zero_to_One_Generator : Generator; 
  31.  
  32.    use Real_Elementary_Functions; 
  33.  
  34.    Smoothing_Time : constant Positive := 10; -- seconds 
  35.  
  36.    package Centre_Of_Gravity_Stats is new Generic_Sliding_Statistics (Element      => Vector_3D, 
  37.                                                                       Buffer_Size  => Smoothing_Time * Positive (Intented_Framerate)); 
  38.    package Mean_Radius_Stats       is new Generic_Sliding_Statistics (Element      => Real, 
  39.                                                                       Buffer_Size  => Smoothing_Time * Positive (Intented_Framerate)); 
  40.  
  41.    package Centre_Of_Gravity_Averages is new Centre_Of_Gravity_Stats.Averages; use Centre_Of_Gravity_Averages; 
  42.    package Mean_Radius_Averages       is new Mean_Radius_Stats.Averages;       use Mean_Radius_Averages; 
  43.  
  44.    use Swarm_Vectors; 
  45.  
  46.    package Swarm_Control_Concurrent is new Swarm_Control_Concurrent_Generic (No_of_Cores_for_Swarm); 
  47.    use Swarm_Control_Concurrent; 
  48.  
  49.    package Execute_Commands is 
  50.       procedure Act_On_Input (Position  : in out Vector_3D; 
  51.                               Rotation  : in out Quaternion_Rotation; 
  52.                               Time      :        Real; 
  53.                               Commands  :        Commands_Array); 
  54.    private 
  55.       Keys_Released : Boolean  := True; 
  56.    end Execute_Commands; 
  57.  
  58.    package body Execute_Commands is 
  59.  
  60.       procedure Act_On_Input (Position  : in out Vector_3D; 
  61.                               Rotation  : in out Quaternion_Rotation; 
  62.                               Time      :        Real; 
  63.                               Commands  :        Commands_Array) is 
  64.  
  65.          Accelerator    : constant Real  :=  4.0; 
  66.          Rotation_Speed :          Real  :=  0.3 * Time; 
  67.          Moving_Speed   :          Real  :=  0.3 * Time; 
  68.          Step           :      Vector_3D := (0.0, 0.0, 0.0); 
  69.  
  70.       begin 
  71.          for Command in Commands'Range loop 
  72.             if Commands (Command) then 
  73.                case Command is 
  74.  
  75.                   when Move_Accelerator => 
  76.                      Rotation_Speed := Rotation_Speed * Accelerator; 
  77.                      Moving_Speed   := Moving_Speed   * Accelerator; 
  78.                   when Full_Screen  => 
  79.                      if Keys_Released then 
  80.                         Full_Screen_Mode.Change_Full_Screen; 
  81.                      end if; 
  82.                   when Reset_Camera => 
  83.                      case Camera_Mode is 
  84.                         when Scene => 
  85.                            Position := Initial_Cams (Camera_Mode).Scene_Offset; 
  86.                            Rotation := Initial_Cams (Camera_Mode).Rotation; 
  87.                         when Chase => 
  88.                            Position := Initial_Cams (Camera_Mode).Object_Offset; 
  89.                            Rotation := Initial_Cams (Camera_Mode).Rotation; 
  90.                      end case; 
  91.                   when Screen_Shot => Take_Shot; 
  92.                   when Toggle_Axis => 
  93.                      if Keys_Released then 
  94.                         Show_Axis := not Show_Axis; 
  95.                      end if; 
  96.                   when Toggle_Lines => 
  97.                      if Keys_Released then 
  98.                         Show_Connecting_Lines := not Show_Connecting_Lines; 
  99.                      end if; 
  100.                   when Text_Overlay => 
  101.                      if Keys_Released then 
  102.                         Show_Text_Overlay := not Show_Text_Overlay; 
  103.                      end if; 
  104.                   when Space => 
  105.                      if Keys_Released then 
  106.                         case Camera_Mode is 
  107.                            when Scene => Camera_Mode := Chase; 
  108.                            when Chase => Camera_Mode := Scene; 
  109.                         end case; 
  110.                      end if; 
  111.  
  112.                      -- Rotation -- 
  113.                   when Rotate_Left => Rotation := Rotate 
  114.                        (Rotation, To_Rotation (0.0, 0.0,  Rotation_Speed)); 
  115.                   when Rotate_Right => Rotation := Rotate 
  116.                        (Rotation, To_Rotation (0.0, 0.0, -Rotation_Speed)); 
  117.                   when Rotate_Up => Rotation := Rotate 
  118.                        (Rotation, To_Rotation (0.0,  Rotation_Speed, 0.0)); 
  119.                   when Rotate_Down => Rotation := Rotate 
  120.                        (Rotation, To_Rotation (0.0, -Rotation_Speed, 0.0)); 
  121.                   when Rotate_CW => Rotation := Rotate 
  122.                        (Rotation, To_Rotation (-Rotation_Speed, 0.0, 0.0)); 
  123.                   when Rotate_AntiCW => Rotation := Rotate 
  124.                        (Rotation, To_Rotation  (Rotation_Speed, 0.0, 0.0)); 
  125.  
  126.                      -- Stepping -- 
  127.                   when Strafe_Left     => Step (x) := Step (x) - Moving_Speed; 
  128.                   when Strafe_Right    => Step (x) := Step (x) + Moving_Speed; 
  129.                   when Strafe_Up       => Step (z) := Step (z) + Moving_Speed; 
  130.                   when Strafe_Down     => Step (z) := Step (z) - Moving_Speed; 
  131.                   when Strafe_Forward  => Step (y) := Step (y) + Moving_Speed; 
  132.                   when Strafe_Backward => Step (y) := Step (y) - Moving_Speed; 
  133.  
  134.                      -- Swarm control -- 
  135.  
  136.                   when Add_Vehicle    => 
  137.                      if Keys_Released then 
  138.                         if Natural (Length (Swarm_State)) = 0 then 
  139.                            Swarm_Monitor.Append_Random_Swarm (1); 
  140.                         else 
  141.                            Swarm_Monitor.Append_Random_Swarm (1, Swarm_Monitor.Centre_Of_Gravity, 0.0001); 
  142.                         end if; 
  143.                      end if; 
  144.                   when Remove_Vehicle => 
  145.                      if Keys_Released then -- and then Natural (Length (Swarm_State)) > 1 then 
  146.                         Remove_Vehicles (1); 
  147.                      end if; 
  148.                end case; 
  149.             end if; 
  150.          end loop; 
  151.  
  152.          Keys_Released := Commands = Command_Set_Reset; 
  153.  
  154.          case Camera_Mode is 
  155.             when Scene => Step := Rotate (Step, Rotation); 
  156.             when Chase => null; 
  157.          end case; 
  158.  
  159.          for Axes in Step'Range loop 
  160.             Position (Axes) := Position (Axes) + Step (Axes); 
  161.          end loop; 
  162.  
  163.       end Act_On_Input; 
  164.    end Execute_Commands; 
  165.  
  166.    -- 
  167.    -- 
  168.    -- 
  169.  
  170.    procedure Main_Operations is 
  171.  
  172.       Time_Interval      : constant Time_Span  := Measure_Interval; -- Time since last call 
  173.       FrameRate          : constant Natural    := Natural (Average_Framerate (Time_Interval)); 
  174.       Time_Interval_Real : constant Real       := Real (To_Duration (Time_Interval)); 
  175.  
  176.       Commands : Commands_Array := Command_Set_Reset; 
  177.  
  178.    begin 
  179.       Framerate_Limiter (Intented_Framerate); 
  180.  
  181.       Get_Keys (Commands); 
  182.  
  183.       case Camera_Mode is 
  184.          when Scene => 
  185.             Execute_Commands.Act_On_Input (Cam.Scene_Offset, Cam.Rotation, Time_Interval_Real, Commands); 
  186.             case Camera_Mode is 
  187.                when Scene => 
  188.                   Cam.Position := Swarm_Monitor.Centre_Of_Gravity; 
  189.                when Chase => 
  190.                   Cam := Initial_Cams (Camera_Mode); 
  191.             end case; 
  192.  
  193.          when Chase => 
  194.             Execute_Commands.Act_On_Input (Cam.Object_Offset, Cam.Rotation, Time_Interval_Real, Commands); 
  195.             case Camera_Mode is 
  196.                when Scene => Cam := Initial_Cams (Camera_Mode); 
  197.                when Chase => 
  198.                   Cam.Position := Element (Swarm_State, 1).Position.all.Read; 
  199.                   declare 
  200.                      --                 Element_Roll  : constant Angle := Roll  (Element (Swarm_State, 1).Rotation); 
  201.                      Element_Pitch : constant Radiants := Pitch (Element (Swarm_State, 1).Rotation.all.Read); 
  202.                      Element_Yaw   : constant Radiants := Yaw   (Element (Swarm_State, 1).Rotation.all.Read); 
  203.                   begin 
  204.                      Cam.Rotation := To_Rotation (0.0, 0.0, -Element_Yaw); 
  205.                      Cam.Rotation := Rotate (Cam.Rotation, To_Rotation (0.0, -Element_Pitch, 0.0)); 
  206.                      --                 Cam.Rotation := Rotate (Cam.Rotation, To_Rotation (-Element_Roll, 0.0, 0.0)); 
  207.                   end; 
  208. --                    Cam.Rotation := Inverse (Element (Swarm_State, 1).Rotation); 
  209.             end case; 
  210.       end case; 
  211.  
  212.       Position_Camera; 
  213.  
  214.       for Element_Index in First_Index (Swarm_State) .. Last_Index (Swarm_State) loop 
  215.          declare 
  216.             This_Element : constant Swarm_Element_State := Element (Swarm_State, Element_Index); 
  217.             Charge_Index : constant Positive            := 
  218.               Positive ((Real (This_Element.Charge.Level) * (Real (Spaceship_Gradient'Last (2) - Spaceship_Gradient'First (2)))) 
  219.                         + Real (Spaceship_Gradient'First (2))); 
  220.          begin 
  221.  
  222.             if This_Element.Controls.all.Read_Throttle /= Idle_Throttle then 
  223.                Draw (Spaceship_Gradient (G_Ruby,      Charge_Index), This_Element.Position.all.Read, This_Element.Rotation.all.Read); 
  224.             else 
  225.                Draw (Spaceship_Gradient (G_Turquoise, Charge_Index), This_Element.Position.all.Read, This_Element.Rotation.all.Read); 
  226.             end if; 
  227.  
  228.             if Show_Connecting_Lines then 
  229.                for Neighbour_Index in Distance_Vectors.First_Index (This_Element.Neighbours.all) .. Distance_Vectors.Last_Index (This_Element.Neighbours.all) loop 
  230.                   declare 
  231.                      Distance_Entry : constant Distance_Entries := Distance_Vectors.Element (This_Element.Neighbours.all, Neighbour_Index); 
  232.                   begin 
  233.                      if Distance_Entry.Distance <= Comms_Range then 
  234.                         Draw_Lines ((This_Element.Position.all.Read, Element (Swarm_State, Distance_Entry.Index).Position.all.Read)); 
  235.                      end if; 
  236.                   exception 
  237.                      when Constraint_Error => null; -- Neighbour died 
  238.                   end; 
  239.                end loop; 
  240.             end if; 
  241.          end; 
  242.       end loop; 
  243.  
  244.       case Configuration is 
  245.  
  246.          when Single_Globe_In_Orbit => 
  247.  
  248.             Sphere_Angles := Sphere_Angles + Sphere_Increment; 
  249.  
  250.             for Globe_Ix in Globes'Range loop 
  251.                declare 
  252.  
  253.                   Sin_x : constant Real := Sin (Sphere_Angles (x)); 
  254.                   Cos_x : constant Real := Cos (Sphere_Angles (x)); 
  255.                   Sin_y : constant Real := Sin (Sphere_Angles (y)); 
  256.                   Cos_y : constant Real := Cos (Sphere_Angles (y)); 
  257.                   Sin_z : constant Real := Sin (Sphere_Angles (z)); 
  258.                   Cos_z : constant Real := Cos (Sphere_Angles (z)); 
  259.  
  260.                   Radius : constant Real := Average (Swarm_Monitor.Mean_Radius); 
  261.  
  262.                   Sphere_Offset : constant Positions := (x => Sin_z * Radius * Cos_x * Cos_y, 
  263.                                                          y => Sin_z * Radius * Cos_x * Sin_y, 
  264.                                                          z => Cos_z * Radius * Sin_x); 
  265.  
  266.                   New_Position : constant Positions := Average (Swarm_Monitor.Centre_Of_Gravity) + Sphere_Offset; 
  267.  
  268.                begin 
  269.                   Globes (Globe_Ix).Velocity.all.Write ((New_Position - Globes (Globe_Ix).Position.all.Read) / Time_Interval_Real); 
  270.                   Globes (Globe_Ix).Position.all.Write (New_Position); 
  271.                   Draw (Model_Set (Sphere), New_Position, Zero_Rotation); 
  272.                end; 
  273.             end loop; 
  274.  
  275.          when Dual_Globes_In_Orbit => 
  276.  
  277.             Sphere_Angles := Sphere_Angles + Sphere_Increment; 
  278.  
  279.             for Globe_Ix in Globes'Range loop 
  280.                declare 
  281.  
  282.                   Sin_x : constant Real := Sin (Sphere_Angles (x)); 
  283.                   Cos_x : constant Real := Cos (Sphere_Angles (x)); 
  284.                   Sin_y : constant Real := Sin (Sphere_Angles (y)); 
  285.                   Cos_y : constant Real := Cos (Sphere_Angles (y)); 
  286.                   Sin_z : constant Real := Sin (Sphere_Angles (z)); 
  287.                   Cos_z : constant Real := Cos (Sphere_Angles (z)); 
  288.  
  289.                   Radius : constant Real := Average (Swarm_Monitor.Mean_Radius); 
  290.  
  291.                   Sphere_Offset_1 : constant Positions := (x => Sin_z * Radius * Cos_x * Cos_y, 
  292.                                                            y => Sin_z * Radius * Cos_x * Sin_y, 
  293.                                                            z => Cos_z * Radius * Sin_x); 
  294.  
  295.                   Sphere_Offset_2 : constant Positions := -Sphere_Offset_1; 
  296.  
  297.                   New_Position_1 : constant Positions := Average (Swarm_Monitor.Centre_Of_Gravity) + Sphere_Offset_1; 
  298.                   New_Position_2 : constant Positions := Average (Swarm_Monitor.Centre_Of_Gravity) + Sphere_Offset_2; 
  299.  
  300.                begin 
  301.                   if Globe_Ix = Globes'First then 
  302.                      Globes (Globe_Ix).Velocity.all.Write ((New_Position_1 - Globes (Globe_Ix).Position.all.Read) / Time_Interval_Real); 
  303.                      Globes (Globe_Ix).Position.all.Write (New_Position_1); 
  304.                      Draw (Model_Set (Sphere), New_Position_1, Zero_Rotation); 
  305.  
  306.                   else 
  307.                      Globes (Globe_Ix).Velocity.all.Write ((New_Position_2 - Globes (Globe_Ix).Position.all.Read) / Time_Interval_Real); 
  308.                      Globes (Globe_Ix).Position.all.Write (New_Position_2); 
  309.                      Draw (Model_Set (Sphere), New_Position_2, Zero_Rotation); 
  310.                   end if; 
  311.                end; 
  312.             end loop; 
  313.  
  314.          when Dual_Globes_In_Orbit_Fast => 
  315.  
  316.             Sphere_Angles := Sphere_Angles + Sphere_Increment_Fast; 
  317.  
  318.             for Globe_Ix in Globes'Range loop 
  319.                declare 
  320.  
  321.                   Sin_x : constant Real := Sin (Sphere_Angles (x)); 
  322.                   Cos_x : constant Real := Cos (Sphere_Angles (x)); 
  323.                   Sin_y : constant Real := Sin (Sphere_Angles (y)); 
  324.                   Cos_y : constant Real := Cos (Sphere_Angles (y)); 
  325.                   Sin_z : constant Real := Sin (Sphere_Angles (z)); 
  326.                   Cos_z : constant Real := Cos (Sphere_Angles (z)); 
  327.  
  328.                   Radius : constant Real := Average (Swarm_Monitor.Mean_Radius); 
  329.  
  330.                   Sphere_Offset_1 : constant Positions := (x => Sin_z * Radius * Cos_x * Cos_y, 
  331.                                                            y => Sin_z * Radius * Cos_x * Sin_y, 
  332.                                                            z => Cos_z * Radius * Sin_x); 
  333.  
  334.                   Sphere_Offset_2 : constant Positions := -Sphere_Offset_1; 
  335.  
  336.                   New_Position_1 : constant Positions := Average (Swarm_Monitor.Centre_Of_Gravity) + Sphere_Offset_1; 
  337.                   New_Position_2 : constant Positions := Average (Swarm_Monitor.Centre_Of_Gravity) + Sphere_Offset_2; 
  338.  
  339.                begin 
  340.                   if Globe_Ix = Globes'First then 
  341.                      Globes (Globe_Ix).Velocity.all.Write ((New_Position_1 - Globes (Globe_Ix).Position.all.Read) / Time_Interval_Real); 
  342.                      Globes (Globe_Ix).Position.all.Write (New_Position_1); 
  343.                      Draw (Model_Set (Sphere), New_Position_1, Zero_Rotation); 
  344.  
  345.                   else 
  346.                      Globes (Globe_Ix).Velocity.all.Write ((New_Position_2 - Globes (Globe_Ix).Position.all.Read) / Time_Interval_Real); 
  347.                      Globes (Globe_Ix).Position.all.Write (New_Position_2); 
  348.                      Draw (Model_Set (Sphere), New_Position_2, Zero_Rotation); 
  349.                   end if; 
  350.                end; 
  351.             end loop; 
  352.  
  353.          when Random_Globes_In_Orbits => null; 
  354.  
  355.             Sphere_Angles := Sphere_Angles + Sphere_Increment_Fast; 
  356.  
  357.             declare 
  358.  
  359.                Sin_x : constant Real := Sin (Sphere_Angles (x)); 
  360.                Cos_x : constant Real := Cos (Sphere_Angles (x)); 
  361.                Sin_y : constant Real := Sin (Sphere_Angles (y)); 
  362.                Cos_y : constant Real := Cos (Sphere_Angles (y)); 
  363.                Sin_z : constant Real := Sin (Sphere_Angles (z)); 
  364.                Cos_z : constant Real := Cos (Sphere_Angles (z)); 
  365.  
  366.                Radius : constant Real := Average (Swarm_Monitor.Mean_Radius); 
  367.  
  368.                Phase : constant Positions := 
  369.                  (x => Sin_z * Radius * Cos_x * Cos_y, 
  370.                   y => Sin_z * Radius * Cos_x * Sin_y, 
  371.                   z => Cos_z * Radius * Sin_x); 
  372.  
  373.                Sphere_Offsets : constant array (Globes'Range) of Positions := 
  374.                  (1 => Phase, 
  375.                   2 => -Phase, 
  376.                   3 => (x => Phase (x), 
  377.                         y => Phase (z), 
  378.                         z => Phase (y)), 
  379.                   4 => (x => -Phase (x), 
  380.                         y => -Phase (z), 
  381.                         z => -Phase (y)), 
  382.                   5 => (x => Phase (z), 
  383.                         y => Phase (y), 
  384.                         z => Phase (x)), 
  385.                   6 => (x => -Phase (z), 
  386.                         y => -Phase (y), 
  387.                         z => -Phase (x)) 
  388.                  ); 
  389.  
  390.             begin 
  391.                for Globe_Ix in Globes'Range loop 
  392.                   declare 
  393.                      New_Position : constant Positions := Average (Swarm_Monitor.Centre_Of_Gravity) + Sphere_Offsets (Globe_Ix); 
  394.  
  395.                      function No_of_Active_Globes (Ix : Positive) return Natural is 
  396.                        ((if Globes (Ix).Active then 1 else 0) 
  397.                         + (if Ix < Globes'Last then No_of_Active_Globes (Ix + 1) else 0)); 
  398.  
  399.                   begin 
  400.                      Globes (Globe_Ix).Velocity.all.Write ((New_Position - Globes (Globe_Ix).Position.all.Read) / Time_Interval_Real); 
  401.                      Globes (Globe_Ix).Position.all.Write (New_Position); 
  402.                      if Random (Zero_to_One_Generator) < 0.001 then 
  403.                         Globes (Globe_Ix).Active := not Globes (Globe_Ix).Active; 
  404.                         if No_of_Active_Globes (Globes'First) < 2 then 
  405.                            Globes (Globe_Ix).Active := True; 
  406.                         end if; 
  407.                      end if; 
  408.                      if Globes (Globe_Ix).Active then 
  409.                         Draw (Model_Set (Sphere), New_Position, Zero_Rotation); 
  410.                      end if; 
  411.                   end; 
  412.                end loop; 
  413.             end; 
  414.  
  415.          when Globe_Grid_In_Centre => 
  416.  
  417.             for Globe_Ix in Globes'Range loop 
  418.                declare 
  419.                   New_Position : constant Positions := Average (Swarm_Monitor.Centre_Of_Gravity) + Energy_Globes_Defaults (Globe_Ix).Position; 
  420.                begin 
  421.                   Globes (Globe_Ix).Velocity.all.Write ((New_Position - Globes (Globe_Ix).Position.all.Read) / Time_Interval_Real); 
  422.                   Globes (Globe_Ix).Position.all.Write (New_Position); 
  423.                   Draw (Model_Set (Sphere), Globes (Globe_Ix).Position.all.Read, Zero_Rotation); 
  424.                end; 
  425.             end loop; 
  426.  
  427.          when Globe_Grid_Drifting => 
  428.  
  429.             for Globe_Ix in Globes'Range loop 
  430.                Globes (Globe_Ix).Velocity.all.Write (Energy_Globes_Velocity); 
  431.                Globes (Globe_Ix).Position.all.Write (Globes (Globe_Ix).Position.all.Read + Energy_Globes_Velocity * Time_Interval_Real); 
  432.                Draw (Model_Set (Sphere), Globes (Globe_Ix).Position.all.Read, Zero_Rotation); 
  433.             end loop; 
  434.  
  435.       end case; 
  436.  
  437.       -- Coordinate axes for reference 
  438.       -- 
  439.  
  440. --        Draw_Lines (((-1.0, 0.0, 0.0), (1.0, 0.0, 0.0))); 
  441. --        Draw_Lines (((0.0, -1.0, 0.0), (0.0, 1.0, 0.0))); 
  442. --        Draw_Lines (((0.0, 0.0, -1.0), (0.0, 0.0, 1.0))); 
  443.  
  444.       if Show_Axis then 
  445.          declare 
  446.             Beam_Colour_Red     : constant RGBA_Colour := (Red => 1.00, Green => 0.00, Blue => 0.00, Alpha => 1.00); 
  447.             Beam_Colour_Green   : constant RGBA_Colour := (Red => 0.00, Green => 1.00, Blue => 0.00, Alpha => 1.00); 
  448.             Beam_Colour_Blue    : constant RGBA_Colour := (Red => 0.00, Green => 0.00, Blue => 1.00, Alpha => 1.00); 
  449.             Beam_Colour_Magenta : constant RGBA_Colour := (Red => 1.00, Green => 0.00, Blue => 1.00, Alpha => 1.00); 
  450.             Beam_Colour_Cyan    : constant RGBA_Colour := (Red => 0.00, Green => 1.00, Blue => 1.00, Alpha => 1.00); 
  451.             Beam_Colour_Yellow  : constant RGBA_Colour := (Red => 1.00, Green => 1.00, Blue => 0.00, Alpha => 1.00); 
  452.  
  453.          begin 
  454.             Draw_Laser ((-1.0,  0.0,  0.0), (1.0,  0.0,  0.0), Beam_Radius => 0.0001, Aura_Radius => 0.008, Beam_Colour => Beam_Colour_Red); 
  455.             Draw_Laser ((0.0,  -1.0,  0.0), (0.0,  1.0,  0.0), Beam_Radius => 0.0001, Aura_Radius => 0.008, Beam_Colour => Beam_Colour_Green); 
  456.             Draw_Laser ((0.0,   0.0, -1.0), (0.0,  0.0,  1.0), Beam_Radius => 0.0001, Aura_Radius => 0.008, Beam_Colour => Beam_Colour_Blue); 
  457.  
  458.             Draw_Laser ((-1.0,  0.0, -1.0), (1.0,  0.0,  1.0), Beam_Radius => 0.0001, Aura_Radius => 0.008, Beam_Colour => Beam_Colour_Magenta); 
  459.             Draw_Laser ((-1.0,  0.0,  1.0), (1.0,  0.0, -1.0), Beam_Radius => 0.0001, Aura_Radius => 0.008, Beam_Colour => Beam_Colour_Magenta); 
  460.  
  461.             Draw_Laser ((0.0,  -1.0, -1.0), (0.0,  1.0,  1.0), Beam_Radius => 0.0001, Aura_Radius => 0.008, Beam_Colour => Beam_Colour_Cyan); 
  462.             Draw_Laser ((0.0,  -1.0,  1.0), (0.0,  1.0, -1.0), Beam_Radius => 0.0001, Aura_Radius => 0.008, Beam_Colour => Beam_Colour_Cyan); 
  463.  
  464.             Draw_Laser ((-1.0, -1.0,  0.0), (1.0,  1.0,  0.0), Beam_Radius => 0.0001, Aura_Radius => 0.008, Beam_Colour => Beam_Colour_Yellow); 
  465.             Draw_Laser ((-1.0,  1.0,  0.0), (1.0, -1.0,  0.0), Beam_Radius => 0.0001, Aura_Radius => 0.008, Beam_Colour => Beam_Colour_Yellow); 
  466.          end; 
  467.       end if; 
  468.  
  469.       if Show_Text_Overlay then 
  470.          declare 
  471.             Text_Colour : constant RGBA_Colour := (Red => 0.40, Green => 0.44, Blue => 0.40, Alpha => 0.80); 
  472.             use Cursor_Management; 
  473.          begin 
  474.             Set_Colour (Text_Colour); 
  475.             Home; 
  476.             Text_2D ("Framerate: " & Natural'Image (FrameRate) & " Hz");             Line_Feed; 
  477.             Text_2D ("Number of vehicles"); Indend (105); Text_2D (": " & Natural'Image (Natural (Length (Swarm_State))));  Line_Feed; 
  478.             Text_2D ("Swarm velocity    "); Indend (105); Text_2D (": " & Real'Image (Vectors_3D."abs" (Swarm_Monitor.Mean_Velocity)));   Line_Feed; 
  479.             Text_2D ("Average velocity  "); Indend (105); Text_2D (": " & Real'Image (Swarm_Monitor.Mean_Velocity));         Line_Feed; 
  480.             Text_2D ("Max swarm radius  "); Indend (105); Text_2D (": " & Real'Image (Swarm_Monitor.Maximal_Radius));        Line_Feed; 
  481.             Text_2D ("Mean swarm radius "); Indend (105); Text_2D (": " & Real'Image (Swarm_Monitor.Mean_Radius));           Line_Feed; 
  482.             Text_2D ("Mean spacing      "); Indend (105); Text_2D (": " & Real'Image (Swarm_Monitor.Mean_Closest_Distance)); Paragraph_Feed; 
  483.  
  484.             Text_2D ("Press <space> to change to chase mode");                       Line_Feed; 
  485.             Text_2D ("<alt-.> to toggle neighbourhood lines");                       Line_Feed; 
  486.             Text_2D ("<alt-,> to toggle axis lines");                                Paragraph_Feed; 
  487.  
  488.             Text_2D ("Fullscreen: <alt-f>");                                         Line_Feed; 
  489.             Text_2D ("Screenshot: <alt-s>");                                         Line_Feed; 
  490.             Text_2D ("Reset camera: <alt-c>");                                       Paragraph_Feed; 
  491.  
  492.             Text_2D ("Translations: <a|d|s|w|q|e> - Rotation: <j|l|k|i|u|o>");       Line_Feed; 
  493.             Text_2D ("<alt-t> to make this text disappear");                         Paragraph_Feed; 
  494.  
  495.             Text_2D ("<+> to add a vehicle, <-> to remove one");                     Line_Feed; 
  496.          end; 
  497.       end if; 
  498.  
  499.       Show_Drawing; 
  500.  
  501. --        Set_All_Accelerations; 
  502. --        Forward_All_Messages; 
  503. --        Move_All_Elements; 
  504. --        Update_All_Rotations; 
  505.  
  506.       Distribute_Jobs (Set_Accelerations); 
  507.       Distribute_Jobs (Forward_Messages); 
  508.       Distribute_Jobs (Move_Elements); 
  509.       Distribute_Jobs (Update_Rotations); 
  510.       Remove_Empties; 
  511.  
  512.       Simulator_Tick.Tick; 
  513.  
  514.    exception 
  515.       when E : others => Show_Exception (E); 
  516.  
  517.    end Main_Operations; 
  518.  
  519.    ---------------------------- 
  520.    -- Initialize Environment -- 
  521.    ---------------------------- 
  522.  
  523.    procedure Initialize_Environment is 
  524.  
  525.    begin 
  526.       Cam := Initial_Cams (Camera_Mode); 
  527.       Swarm_Monitor.Append_Random_Swarm; 
  528.       Reset (Zero_to_One_Generator); 
  529.    exception 
  530.       when E : others => Show_Exception (E); 
  531.    end Initialize_Environment; 
  532.  
  533. begin 
  534.    Initialize_Environment; 
  535. end Callback_Procedures;