Tiberian Technologies Scripts Reference Revision: 9000
Loading...
Searching...
No Matches
GridCull.h
1/* Renegade Scripts.dll
2 Copyright 2013 Tiberian Technologies
3
4 This file is part of the Renegade scripts.dll
5 The Renegade scripts.dll is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 2, or (at your option) any later
8 version. See the file COPYING for more details.
9 In addition, an exemption is given to allow Run Time Dynamic Linking of this code with any closed source module that does not contain code covered by this licence.
10 Only the source code to the module(s) containing the licenced code has to be released.
11*/
12#ifndef TT_INCLUDE_GRIDCULL_H
13#define TT_INCLUDE_GRIDCULL_H
14#include "cullsystemclass.h"
15#include "frustumclass.h"
16#include "aaboxclass.h"
17#include "obboxclass.h"
18class ChunkLoadClass;
19class ChunkSaveClass;
20class GridCullSystemClass : public CullSystemClass
21{
22public:
23 GridCullSystemClass(void);
24 ~GridCullSystemClass(void);
25 virtual void Collect_Objects(const Vector3 & point);
26 virtual void Collect_Objects(const AABoxClass & box);
27 virtual void Collect_Objects(const OBBoxClass & box);
28 virtual void Collect_Objects(const FrustumClass & frustum);
29 virtual void Re_Partition(const Vector3 & min,const Vector3 & max,float objdim);
30 virtual void Update_Culling(CullableClass * obj);
31 virtual void Load(ChunkLoadClass & cload);
32 virtual void Save(ChunkSaveClass & csave);
33 virtual int Get_Object_Count (void) const { return ObjCount; }
34 struct StatsStruct
35 {
36 int NodeCount;
37 int NodesAccepted;
38 int NodesTriviallyAccepted;
39 int NodesRejected;
40 };
41 void Reset_Statistics(void);
42 const StatsStruct & Get_Statistics(void);
43 void Get_Min_Cell_Size (Vector3 &size) const { size = MinCellSize; }
44 void Set_Min_Cell_Size (const Vector3 &size) { MinCellSize = size; }
45 int Get_Termination_Count (void) const { return TerminationCellCount; }
46 void Set_Termination_Count (int count) { TerminationCellCount = count; }
47protected:
48 void Collect_And_Unlink_All(void);
49 void Add_Object_Internal(CullableClass * obj);
50 void Remove_Object_Internal(CullableClass * obj);
51 enum
52 {
53 TERMINATION_CELL_COUNT = 16384,
54 UNGRIDDED_ADDRESS = 0xFFFFFFFF
55 };
56 Vector3 MinCellSize; // min dimensions for a cell (don't go below this...)
57 float MaxObjExtent; // max extent/radius (objects bigger than this are just put in a list)
58 int TerminationCellCount;
59 Vector3 Origin;
60 Vector3 CellDim;
61 Vector3 OOCellDim;
62 int CellCount[3];
63 CullableClass ** Cells;
64 CullableClass * NoGridList;
65 int ObjCount;
66 StatsStruct Stats;
67 struct VolumeStruct
68 {
69 VolumeStruct(void)
70 {
71 }
72 VolumeStruct(int i0,int j0,int k0,int i1,int j1,int k1)
73 {
74 Min[0] = i0;
75 Min[1] = j0;
76 Min[2] = k0;
77 Max[0] = i1;
78 Max[1] = j1;
79 Max[2] = k1;
80 }
81 bool Is_Leaf(void) const
82 {
83 return ((Max[0]-Min[0] == 1) && (Max[1]-Min[1] == 1) && (Max[2]-Min[2] == 1));
84 }
85 bool Is_Empty(void) const
86 {
87 return ((Max[0]-Min[0] <= 0) || (Max[1]-Min[1] <= 0) || (Max[2]-Min[2] <= 0));
88 }
89 void Split(VolumeStruct & v0,VolumeStruct & v1) const
90 {
91 int split_axis = 0;
92 int delta[3];
93 delta[0] = Max[0] - Min[0];
94 delta[1] = Max[1] - Min[1];
95 delta[2] = Max[2] - Min[2];
96 if (delta[1] > delta[split_axis]) split_axis = 1;
97 if (delta[2] > delta[split_axis]) split_axis = 2;
98 memcpy(&v0,this,sizeof(VolumeStruct));
99 memcpy(&v1,this,sizeof(VolumeStruct));
100 v0.Max[split_axis] = v1.Min[split_axis] = Min[split_axis] + (delta[split_axis] >> 1);
101 }
102 int Min[3];
103 int Max[3];
104 };
105 void link_object(CullableClass * obj);
106 void link_object(CullableClass * obj,int address);
107 void unlink_object(CullableClass * obj);
108 void link_object_to_list(CullableClass ** head,CullableClass * obj);
109 void unlink_object_from_list(CullableClass ** head,CullableClass * obj);
110 bool map_point_to_cell(const Vector3 & pt,int & set_i,int & set_j,int & set_k)
111 {
112 Vector3 dp = pt - Origin;
113 set_i = (int)floor(dp.X * OOCellDim.X);
114 set_j = (int)floor(dp.Y * OOCellDim.Y);
115 set_k = (int)floor(dp.Z * OOCellDim.Z);
116 if ( (set_i >= 0) && (set_j >= 0) && (set_k >= 0) && (set_i < CellCount[0]) && (set_j < CellCount[1]) && (set_k < CellCount[2]) )
117 {
118 return true;
119 }
120 return false;
121 }
122 bool map_point_to_address(const Vector3 & pt,int & set_address)
123 {
124 int i,j,k;
125 bool res = map_point_to_cell(pt,i,j,k);
126 if (res)
127 {
128 set_address = map_indices_to_address(i,j,k);
129 return true;
130 }
131 else
132 {
133 set_address = UNGRIDDED_ADDRESS;
134 return false;
135 }
136 }
137 int map_indices_to_address(int i,int j,int k)
138 {
139 return i + j*CellCount[0] + k*CellCount[0]*CellCount[1];
140 }
141 void clamp_indices_to_grid(int * i,int * j,int * k)
142 {
143 if (*i < 0) *i = 0;
144 if (*i >= CellCount[0]) *i = CellCount[0] - 1;
145 if (*j < 0) *j = 0;
146 if (*j >= CellCount[1]) *j = CellCount[1] - 1;
147 if (*k < 0) *k = 0;
148 if (*k >= CellCount[2]) *k = CellCount[2] - 1;
149 }
150 int total_cell_count(void)
151 {
152 return CellCount[0] * CellCount[1] * CellCount[2];
153 }
154 void compute_box(int i,int j,int k,AABoxClass * set_box)
155 {
156 Vector3 min,max;
157 min.X = Origin.X + i * CellDim.X - MaxObjExtent;
158 min.Y = Origin.Y + j * CellDim.Y - MaxObjExtent;
159 min.Z = Origin.Z + k * CellDim.Z - MaxObjExtent;
160 max.X = min.X + CellDim.X + 2.0f*MaxObjExtent;
161 max.Y = min.Y + CellDim.Y + 2.0f*MaxObjExtent;
162 max.Z = min.Z + CellDim.Z + 2.0f*MaxObjExtent;
163 set_box->Init((min+max)*0.5f, (min-max)*0.5f);
164 }
165 void compute_box(const VolumeStruct & vol, AABoxClass * set_box)
166 {
167 Vector3 min,max;
168 min.X = Origin.X + vol.Min[0] * CellDim.X - MaxObjExtent;
169 min.Y = Origin.Y + vol.Min[1] * CellDim.Y - MaxObjExtent;
170 min.Z = Origin.Z + vol.Min[2] * CellDim.Z - MaxObjExtent;
171 max.X = Origin.X + vol.Max[0] * CellDim.X + MaxObjExtent;
172 max.Y = Origin.Y + vol.Max[1] * CellDim.Y + MaxObjExtent;
173 max.Z = Origin.Z + vol.Max[2] * CellDim.Z + MaxObjExtent;
174 Vector3 center((max.X+min.X)*0.5f,(max.Y+min.Y)*0.5f,(max.Z+min.Z)*0.5f);
175 Vector3 extent((max.X-min.X)*0.5f,(max.Y-min.Y)*0.5f,(max.Z-min.Z)*0.5f);
176 set_box->Init(center,extent);
177 }
178 void init_volume(const Vector3 & bound_min,const Vector3 & bound_max,VolumeStruct * set_vol)
179 {
180 Vector3 grid_min = bound_min;
181 grid_min.X -= MaxObjExtent;
182 grid_min.Y -= MaxObjExtent;
183 grid_min.Z -= MaxObjExtent;
184 Vector3 grid_max = bound_max;
185 grid_max.X += MaxObjExtent;
186 grid_max.Y += MaxObjExtent;
187 grid_max.Z += MaxObjExtent;
188 GridCullSystemClass::map_point_to_cell(grid_min,set_vol->Min[0],set_vol->Min[1],set_vol->Min[2]);
189 GridCullSystemClass::map_point_to_cell(grid_max,set_vol->Max[0],set_vol->Max[1],set_vol->Max[2]);
190 clamp_indices_to_grid(&(set_vol->Min[0]),&(set_vol->Min[1]),&(set_vol->Min[2]));
191 clamp_indices_to_grid(&(set_vol->Max[0]),&(set_vol->Max[1]),&(set_vol->Max[2]));
192 set_vol->Max[0]++;
193 set_vol->Max[1]++;
194 set_vol->Max[2]++;
195 }
196 void init_volume(const Vector3 & point,VolumeStruct * set_volume);
197 void init_volume(const LineSegClass & line,VolumeStruct * set_volume)
198 {
199 Vector3 min_pt,max_pt;
200 min_pt.X = WWMath::Min(line.Get_P0().X,line.Get_P1().X);
201 max_pt.X = WWMath::Max(line.Get_P0().X,line.Get_P1().X);
202 min_pt.Y = WWMath::Min(line.Get_P0().Y,line.Get_P1().Y);
203 max_pt.Y = WWMath::Max(line.Get_P0().Y,line.Get_P1().Y);
204 min_pt.Z = WWMath::Min(line.Get_P0().Z,line.Get_P1().Z);
205 max_pt.Z = WWMath::Max(line.Get_P0().Z,line.Get_P1().Z);
206 init_volume(min_pt,max_pt,set_volume);
207 }
208 void init_volume(const AABoxClass & box,VolumeStruct * set_volume)
209 {
210 init_volume(box.Center - box.Extent,box.Center + box.Extent,set_volume);
211 }
212 void init_volume(const OBBoxClass & box,VolumeStruct * set_volume)
213 {
214 Vector3 aaextent;
215 box.Compute_Axis_Aligned_Extent(&aaextent);
216 init_volume(box.Center - aaextent,box.Center + aaextent,set_volume);
217 }
218 void init_volume(const FrustumClass & frustum,VolumeStruct * set_volume)
219 {
220 init_volume(frustum.Get_Bound_Min(),frustum.Get_Bound_Max(),set_volume);
221 }
222 void collect_objects_in_leaf(const Vector3 & point,CullableClass * head);
223 void collect_objects_in_leaf(const AABoxClass & aabox,CullableClass * head);
224 void collect_objects_in_leaf(const OBBoxClass & obbox,CullableClass * head);
225 void collect_objects_in_leaf(const FrustumClass & frustum,CullableClass * head);
226};
227#define GRIDCULL_NODE_ACCEPTED
228#define GRIDCULL_NODE_TRIVIALLY_ACCEPTED
229#define GRIDCULL_NODE_REJECTED
230template <class T> class TypedGridCullSystemClass : public GridCullSystemClass
231{
232public:
233 virtual void Add_Object(T * obj) { Add_Object_Internal(obj); }
234 virtual void Remove_Object(T * obj) { Remove_Object_Internal(obj); }
235 T * Get_First_Collected_Object(void) { return (T*)Get_First_Collected_Object_Internal(); }
236 T * Get_Next_Collected_Object(T * obj) { return (T*)Get_Next_Collected_Object_Internal(obj); }
237};
238class GridLinkClass : public CullLinkClass, public AutoPoolClass<GridLinkClass,256>
239{
240public:
241 GridLinkClass(GridCullSystemClass * system);
242 virtual ~GridLinkClass(void);
243 int GridAddress; // address in the grid.
244 CullableClass * Prev; // prev object in this cell
245 CullableClass * Next; // next object in this cell
246};
247class GridListIterator
248{
249public:
250 GridListIterator(CullableClass * head) { First(head); }
251 void First(CullableClass * head) { Head = head; CurObj = head; }
252 void First(void) { CurObj = Head; }
253 void Next(void) { if (CurObj) { CurObj = ((GridLinkClass *)CurObj->Get_Cull_Link())->Next; } }
254 void Prev(void) { if (CurObj) { CurObj = ((GridLinkClass *)CurObj->Get_Cull_Link())->Prev; } }
255 bool Is_Done(void) { return (CurObj == NULL); }
256 CullableClass * Get_Obj(void) { if (CurObj) { CurObj->Add_Ref(); } return CurObj; }
257 CullableClass * Peek_Obj(void) { return CurObj; }
258private:
259 CullableClass * Head; // head of the list we're working in
260 CullableClass * CurObj; // node we're currently at.
261};
262
263#endif