with
     openGL.Conversions,
     ada.Strings.fixed;


package body openGL.Program.lit
is

   overriding
   procedure Lights_are (Self : in out Item;   Now : in Light.items)
   is
   begin
      Self.light_Count              := Now'Length;
      Self.Lights (1 .. Now'Length) := Now;
   end Lights_are;



   overriding
   procedure camera_Site_is (Self : in out Item;   Now : in Vector_3)
   is
   begin
      Self.camera_Site := Now;
   end camera_Site_is;



   overriding
   procedure model_Matrix_is (Self : in out Item;   Now : in Matrix_4x4)
   is
   begin
      Self.model_Transform := Now;
   end model_Matrix_is;



   overriding
   procedure set_Uniforms (Self : in Item)
   is
      use openGL.Conversions,
          linear_Algebra_3d;

      the_model_transform_Uniform        : constant Variable.uniform.mat4 := Self.uniform_Variable ("model_Transform");
      the_inverse_model_rotation_Uniform : constant Variable.uniform.mat3 := Self.uniform_Variable ("inverse_model_Rotation");

      the_camera_site_Uniform            : constant Variable.uniform.vec3 := Self.uniform_Variable ("camera_Site");
      the_light_count_Uniform            : constant Variable.uniform.int  := Self.uniform_Variable ("light_Count");
      the_specular_color_Uniform         : constant Variable.uniform.vec3 := Self.uniform_Variable ("specular_Color");
   begin
      openGL.Program.item (Self).set_Uniforms;

      the_camera_site_Uniform.Value_is (Self.camera_Site);
      the_model_transform_Uniform       .Value_is (Self.model_Transform);
      the_inverse_model_rotation_Uniform.Value_is (Inverse (get_Rotation (Self.model_Transform)));

      -- Lights.
      --
      the_light_count_Uniform   .Value_is (Self.light_Count);
      the_specular_color_Uniform.Value_is (to_Vector_3 (Self.specular_Color));

      for i in 1 .. Self.light_Count
      loop
         declare
            use Light;

            Light : openGL.Light.item renames Self.Lights (i);

            function light_Name return String
            is
               use ada.Strings,
                   ada.Strings.fixed;
            begin
               return "Lights[" & Trim (Integer'Image (i - 1), Left) & "]";
            end light_Name;

            site_Uniform                : constant Variable.uniform.vec4  := Self.uniform_Variable (light_Name & ".Site");
            strength_Uniform            : constant Variable.uniform.float := Self.uniform_Variable (light_Name & ".Strength");
            color_Uniform               : constant Variable.uniform.vec3  := Self.uniform_Variable (light_Name & ".Color");
            attenuation_Uniform         : constant Variable.uniform.float := Self.uniform_Variable (light_Name & ".Attenuation");
            ambient_coefficient_Uniform : constant Variable.uniform.float := Self.uniform_Variable (light_Name & ".ambient_Coefficient");
            cone_angle_Uniform          : constant Variable.uniform.float := Self.uniform_Variable (light_Name & ".cone_Angle");
            cone_direction_Uniform      : constant Variable.uniform.vec3  := Self.uniform_Variable (light_Name & ".cone_Direction");
         begin
            case Light.Kind
            is
            when Diffuse =>   site_Uniform.Value_is (Vector_4 (Light.Site & 1.0));
            when Direct  =>   site_Uniform.Value_is (Vector_4 (Light.Site & 0.0));    -- '0.0' tells shader that this light is 'direct'.
            end case;

            color_Uniform              .Value_is (to_Vector_3 (Light.Color));
            strength_Uniform           .Value_is (Real        (Light.Strength));
            attenuation_Uniform        .Value_is (             Light.Attenuation);
            ambient_coefficient_Uniform.Value_is (             Light.ambient_Coefficient);
            cone_angle_Uniform         .Value_is (Real        (Light.cone_Angle));
            cone_direction_Uniform     .Value_is (             Light.cone_Direction);
         end;
      end loop;
   end set_Uniforms;



   procedure specular_Color_is (Self : in out Item;   Now : in Color)
   is
   begin
      Self.specular_Color := Now;
   end specular_Color_is;



end openGL.Program.lit;
