#include #include #include using namespace std; #include "opengl.h" #include "util.h" #include "entity.h" #include "oct.h" #include "view.h" ///////////////////////////////////////////////////////////////////////////// geometry::~geometry () { } template class geometry_opengl1d; template class geometry_opengl1d; template class geometry_opengl1d; template class geometry_opengl1d; template class geometry_opengl2d; template class geometry_opengl2d; template class geometry_opengl2d; template class geometry_opengl2d; template class geometry_opengl2d; template class geometry_opengl2d; geometry_opengl::geometry_opengl () { list = glGenLists (1); } geometry_opengl::~geometry_opengl () { glDeleteLists (list, 1); } template void geometry_opengl1d::set (const vector &v) { clear (); insert (end (), v.begin (), v.end ()); bbox.reset (); for (const_iterator i = end (); i-- != begin (); ) bbox.add (i->v); update (); } template void geometry_opengl1d::draw (view &ctx) { glBegin (type); for (iterator i = begin (); i < end (); ++i) glVertex3fv ((GLfloat *)&i->v); glEnd (); } template void geometry_opengl2d::set (const vector &v) { bbox.reset (); for (vector::const_iterator i = v.end (); i-- != v.begin (); ) bbox.add (i->v); update (); glNewList (list, GL_COMPILE); #if 0 glBegin (type); for (vector::const_iterator i = v.begin (); i < v.end (); ++i) { glTexCoord2fv ((GLfloat *)&i->t); glNormal3fv ((GLfloat *)&i->n); glVertex3fv ((GLfloat *)&i->v); } glEnd (); #else glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0); glEnableClientState (GL_VERTEX_ARRAY); glEnableClientState (GL_NORMAL_ARRAY); glEnableClientState (GL_TEXTURE_COORD_ARRAY); glNormalPointer (GL_FLOAT, sizeof (vertex_t2f_n3f_v3f), (void *)&v.begin ()->n); glTexCoordPointer (2, GL_FLOAT, sizeof (vertex_t2f_n3f_v3f), (void *)&v.begin ()->t); glVertexPointer (3, GL_FLOAT, sizeof (vertex_t2f_n3f_v3f), (void *)&v.begin ()->v); glDrawArrays (type, 0, v.size ()); glDisableClientState (GL_VERTEX_ARRAY); glDisableClientState (GL_NORMAL_ARRAY); glDisableClientState (GL_TEXTURE_COORD_ARRAY); #endif glEndList (); } template void geometry_opengl2d::draw (view &ctx) { m->enable (ctx); glCallList (list); m->disable (ctx); } void geometry_sphere::update () { bbox.reset (); bbox.add (-point (radius, radius, radius)); bbox.add ( point (radius, radius, radius)); geometry::update (); } void geometry_sphere::draw (view &ctx) { int n = min (100, max (15, (int)(ctx.pixfact * radius) / 10)); m->enable (ctx); GLUquadric *quad = gluNewQuadric (); gluQuadricTexture (quad, true); gluSphere (quad, radius, n, n); gluDeleteQuadric (quad); m->disable (ctx); } ///////////////////////////////////////////////////////////////////////////// void geometry_indexed_2d::draw (view &ctx) { m->enable (ctx); vb.bind (); ib.draw (type, 0, ib.count); m->disable (ctx); } ///////////////////////////////////////////////////////////////////////////// void geometry_transform::update () { const box &sub = g->bbox; bbox.reset (); bbox.add (m * vec3 (sub.a.x, sub.a.y, sub.a.z)); bbox.add (m * vec3 (sub.b.x, sub.a.y, sub.a.z)); bbox.add (m * vec3 (sub.a.x, sub.b.y, sub.a.z)); bbox.add (m * vec3 (sub.b.x, sub.b.y, sub.a.z)); bbox.add (m * vec3 (sub.a.x, sub.a.y, sub.b.z)); bbox.add (m * vec3 (sub.b.x, sub.a.y, sub.b.z)); bbox.add (m * vec3 (sub.a.x, sub.b.y, sub.b.z)); bbox.add (m * vec3 (sub.b.x, sub.b.y, sub.b.z)); geometry::update (); } #if 0 void geometry_transform::renormalize () { point trans(m(0,3), m(1,3), m(2,3)); ::renormalize (e->orig, trans); m(0,3) = trans.x; m(1,3) = trans.y; m(2,3) = trans.z; } #endif void geometry_transform::update (const matrix &xfrm) { m = m * xfrm; update (); } void geometry_transform::set_matrix (const matrix &xfrm) { m = xfrm; update (); } void geometry_transform::draw (view &ctx) { glPushMatrix (); glMultMatrixf ((GLfloat *)&m); g->draw (ctx); glPopMatrix (); } void geometry_anim::draw (view &ctx) { matrix save_m = m; update (matrix::rotation (vx * timer.now, vec3 (1, 0, 0)) * matrix::rotation (vy * timer.now, vec3 (0, 1, 0)) * matrix::rotation (vz * timer.now, vec3 (0, 0, 1))); geometry_transform::draw (ctx); m = save_m; } ///////////////////////////////////////////////////////////////////////////// void geometry_filter::set (geometry *g) { this->g = g; if (g) g->parent = this; update (); } void geometry_filter::update () { if (g) { bbox = g->bbox; geometry::update (); } } void geometry_filter::draw (view &ctx) { g->draw (ctx); } geometry_filter::~geometry_filter () { delete g; } ///////////////////////////////////////////////////////////////////////////// void geometry_container::update () { bbox.reset (); for (iterator i = end (); i-- != begin (); ) bbox.add ((*i)->bbox); geometry::update (); } void geometry_container::add (geometry *g) { push_back (g); g->parent = this; update (); } void geometry_container::draw (view &ctx) { for (iterator i = end (); i-- != begin (); ) (*i)->draw (ctx); } geometry_container::~geometry_container () { for (iterator i = end (); i-- != begin (); ) delete *i; clear (); } /////////////////////////////////////////////////////////////////////////// static void nurbs_error (GLenum errorCode) { const GLubyte *estring; estring = gluErrorString(errorCode); fprintf (stderr, "Nurbs error: %s\n", estring); } void errorCallback(GLenum errorCode) { const GLubyte *estring; estring = gluErrorString(errorCode); fprintf (stderr, "Tessellation Error: %s\n", estring); exit (0); } void tcbBegin (GLenum prim) { glBegin (prim); } void tcbVertex (void *data) { glVertex3fv ((GLfloat *)data); } void tcbEnd () { glEnd (); } void geometry_nurbs::set () { // < XXX >: Testing CODE int u, v; for (u = 0; u < 4; u++) { for (v = 0; v < 4; v++) { ctlpoints[u][v][0] = 2.0*((GLfloat)u - 1.5); ctlpoints[u][v][1] = 2.0*((GLfloat)v - 1.5); if ( (u == 1 || u == 2) && (v == 1 || v == 2)) ctlpoints[u][v][2] = 3.0; else ctlpoints[u][v][2] = -3.0; } } tess = gluNewTess(); // glEnable(GL_AUTO_NORMAL); nurb = gluNewNurbsRenderer (); gluNurbsProperty (nurb, GLU_AUTO_LOAD_MATRIX, GL_FALSE); gluNurbsProperty (nurb, GLU_DISPLAY_MODE, GLU_FILL); gluNurbsProperty (nurb, GLU_NURBS_MODE, GLU_NURBS_TESSELLATOR); gluNurbsProperty (nurb, GLU_SAMPLING_METHOD, GLU_OBJECT_PATH_LENGTH); gluNurbsProperty (nurb, GLU_SAMPLING_TOLERANCE, 1.0); gluNurbsCallback (nurb, GLU_ERROR, (GLvoid (*)()) nurbs_error); gluNurbsCallback (nurb, GLU_NURBS_BEGIN, (GLvoid(*)()) tcbBegin); gluNurbsCallback (nurb, GLU_NURBS_VERTEX,(GLvoid(*)()) tcbVertex); gluNurbsCallback (nurb, GLU_NURBS_END, tcbEnd); glDisable(GL_AUTO_NORMAL); } void geometry_nurbs::draw (view &ctx) { GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0}; GLfloat mat_diffuse[] = { 0.7, 0.7, 0.7, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 100.0 }; glClearColor (0.0, 0.0, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glEnable(GL_AUTO_NORMAL); gluBeginSurface (nurb); gluNurbsSurface (nurb, 8, knots, 8, knots, 4 * 3, 3, &ctlpoints[0][0][0], 4, 4, GL_MAP2_VERTEX_3); gluEndSurface (nurb); /* glEnable(GL_AUTO_NORMAL); glPushMatrix(); GL_LG_DEBUG; ======= gluEndSurface (nurb); >>>>>>> 1.40 glDisable(GL_AUTO_NORMAL); glPopMatrix(); glFlush(); */ } ///////////////////////////////////////////////////////////////////////////// entity::entity (geometry *g) : geometry_filter(g) , p(0,0,0) { update (); } entity::~entity () { hide (); } visibility_base *entity::new_visibility () { return new entity_visibility (*this); } void entity::clear_visibility (visibility_base *vs) { ((entity_visibility *)vs)->clear (); } void entity::move (const vec3 &v) { p = p + v; renormalize (orig, p); update (); } void entity::show () { if (!o.size ()) world.add (this); } void entity::hide () { for (vector::iterator i = o.end (); i-- != o.begin (); ) (*i)->remove (this); o.clear (); } void entity::update () { if (!g) return; bbox = g->bbox; a.x = orig.x + (soffs)floorf (bbox.a.x + p.x); a.y = orig.y + (soffs)floorf (bbox.a.y + p.y); a.z = orig.z + (soffs)floorf (bbox.a.z + p.z); b.x = orig.x + (soffs)ceilf (bbox.b.x + p.x); b.y = orig.y + (soffs)ceilf (bbox.b.y + p.y); b.z = orig.z + (soffs)ceilf (bbox.b.z + p.z); if (o.size ()) { hide (); show (); } } void entity::draw (view &ctx) { ctx.eorig = orig - ctx.orig; glPushMatrix (); glTranslatef (p.x + ctx.eorig.x, p.y + ctx.eorig.y, p.z + ctx.eorig.z); g->draw (ctx); glPopMatrix (); } ///////////////////////////////////////////////////////////////////////////// // #define SIZE 33 struct geometry_heightfield::node { vertex_t2f_n3f_v3f vd[SIZE][SIZE]; gl::vertex_buffer vb; GLushort *ibp; GLfloat hvar; GLfloat x, y, z, e; // 23 // 01 struct geometry_heightfield::node *sub[4]; void update_normals (); void draw (view &ctx); node (); }; geometry_heightfield::node::node () { sub[0] = sub[1] = sub[2] = sub[3] = 0; //vb.set (vd); } static index_buffer ib; static GLushort *ibp; static int icnt; geometry_heightfield::geometry_heightfield (GLfloat sx, GLfloat sy) : sx(sx), sy(sy) , sm (max (sx, sy)) { if (!ib) { ib.set (SIZE * SIZE * 6, GL_STATIC_DRAW); ibp = (GLushort *)ib.map (); GLushort *p = ibp; for (int x = 0; x < SIZE - 1; x++) for (int y = 0; y < SIZE - 1; y++) { unsigned short a = (y + 0) * SIZE + (x + 0); unsigned short b = (y + 0) * SIZE + (x + 1); unsigned short c = (y + 1) * SIZE + (x + 1); unsigned short d = (y + 1) * SIZE + (x + 0); *p++ = c; *p++ = b; *p++ = a; *p++ = d; *p++ = c; *p++ = a; } icnt = p - ibp; ib.unmap (); } update (); tree = new node; tree->hvar = 0.01F * sx; tree->x = tree->y = 0.F; tree->e = sm; for (int x = 0; x < SIZE; x++) for (int y = 0; y < SIZE; y++) { vertex_t2f_n3f_v3f &v = tree->vd[y][x]; v.t = tex2 ((GLfloat)x / (SIZE - 1), (GLfloat)y / (SIZE - 1)); v.v = vec3 (sx * x / (SIZE - 1), tree->hvar * rand () / RAND_MAX, sy * y / (SIZE - 1)); v.n = vec3 (0, 1, 0); } tree->update_normals (); tree->vb.set (&tree->vd[0][0], SIZE * SIZE); bbox.reset (); bbox.add (vec3 (0, 0, 0)); bbox.add (vec3 (sx, tree->hvar, sy)); } void geometry_heightfield::update () { geometry::update (); } static int maxcnt, thiscnt; static GLfloat mine; void geometry_heightfield::draw (view &ctx) { testmat->enable (ctx); maxcnt = 10; thiscnt = 0; mine = 1e38; tree->draw (ctx); testmat->disable (ctx); //printf (" TC %d mine %f\n", thiscnt, mine); } void geometry_heightfield::node::update_normals () { GLfloat az = 0.F; for (int x = 0; x < SIZE; x++) for (int y = 0; y < SIZE; y++) { vertex_t2f_n3f_v3f &v = vd[y][x]; if (x && y) v.n = normalize (cross (vd[y-1][x].v - v.v, vd[y][x-1].v - v.v)); az += v.v.y; } z = az / (SIZE * SIZE); } void geometry_heightfield::node::draw (view &ctx) { vec3 center = vec3 (ctx.eorig) + vec3 (x + e * .5F, z, y + e * .5F); GLfloat d = length (center); if (!overlap (ctx.frustum.c, sphere (center, e * 2))) return; if (d > e * 2.F) { if (mine > e) mine = e; thiscnt++; vb.bind (); ib.draw (GL_TRIANGLES, 0, icnt); } else { for (int i = 0; i < 4; i++) { if (!sub[i]) { if (!--maxcnt) { vb.bind (); ib.draw (GL_TRIANGLES, 0, icnt); } node *n = sub[i] = new node; n->hvar = hvar * 0.5; n->x = x + (i & 1 ? e * .5F : 0.F); n->y = y + (i & 2 ? e * .5F : 0.F); n->e = e * .5F; for (int x = 0; x < SIZE; x++) for (int y = 0; y < SIZE; y++) n->vd[y][x] = vd[(y >> 1) + (i & 2 ? SIZE / 2 : 0)][(x >> 1) + (i & 1 ? SIZE / 2 : 0)]; for (int x = 1; x < SIZE; x += 2) for (int y = 0; y < SIZE; y += 2) { n->vd[y][x].t = (n->vd[y][x-1].t + n->vd[y][x+1].t) * 0.5F; n->vd[y][x].v = (n->vd[y][x-1].v + n->vd[y][x+1].v) * 0.5F; if (y && y < SIZE - 1) n->vd[y][x].v.y += n->hvar * (GLfloat)rand () / RAND_MAX - n->hvar * .5F; } for (int x = 0; x < SIZE; x++) for (int y = 1; y < SIZE; y += 2) { n->vd[y][x].t = (n->vd[y-1][x].t + n->vd[y+1][x].t) * 0.5F; n->vd[y][x].v = (n->vd[y-1][x].v + n->vd[y+1][x].v) * 0.5F; if (x && x < SIZE - 1) n->vd[y][x].v.y += n->hvar * (GLfloat)rand () / RAND_MAX - n->hvar * .5F; } n->update_normals (); n->vb.set (&n->vd[0][0], SIZE * SIZE); } sub[i]->draw (ctx); } } } void entity_moveable::perform_step (double t) { vec3 vel = t * v; move (vel); } ///////////////////////////////////////////////////////////////////////////// skybox::skybox ( const char *left, const char *front, const char *right, const char *back, const char *top, const char *bottom ) { tex [0] = new texture (left , texture::CLAMP); tex [1] = new texture (front , texture::CLAMP); tex [2] = new texture (right , texture::CLAMP); tex [3] = new texture (back , texture::CLAMP); tex [4] = new texture (top , texture::CLAMP); tex [5] = new texture (bottom, texture::CLAMP); } skybox::~skybox () { for (int i = 6; i--; ) delete tex [i]; } void skybox::draw (view &ctx) { float x = ctx.p.x; float y = ctx.p.y; float z = ctx.p.z; float width = 1000.; float height = 1000.; float length = 1000.; x -= width * .5F; y -= height * .5F; z -= length * .5F; static skybox_material sm; sm.enable (ctx); // Draw Left side sm.tex->name = tex [0]->name; sm.tex->enable (); glBegin (GL_QUADS); glTexCoord2f (1.0f, 0.0f); glVertex3f (x, y + height, z); glTexCoord2f (0.0f, 0.0f); glVertex3f (x, y + height, z + length); glTexCoord2f (0.0f, 1.0f); glVertex3f (x, y, z + length); glTexCoord2f (1.0f, 1.0f); glVertex3f (x, y, z); glEnd (); sm.tex->disable (); // Draw Front side sm.tex->name = tex [1]->name; sm.tex->enable (); glBegin (GL_QUADS); glTexCoord2f (1.0f, 1.0f); glVertex3f (x + width, y, z); glTexCoord2f (1.0f, 0.0f); glVertex3f (x + width, y + height, z); glTexCoord2f (0.0f, 0.0f); glVertex3f (x, y + height, z); glTexCoord2f (0.0f, 1.0f); glVertex3f (x, y, z); glEnd (); sm.tex->disable (); // Draw Right side sm.tex->name = tex [2]->name; sm.tex->enable (); glBegin (GL_QUADS); glTexCoord2f (0.0f, 1.0f); glVertex3f (x + width, y, z); glTexCoord2f (1.0f, 1.0f); glVertex3f (x + width, y, z + length); glTexCoord2f (1.0f, 0.0f); glVertex3f (x + width, y + height, z + length); glTexCoord2f (0.0f, 0.0f); glVertex3f (x + width, y + height, z); glEnd (); sm.tex->disable (); // Draw Back side sm.tex->name = tex [3]->name; sm.tex->enable (); glBegin (GL_QUADS); glTexCoord2f (1.0f, 1.0f); glVertex3f (x, y, z + length); glTexCoord2f (1.0f, 0.0f); glVertex3f (x, y + height, z + length); glTexCoord2f (0.0f, 0.0f); glVertex3f (x + width, y + height, z + length); glTexCoord2f (0.0f, 1.0f); glVertex3f (x + width, y, z + length); glEnd (); sm.tex->disable (); // Draw Up side sm.tex->name = tex [4]->name; sm.tex->enable (); glBegin (GL_QUADS); glTexCoord2f (1.0f, 0.0f); glVertex3f (x, y, z); glTexCoord2f (0.0f, 0.0f); glVertex3f (x, y, z + length); glTexCoord2f (0.0f, 1.0f); glVertex3f (x + width, y, z + length); glTexCoord2f (1.0f, 1.0f); glVertex3f (x + width, y, z); glEnd (); sm.tex->disable (); // Draw Down side sm.tex->name = tex [5]->name; sm.tex->enable (); glBegin (GL_QUADS); glTexCoord2f (1.0f, 0.0f); glVertex3f (x + width, y + height, z); glTexCoord2f (0.0f, 0.0f); glVertex3f (x + width, y + height, z + length); glTexCoord2f (0.0f, 1.0f); glVertex3f (x, y + height, z + length); glTexCoord2f (1.0f, 1.0f); glVertex3f (x, y + height, z); glEnd (); sm.tex->disable (); sm.disable (ctx); }