1 /*!
2    \file lib/ogsf/gsd_prim.c
3 
4    \brief OGSF library - primitive drawing functions (lower level functions)
5 
6    GRASS OpenGL gsurf OGSF Library
7 
8    (C) 1999-2008, 2018 by the GRASS Development Team
9 
10    This program is free software under the
11    GNU General Public License (>=v2).
12    Read the file COPYING that comes with GRASS
13    for details.
14 
15    \author Bill Brown USACERL (January 1993)
16    \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
17    \author Support for framebuffer objects by Huidae Cho <grass4u gmail.com> (July 2018)
18  */
19 
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <grass/config.h>
24 
25 #if defined(OPENGL_X11)
26 #include <GL/gl.h>
27 #include <GL/glu.h>
28 #include <GL/glx.h>
29 #elif defined(OPENGL_AQUA)
30 #include <OpenGL/gl.h>
31 #include <OpenGL/glu.h>
32 #if defined(OPENGL_AGL)
33 #include <AGL/agl.h>
34 #endif
35 #elif defined(OPENGL_WINDOWS)
36 #include <GL/gl.h>
37 #include <GL/glu.h>
38 #include <wingdi.h>
39 #endif
40 
41 #include <grass/gis.h>
42 #include <grass/ogsf.h>
43 #include <grass/glocale.h>
44 
45 #define USE_GL_NORMALIZE
46 
47 #define RED_MASK 0x000000FF
48 #define GRN_MASK 0x0000FF00
49 #define BLU_MASK 0x00FF0000
50 #define ALP_MASK 0xFF000000
51 
52 #define INT_TO_RED(i, r)    (r = (i & RED_MASK))
53 #define INT_TO_GRN(i, g)    (g = (i & GRN_MASK) >> 8)
54 #define INT_TO_BLU(i, b)    (b = (i & BLU_MASK) >> 16)
55 #define INT_TO_ALP(i, a)    (a = (i & ALP_MASK) >> 24)
56 
57 #define MAX_OBJS 64
58 /* ^ TMP - move to gstypes */
59 
60 /* define border width (pixels) for viewport check */
61 #define border 15
62 
63 static GLuint ObjList[MAX_OBJS];
64 static int numobjs = 0;
65 
66 static int Shade;
67 
68 static float ogl_light_amb[MAX_LIGHTS][4];
69 static float ogl_light_diff[MAX_LIGHTS][4];
70 static float ogl_light_spec[MAX_LIGHTS][4];
71 static float ogl_light_pos[MAX_LIGHTS][4];
72 static float ogl_mat_amb[4];
73 static float ogl_mat_diff[4];
74 static float ogl_mat_spec[4];
75 static float ogl_mat_emis[4];
76 static float ogl_mat_shin;
77 
78 /*!
79    \brief Mostly for flushing drawing commands across a network
80 
81    glFlush doesn't block, so if blocking is desired use glFinish.
82  */
gsd_flush(void)83 void gsd_flush(void)
84 {
85     glFlush();
86 
87     return;
88 }
89 
90 /*!
91    \brief Set color mode
92 
93    Call glColorMaterial before enabling the GL_COLOR_MATERIAL
94 
95    \param cm color mode value
96  */
gsd_colormode(int cm)97 void gsd_colormode(int cm)
98 {
99     switch (cm) {
100     case CM_COLOR:
101 
102 	glDisable(GL_COLOR_MATERIAL);
103 	glDisable(GL_LIGHTING);
104 
105 	break;
106     case CM_EMISSION:
107 
108 	glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
109 	glEnable(GL_COLOR_MATERIAL);
110 	glEnable(GL_LIGHTING);
111 
112 	break;
113     case CM_DIFFUSE:
114 
115 	glColorMaterial(GL_FRONT, GL_DIFFUSE);
116 	glEnable(GL_COLOR_MATERIAL);
117 	glEnable(GL_LIGHTING);
118 
119 	break;
120     case CM_AD:
121 
122 	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
123 	glEnable(GL_COLOR_MATERIAL);
124 	glEnable(GL_LIGHTING);
125 
126 	break;
127     case CM_NULL:
128 
129 	/* OGLXXX
130 	 * lmcolor: if LMC_NULL,  use:
131 	 * glDisable(GL_COLOR_MATERIAL);
132 	 * LMC_NULL: use glDisable(GL_COLOR_MATERIAL);
133 	 */
134 	glDisable(GL_COLOR_MATERIAL);
135 	glEnable(GL_LIGHTING);
136 
137 	break;
138     default:
139 
140 	glDisable(GL_COLOR_MATERIAL);
141 	break;
142     }
143 
144     return;
145 }
146 
147 /*!
148    \brief Print color mode to stderr
149  */
show_colormode(void)150 void show_colormode(void)
151 {
152     GLint mat;
153 
154     glGetIntegerv(GL_COLOR_MATERIAL_PARAMETER, &mat);
155     G_message(_("Color Material: %d"), mat);
156 
157     return;
158 }
159 
160 /*!
161    \brief ADD
162 
163    \param x,y
164    \param rad
165  */
gsd_circ(float x,float y,float rad)166 void gsd_circ(float x, float y, float rad)
167 {
168     GLUquadricObj *qobj = gluNewQuadric();
169 
170     gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
171     glPushMatrix();
172     glTranslatef(x, y, 0.);
173     gluDisk(qobj, 0., rad, 32, 1);
174     glPopMatrix();
175     gluDeleteQuadric(qobj);
176 
177     return;
178 }
179 
180 /*!
181    \brief ADD
182 
183    \param x,y,z
184    \param rad
185  */
gsd_disc(float x,float y,float z,float rad)186 void gsd_disc(float x, float y, float z, float rad)
187 {
188     GLUquadricObj *qobj = gluNewQuadric();
189 
190     gluQuadricDrawStyle(qobj, GLU_FILL);
191     glPushMatrix();
192     glTranslatef(x, y, z);
193     gluDisk(qobj, 0., rad, 32, 1);
194     glPopMatrix();
195     gluDeleteQuadric(qobj);
196 
197     return;
198 }
199 
200 /*!
201    \brief ADD
202 
203    \param center center-point
204    \param siz size value
205  */
gsd_sphere(float * center,float siz)206 void gsd_sphere(float *center, float siz)
207 {
208     static int first = 1;
209     static GLUquadricObj *QOsphere;
210 
211     if (first) {
212 	QOsphere = gluNewQuadric();
213 
214 	if (QOsphere) {
215 	    gluQuadricNormals(QOsphere, GLU_SMOOTH);	/* default */
216 	    gluQuadricTexture(QOsphere, GL_FALSE);	/* default */
217 	    gluQuadricOrientation(QOsphere, GLU_OUTSIDE);	/* default */
218 	    gluQuadricDrawStyle(QOsphere, GLU_FILL);
219 	}
220 
221 	first = 0;
222     }
223 
224     glPushMatrix();
225     glTranslatef(center[0], center[1], center[2]);
226     gluSphere(QOsphere, (double)siz, 24, 24);
227     glPopMatrix();
228 
229     return;
230 }
231 
232 /*!
233    \brief Write out z-mask
234 
235    Enable or disable writing into the depth buffer
236 
237    \param n Specifies whether the depth buffer is enabled for
238    writing
239  */
gsd_zwritemask(unsigned long n)240 void gsd_zwritemask(unsigned long n)
241 {
242     /* OGLXXX glDepthMask is boolean only */
243     glDepthMask((GLboolean) (n));
244 
245     return;
246 }
247 
248 /*!
249    \brief ADD
250 
251    \param n
252  */
gsd_backface(int n)253 void gsd_backface(int n)
254 {
255     glCullFace(GL_BACK);
256     (n) ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE);
257 
258     return;
259 }
260 
261 /*!
262    \brief Set width of rasterized lines
263 
264    \param n line width
265  */
gsd_linewidth(short n)266 void gsd_linewidth(short n)
267 {
268     glLineWidth((GLfloat) (n));
269 
270     return;
271 }
272 
273 /*!
274    \brief ADD
275  */
gsd_bgnqstrip(void)276 void gsd_bgnqstrip(void)
277 {
278     glBegin(GL_QUAD_STRIP);
279 
280     return;
281 }
282 
283 /*!
284    \brief ADD
285  */
gsd_endqstrip(void)286 void gsd_endqstrip(void)
287 {
288     glEnd();
289 
290     return;
291 }
292 
293 /*!
294    \brief ADD
295  */
gsd_bgntmesh(void)296 void gsd_bgntmesh(void)
297 {
298     glBegin(GL_TRIANGLE_STRIP);
299 
300     return;
301 }
302 
303 /*!
304    \brief ADD
305  */
gsd_endtmesh(void)306 void gsd_endtmesh(void)
307 {
308     glEnd();
309 
310     return;
311 }
312 
313 /*!
314    \brief ADD
315  */
gsd_bgntstrip(void)316 void gsd_bgntstrip(void)
317 {
318     glBegin(GL_TRIANGLE_STRIP);
319 
320     return;
321 }
322 
323 /*!
324    \brief ADD
325  */
gsd_endtstrip(void)326 void gsd_endtstrip(void)
327 {
328     glEnd();
329 
330     return;
331 }
332 
333 /*!
334    \brief ADD
335  */
gsd_bgntfan(void)336 void gsd_bgntfan(void)
337 {
338     glBegin(GL_TRIANGLE_FAN);
339 
340     return;
341 }
342 
343 /*!
344    \brief ADD
345  */
gsd_endtfan(void)346 void gsd_endtfan(void)
347 {
348     glEnd();
349 
350     return;
351 }
352 
353 /*!
354    \brief ADD
355  */
gsd_swaptmesh(void)356 void gsd_swaptmesh(void)
357 {
358     /* OGLXXX
359      * swaptmesh not supported, maybe glBegin(GL_TRIANGLE_FAN)
360      * swaptmesh()
361      */
362 
363      /*DELETED*/;
364 
365     return;
366 }
367 
368 /*!
369    \brief Delimit the vertices of a primitive or a group of like primitives
370  */
gsd_bgnpolygon(void)371 void gsd_bgnpolygon(void)
372 {
373     /* OGLXXX
374      * special cases for polygons:
375      *  independent quads: use GL_QUADS
376      *  independent triangles: use GL_TRIANGLES
377      */
378     glBegin(GL_POLYGON);
379 
380     return;
381 }
382 
383 /*!
384    \brief Delimit the vertices of a primitive or a group of like primitives
385  */
gsd_endpolygon(void)386 void gsd_endpolygon(void)
387 {
388     glEnd();
389 
390     return;
391 }
392 
393 /*!
394    \brief Begin line
395  */
gsd_bgnline(void)396 void gsd_bgnline(void)
397 {
398     /* OGLXXX for multiple, independent line segments: use GL_LINES */
399     glBegin(GL_LINE_STRIP);
400     return;
401 }
402 
403 /*!
404    \brief End line
405  */
gsd_endline(void)406 void gsd_endline(void)
407 {
408     glEnd();
409 
410     return;
411 }
412 
413 /*!
414    \brief Set shaded model
415 
416    \param shade non-zero for GL_SMOOTH otherwise GL_FLAT
417  */
gsd_shademodel(int shade)418 void gsd_shademodel(int shade)
419 {
420     Shade = shade;
421 
422     if (shade) {
423 	glShadeModel(GL_SMOOTH);
424     }
425     else {
426 	glShadeModel(GL_FLAT);
427     }
428 
429     return;
430 }
431 
432 /*!
433    \brief Get shaded model
434 
435    \return shade
436  */
gsd_getshademodel(void)437 int gsd_getshademodel(void)
438 {
439     return (Shade);
440 }
441 
442 /*!
443    \brief Draw to the front and back buffers
444  */
gsd_bothbuffers(void)445 void gsd_bothbuffers(void)
446 {
447 #if !defined(OPENGL_FBO)
448     /* OGLXXX bothbuffer: other possibilities include GL_FRONT, GL_BACK */
449     glDrawBuffer(GL_FRONT_AND_BACK);
450 #endif
451     return;
452 }
453 
454 /*!
455    \brief Draw to the front buffer
456  */
gsd_frontbuffer(void)457 void gsd_frontbuffer(void)
458 {
459 #if !defined(OPENGL_FBO)
460     /* OGLXXX frontbuffer: other possibilities include GL_FRONT_AND_BACK */
461     glDrawBuffer(GL_FRONT);
462 #endif
463     return;
464 }
465 
466 /*!
467    \brief Draw to the back buffer
468  */
gsd_backbuffer(void)469 void gsd_backbuffer(void)
470 {
471 #if !defined(OPENGL_FBO)
472     /* OGLXXX backbuffer: other possibilities include GL_FRONT_AND_BACK */
473     glDrawBuffer(GL_BACK);
474 #endif
475     return;
476 }
477 
478 /*!
479    \brief Swap buffers
480  */
gsd_swapbuffers(void)481 void gsd_swapbuffers(void)
482 {
483 #if !defined(OPENGL_FBO)
484     /* OGLXXX swapbuffers: copy the back buffer to the front;
485      * the back buffer becomes undefined afterward */
486 #if defined(OPENGL_X11)
487     glXSwapBuffers(glXGetCurrentDisplay(), glXGetCurrentDrawable());
488 #elif defined(OPENGL_AQUA)
489     aglSwapBuffers(aglGetCurrentContext());
490 #elif defined(OPENGL_WINDOWS)
491     SwapBuffers(wglGetCurrentDC());
492 #endif
493 #endif
494     return;
495 }
496 
497 /*!
498    \brief Pop the current matrix stack
499  */
gsd_popmatrix(void)500 void gsd_popmatrix(void)
501 {
502     glPopMatrix();
503 
504     return;
505 }
506 
507 /*!
508    \brief Push the current matrix stack
509  */
gsd_pushmatrix(void)510 void gsd_pushmatrix(void)
511 {
512     glPushMatrix();
513 
514     return;
515 }
516 
517 /*!
518    \brief Multiply the current matrix by a general scaling matrix
519 
520    \param xs x scale value
521    \param ys y scale value
522    \param zs z scale value
523  */
gsd_scale(float xs,float ys,float zs)524 void gsd_scale(float xs, float ys, float zs)
525 {
526     glScalef(xs, ys, zs);
527 
528     return;
529 }
530 
531 /*!
532    \brief Multiply the current matrix by a translation matrix
533 
534    \param dx x translation value
535    \param dy y translation value
536    \param dz z translation value
537  */
gsd_translate(float dx,float dy,float dz)538 void gsd_translate(float dx, float dy, float dz)
539 {
540     glTranslatef(dx, dy, dz);
541 
542     return;
543 }
544 
545 /*!
546    \brief Get viewport
547 
548    \param[out] window
549    \param viewport
550    \param modelMatrix model matrix
551    \param projMatrix projection matrix
552  */
gsd_getwindow(int * window,int * viewport,double * modelMatrix,double * projMatrix)553 void gsd_getwindow(int *window, int *viewport, double *modelMatrix,
554 		   double *projMatrix)
555 {
556     gsd_pushmatrix();
557     gsd_do_scale(1);
558 
559     glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
560     glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
561     glGetIntegerv(GL_VIEWPORT, viewport);
562     gsd_popmatrix();
563 
564     window[0] = viewport[1] + viewport[3] + border;
565     window[1] = viewport[1] - border;
566     window[2] = viewport[0] - border;
567     window[3] = viewport[0] + viewport[2] + border;
568 
569     return;
570 
571 }
572 
573 /*!
574    \brief ADD
575 
576    \param pt
577    \param widnow
578    \param viewport
579    \param doubleMatrix
580    \param projMatrix
581 
582    \return 0
583    \return 1
584  */
gsd_checkpoint(float pt[4],int window[4],int viewport[4],double modelMatrix[16],double projMatrix[16])585 int gsd_checkpoint(float pt[4],
586 		   int window[4],
587 		   int viewport[4],
588 		   double modelMatrix[16], double projMatrix[16])
589 {
590     GLdouble fx, fy, fz;
591 
592     gluProject((GLdouble) pt[X], (GLdouble) pt[Y], (GLdouble) pt[Z],
593 	       modelMatrix, projMatrix, viewport, &fx, &fy, &fz);
594 
595     if (fx < window[2] || fx > window[3]
596 	|| fy < window[1] || fy > window[0])
597 	return 1;
598     else
599 	return 0;
600 
601 }
602 
603 /*!
604    \brief ADD
605 
606    \param angle
607    \param axis
608  */
gsd_rot(float angle,char axis)609 void gsd_rot(float angle, char axis)
610 {
611     GLfloat x;
612     GLfloat y;
613     GLfloat z;
614 
615     switch (axis) {
616     case 'x':
617     case 'X':
618 
619 	x = 1.0;
620 	y = 0.0;
621 	z = 0.0;
622 
623 	break;
624     case 'y':
625     case 'Y':
626 
627 	x = 0.0;
628 	y = 1.0;
629 	z = 0.0;
630 
631 	break;
632     case 'z':
633     case 'Z':
634 
635 	x = 0.0;
636 	y = 0.0;
637 	z = 1.0;
638 
639 	break;
640     default:
641 
642 	G_warning(_("gsd_rot(): %c is an invalid axis "
643 		    "specification. Rotation ignored. "
644 		    "Please advise GRASS developers of this error"), axis);
645 	return;
646     }
647 
648     glRotatef((GLfloat) angle, x, y, z);
649 
650     return;
651 }
652 
653 /*!
654    \brief Set the current normal vector & specify vertex
655 
656    \param norm normal vector
657    \param col color value
658    \param pt point (model coordinates)
659  */
gsd_litvert_func(float * norm,unsigned long col,float * pt)660 void gsd_litvert_func(float *norm, unsigned long col, float *pt)
661 {
662     glNormal3fv(norm);
663     gsd_color_func(col);
664     glVertex3fv(pt);
665 
666     return;
667 }
668 
669 /*!
670    \brief ADD
671 
672    \param norm
673    \param col
674    \param pt
675  */
gsd_litvert_func2(float * norm,unsigned long col,float * pt)676 void gsd_litvert_func2(float *norm, unsigned long col, float *pt)
677 {
678     glNormal3fv(norm);
679     glVertex3fv(pt);
680 
681     return;
682 }
683 
684 /*!
685    \brief ADD
686 
687    \param pt
688  */
gsd_vert_func(float * pt)689 void gsd_vert_func(float *pt)
690 {
691     glVertex3fv(pt);
692 
693     return;
694 }
695 
696 /*!
697    \brief Set current color
698 
699    \param col color value
700  */
gsd_color_func(unsigned int col)701 void gsd_color_func(unsigned int col)
702 {
703     GLbyte r, g, b, a;
704 
705     /* OGLXXX
706      * cpack: if argument is not a variable
707      * might need to be:
708      *  glColor4b(($1)&0xff, ($1)>>8&0xff, ($1)>>16&0xff, ($1)>>24&0xff)
709      */
710     INT_TO_RED(col, r);
711     INT_TO_GRN(col, g);
712     INT_TO_BLU(col, b);
713     INT_TO_ALP(col, a);
714     glColor4ub(r, g, b, a);
715 
716     return;
717 }
718 
719 /*!
720    \brief Initialize model light
721  */
gsd_init_lightmodel(void)722 void gsd_init_lightmodel(void)
723 {
724 
725     glEnable(GL_LIGHTING);
726 
727     /* normal vector renormalization */
728 #ifdef USE_GL_NORMALIZE
729     {
730 	glEnable(GL_NORMALIZE);
731     }
732 #endif
733 
734     /* OGLXXX
735      * Ambient:
736      *  If this is a light model lmdef, then use
737      *      glLightModelf and GL_LIGHT_MODEL_AMBIENT.
738      *      Include ALPHA parameter with ambient
739      */
740 
741     /* Default is front face lighting, infinite viewer
742      */
743     ogl_mat_amb[0] = 0.1;
744     ogl_mat_amb[1] = 0.1;
745     ogl_mat_amb[2] = 0.1;
746     ogl_mat_amb[3] = 1.0;
747 
748     ogl_mat_diff[0] = 0.8;
749     ogl_mat_diff[1] = 0.8;
750     ogl_mat_diff[2] = 0.8;
751     ogl_mat_diff[3] = 0.8;
752 
753     ogl_mat_spec[0] = 0.8;
754     ogl_mat_spec[1] = 0.8;
755     ogl_mat_spec[2] = 0.8;
756     ogl_mat_spec[3] = 0.8;
757 
758     ogl_mat_emis[0] = 0.0;
759     ogl_mat_emis[1] = 0.0;
760     ogl_mat_emis[2] = 0.0;
761     ogl_mat_emis[3] = 0.0;
762 
763     ogl_mat_shin = 25.0;
764 
765     /* OGLXXX
766      * attenuation: see glLightf man page: (ignored for infinite lights)
767      * Add GL_LINEAR_ATTENUATION.
768      sgi_lmodel[0] = GL_CONSTANT_ATTENUATION;
769      sgi_lmodel[1] = 1.0;
770      sgi_lmodel[2] = 0.0;
771      sgi_lmodel[3] = ;
772      */
773 
774     /* OGLXXX
775      * lmdef other possibilities include:
776      *  glLightf(light, pname, *params);
777      *  glLightModelf(pname, param);
778      * Check list numbering.
779      * Translate params as needed.
780      */
781     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ogl_mat_amb);
782     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, ogl_mat_diff);
783     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, ogl_mat_spec);
784     glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, ogl_mat_emis);
785     glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, ogl_mat_shin);
786 
787     /* OGLXXX lmbind: check object numbering. */
788     /* OGLXXX
789      * lmbind: check object numbering.
790      * Use GL_FRONT in call to glMaterialf.
791      * Use GL_FRONT in call to glMaterialf.
792      if(1) {glCallList(1); glEnable(LMODEL);} else glDisable(LMODEL);
793      if(1) {glCallList(1); glEnable(GL_FRONT);} else glDisable(GL_FRONT);
794      */
795 
796     return;
797 }
798 
799 /*!
800    \brief Set material
801 
802    \param set_shin,set_emis  flags
803    \param sh,em should be 0. - 1.
804    \param emcolor packed colors to use for emission
805  */
gsd_set_material(int set_shin,int set_emis,float sh,float em,int emcolor)806 void gsd_set_material(int set_shin, int set_emis, float sh, float em,
807 		      int emcolor)
808 {
809     if (set_shin) {
810 	ogl_mat_spec[0] = sh;
811 	ogl_mat_spec[1] = sh;
812 	ogl_mat_spec[2] = sh;
813 	ogl_mat_spec[3] = sh;
814 
815 	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, ogl_mat_spec);
816 
817 	ogl_mat_shin = 60. + (int)(sh * 68.);
818 
819 	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, ogl_mat_shin);
820     }
821 
822     if (set_emis) {
823 	ogl_mat_emis[0] = (em * (emcolor & 0x0000FF)) / 255.;
824 	ogl_mat_emis[1] = (em * ((emcolor & 0x00FF00) >> 8)) / 255.;
825 	ogl_mat_emis[2] = (em * ((emcolor & 0xFF0000) >> 16)) / 255.;
826 
827 	glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, ogl_mat_emis);
828     }
829 
830     return;
831 }
832 
833 /*!
834    \brief Define light
835 
836    \param num light id (starts with 1)
837    \param vals position(x,y,z,w), color, ambientm, emission
838  */
gsd_deflight(int num,struct lightdefs * vals)839 void gsd_deflight(int num, struct lightdefs *vals)
840 {
841     if (num > 0 && num <= MAX_LIGHTS) {
842 	ogl_light_pos[num - 1][0] = vals->position[X];
843 	ogl_light_pos[num - 1][1] = vals->position[Y];
844 	ogl_light_pos[num - 1][2] = vals->position[Z];
845 	ogl_light_pos[num - 1][3] = vals->position[W];
846 
847 	glLightfv(GL_LIGHT0 + num, GL_POSITION, ogl_light_pos[num - 1]);
848 
849 	ogl_light_diff[num - 1][0] = vals->color[0];
850 	ogl_light_diff[num - 1][1] = vals->color[1];
851 	ogl_light_diff[num - 1][2] = vals->color[2];
852 	ogl_light_diff[num - 1][3] = .3;
853 
854 	glLightfv(GL_LIGHT0 + num, GL_DIFFUSE, ogl_light_diff[num - 1]);
855 
856 	ogl_light_amb[num - 1][0] = vals->ambient[0];
857 	ogl_light_amb[num - 1][1] = vals->ambient[1];
858 	ogl_light_amb[num - 1][2] = vals->ambient[2];
859 	ogl_light_amb[num - 1][3] = .3;
860 
861 	glLightfv(GL_LIGHT0 + num, GL_AMBIENT, ogl_light_amb[num - 1]);
862 
863 	ogl_light_spec[num - 1][0] = vals->color[0];
864 	ogl_light_spec[num - 1][1] = vals->color[1];
865 	ogl_light_spec[num - 1][2] = vals->color[2];
866 	ogl_light_spec[num - 1][3] = .3;
867 
868 	glLightfv(GL_LIGHT0 + num, GL_SPECULAR, ogl_light_spec[num - 1]);
869     }
870 
871     return;
872 }
873 
874 /*!
875    \brief Switch light on/off
876 
877    \param num
878    \param on 1 for 'on', 0 turns them off
879  */
gsd_switchlight(int num,int on)880 void gsd_switchlight(int num, int on)
881 {
882     short defin;
883 
884     defin = on ? num : 0;
885 
886     if (defin) {
887 	glEnable(GL_LIGHT0 + num);
888     }
889     else {
890 	glDisable(GL_LIGHT0 + num);
891     }
892 
893     return;
894 }
895 
896 /*!
897    \brief Get image of current GL screen
898 
899    \param pixbuf data buffer
900    \param[out] xsize,ysize picture dimension
901 
902    \return 0 on failure
903    \return 1 on success
904  */
gsd_getimage(unsigned char ** pixbuf,unsigned int * xsize,unsigned int * ysize)905 int gsd_getimage(unsigned char **pixbuf, unsigned int *xsize,
906 		 unsigned int *ysize)
907 {
908     GLuint l, r, b, t;
909 
910     /* OGLXXX
911      * get GL_VIEWPORT:
912      * You can probably do better than this.
913      */
914     GLint tmp[4];
915 
916     glGetIntegerv(GL_VIEWPORT, tmp);
917     l = tmp[0];
918     r = tmp[0] + tmp[2] - 1;
919     b = tmp[1];
920     t = tmp[1] + tmp[3] - 1;
921 
922     *xsize = r - l + 1;
923     *ysize = t - b + 1;
924 
925     if (!*xsize || !*ysize)
926 	return (0);
927 
928     *pixbuf = (unsigned char *)G_malloc((*xsize) * (*ysize) * 4);	/* G_fatal_error */
929 
930     if (!*pixbuf)
931 	return (0);
932 
933 #if !defined(OPENGL_FBO)
934     glReadBuffer(GL_FRONT);
935 #endif
936 
937     /* OGLXXX lrectread: see man page for glReadPixels */
938     glReadPixels(l, b, (r) - (l) + 1, (t) - (b) + 1, GL_RGBA,
939 		 GL_UNSIGNED_BYTE, *pixbuf);
940 
941     return (1);
942 }
943 
944 /*!
945    \brief Get viewpoint
946 
947    \param tmp
948    \param num
949 
950    \return 1
951  */
gsd_getViewport(GLint tmp[4],GLint num[2])952 int gsd_getViewport(GLint tmp[4], GLint num[2])
953 {
954 
955     /* Save current viewport to tmp */
956     glGetIntegerv(GL_VIEWPORT, tmp);
957     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, num);
958 
959     return (1);
960 }
961 
962 /*!
963    \brief Write view
964 
965    \param pixbuf data buffer
966    \param xsize,ysize picture dimension
967 
968    \return 0 on failure
969    \return 1 on success
970  */
gsd_writeView(unsigned char ** pixbuf,unsigned int xsize,unsigned int ysize)971 int gsd_writeView(unsigned char **pixbuf, unsigned int xsize,
972 		  unsigned int ysize)
973 {
974 
975     /* Malloc Buffer for image */
976     *pixbuf = (unsigned char *)G_malloc(xsize * ysize * 4);	/* G_fatal_error */
977     if (!*pixbuf) {
978 	return (0);
979     }
980 
981 #if !defined(OPENGL_FBO)
982     /* Read image buffer */
983     glReadBuffer(GL_FRONT);
984 #endif
985 
986     /* Read Pixels into Buffer */
987     glReadPixels(0, 0, xsize, ysize, GL_RGBA, GL_UNSIGNED_BYTE, *pixbuf);
988     return (1);
989 }
990 
991 /*!
992    \brief Specify pixel arithmetic
993 
994    \param yesno turn on/off
995  */
gsd_blend(int yesno)996 void gsd_blend(int yesno)
997 {
998     if (yesno) {
999 	glEnable(GL_BLEND);
1000 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1001     }
1002     else {
1003 	glDisable(GL_BLEND);
1004 	glBlendFunc(GL_ONE, GL_ZERO);
1005     }
1006 
1007     return;
1008 }
1009 
1010 /*!
1011    \brief Define clip plane
1012 
1013    \param num
1014    \param params
1015  */
gsd_def_clipplane(int num,double * params)1016 void gsd_def_clipplane(int num, double *params)
1017 {
1018     int wason = 0;
1019 
1020     /* OGLXXX see man page for glClipPlane equation */
1021     if (glIsEnabled(GL_CLIP_PLANE0 + (num))) {
1022 	wason = 1;
1023     }
1024 
1025     glClipPlane(GL_CLIP_PLANE0 + (num), params);
1026 
1027     if (wason) {
1028 	glEnable(GL_CLIP_PLANE0 + (num));
1029     }
1030     else {
1031 	glDisable(GL_CLIP_PLANE0 + (num));
1032     }
1033 
1034     return;
1035 }
1036 
1037 /*!
1038    \brief Set clip plane
1039 
1040    \param num
1041    \param able
1042  */
gsd_set_clipplane(int num,int able)1043 void gsd_set_clipplane(int num, int able)
1044 {
1045     /* OGLXXX see man page for glClipPlane equation */
1046     if (able) {
1047 	glEnable(GL_CLIP_PLANE0 + (num));
1048     }
1049     else {
1050 	glDisable(GL_CLIP_PLANE0 + (num));
1051     }
1052 
1053     return;
1054 }
1055 
1056 /*!
1057    \brief Finish
1058 
1059    Does nothing, only called from src.contrib/GMSL/NVIZ2.2/src/glwrappers.c
1060  */
gsd_finish(void)1061 void gsd_finish(void)
1062 {
1063     return;
1064 }
1065 
1066 /*!
1067    \brief Set the viewport
1068 
1069    <i>l</i>, <i>b</i> specify the lower left corner of the viewport
1070    rectangle, in pixels.
1071 
1072    <i>r</i>, <i>t</i> specify the width and height of the viewport.
1073 
1074    \param l left
1075    \param r right
1076    \param b bottom
1077    \param t top
1078  */
gsd_viewport(int l,int r,int b,int t)1079 void gsd_viewport(int l, int r, int b, int t)
1080 {
1081     /* Screencoord */
1082     glViewport(l, b, r, t);
1083 
1084     return;
1085 }
1086 
1087 /*!
1088    \brief ADD
1089 
1090    First time called, gets a bunch of objects, then hands them back
1091    when needed
1092 
1093    \return -1 on failure
1094    \return number of objects
1095  */
gsd_makelist(void)1096 int gsd_makelist(void)
1097 {
1098     int i;
1099 
1100     if (numobjs) {
1101 	if (numobjs < MAX_OBJS) {
1102 	    numobjs++;
1103 
1104 	    return (numobjs);
1105 	}
1106 
1107 	return (-1);
1108     }
1109     else {
1110 	ObjList[0] = glGenLists(MAX_OBJS);
1111 
1112 	for (i = 1; i < MAX_OBJS; i++) {
1113 	    ObjList[i] = ObjList[0] + i;
1114 	}
1115 	numobjs = 1;
1116 
1117 	return (numobjs);
1118     }
1119 
1120 }
1121 
1122 /*!
1123    \brief ADD
1124 
1125    \param listno
1126    \param do_draw
1127  */
gsd_bgnlist(int listno,int do_draw)1128 void gsd_bgnlist(int listno, int do_draw)
1129 {
1130     if (do_draw) {
1131 	glNewList(ObjList[listno], GL_COMPILE_AND_EXECUTE);
1132     }
1133     else {
1134 	glNewList(ObjList[listno], GL_COMPILE);
1135     }
1136 
1137     return;
1138 }
1139 
1140 /*!
1141    \brief End list
1142  */
gsd_endlist(void)1143 void gsd_endlist(void)
1144 {
1145     glEndList();
1146 
1147     return;
1148 }
1149 
1150 /*!
1151    \brief Delete list
1152 
1153    \param listno
1154    \param range
1155  */
gsd_deletelist(GLuint listno,int range)1156 void gsd_deletelist(GLuint listno, int range)
1157 {
1158     unsigned int i;
1159 
1160     for (i = 1; i < MAX_OBJS; i++) {
1161 	if (i == listno) {
1162 	    glDeleteLists(ObjList[i], 1);
1163 	    numobjs--;
1164 	    if (numobjs < 1)
1165 		numobjs = 1;
1166 	    return;
1167 	}
1168     }
1169 }
1170 
1171 /*!
1172    \brief ADD
1173 
1174    \param listno
1175  */
gsd_calllist(int listno)1176 void gsd_calllist(int listno)
1177 {
1178     glCallList(ObjList[listno]);
1179 
1180     return;
1181 }
1182 
1183 
1184 /*!
1185    \brief ADD
1186 
1187    \param listno
1188  */
gsd_calllists(int listno)1189 void gsd_calllists(int listno)
1190 {
1191     int i;
1192 
1193     gsd_pushmatrix();
1194     for (i = 1; i < MAX_OBJS; i++) {
1195 	glCallList(ObjList[i]);
1196 	glFlush();
1197     }
1198     gsd_popmatrix();
1199 
1200     gsd_call_label();
1201 
1202     return;
1203 }
1204