ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libgender/oct.C
Revision: 1.91
Committed: Wed Aug 10 02:13:50 2005 UTC (18 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.90: +37 -17 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 enum visibility_state {
15 PARTIAL, // surrounding the viewpoint
16 FULL, // in frustum
17 OCCLUDED, // in frustom, but occluded
18 };
19
20 struct evis {
21 entity *e;
22 visibility_state state;
23 double last; // time of last check
24
25 void clear ()
26 {
27 last = 0.;
28 state = FULL;
29 }
30
31 evis ()
32 {
33 clear ();
34 }
35 };
36
37 struct oct_visibility : visibility_base
38 {
39 vector<evis> vismap;
40
41 visibility_state state;
42 bool vis;
43
44 evis &get_visibility (int i, entity *e)
45 {
46 evis &evs = vismap [i];
47
48 if (evs.e != e)
49 {
50 evs.clear ();
51 evs.e = e;
52 }
53
54 return evs;
55 }
56
57 oct_visibility (octant &oct)
58 : state (FULL), vis (true)
59 {
60 }
61 };
62
63 octant world(0, sector (0, 0, 0), MAXEXTENT);
64
65 octant::octant (octant *parent, const sector &orig, uoffs extent)
66 : parent(parent)
67 , orig(orig)
68 , extent(extent)
69 {
70 for (fill = 8; fill--; )
71 sub[fill] = 0;
72 }
73
74 visibility_base *octant::new_visibility ()
75 {
76 return new oct_visibility (*this);
77 }
78
79 void octant::clear_visibility (visibility_base *vs)
80 {
81 ((oct_visibility *)vs)->vismap.clear ();
82 ((oct_visibility *)vs)->state = FULL;
83 }
84
85 octant::~octant ()
86 {
87 for (fill = 8; fill--; )
88 delete sub[fill];
89 }
90
91 static bool overlap (const sector &orig, uoffs extent, const sector &a, const sector &b)
92 {
93 sector size = (b - a + 1) >> 1;
94 sector center = a + size;
95
96 return abs (orig - center) <= extent + size;
97 }
98
99 static sector offset (const sector &s, int subindex, uoffs extent)
100 {
101 return sector (
102 s.x + (subindex & 1 ? extent : -extent),
103 s.y + (subindex & 2 ? extent : -extent),
104 s.z + (subindex & 4 ? extent : -extent)
105 );
106 }
107
108 void octant::add (entity *e)
109 {
110 const sector &a = e->a;
111 const sector &b = e->b;
112
113 uoffs size = max (abs (b - a));
114
115 if (size >= extent >> 4)
116 {
117 if (overlap (orig, extent, a, b))
118 {
119 push_back (e);
120 e->o.push_back (this);
121 }
122 }
123 else
124 {
125 uoffs extent2 = extent >> 1;
126
127 for (int i = 8; i--; )
128 {
129 sector s = offset (orig, i, extent2);
130
131 if (overlap (s, extent2, a, b))
132 {
133 if (!sub[i])
134 {
135 sub[i] = new octant (this, s, extent2);
136 fill++;
137 }
138
139 sub[i]->add (e);
140 }
141 }
142 }
143 }
144
145 void octant::remove (entity *e)
146 {
147 }
148
149 bool octant::detect_visibility (view &ctx) //, bool fully_visible)
150 {
151 sector centeri = orig - ctx.orig;
152 point centerf = point (centeri);
153
154 GLfloat rad = ctx.diagfact * extent;
155
156 if (!overlap (ctx.frustum.c, sphere (centerf, rad)))
157 return false;
158
159 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
160
161 if (max (centeri) < extent)
162 vs.state = PARTIAL;
163 else
164 {
165 if (distance (ctx.frustum.t, centerf) < -rad) return false;
166 if (distance (ctx.frustum.b, centerf) < -rad) return false;
167 if (distance (ctx.frustum.l, centerf) < -rad) return false;
168 if (distance (ctx.frustum.r, centerf) < -rad) return false;
169 if (distance (ctx.frustum.n, centerf) < -rad) return false;
170 }
171
172 #if 0
173 GLfloat fd = distance (ctx.frustum.f, centerf);
174
175 if (fd < -(ctx.c_far - ctx.z_far) -rad * 3.F)
176 return false;
177 #endif
178
179 // very important, optimize?
180 GLfloat z = length (ctx.p - centerf) + rad;
181 if (z < 0.F || ctx.perspfact * extent / z < 10.) // very crude "too small to see" check
182 return false;
183
184 #if 0
185 if (vs.state == PARTIAL || vs.state == FULL)
186 ctx.nc_far = max (ctx.nc_far, z);
187 #endif
188
189 if (vs.state == OCCLUDED)
190 {
191 ctx.postdepthlist.push_back (this);
192
193 return false;
194 }
195
196 //bool visible = size () && vs.state != OCCLUDED;
197 bool visible = false;
198
199 // node to start with
200 unsigned char si = centeri.x > 0 ? 1 : 0
201 | centeri.y > 0 ? 2 : 0
202 | centeri.z > 0 ? 4 : 0;
203
204 // bit-toggle to find next child for front-to-back order
205 static unsigned char toggle[8+1]
206 = { 0, 0^1, 1^2, 2^4, 4^3, 3^5, 5^6, 6^7, 0 };
207
208 unsigned char *next = toggle;
209 do
210 {
211 si ^= *next;
212
213 if (sub[si])
214 visible = visible | sub[si]->detect_visibility (ctx);
215 }
216 while (*++next);
217
218 if (visible)
219 {
220 if (size ())
221 {
222 ctx.postdepthlist.push_back (this);
223 ctx.vislist.push_back (this);
224 }
225
226 vs.state = FULL;
227
228 return true;
229 }
230 else if (vs.state == OCCLUDED)
231 {
232 ctx.postdepthlist.push_back (this);
233
234 return false;
235 }
236 else if (size())
237 {
238 ctx.postdepthlist.push_back (this);
239 ctx.vislist.push_back (this);
240
241 return true;
242 }
243 else
244 {
245 return vs.state != PARTIAL;
246 }
247 }
248
249 void octant::draw_depth (view &ctx)
250 {
251 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
252
253 vs.vismap.resize (size ());
254
255 if (vs.state == OCCLUDED)
256 return;
257
258 for (int i = 0; i < size (); ++i)
259 {
260 entity *e = (*this)[i];
261 const evis &evs = vs.get_visibility (i, e);
262
263 if (evs.state != OCCLUDED)
264 {
265 if (!ctx.may_draw (e))
266 continue;
267
268 sector center = ((e->a + e->b) >> 1) - ctx.orig;
269 GLfloat z = length (vec3 (center));
270 ctx.pixfact = ctx.perspfact / z;
271
272 ctx.nz_far = max (ctx.nz_far, z + extent);
273 ctx.nz_near = min (ctx.nz_near, z - extent);
274
275 e->draw (ctx);
276 }
277 }
278 }
279
280 void octant::draw_postdepth (view &ctx)
281 {
282 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
283
284 if (vs.state == OCCLUDED || !vs.vis)
285 {
286 ctx.begin_occ_query (*this, 0);
287 sector s = orig - ctx.orig;
288 gl::draw_bbox (s - extent, s + extent);
289 ctx.end_occ_query ();
290 }
291 else
292 {
293 vs.vis = !size ();
294
295 for (int i = 0; i < size (); ++i)
296 {
297 entity *e = (*this)[i];
298 const evis &evs = vs.get_visibility (i, e);
299
300 if (evs.state == OCCLUDED)
301 {
302 if (!ctx.may_draw (e))
303 continue;
304
305 ctx.begin_occ_query (*this, e);
306 gl::draw_bbox (e->a - ctx.orig, e->b - ctx.orig);
307 ctx.end_occ_query ();
308 }
309 else
310 vs.vis = true;
311 }
312 vs.vis = true;//D
313 }
314 }
315
316 void octant::draw_lighted (view &ctx)
317 {
318 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
319
320 #if 0
321 if (vs.state == FULL || vs.state == OCCLUDED)
322 {
323 sector s = orig - ctx.orig;
324 debugmat->enable (ctx);
325 if (max (s) >= extent)
326 gl::draw_bbox (s - extent, s + extent);
327 debugmat->disable (ctx);
328 //printf ("DLP %ld %ld %ld (%ld)\n", orig.x, orig.y, orig.z, extent);//D
329 }
330 #endif
331
332 if (vs.state == OCCLUDED)
333 return;
334
335 for (int i = 0; i < size (); ++i)
336 {
337 entity *e = (*this)[i];
338 evis &evs = vs.get_visibility (i, e);
339
340 if (evs.state != OCCLUDED)
341 {
342 if (!ctx.may_draw (e))
343 continue;
344
345 sector center = ((e->a + e->b) >> 1) - ctx.orig;
346 GLfloat z = length (vec3 (center));
347 ctx.pixfact = ctx.perspfact / z;
348
349 if (!ctx.first_lighted
350 || evs.last + 1. > timer.now)
351 e->draw (ctx);
352 else
353 {
354 evs.last = timer.now;
355 ctx.begin_occ_query (*this, e);
356 e->draw (ctx);
357 ctx.end_occ_query ();
358 }
359 }
360 }
361 }
362
363 void octant::event (occ_query &ev)
364 {
365 oct_visibility &vs = *(oct_visibility *)get_visibility (ev.ctx);
366 entity *e = (entity *)ev.id;
367
368 if (e)
369 {
370 #if 1
371 for (vector<evis>::iterator i = vs.vismap.begin ();
372 i != vs.vismap.end ();
373 ++i)
374 if (i->e == e)
375 {
376 i->state = ev.count ? FULL : OCCLUDED;
377 return;
378 }
379 #endif
380 }
381 else
382 {
383 vs.state = ev.count ? FULL : OCCLUDED;
384 vs.vis = ev.count ? true : false;
385 }
386 }
387
388