1. -- 
  2. -- Copyright (c) 2012 Kevin Wellwood 
  3. -- All rights reserved. 
  4. -- 
  5. -- This source code is distributed under the Modified BSD License. For terms and 
  6. -- conditions, see license.txt. 
  7. -- 
  8.  
  9. with Entities;                          use Entities; 
  10. with Events.Listeners;                  use Events.Listeners; 
  11.  
  12. private with Ada.Containers.Ordered_Maps; 
  13. private with Ada.Containers.Ordered_Sets; 
  14. private with Events; 
  15. private with Events.Entities; 
  16. private with Events.World; 
  17. private with Interfaces; 
  18. private with Maps; 
  19. private with Tiles.Libraries; 
  20. private with Widgets.Sprites; 
  21.  
  22. package Widgets.Containers.Scenes is 
  23.  
  24.     -- A Scene displays a graphical view of a game world as a layered map built 
  25.     -- from tiles. As a container widget, it contains Sprite widgets, each 
  26.     -- corresponding to a non-metaphysical entity in the world. The Scene's 
  27.     -- viewport generally shows only a portion of the world at a time and can be 
  28.     -- zoomed or scrolled, either manually or by following an entity. 
  29.     type Scene is abstract new Container and Event_Listener with private; 
  30.     type A_Scene is access all Scene'Class; 
  31.  
  32.     -- Draws the range of tiles visible in the scene's viewport for layer 
  33.     -- 'layer' of the scene's map. The drawing location for the tile at 
  34.     -- 'tileX1','tileY1' is given by 'startX', 'startY'. Missing tiles should 
  35.     -- not drawn. All tiles in this layer are assumed to be opaque so 
  36.     -- transparency doesn't need to be handled when drawin. This procedure will 
  37.     -- be called per redraw per layer from background to foreground. 
  38.     procedure Draw_Layer( this   : access Scene; 
  39.                           layer  : Positive;      -- layer to draw 
  40.                           startX,                 -- location in content coordinates 
  41.                           startY : Integer;       --     to start drawing 
  42.                           tileX1,                 -- range of the visible layer 
  43.                           tileY1,                 --     in tile coordinates 
  44.                           tileX2,                 -- 
  45.                           tileY2 : Integer        -- 
  46.                         ) is abstract; 
  47.  
  48.     -- Returns the height of the scene's map in tiles. 
  49.     function Get_Height_Tiles( this : not null access Scene'Class ) return Natural; 
  50.  
  51.     -- Returns the width of the scene's map in tiles. 
  52.     function Get_Width_Tiles( this : not null access Scene'Class ) return Natural; 
  53.  
  54.     -- Scrolls the viewport by x, y in world coordinates. If the scene is 
  55.     -- following an entity then scrolling will be constrained to the target by 
  56.     -- the slack distance. 
  57.     procedure Scroll( this : not null access Scene'Class; x, y : Float ); 
  58.  
  59.     -- Passing null in 'child' will clear the selection. 
  60.     procedure Set_Selection( this : access Scene; child : A_Widget ); 
  61.  
  62.     -- Sets the scene's target entity, 'target', by Entity_Id. The scene will 
  63.     -- automatically scroll its viewport to keep the target entity in sight, 
  64.     -- constrained by a slack distance from dead center. If 'target' equals 
  65.     -- INVALID_ID then the scene will not follow an entity. 
  66.     procedure Set_Target( this : access Scene; target : Entity_Id ); 
  67.  
  68.     -- Unselects 'child' widget, removing it from the set of selected children. 
  69.     -- This is not the same thing as input focus. 
  70.     procedure Unselect( this : access Scene; child : not null A_Widget ); 
  71.  
  72. private 
  73.  
  74.     use Events; 
  75.     use Events.Entities; 
  76.     use Events.World; 
  77.     use Interfaces; 
  78.     use Maps; 
  79.     use Tiles.Libraries; 
  80.     use Widgets.Sprites; 
  81.  
  82.     -- Provides a Map to map entity id values to their respective Sprite widgets. 
  83.     package Sprite_Maps is new Ada.Containers.Ordered_Maps( Entity_Id, A_Sprite, "<", "=" ); 
  84.     use Sprite_Maps; 
  85.  
  86.     -- Provides an ordered Set of widget references. 
  87.     package Widget_Sets is new Ada.Containers.Ordered_Sets( A_Widget, Lt, "=" ); 
  88.     use Widget_Sets; 
  89.  
  90.     type Boolean_Array is array (Natural range <>) of Boolean; 
  91.     type A_Boolean_Array is access all Boolean_Array; 
  92.  
  93.     type Byte_Array is array (Natural range <>) of Unsigned_8; 
  94.     type A_Byte_Array is access all Byte_Array; 
  95.  
  96.     -- A cache record of a tile bitmap retrieved from the scene's tile library. 
  97.     -- A Cached_Bitmap doesn't maintain a copy of the bitmap, but only a 
  98.     -- reference. A Cached_Bitmap should not be used after the scene's tile 
  99.     -- library is unloaded. 
  100.     type Cached_Bitmap is 
  101.         record 
  102.             tileId : Natural := 0; 
  103.             bmp    : A_Allegro_Bitmap := null; 
  104.         end record; 
  105.  
  106.     -- An array of Cached_Bitmap records. 
  107.     type Cached_Bitmap_Array is array (Natural range <>) of Cached_Bitmap; 
  108.     type A_Cached_Bitmap_Array is access all Cached_Bitmap_Array; 
  109.  
  110.     -- An array of Cached_Bitmap_Arrays. 
  111.     type Bitmap_Cache is array (Natural range <>) of A_Cached_Bitmap_Array; 
  112.     type A_Bitmap_Cache is access all Bitmap_Cache; 
  113.  
  114.     ---------------------------------------------------------------------------- 
  115.  
  116.     type Scene is abstract new Container and Event_Listener with 
  117.         record 
  118.             hasData       : Boolean := False; 
  119.             mapWidth, 
  120.             mapHeight     : Natural := 0; 
  121.             mapLayers     : A_Layer_Array := null; 
  122.             bitmapCache   : A_Bitmap_Cache := null; 
  123.             visibleLayers : A_Boolean_Array := null; 
  124.             lightLevels   : A_Byte_Array := null; 
  125.             spriteLayer   : Integer := Integer'Last;   -- sprites draw on top of this layer 
  126.             tileWidth     : Positive := 1; 
  127.             tileLib       : A_Tile_Library := null; 
  128.             target        : Entity_Id := INVALID_ID;   -- target entity to follow 
  129.             wFocusX,                          -- world coords at center of scene 
  130.             wFocusY       : Float := 0.0;     -- 
  131.             wSlackX,                          -- max pixels target can be from center 
  132.             wSlackY       : Float := 0.0;     -- in world units (changes with zoom) 
  133.             spriteMap     : Sprite_Maps.Map;  -- maps entity id to sprite widget 
  134.             selectedSet   : Widget_Sets.Set;  -- set of selected widgets 
  135.         end record; 
  136.  
  137.     procedure Construct( this : access Scene; 
  138.                          view : not null access Game_Views.Game_View'Class; 
  139.                          id   : String ); 
  140.     pragma Precondition( id'Length > 0 ); 
  141.  
  142.     procedure Delete( this : in out Scene ); 
  143.  
  144.     -- Adds a sprite widget to the scene as a child, updating the entity 
  145.     -- id/sprite map. 'sprite' will be consumed only if 'consume' is True. 
  146.     -- However, 'sprite' will be owned by the scene after this call regardless. 
  147.     procedure Add_Sprite( this    : access Scene; 
  148.                           sprite  : in out A_Sprite; 
  149.                           consume : Boolean := True ); 
  150.     pragma Precondition( sprite /= null ); 
  151.     pragma Postcondition( consume xor sprite /= null ); 
  152.  
  153.     -- Unselects all currently selected child widgets. 
  154.     procedure Clear_Selection( this : access Scene ); 
  155.  
  156.     -- Deletes sprite child widget 'sprite', updating the sprite map and 
  157.     -- selection set as necessary. 'sprite' will be consumed. Exception 
  158.     -- WIDGET_NOT_FOUND will be raised if 'sprite' is not a child of the scene. 
  159.     procedure Delete_Sprite( this : access Scene; sprite : in out A_Sprite ); 
  160.  
  161.     -- Deletes all child widgets, updating the sprite map and selection set as 
  162.     -- necessary. 
  163.     procedure Delete_Children( this : access Scene ); 
  164.  
  165.     -- Draws the scene's background behind the sprites. 
  166.     procedure Draw_Content( this : access Scene ); 
  167.  
  168.     -- Draws the scene's foreground in front of the sprites. 
  169.     procedure Draw_Content_Foreground( this : access Scene ); 
  170.  
  171.     -- Draws any visuals that should overlay the foreground of the scene within 
  172.     -- the viewport. The signature is similar to Draw_Layer with the exception 
  173.     -- of a layer parameter. The drawing location for the tile at 
  174.     -- 'tileX1','tileY1' is given by 'startX', 'startY'. 
  175.     procedure Draw_Layer_Overlay( this   : access Scene; 
  176.                                   startX, 
  177.                                   startY : Integer; 
  178.                                   tileX1, 
  179.                                   tileY1, 
  180.                                   tileX2, 
  181.                                   tileY2 : Integer ) is null; 
  182.  
  183.     -- Returns a reference to an entity's representative Sprite, which is a 
  184.     -- child widget of the scene. If 'id' is not recognized entity then null 
  185.     -- will be returned. 
  186.     function Find_Sprite( this : not null access Scene'Class; 
  187.                           id   : Entity_Id ) return A_Sprite; 
  188.  
  189.     -- Focus the scene on a point in world coordinates. If the point is already 
  190.     -- within the slack focus area, the viewport will not change. However, if 
  191.     -- centered is set to True then the viewport will ignore slack constraints 
  192.     -- and attempt to center the focal point. 
  193.     procedure Focus_On( this     : not null access Scene'Class; 
  194.                         x, y     : Float; 
  195.                         centered : Boolean := False ); 
  196.  
  197.     -- Returns the minimum height of the scene, taking into account a previously 
  198.     -- specified minimum height or the height of the scene's map in pixels. 
  199.     function Get_Min_Height( this : access Scene ) return Natural; 
  200.  
  201.     -- Returns the minimum width of the scene, taking into account a previously 
  202.     -- specified minimum width or the width of the scene's map in pixels. 
  203.     function Get_Min_Width( this : access Scene ) return Natural; 
  204.  
  205.     -- Handles an Entity_Attribute_Changed event by calling Set_Attribute on 
  206.     -- the affected entity's Sprite. 
  207.     procedure Handle_Entity_Attribute_Changed( this : access Scene; 
  208.                                                evt  : not null A_Entity_Attribute_Event ); 
  209.  
  210.     -- Handles an Entity_Created event by creating and adding a corresponding 
  211.     -- Sprite child widget to represent the entity, if it is non-metaphysical. 
  212.     procedure Handle_Entity_Created( this : access Scene; 
  213.                                      evt  : not null A_Entity_Created_Event ); 
  214.  
  215.     -- Handles an Entity_Deleted event by deleting the entity's corresponding 
  216.     -- Sprite, if it has one. 
  217.     procedure Handle_Entity_Deleted( this : access Scene; 
  218.                                      evt  : not null A_Entity_Event ); 
  219.  
  220.     -- Handles an Entity_Moved event by moving the entity's corresponding Sprite 
  221.     -- and focusing the viewport on the entity, if it's the scene's target. 
  222.     procedure Handle_Entity_Moved( this : access Scene; 
  223.                                    evt  : not null A_Entity_Moved_Event ); 
  224.  
  225.     -- Handles an Entity_Resized event by resizing the entity's corresponding 
  226.     -- Sprite. 
  227.     procedure Handle_Entity_Resized( this : access Scene; 
  228.                                      evt  : not null A_Entity_Resized_Event ); 
  229.  
  230.     -- Handles an event received from the corral is registered with. This is the 
  231.     -- same corral provided by the Game View system's Game_View object. If 'evt' 
  232.     -- is returned null then the event was consumed. 
  233.     procedure Handle_Event( this : access Scene; 
  234.                             evt  : in out A_Event; 
  235.                             resp : out Response_Type ); 
  236.     pragma Precondition( evt /= null ); 
  237.  
  238.     -- Handles a Frame_Changed event by changing the image of the entity's 
  239.     -- corresponding Sprite. 
  240.     procedure Handle_Frame_Changed( this : access Scene; 
  241.                                     evt  : not null A_Frame_Changed_Event ); 
  242.  
  243.     -- Handles a World_Loaded event by clearing the scene's current map and all 
  244.     -- child widgets, and loading the new world's tile library and map. No 
  245.     -- sprites will be added yet because the World_Loaded event does not contain 
  246.     -- entity information. A series of Entity_Created events will follow to 
  247.     -- populate the world's entities in the scene. 
  248.     procedure Handle_World_Loaded( this : access Scene; 
  249.                                    evt  : not null A_World_Loaded_Event ); 
  250.  
  251.     -- Handles a Tile_Changed event by updating the specified tile in the 
  252.     -- scene's tile map. 
  253.     procedure Handle_Tile_Changed( this : access Scene; 
  254.                                    evt  : not null A_Tile_Changed_Event ); 
  255.  
  256.     -- Handles a World_Property_Changed event. It should be overridden as 
  257.     -- necessary to handle changes to world properties. 
  258.     procedure Handle_World_Property_Changed( this : access Scene; 
  259.                                              evt  : not null A_World_Property_Event ) is null; 
  260.  
  261.     -- Returns True if the tile at 'x','y' in layer 'layer' of the scene's map 
  262.     -- is currently visible in the scene's viewport. 
  263.     function Is_Tile_Visible( this  : not null access Scene'Class; 
  264.                               layer : Positive; 
  265.                               x, y  : Integer ) return Boolean; 
  266.  
  267.     -- Removes a sprite widget from the scene, updating the sprite map and 
  268.     -- selection set as necessary. 'sprite' will belong to the caller. 
  269.     procedure Remove_Sprite( this : access Scene; sprite : not null A_Sprite ); 
  270.  
  271.     ---------------------------------------------------------------------------- 
  272.  
  273.     -- Deletes a Boolean_Array. 
  274.     procedure Delete( ba : in out A_Boolean_Array ); 
  275.  
  276.     -- Deletes a Byte_Array. 
  277.     procedure Delete( ba : in out A_Byte_Array ); 
  278.  
  279.     -- Deletes a Bitmap_Cache record. The bitmap referenced by this record is 
  280.     -- not owned so it will not be touched. 
  281.     procedure Delete( bc : in out A_Bitmap_Cache ); 
  282.  
  283. end Widgets.Containers.Scenes;