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;