1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274 | 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;
|