/* * opengl interface */ #include "config.h" #if HAVE_OPENGL #include #include #include #include #include #include #include #include "interface.h" #include "gl_int.h" inline void glVertex (const vec &v) { glVertex3d (v[0], v[1], v[2]); } inline void glNormal (const vec &v) { glNormal3d (v[0], v[1], v[2]); } #define Begin(m) glBegin(m); in_begin = true; #define End() glEnd(); in_begin = false; #define HW_ACCUM 1 //#undef HW_ACCUM gl_int::gl_int () t_no { in_begin = false; dpy = XOpenDisplay (0); if (!dpy) throw error("can't open display"); int attributeList[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, #if HW_ACCUM GLX_ACCUM_RED_SIZE, 1, GLX_ACCUM_GREEN_SIZE, 1, GLX_ACCUM_BLUE_SIZE, 1, #endif None }; vi = glXChooseVisual (dpy, DefaultScreen(dpy), attributeList); if (!vi) error("no suitable visual"); glXGetConfig (dpy, vi, GLX_ALPHA_SIZE, &fb_depth); if (fb_depth > 0) { fb_format = GL_RGBA; fb_depth = 4; } else { fb_format = GL_RGB; fb_depth = 3; } cx = glXCreateContext (dpy, vi, 0, GL_TRUE); swa.colormap = XCreateColormap (dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); swa.border_pixel = 0; swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask; win = XCreateWindow (dpy, RootWindow (dpy, vi->screen), 0, 0, 900, 900, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa); XStoreName (dpy, win, PACKAGE " - " VERSION); XMapWindow (dpy, win); glXMakeCurrent(dpy, win, cx); /* set up viewing parameters */ glMatrixMode (GL_PROJECTION); gluPerspective (20, 1, 0.1, 20); glMatrixMode (GL_MODELVIEW); glTranslatef (0, 0, -15); /* set other relevant state information */ glEnable (GL_DEPTH_TEST); //glEnable (GL_AUTO_NORMAL); //glEnable (GL_DITHER); //glEnable (GL_LINE_SMOOTH); //glEnable (GL_POLYGON_SMOOTH); float specular[] = {1.0, 1.0, 1.0, 1.0}; float diffuse[] = {0.7, 0.7, 0.7, 0.7}; float position0[] = {0.2, -1.0, 0.2, 0.0}; float position1[] = {0.0, -1.0, -1.0, 0.0}; float lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0}; float local_view[] = { 0.0 }; glLightModelfv (GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv (GL_LIGHT0, GL_POSITION, position0); glLightfv (GL_LIGHT1, GL_DIFFUSE, diffuse); glLightfv (GL_LIGHT1, GL_POSITION, position1); glEnable (GL_LIGHT0); //glEnable (GL_LIGHT1); glEnable (GL_LIGHTING); glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); glHint (GL_POLYGON_SMOOTH_HINT, GL_FASTEST); glEnable (GL_NORMALIZE); glShadeModel (GL_SMOOTH); glEnable (GL_POLYGON_OFFSET_FILL); glPolygonOffset (-1, -1); glClearColor (1.0, 1.0, 1.0, 0.0); float spec[] = { 0.7, 0.7, 0.7, 0.0 }; glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec); float shine[] = { 20.0 }; glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, shine); float diff[] = { 0.4, 0.4, 0.4, 1.0 }; glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, diff); } gl_int::~gl_int () t_no { XCloseDisplay (dpy); } #define TREE_LIST 1 void gl_int::begin_fig () t_no { x1 = 1e10; y1 = 1e10; z1 = 1e10; x2 = -1e10; y2 = -1e10; z2 = -1e10; glNewList (TREE_LIST, GL_COMPILE); } void gl_int::end_fig () t_no { XEvent event; static int prevx, prevy; static int deltax = 0, deltay = 0; x1 -= 0.1; y1 -= 0.1; z1 -= 0.1; x2 += 0.1; y2 += 0.1; z2 += 0.2; glEndList (); bool changed = true; const bool hwaccum = false; // hwaccum does not work // the following are only initialized to prevent a compiler warning double xoffset = -1; double yoffset = -1; double stepsize = -1; bool even = false; double weight = -1; bool antialias = false; static bool buttondown = false; static unsigned long vX, vY, vW, vH, wW, wH, wWHD; // must(!) be static // swaccum typedef unsigned char pix_t; typedef unsigned long acc_t; const int acc_scale = 1 << 24; pix_t *pixbuf = 0; // read pixel buffer acc_t *accumbuf = 0; // our accumbuf acc_t accsum; for (bool loop = true; loop; ) { antialias = antialias || !buttondown; if (buttondown || !antialias || XPending (dpy)) do { char buf[31]; KeySym keysym; XNextEvent (dpy, &event); switch (event.type) { case Expose: break; case ConfigureNotify: { /* this approach preserves a 1:1 viewport aspect ratio */ int eW = event.xconfigure.width, eH = event.xconfigure.height; eW = eW & ~3; // for alignment purposes if (eW != wW || eH != wH) { changed = true; wW = eW; wH = eH; wWHD = wW * wH * fb_depth; if (eW >= eH) { vX = 0; vY = (eH - eW) >> 1; vW = vH = eW; } else { vX = (eW - eH) >> 1; vY = 0; vW = vH = eH; } glViewport (vX, vY, vW, vH); } } break; case KeyPress: (void) XLookupString (&event.xkey, buf, sizeof (buf), &keysym, NULL); switch (keysym) { case XK_a: antialias = true; break; case XK_q: case XK_Escape: loop = false; break; default: break; } break; case ButtonPress: prevx = event.xbutton.x; prevy = event.xbutton.y; buttondown = true; break; case ButtonRelease: buttondown = false; break; case MotionNotify: deltax += (event.xbutton.x - prevx); prevx = event.xbutton.x; deltay += (event.xbutton.y - prevy); prevy = event.xbutton.y; changed = true; break; default: break; } } while (XPending (dpy)); if (changed || buttondown) { changed = false; stepsize = 2; xoffset = 0; yoffset = 0; even = false; weight = 1; if (hwaccum) glClear(GL_ACCUM_BUFFER_BIT); else { free (pixbuf); pixbuf = 0; free (accumbuf); accumbuf = 0; accsum = 0; } } glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glPushMatrix (); glRotated ( deltax, 0, 1, 0); glRotated (-deltay, 1, 0, 1); double sc; sc = abs(4/(x2-x1)); if (abs (4/(y2-y1)) < sc) sc = abs(4/(y2-y1)); if (abs (4/(z2-z1)) < sc) sc = abs(4/(z2-z1)); glScaled (sc, sc, -sc); glTranslated (-0.5*(x2+x1),-0.5*(y2+y1), -0.5*(z1+z2)); glMatrixMode(GL_PROJECTION); glPushMatrix (); glTranslated (xoffset*10/vW, yoffset*10/vH, 0); glCallList (TREE_LIST); glPopMatrix (); glMatrixMode(GL_MODELVIEW); glPopMatrix (); if (buttondown || !antialias) { glXSwapBuffers (dpy, win); continue; } if (hwaccum) glAccum (GL_ACCUM, weight); else { if (!pixbuf ) pixbuf = (pix_t *) malloc (wWHD * sizeof (pix_t)); if (!accumbuf) accumbuf = (acc_t *) calloc (wWHD , sizeof (acc_t)); glReadPixels (0, 0, wW, wH, fb_format, GL_UNSIGNED_BYTE, pixbuf); acc_t scale[256]; // 256 == pix_t range for (int t = 0; t < 256; t++) scale[t] = acc_t (float (t) * acc_scale * weight); pix_t *p; acc_t *a; for (p = pixbuf, a = accumbuf; p < pixbuf + wWHD; p++, a++) *a += scale[*p]; } cout << setw(9) << stepsize << " " << setw(9) << 1 - yoffset << "\r" << flush; xoffset += even ? stepsize*0.5 : stepsize; if (xoffset >= 1.0) { yoffset += stepsize*0.5; if (yoffset >= 1.0) { if (hwaccum) { glAccum (GL_RETURN, 1.); glXSwapBuffers (dpy, win); glAccum (GL_MULT, 0.25); } else { pix_t *p; acc_t *a; for (p = pixbuf, a = accumbuf; p < pixbuf + wWHD; p++, a++) { *p = *a / acc_scale; *a /= 4; } glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode (GL_MODELVIEW); glPushMatrix (); glLoadIdentity (); glMatrixMode (GL_PROJECTION); glPushMatrix (); glLoadIdentity (); glRasterPos2f (float(-vX) / float(vW / 2) - 1, float(-vY) / float(vH / 2) - 1); glDrawPixels (wW, wH, fb_format, GL_UNSIGNED_BYTE, pixbuf); glPopMatrix (); glMatrixMode (GL_MODELVIEW); glPopMatrix (); glXSwapBuffers (dpy, win); accsum /= 4; } yoffset = 0; even = true; stepsize *= 0.5; weight *= 0.25; antialias = false; } even = !even; xoffset = even ? 0 : stepsize*0.5; } } free (pixbuf); free (accumbuf); glDeleteLists (TREE_LIST, 1); } void gl_int::clip (const vec &v) t_no { if (x1 > v[0]) x1 = v[0]; if (y1 > v[1]) y1 = v[1]; if (z1 > v[2]) z1 = v[2]; if (x2 < v[0]) x2 = v[0]; if (y2 < v[1]) y2 = v[1]; if (z2 < v[2]) z2 = v[2]; } void gl_int::check_attrs (const attribute_set &attr) t_err { vec v; if (!in_begin) glLineWidth (attr ("width",1)); v = attr("color", vec( 1, 1, 1)); float col[4]; col[0] = v[0]; col[1] = v[1]; col[2] = v[2]; col[3] = 1.0; glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col); } void gl_int::segment (const point &a, const point &b) t_err { check_attrs (a.attr); Begin (GL_LINES); glNormal (vec (0, 0, 0)); glVertex (a.v); clip(a.v); glVertex (b.v); clip(b.v); End (); } void gl_int::object (const points &v) t_err { // cerr << "polygon "; for (points::const_iterator j = v.begin (); j != v.end (); j++) cerr << j->first << " "; cerr << endl; if (v.size () < 3) return; glFrontFace (winding (v) > 0 ? GL_CCW : GL_CW); check_attrs (v.front ().attr); Begin (GL_POLYGON); for(points::const_iterator i = v.begin (); i != v.end(); ++i) { check_attrs (i->attr); glNormal (i->n); glVertex (i->v); clip (i->v); } End (); double len; if ((len = v.front ().attr ("draw_normals", 0))) { glNormal (vec (0, 0, 0)); Begin (GL_LINES); for(points::const_iterator i = v.begin (); i != v.end(); ++i) { glVertex (i->v); glVertex (i->v + len * i->n); } End (); } } #endif