1 |
root |
1.1 |
/* |
2 |
|
|
* opengl interface |
3 |
|
|
*/ |
4 |
|
|
|
5 |
|
|
#include "config.h" |
6 |
|
|
|
7 |
|
|
#if HAVE_OPENGL |
8 |
|
|
|
9 |
|
|
#include <GL/glx.h> |
10 |
|
|
#include <GL/glu.h> |
11 |
|
|
#include <X11/keysym.h> |
12 |
|
|
|
13 |
|
|
#include <iostream> |
14 |
|
|
#include <iomanip> |
15 |
|
|
#include <cmath> |
16 |
|
|
#include <cstdlib> |
17 |
|
|
|
18 |
|
|
#include "interface.h" |
19 |
|
|
#include "gl_int.h" |
20 |
|
|
|
21 |
|
|
inline void glVertex (const vec &v) { glVertex3d (v[0], v[1], v[2]); } |
22 |
|
|
inline void glNormal (const vec &v) { glNormal3d (v[0], v[1], v[2]); } |
23 |
|
|
|
24 |
|
|
#define Begin(m) glBegin(m); in_begin = true; |
25 |
|
|
#define End() glEnd(); in_begin = false; |
26 |
|
|
|
27 |
|
|
#define HW_ACCUM 1 |
28 |
|
|
//#undef HW_ACCUM |
29 |
|
|
|
30 |
|
|
gl_int::gl_int () t_no |
31 |
|
|
{ |
32 |
|
|
in_begin = false; |
33 |
|
|
|
34 |
|
|
dpy = XOpenDisplay (0); |
35 |
|
|
if (!dpy) |
36 |
|
|
throw error("can't open display"); |
37 |
|
|
|
38 |
|
|
int attributeList[] = { |
39 |
|
|
GLX_RGBA, |
40 |
|
|
GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, |
41 |
|
|
#if HW_ACCUM |
42 |
|
|
GLX_ACCUM_RED_SIZE, 1, GLX_ACCUM_GREEN_SIZE, 1, GLX_ACCUM_BLUE_SIZE, 1, |
43 |
|
|
#endif |
44 |
|
|
None }; |
45 |
|
|
|
46 |
|
|
vi = glXChooseVisual (dpy, DefaultScreen(dpy), attributeList); |
47 |
|
|
if (!vi) error("no suitable visual"); |
48 |
|
|
|
49 |
|
|
glXGetConfig (dpy, vi, GLX_ALPHA_SIZE, &fb_depth); |
50 |
|
|
if (fb_depth > 0) |
51 |
|
|
{ |
52 |
|
|
fb_format = GL_RGBA; |
53 |
|
|
fb_depth = 4; |
54 |
|
|
} |
55 |
|
|
else |
56 |
|
|
{ |
57 |
|
|
fb_format = GL_RGB; |
58 |
|
|
fb_depth = 3; |
59 |
|
|
} |
60 |
|
|
|
61 |
|
|
cx = glXCreateContext (dpy, vi, 0, GL_TRUE); |
62 |
|
|
|
63 |
|
|
swa.colormap = XCreateColormap (dpy, RootWindow(dpy, vi->screen), |
64 |
|
|
vi->visual, AllocNone); |
65 |
|
|
|
66 |
|
|
swa.border_pixel = 0; |
67 |
|
|
swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | |
68 |
|
|
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask; |
69 |
|
|
win = XCreateWindow (dpy, RootWindow (dpy, vi->screen), 0, 0, 900, 900, |
70 |
|
|
0, vi->depth, InputOutput, vi->visual, |
71 |
|
|
CWBorderPixel | CWColormap | CWEventMask, &swa); |
72 |
|
|
XStoreName (dpy, win, PACKAGE " - " VERSION); |
73 |
|
|
XMapWindow (dpy, win); |
74 |
|
|
|
75 |
|
|
glXMakeCurrent(dpy, win, cx); |
76 |
|
|
|
77 |
|
|
/* set up viewing parameters */ |
78 |
|
|
glMatrixMode (GL_PROJECTION); |
79 |
|
|
gluPerspective (20, 1, 0.1, 20); |
80 |
|
|
glMatrixMode (GL_MODELVIEW); |
81 |
|
|
glTranslatef (0, 0, -15); |
82 |
|
|
|
83 |
|
|
/* set other relevant state information */ |
84 |
|
|
glEnable (GL_DEPTH_TEST); |
85 |
|
|
//glEnable (GL_AUTO_NORMAL); |
86 |
|
|
//glEnable (GL_DITHER); |
87 |
|
|
//glEnable (GL_LINE_SMOOTH); |
88 |
|
|
//glEnable (GL_POLYGON_SMOOTH); |
89 |
|
|
|
90 |
|
|
float specular[] = {1.0, 1.0, 1.0, 1.0}; |
91 |
|
|
float diffuse[] = {0.7, 0.7, 0.7, 0.7}; |
92 |
|
|
float position0[] = {0.2, -1.0, 0.2, 0.0}; |
93 |
|
|
float position1[] = {0.0, -1.0, -1.0, 0.0}; |
94 |
|
|
float lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0}; |
95 |
|
|
float local_view[] = { 0.0 }; |
96 |
|
|
|
97 |
|
|
glLightModelfv (GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); |
98 |
|
|
glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); |
99 |
|
|
glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); |
100 |
|
|
glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse); |
101 |
|
|
glLightfv (GL_LIGHT0, GL_POSITION, position0); |
102 |
|
|
glLightfv (GL_LIGHT1, GL_DIFFUSE, diffuse); |
103 |
|
|
glLightfv (GL_LIGHT1, GL_POSITION, position1); |
104 |
|
|
glEnable (GL_LIGHT0); |
105 |
|
|
//glEnable (GL_LIGHT1); |
106 |
|
|
glEnable (GL_LIGHTING); |
107 |
|
|
|
108 |
|
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); |
109 |
|
|
glHint (GL_POLYGON_SMOOTH_HINT, GL_FASTEST); |
110 |
|
|
|
111 |
|
|
glEnable (GL_NORMALIZE); |
112 |
|
|
|
113 |
|
|
glShadeModel (GL_SMOOTH); |
114 |
|
|
glEnable (GL_POLYGON_OFFSET_FILL); |
115 |
|
|
glPolygonOffset (-1, -1); |
116 |
|
|
|
117 |
|
|
glClearColor (1.0, 1.0, 1.0, 0.0); |
118 |
|
|
|
119 |
|
|
float spec[] = { 0.7, 0.7, 0.7, 0.0 }; glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, spec); |
120 |
|
|
float shine[] = { 20.0 }; glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, shine); |
121 |
|
|
float diff[] = { 0.4, 0.4, 0.4, 1.0 }; glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, diff); |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
gl_int::~gl_int () t_no |
125 |
|
|
{ |
126 |
|
|
XCloseDisplay (dpy); |
127 |
|
|
} |
128 |
|
|
|
129 |
|
|
#define TREE_LIST 1 |
130 |
|
|
|
131 |
|
|
void gl_int::begin_fig () t_no |
132 |
|
|
{ |
133 |
|
|
x1 = 1e10; y1 = 1e10; z1 = 1e10; |
134 |
|
|
x2 = -1e10; y2 = -1e10; z2 = -1e10; |
135 |
|
|
glNewList (TREE_LIST, GL_COMPILE); |
136 |
|
|
} |
137 |
|
|
|
138 |
|
|
void gl_int::end_fig () t_no |
139 |
|
|
{ |
140 |
|
|
XEvent event; |
141 |
|
|
static int prevx, prevy; |
142 |
|
|
static int deltax = 0, deltay = 0; |
143 |
|
|
|
144 |
|
|
x1 -= 0.1; y1 -= 0.1; z1 -= 0.1; |
145 |
|
|
x2 += 0.1; y2 += 0.1; z2 += 0.2; |
146 |
|
|
glEndList (); |
147 |
|
|
|
148 |
|
|
bool changed = true; |
149 |
|
|
const bool hwaccum = false; // hwaccum does not work |
150 |
|
|
|
151 |
|
|
// the following are only initialized to prevent a compiler warning |
152 |
|
|
double xoffset = -1; |
153 |
|
|
double yoffset = -1; |
154 |
|
|
double stepsize = -1; |
155 |
|
|
bool even = false; |
156 |
|
|
double weight = -1; |
157 |
|
|
|
158 |
|
|
bool antialias = false; |
159 |
|
|
static bool buttondown = false; |
160 |
|
|
|
161 |
|
|
static unsigned long vX, vY, vW, vH, wW, wH, wWHD; // must(!) be static |
162 |
|
|
|
163 |
|
|
// swaccum |
164 |
|
|
typedef unsigned char pix_t; |
165 |
|
|
typedef unsigned long acc_t; |
166 |
|
|
const int acc_scale = 1 << 24; |
167 |
|
|
pix_t *pixbuf = 0; // read pixel buffer |
168 |
|
|
acc_t *accumbuf = 0; // our accumbuf |
169 |
|
|
acc_t accsum; |
170 |
|
|
|
171 |
|
|
for (bool loop = true; loop; ) |
172 |
|
|
{ |
173 |
|
|
antialias = antialias || !buttondown; |
174 |
|
|
|
175 |
|
|
if (buttondown || !antialias || XPending (dpy)) |
176 |
|
|
do |
177 |
|
|
{ |
178 |
|
|
char buf[31]; |
179 |
|
|
KeySym keysym; |
180 |
|
|
|
181 |
|
|
XNextEvent (dpy, &event); |
182 |
|
|
switch (event.type) |
183 |
|
|
{ |
184 |
|
|
case Expose: |
185 |
|
|
break; |
186 |
|
|
|
187 |
|
|
case ConfigureNotify: |
188 |
|
|
{ |
189 |
|
|
/* this approach preserves a 1:1 viewport aspect ratio */ |
190 |
|
|
int eW = event.xconfigure.width, eH = event.xconfigure.height; |
191 |
|
|
|
192 |
|
|
eW = eW & ~3; // for alignment purposes |
193 |
|
|
|
194 |
|
|
if (eW != wW || eH != wH) |
195 |
|
|
{ |
196 |
|
|
changed = true; |
197 |
|
|
wW = eW; wH = eH; |
198 |
|
|
wWHD = wW * wH * fb_depth; |
199 |
|
|
|
200 |
|
|
if (eW >= eH) |
201 |
|
|
{ |
202 |
|
|
vX = 0; |
203 |
|
|
vY = (eH - eW) >> 1; |
204 |
|
|
vW = vH = eW; |
205 |
|
|
} |
206 |
|
|
else |
207 |
|
|
{ |
208 |
|
|
vX = (eW - eH) >> 1; |
209 |
|
|
vY = 0; |
210 |
|
|
vW = vH = eH; |
211 |
|
|
} |
212 |
|
|
|
213 |
|
|
glViewport (vX, vY, vW, vH); |
214 |
|
|
} |
215 |
|
|
} |
216 |
|
|
break; |
217 |
|
|
|
218 |
|
|
case KeyPress: |
219 |
|
|
(void) XLookupString (&event.xkey, buf, sizeof (buf), &keysym, NULL); |
220 |
|
|
switch (keysym) |
221 |
|
|
{ |
222 |
|
|
case XK_a: |
223 |
|
|
antialias = true; |
224 |
|
|
break; |
225 |
|
|
case XK_q: |
226 |
|
|
case XK_Escape: |
227 |
|
|
loop = false; |
228 |
|
|
break; |
229 |
|
|
default: |
230 |
|
|
break; |
231 |
|
|
} |
232 |
|
|
break; |
233 |
|
|
|
234 |
|
|
case ButtonPress: |
235 |
|
|
prevx = event.xbutton.x; |
236 |
|
|
prevy = event.xbutton.y; |
237 |
|
|
buttondown = true; |
238 |
|
|
break; |
239 |
|
|
|
240 |
|
|
case ButtonRelease: |
241 |
|
|
buttondown = false; |
242 |
|
|
break; |
243 |
|
|
|
244 |
|
|
case MotionNotify: |
245 |
|
|
deltax += (event.xbutton.x - prevx); |
246 |
|
|
prevx = event.xbutton.x; |
247 |
|
|
deltay += (event.xbutton.y - prevy); |
248 |
|
|
prevy = event.xbutton.y; |
249 |
|
|
changed = true; |
250 |
|
|
break; |
251 |
|
|
|
252 |
|
|
default: |
253 |
|
|
break; |
254 |
|
|
} |
255 |
|
|
} |
256 |
|
|
while (XPending (dpy)); |
257 |
|
|
|
258 |
|
|
if (changed || buttondown) |
259 |
|
|
{ |
260 |
|
|
changed = false; |
261 |
|
|
stepsize = 2; |
262 |
|
|
xoffset = 0; |
263 |
|
|
yoffset = 0; |
264 |
|
|
even = false; |
265 |
|
|
weight = 1; |
266 |
|
|
|
267 |
|
|
if (hwaccum) |
268 |
|
|
glClear(GL_ACCUM_BUFFER_BIT); |
269 |
|
|
else |
270 |
|
|
{ |
271 |
|
|
free (pixbuf); pixbuf = 0; |
272 |
|
|
free (accumbuf); accumbuf = 0; |
273 |
|
|
accsum = 0; |
274 |
|
|
} |
275 |
|
|
} |
276 |
|
|
|
277 |
|
|
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
278 |
|
|
|
279 |
|
|
glMatrixMode(GL_MODELVIEW); |
280 |
|
|
glPushMatrix (); |
281 |
|
|
|
282 |
|
|
glRotated ( deltax, 0, 1, 0); |
283 |
|
|
glRotated (-deltay, 1, 0, 1); |
284 |
|
|
|
285 |
|
|
double sc; |
286 |
|
|
|
287 |
|
|
sc = abs(4/(x2-x1)); |
288 |
|
|
if (abs (4/(y2-y1)) < sc) sc = abs(4/(y2-y1)); |
289 |
|
|
if (abs (4/(z2-z1)) < sc) sc = abs(4/(z2-z1)); |
290 |
|
|
glScaled (sc, sc, -sc); |
291 |
|
|
|
292 |
|
|
glTranslated (-0.5*(x2+x1),-0.5*(y2+y1), -0.5*(z1+z2)); |
293 |
|
|
|
294 |
|
|
glMatrixMode(GL_PROJECTION); |
295 |
|
|
glPushMatrix (); |
296 |
|
|
glTranslated (xoffset*10/vW, yoffset*10/vH, 0); |
297 |
|
|
|
298 |
|
|
glCallList (TREE_LIST); |
299 |
|
|
|
300 |
|
|
glPopMatrix (); |
301 |
|
|
glMatrixMode(GL_MODELVIEW); |
302 |
|
|
glPopMatrix (); |
303 |
|
|
|
304 |
|
|
if (buttondown || !antialias) |
305 |
|
|
{ |
306 |
|
|
glXSwapBuffers (dpy, win); |
307 |
|
|
continue; |
308 |
|
|
} |
309 |
|
|
|
310 |
|
|
if (hwaccum) |
311 |
|
|
glAccum (GL_ACCUM, weight); |
312 |
|
|
else |
313 |
|
|
{ |
314 |
|
|
if (!pixbuf ) pixbuf = (pix_t *) malloc (wWHD * sizeof (pix_t)); |
315 |
|
|
if (!accumbuf) accumbuf = (acc_t *) calloc (wWHD , sizeof (acc_t)); |
316 |
|
|
|
317 |
|
|
glReadPixels (0, 0, wW, wH, fb_format, GL_UNSIGNED_BYTE, pixbuf); |
318 |
|
|
|
319 |
|
|
acc_t scale[256]; // 256 == pix_t range |
320 |
|
|
for (int t = 0; t < 256; t++) |
321 |
|
|
scale[t] = acc_t (float (t) * acc_scale * weight); |
322 |
|
|
|
323 |
|
|
pix_t *p; |
324 |
|
|
acc_t *a; |
325 |
|
|
for (p = pixbuf, a = accumbuf; |
326 |
|
|
p < pixbuf + wWHD; |
327 |
|
|
p++, a++) |
328 |
|
|
*a += scale[*p]; |
329 |
|
|
} |
330 |
|
|
|
331 |
|
|
cout << setw(9) << stepsize << " " |
332 |
|
|
<< setw(9) << 1 - yoffset << "\r" << flush; |
333 |
|
|
|
334 |
|
|
xoffset += even ? stepsize*0.5 : stepsize; |
335 |
|
|
if (xoffset >= 1.0) |
336 |
|
|
{ |
337 |
|
|
yoffset += stepsize*0.5; |
338 |
|
|
if (yoffset >= 1.0) |
339 |
|
|
{ |
340 |
|
|
if (hwaccum) |
341 |
|
|
{ |
342 |
|
|
glAccum (GL_RETURN, 1.); |
343 |
|
|
glXSwapBuffers (dpy, win); |
344 |
|
|
glAccum (GL_MULT, 0.25); |
345 |
|
|
} |
346 |
|
|
else |
347 |
|
|
{ |
348 |
|
|
pix_t *p; |
349 |
|
|
acc_t *a; |
350 |
|
|
for (p = pixbuf, a = accumbuf; |
351 |
|
|
p < pixbuf + wWHD; |
352 |
|
|
p++, a++) |
353 |
|
|
{ |
354 |
|
|
*p = *a / acc_scale; |
355 |
|
|
*a /= 4; |
356 |
|
|
} |
357 |
|
|
|
358 |
|
|
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
359 |
|
|
|
360 |
|
|
glMatrixMode (GL_MODELVIEW); |
361 |
|
|
glPushMatrix (); |
362 |
|
|
glLoadIdentity (); |
363 |
|
|
glMatrixMode (GL_PROJECTION); |
364 |
|
|
glPushMatrix (); |
365 |
|
|
glLoadIdentity (); |
366 |
|
|
|
367 |
|
|
glRasterPos2f (float(-vX) / float(vW / 2) - 1, float(-vY) / float(vH / 2) - 1); |
368 |
|
|
glDrawPixels (wW, wH, fb_format, GL_UNSIGNED_BYTE, pixbuf); |
369 |
|
|
glPopMatrix (); |
370 |
|
|
|
371 |
|
|
glMatrixMode (GL_MODELVIEW); |
372 |
|
|
glPopMatrix (); |
373 |
|
|
|
374 |
|
|
glXSwapBuffers (dpy, win); |
375 |
|
|
|
376 |
|
|
accsum /= 4; |
377 |
|
|
} |
378 |
|
|
|
379 |
|
|
yoffset = 0; |
380 |
|
|
even = true; |
381 |
|
|
stepsize *= 0.5; |
382 |
|
|
weight *= 0.25; |
383 |
|
|
antialias = false; |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
even = !even; |
387 |
|
|
xoffset = even ? 0 : stepsize*0.5; |
388 |
|
|
} |
389 |
|
|
|
390 |
|
|
} |
391 |
|
|
|
392 |
|
|
free (pixbuf); |
393 |
|
|
free (accumbuf); |
394 |
|
|
|
395 |
|
|
glDeleteLists (TREE_LIST, 1); |
396 |
|
|
} |
397 |
|
|
|
398 |
|
|
void gl_int::clip (const vec &v) t_no |
399 |
|
|
{ |
400 |
|
|
if (x1 > v[0]) x1 = v[0]; |
401 |
|
|
if (y1 > v[1]) y1 = v[1]; |
402 |
|
|
if (z1 > v[2]) z1 = v[2]; |
403 |
|
|
|
404 |
|
|
if (x2 < v[0]) x2 = v[0]; |
405 |
|
|
if (y2 < v[1]) y2 = v[1]; |
406 |
|
|
if (z2 < v[2]) z2 = v[2]; |
407 |
|
|
} |
408 |
|
|
|
409 |
|
|
void gl_int::check_attrs (const attribute_set &attr) t_err |
410 |
|
|
{ |
411 |
|
|
vec v; |
412 |
|
|
|
413 |
|
|
if (!in_begin) |
414 |
|
|
glLineWidth (attr ("width",1)); |
415 |
|
|
|
416 |
|
|
v = attr("color", vec( 1, 1, 1)); |
417 |
|
|
float col[4]; |
418 |
|
|
col[0] = v[0]; |
419 |
|
|
col[1] = v[1]; |
420 |
|
|
col[2] = v[2]; |
421 |
|
|
col[3] = 1.0; |
422 |
|
|
glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col); |
423 |
|
|
} |
424 |
|
|
|
425 |
|
|
void gl_int::segment (const point &a, const point &b) t_err |
426 |
|
|
{ |
427 |
|
|
check_attrs (a.attr); |
428 |
|
|
|
429 |
|
|
Begin (GL_LINES); |
430 |
|
|
glNormal (vec (0, 0, 0)); |
431 |
|
|
glVertex (a.v); clip(a.v); |
432 |
|
|
glVertex (b.v); clip(b.v); |
433 |
|
|
End (); |
434 |
|
|
} |
435 |
|
|
|
436 |
|
|
void gl_int::object (const points &v) t_err |
437 |
|
|
{ |
438 |
|
|
// cerr << "polygon "; for (points::const_iterator j = v.begin (); j != v.end (); j++) cerr << j->first << " "; cerr << endl; |
439 |
|
|
if (v.size () < 3) |
440 |
|
|
return; |
441 |
|
|
|
442 |
|
|
glFrontFace (winding (v) > 0 ? GL_CCW : GL_CW); |
443 |
|
|
|
444 |
|
|
check_attrs (v.front ().attr); |
445 |
|
|
|
446 |
|
|
Begin (GL_POLYGON); |
447 |
|
|
for(points::const_iterator i = v.begin (); i != v.end(); ++i) |
448 |
|
|
{ |
449 |
|
|
check_attrs (i->attr); |
450 |
|
|
glNormal (i->n); |
451 |
|
|
glVertex (i->v); |
452 |
|
|
clip (i->v); |
453 |
|
|
} |
454 |
|
|
End (); |
455 |
|
|
|
456 |
|
|
double len; |
457 |
|
|
|
458 |
|
|
if ((len = v.front ().attr ("draw_normals", 0))) |
459 |
|
|
{ |
460 |
|
|
glNormal (vec (0, 0, 0)); |
461 |
|
|
|
462 |
|
|
Begin (GL_LINES); |
463 |
|
|
for(points::const_iterator i = v.begin (); i != v.end(); ++i) |
464 |
|
|
{ |
465 |
|
|
glVertex (i->v); |
466 |
|
|
glVertex (i->v + len * i->n); |
467 |
|
|
} |
468 |
|
|
End (); |
469 |
|
|
} |
470 |
|
|
} |
471 |
|
|
|
472 |
|
|
#endif |
473 |
|
|
|