Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
predlod.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/***************************************************************************
20 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
21 ***************************************************************************
22 * *
23 * Project Name : G *
24 * *
25 * $Archive:: /Commando/Code/ww3d2/predlod.cpp $*
26 * *
27 * $Author:: Jani_p $*
28 * *
29 * $Modtime:: 9/20/01 10:10a $*
30 * *
31 * $Revision:: 5 $*
32 * *
33 *-------------------------------------------------------------------------*
34 * Functions: *
35 * PredictiveLODOptimizerClass::Clear -- clear object list and total cost*
36 * PredictiveLODOptimizerClass::Add_Object -- adds object to list, cost *
37 * PredictiveLODOptimizerClass::Optimize_LODs -- does LOD optimization *
38 * PredictiveLODOptimizerClass::Free -- releases all memory used. *
39 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
40
41#include "predlod.h"
42#include <memory.h>
43
44/* NOTE: The LODHeapNode and LODHeap classes are defined here for use in the
45 * Optimize_LODs() member function. */
46
47// A node entry for a heap. It has no son/father pointers since it will be
48// used in an array implementation of a heap.
49
50/*
51** NOTE: LODHeapNodes contain pointers to RenderObjClass, but these pointers
52** are NOT tracked via refcounting. This is because the heaps are created and
53** destroyed within one function, so all references created are necessary;
54** and performing Add_Ref and Release_Ref every time a pointer is copied
55** would hurt performance.
56*/
57
59 public:
60 LODHeapNode(void) { Item = NULL; }
61 LODHeapNode (float key) { Item = NULL; Key = key; }
62 LODHeapNode (RenderObjClass * item, float key) { Item = item; Key = key; }
63
64 ~LODHeapNode(void) { }
65
66 RenderObjClass * Get_Item(void) { return(Item); }
67
68 float Get_Key(void) { return(Key); }
69 void Set_Key(float key) { Key = key; }
70
71 int operator < (const LODHeapNode& node) { return(Key < node.Key); }
72 int operator <= (const LODHeapNode& node) { return(Key <= node.Key); }
73 int operator > (const LODHeapNode& node) { return(Key > node.Key); }
74 int operator >= (const LODHeapNode& node) { return(Key >= node.Key); }
75 int operator == (const LODHeapNode& node) { return(Key == node.Key); }
76 int operator != (const LODHeapNode& node) { return(Key != node.Key); }
77
78 private:
79 RenderObjClass *Item;
80 float Key;
81};
82
83// A Heap implemented as a complete binary tree in an array.
84class LODHeap {
85 public:
86 // This constructor receives an array of HeapNodes and arranges it to
87 // fulfil the heap condition. Note: the array will be used inside the
88 // heap, so it should never be used or deleted outside. The resulting
89 // heap is full - no nodes can be added until some are removed.
90 LODHeap(int count, LODHeapNode *NodeArray) {
91 Nodes = NodeArray;
92 Num = Max = count;
93 // Now build a heap from the array by working backwards, building
94 // subheaps from the bottom up. (starting at the middle of the array
95 // since the single-node subtrees at the leaves are already heaps)
96 int index;
97 for (index = Num/2; index >= 1; index--) Downheap(index);
98 }
99
100 ~LODHeap(void) {
101// delete []Nodes;
102 }
103
105 return &(Nodes[1]);
106 }
107
108 // This changes the key value of the entry at the top of the heap and
109 // adjusts the heap accordingly.
110 void Change_Key_Top(float new_key) {
111 Nodes[1].Set_Key(new_key);
112 Downheap(1);
113 }
114
115 // This searches for an entry which has a certain Item value, and
116 // changes its key to a new one. The heap is then adjusted accordingly.
117 void Change_Key(RenderObjClass *item, float new_key) {
118 for (int i=1; i <= Num; i++) {
119 if (Nodes[i].Get_Item() == item) {
120 float old_key = Nodes[i].Get_Key();
121 Nodes[i].Set_Key(new_key);
122 // If the key has been decreased, adjust the node downwards.
123 // Otherwise, adjust it upwards.
124 if (new_key < old_key) Downheap(i);
125 else Upheap(i);
126 break;
127 }
128 }
129 }
130
131 private:
132 LODHeap(void) {} // Just to ensure the default constructor is not used.
133
134 // The node and key arrays have one extra entry because entry [0] is
135 // reserved for various uses.
136 LODHeapNode * Nodes; // The nodes
137
138 int Max; // The maximum number of nodes
139 int Num; // the current number of nodes
140
141 // Two utility methods used by various other methods: both take a
142 // single entry which violates the heap condition and moves it in the
143 // heap until the heap condition is fulfilled.
144
145 // Upheap takes an entry with a (possibly) overlarge key and moves it
146 // up until the heap condition is satisfied. (this is a private
147 // method, so no error checking is needed).
148 // Note that Upheap puts a sentinel in Nodes[0].
149 void Upheap(int index) {
150 LODHeapNode node = Nodes[index];
151 Nodes[0].Set_Key(FLT_MAX);
152 while (Nodes[index/2] <= node) {
153 Nodes[index] = Nodes[index/2];
154 index = index/2;
155 }
156 Nodes[index] = node;
157 }
158
159 // Downheap takes an entry with a (possibly) oversmall key and moves it
160 // down until the heap condition is satisfied. (this is a private
161 // method, so no error checking is needed).
162 void Downheap(int index) {
163 LODHeapNode node = Nodes[index];
164 while (index <= Num/2) {
165 int child_index = index + index;
166 if ((child_index < Num) && (Nodes[child_index] < Nodes[child_index+1])) child_index++;
167 if (node >= Nodes[child_index]) break;
168 Nodes[index] = Nodes[child_index];
169 index = child_index;
170 }
171 Nodes[index] = node;
172 }
173};
174
175// Static PredictiveLODOptimizerClass data members:
176RenderObjClass ** PredictiveLODOptimizerClass::ObjectArray = NULL;
177int PredictiveLODOptimizerClass::ArraySize = 0;
178int PredictiveLODOptimizerClass::NumObjects = 0;
179float PredictiveLODOptimizerClass::TotalCost = 0.0f;
180LODHeapNode * PredictiveLODOptimizerClass::VisibleObjArray1;
181LODHeapNode * PredictiveLODOptimizerClass::VisibleObjArray2;
182int PredictiveLODOptimizerClass::VisibleObjArraySize;
183
184
185/**************************************************************************
186 * PredictiveLODOptimizerClass::Clear -- clear object list and total cost *
187 * *
188 * INPUT: *
189 * *
190 * OUTPUT: *
191 * *
192 * WARNINGS: *
193 * *
194 * HISTORY: *
195 * 03/12/1999 NH : Created. *
196 *========================================================================*/
198{
199 if (ObjectArray) {
200 // Release refs to all objects in the list:
201 for (int i = 0; i < NumObjects; i++) {
202 if (ObjectArray[i]) {
203 ObjectArray[i]->Release_Ref();
204 ObjectArray[i] = NULL;
205 }
206 }
207 }
208
209 TotalCost = 0.0f;
210 NumObjects = 0;
211}
212
213
214/**************************************************************************
215 * PredictiveLODOptimizerClass::Add_Object -- adds object to list, cost *
216 * *
217 * INPUT: *
218 * *
219 * OUTPUT: *
220 * *
221 * WARNINGS: *
222 * *
223 * HISTORY: *
224 * 03/12/1999 NH : Created. *
225 *========================================================================*/
227{
228 // If array present but too small, free it and copy it to new array.
229 if (ObjectArray) {
230 if (ArraySize <= NumObjects) {
231 int new_array_size = NumObjects + 100;
232 RenderObjClass **new_array = W3DNEWARRAY RenderObjClass *[new_array_size];
233 memcpy(new_array, ObjectArray, sizeof(RenderObjClass *) * NumObjects);
234 delete [] ObjectArray;
235 ObjectArray = new_array;
236 ArraySize = new_array_size;
237 }
238 } else {
239 // Create new object array.
240 ObjectArray = W3DNEWARRAY RenderObjClass *[100];
241 }
242
243 // Copy pointer and add ref
244 ObjectArray[NumObjects] = robj;
245 ObjectArray[NumObjects]->Add_Ref();
246 NumObjects++;
247
248 float cost = robj->Get_Cost();
249 // Some sanity checking so one object doesn't mess up the entire scene
250 WWASSERT (cost >= 0.0f);
251 WWASSERT (cost < 1.0e6);
252 TotalCost += cost;
253}
254
255
256/**************************************************************************
257 * PredictiveLODOptimizerClass::Optimize_LODs -- does LOD optimization *
258 * *
259 * INPUT: float max_cost - the upper bound on the total scene Cost. *
260 * *
261 * OUTPUT: none. *
262 * *
263 * WARNINGS: *
264 * *
265 * HISTORY: *
266 * 12/08/1997 NH : Created. *
267 * 04/23/1997 NH : Ported to SR 1.3. *
268 * 03/12/1999 NH : Moved to PredictiveLODOptimizerClass. *
269 * *
270 * COMMENTS: *
271 * This function implements the algorithm outlined in "Adaptive *
272 * Display Algorithm for Interactive Frame Rates During Visualization *
273 * of Complex Virtual Environments", Thomas Funkhouser & Carlo Sequin, *
274 * SIGGRAPH '93 Proceedings, pp. 247-253. *
275 * Modifications have been made to support screensize clamping of LODs. *
276 *========================================================================*/
278{
279 if (!ObjectArray || NumObjects == 0) return;
280
281 AllocVisibleObjArrays(NumObjects);
282
283 // Allocate and fill arrays. (one extra entry since the zeroth entry is not used).
284// LODHeapNode *visible_obj_array1 = W3DNEWARRAY LODHeapNode[NumObjects + 1];
285// LODHeapNode *visible_obj_array2 = W3DNEWARRAY LODHeapNode[NumObjects + 1];
286
287 // Insert objects into arrays: (0th entry reserved for sentinel values)
288 for (int i = 0; i < NumObjects; i++) {
289 RenderObjClass *robj = ObjectArray[i];
290 // We use minus Value for the first queue to make it ordered by minimum Value.
291 VisibleObjArray1[i + 1] = LODHeapNode(robj, -(robj->Get_Value()));
292 VisibleObjArray2[i + 1] = LODHeapNode(robj, robj->Get_Post_Increment_Value());
293 }
294
295 // Build priority queues:
296 LODHeap min_current_value_queue(NumObjects, VisibleObjArray1);
297 LODHeap max_post_increment_value_queue(NumObjects, VisibleObjArray2);
298 // These memory areas now are pointed to within the heaps:
299// visible_obj_array1 = NULL;
300// visible_obj_array2 = NULL;
301
302 // Main loop: iteratively increment/decrement tuples.
303 bool done = false;
304 RenderObjClass *max_data, *min_data;
305
306 while (!done) {
307 // Initialize max_data and min_data so comparison at end of loop uses correct values.
308 max_data = NULL;
309 min_data = NULL;
310
311 // Increment incrementable tuple with maximum next value.
312 if (TotalCost <= max_cost) {
313 // If tuple with maximum next value is already at maximum lod, all
314 // tuples are (since AT_MAX_LOD is smaller than any Value), so stop.
315 if (max_post_increment_value_queue.Top()->Get_Key() == RenderObjClass::AT_MAX_LOD) {
316 done = true;
317 break;
318 }
319
320 // Get (incrementable) tuple with maximum next value.
321 max_data = max_post_increment_value_queue.Top()->Get_Item();
322
323 // Increment tuple (and update TotalCost accordingly).
324 TotalCost -= max_data->Get_Cost();
325 max_data->Increment_LOD();
326 TotalCost += max_data->Get_Cost();
327
328 // Update priority queues with incremented tuple.
329 max_post_increment_value_queue.Change_Key_Top(max_data->Get_Post_Increment_Value());
330 min_current_value_queue.Change_Key(max_data, -(max_data->Get_Value()));
331 }
332
333 // Decrement decerementable tuples with minimum current value.
334 while (TotalCost > max_cost) {
335 // If tuple with minimum current value is already at minimum lod, all
336 // tuples are (since AT_MIN_LOD is smaller than any (negated) Value),
337 // so stop.
338 if (min_current_value_queue.Top()->Get_Key() == -RenderObjClass::AT_MIN_LOD) {
339 done = true;
340 break;
341 }
342
343 // Get (decrementable) tuple with minimum current value.
344 min_data = min_current_value_queue.Top()->Get_Item();
345
346 // Decrement tuple (and update TotalCost accordingly).
347 TotalCost -= min_data->Get_Cost();
348 min_data->Decrement_LOD();
349 TotalCost += min_data->Get_Cost();
350
351 // Update priority queues with incremented tuple.
352 min_current_value_queue.Change_Key_Top(-(min_data->Get_Value()));
353 max_post_increment_value_queue.Change_Key(min_data, min_data->Get_Post_Increment_Value());
354
355 // Check termination criterion (same tuple incremented and decremented).
356 if (max_data == min_data) {
357 done = true;
358 break;
359 }
360 }
361 }
362
363 // Clear optimizer:
364 Clear();
365}
366
367
368/**************************************************************************
369 * PredictiveLODOptimizerClass::Free -- releases all memory used. *
370 * *
371 * INPUT: *
372 * *
373 * OUTPUT: *
374 * *
375 * WARNINGS: *
376 * *
377 * HISTORY: *
378 * 03/12/1999 NH : Created. *
379 *========================================================================*/
381{
382 Clear();
383
384 if (ObjectArray) {
385 delete [] ObjectArray;
386 ObjectArray = NULL;
387 ArraySize = 0;
388 }
389
390 // Only the array number one has been allocated...
391 if (VisibleObjArray1) delete[] VisibleObjArray1;
392 VisibleObjArray1=NULL;
393 VisibleObjArray2=NULL;
394 VisibleObjArraySize = 0;
395}
396
397void PredictiveLODOptimizerClass::AllocVisibleObjArrays(int num_objects)
398{
399 if (VisibleObjArraySize<num_objects) {
400 VisibleObjArraySize=num_objects;
401 if (VisibleObjArray1) delete[] VisibleObjArray1; // Only the first array is actually allocated
402 VisibleObjArray1=W3DNEWARRAY LODHeapNode[2*(num_objects + 1)];
403 VisibleObjArray2=VisibleObjArray1+(num_objects + 1);
404 }
405}
406
#define NULL
Definition BaseType.h:92
#define WWASSERT
#define W3DNEWARRAY
Definition always.h:110
void Change_Key(RenderObjClass *item, float new_key)
Definition predlod.cpp:117
void Change_Key_Top(float new_key)
Definition predlod.cpp:110
LODHeap(int count, LODHeapNode *NodeArray)
Definition predlod.cpp:90
LODHeapNode * Top(void)
Definition predlod.cpp:104
~LODHeap(void)
Definition predlod.cpp:100
int operator==(const LODHeapNode &node)
Definition predlod.cpp:75
int operator>=(const LODHeapNode &node)
Definition predlod.cpp:74
~LODHeapNode(void)
Definition predlod.cpp:64
int operator<=(const LODHeapNode &node)
Definition predlod.cpp:72
int operator>(const LODHeapNode &node)
Definition predlod.cpp:73
float Get_Key(void)
Definition predlod.cpp:68
int operator!=(const LODHeapNode &node)
Definition predlod.cpp:76
void Set_Key(float key)
Definition predlod.cpp:69
RenderObjClass * Get_Item(void)
Definition predlod.cpp:66
LODHeapNode(RenderObjClass *item, float key)
Definition predlod.cpp:62
LODHeapNode(void)
Definition predlod.cpp:60
LODHeapNode(float key)
Definition predlod.cpp:61
int operator<(const LODHeapNode &node)
Definition predlod.cpp:71
static void Clear(void)
Definition predlod.cpp:197
static void Add_Object(RenderObjClass *robj)
Definition predlod.cpp:226
static void Optimize_LODs(float max_cost)
Definition predlod.cpp:277
static void Free(void)
Definition predlod.cpp:380
void Add_Ref(void) const
Definition refcount.cpp:171
virtual void Decrement_LOD(void)
Definition rendobj.h:410
virtual float Get_Post_Increment_Value(void) const
Definition rendobj.h:413
virtual void Increment_LOD(void)
Definition rendobj.h:409
virtual float Get_Cost(void) const
Definition rendobj.cpp:675
static const float AT_MAX_LOD
Definition rendobj.h:405
static const float AT_MIN_LOD
Definition rendobj.h:404
virtual float Get_Value(void) const
Definition rendobj.h:412