1 //
2 // "$Id: context.cc,v 1.1 2003/02/06 09:37:53 jpr Exp $"
3 //
4 // GLPcontext class functions for the GLP library, an OpenGL printing
5 // toolkit.
6 //
7 // The GLP library is distributed under the terms of the GNU Library
8 // General Public License which is described in the file "COPYING.LIB".
9 // If you use this library in your program, please include a line reading
10 // "OpenGL Printing Toolkit by Michael Sweet" in your version or copyright
11 // output.
12 //
13 // Contents:
14 //
15 // ~GLPcontext, StartPage, UpdatePage, EndPage,
16 // add_primitive, sort_primitive, get_vertex, delete_all
17 //
18 // Revision History:
19 //
20 // $Log: context.cc,v $
21 // Revision 1.1 2003/02/06 09:37:53 jpr
22 // *** empty log message ***
23 //
24 // 2003/02/01 Juha Ruokolainen / CSC - IT Center for Science Ltd.
25 // Fixed some bugs in add_primitive. Changed the list of primitives
26 // to a binary tree of primitives. Sorting now works correctly.
27 // Added handling of GL_LINE_RESET_TOKEN, but the line patterns etc. are
28 // still silently ignored.
29 //
30 // Revision 1.2 1996/07/13 12:52:02 mike
31 // Fixed delete_all() - was not setting bboxes list pointer to NULL at end.
32 //
33 // Revision 1.1 1996/06/27 00:58:11 mike
34 // Initial revision
35 //
36
37 //
38 // Include necessary headers.
39 //
40
41 #include <../../config.h>
42
43 #include "glp.h"
44 #include <math.h>
45 #include <stdlib.h>
46 #ifdef HAVE_STRING_H
47 #include <string.h>
48 #endif
49
50 //#define DEBUG
51
52
53 #define min(a,b) ((a) < (b) ? (a) : (b))
54 #define max(a,b) ((a) > (b) ? (a) : (b))
55
56
57 //
58 // GLPcontext destructor; like the constructor, this just does the basics.
59 // You'll want to implement your own...
60 //
61
~GLPcontext(void)62 GLPcontext :: ~GLPcontext(void)
63 {
64 // Free any memory we've allocated...
65
66 delete_all();
67
68 // if (feedback != NULL)
69 // delete feedback;
70 // if (colormap != NULL)
71 // delete colormap;
72 }
73
74
75 //
76 // 'StartPage' function for RGBA windows; this should perform any necessary
77 // output initialization (e.g. send 'start of page' commands, etc) and enable
78 // feedback mode...
79 //
80
81 int
StartPage(int mode)82 GLPcontext :: StartPage(int mode)
83 {
84 // Initialize feedback mode...
85
86 feedmode = mode;
87
88 #ifdef DEBUG
89 cout << "RGBA feedmode = " << mode << "\n" << flush;
90 #endif /* DEBUG */
91
92 glFeedbackBuffer(feedsize, GL_3D_COLOR, feedback);
93 glRenderMode(GL_FEEDBACK);
94
95 // You'd put any other 'start page' things here...
96
97 return (0);
98 }
99
100
101 //
102 // 'StartPage' function for color index windows; this does the same thing as
103 // the RGBA start page function, and also copies the given colormap into our
104 // class colormap structure for later use...
105 //
106
107 int
StartPage(int mode,int size,GLPrgba * rgba)108 GLPcontext :: StartPage(int mode,
109 int size,
110 GLPrgba *rgba)
111 {
112 // Initialize feedback mode...
113
114 feedmode = mode;
115
116 #ifdef DEBUG
117 cout << "Index feedmode = " << mode << "\n" << flush;
118 #endif /* DEBUG */
119
120 glFeedbackBuffer(feedsize, GL_3D_COLOR, feedback);
121 glRenderMode(GL_FEEDBACK);
122
123 // Copy the colormap over, removing the old one as necessary...
124
125 if (colormap != NULL)
126 delete colormap;
127
128 colorsize = size;
129 colormap = new GLPrgba[size];
130 memcpy(colormap, rgba, size * sizeof(GLPrgba));
131
132 // You'd put any other 'start page' things here...
133
134 return (0);
135 }
136
137
138 //
139 // 'UpdatePage' function; this does most of the dirty work, adding feedback
140 // data to the current primitive list.
141 //
142 // If the 'more' argument is TRUE then the current rendering mode is put back
143 // into 'GL_FEEDBACK' mode...
144 //
145 // Normally you won't redefine this function...
146 //
147 #include <stdio.h>
148
149 int
UpdatePage(GLboolean more)150 GLPcontext :: UpdatePage(GLboolean more)
151 {
152 int i, used, count, v;
153 GLfloat *current;
154 GLPvertex vertices[3];
155 GLboolean depth,
156 shade;
157 GLint shademodel;
158
159
160 #ifdef DEBUG
161 cout << "UpdatePage(" << (more ? "GL_TRUE" : "GL_FALSE") << ")\n" << flush;
162 #endif /* DEBUG */
163
164 // Get the current depth test state and shade model...
165
166 depth = glIsEnabled(GL_DEPTH_TEST);
167 glGetIntegerv(GL_SHADE_MODEL, &shademodel);
168 shade = shademodel == GL_SMOOTH;
169
170 // Figure out how many feedback entries there are and put the current
171 // OpenGL context back in feedback mode if 'more' is true...
172
173 used = glRenderMode(more ? GL_FEEDBACK : GL_RENDER);
174 fprintf( stderr, "yseD: %d\n", used );
175 if (used <= 0) return (GLP_NO_FEEDBACK);
176
177 #ifdef DEBUG
178 cout << "glGetError() after glRenderMode returned " << glGetError() << "\n" << flush;
179 cout << "First: used = " << used << ", feedback[0] = " << feedback[0] << "\n" << flush;
180 #endif /* DEBUG */
181
182 // Parse the feedback buffer...
183
184 current = feedback;
185 while (used > 0)
186 {
187 #ifdef DEBUG
188 cout << "Loop: used = " << used << "\n" << flush;
189 #endif /* DEBUG */
190
191 switch ((int)*current)
192 {
193 case GL_POINT_TOKEN :
194 current ++;
195 used --;
196 i = get_vertex(vertices + 0, current);
197 current += i;
198 used -= i;
199 add_primitive(depth, shade, 1, vertices);
200 break;
201 case GL_LINE_TOKEN: case GL_LINE_RESET_TOKEN:
202 current ++;
203 used --;
204 i = get_vertex(vertices + 0, current);
205 current += i;
206 used -= i;
207 i = get_vertex(vertices + 1, current);
208 current += i;
209 used -= i;
210 add_primitive(depth, shade, 2, vertices);
211 break;
212
213 case GL_POLYGON_TOKEN :
214 // Get the number of vertices...
215
216 count = (int)current[1];
217
218 current += 2;
219 used -= 2;
220
221 // Loop through and add a series of triangles...
222
223 v = 0;
224 while (count > 0 && used > 0)
225 {
226 i = get_vertex( vertices + v, current );
227 current += i;
228 used -= i;
229 count --;
230
231 // Add a triangle if we have 3 vertices...
232
233 if (v == 2)
234 {
235 add_primitive( depth, shade, 3, vertices );
236 vertices[1] = vertices[2];
237 v = 0;
238 }
239 else
240 v++;
241 };
242 break;
243
244 case GL_BITMAP_TOKEN :
245 case GL_DRAW_PIXEL_TOKEN :
246 case GL_COPY_PIXEL_TOKEN :
247 current ++;
248 used --;
249 i = get_vertex(vertices + 0, current);
250 current += i;
251 used -= i;
252 break;
253
254 case GL_PASS_THROUGH_TOKEN :
255 #ifdef DEBUG
256 std::cout << "UpdatePage: Ignoring passthrough token " << current[1] << "...\n" << std::flush;
257 #endif /* DEBUG */
258 current += 2;
259 used -= 2;
260 break;
261
262 default :
263 std::cout << "UpdatePage: Ignoring unknown token " << current[0] << "...\n" << std::flush;
264 current ++;
265 used --;
266 break;
267 };
268 };
269
270 return (GLP_SUCCESS);
271 }
272
273
274 //
275 // 'EndPage' function; this does nothing except parse the bounding boxes
276 // and output any remaining primitives. It then frees the bounding box
277 // and primitive lists...
278 //
279
280 int
EndPage(void)281 GLPcontext :: EndPage(void)
282 {
283 GLPbbox *bbox; // Current bounding box
284 GLPprimitive *prim; // Current primitive
285
286
287 #ifdef DEBUG
288 cout << "EndPage()\n" << flush;
289 #endif /* DEBUG */
290
291 // Stop doing feedback...
292
293 UpdatePage(GL_FALSE);
294
295 if (bboxes == NULL) return (GLP_NO_FEEDBACK);
296
297 // Loop through all bounding boxes and primitives...
298 for (bbox = bboxes; bbox != NULL; bbox = bbox->next)
299 {
300 };
301
302 // Delete everything from the bounding box and primitive lists...
303
304 delete_all();
305
306 #ifdef DEBUG
307 cout << "EndPage() - done.\n" << flush;
308 #endif /* DEBUG */
309
310 return (GLP_SUCCESS);
311 }
312
313
314 //
315 // 'SetOptions' function; this just sets the 'options' member to whatever is
316 // passed in.
317 //
318
319 void
SetOptions(int print_options)320 GLPcontext :: SetOptions(int print_options) // I - New printing options
321 {
322 options = print_options;
323 }
324
325
326 //
327 // 'add_primitive' function; add a primitive to the list of primitives and
328 // bounding boxes for the current context.
329 //
330
331 void
add_primitive(GLboolean depth,GLboolean shade,int num_verts,GLPvertex * verts)332 GLPcontext :: add_primitive(GLboolean depth, // I - Depth testing enabled?
333 GLboolean shade, // I - Smooth shading?
334 int num_verts,// I - Number of vertices
335 GLPvertex *verts) // I - Vertices
336 {
337 int i, // Looping var
338 count; // Count of intersections
339 GLfloat min[3], // Minimum (x,y) coords
340 max[3]; // Maximum (x,y) coords
341 GLPprimitive *newprim,*pprim,*ppprim; // New primitive
342 GLPbbox *bbox, // Current bounding box
343 *joinbbox, // Bounding box to join with
344 *nextbbox; // Next bounding box...
345
346
347 #ifdef DEBUG
348 cout << "add_primitive(" << (depth ? "GL_TRUE" : "GL_FALSE") << ", "
349 << (shade ? "GL_TRUE" : "GL_FALSE") << ", "
350 << num_verts << ", "
351 << (int)verts << ")\n" << flush;
352 #endif /* DEBUG */
353
354 // First create the new primitive and compute the bounding box for it...
355
356 newprim = new GLPprimitive;
357
358 newprim->left = NULL;
359 newprim->right = NULL;
360 newprim->shade = shade;
361 newprim->num_verts = num_verts;
362 memcpy( newprim->verts, verts, sizeof(GLPvertex) * num_verts );
363
364 min[0] = min[1] = min[2] = 1e20;
365 max[0] = max[1] = max[2] = -1e20;
366
367 for (i = 0; i < num_verts; i ++)
368 {
369 if ( verts[i].xyz[0] < min[0] ) min[0] = verts[i].xyz[0];
370 if ( verts[i].xyz[1] < min[1] ) min[1] = verts[i].xyz[1];
371 if ( verts[i].xyz[2] < min[2] ) min[2] = verts[i].xyz[2];
372
373 if ( verts[i].xyz[0] > max[0] ) max[0] = verts[i].xyz[0];
374 if ( verts[i].xyz[1] > max[1] ) max[1] = verts[i].xyz[1];
375 if ( verts[i].xyz[2] > max[2] ) max[2] = verts[i].xyz[2];
376 };
377
378 newprim->zmin = min[2];
379 newprim->zmax = max[2];
380
381 // Stretch the bbox out to the nearest 64 pixels to improve performance...
382 min[0] = floor( min[0] * 0.015625 ) * 64.0;
383 min[1] = floor( min[1] * 0.015625 ) * 64.0;
384 max[0] = ceil( max[0] * 0.015625 ) * 64.0;
385 max[1] = ceil( max[1] * 0.015625 ) * 64.0;
386
387 // Now search the current bounding box list to see if this primitive lies
388 // inside an existing bbox, partially inside, or completely outside...
389 //
390 // The 'count' variable counts the number of corners that lie inside the
391 // current bounding box. If 'count' is 0, then the bbox is completely
392 // outside the current bbox. Values between 1 and 3 indicate a partially
393 // inside primitive. A value of 4 means that the primitive is completely
394 // inside the bbox.
395 //
396 // If the primitive lies completely outside any bboxes that are out there
397 // already, then a new bbox is created with the primitive in it.
398 //
399 // If the primitive lies partially inside the bbox, the bbox is expanded to
400 // include the primitive, and a 'join' operation is performed with any
401 // neighboring bboxes that intersect with the expanded bbox. Finall, the
402 // primitive is added to the bbox using the 'sort_primitive()' function
403 // (this handles depth buffering if enabled).
404 //
405 // If the primitive lies completely inside the bbox, it is added with
406 // 'sort_primitive()'.
407
408 for (bbox = bboxes; bbox != NULL; bbox = bbox->next)
409 {
410 count = 0;
411
412 if ( min[0] > bbox->min[0] && min[0] < bbox->max[0] ) count++;
413 if ( max[0] > bbox->min[0] && max[0] < bbox->max[0] ) count++;
414 if ( min[1] > bbox->min[1] && min[1] < bbox->max[1] ) count++;
415 if ( max[1] > bbox->min[1] && max[1] < bbox->max[1] ) count++;
416
417 if ( count > 0 ) break;
418 };
419
420 if (bbox == NULL)
421 {
422 // New bbox...
423
424 bbox = new GLPbbox;
425
426 bbox->prev = NULL;
427 bbox->next = bboxes;
428 if (bboxes != NULL) bboxes->prev = bbox;
429 bboxes = bbox;
430
431 bbox->min[0] = min[0];
432 bbox->max[0] = max[0];
433 bbox->min[1] = min[1];
434 bbox->max[1] = max[1];
435 bbox->min[2] = min[2];
436 bbox->max[2] = max[2];
437 bbox->primitives = newprim;
438 bbox->lastprim = newprim;
439 }
440 else if (count < 4)
441 {
442 // Partially inside...
443
444 if ( min[0] < bbox->min[0] ) bbox->min[0] = min[0];
445 if ( max[0] > bbox->max[0] ) bbox->max[0] = max[0];
446 if ( min[1] < bbox->min[1] ) bbox->min[1] = min[1];
447 if ( max[1] > bbox->max[1] ) bbox->max[1] = max[1];
448
449 // Incrementally join bounding boxes until no more boxes are joined...
450
451 do
452 {
453 count = 0;
454 for (joinbbox = bboxes; joinbbox != NULL; joinbbox = nextbbox)
455 {
456 nextbbox = joinbbox->next;
457
458 if (joinbbox == bbox)
459 continue;
460 else if (( bbox->min[0] > joinbbox->min[0] && bbox->min[0] < joinbbox->max[0]) ||
461 ( bbox->max[0] > joinbbox->min[0] && bbox->max[0] < joinbbox->max[0]) ||
462 ( bbox->min[1] > joinbbox->min[1] && bbox->min[1] < joinbbox->max[1]) ||
463 ( bbox->max[1] > joinbbox->min[1] && bbox->max[1] < joinbbox->max[1]))
464 {
465 // Join this one...
466
467 count++;
468
469 if (joinbbox->prev == NULL)
470 bboxes = joinbbox->next;
471 else
472 (joinbbox->prev)->next = joinbbox->next;
473
474 if (nextbbox != NULL)
475 nextbbox->prev = joinbbox->prev;
476
477 for (i = 0; i < 3; i ++)
478 {
479 if ( joinbbox->min[i] < bbox->min[i] ) bbox->min[i] = joinbbox->min[i];
480 if ( joinbbox->max[i] > bbox->max[i] ) bbox->max[i] = joinbbox->max[i];
481 };
482
483 add_subtree( &bbox->primitives, joinbbox->primitives );
484 delete joinbbox;
485 };
486 };
487 }
488 while (count > 0);
489
490 // Add the primitive to this bbox...
491
492 add_tree( &bbox->primitives, newprim);
493 }
494 else
495 {
496 // Primitive lies completely inside the bbox, so just add it...
497 add_tree( &bbox->primitives, newprim);
498 };
499 }
500
501
502 //
503 // 'get_vertex' function; get a vertex from the feedback buffer...
504 //
505
506 int
get_vertex(GLPvertex * v,GLfloat * p)507 GLPcontext :: get_vertex(GLPvertex *v, // O - Vertex pointer
508 GLfloat *p) // I - Data pointer
509 {
510 int i; // Color index
511
512
513 v->xyz[0] = p[0];
514 v->xyz[1] = p[1];
515 v->xyz[2] = p[2];
516
517 #ifdef DEBUG
518 cout << "{ " << p[0] << ", " << p[1] << ", " << p[2] << "}, " << flush;
519 #endif /* DEBUG */
520
521 if (feedmode == GL_COLOR_INDEX && colorsize > 0)
522 {
523 // Color index value...
524 i = (int)(p[3] + 0.5);
525
526 v->rgba[0] = colormap[i][0];
527 v->rgba[1] = colormap[i][1];
528 v->rgba[2] = colormap[i][2];
529 v->rgba[3] = colormap[i][3];
530
531 return (4);
532 }
533 else
534 {
535 // RGBA value...
536
537 v->rgba[0] = p[3];
538 v->rgba[1] = p[4];
539 v->rgba[2] = p[5];
540 v->rgba[3] = p[6];
541
542 return (7);
543 };
544 }
545
546
547 //
548 // 'delete_all' function; delete all bounding boxes and primitives from
549 // the current context.
550 //
551
delete_tree(GLPprimitive * tree)552 void GLPcontext :: delete_tree( GLPprimitive *tree )
553 {
554 if ( !tree ) return;
555 delete_tree( tree->left );
556 delete_tree( tree->right );
557 delete tree;
558 }
559
560 void
delete_all(void)561 GLPcontext :: delete_all(void)
562 {
563 GLPbbox *bbox, // Current bounding box
564 *nextbbox; // Next bounding box
565 GLPprimitive *prim, // Current primitive
566 *nextprim; // Next primitive
567
568
569 #ifdef DEBUG
570 cout << "delete_all()\n" << flush;
571 #endif /* DEBUG */
572
573 for (bbox = bboxes, nextbbox = NULL; bbox != NULL; bbox = nextbbox)
574 {
575 delete_tree( bbox->primitives );
576 nextbbox = bbox->next;
577 delete bbox;
578 };
579
580 bboxes = NULL;
581
582 delete_tree( tree );
583 tree = NULL;
584
585 #ifdef DEBUG
586 cout << "delete_all(): done.\n" << flush;
587 #endif /* DEBUG */
588 }
589
590
add_subtree(GLPprimitive ** ptree,GLPprimitive * prim)591 void GLPcontext::add_subtree( GLPprimitive **ptree, GLPprimitive *prim )
592 {
593 GLPprimitive *left, *right;
594
595 if ( !prim ) return;
596
597 left = prim->left;
598 right = prim->right;
599
600 prim->left = NULL;
601 prim->right = NULL;
602 add_tree( ptree, prim );
603
604 add_subtree( ptree, left );
605 add_subtree( ptree, right );
606 }
607
add_tree(GLPprimitive ** ptree,GLPprimitive * prim)608 void GLPcontext::add_tree( GLPprimitive **ptree, GLPprimitive *prim )
609 {
610 static int count=0;
611 if ( !*ptree )
612 {
613 *ptree = prim;
614 } else {
615 if ( (prim->zmin+prim->zmax) == ((*ptree)->zmin+(*ptree)->zmax) )
616 {
617 if ( count++ ) {
618 prim->right = (*ptree)->left;
619 (*ptree)->left = prim;
620 count = 0;
621 } else {
622 prim->left = (*ptree)->right;
623 (*ptree)->right = prim;
624 }
625 } else if ( (prim->zmin+prim->zmax) > ((*ptree)->zmin+(*ptree)->zmax) )
626 {
627 if ( (*ptree)->left )
628 add_tree( &(*ptree)->left, prim );
629 else
630 (*ptree)->left = prim;
631 } else {
632 if ( (*ptree)->right )
633 add_tree( &(*ptree)->right, prim );
634 else
635 (*ptree)->right = prim;
636 }
637 }
638 }
639
640 //
641 // End of "$Id: context.cc,v 1.1 2003/02/06 09:37:53 jpr Exp $".
642 //
643