source: trunk/source/visualization/OpenInventor/src/gl2ps.cc @ 849

Last change on this file since 849 was 849, checked in by garnier, 16 years ago

maj de CVS

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