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