ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libgender/oct.C
Revision: 1.93
Committed: Thu Aug 11 19:28:45 2005 UTC (18 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.92: +60 -118 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #include <cstdlib>
2
3 #include <vector>
4
5 using namespace std;
6
7 #include "opengl.h"
8
9 #include "oct.h"
10 #include "view.h"
11 #include "entity.h"
12 #include "material.h" //DEBUG
13
14 struct oct_visibility : visibility_base
15 {
16 bool subvis, evis;
17 int occ_res;
18
19 void clear ()
20 {
21 occ_res = -1;
22 evis = true;
23 subvis = true;
24 }
25
26 oct_visibility (octant &oct)
27 {
28 clear ();
29 }
30 };
31
32 octant world(0, sector (0, 0, 0), MAXEXTENT);
33
34 octant::octant (octant *parent, const sector &orig, uoffs extent)
35 : parent(parent)
36 , orig(orig)
37 , extent(extent)
38 {
39 for (fill = 8; fill--; )
40 sub[fill] = 0;
41 }
42
43 visibility_base *octant::new_visibility ()
44 {
45 return new oct_visibility (*this);
46 }
47
48 void octant::clear_visibility (visibility_base *vs)
49 {
50 ((oct_visibility *)vs)->clear ();
51 }
52
53 octant::~octant ()
54 {
55 for (fill = 8; fill--; )
56 delete sub[fill];
57 }
58
59 static bool overlap (const sector &orig, uoffs extent, const sector &a, const sector &b)
60 {
61 sector size = (b - a + 1) >> 1;
62 sector center = a + size;
63
64 return abs (orig - center) <= extent + size;
65 }
66
67 static sector offset (const sector &s, int subindex, uoffs extent)
68 {
69 return sector (
70 s.x + (subindex & 1 ? extent : -extent),
71 s.y + (subindex & 2 ? extent : -extent),
72 s.z + (subindex & 4 ? extent : -extent)
73 );
74 }
75
76 void octant::add (entity *e)
77 {
78 const sector &a = e->a;
79 const sector &b = e->b;
80
81 uoffs size = max (abs (b - a));
82
83 if (size >= extent >> 4)
84 {
85 if (overlap (orig, extent, a, b))
86 {
87 push_back (e);
88 e->o.push_back (this);
89 }
90 }
91 else
92 {
93 uoffs extent2 = extent >> 1;
94
95 for (int i = 8; i--; )
96 {
97 sector s = offset (orig, i, extent2);
98
99 if (overlap (s, extent2, a, b))
100 {
101 if (!sub[i])
102 {
103 sub[i] = new octant (this, s, extent2);
104 fill++;
105 }
106
107 sub[i]->add (e);
108 }
109 }
110 }
111 }
112
113 void octant::remove (entity *e)
114 {
115 }
116
117 bool octant::detect_visibility (view &ctx) //, bool fully_visible)
118 {
119 sector centeri = orig - ctx.orig;
120 point centerf = point (centeri);
121
122 GLfloat rad = ctx.diagfact * extent;
123
124 if (!overlap (ctx.frustum.c, sphere (centerf, rad)))
125 return false;
126
127 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
128
129 if (max (centeri) < extent)
130 {
131 vs.evis = true;
132 vs.occ_res = -1;
133 }
134 else if (distance (ctx.frustum.t, centerf) < -rad
135 || distance (ctx.frustum.b, centerf) < -rad
136 || distance (ctx.frustum.l, centerf) < -rad
137 || distance (ctx.frustum.r, centerf) < -rad
138 || distance (ctx.frustum.n, centerf) < -rad)
139 {
140 vs.clear ();
141 return false;
142 }
143
144 #if 0
145 GLfloat fd = distance (ctx.frustum.f, centerf);
146
147 if (fd < -(ctx.c_far - ctx.z_far) -rad * 3.F)
148 return false;
149 #endif
150
151 // very important, optimize?
152 GLfloat z = length (ctx.p - centerf) + rad;
153 if (z < 0.F || ctx.perspfact * extent / z < 10.) // very crude "too small to see" check
154 {
155 vs.clear ();//D
156 return false;
157 }
158
159 #if 0
160 if (vs.state == PARTIAL || vs.state == FULL)
161 ctx.nc_far = max (ctx.nc_far, z);
162 #endif
163
164 if (vs.occ_res > 0)
165 {
166 vs.evis = true;
167 vs.occ_res = -1;
168 }
169
170 if (!(vs.subvis || vs.evis))
171 {
172 ctx.postdepthlist.push_back (this);
173 return false;
174 }
175
176 bool subvis = false;
177
178 // node to start with
179 unsigned char si = centeri.x > 0 ? 1 : 0
180 | centeri.y > 0 ? 2 : 0
181 | centeri.z > 0 ? 4 : 0;
182
183 // bit-toggle to find next child for front-to-back order
184 static unsigned char toggle[8+1]
185 = { 0, 0^1, 1^2, 2^4, 4^3, 3^5, 5^6, 6^7, 0 };
186
187 unsigned char *next = toggle;
188 do
189 {
190 si ^= *next;
191
192 if (sub[si])
193 subvis = subvis | sub[si]->detect_visibility (ctx);
194 }
195 while (*++next);
196
197 vs.subvis = subvis;
198
199 if (subvis)
200 {
201 if (size ())
202 {
203 ctx.postdepthlist.push_back (this);
204 ctx.vislist.push_back (this);
205 }
206
207 return true;
208 }
209 else if (!vs.evis)
210 {
211 ctx.postdepthlist.push_back (this);
212 ctx.vislist.push_back (this);
213
214 return false;
215 }
216 else
217 {
218 ctx.postdepthlist.push_back (this);
219 ctx.vislist.push_back (this);
220
221 return true;
222 }
223 }
224
225 void octant::draw_depth (view &ctx)
226 {
227 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
228
229 if (!(vs.subvis || vs.evis))
230 return;
231
232 for (int i = 0; i < size (); ++i)
233 {
234 entity *e = (*this)[i];
235
236 entity_visibility &evis = *(entity_visibility *)e->get_visibility (ctx);
237
238 if (evis.occ_res)
239 {
240 if (!ctx.may_draw (e))
241 continue;
242
243 sector center = ((e->a + e->b) >> 1) - ctx.orig;
244 GLfloat z = length (vec3 (center));
245 ctx.pixfact = ctx.perspfact / z;
246
247 ctx.nz_far = max (ctx.nz_far, z + extent);
248 ctx.nz_near = min (ctx.nz_near, z - extent);
249
250 e->draw (ctx);
251 }
252 }
253 }
254
255 void octant::draw_postdepth (view &ctx)
256 {
257 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
258
259 if (!(vs.subvis || vs.evis))
260 {
261 ctx.begin_occ_query (vs.occ_res);
262 sector s = orig - ctx.orig;
263 gl::draw_bbox (s - extent, s + extent);
264 ctx.end_occ_query ();
265 }
266 else
267 {
268 vs.evis = false;
269
270 for (int i = 0; i < size (); ++i)
271 {
272 entity *e = (*this)[i];
273 entity_visibility &evis = *(entity_visibility *)e->get_visibility (ctx);
274
275 if (evis.occ_res)
276 vs.evis = true;
277 else
278 {
279 if (!ctx.may_draw (e))
280 continue;
281
282 ctx.stat1++;
283 ctx.begin_occ_query (evis.occ_res);
284 gl::draw_bbox (e->a - ctx.orig, e->b - ctx.orig);
285 ctx.end_occ_query ();
286 }
287 }
288 }
289 }
290
291 void octant::draw_lighted (view &ctx)
292 {
293 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
294
295 #if 0
296 if (vs.state == FULL || vs.state == OCCLUDED)
297 {
298 sector s = orig - ctx.orig;
299 debugmat->enable (ctx);
300 if (max (s) >= extent)
301 gl::draw_bbox (s - extent, s + extent);
302 debugmat->disable (ctx);
303 //printf ("DLP %ld %ld %ld (%ld)\n", orig.x, orig.y, orig.z, extent);//D
304 }
305 #endif
306
307 for (int i = 0; i < size (); ++i)
308 {
309 entity *e = (*this)[i];
310 entity_visibility &evis = *(entity_visibility *)e->get_visibility (ctx);
311
312 if (evis.occ_res)
313 {
314 if (!ctx.may_draw (e))
315 continue;
316
317 sector center = ((e->a + e->b) >> 1) - ctx.orig;
318 GLfloat z = length (vec3 (center));
319 ctx.pixfact = ctx.perspfact / z;
320
321 if (!ctx.first_lighted
322 || evis.next > timer.now)
323 e->draw (ctx);
324 else
325 {
326 ctx.stat2++;//D
327 evis.next = timer.now + 0.2 + 1e6;
328 ctx.begin_occ_query (evis.occ_res);
329 e->draw (ctx);
330 ctx.end_occ_query ();
331 }
332 }
333 }
334 }
335