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