#include #include using namespace std; #define GL_GLEXT_PROTOTYPES #include #include #include "oct.h" #include "view.h" #include "entity.h" vector occ_query_objects; static GLuint begin_occ_query () { GLuint id; if (occ_query_objects.size ()) { id = *(occ_query_objects.end () - 1); occ_query_objects.pop_back (); } else glGenQueriesARB (1, &id); glBeginQueryARB (GL_SAMPLES_PASSED, id); return id; } #define end_occ_query() glEndQueryARB (GL_SAMPLES_PASSED) GLuint occ_query_result (GLuint id) { GLuint count; glGetQueryObjectuivARB (id, GL_QUERY_RESULT, &count); occ_query_objects.push_back (id); return count; } octant world(0, sector (SOFFS_MIN, SOFFS_MIN, SOFFS_MIN), MAXEXTENT); octant::octant (octant *parent, const sector &orig, uoffs extent) : parent(parent), orig(orig), extent(extent) { for (fill = 8; fill--; ) sub[fill] = 0; } octant::~octant () { for (fill = 8; fill--; ) delete sub[fill]; } static bool overlap (const sector &o1, uoffs ea, const sector &a, const sector &b) { ea /= 2; sector center_1 = o1 + ea; sector size_2 = b - a; sector center_2 = a + size_2 / 2; return abs (center_1 - center_2) <= ea + size_2; } void octant::add (entity *e) { const sector &a = e->a; const sector &b = e->b; if (overlap (orig, extent, a, b)) { uoffs extent2 = extent / 2; uoffs size = max (abs (b - a)); if (size > extent2 || !extent2) { push_back (e); e->o.push_back (this); return; } for (int i = 8; i--; ) { sector s = orig; s.offset (i, extent2); if (overlap (s, extent2, a, b)) { if (!sub[i]) sub[i] = new octant (this, s, extent2); sub[i]->add (e); } } } } void octant::remove (entity *e) { } void octant::detect_visibility (view &ctx) { visibility_state &vs = ctx.vismap[this]; if (vs.generation != ctx.generation) vs.visibility = visibility_state::UNKNOWN; if (orig <= ctx.orig && ctx.orig <= orig + extent) { vs.visibility = visibility_state::PARTIAL; vs.generation = ctx.generation; } else { sector center_s (orig + extent / 2 - ctx.orig); point center (center_s.x, center_s.y, center_s.z); GLfloat dia = sqrtf (3) * (GLfloat)extent; if (ctx.frustum.t.distance (center) < -dia) return; if (ctx.frustum.b.distance (center) < -dia) return; if (ctx.frustum.l.distance (center) < -dia) return; if (ctx.frustum.r.distance (center) < -dia) return; if (ctx.frustum.n.distance (center) < -dia) return; GLfloat fd = ctx.frustum.f.distance (center); if (fd < -dia) { if (fd < -dia * 2) return; ctx.farlist.push_back (this); return; } } if (vs.visibility == visibility_state::UNKNOWN) vs.visibility = visibility_state::FULL; if (size ()) ctx.vislist.push_back (this); // node to start with unsigned char si = ctx.d.x < 0 ? 1 : 0 | ctx.d.y < 0 ? 2 : 0 | ctx.d.z < 0 ? 4 : 0; // bit-toggle to find next child for front-to-back order static unsigned char next[8] = { 0, 0^1, 1^2, 2^4, 4^3, 3^5, 5^6, 6^7 }; for (int i = 0; i < 8; i++) { si ^= next[i]; if (sub[si]) sub[si]->detect_visibility (ctx); } vs.generation = ctx.generation; } void octant::display (view &ctx) { #if 0 glBegin (GL_LINES); sector s = orig - ctx.orig; vec3 clr(0, 0.8, 0); glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, (const GLfloat*)&clr); for (int i = 8; i--; ) for (int ji = 3; ji--; ) { int j = i | (1 << ji); if (i != j) { glVertex3i (s.x + !!(i & 1) * extent, s.y + !!(i & 2) * extent, s.z + !!(i & 4) * extent); glVertex3i (s.x + !!(j & 1) * extent, s.y + !!(j & 2) * extent, s.z + !!(j & 4) * extent); } } glEnd (); glDisable(GL_COLOR_MATERIAL); #endif for (iterator i = end (); i != begin (); ) (*--i)->display (ctx); } void octant::draw_bbox (view &ctx) { sector s = orig - ctx.orig; int i; GLint verts[4 * 6] = { 0x00, 0x40, 0x60, 0x20, // -x 0x10, 0x30, 0x70, 0x50, // +x 0x00, 0x10, 0x50, 0x40, // -y 0x70, 0x30, 0x20, 0x60, // +y 0x00, 0x20, 0x30, 0x10, // -z 0x40, 0x50, 0x70, 0x60, // +z }; GLfloat cube[8][3] = { { s.x , s.y , s.z }, { s.x + (soffs)extent, s.y , s.z }, { s.x , s.y + (soffs)extent, s.z }, { s.x + (soffs)extent, s.y + (soffs)extent, s.z }, { s.x , s.y , s.z + (soffs)extent }, { s.x + (soffs)extent, s.y , s.z + (soffs)extent }, { s.x , s.y + (soffs)extent, s.z + (soffs)extent }, { s.x + (soffs)extent, s.y + (soffs)extent, s.z + (soffs)extent }, }; glBegin (GL_LINE_LOOP); for (i = 0; i < 4 * 6; i++) glVertex3fv (cube [verts [i] >> 4]); glEnd (); }