ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libgender/oct.C
Revision: 1.94
Committed: Thu Aug 11 20:20:08 2005 UTC (18 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.93: +8 -15 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 ;//vs.occ_res = -1;
166 else if (!(vs.subvis || vs.evis))
167 {
168 ctx.postdepthlist.push_back (this);
169 return false;
170 }
171 else if (!vs.occ_res)
172 {
173 ctx.postdepthlist.push_back (this);
174 return false;
175 }
176
177 bool subvis = false;
178
179 // node to start with
180 unsigned char si = centeri.x > 0 ? 1 : 0
181 | centeri.y > 0 ? 2 : 0
182 | centeri.z > 0 ? 4 : 0;
183
184 // bit-toggle to find next child for front-to-back order
185 static unsigned char toggle[8+1]
186 = { 0, 0^1, 1^2, 2^4, 4^3, 3^5, 5^6, 6^7, 0 };
187
188 unsigned char *next = toggle;
189 do
190 {
191 si ^= *next;
192
193 if (sub[si])
194 subvis = subvis | sub[si]->detect_visibility (ctx);
195 }
196 while (*++next);
197
198 vs.subvis = subvis;
199
200 if (subvis)
201 {
202 if (size ())
203 {
204 ctx.postdepthlist.push_back (this);
205 ctx.vislist.push_back (this);
206 }
207
208 return true;
209 }
210 else
211 {
212 ctx.postdepthlist.push_back (this);
213 ctx.vislist.push_back (this);
214
215 return vs.evis || vs.occ_res > 0;
216 }
217 }
218
219 void octant::draw_depth (view &ctx)
220 {
221 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
222
223 if (!(vs.subvis || vs.evis))
224 return;
225
226 for (int i = 0; i < size (); ++i)
227 {
228 entity *e = (*this)[i];
229
230 entity_visibility &evis = *(entity_visibility *)e->get_visibility (ctx);
231
232 if (evis.occ_res)
233 {
234 if (!ctx.may_draw (e))
235 continue;
236
237 sector center = ((e->a + e->b) >> 1) - ctx.orig;
238 GLfloat z = length (vec3 (center));
239 ctx.pixfact = ctx.perspfact / z;
240
241 ctx.nz_far = max (ctx.nz_far, z + extent);
242 ctx.nz_near = min (ctx.nz_near, z - extent);
243
244 e->draw (ctx);
245 }
246 }
247 }
248
249 void octant::draw_postdepth (view &ctx)
250 {
251 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
252
253 if (!vs.evis)
254 {
255 ctx.begin_occ_query (vs.occ_res);
256 sector s = orig - ctx.orig;
257 gl::draw_bbox (s - extent, s + extent);
258 ctx.end_occ_query ();
259 }
260 else
261 {
262 vs.evis = false;
263
264 for (int i = 0; i < size (); ++i)
265 {
266 entity *e = (*this)[i];
267 entity_visibility &evis = *(entity_visibility *)e->get_visibility (ctx);
268
269 if (evis.occ_res)
270 vs.evis = true;
271 else
272 {
273 if (!ctx.may_draw (e))
274 continue;
275
276 ctx.stat1++;
277 ctx.begin_occ_query (evis.occ_res);
278 gl::draw_bbox (e->a - ctx.orig, e->b - ctx.orig);
279 ctx.end_occ_query ();
280 }
281 }
282 }
283 }
284
285 void octant::draw_lighted (view &ctx)
286 {
287 oct_visibility &vs = *(oct_visibility *)get_visibility (ctx);
288
289 #if 0
290 if (vs.state == FULL || vs.state == OCCLUDED)
291 {
292 sector s = orig - ctx.orig;
293 debugmat->enable (ctx);
294 if (max (s) >= extent)
295 gl::draw_bbox (s - extent, s + extent);
296 debugmat->disable (ctx);
297 //printf ("DLP %ld %ld %ld (%ld)\n", orig.x, orig.y, orig.z, extent);//D
298 }
299 #endif
300
301 for (int i = 0; i < size (); ++i)
302 {
303 entity *e = (*this)[i];
304 entity_visibility &evis = *(entity_visibility *)e->get_visibility (ctx);
305
306 if (evis.occ_res)
307 {
308 if (!ctx.may_draw (e))
309 continue;
310
311 sector center = ((e->a + e->b) >> 1) - ctx.orig;
312 GLfloat z = length (vec3 (center));
313 ctx.pixfact = ctx.perspfact / z;
314
315 if (!ctx.first_lighted
316 || evis.next > timer.now)
317 e->draw (ctx);
318 else
319 {
320 evis.next = timer.now + 0.2;
321 ctx.begin_occ_query (evis.occ_res);
322 e->draw (ctx);
323 ctx.end_occ_query ();
324 }
325 }
326 }
327 }
328