source: trunk/source/visualization/externals/gl2ps/src/gl2ps.cc @ 930

Last change on this file since 930 was 930, checked in by garnier, 15 years ago

rien de special, juste un backup avant de commiter sur cvs

  • Property svn:mime-type set to text/cpp
File size: 69.1 KB
Line 
1//
2// ********************************************************************
3// * License and Disclaimer                                           *
4// *                                                                  *
5// * The  Geant4 software  is  copyright of the Copyright Holders  of *
6// * the Geant4 Collaboration.  It is provided  under  the terms  and *
7// * conditions of the Geant4 Software License,  included in the file *
8// * LICENSE and available at  http://cern.ch/geant4/license .  These *
9// * include a list of copyright holders.                             *
10// *                                                                  *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work  make  any representation or  warranty, express or implied, *
14// * regarding  this  software system or assume any liability for its *
15// * use.  Please see the license in the file  LICENSE  and URL above *
16// * for the full disclaimer and the limitation of liability.         *
17// *                                                                  *
18// * This  code  implementation is the result of  the  scientific and *
19// * technical work of the GEANT4 collaboration.                      *
20// * By using,  copying,  modifying or  distributing the software (or *
21// * any work based  on the software)  you  agree  to acknowledge its *
22// * use  in  resulting  scientific  publications,  and indicate your *
23// * acceptance of all terms of the Geant4 Software license.          *
24// ********************************************************************
25//
26#ifdef G4VIS_BUILD_OPENGL_DRIVER
27 #define G4VIS_BUILD_OPENGL_GL2PS
28#endif
29#ifdef G4VIS_BUILD_OI_DRIVER
30 #define G4VIS_BUILD_OPENGL_GL2PS
31#endif
32
33#ifdef G4VIS_BUILD_OPENGL_GL2PS
34
35/*
36 * GL2PS, an OpenGL to PostScript Printing Library
37 * Copyright (C) 1999-2003  Christophe Geuzaine
38 *
39 * $Id: gl2ps.cc,v 1.1 2009/02/18 09:54:12 lgarnier Exp $
40 *
41 * E-mail: geuz@geuz.org
42 * URL: http://www.geuz.org/gl2ps/
43 *
44 * This library is free software; you can redistribute it and/or
45 * modify it under the terms of the GNU Library General Public
46 * License as published by the Free Software Foundation; either
47 * version 2 of the License, or (at your option) any later version.
48 *
49 * This library is distributed in the hope that it will be useful,
50 * but WITHOUT ANY WARRANTY; without even the implied warranty of
51 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
52 * Library General Public License for more details.
53 *
54 * You should have received a copy of the GNU Library General Public
55 * License along with this library; if not, write to the Free
56 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
57 *
58 */
59
60#include <string.h>
61#include <sys/types.h>
62#include <stdarg.h>
63#include <time.h>
64#include "Geant4_gl2ps.h"
65
66/* The gl2ps context. gl2ps is not thread safe (we should create a
67   local GL2PScontext during gl2psBeginPage). */
68
69GL2PScontext *gl2ps = NULL;
70
71/* Some 'system' utility routines */
72
73void gl2psMsg(GLint level, const char *fmt, ...){
74  va_list args;
75
76  if(!(gl2ps->options & GL2PS_SILENT)){
77    switch(level){
78    case GL2PS_INFO : fprintf(stderr, "GL2PS info: "); break;
79    case GL2PS_WARNING : fprintf(stderr, "GL2PS warning: "); break;
80    case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break;
81    }
82    va_start(args, fmt);
83    vfprintf(stderr, fmt, args);
84    va_end(args);
85    fprintf(stderr, "\n");
86  }
87  /*
88    if(level == GL2PS_ERROR) exit(1);
89  */
90}
91
92void *gl2psMalloc(size_t size){
93  void *ptr;
94
95  if(!size) return(NULL);
96  ptr = malloc(size);
97  if(!ptr){
98    gl2psMsg(GL2PS_ERROR, "Couldn't allocate requested memory");
99    exit(1);
100  }
101  return(ptr);
102}
103
104void *gl2psRealloc(void *ptr, size_t size){
105  if(!size) return(NULL);
106  ptr = realloc(ptr, size);
107  if(!ptr){
108    gl2psMsg(GL2PS_ERROR, "Couldn't reallocate requested memory");
109    exit(1);
110  }
111  return(ptr);
112}
113
114void gl2psFree(void *ptr){
115  if(!ptr) return;
116  free(ptr);
117}
118
119/* The list handling routines */
120
121void gl2psListRealloc(GL2PSlist *list, GLint n){
122  if(n <= 0) return;
123  if(!list->array){
124    list->nmax = ((n - 1) / list->incr + 1) * list->incr;
125    list->array = (char *)gl2psMalloc(list->nmax * list->size);
126  }
127  else{
128    if(n > list->nmax){
129      list->nmax = ((n - 1) / list->incr + 1) * list->incr;
130      list->array = (char *)gl2psRealloc(list->array,
131                                         list->nmax * list->size);
132    }
133  }
134}
135
136GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size){
137  GL2PSlist *list;
138
139  if(n < 0) n = 0;
140  if(incr <= 0) incr = 1;
141  list = (GL2PSlist *)gl2psMalloc(sizeof(GL2PSlist));
142  list->nmax = 0;
143  list->incr = incr;
144  list->size = size;
145  list->n = 0;
146  list->array = NULL;
147  gl2psListRealloc(list, n);
148  return(list);
149}
150
151void gl2psListReset(GL2PSlist *list){
152  list->n = 0;
153}
154
155void gl2psListDelete(GL2PSlist *list){
156  gl2psFree(list->array);
157  gl2psFree(list);
158}
159
160void gl2psListAdd(GL2PSlist *list, void *data){
161  list->n++;
162  gl2psListRealloc(list, list->n);
163  memcpy(&list->array[(list->n - 1) * list->size], data, list->size);
164}
165
166GLint gl2psListNbr(GL2PSlist *list){
167  return(list->n);
168}
169
170void *gl2psListPointer(GL2PSlist *list, GLint index){
171  if((index < 0) || (index >= list->n)){
172    gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListPointer");
173    return(&list->array[0]);
174  }
175  return(&list->array[index * list->size]);
176}
177
178void gl2psListSort(GL2PSlist *list,
179                   int (*fcmp)(const void *a, const void *b)){
180  qsort(list->array, list->n, list->size, fcmp);
181}
182
183void gl2psListAction(GL2PSlist *list,
184                     void (*action)(void *data, void *dummy)){
185  GLint i, dummy;
186
187  for(i = 0; i < gl2psListNbr(list); i++){
188    (*action)(gl2psListPointer(list, i), &dummy);
189  }
190}
191
192void gl2psListActionInverse(GL2PSlist *list,
193                            void (*action)(void *data, void *dummy)){
194  GLint i, dummy;
195
196  for(i = gl2psListNbr(list); i > 0; i--){
197    (*action)(gl2psListPointer(list, i-1), &dummy);
198  }
199}
200
201/* The 3D sorting routines */
202
203GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane){
204  return(plane[0] * point[0] +
205         plane[1] * point[1] +
206         plane[2] * point[2] +
207         plane[3]);
208}
209
210GLfloat gl2psPsca(GLfloat *a, GLfloat *b){
211  return(a[0]*b[0] + a[1]*b[1] + a[2]*b[2]);
212}
213
214void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c){
215  c[0] = a[1]*b[2] - a[2]*b[1];
216  c[1] = a[2]*b[0] - a[0]*b[2];
217  c[2] = a[0]*b[1] - a[1]*b[0];
218}
219
220GLfloat gl2psNorm(GLfloat *a){
221  return std::sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]);
222}
223
224void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c){
225  GLfloat norm;
226
227  gl2psPvec(a, b, c);
228  if(!GL2PS_ZERO(norm = gl2psNorm(c))){
229    c[0] = c[0] / norm;
230    c[1] = c[1] / norm;
231    c[2] = c[2] / norm;
232  }
233  else{
234    /* The plane is still wrong, despite our tests in
235       gl2psGetPlane... Let's return a dummy value (this is a hack: we
236       should do more tests in GetPlane): */
237    c[0] = c[1] = 0.;
238    c[2] = 1.;
239  }
240}
241
242void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane){
243  GL2PSxyz v = {0., 0., 0.}, w = {0., 0., 0.};
244
245  switch(prim->type){
246  case GL2PS_TRIANGLE :
247  case GL2PS_QUADRANGLE :
248    v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0];
249    v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1];
250    v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2];
251    w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0];
252    w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1];
253    w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2];
254    if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) ||
255       (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){
256      plane[0] = plane[1] = 0.;
257      plane[2] = 1.;
258      plane[3] = -prim->verts[0].xyz[2];
259    }
260    else{
261      gl2psGetNormal(v, w, plane);
262      plane[3] =
263        - plane[0] * prim->verts[0].xyz[0]
264        - plane[1] * prim->verts[0].xyz[1]
265        - plane[2] * prim->verts[0].xyz[2];
266    }
267    break;
268  case GL2PS_LINE :
269    v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0];
270    v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1];
271    v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2];
272    if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){
273      plane[0] = plane[1] = 0.;
274      plane[2] = 1.;
275      plane[3] = -prim->verts[0].xyz[2];
276    }
277    else{
278      if(GL2PS_ZERO(v[0]))      w[0] = 1.;
279      else if(GL2PS_ZERO(v[1])) w[1] = 1.;
280      else                      w[2] = 1.;
281      gl2psGetNormal(v, w, plane);
282      plane[3] =
283        - plane[0] * prim->verts[0].xyz[0]
284        - plane[1] * prim->verts[0].xyz[1]
285        - plane[2] * prim->verts[0].xyz[2];
286    }
287    break;
288  case GL2PS_POINT :
289  case GL2PS_PIXMAP :
290  case GL2PS_TEXT :
291    plane[0] = plane[1] = 0.;
292    plane[2] = 1.;
293    plane[3] = -prim->verts[0].xyz[2];
294    break;
295  default :
296    gl2psMsg(GL2PS_ERROR, "Unknown primitive type in BSP tree");
297    plane[0] = plane[1] = plane[3] = 0.;
298    plane[2] = 1.;
299    break;
300  }
301}
302
303void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane,
304                  GL2PSvertex *c){
305  GL2PSxyz v;
306  GLfloat sect;
307
308  v[0] = b->xyz[0] - a->xyz[0];
309  v[1] = b->xyz[1] - a->xyz[1];
310  v[2] = b->xyz[2] - a->xyz[2];
311  sect = - gl2psComparePointPlane(a->xyz, plane) / gl2psPsca(plane, v);
312
313  c->xyz[0] = a->xyz[0] + v[0] * sect;
314  c->xyz[1] = a->xyz[1] + v[1] * sect;
315  c->xyz[2] = a->xyz[2] + v[2] * sect;
316 
317  c->rgba[0] = (1.-sect) * a->rgba[0] + sect * b->rgba[0];
318  c->rgba[1] = (1.-sect) * a->rgba[1] + sect * b->rgba[1];
319  c->rgba[2] = (1.-sect) * a->rgba[2] + sect * b->rgba[2];
320  c->rgba[3] = (1.-sect) * a->rgba[3] + sect * b->rgba[3];
321}
322
323void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane,
324                               GL2PSprimitive *child, GLshort numverts,
325                               GLshort *index0, GLshort *index1){
326  GLshort i;
327
328  if(numverts > 4){
329    gl2psMsg(GL2PS_WARNING, "%d vertices in polygon", numverts);
330    numverts = 4;
331  }
332
333  switch(numverts){
334  case 1 : child->type = GL2PS_POINT; break;
335  case 2 : child->type = GL2PS_LINE; break;
336  case 3 : child->type = GL2PS_TRIANGLE; break;
337  case 4 : child->type = GL2PS_QUADRANGLE; break;   
338  }
339  child->boundary = 0; /* not done! */
340  child->depth = parent->depth; /* should not be used in this case */
341  child->culled = parent->culled;
342  child->dash = parent->dash;
343  child->width = parent->width;
344  child->numverts = numverts;
345  child->verts = (GL2PSvertex *)gl2psMalloc(numverts * sizeof(GL2PSvertex));
346
347  for(i = 0; i < numverts; i++){
348    if(index1[i] < 0){
349      child->verts[i] = parent->verts[index0[i]];
350    }
351    else{
352      gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]],
353                   plane, &child->verts[i]);
354    }
355  }
356}
357
358void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb,
359                   GLshort i, GLshort j){
360  GLint k;
361
362  for(k = 0; k < *nb; k++){
363    if((index0[k] == i && index1[k] == j) ||
364       (index1[k] == i && index0[k] == j)) return;
365  }
366  index0[*nb] = i;
367  index1[*nb] = j;
368  (*nb)++;
369}
370
371GLshort gl2psGetIndex(GLshort i, GLshort num){
372  return(i < num-1) ? i+1 : 0;
373}
374
375GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane){
376  GLint type = GL2PS_COINCIDENT;
377  GLshort i, j;
378  GLfloat d[5];
379
380  for(i = 0; i < prim->numverts; i++){ 
381    d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane);
382  }
383
384  if(prim->numverts < 2){
385    return 0;
386  }
387  else{
388    for(i = 0; i < prim->numverts; i++){
389      j = gl2psGetIndex(i, prim->numverts);
390      if(d[j] > GL2PS_EPSILON){
391        if(type == GL2PS_COINCIDENT)      type = GL2PS_IN_BACK_OF;
392        else if(type != GL2PS_IN_BACK_OF) return 1;
393        if(d[i] < -GL2PS_EPSILON)         return 1;
394      }
395      else if(d[j] < -GL2PS_EPSILON){
396        if(type == GL2PS_COINCIDENT)       type = GL2PS_IN_FRONT_OF;   
397        else if(type != GL2PS_IN_FRONT_OF) return 1;
398        if(d[i] > GL2PS_EPSILON)           return 1;
399      }
400    }
401  }
402  return 0;
403}
404
405GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane,
406                          GL2PSprimitive **front, GL2PSprimitive **back){
407  GLshort i, j, in=0, out=0, in0[5], in1[5], out0[5], out1[5];
408  GLint type;
409  GLfloat d[5];
410
411  type = GL2PS_COINCIDENT;
412
413  for(i = 0; i < prim->numverts; i++){ 
414    d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane);
415  }
416
417  switch(prim->type){
418  case GL2PS_POINT :
419    if(d[0] > GL2PS_EPSILON)       type = GL2PS_IN_BACK_OF;
420    else if(d[0] < -GL2PS_EPSILON) type = GL2PS_IN_FRONT_OF;
421    else                           type = GL2PS_COINCIDENT;
422    break;
423  default :
424    for(i = 0; i < prim->numverts; i++){
425      j = gl2psGetIndex(i, prim->numverts);
426      if(d[j] > GL2PS_EPSILON){
427        if(type == GL2PS_COINCIDENT)      type = GL2PS_IN_BACK_OF;
428        else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING;
429        if(d[i] < -GL2PS_EPSILON){
430          gl2psAddIndex(in0, in1, &in, i, j);
431          gl2psAddIndex(out0, out1, &out, i, j);
432          type = GL2PS_SPANNING;
433        }
434        gl2psAddIndex(out0, out1, &out, j, -1);
435      }
436      else if(d[j] < -GL2PS_EPSILON){
437        if(type == GL2PS_COINCIDENT)       type = GL2PS_IN_FRONT_OF;   
438        else if(type != GL2PS_IN_FRONT_OF) type = GL2PS_SPANNING;
439        if(d[i] > GL2PS_EPSILON){
440          gl2psAddIndex(in0, in1, &in, i, j);
441          gl2psAddIndex(out0, out1, &out, i, j);
442          type = GL2PS_SPANNING;
443        }
444        gl2psAddIndex(in0, in1, &in, j, -1);
445      }
446      else{
447        gl2psAddIndex(in0, in1, &in, j, -1);
448        gl2psAddIndex(out0, out1, &out, j, -1);
449      }
450    }
451    break;
452  }
453
454  if(type == GL2PS_SPANNING){
455    *back = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
456    *front = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
457    gl2psCreateSplitPrimitive(prim, plane, *back, out, out0, out1);
458    gl2psCreateSplitPrimitive(prim, plane, *front, in, in0, in1);
459  }
460
461  return type;
462}
463
464void gl2psDivideQuad(GL2PSprimitive *quad,
465                     GL2PSprimitive **t1, GL2PSprimitive **t2){
466  *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
467  *t2 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
468  (*t1)->type = (*t2)->type = GL2PS_TRIANGLE;
469  (*t1)->numverts = (*t2)->numverts = 3;
470  (*t1)->depth = (*t2)->depth = quad->depth;
471  (*t1)->culled = (*t2)->culled = quad->culled;
472  (*t1)->dash = (*t2)->dash = quad->dash;
473  (*t1)->width = (*t2)->width = quad->width;
474  (*t1)->verts = (GL2PSvertex *)gl2psMalloc(3 * sizeof(GL2PSvertex));
475  (*t2)->verts = (GL2PSvertex *)gl2psMalloc(3 * sizeof(GL2PSvertex));
476  (*t1)->verts[0] = quad->verts[0];
477  (*t1)->verts[1] = quad->verts[1];
478  (*t1)->verts[2] = quad->verts[2];
479  (*t1)->boundary = ((quad->boundary & 1) ? 1 : 0) | ((quad->boundary & 2) ? 2 : 0);
480  (*t2)->verts[0] = quad->verts[0];
481  (*t2)->verts[1] = quad->verts[2];
482  (*t2)->verts[2] = quad->verts[3];
483  (*t1)->boundary = ((quad->boundary & 4) ? 2 : 0) | ((quad->boundary & 4) ? 2 : 0);
484}
485
486int gl2psCompareDepth(const void *a, const void *b){
487  GL2PSprimitive *q, *w;
488  GLfloat diff;
489
490  q = *(GL2PSprimitive**)a;
491  w = *(GL2PSprimitive**)b;
492  diff = q->depth - w->depth;
493  if(diff > 0.){
494    return 1;
495  }
496  else if(diff < 0.){
497    return -1;
498  }
499  else{
500    return 0;
501  }
502}
503
504int gl2psTrianglesFirst(const void *a, const void *b){
505  GL2PSprimitive *q, *w;
506
507  q = *(GL2PSprimitive**)a;
508  w = *(GL2PSprimitive**)b;
509  return(q->type < w->type ? 1 : -1);
510}
511
512GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root){
513  GLint i, j, count, best = 1000000, index = 0;
514  GL2PSprimitive *prim1, *prim2;
515  GL2PSplane plane;
516  GLint maxp;
517
518  if(gl2ps->options & GL2PS_BEST_ROOT){
519    *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0);
520    maxp = gl2psListNbr(primitives);
521    if(maxp > gl2ps->maxbestroot){
522      maxp = gl2ps->maxbestroot;
523    }
524    for(i = 0; i < maxp; i++){
525      prim1 = *(GL2PSprimitive**)gl2psListPointer(primitives, i);
526      gl2psGetPlane(prim1, plane);
527      count = 0;
528      for(j = 0; j < gl2psListNbr(primitives); j++){
529        if(j != i){
530          prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j);
531          count += gl2psTestSplitPrimitive(prim2, plane);
532        }
533        if(count > best) break;
534      }
535      if(count < best){
536        best = count;
537        index = i;
538        *root = prim1;
539        if(!count) return index;
540      }
541    }
542    /* if(index) gl2psMsg(GL2PS_INFO, "GL2PS_BEST_ROOT was worth it: %d", index); */
543    return index;
544  }
545  else{
546    *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0);
547    return 0;
548  }
549}
550
551void gl2psFreePrimitive(void *a, void *){
552  GL2PSprimitive *q;
553 
554  q = *(GL2PSprimitive**)a;
555  gl2psFree(q->verts);
556  if(q->type == GL2PS_TEXT){
557    gl2psFree(q->text->str);
558    gl2psFree(q->text->fontname);
559    gl2psFree(q->text);
560  }
561  if(q->type == GL2PS_PIXMAP){
562    gl2psFree(q->image->pixels);
563    gl2psFree(q->image);
564  }
565  gl2psFree(q);
566}
567
568void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list){
569  GL2PSprimitive *t1, *t2;
570
571  if(prim->type != GL2PS_QUADRANGLE){
572    gl2psListAdd(list, &prim);
573  }
574  else{
575    gl2psDivideQuad(prim, &t1, &t2);
576    gl2psListAdd(list, &t1);
577    gl2psListAdd(list, &t2);
578    gl2psFreePrimitive(&prim, NULL);
579  }
580 
581}
582
583void gl2psFreeBspTree(GL2PSbsptree **tree){
584  if(*tree){
585    if((*tree)->back) gl2psFreeBspTree(&(*tree)->back);
586    if((*tree)->primitives){
587      gl2psListAction((*tree)->primitives, gl2psFreePrimitive);
588      gl2psListDelete((*tree)->primitives);
589    }
590    if((*tree)->front) gl2psFreeBspTree(&(*tree)->front);
591    gl2psFree(*tree);
592    *tree = NULL;
593  }
594}
595
596GLboolean gl2psGreater(GLfloat f1, GLfloat f2){
597  if(f1 > f2) return 1;
598  else return 0;
599}
600
601GLboolean gl2psLess(GLfloat f1, GLfloat f2){
602  if(f1 < f2) return 1;
603  else return 0;
604}
605
606void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives){
607  GL2PSprimitive *prim, *frontprim, *backprim;
608  GL2PSlist *frontlist, *backlist;
609  GLint i, index;
610
611  tree->front = NULL;
612  tree->back = NULL;
613  tree->primitives = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
614  index = gl2psFindRoot(primitives, &prim);
615  gl2psGetPlane(prim, tree->plane);
616  gl2psAddPrimitiveInList(prim, tree->primitives);
617
618  frontlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
619  backlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*));
620
621  for(i = 0; i < gl2psListNbr(primitives); i++){
622    if(i != index){
623      prim = *(GL2PSprimitive**)gl2psListPointer(primitives,i);
624      switch(gl2psSplitPrimitive(prim, tree->plane, &frontprim, &backprim)){
625      case GL2PS_COINCIDENT:
626        gl2psAddPrimitiveInList(prim, tree->primitives);
627        break;
628      case GL2PS_IN_BACK_OF:
629        gl2psAddPrimitiveInList(prim, backlist);
630        break;
631      case GL2PS_IN_FRONT_OF:
632        gl2psAddPrimitiveInList(prim, frontlist);
633        break;
634      case GL2PS_SPANNING:
635        gl2psAddPrimitiveInList(backprim, backlist);
636        gl2psAddPrimitiveInList(frontprim, frontlist);
637        gl2psFreePrimitive(&prim, NULL);
638        break;
639      }
640    }
641  }
642
643  if(gl2psListNbr(tree->primitives)){
644    gl2psListSort(tree->primitives, gl2psTrianglesFirst);
645  }
646
647  if(gl2psListNbr(frontlist)){
648    gl2psListSort(frontlist, gl2psTrianglesFirst);
649    tree->front = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
650    gl2psBuildBspTree(tree->front, frontlist);
651  }
652  else{
653    gl2psListDelete(frontlist);
654  }
655
656  if(gl2psListNbr(backlist)){
657    gl2psListSort(backlist, gl2psTrianglesFirst);
658    tree->back = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
659    gl2psBuildBspTree(tree->back, backlist);
660  }
661  else{
662    gl2psListDelete(backlist);
663  }
664
665  gl2psListDelete(primitives);
666}
667
668void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon,
669                          GLboolean (*compare)(GLfloat f1, GLfloat f2),
670                          void (*action)(void *data, void *dummy)){
671  GLfloat result;
672
673  if(!tree) return;
674
675  result = gl2psComparePointPlane(eye, tree->plane);
676
677  if(compare(result, epsilon)){
678    gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action);
679    gl2psListAction(tree->primitives, action);
680    gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action);
681  }
682  else if(compare(-epsilon, result)){
683    gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action);
684    gl2psListAction(tree->primitives, action);
685    gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action);
686  }
687  else{
688    gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action);
689    gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action);
690  }
691}
692
693/* The 2D sorting routines (for occlusion culling) */
694
695GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane){ 
696  GLfloat n;
697
698  plane[0] = b[1] - a[1];
699  plane[1] = a[0] - b[0];
700  n = std::sqrt(plane[0]*plane[0] + plane[1]*plane[1]);
701  plane[2]=0.;
702  if(n != 0.){
703    plane[0] /= n;
704    plane[1] /= n;
705    plane[3] = -plane[0]*a[0]-plane[1]*a[1];
706    return 1;
707  }
708  else{
709    plane[0] = -1.0;
710    plane[1] = 0.;
711    plane[3] = a[0];
712    return 0;
713  }
714}
715
716void gl2psFreeBspImageTree(GL2PSbsptree2d **tree){
717  if(*tree){
718    if((*tree)->back)  gl2psFreeBspImageTree(&(*tree)->back);
719    if((*tree)->front) gl2psFreeBspImageTree(&(*tree)->front);
720    gl2psFree(*tree);
721    *tree = NULL;
722  }
723}
724
725GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane){
726  GLfloat pt_dis;
727
728  pt_dis = gl2psComparePointPlane(point, plane);
729  if(pt_dis > GL2PS_EPSILON)        return GL2PS_POINT_INFRONT;
730  else if(pt_dis < -GL2PS_EPSILON)  return GL2PS_POINT_BACK;
731  else                              return GL2PS_POINT_COINCIDENT;
732}
733
734void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim,
735                                  GL2PSbsptree2d **tree){
736  GLint ret = 0;
737  GLint i;
738  GLint offset = 0;
739  GL2PSbsptree2d *head = NULL, *cur = NULL;
740
741  if((*tree == NULL) && (prim->numverts > 2)){
742    head = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
743    for(i = 0; i < prim->numverts-1; i++){
744      if(!gl2psGetPlaneFromPoints(prim->verts[i].xyz,
745                                  prim->verts[i+1].xyz,
746                                  head->plane)){
747        if(prim->numverts-i > 3){
748          offset++;
749        }
750        else{
751          gl2psFree(head);
752          return;
753        }
754      }
755      else{
756        break;
757      }
758    }
759    head->back = NULL;
760    head->front = NULL;
761    for(i = 2+offset; i < prim->numverts; i++){
762      ret = gl2psCheckPoint(prim->verts[i].xyz, head->plane);
763      if(ret != GL2PS_POINT_COINCIDENT) break;
764    }
765    switch(ret){
766    case GL2PS_POINT_INFRONT :
767      cur = head;
768      for(i = 1+offset; i < prim->numverts-1; i++){
769        if(cur->front == NULL){
770          cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
771        }
772        if(gl2psGetPlaneFromPoints(prim->verts[i].xyz,
773                                   prim->verts[i+1].xyz,
774                                   cur->front->plane)){
775          cur = cur->front;
776          cur->front = NULL;
777          cur->back = NULL;
778        }
779      }
780      if(cur->front == NULL){
781        cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
782      }
783      if(gl2psGetPlaneFromPoints(prim->verts[i].xyz,
784                                 prim->verts[offset].xyz,
785                                 cur->front->plane)){
786        cur->front->front = NULL;
787        cur->front->back = NULL;
788      }
789      else{
790        gl2psFree(cur->front);
791        cur->front = NULL;
792      }
793      break;
794    case GL2PS_POINT_BACK :
795      for(i = 0; i < 4; i++){
796        head->plane[i] = -head->plane[i];
797      }
798      cur = head;
799      for(i = 1+offset; i < prim->numverts-1; i++){
800        if(cur->front == NULL){
801          cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
802        }
803        if(gl2psGetPlaneFromPoints(prim->verts[i+1].xyz,
804                                   prim->verts[i].xyz,
805                                   cur->front->plane)){
806          cur = cur->front;
807          cur->front = NULL;
808          cur->back = NULL;
809        }
810      }
811      if(cur->front == NULL){
812        cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d));
813      }
814      if(gl2psGetPlaneFromPoints(prim->verts[offset].xyz,
815                                 prim->verts[i].xyz,
816                                 cur->front->plane)){
817        cur->front->front = NULL;
818        cur->front->back = NULL;
819      }
820      else{
821        gl2psFree(cur->front);
822        cur->front = NULL;
823      }
824      break;
825    default:
826      gl2psFree(head);
827      return;
828    }
829    (*tree) = head;
830  }
831}
832
833GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane){
834  GLint i;
835  GLint pos;
836
837  pos = gl2psCheckPoint(prim->verts[0].xyz, plane);
838  for(i = 1; i < prim->numverts; i++){
839    pos |= gl2psCheckPoint(prim->verts[i].xyz, plane);
840    if(pos == (GL2PS_POINT_INFRONT | GL2PS_POINT_BACK)) return GL2PS_SPANNING;
841  }
842  if(pos & GL2PS_POINT_INFRONT)   return GL2PS_IN_FRONT_OF;
843  else if(pos & GL2PS_POINT_BACK) return GL2PS_IN_BACK_OF;
844  else                            return GL2PS_COINCIDENT;
845}
846
847GL2PSprimitive* gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent,
848                                            GLshort numverts,
849                                            GL2PSvertex *vertx){
850  GLint i;
851  GL2PSprimitive *child = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
852
853  switch(numverts){
854  case 1 : child->type = GL2PS_POINT; break;
855  case 2 : child->type = GL2PS_LINE; break;
856  case 3 : child->type = GL2PS_TRIANGLE; break;
857  case 4 : child->type = GL2PS_QUADRANGLE; break;
858  }
859  child->boundary = 0; /* not done! */
860  child->depth = parent->depth;
861  child->culled = parent->culled;
862  child->dash = parent->dash;
863  child->width = parent->width;
864  child->numverts = numverts;
865  child->verts = (GL2PSvertex *)gl2psMalloc(numverts * sizeof(GL2PSvertex));
866  for(i = 0; i < numverts; i++){
867    child->verts[i] = vertx[i];
868  }
869  return child;
870}
871
872void gl2psSplitPrimitive2D(GL2PSprimitive *prim,
873                           GL2PSplane plane,
874                           GL2PSprimitive **front,
875                           GL2PSprimitive **back){
876
877  /* cur will hold the position of current vertex
878     prev will holds the position of previous vertex
879     prev0 will holds the position of vertex number 0
880     v1 and v2 represent the current and previous vertexs respectively
881     flag will represents that should the current be checked against the plane */
882  GLint cur = -1, prev = -1, i, v1 = 0, v2 = 0, flag = 1, prev0 = -1;
883 
884  /* list of vertexs which will go in front and back Primitive */
885  GL2PSvertex *front_list = NULL, *back_list = NULL;
886 
887  /* number of vertex in front and back list */
888  GLint front_count = 0, back_count = 0;
889
890  for(i = 0; i <= prim->numverts; i++){
891    v1 = i;
892    if(v1 == prim->numverts){
893      if(prim->numverts < 3) break;
894      v1 = 0;
895      v2 = prim->numverts-1;
896      cur = prev0;
897    }
898    else if(flag){
899      cur = gl2psCheckPoint(prim->verts[v1].xyz, plane);
900      if(i == 0){
901        prev0 = cur;
902      }
903    }
904    if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) &&
905       (i < prim->numverts)){
906      if(cur == GL2PS_POINT_INFRONT){
907        front_count++;
908        front_list = (GL2PSvertex*)gl2psRealloc(front_list,
909                                                sizeof(GL2PSvertex)*front_count);
910        front_list[front_count-1] = prim->verts[v1];
911      }
912      else if(cur == GL2PS_POINT_BACK){
913        back_count++;
914        back_list = (GL2PSvertex*)gl2psRealloc(back_list,
915                                               sizeof(GL2PSvertex)*back_count);
916        back_list[back_count-1] = prim->verts[v1];
917      }
918      else{
919        front_count++;
920        front_list = (GL2PSvertex*)gl2psRealloc(front_list,
921                                                sizeof(GL2PSvertex)*front_count);
922        front_list[front_count-1] = prim->verts[v1];
923        back_count++;
924        back_list = (GL2PSvertex*)gl2psRealloc(back_list,
925                                               sizeof(GL2PSvertex)*back_count);
926        back_list[back_count-1] = prim->verts[v1];
927      }
928      flag = 1;
929    }
930    else if((prev != cur) && (cur != 0) && (prev != 0)){
931      if(v1 != 0){
932        v2 = v1-1;
933        i--;
934      }
935      front_count++;
936      front_list = (GL2PSvertex*)gl2psRealloc(front_list,
937                                              sizeof(GL2PSvertex)*front_count);
938      gl2psCutEdge(&prim->verts[v2],
939                   &prim->verts[v1],
940                   plane,
941                   &front_list[front_count-1]);
942      back_count++;
943      back_list = (GL2PSvertex*)gl2psRealloc(back_list,
944                                             sizeof(GL2PSvertex)*back_count);
945      back_list[back_count-1] = front_list[front_count-1];
946      flag = 0;
947    }
948    prev = cur;
949  }
950  *front = gl2psCreateSplitPrimitive2D(prim, front_count, front_list);
951  *back = gl2psCreateSplitPrimitive2D(prim, back_count, back_list);
952  gl2psFree(front_list);
953  gl2psFree(back_list);
954}
955
956GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree){
957  GLint ret = 0;
958  GL2PSprimitive *frontprim = NULL, *backprim = NULL;
959
960  if(*tree == NULL){
961    gl2psAddPlanesInBspTreeImage(prim, tree);
962    return 1;
963  }
964  else{
965    switch(gl2psCheckPrimitive(prim, (*tree)->plane)){
966    case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back);
967    case GL2PS_IN_FRONT_OF:
968      if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front);
969      else                       return 0;
970    case GL2PS_SPANNING:
971      gl2psSplitPrimitive2D(prim, (*tree)->plane, &frontprim, &backprim);
972      ret = gl2psAddInBspImageTree(backprim, &(*tree)->back);
973      if((*tree)->front != NULL){
974        if(gl2psAddInBspImageTree(frontprim, &(*tree)->front)){
975          ret = 1;
976        }
977      }
978      gl2psFree(frontprim->verts);
979      gl2psFree(frontprim);
980      gl2psFree(backprim->verts);
981      gl2psFree(backprim);
982      return ret;
983    case GL2PS_COINCIDENT:
984      if(prim->numverts < 3) return 1;
985      else                   return 0;
986    }
987  }
988  return 0;
989}
990
991void gl2psAddInImageTree(void *a, void *){
992  GL2PSprimitive *prim = *(GL2PSprimitive **)a;
993
994  if(!gl2psAddInBspImageTree(prim, &gl2ps->imagetree)){
995    prim->culled = 1;
996  }
997}
998
999/* Boundary contruction */
1000
1001void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list){
1002  GL2PSprimitive *b;
1003  GLshort i;
1004  GL2PSxyz c;
1005
1006  c[0] = c[1] = c[2] = 0.;
1007  for(i = 0; i < prim->numverts; i++){
1008    c[0] += prim->verts[i].xyz[0];
1009    c[1] += prim->verts[i].xyz[1];
1010  }
1011  c[0] /= prim->numverts;
1012  c[1] /= prim->numverts;
1013
1014  for(i = 0; i < prim->numverts; i++){
1015    if(prim->boundary & (GLint)pow(2., i)){
1016      b = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive));
1017      b->type = GL2PS_LINE;
1018      b->dash = prim->dash;
1019      b->depth = prim->depth; /* this is wrong */
1020      b->culled = prim->culled;
1021      b->width = prim->width;
1022      b->boundary = 0;
1023      b->numverts = 2;
1024      b->verts = (GL2PSvertex *)gl2psMalloc(2 * sizeof(GL2PSvertex));
1025
1026#if 0 /* need to work on boundary offset... */
1027      v[0] = c[0] - prim->verts[i].xyz[0];
1028      v[1] = c[1] - prim->verts[i].xyz[1];
1029      v[2] = 0.;
1030      norm = gl2psNorm(v);
1031      v[0] /= norm;
1032      v[1] /= norm;
1033      b->verts[0].xyz[0] = prim->verts[i].xyz[0] +0.1*v[0];
1034      b->verts[0].xyz[1] = prim->verts[i].xyz[1] +0.1*v[1];
1035      b->verts[0].xyz[2] = prim->verts[i].xyz[2];
1036      v[0] = c[0] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0];
1037      v[1] = c[1] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1];
1038      norm = gl2psNorm(v);
1039      v[0] /= norm;
1040      v[1] /= norm;
1041      b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0] +0.1*v[0];
1042      b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1] +0.1*v[1];
1043      b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2];
1044#else
1045      b->verts[0].xyz[0] = prim->verts[i].xyz[0];
1046      b->verts[0].xyz[1] = prim->verts[i].xyz[1];
1047      b->verts[0].xyz[2] = prim->verts[i].xyz[2];
1048      b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0];
1049      b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1];
1050      b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2];
1051#endif
1052
1053      b->verts[0].rgba[0] = 0.;
1054      b->verts[0].rgba[1] = 0.;
1055      b->verts[0].rgba[2] = 0.;
1056      b->verts[0].rgba[3] = 0.;
1057      b->verts[1].rgba[0] = 0.;
1058      b->verts[1].rgba[1] = 0.;
1059      b->verts[1].rgba[2] = 0.;
1060      b->verts[1].rgba[3] = 0.;
1061      gl2psListAdd(list, &b);
1062    }
1063  }
1064
1065}
1066
1067void gl2psBuildPolygonBoundary(GL2PSbsptree *tree){
1068  GLint i, n;
1069  GL2PSprimitive *prim;
1070
1071  if(!tree) return;
1072  gl2psBuildPolygonBoundary(tree->back);
1073  n = gl2psListNbr(tree->primitives);
1074  for(i = 0; i < n; i++){
1075    prim = *(GL2PSprimitive**)gl2psListPointer(tree->primitives, i);
1076    if(prim->boundary) gl2psAddBoundaryInList(prim, tree->primitives);
1077  }
1078  gl2psBuildPolygonBoundary(tree->front);
1079}
1080
1081/* The feedback buffer parser */
1082
1083void gl2psAddPolyPrimitive(GLshort type, GLshort numverts,
1084                           GL2PSvertex *verts, GLint offset,
1085                           char dash, GLfloat width,
1086                           char boundary){
1087  GLshort i;
1088  GLfloat factor, units, area, dZ, dZdX, dZdY, maxdZ;
1089  GL2PSprimitive *prim;
1090
1091  prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive));
1092  prim->type = type;
1093  prim->numverts = numverts;
1094  prim->verts = (GL2PSvertex *)gl2psMalloc(numverts * sizeof(GL2PSvertex));
1095  memcpy(prim->verts, verts, numverts * sizeof(GL2PSvertex));
1096  prim->boundary = boundary;
1097  prim->dash = dash;
1098  prim->width = width;
1099  prim->culled = 0;
1100
1101  if(gl2ps->options & GL2PS_SIMPLE_LINE_OFFSET){
1102
1103    if(type == GL2PS_LINE){
1104      if(gl2ps->sort == GL2PS_SIMPLE_SORT){
1105        prim->verts[0].xyz[2] -= GL2PS_SIMPLE_OFFSET_LARGE;
1106        prim->verts[1].xyz[2] -= GL2PS_SIMPLE_OFFSET_LARGE;
1107      }
1108      else{
1109        prim->verts[0].xyz[2] -= GL2PS_SIMPLE_OFFSET;
1110        prim->verts[1].xyz[2] -= GL2PS_SIMPLE_OFFSET;
1111      }
1112    }
1113
1114  }
1115  else if(offset && type == GL2PS_TRIANGLE){
1116
1117    /* This needs some more work... */
1118
1119    if(gl2ps->sort == GL2PS_SIMPLE_SORT){   
1120      factor = gl2ps->offset[0];
1121      units = gl2ps->offset[1];
1122    }
1123    else{
1124      factor = gl2ps->offset[0] / 800.;
1125      units = gl2ps->offset[1] / 800.;
1126    }
1127
1128    area =
1129      (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) *
1130      (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) -
1131      (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) *
1132      (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]);
1133    dZdX =
1134      (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) *
1135      (prim->verts[1].xyz[2] - prim->verts[0].xyz[2]) -
1136      (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]) *
1137      (prim->verts[2].xyz[2] - prim->verts[1].xyz[2]) / area;
1138    dZdY =
1139      (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) *
1140      (prim->verts[2].xyz[2] - prim->verts[1].xyz[2]) -
1141      (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) *
1142      (prim->verts[1].xyz[2] - prim->verts[0].xyz[2]) / area;
1143   
1144    maxdZ = std::sqrt(dZdX*dZdX + dZdY*dZdY);
1145
1146    dZ = factor * maxdZ + units;
1147
1148    prim->verts[0].xyz[2] += dZ;
1149    prim->verts[1].xyz[2] += dZ;
1150    prim->verts[2].xyz[2] += dZ;
1151  }
1152
1153  prim->depth = 0.;
1154  if(gl2ps->sort == GL2PS_SIMPLE_SORT){
1155    for(i = 0; i < numverts; i++){
1156      prim->depth += prim->verts[i].xyz[2];
1157    }
1158    prim->depth /= (GLfloat)numverts;
1159  }
1160 
1161  gl2psListAdd(gl2ps->primitives, &prim);
1162}
1163
1164GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p){
1165  GLint i;
1166
1167  v->xyz[0] = p[0];
1168  v->xyz[1] = p[1];
1169  v->xyz[2] = GL2PS_DEPTH_FACT * p[2];
1170
1171  if(gl2ps->colormode == GL_COLOR_INDEX && gl2ps->colorsize > 0){
1172    i = (GLint)(p[3] + 0.5);
1173    v->rgba[0] = gl2ps->colormap[i][0];
1174    v->rgba[1] = gl2ps->colormap[i][1];
1175    v->rgba[2] = gl2ps->colormap[i][2];
1176    v->rgba[3] = gl2ps->colormap[i][3];
1177    return 4;
1178  }
1179  else{
1180    v->rgba[0] = p[3];
1181    v->rgba[1] = p[4];
1182    v->rgba[2] = p[5];
1183    v->rgba[3] = p[6];
1184    return 7;
1185  }
1186}
1187
1188GLint gl2psParseFeedbackBuffer(void){
1189  char flag, dash = 0;
1190  GLshort boundary;
1191  GLint i, used, count, v, vtot, offset = 0;
1192  GLfloat lwidth = 1., psize = 1.;
1193  GLfloat *current;
1194  GL2PSvertex vertices[3];
1195
1196  used = glRenderMode(GL_RENDER);
1197
1198  if(used < 0){
1199    gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow");
1200    return GL2PS_OVERFLOW;
1201  }
1202
1203  if(used == 0){
1204    /* gl2psMsg(GL2PS_INFO, "Empty feedback buffer"); */
1205    return GL2PS_NO_FEEDBACK;
1206  }
1207
1208  current = gl2ps->feedback;
1209  boundary = gl2ps->boundary = 0;
1210
1211  while(used > 0){
1212
1213    if(boundary) gl2ps->boundary = 1;
1214   
1215    switch((GLint)*current){
1216    case GL_POINT_TOKEN :
1217      current ++;
1218      used --;
1219      i = gl2psGetVertex(&vertices[0], current);
1220      current += i;
1221      used    -= i;
1222      gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, dash, psize, 0);
1223      break;
1224    case GL_LINE_TOKEN :
1225    case GL_LINE_RESET_TOKEN :
1226      current ++;
1227      used --;
1228      i = gl2psGetVertex(&vertices[0], current);
1229      current += i;
1230      used    -= i;
1231      i = gl2psGetVertex(&vertices[1], current);
1232      current += i;
1233      used    -= i;
1234      gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, dash, lwidth, 0);
1235      break;
1236    case GL_POLYGON_TOKEN :
1237      count = (GLint)current[1];
1238      current += 2;
1239      used -= 2;
1240      v = vtot = 0;
1241      while(count > 0 && used > 0){
1242        i = gl2psGetVertex(&vertices[v], current);
1243        current += i;
1244        used    -= i;
1245        count --;
1246        vtot++;
1247        if(v == 2){
1248          if(boundary){
1249            if(!count && vtot == 2) flag = 1|2|4;
1250            else if(!count) flag = 2|4;
1251            else if(vtot == 2) flag = 1|2;
1252            else flag = 2;
1253          }
1254          else
1255            flag = 0;
1256          gl2psAddPolyPrimitive(GL2PS_TRIANGLE, 3, vertices,
1257                                offset, dash, 1, flag);
1258          vertices[1] = vertices[2];
1259        }
1260        else
1261          v ++;
1262      }
1263      break;     
1264    case GL_BITMAP_TOKEN :
1265    case GL_DRAW_PIXEL_TOKEN :
1266    case GL_COPY_PIXEL_TOKEN :
1267      current ++;
1268      used --;
1269      i = gl2psGetVertex(&vertices[0], current);
1270      current += i;
1271      used    -= i;
1272      break;     
1273    case GL_PASS_THROUGH_TOKEN :
1274      switch((GLint)current[1]){
1275      case GL2PS_BEGIN_POLYGON_OFFSET_FILL : offset = 1; break;
1276      case GL2PS_END_POLYGON_OFFSET_FILL : offset = 0; break;
1277      case GL2PS_BEGIN_POLYGON_BOUNDARY : boundary = 1; break;
1278      case GL2PS_END_POLYGON_BOUNDARY : boundary = 0; break;
1279      case GL2PS_BEGIN_LINE_STIPPLE : dash = 4; break;
1280      case GL2PS_END_LINE_STIPPLE : dash = 0; break;
1281      case GL2PS_SET_POINT_SIZE :
1282        current += 2;
1283        used -= 2;
1284        psize = current[1];
1285        break;
1286      case GL2PS_SET_LINE_WIDTH :
1287        current += 2;
1288        used -= 2;
1289        lwidth = current[1];
1290        break;
1291      }
1292      current += 2;
1293      used -= 2;
1294      break;     
1295    default :
1296      gl2psMsg(GL2PS_WARNING, "Unknown token in buffer");
1297      current ++;
1298      used --;
1299      break;
1300    }
1301  }
1302 
1303  return GL2PS_SUCCESS;
1304}
1305
1306GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2){
1307  return !(rgba1[0] != rgba2[0] ||
1308           rgba1[1] != rgba2[1] ||
1309           rgba1[2] != rgba2[2]);
1310}
1311 
1312GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim){
1313  int i;
1314
1315  for(i = 1; i < prim->numverts; i++){
1316    if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){
1317      return 0;
1318    }
1319  }
1320  return 1;
1321}
1322
1323GLint gl2psPrintPrimitives(void);
1324
1325/* The PostScript routines. Other (vector) image formats should be
1326   easy to generate by creating the three corresponding routines
1327   (gl2psPrintXXXHeader, gl2psPrintXXXPrimitive, gl2psPrintXXXFooter,
1328   gl2psPrintXXXBeginViewport and gl2psPrintXXXEndViewport) for the
1329   new format. */
1330
1331void gl2psWriteByte(FILE *stream, unsigned char byte){
1332  unsigned char h = byte / 16;
1333  unsigned char l = byte % 16;
1334  fprintf(stream, "%x%x", h, l);
1335}
1336
1337int gl2psGetRGB(GLfloat *pixels, GLsizei width, GLsizei height, GLuint x, GLuint y,
1338                GLfloat *red, GLfloat *green, GLfloat *blue){
1339  /* OpenGL image is from down to up, PS image is up to down */
1340  GLfloat *pimag;
1341  pimag = pixels + 3 * (width * (height - 1 - y) + x);
1342  *red   = *pimag; pimag++;
1343  *green = *pimag; pimag++;
1344  *blue  = *pimag; pimag++;
1345  return 1;
1346}
1347
1348void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GLsizei width, GLsizei height,
1349                                GLenum, GLenum, GLfloat *pixels,
1350                                FILE *stream){
1351  typedef unsigned char Uchar;
1352  int status = 1, nbhex, nbyte;
1353  int row, col, ibyte,icase;
1354  float dr = 0, dg = 0, db = 0, fgrey = 0;
1355  Uchar red, green, blue, b, grey;
1356  /* Options */
1357  int shade = 0;
1358  //int nbit = 2;
1359  int nbit = 4;
1360  //int nbit = 8;
1361
1362  if((width <= 0) || (height <= 0)) return;
1363
1364  /* Msg(INFO, "gl2psPrintPostScriptPixmap: x %g y %g w %d h %d", x, y, width, height); */
1365
1366  fprintf(stream, "gsave\n");
1367  fprintf(stream, "%.2f %.2f translate\n", x, y);
1368  fprintf(stream, "%d %d scale\n", width, height);
1369
1370  if(shade != 0){ /* grey */
1371    fprintf(stream, "/picstr %d string def\n", width);
1372    fprintf(stream, "%d %d %d\n", width, height, 8);
1373    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", width, height, height);
1374    fprintf(stream, "{ currentfile picstr readhexstring pop }\n");
1375    fprintf(stream, "image\n");
1376    for(row = 0; row < height; row++){
1377      for(col = 0; col < width; col++){
1378        status = gl2psGetRGB(pixels, width, height,
1379                             col, row, &dr, &dg, &db) == 0 ? 0 : status;
1380        fgrey = (0.30 * dr + 0.59 * dg + 0.11 * db);
1381        grey = (Uchar)(255. * fgrey);
1382        gl2psWriteByte(stream, grey);
1383      }
1384      fprintf(stream, "\n");
1385    }
1386    nbhex = width * height * 2;
1387    fprintf(stream, "%%%% nbhex digit          :%d\n", nbhex);
1388  }
1389  else if(nbit == 2){
1390    int nrgb = width  * 3;
1391    int nbits = nrgb * nbit;
1392    nbyte = nbits/8;
1393    if((nbyte*8)!=nbits) nbyte++;
1394    /* 2 bit for r and g and b */
1395    /* rgbs following each other */
1396    fprintf(stream, "/rgbstr %d string def\n", nbyte);
1397    fprintf(stream, "%d %d %d\n", width, height, nbit);
1398    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", width, height, height);
1399    fprintf(stream, "{ currentfile rgbstr readhexstring pop }\n" );
1400    fprintf(stream, "false 3\n" );
1401    fprintf(stream, "colorimage\n" );   
1402    for(row = 0; row < height; row++){
1403      icase = 1;
1404      col = 0;
1405      b = 0;
1406      for(ibyte = 0; ibyte < nbyte; ibyte++){
1407        if(icase==1) {
1408          if(col<width) {
1409            status = gl2psGetRGB(pixels, width, height,
1410                             col, row, &dr, &dg, &db) == 0 ? 0 : status;
1411          } else {
1412            dr = dg = db = 0;
1413          }
1414          col++;
1415          red = (Uchar)(3. * dr);
1416          green = (Uchar)(3. * dg);
1417          blue = (Uchar)(3. * db);
1418          b = red;
1419          b = (b<<2)+green;
1420          b = (b<<2)+blue;
1421          if(col<width) {
1422            status = gl2psGetRGB(pixels, width, height,
1423                             col, row, &dr, &dg, &db) == 0 ? 0 : status;
1424          } else {
1425            dr = dg = db = 0;
1426          }
1427          col++;
1428          red = (Uchar)(3. * dr);
1429          green = (Uchar)(3. * dg);
1430          blue = (Uchar)(3. * db);
1431          b = (b<<2)+red;
1432          gl2psWriteByte(stream, b);
1433          b = 0;
1434          icase++;
1435        } else if(icase==2) {
1436          b = green;
1437          b = (b<<2)+blue;
1438          if(col<width) {
1439            status = gl2psGetRGB(pixels, width, height,
1440                             col, row, &dr, &dg, &db) == 0 ? 0 : status;
1441          } else {
1442            dr = dg = db = 0;
1443          }
1444          col++;
1445          red = (Uchar)(3. * dr);
1446          green = (Uchar)(3. * dg);
1447          blue = (Uchar)(3. * db);
1448          b = (b<<2)+red;
1449          b = (b<<2)+green;
1450          gl2psWriteByte(stream, b);
1451          b = 0;
1452          icase++;
1453        } else if(icase==3) {
1454          b = blue;
1455          if(col<width) {
1456            status = gl2psGetRGB(pixels,width,height,
1457                             col, row, &dr, &dg, &db) == 0 ? 0 : status;
1458          } else {
1459            dr = dg = db = 0;
1460          }
1461          col++;
1462          red = (Uchar)(3. * dr);
1463          green = (Uchar)(3. * dg);
1464          blue = (Uchar)(3. * db);
1465          b = (b<<2)+red;
1466          b = (b<<2)+green;
1467          b = (b<<2)+blue;
1468          gl2psWriteByte(stream, b);
1469          b = 0;
1470          icase = 1;
1471        }
1472      }
1473      fprintf(stream, "\n");
1474    }
1475  }
1476  else if(nbit == 4){
1477    int nrgb = width  * 3;
1478    int nbits = nrgb * nbit;
1479    nbyte = nbits/8;
1480    if((nbyte*8)!=nbits) nbyte++;
1481    /* 4 bit for r and g and b */
1482    /* rgbs following each other */
1483    fprintf(stream, "/rgbstr %d string def\n", nbyte);
1484    fprintf(stream, "%d %d %d\n", width, height,nbit);
1485    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", width, height, height);
1486    fprintf(stream, "{ currentfile rgbstr readhexstring pop }\n");
1487    fprintf(stream, "false 3\n");
1488    fprintf(stream, "colorimage\n");
1489    for(row = 0; row < height; row++){
1490      col = 0;
1491      icase = 1;
1492      for(ibyte = 0; ibyte < nbyte; ibyte++){
1493        if(icase==1) {
1494          if(col<width) {
1495            status = gl2psGetRGB(pixels, width, height,
1496                             col, row, &dr, &dg, &db) == 0 ? 0 : status;
1497          } else {
1498            dr = dg = db = 0;
1499          }
1500          col++;
1501          red = (Uchar)(15. * dr);
1502          green = (Uchar)(15. * dg);
1503          fprintf(stream, "%x%x", red, green);
1504          icase++;
1505        } else if(icase==2) {
1506          blue = (Uchar)(15. * db);
1507          if(col<width) {
1508            status = gl2psGetRGB(pixels, width, height,
1509                             col, row, &dr, &dg, &db) == 0 ? 0 : status;
1510          } else {
1511            dr = dg = db = 0;
1512          }
1513          col++;
1514          red = (Uchar)(15. * dr);
1515          fprintf(stream,"%x%x",blue,red);
1516          icase++;
1517        } else if(icase==3) {
1518          green = (Uchar)(15. * dg);
1519          blue = (Uchar)(15. * db);
1520          fprintf(stream, "%x%x", green, blue);
1521          icase = 1;
1522        }
1523      }
1524      fprintf(stream, "\n");
1525    }
1526  }
1527  else{
1528    nbyte = width * 3;
1529    /* 8 bit for r and g and b */
1530    fprintf(stream, "/rgbstr %d string def\n", nbyte);
1531    fprintf(stream, "%d %d %d\n", width, height, 8);
1532    fprintf(stream, "[ %d 0 0 -%d 0 %d ]\n", width, height, height);
1533    fprintf(stream, "{ currentfile rgbstr readhexstring pop }\n");
1534    fprintf(stream, "false 3\n");
1535    fprintf(stream, "colorimage\n");
1536    for(row = 0; row < height; row++){
1537      for(col = 0; col < width; col++){
1538        status = gl2psGetRGB(pixels, width, height,
1539                             col, row, &dr, &dg, &db) == 0 ? 0 : status;
1540        red = (Uchar)(255. * dr);
1541        gl2psWriteByte(stream, red);
1542        green = (Uchar)(255. * dg);
1543        gl2psWriteByte(stream, green);
1544        blue = (Uchar)(255. * db);
1545        gl2psWriteByte(stream, blue);
1546      }
1547      fprintf(stream, "\n");
1548    }
1549  }
1550
1551  if(status == 0){
1552    gl2psMsg(GL2PS_ERROR, "Problem to retreive some pixel rgb");
1553  }
1554  fprintf(stream, "grestore\n");
1555}
1556
1557void gl2psPrintPostScriptHeader(void){
1558  GLint index;
1559  GLfloat rgba[4];
1560  time_t now;
1561
1562  time(&now);
1563
1564  if(gl2ps->format == GL2PS_PS){
1565    fprintf(gl2ps->stream, "%%!PS-Adobe-3.0\n");
1566  }
1567  else{
1568    fprintf(gl2ps->stream, "%%!PS-Adobe-3.0 EPSF-3.0\n");
1569  }
1570
1571  fprintf(gl2ps->stream,
1572          "%%%%Title: %s\n"
1573          "%%%%Creator: GL2PS, an OpenGL to PostScript Printing Library, v. %g\n"
1574          "%%%%For: %s\n"
1575          "%%%%CreationDate: %s"
1576          "%%%%LanguageLevel: 3\n"
1577          "%%%%DocumentData: Clean7Bit\n"
1578          "%%%%Pages: 1\n",
1579          gl2ps->title, GL2PS_VERSION, gl2ps->producer, ctime(&now));
1580
1581  if(gl2ps->format == GL2PS_PS){
1582    fprintf(gl2ps->stream,
1583            "%%%%Orientation: %s\n"
1584            "%%%%DocumentMedia: Default %d %d 0 () ()\n",
1585            (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait",
1586            (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[3] : gl2ps->viewport[2],
1587            (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[2] : gl2ps->viewport[3]);
1588  }
1589
1590  fprintf(gl2ps->stream,
1591          "%%%%BoundingBox: %d %d %d %d\n"
1592          "%%%%Copyright: GNU LGPL (C) 1999-2003 Christophe Geuzaine <geuz@geuz.org>\n"
1593          "%%%%EndComments\n",
1594          (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[1] : gl2ps->viewport[0],
1595          (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[0] : gl2ps->viewport[1],
1596          (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[3] : gl2ps->viewport[2],
1597          (gl2ps->options & GL2PS_LANDSCAPE) ? gl2ps->viewport[2] : gl2ps->viewport[3]);
1598
1599  /* RGB color: r g b C (replace C by G in output to change from rgb to gray)
1600     Grayscale: r g b G
1601     Font choose: size fontname FC
1602     String primitive: (string) x y size fontname S
1603     Point primitive: x y size P
1604     Line width: width W
1605     Flat-shaded line: x2 y2 x1 y1 L
1606     Smooth-shaded line: x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 SL
1607     Flat-shaded triangle: x3 y3 x2 y2 x1 y1 T
1608     Smooth-shaded triangle: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 ST */
1609
1610  fprintf(gl2ps->stream,
1611          "%%%%BeginProlog\n"
1612          "/gl2psdict 64 dict def gl2psdict begin\n"
1613          "1 setlinecap 1 setlinejoin\n"
1614          "/tryPS3shading %s def %% set to false to force subdivision\n"
1615          "/rThreshold %g def %% red component subdivision threshold\n"
1616          "/gThreshold %g def %% green component subdivision threshold\n"
1617          "/bThreshold %g def %% blue component subdivision threshold\n"
1618          "/BD { bind def } bind def\n"
1619          "/C  { setrgbcolor } BD\n"
1620          "/G  { 0.082 mul exch 0.6094 mul add exch 0.3086 mul add neg 1.0 add setgray } BD\n"
1621          "/W  { setlinewidth } BD\n"
1622          "/FC { findfont exch scalefont setfont } BD\n"
1623          "/S  { FC moveto show } BD\n"
1624          "/P  { newpath 0.0 360.0 arc closepath fill } BD\n"
1625          "/L  { newpath moveto lineto stroke } BD\n"
1626          "/SL { C moveto C lineto stroke } BD\n"
1627          "/T  { newpath moveto lineto lineto closepath fill } BD\n",
1628          (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true",
1629          gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]);
1630
1631  /* Smooth-shaded triangle with PostScript level 3 shfill operator:
1632        x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STshfill */
1633
1634  fprintf(gl2ps->stream,
1635          "/STshfill {\n"
1636          "      /b1 exch def /g1 exch def /r1 exch def /y1 exch def /x1 exch def\n"
1637          "      /b2 exch def /g2 exch def /r2 exch def /y2 exch def /x2 exch def\n"
1638          "      /b3 exch def /g3 exch def /r3 exch def /y3 exch def /x3 exch def\n"
1639          "      gsave << /ShadingType 4 /ColorSpace [/DeviceRGB]\n"
1640          "      /DataSource [ 0 x1 y1 r1 g1 b1 0 x2 y2 r2 g2 b2 0 x3 y3 r3 g3 b3 ] >>\n"
1641          "      shfill grestore } BD\n");
1642
1643  /* Flat-shaded triangle with middle color:
1644        x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 Tm */
1645
1646  fprintf(gl2ps->stream,
1647          /* stack : x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 */
1648          "/Tm { 3 -1 roll 8 -1 roll 13 -1 roll add add 3 div\n" /* r = (r1+r2+r3)/3 */
1649          /* stack : x3 y3 g3 b3 x2 y2 g2 b2 x1 y1 g1 b1 r */
1650          "      3 -1 roll 7 -1 roll 11 -1 roll add add 3 div\n" /* g = (g1+g2+g3)/3 */
1651          /* stack : x3 y3 b3 x2 y2 b2 x1 y1 b1 r g b */
1652          "      3 -1 roll 6 -1 roll 9 -1 roll add add 3 div" /* b = (b1+b2+b3)/3 */
1653          /* stack : x3 y3 x2 y2 x1 y1 r g b */
1654          " C T } BD\n");
1655
1656  /* Split triangle in four sub-triangles (at sides middle points) and call the
1657     STnoshfill procedure on each, interpolating the colors in RGB space:
1658        x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STsplit
1659     (in procedure comments key: (Vi) = xi yi ri gi bi) */
1660
1661  fprintf(gl2ps->stream,
1662          "/STsplit {\n"
1663          "      4 index 15 index add 0.5 mul\n" /* x13 = (x1+x3)/2 */
1664          "      4 index 15 index add 0.5 mul\n" /* y13 = (y1+y3)/2 */
1665          "      4 index 15 index add 0.5 mul\n" /* r13 = (r1+r3)/2 */
1666          "      4 index 15 index add 0.5 mul\n" /* g13 = (g1+g3)/2 */
1667          "      4 index 15 index add 0.5 mul\n" /* b13 = (b1+b3)/2 */
1668          "      5 copy 5 copy 25 15 roll\n"
1669          /* stack : (V3) (V13) (V13) (V13) (V2) (V1) */
1670          "      9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */
1671          "      9 index 30 index add 0.5 mul\n" /* y23 = (y2+y3)/2 */
1672          "      9 index 30 index add 0.5 mul\n" /* r23 = (r2+r3)/2 */
1673          "      9 index 30 index add 0.5 mul\n" /* g23 = (g2+g3)/2 */
1674          "      9 index 30 index add 0.5 mul\n" /* b23 = (b2+b3)/2 */
1675          "      5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n"
1676          /* stack : (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */
1677          "      4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */
1678          "      4 index 10 index add 0.5 mul\n" /* y12 = (y1+y2)/2 */
1679          "      4 index 10 index add 0.5 mul\n" /* r12 = (r1+r2)/2 */
1680          "      4 index 10 index add 0.5 mul\n" /* g12 = (g1+g2)/2 */
1681          "      4 index 10 index add 0.5 mul\n" /* b12 = (b1+b2)/2 */
1682          "      5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n"
1683          /* stack : (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */
1684          "      STnoshfill STnoshfill STnoshfill STnoshfill } BD\n");
1685
1686  /* Gouraud shaded triangle using recursive subdivision until the difference
1687     between corner colors does not exceed the thresholds:
1688        x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STnoshfill  */
1689
1690  fprintf(gl2ps->stream,
1691          "/STnoshfill {\n"
1692          "      2 index 8 index sub abs rThreshold gt\n" /* |r1-r2|>rth */
1693          "      { STsplit }\n"
1694          "      { 1 index 7 index sub abs gThreshold gt\n" /* |g1-g2|>gth */
1695          "        { STsplit }\n"
1696          "        { dup 6 index sub abs bThreshold gt\n" /* |b1-b2|>bth */
1697          "          { STsplit }\n"
1698          "          { 2 index 13 index sub abs rThreshold gt\n" /* |r1-r3|>rht */
1699          "            { STsplit }\n"
1700          "            { 1 index 12 index sub abs gThreshold gt\n" /* |g1-g3|>gth */
1701          "              { STsplit }\n"
1702          "              { dup 11 index sub abs bThreshold gt\n" /* |b1-b3|>bth */
1703          "                { STsplit }\n"
1704          "                { 7 index 13 index sub abs rThreshold gt\n" /* |r2-r3|>rht */
1705          "                  { STsplit }\n"
1706          "                  { 6 index 12 index sub abs gThreshold gt\n" /* |g2-g3|>gth */
1707          "                    { STsplit }\n"
1708          "                    { 5 index 11 index sub abs bThreshold gt\n" /* |b2-b3|>bth */
1709          "                      { STsplit }\n"
1710          "                      { Tm }\n" /* all colors sufficiently similar */
1711          "                      ifelse }\n"
1712          "                    ifelse }\n"
1713          "                  ifelse }\n"
1714          "                ifelse }\n"
1715          "              ifelse }\n"
1716          "            ifelse }\n"
1717          "          ifelse }\n"
1718          "        ifelse }\n"
1719          "      ifelse } BD\n");
1720
1721  fprintf(gl2ps->stream,
1722          "tryPS3shading\n"
1723          "{ /shfill where\n"
1724          "  { /ST { STshfill } BD }\n"
1725          "  { /ST { STnoshfill } BD }\n"
1726          "  ifelse }\n"
1727          "{ /ST { STnoshfill } BD }\n"
1728          "ifelse\n");
1729
1730  fprintf(gl2ps->stream,
1731          "end\n"
1732          "%%%%EndProlog\n"
1733          "%%%%BeginSetup\n"
1734          "/DeviceRGB setcolorspace\n"
1735          "gl2psdict begin\n"
1736          "%%%%EndSetup\n"
1737          "%%%%Page: 1 1\n"
1738          "%%%%BeginPageSetup\n");
1739
1740  if(gl2ps->options & GL2PS_LANDSCAPE){
1741    fprintf(gl2ps->stream,
1742            "%d 0 translate 90 rotate\n",
1743            gl2ps->viewport[3]);
1744  }
1745
1746  fprintf(gl2ps->stream,
1747          "%%%%EndPageSetup\n"
1748          "mark\n"
1749          "gsave\n"
1750          "1.0 1.0 scale\n");
1751         
1752  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
1753    if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
1754      glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
1755    }
1756    else{
1757      glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
1758      rgba[0] = gl2ps->colormap[index][0];
1759      rgba[1] = gl2ps->colormap[index][1];
1760      rgba[2] = gl2ps->colormap[index][2];
1761      rgba[3] = 0.;
1762    }
1763    fprintf(gl2ps->stream,
1764            "%g %g %g C\n"
1765            "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
1766            "closepath fill\n",
1767            rgba[0], rgba[1], rgba[2],
1768            gl2ps->viewport[0], gl2ps->viewport[1], gl2ps->viewport[2],
1769            gl2ps->viewport[1], gl2ps->viewport[2], gl2ps->viewport[3],
1770            gl2ps->viewport[0], gl2ps->viewport[3]);
1771  }
1772}
1773
1774void gl2psPrintPostScriptColor(GL2PSrgba rgba){
1775  if(!gl2psSameColor(gl2ps->lastrgba, rgba)){
1776    gl2ps->lastrgba[0] = rgba[0];
1777    gl2ps->lastrgba[1] = rgba[1];
1778    gl2ps->lastrgba[2] = rgba[2];
1779    fprintf(gl2ps->stream, "%g %g %g C\n", rgba[0], rgba[1], rgba[2]);
1780  }
1781}
1782
1783void gl2psResetPostScriptColor(void){
1784  gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.;
1785}
1786
1787void gl2psPrintPostScriptPrimitive(void *a, void *){
1788  GL2PSprimitive *prim;
1789
1790  prim = *(GL2PSprimitive**)a;
1791
1792  if(gl2ps->options & GL2PS_OCCLUSION_CULL && prim->culled) return;
1793
1794  switch(prim->type){
1795  case GL2PS_PIXMAP :
1796    gl2psPrintPostScriptPixmap(prim->verts[0].xyz[0], prim->verts[0].xyz[1],
1797                               prim->image->width, prim->image->height,
1798                               prim->image->format, prim->image->type,
1799                               prim->image->pixels, gl2ps->stream);
1800    break;
1801  case GL2PS_TEXT :
1802    gl2psPrintPostScriptColor(prim->verts[0].rgba);
1803    fprintf(gl2ps->stream, "(%s) %g %g %d /%s S\n",
1804            prim->text->str, prim->verts[0].xyz[0], prim->verts[0].xyz[1],
1805            prim->text->fontsize, prim->text->fontname);
1806    break;
1807  case GL2PS_POINT :
1808    gl2psPrintPostScriptColor(prim->verts[0].rgba);
1809    fprintf(gl2ps->stream, "%g %g %g P\n",
1810            prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5*prim->width);
1811    break;
1812  case GL2PS_LINE :
1813    if(gl2ps->lastlinewidth != prim->width){
1814      gl2ps->lastlinewidth = prim->width;
1815      fprintf(gl2ps->stream, "%g W\n", gl2ps->lastlinewidth);
1816    }
1817    if(prim->dash){
1818      fprintf(gl2ps->stream, "[%d] 0 setdash\n", prim->dash);
1819    }
1820    if(gl2ps->shade && !gl2psVertsSameColor(prim)){
1821      gl2psResetPostScriptColor();
1822      fprintf(gl2ps->stream, "%g %g %g %g %g %g %g %g %g %g SL\n",
1823              prim->verts[1].xyz[0], prim->verts[1].xyz[1],
1824              prim->verts[1].rgba[0], prim->verts[1].rgba[1],
1825              prim->verts[1].rgba[2], prim->verts[0].xyz[0],
1826              prim->verts[0].xyz[1], prim->verts[0].rgba[0],
1827              prim->verts[0].rgba[1], prim->verts[0].rgba[2]);
1828    }
1829    else{
1830      gl2psPrintPostScriptColor(prim->verts[0].rgba);
1831      fprintf(gl2ps->stream, "%g %g %g %g L\n",
1832              prim->verts[1].xyz[0], prim->verts[1].xyz[1],
1833              prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
1834    }
1835    if(prim->dash){
1836      fprintf(gl2ps->stream, "[] 0 setdash\n");
1837    }
1838    break;
1839  case GL2PS_TRIANGLE :
1840    if(gl2ps->shade && !gl2psVertsSameColor(prim)){
1841      gl2psResetPostScriptColor();
1842      fprintf(gl2ps->stream, "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g ST\n",
1843              prim->verts[2].xyz[0], prim->verts[2].xyz[1],
1844              prim->verts[2].rgba[0], prim->verts[2].rgba[1],
1845              prim->verts[2].rgba[2], prim->verts[1].xyz[0],
1846              prim->verts[1].xyz[1], prim->verts[1].rgba[0],
1847              prim->verts[1].rgba[1], prim->verts[1].rgba[2],
1848              prim->verts[0].xyz[0], prim->verts[0].xyz[1],
1849              prim->verts[0].rgba[0], prim->verts[0].rgba[1],
1850              prim->verts[0].rgba[2]);
1851    }
1852    else{
1853      gl2psPrintPostScriptColor(prim->verts[0].rgba);
1854      fprintf(gl2ps->stream, "%g %g %g %g %g %g T\n",
1855              prim->verts[2].xyz[0], prim->verts[2].xyz[1],
1856              prim->verts[1].xyz[0], prim->verts[1].xyz[1],
1857              prim->verts[0].xyz[0], prim->verts[0].xyz[1]);
1858    }
1859    break;
1860  case GL2PS_QUADRANGLE :
1861    gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print");
1862    break;
1863  default :
1864    gl2psMsg(GL2PS_ERROR, "Unknown type of primitive to print");
1865    break;
1866  }
1867}
1868
1869void gl2psPrintPostScriptFooter(void){
1870  fprintf(gl2ps->stream,
1871          "grestore\n"
1872          "showpage\n"
1873          "cleartomark\n"
1874          "%%%%PageTrailer\n"
1875          "%%%%Trailer\n"
1876          "end\n"
1877          "%%%%EOF\n");
1878}
1879
1880void gl2psPrintPostScriptBeginViewport(GLint viewport[4]){
1881  GLint index;
1882  GLfloat rgba[4];
1883  int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3];
1884
1885  glRenderMode(GL_FEEDBACK);
1886
1887  fprintf(gl2ps->stream,
1888          "gsave\n"
1889          "1.0 1.0 scale\n");
1890         
1891  if(gl2ps->options & GL2PS_DRAW_BACKGROUND){
1892    if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){
1893      glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba);
1894    }
1895    else{
1896      glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index);
1897      rgba[0] = gl2ps->colormap[index][0];
1898      rgba[1] = gl2ps->colormap[index][1];
1899      rgba[2] = gl2ps->colormap[index][2];
1900      rgba[3] = 0.;
1901    }
1902    fprintf(gl2ps->stream,
1903            "%g %g %g C\n"
1904            "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
1905            "closepath fill\n",
1906            rgba[0], rgba[1], rgba[2],
1907            x, y, x+w, y, x+w, y+h, x, y+h);
1908    fprintf(gl2ps->stream,
1909            "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n"
1910            "closepath clip\n",
1911            x, y, x+w, y, x+w, y+h, x, y+h);
1912  }
1913
1914}
1915
1916GLint gl2psPrintPostScriptEndViewport(void){
1917  GLint res;
1918
1919  res = gl2psPrintPrimitives();
1920  fprintf(gl2ps->stream, "grestore\n");
1921  return res;
1922}
1923
1924/* The LaTeX routines */
1925
1926void gl2psPrintTeXHeader(void){
1927  char name[256];
1928  int i;
1929
1930  if(gl2ps->filename && strlen(gl2ps->filename) < 256){
1931    for(i = strlen(gl2ps->filename)-1; i >= 0; i--){
1932      if(gl2ps->filename[i] == '.'){
1933        strncpy(name, gl2ps->filename, i);
1934        name[i] = '\0';
1935        break;
1936      }
1937    }
1938    if(i <= 0) strcpy(name, gl2ps->filename);
1939  }
1940  else{
1941    strcpy(name, "untitled");
1942  }
1943
1944  fprintf(gl2ps->stream,
1945          "\\setlength{\\unitlength}{1pt}\n"
1946          "\\begin{picture}(0,0)\n"
1947          "\\includegraphics{%s}\n"
1948          "\\end{picture}%%\n"
1949          "%s\\begin{picture}(%d,%d)(0,0)\n",
1950          name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "",
1951          gl2ps->viewport[2], gl2ps->viewport[3]);
1952}
1953
1954void gl2psPrintTeXPrimitive(void *a, void *){
1955  GL2PSprimitive *prim;
1956
1957  prim = *(GL2PSprimitive**)a;
1958
1959  switch(prim->type){
1960  case GL2PS_TEXT :
1961    fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)[lb]{%s}}\n",
1962            prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->text->str);
1963    break;
1964  default :
1965    break;
1966  }
1967}
1968
1969void gl2psPrintTeXFooter(void){
1970  fprintf(gl2ps->stream, "\\end{picture}%s\n",
1971          (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : "");
1972}
1973
1974void gl2psPrintTeXBeginViewport(GLint){
1975}
1976
1977GLint gl2psPrintTeXEndViewport(void){
1978  return GL2PS_SUCCESS;
1979}
1980
1981/* The general primitive printing routine */
1982
1983GLint gl2psPrintPrimitives(void){
1984  GL2PSbsptree *root;
1985  GL2PSxyz eye = {0., 0., 100000.};
1986  GLint shademodel, res;
1987  void (*pprim)(void *a, void *b) = 0;
1988
1989  glGetIntegerv(GL_SHADE_MODEL, &shademodel);
1990  gl2ps->shade = (shademodel == GL_SMOOTH);
1991
1992  if(gl2ps->format == GL2PS_TEX){
1993    res = GL2PS_SUCCESS;
1994  }
1995  else{
1996    res = gl2psParseFeedbackBuffer();
1997  }
1998
1999  if(res == GL2PS_SUCCESS){
2000
2001    switch(gl2ps->format){
2002    case GL2PS_TEX :
2003      pprim = gl2psPrintTeXPrimitive;
2004      break;
2005    case GL2PS_PS :
2006    case GL2PS_EPS :
2007      pprim = gl2psPrintPostScriptPrimitive;
2008      break;
2009    }
2010
2011    switch(gl2ps->sort){
2012    case GL2PS_NO_SORT :
2013      gl2psListAction(gl2ps->primitives, pprim);
2014      gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
2015      /* reset the primitive list, waiting for the next viewport */
2016      gl2psListReset(gl2ps->primitives);
2017      break;
2018    case GL2PS_SIMPLE_SORT :
2019      gl2psListSort(gl2ps->primitives, gl2psCompareDepth);
2020      if(gl2ps->options & GL2PS_OCCLUSION_CULL){
2021        gl2psListAction(gl2ps->primitives, gl2psAddInImageTree);
2022        gl2psFreeBspImageTree(&gl2ps->imagetree);
2023      }
2024      gl2psListActionInverse(gl2ps->primitives, pprim);
2025      gl2psListAction(gl2ps->primitives, gl2psFreePrimitive);
2026      /* reset the primitive list, waiting for the next viewport */
2027      gl2psListReset(gl2ps->primitives);
2028      break;
2029    case GL2PS_BSP_SORT :
2030      root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree));
2031      gl2psBuildBspTree(root, gl2ps->primitives);
2032      if(gl2ps->boundary) gl2psBuildPolygonBoundary(root);
2033      if(gl2ps->options & GL2PS_OCCLUSION_CULL){
2034        gl2psTraverseBspTree(root, eye, -(float)GL2PS_EPSILON, gl2psLess,
2035                             gl2psAddInImageTree);
2036        gl2psFreeBspImageTree(&gl2ps->imagetree);
2037      }
2038      gl2psTraverseBspTree(root, eye, (float)GL2PS_EPSILON, gl2psGreater,
2039                           pprim);
2040      gl2psFreeBspTree(&root);
2041      /* reallocate the primitive list (it's been deleted by
2042         gl2psBuildBspTree) in case there is another viewport */
2043      gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
2044      break;
2045    default :
2046      gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", gl2ps->sort);
2047      res = GL2PS_ERROR;
2048      break;
2049    }
2050    fflush(gl2ps->stream);
2051
2052  }
2053
2054  return res;
2055}
2056
2057/* The public routines */
2058
2059GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer,
2060                                  GLint viewport[4], GLint format, GLint sort,
2061                                  GLint options, GLint colormode,
2062                                  GLint colorsize, GL2PSrgba *colormap,
2063                                  GLint nr, GLint ng, GLint nb, GLint buffersize,
2064                                  FILE *stream, const char *filename){
2065  int i;
2066
2067  gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext));
2068  gl2ps->maxbestroot = 10;
2069  gl2ps->format = format;
2070  gl2ps->title = title;
2071  gl2ps->producer = producer;
2072  gl2ps->filename = filename;
2073  gl2ps->sort = sort;
2074  gl2ps->options = options;
2075  for(i = 0; i < 4; i++){
2076    gl2ps->viewport[i] = viewport[i];
2077  }
2078  gl2ps->threshold[0] = nr ? 1./(GLfloat)nr : 0.032;
2079  gl2ps->threshold[1] = ng ? 1./(GLfloat)ng : 0.017;
2080  gl2ps->threshold[2] = nb ? 1./(GLfloat)nb : 0.05;
2081  gl2ps->colormode = colormode;
2082  gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048;
2083  for(i = 0; i < 4; i++){
2084    gl2ps->lastrgba[i] = -1.;
2085  }
2086  gl2ps->lastlinewidth = -1.;
2087  gl2ps->imagetree = NULL;
2088
2089  if(gl2ps->colormode == GL_RGBA){
2090    gl2ps->colorsize = 0;
2091    gl2ps->colormap = NULL;
2092  }
2093  else if(gl2ps->colormode == GL_COLOR_INDEX){
2094    if(!colorsize || !colormap){
2095      gl2psMsg(GL2PS_ERROR, "Missing colormap for GL_COLOR_INDEX rendering");
2096      gl2psFree(gl2ps);
2097      gl2ps = NULL;
2098      return GL2PS_ERROR;
2099    }
2100    gl2ps->colorsize = colorsize;
2101    gl2ps->colormap = (GL2PSrgba*)gl2psMalloc(gl2ps->colorsize * sizeof(GL2PSrgba));
2102    memcpy(gl2ps->colormap, colormap, gl2ps->colorsize * sizeof(GL2PSrgba));
2103  }
2104  else{
2105    gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage");
2106    gl2psFree(gl2ps);
2107    gl2ps = NULL;
2108    return GL2PS_ERROR;
2109  }
2110
2111  if(!stream){
2112    gl2psMsg(GL2PS_ERROR, "Bad file pointer");
2113    gl2psFree(gl2ps);
2114    gl2ps = NULL;
2115    return GL2PS_ERROR;
2116  }
2117  else{
2118    gl2ps->stream = stream;
2119    /* In case gl2psEndPage failed (e.g. due to a GL2PS_OVERFLOW) and
2120       we didn't reopen the stream before calling gl2psBeginPage
2121       again, we need to rewind the stream */
2122    rewind(gl2ps->stream);
2123  }
2124
2125  switch(gl2ps->format){
2126  case GL2PS_TEX :
2127    gl2psPrintTeXHeader();
2128    break;
2129  case GL2PS_PS :
2130  case GL2PS_EPS :
2131    gl2psPrintPostScriptHeader();
2132    break;
2133  default :
2134    gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", gl2ps->format);
2135    gl2psFree(gl2ps);
2136    gl2ps = NULL;
2137    return GL2PS_ERROR;
2138  }
2139
2140  gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*));
2141  gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat));
2142  glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback);
2143  glRenderMode(GL_FEEDBACK); 
2144
2145  return GL2PS_SUCCESS;
2146}
2147
2148GL2PSDLL_API GLint gl2psEndPage(void){
2149  GLint res;
2150
2151  if(!gl2ps) return GL2PS_UNINITIALIZED;
2152
2153  res = gl2psPrintPrimitives();
2154
2155  /* print the footer even if gl2psPrintPrimitives didn't succeed, so
2156     that we end up with a valid file */
2157  switch(gl2ps->format){
2158  case GL2PS_TEX :
2159    gl2psPrintTeXFooter();
2160    break;
2161  case GL2PS_PS :
2162  case GL2PS_EPS :
2163    gl2psPrintPostScriptFooter();
2164    break;
2165  }
2166
2167  fflush(gl2ps->stream);
2168
2169  gl2psListDelete(gl2ps->primitives);
2170  gl2psFree(gl2ps->colormap);
2171  gl2psFree(gl2ps->feedback);
2172  gl2psFree(gl2ps);
2173  gl2ps = NULL;
2174
2175  return res;
2176}
2177
2178GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]){
2179  if(!gl2ps) return GL2PS_UNINITIALIZED;
2180
2181  switch(gl2ps->format){
2182  case GL2PS_EPS :
2183    gl2psPrintPostScriptBeginViewport(viewport);
2184    break;
2185  default :
2186    /* FIXME: handle other formats */
2187    break;
2188  }
2189 
2190  return GL2PS_SUCCESS;
2191}
2192
2193GL2PSDLL_API GLint gl2psEndViewport(void){
2194  GLint res;
2195
2196  if(!gl2ps) return GL2PS_UNINITIALIZED;
2197
2198  switch(gl2ps->format){
2199  case GL2PS_EPS :
2200    res = gl2psPrintPostScriptEndViewport();
2201    break;
2202  default :
2203    /* FIXME: handle other formats */
2204    res = GL2PS_SUCCESS;
2205    break;
2206  }
2207
2208  return res;
2209}
2210
2211GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize){
2212  GLfloat pos[4];
2213  GL2PSprimitive *prim;
2214  GLboolean valid;
2215
2216  if(!gl2ps || !str) return GL2PS_UNINITIALIZED;
2217
2218  if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS;
2219
2220  glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
2221  if(!valid) return GL2PS_SUCCESS; /* the primitive is culled */
2222
2223  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
2224
2225  prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive));
2226  prim->type = GL2PS_TEXT;
2227  prim->boundary = 0;
2228  prim->numverts = 1;
2229  prim->verts = (GL2PSvertex *)gl2psMalloc(sizeof(GL2PSvertex));
2230  prim->verts[0].xyz[0] = pos[0];
2231  prim->verts[0].xyz[1] = pos[1];
2232  prim->verts[0].xyz[2] = GL2PS_DEPTH_FACT * pos[2];
2233  prim->depth = pos[2];
2234  prim->culled = 0;
2235  prim->dash = 0;
2236  prim->width = 1;
2237  glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
2238  prim->text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring));
2239  prim->text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char));
2240  strcpy(prim->text->str, str);
2241  prim->text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char));
2242  strcpy(prim->text->fontname, fontname);
2243  prim->text->fontsize = fontsize;
2244
2245  gl2psListAdd(gl2ps->primitives, &prim);
2246
2247  return GL2PS_SUCCESS;
2248}
2249
2250GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height,
2251                                   GLint xorig, GLint yorig,
2252                                   GLenum format, GLenum type,
2253                                   const void *pixels){
2254  int size;
2255  GLfloat pos[4];
2256  GL2PSprimitive *prim;
2257  GLboolean valid;
2258
2259  if(!gl2ps || !pixels) return GL2PS_UNINITIALIZED;
2260
2261  if((width <= 0) || (height <= 0)) return GL2PS_ERROR;
2262
2263  if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS;
2264
2265  if(format != GL_RGB || type != GL_FLOAT){
2266    gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for GL_RGB, GL_FLOAT pixels");
2267    return GL2PS_ERROR;
2268  }
2269
2270  glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
2271  if(!valid) return GL2PS_SUCCESS; /* the primitive is culled */
2272
2273  glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
2274
2275  prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive));
2276  prim->type = GL2PS_PIXMAP;
2277  prim->boundary = 0;
2278  prim->numverts = 1;
2279  prim->verts = (GL2PSvertex *)gl2psMalloc(sizeof(GL2PSvertex));
2280  prim->verts[0].xyz[0] = pos[0] + xorig;
2281  prim->verts[0].xyz[1] = pos[1] + yorig;
2282  prim->verts[0].xyz[2] = GL2PS_DEPTH_FACT * pos[2];
2283  prim->depth = pos[2];
2284  prim->culled = 0;
2285  prim->dash = 0;
2286  prim->width = 1;
2287  glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba);
2288  prim->image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage));
2289  prim->image->width = width;
2290  prim->image->height = height;
2291  prim->image->format = format;
2292  prim->image->type = type;
2293  size = height*width*3*sizeof(GLfloat); /* FIXME: generalize to other types/formats */
2294  prim->image->pixels = (GLfloat*)gl2psMalloc(size);
2295  memcpy(prim->image->pixels, pixels, size);
2296
2297  gl2psListAdd(gl2ps->primitives, &prim);
2298
2299  return GL2PS_SUCCESS;
2300}
2301
2302GL2PSDLL_API GLint gl2psEnable(GLint mode){
2303  if(!gl2ps) return GL2PS_UNINITIALIZED;
2304
2305  switch(mode){
2306  case GL2PS_POLYGON_OFFSET_FILL :
2307    glPassThrough(GL2PS_BEGIN_POLYGON_OFFSET_FILL);
2308    glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]);
2309    glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]);
2310    break;
2311  case GL2PS_POLYGON_BOUNDARY :
2312    glPassThrough(GL2PS_BEGIN_POLYGON_BOUNDARY);
2313    break;
2314  case GL2PS_LINE_STIPPLE :
2315    glPassThrough(GL2PS_BEGIN_LINE_STIPPLE);
2316    break;
2317  default :
2318    gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode);
2319    return GL2PS_WARNING;
2320  }
2321
2322  return GL2PS_SUCCESS;
2323}
2324
2325GL2PSDLL_API GLint gl2psDisable(GLint mode){
2326  if(!gl2ps) return GL2PS_UNINITIALIZED;
2327
2328  switch(mode){
2329  case GL2PS_POLYGON_OFFSET_FILL :
2330    glPassThrough(GL2PS_END_POLYGON_OFFSET_FILL);
2331    break;
2332  case GL2PS_POLYGON_BOUNDARY :
2333    glPassThrough(GL2PS_END_POLYGON_BOUNDARY);
2334    break;
2335  case GL2PS_LINE_STIPPLE :
2336    glPassThrough(GL2PS_END_LINE_STIPPLE);
2337    break;
2338  default :
2339    gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode);
2340    return GL2PS_WARNING;
2341  }
2342
2343  return GL2PS_SUCCESS;
2344}
2345
2346GL2PSDLL_API GLint gl2psPointSize(GLfloat value){
2347  if(!gl2ps) return GL2PS_UNINITIALIZED;
2348
2349  glPassThrough(GL2PS_SET_POINT_SIZE);
2350  glPassThrough(value);
2351 
2352  return GL2PS_SUCCESS;
2353}
2354
2355GL2PSDLL_API GLint gl2psLineWidth(GLfloat value){
2356  if(!gl2ps) return GL2PS_UNINITIALIZED;
2357
2358  glPassThrough(GL2PS_SET_LINE_WIDTH);
2359  glPassThrough(value);
2360
2361  return GL2PS_SUCCESS;
2362}
2363
2364#endif
Note: See TracBrowser for help on using the repository browser.