Files
lace/3-mid/opengl/source/lean/renderer/opengl-impostorer.adb
2022-07-31 17:34:54 +10:00

275 lines
10 KiB
Ada

with
openGL.Camera,
openGL.Impostor.simple,
openGL.Impostor.terrain,
ada.Containers.generic_Array_sort,
ada.unchecked_Deallocation;
package body openGL.Impostorer
is
---------
--- Forge
--
procedure define (Self : in out Item)
is
begin
Self.impostor_size_Min.Value_is (0.0625);
end define;
procedure destruct (Self : in out Item)
is
procedure deallocate is new ada.unchecked_Deallocation (impostor_load_Balancer.Slots,
impostor_load_Balancer.Slots_view);
begin
deallocate (Self.impostor_load_Slots);
declare
use Impostor,
visual_Maps_of_impostor;
the_Impostor : Impostor.view;
Cursor : visual_Maps_of_impostor.Cursor := Self.visual_Map_of_imposter.First;
begin
while has_Element (Cursor)
loop
the_Impostor := Element (Cursor);
Self.Renderer.free (the_Impostor);
next (Cursor);
end loop;
end;
end destruct;
--------------
--- Attributes
--
function impostor_Count (Self : in Item) return Natural
is
begin
return Natural (Self.visual_Map_of_imposter.Length);
end impostor_Count;
function impostor_size_Min (Self : in Item'Class) return Real
is
begin
return Self.impostor_size_Min.Value;
end impostor_size_Min;
procedure impostor_size_Min_is (Self : in out Item'Class; Now : in Real)
is
begin
Self.impostor_size_Min.Value_is (Now);
end impostor_size_Min_is;
function Camera (Self : in Item'Class) return access openGL.Camera.item'Class
is
begin
return Self.Camera;
end Camera;
procedure Camera_is (Self : in out Item'Class; Now : access openGL.Camera.item'Class)
is
begin
Self.Camera := Camera_view (Now);
end Camera_is;
function Renderer (Self : in Item'Class) return openGL.Renderer.lean.view
is
begin
return openGL.Renderer.lean.view (Self.Renderer);
end Renderer;
procedure Renderer_is (Self : in out Item'Class; Now : in openGL.Renderer.lean.view)
is
begin
Self.Renderer := Renderer_view (Now);
end Renderer_is;
--------------
-- Operations
--
procedure substitute (Self : in out Item; the_Visuals : in out openGL.Visual.views;
Camera : access openGL.Camera.item'Class)
is
begin
-- Find whether visual or imposter is used, for each object.
--
declare
transposed_camera_Attitude : constant Matrix_3x3 := Transpose (Camera.Spin);
Impostor_updates : openGL.Renderer.lean.impostor_Updates (1 .. 20_000);
impostor_updates_Last : Natural := 0;
procedure add (the_Impostor : in Impostor.view)
is
begin
impostor_updates_Last := impostor_updates_Last + 1;
Impostor_updates (impostor_updates_Last) := (Impostor => the_Impostor,
current_Width_pixels => the_Impostor.current_Width_pixels,
current_Height_pixels => the_Impostor.current_Height_pixels,
current_copy_x_Offset => the_Impostor.current_copy_X_Offset,
current_copy_y_Offset => the_Impostor.current_copy_Y_Offset,
current_copy_X => the_Impostor.current_copy_X,
current_copy_Y => the_Impostor.current_copy_Y,
current_copy_Width => the_Impostor.current_copy_Width,
current_copy_Height => the_Impostor.current_copy_Height,
current_Camera_look_at_Rotation => the_Impostor.current_Camera_look_at_Rotation);
the_Impostor.freshen_Count := 0;
the_Impostor.never_Updated := False;
end add;
the_impostor_size_Min : constant Real := Self.impostor_size_Min.Value;
begin
for Each in Self.impostor_load_Slots'Range
loop
Self.impostor_load_Slots (Each).impostors_Count := 0; -- Empty each slot's contents.
end loop;
for i in the_Visuals'Range
loop
declare
the_Visual : Visual .view renames the_Visuals (i);
the_Impostor : Impostor.view;
begin
-- Replace the visual with the impostors visual, if the visuals apparent size is small enough.
--
if the_Visual.apparent_Size < the_impostor_size_Min
then -- Use impostor.
-- Find or create the impostor for the visual.
--
declare
use visual_Maps_of_impostor;
begin
the_Impostor := Self.visual_Map_of_imposter.Element (the_Visual);
exception
when constraint_Error => -- No impostor exists for this visual yet, so create one.
if the_Visual.is_Terrain
then
the_Impostor := new Impostor.terrain.item;
else
the_Impostor := new Impostor.simple.item;
the_Impostor.set_size_update_trigger_Delta (to => 10);
the_Impostor.set_freshen_count_update_trigger_Mod (to => 250);
end if;
the_Impostor.set_Target (the_Visual);
Self.visual_Map_of_imposter.insert (the_Visual, the_Impostor);
end;
declare
use Visual;
impostor_Target : Visual.view renames the_Visual;
Impostor_update_required : constant Boolean := the_Impostor.update_Required (Camera);
Impostor_is_valid : constant Boolean := the_Impostor.is_Valid;
Impostor_never_updated : constant Boolean := the_Impostor.never_Updated;
begin
if Impostor_is_valid
then
if Impostor_update_required
then
the_Impostor.target_camera_Distance_less_frame_Count := the_Impostor.target_camera_Distance
- Real (the_Impostor.frame_Count_since_last_update);
if Impostor_never_updated
then
add (the_Impostor);
else
declare -- Add impostor to appropriate load balancing slot.
target_face_Count : constant Positive := impostor_Target.face_Count;
function Slot_Id return Positive
is
begin
for Each in Self.impostor_load_Slots'Range
loop
if target_face_Count <= Self.impostor_load_Slots (Each).max_Faces
then
return Each;
end if;
end loop;
raise Program_Error;
end Slot_Id;
the_Slot : impostor_load_Balancer.Slot renames Self.impostor_load_Slots (Slot_Id);
begin
the_Slot.impostors_Count := the_Slot.impostors_Count + 1;
the_Slot.Impostors (the_Slot.impostors_Count) := the_Impostor;
end;
end if;
end if;
the_Impostor.Visual.Site_is (Site_of (the_Visual.all));
the_Impostor.Visual.Spin_is (transposed_camera_Attitude);
the_Visuals (i) := the_Impostor.Visual; -- Replace the visual with the impostor.
end if;
end;
else -- Don't use impostor.
null;
end if;
end;
end loop;
-- Add the load balanced impostor updates.
--
for i in Self.impostor_load_Slots'Range
loop
declare
the_Slot : impostor_load_Balancer.Slot renames Self.impostor_load_Slots (i);
num_Updates : constant Natural := Natural'Min (the_Slot.max_Updates,
the_Slot.impostors_Count);
function "<" (Left, Right : in Impostor.view) return Boolean
is
begin
return Left .target_camera_Distance_less_frame_Count -- Subtracting 'frame count' allows distant targets a chance of
< Right.target_camera_Distance_less_frame_Count; -- update. (TODO: Need some sort of user-settable scale parameter
end "<"; -- to allow for very large scales such as space).
procedure sort is new ada.Containers.generic_Array_sort (Positive,
Impostor.view,
Impostor.views);
begin
sort (the_Slot.Impostors (1 .. the_Slot.impostors_Count));
for Each in 1 .. num_Updates
loop
add (the_Slot.Impostors (Each));
end loop;
end;
end loop;
Self.Renderer.queue_Impostor_updates (Impostor_updates (1 .. impostor_updates_Last),
Camera);
end;
end substitute;
end openGL.Impostorer;