Files
lace/3-mid/opengl/source/lean/renderer/opengl-impostor.adb
2025-10-05 16:22:49 +11:00

337 lines
12 KiB
Ada

with
openGL.Camera,
openGL.Model.billboard.textured,
openGL.texture_Set,
ada.unchecked_Deallocation;
package body openGL.Impostor
is
---------
--- Forge
--
procedure destroy (Self : in out Item)
is
use openGL.Visual,
Model,
Texture;
the_Model : Model.view := Self.Visual.Model;
the_Texture : Texture.Object := Model.billboard.textured.view (the_Model).Texture;
begin
free (the_Texture);
free (the_Model);
free (Self.Visual);
end destroy;
procedure free (Self : in out View)
is
procedure deallocate is new ada.unchecked_Deallocation (Item'Class, View);
begin
if Self /= null then
destroy (Self.all);
deallocate (Self);
end if;
end free;
--------------
--- Attributes
--
procedure Visual_is (Self : in out Item; Now : in openGL.Visual.view)
is
begin
Self.Visual := Now;
end Visual_is;
function Visual (Self : access Item) return openGL.Visual.view
is
begin
return Self.Visual;
end Visual;
function get_Target (Self : in Item) return openGL.Visual.view
is
begin
return Self.Target;
end get_Target;
procedure set_Target (Self : in out Item; Target : in openGL.Visual.view)
is
use type openGL.Visual.view;
Width : constant Real := Target.Model.Bounds.Ball * 2.00;
Height : constant Real := Target.Model.Bounds.Ball * 2.00;
begin
if Self.Visual = null
then
Self.Visual := new openGL.Visual.item;
end if;
Self.Target := Target;
Self.is_Terrain := Target.is_Terrain;
Self.Visual.Model_is (Model.billboard.textured.Forge.new_Billboard (Size => (Width => Width,
Height => Height),
Plane => Model.billboard.xy,
Texture => null_Asset,
texture_Details => texture_Set.to_Set ([1 => null_Asset])).all'Access);
Self.Visual.Transform_is (Target.Transform);
-- Self.Visual.model_Transform_is (Target.model_Transform);
end set_Target;
function target_camera_Distance (Self : in Item'Class) return Real
is
begin
return Self.target_camera_Distance;
end target_camera_Distance;
function is_Valid (Self : in Item'Class) return Boolean
is
begin
return Self.is_Valid;
end is_Valid;
function never_Updated (Self : in Item'Class) return Boolean
is
begin
return Self.never_Updated;
end never_Updated;
function frame_Count_since_last_update (Self : in Item'Class) return Natural
is
begin
return Natural (Self.freshen_Count);
end frame_Count_since_last_update;
function face_Count (Self : in Item) return Natural
is
pragma unreferenced (Self);
begin
return 1;
end face_Count;
procedure set_Alpha (Self : in out Item; Alpha : in Real)
is
begin
null; -- TODO
end set_Alpha;
function Bounds (Self : in Item) return openGL.Bounds
is
pragma Unreferenced (Self);
begin
return (others => <>); -- TODO
end Bounds;
pragma Unreferenced (Bounds);
function is_Transparent (Self : in Item) return Boolean
is
pragma unreferenced (Self);
begin
return True;
end is_Transparent;
-- Update trigger configuration.
--
procedure set_freshen_count_update_trigger_Mod (Self : in out Item; To : in Positive)
is
begin
Self.freshen_count_update_trigger_Mod := Counter (To);
end set_freshen_count_update_trigger_Mod;
function get_freshen_count_update_trigger_Mod (Self : in Item) return Positive
is
begin
return Positive (Self.freshen_count_update_trigger_Mod);
end get_freshen_count_update_trigger_Mod;
procedure set_size_update_trigger_Delta (Self : in out Item; To : in Positive)
is
begin
Self.size_update_trigger_Delta := gl.glSizeI (To);
end set_size_update_trigger_Delta;
function get_size_update_trigger_Delta (Self : in Item) return Positive
is
begin
return Positive (Self.size_update_trigger_Delta);
end get_size_update_trigger_Delta;
function general_Update_required (Self : access Item; the_Camera_Site : in Vector_3;
the_pixel_Region : in pixel_Region) return Boolean
is
pragma unreferenced (the_pixel_Region);
use linear_Algebra_3d;
use type gl.GLsizei;
Camera_has_moved : constant Boolean := the_Camera_Site /= Self.prior_camera_Position;
Target_has_moved : constant Boolean := get_Translation (Self.Target.Transform) /= Self.prior_target_Position;
-- Target_has_moved : constant Boolean := get_Translation (Self.Target.model_Transform) /= Self.prior_target_Position;
begin
Self.freshen_Count := Self.freshen_Count + 1;
if Self.freshen_Count > Self.freshen_count_update_trigger_Mod
then
return True;
end if;
if Camera_has_moved
and then abs (Angle (the_Camera_Site,
Self.prior_target_Position,
Self.prior_camera_Position)) > to_Radians (15.0)
then
return True;
end if;
if Target_has_moved
and then abs (Angle (get_Translation (Self.Target.Transform),
-- and then abs (Angle (get_Translation (Self.Target.model_Transform),
Self.prior_camera_Position,
Self.prior_target_Position)) > to_Radians (15.0)
then
return True;
end if;
if Self.prior_pixel_Region.Width > 40 -- Ignore target rotation triggered updates when target is small on screen.
and then Self.prior_pixel_Region.Height > 40 --
and then Self.prior_target_Rotation /= get_Rotation (Self.Target.Transform)
-- and then Self.prior_target_Rotation /= get_Rotation (Self.Target.model_Transform)
then
return True;
end if;
return False;
end general_Update_required;
function size_Update_required (Self : access Item; the_pixel_Region : in pixel_Region) return Boolean
is
use GL;
use type gl.GLsizei;
begin
return abs (the_pixel_Region.Width - Self.prior_Width_Pixels) > Self.size_update_trigger_Delta
or abs (the_pixel_Region.Height - Self.prior_Height_pixels) > Self.size_update_trigger_Delta;
end size_Update_required;
function get_pixel_Region (Self : access Item'Class; camera_Spin : in Matrix_3x3;
camera_Site : in Vector_3;
camera_projection_Transform : in Matrix_4x4;
camera_Viewport : in linear_Algebra_3d.Rectangle) return pixel_Region
is
use linear_Algebra_3D;
-- target_Centre : constant Vector_3 := camera_Spin * ( get_Translation (Self.Target.model_Transform)
target_Centre : constant Vector_3 := camera_Spin * ( get_Translation (Self.Target.Transform)
- camera_Site);
target_lower_Left : constant Vector_3 := target_Centre - [Self.Target.Model.Bounds.Ball,
Self.Target.Model.Bounds.Ball,
0.0];
target_Centre_proj : constant Vector_4 := target_Centre * camera_projection_Transform;
target_Lower_Left_proj : constant Vector_4 := target_lower_Left * camera_projection_Transform;
target_Centre_norm : constant Vector_3 := [target_Centre_proj (1) / target_Centre_proj (4),
target_Centre_proj (2) / target_Centre_proj (4),
target_Centre_proj (3) / target_Centre_proj (4)];
target_Lower_Left_norm : constant Vector_3 := [target_Lower_Left_proj (1) / target_Lower_Left_proj (4),
target_Lower_Left_proj (2) / target_Lower_Left_proj (4),
target_Lower_Left_proj (3) / target_Lower_Left_proj (4)];
target_Centre_norm_0to1 : constant Vector_3 := [target_Centre_norm (1) * 0.5 + 0.5,
target_Centre_norm (2) * 0.5 + 0.5,
target_Centre_norm (3) * 0.5 + 0.5];
target_Lower_Left_norm_0to1 : constant Vector_3 := [target_Lower_Left_norm (1) * 0.5 + 0.5,
target_Lower_Left_norm (2) * 0.5 + 0.5,
target_Lower_Left_norm (3) * 0.5 + 0.5];
viewport_Width : constant Integer := camera_Viewport.Max (1) - camera_Viewport.Min (1) + 1;
viewport_Height : constant Integer := camera_Viewport.Max (2) - camera_Viewport.Min (2) + 1;
Width : constant Real := 2.0 * Real (viewport_Width) * ( target_Centre_norm_0to1 (1)
- target_Lower_Left_norm_0to1 (1));
Width_pixels : constant gl.glSizei := gl.glSizei ( Integer (Real (viewport_Width) * target_Lower_Left_norm_0to1 (1) + Width)
- Integer (Real (viewport_Width) * target_Lower_Left_norm_0to1 (1))
+ 1);
Height : constant Real := 2.0 * Real (viewport_Height) * ( target_Centre_norm_0to1 (2)
- target_Lower_Left_norm_0to1 (2));
Height_pixels : constant gl.glSizei := gl.glSizei ( Integer (Real (viewport_Height) * target_Lower_Left_norm_0to1 (2) + Height)
- Integer (Real (viewport_Height) * target_Lower_Left_norm_0to1 (2))
+ 1);
use type gl.GLsizei;
begin
Self.all.target_camera_Distance := abs (target_Centre); -- NB: Cache distance from camera to target.
return (X => gl.glInt (target_Lower_Left_norm_0to1 (1) * Real (Viewport_Width)) - 0,
Y => gl.glInt (target_Lower_Left_norm_0to1 (2) * Real (viewport_Height)) - 0,
Width => Width_pixels + 0,
Height => Height_pixels + 0);
end get_pixel_Region;
--------------
-- Operations
--
procedure update (Self : in out Item; the_Camera : access Camera.item'Class;
texture_Pool : in texture.Pool_view)
is
pragma unreferenced (the_Camera, texture_Pool);
use openGL.Visual;
-- Width_size : constant openGL.texture.Size := to_Size (Natural (Self.current_Width_pixels));
-- Height_size : constant openGL.texture.Size := to_Size (Natural (Self.current_Height_pixels));
-- texture_Width : constant gl.glSizei := power_of_2_Ceiling (Natural (Self.current_Width_pixels ));
-- texture_Height : constant gl.glSizei := power_of_2_Ceiling (Natural (Self.current_Height_pixels));
the_Model : constant Model.billboard.textured.view := Model.billboard.textured.view (Self.Visual.Model);
-- GL_Error : Boolean;
begin
Self.Visual.all := Self.Target.all;
Self.Visual.Model_is (the_Model.all'Access);
end update;
end openGL.Impostor;