1. pragma Warnings (Off); 
  2. pragma Style_Checks (Off); 
  3.  
  4. with GLOBE_3D.Textures, 
  5.      GLOBE_3D.Math; 
  6.  
  7. with glut.Windows; use glut.Windows; 
  8. with GL.Errors; 
  9. with GLU; 
  10.  
  11. with ada.Text_IO;  use ada.Text_IO; 
  12.  
  13. package body GLOBE_3D.Impostor is 
  14.  
  15.    package G3DT renames GLOBE_3D.Textures; 
  16.    package G3DM renames GLOBE_3D.Math; 
  17.  
  18.    procedure destroy (o  : in out Impostor) 
  19.    is 
  20.       use GL.Geometry, GL.Skins; 
  21.    begin 
  22.       free (o.skinned_Geometry.Geometry); 
  23.       free (o.skinned_Geometry.Skin); 
  24.       free (o.skinned_Geometry.Veneer); 
  25.    end; 
  26.  
  27.    procedure free (o  : in out p_Impostor) 
  28.    is 
  29.       procedure deallocate is new ada.unchecked_Deallocation (Impostor'Class, p_Impostor); 
  30.    begin 
  31.       if o /= null then 
  32.          destroy (o.all); 
  33.       end if; 
  34.  
  35.       deallocate (o); 
  36.    end; 
  37.  
  38.    function get_Target (O  : in Impostor) return p_Visual 
  39.    is 
  40.    begin 
  41.       return o.Target; 
  42.    end; 
  43.  
  44.    procedure set_Target (o  : in out Impostor;   Target  : in p_Visual) 
  45.    is 
  46.       use GL,  GL.Skins, GL.Geometry; 
  47.    begin 
  48.       o.Target     := Target; 
  49.       o.is_Terrain := Target.is_Terrain; 
  50.  
  51.       Target.pre_Calculate; 
  52.  
  53.       -- set o.skinned_Geometry.geometry.vertices & indices 
  54.       -- 
  55.       declare 
  56.          Width  : GL.Double := Target.bounds.sphere_Radius * 1.00; 
  57.       begin 
  58.          o.Quads.Vertices (1) := ( - Width, - Width, 0.0); 
  59.          o.Quads.Vertices (2) := (Width, - Width, 0.0); 
  60.          o.Quads.Vertices (3) := (Width,  Width, 0.0); 
  61.          o.Quads.Vertices (4) := ( - Width,  Width, 0.0); 
  62.       end; 
  63.  
  64.       o.Quads.all.set_vertex_Id (1, 1,  1);      -- tbd : the '.all' required for gnat gpl06 . .. not required in gpl07. 
  65.       o.Quads.all.set_vertex_Id (1, 2,  2); 
  66.       o.Quads.all.set_vertex_Id (1, 3,  3); 
  67.       o.Quads.all.set_vertex_Id (1, 4,  4); 
  68.  
  69.       -- create the veneer, if necessary 
  70.       -- 
  71.       if o.skinned_Geometry.Veneer = null then 
  72.          --o.skinned_Geometry.Veneer := o.skinned_Geometry.Skin.new_Veneer (o.Quads.all); 
  73.          o.skinned_Geometry.Veneer := o.skinned_Geometry.Skin.new_Veneer (o.skinned_geometry.Geometry.all); 
  74.       end if; 
  75.  
  76.       --o.bounding_sphere_Radius := bounding_sphere_Radius (o.Quads.vertex_Pool.all); 
  77.       --o.Bounds := o.skinned_Geometry.Geometry.Bounds; 
  78.    end; 
  79.  
  80.    -- update trigger configuration 
  81.    -- 
  82.  
  83.    procedure set_freshen_count_update_trigger_Mod (o  : in out Impostor;   To  : in Positive) 
  84.    is 
  85.    begin 
  86.       o.freshen_count_update_trigger_Mod := Counter (To); 
  87.    end; 
  88.  
  89.    function get_freshen_count_update_trigger_Mod (o  : in     Impostor) return Positive 
  90.    is 
  91.    begin 
  92.       return Positive (o.freshen_count_update_trigger_Mod); 
  93.    end; 
  94.  
  95.    procedure set_size_update_trigger_Delta (o  : in out Impostor;   To  : in Positive) 
  96.    is 
  97.    begin 
  98.       o.size_update_trigger_Delta := GL.SizeI (To); 
  99.    end; 
  100.  
  101.    function get_size_update_trigger_Delta (o  : in     Impostor) return Positive 
  102.    is 
  103.    begin 
  104.       return Positive (o.size_update_trigger_Delta); 
  105.    end; 
  106.  
  107.    function general_Update_required (o  : access Impostor;   the_Camera        : in p_Camera; 
  108.                                                             the_pixel_Region  : in pixel_Region) return Boolean 
  109.    is 
  110.       use GL, Globe_3D.Math; 
  111.       Camera_has_moved  : Boolean  :=  the_Camera.clipper.eye_Position /= o.prior_camera_Position; 
  112.       Target_has_moved  : Boolean  :=  o.Target.Centre                 /= o.prior_target_Position; 
  113.    begin 
  114.       o.freshen_Count := o.freshen_Count + 1; 
  115.  
  116.       if o.freshen_Count > o.freshen_count_update_trigger_Mod then 
  117.          return True; 
  118.       end if; 
  119.  
  120.       if         Camera_has_moved 
  121.         and then abs (Angle (the_Camera.clipper.eye_Position, o.prior_target_Position, o.prior_camera_Position)) > to_Radians (degrees => 15.0) 
  122.       then 
  123.          return True; 
  124.       end if; 
  125.  
  126.       if         Target_has_moved 
  127.         and then abs (Angle (o.target.Centre, o.prior_camera_Position, o.prior_target_Position)) > to_Radians (degrees => 15.0) 
  128.       then 
  129.          return True; 
  130.       end if; 
  131.  
  132.       if         o.prior_pixel_Region.Width  >  40                -- ignore target rotation triggered updates when target is small on screen 
  133.         and then o.prior_pixel_Region.Height >  40                -- 
  134.         and then o.prior_target_Rotation     /= o.target.Rotation 
  135.       then 
  136.          return True; 
  137.       end if; 
  138.  
  139.       return False; 
  140.    end; 
  141.  
  142.    function size_Update_required (o  : access Impostor;   the_pixel_Region  : in pixel_Region) return Boolean 
  143.    is 
  144.       use GL; 
  145.    begin 
  146.       return         abs (the_pixel_Region.Width  - o.prior_Width_Pixels)  > o.size_update_trigger_Delta 
  147.              or else abs (the_pixel_Region.Height - o.prior_Height_pixels) > o.size_update_trigger_Delta; 
  148.    end; 
  149.  
  150.    function get_pixel_Region (o  : access Impostor'Class;   the_Camera  : in globe_3d.p_Camera) return pixel_Region 
  151.    is 
  152.       use GL, globe_3d.Math; 
  153.  
  154.       target_Centre             : Vector_3d    := the_Camera.world_Rotation * (o.Target.Centre - the_Camera.clipper.eye_Position); 
  155.       target_lower_Left         : Vector_3d    := target_Centre - (o.Target.bounds.sphere_Radius, o.Target.bounds.sphere_Radius, 0.0); 
  156.  
  157.       target_Centre_proj        : Vector_4d    := the_Camera.Projection_Matrix * target_Centre; 
  158.       target_Lower_Left_proj    : Vector_4d    := the_Camera.Projection_Matrix * target_lower_Left; 
  159.  
  160.       target_Centre_norm        : Vector_3d    := (target_Centre_proj (0) / target_Centre_proj (3), 
  161.                                                   target_Centre_proj (1) / target_Centre_proj (3), 
  162.                                                   target_Centre_proj (2) / target_Centre_proj (3)); 
  163.       target_Lower_Left_norm    : Vector_3d    := (target_Lower_Left_proj (0) / target_Lower_Left_proj (3), 
  164.                                                   target_Lower_Left_proj (1) / target_Lower_Left_proj (3), 
  165.                                                   target_Lower_Left_proj (2) / target_Lower_Left_proj (3)); 
  166.  
  167.       target_Centre_norm_0to1   : Vector_3d    := (target_Centre_norm (0)     * 0.5 + 0.5, 
  168.                                                   target_Centre_norm (1)     * 0.5 + 0.5, 
  169.                                                   target_Centre_norm (2)     * 0.5 + 0.5); 
  170.       target_Lower_Left_norm_0to1  : Vector_3d := (target_Lower_Left_norm (0) * 0.5 + 0.5, 
  171.                                                   target_Lower_Left_norm (1) * 0.5 + 0.5, 
  172.                                                   target_Lower_Left_norm (2) * 0.5 + 0.5); 
  173.  
  174.       viewport_Width            : Integer      := the_Camera.clipper.main_Clipping.x2 - the_Camera.clipper.main_Clipping.x1 + 1; 
  175.       viewport_Height           : Integer      := the_Camera.clipper.main_Clipping.y2 - the_Camera.clipper.main_Clipping.y1 + 1; 
  176.  
  177.       Width                     : Real         := 2.0  *  Real (viewport_Width) * (target_Centre_norm_0to1 (0) - target_Lower_Left_norm_0to1 (0)); 
  178.       Width_pixels              : GL.Sizei     := GL.Sizei (Integer (Real (viewport_Width) * target_Lower_Left_norm_0to1 (0) + Width) 
  179.                                                            - Integer (Real (viewport_Width) * target_Lower_Left_norm_0to1 (0)) 
  180.                                                            + 1); 
  181.  
  182.       Height                    : Real         := 2.0  *  Real (viewport_Height) * (target_Centre_norm_0to1 (1) - target_Lower_Left_norm_0to1 (1)); 
  183.       Height_pixels             : GL.Sizei     := GL.Sizei (Integer (Real (viewport_Height) * target_Lower_Left_norm_0to1 (1) + Height) 
  184.                                                            - Integer (Real (viewport_Height) * target_Lower_Left_norm_0to1 (1)) 
  185.                                                            + 1); 
  186.    begin 
  187.       o.all.target_camera_Distance := Norm (target_Centre);   -- nb : cache distance from camera to target. 
  188.  
  189.       return (x      => GL.Int (target_Lower_Left_norm_0to1 (0) * Real (Viewport_Width)), 
  190.               y      => GL.Int (target_Lower_Left_norm_0to1 (1) * Real (viewport_Height)), 
  191.               width  => Width_pixels, 
  192.               height => Height_pixels); 
  193.    end; 
  194.  
  195.    procedure update (o             : in out Impostor; 
  196.                      the_Camera    : in     p_Camera; 
  197.                      texture_Pool  : in     GL.textures.p_Pool) 
  198.    is 
  199.       use GL, GL.Textures; 
  200.  
  201.       Width_size                : GL.textures.Size := to_Size (Natural (o.current_Width_pixels)); 
  202.       Height_size               : GL.textures.Size := to_Size (Natural (o.current_Height_pixels)); 
  203.  
  204.       texture_Width             : GL.sizei         := GL.sizei (power_of_2_Ceiling (Natural (o.current_Width_pixels))); 
  205.       texture_Height            : GL.sizei         := GL.sizei (power_of_2_Ceiling (Natural (o.current_Height_pixels))); 
  206.  
  207.       GL_Error  : Boolean; 
  208.    begin 
  209.       o.prior_pixel_Region    := (o.current_copy_X, o.current_copy_Y,  o.current_Width_pixels, o.current_Height_pixels); 
  210.       o.prior_Width_pixels    := o.current_Width_pixels; 
  211.       o.prior_Height_pixels   := o.current_Height_pixels; 
  212.       o.prior_target_Rotation := o.target.Rotation; 
  213.       o.prior_target_Position := o.target.Centre; 
  214.       o.prior_camera_Position := the_Camera.clipper.Eye_Position; 
  215.  
  216.       GL.ClearColor (0.0,  0.0,  0.0,   0.0); 
  217.       render        ((1 => o.Target),  the_Camera.all); -- render the target for subsequent copy to impostor texture. 
  218.  
  219.       declare -- set texture coordinates for the veneer. 
  220.          use GL.Skins; 
  221.          the_Veneer  : p_Veneer_transparent_unlit_textured := p_Veneer_transparent_unlit_textured (o.skinned_Geometry.Veneer); 
  222.  
  223.          X_first     : Real := o.expand_X; 
  224.          Y_first     : Real := o.expand_Y; 
  225.          X_last      : Real := Real (o.current_Width_pixels)  / Real (texture_Width)  - X_First; 
  226.          Y_last      : Real := Real (o.current_Height_pixels) / Real (texture_Height) - Y_First; 
  227.       begin 
  228.          the_Veneer.texture_Coordinates := (1 => (s => X_first,     t => Y_first), 
  229.                                             2 => (s => X_last,      t => Y_first), 
  230.                                             3 => (s => X_last,      t => Y_last), 
  231.                                             4 => (s => X_first,     t => Y_last)); 
  232.       end; 
  233.  
  234.       if        Width_size  /= GL.textures.Size_width  (o.skin.Texture) 
  235.         or else Height_size /= GL.textures.Size_height (o.skin.Texture) 
  236.       then 
  237.          free (texture_Pool.all,  o.skin.Texture); 
  238.          o.skin.all.Texture := new_Texture (texture_Pool,  Natural (texture_Width),  Natural (texture_Height)); 
  239.       end if; 
  240.  
  241.       enable (o.skin.all.Texture); 
  242.  
  243.       GL.CopyTexSubImage2D (gl.TEXTURE_2D,  0, 
  244.                             o.current_copy_x_Offset, o.current_copy_y_Offset, 
  245.                             o.current_copy_X,        o.current_copy_Y, 
  246.                             o.current_copy_Width,    o.current_copy_Height); 
  247.  
  248.       GL.Errors.log (error_occurred => gl_Error); 
  249.  
  250.       if gl_Error then 
  251.          put_Line ("x_Offset : " & GL.Int'image (o.current_copy_x_Offset) & " ********"); 
  252.          put_Line ("y_Offset : " & GL.Int'image (o.current_copy_y_Offset)); 
  253.  
  254.          put_Line ("start x : " & GL.Int'image (o.current_copy_X)); 
  255.          put_Line ("start y : " & GL.Int'image (o.current_copy_Y)); 
  256.  
  257.          put_Line ("copy width : "  & GL.sizei'image (o.current_copy_Width)); 
  258.          put_Line ("copy height : " & GL.sizei'image (o.current_copy_Height)); 
  259.  
  260.          put_Line ("width_pixels : "  & GL.sizei'image (o.current_Width_pixels)); 
  261.          put_Line ("height_pixels : " & GL.sizei'image (o.current_Height_pixels)); 
  262.  
  263.          put_Line ("width_size : "  & GL.textures.size'image (Width_size)); 
  264.          put_Line ("height_size : " & GL.textures.size'image (Height_size)); 
  265.  
  266.          put_Line ("texture width : "  & GL.sizei'image (texture_Width)); 
  267.          put_Line ("texutre height : " & GL.sizei'image (texture_Height)); 
  268.       end if; 
  269.  
  270.       o.never_Updated := False; 
  271.       o.freshen_Count := 0; 
  272.    end; 
  273.  
  274.    procedure freshen (o  : in out Impostor'Class;   the_Camera    : in     globe_3d.p_Camera; 
  275.                                                    texture_Pool  : in     GL.Textures.p_Pool; 
  276.                                                    is_Valid      :    out Boolean) 
  277.    is 
  278.       update_Required  : Boolean := o.Update_required (the_Camera);    -- nb : caches current update info 
  279.    begin 
  280.       if update_Required then 
  281.          o.update (the_Camera, texture_Pool); 
  282.       end if; 
  283.  
  284.       is_Valid := o.is_Valid; 
  285.    end; 
  286.  
  287.    function target_camera_Distance (o  : in Impostor'Class) return Real 
  288.    is 
  289.    begin 
  290.       return o.target_camera_Distance; 
  291.    end; 
  292.  
  293.    function is_Valid (o  : in Impostor'Class) return Boolean 
  294.    is 
  295.    begin 
  296.       return o.is_Valid; 
  297.    end; 
  298.  
  299.    function never_Updated (o  : in Impostor'Class) return Boolean 
  300.    is 
  301.    begin 
  302.       return o.never_Updated; 
  303.    end; 
  304.  
  305.    function frame_Count_since_last_update (o  : in Impostor'Class) return Natural 
  306.    is 
  307.    begin 
  308.       return Natural (o.freshen_Count); 
  309.    end; 
  310.  
  311.    function skinned_Geometrys (o  : in Impostor) return GL.skinned_geometry.skinned_Geometrys 
  312.    is 
  313.    begin 
  314.       return (1 => o.skinned_Geometry); 
  315.    end; 
  316.  
  317.    function face_Count (o  : in Impostor) return Natural 
  318.    is 
  319.    begin 
  320.       return 1; 
  321.    end; 
  322.  
  323.    procedure Display (o  : in out Impostor;   clip  : in     Clipping_data) 
  324.    is 
  325.    begin 
  326.       null;   -- actual display is done by the renderer (ie glut.Windows), which requests all skinned Geometry's 
  327.               -- and then applies 'gl state' sorting for performance, before drawing. 
  328.    end Display; 
  329.  
  330.    procedure set_Alpha (o     : in out Impostor;   Alpha  : in GL.Double) 
  331.    is 
  332.    begin 
  333.       null;   -- tbd 
  334.    end; 
  335.  
  336.    function Bounds (o  : in     Impostor) return GL.geometry.Bounds_record 
  337.    is 
  338.    begin 
  339.       return o.skinned_geometry.Geometry.Bounds; 
  340.    end; 
  341.  
  342.    function  is_Transparent (o     : in Impostor) return Boolean 
  343.    is 
  344.    begin 
  345.       return True;   -- tbd : - if using gl alpha test, depth sorting is not needed apparently. 
  346.                      --        in which case this could be set to False, and treated as a non - transparent in g3d.render. 
  347.                      --        may then be faster (?). 
  348.                      --      - seems to make little difference . .. test with different vid card. 
  349.    end; 
  350.  
  351.    function Skin (o  : access Impostor) return GL.skins.p_Skin_transparent_unlit_textured 
  352.    is 
  353.    begin 
  354.       return GL.skins.p_Skin_transparent_unlit_textured (o.skinned_geometry.skin); 
  355.    end; 
  356.  
  357.    function Quads (o  : in Impostor) return GL.geometry.primitives.p_Quads 
  358.    is 
  359.       use GL.Geometry.Primitives, GL.geometry.primal; 
  360.    begin 
  361.       return p_Quads (p_primal_Geometry (o.skinned_geometry.Geometry).Primitive); 
  362.    end; 
  363.  
  364.    -- note : only old, unused code folows (may be useful) . .. 
  365.    -- 
  366.  
  367.    -- tbd : enable_rotation is no good for impostors, since they must be aligned with the viewport 
  368.    --      it might be useful for general billboards however ! 
  369.    -- 
  370.    procedure enable_Rotation (o  : in Impostor;   camera_Site  : in Vector_3D) 
  371.    is 
  372.       use globe_3d.Math, globe_3d.REF, GL; 
  373.       lookAt        : Vector_3D := (0.0,  0.0,  1.0); 
  374.       objToCamProj  : Vector_3D := Normalized ((camera_Site (0) - o.Centre (0),  0.0,  camera_Site (2) - o.Centre (2))); 
  375.       upAux         : Vector_3D := lookAt * objToCamProj; 
  376.       angleCosine   : GL.Double := lookAt * objToCamProj; 
  377.    begin 
  378.       if    angleCosine > - 0.9999 
  379.         and angleCosine <  0.9999 
  380.       then 
  381.          GL.Rotate (arcCos (angleCosine) * 180.0 / 3.14,   upAux (0), upAux (1), upAux (2)); 
  382.       end if; 
  383.  
  384.       declare 
  385.          objToCam  : Vector_3D := Normalized ((camera_Site (0) - o.Centre (0), 
  386.                                               camera_Site (1) - o.Centre (1), 
  387.                                               camera_Site (2) - o.Centre (2))); 
  388.       begin 
  389.          angleCosine := objToCamProj * objToCam; 
  390.  
  391.          if    angleCosine > - 0.9999 
  392.            and angleCosine <  0.9999 
  393.          then 
  394.             if objToCam (1) < 0.0 then 
  395.                GL.Rotate (arcCos (angleCosine) * 180.0 / 3.14,   1.0, 0.0, 0.0); 
  396.             else 
  397.                GL.Rotate (arcCos (angleCosine) * 180.0 / 3.14,  - 1.0, 0.0, 0.0); 
  398.             end if; 
  399.          end if; 
  400.       end; 
  401.  
  402.    end; 
  403.    -- 
  404.    -- based on lighthouse3d billboard example. 
  405.  
  406. end GLOBE_3D.Impostor; 
  407.