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