/***********************************************************************

     FONCTION :
     ----------
        File OpenGl_telem_util :
 

     REMARQUES:
     ---------- 
      

     HISTORIQUE DES MODIFICATIONS   :
     --------------------------------
       xx-xx-xx : xxx ; Creation.
       07-02-96 : FMN ; - Ajout trace
			- Suppression code inutile
       08-03-96 : FMN ; - Ajout include manquant 
       01-04-96 : CAL ; Integration MINSK portage WNT
       15-04-96 : CAL ; Integration travail PIXMAP de Jim ROTH
       22-04-96 : FMN ; Ajout TelReadImage TelDrawImage
       10-05-96 : CAL ; Ajout d'un nouveau delta dans les copies
			de pixels (voir CALL_DEF_DELTA)
       25-06-96 : FMN ; Suppression utilisation de glScissor.
       02-07-96 : FMN ; Suppression WSWSHeight et WSWSWidth
			Suppression glViewport inutile.
       18-07-96 : FMN ; Suppression TelFlush inutile.
       08-07-96 : FMN ; Suppression de OPENGL_DEBUG inutile avec la nouvelle
			version de ogldebug.
       24-10-96 : CAL ; Portage WNT
       23-01-97 : CAL ; Suppression de TelClearViews dans TelCopyBuffers
       30-01-97 : FMN ; Ajout commentaires + WNT.
       12-02-97 : FMN ; Suppression TelEnquireFacilities()
       22-04-97 : FMN ; Ajout affichage du cadre pour la copie de buffer
       30-06-97 : FMN ; Suppression OpenGl_telem_light.h
       18-07-97 : FMN ; Utilisation de la toolkit sur les lights
       07-10-97 : FMN ; Simplification WNT + correction Transient
       05-12-97 : FMN ; PRO11168: Suppression TglActiveWs pour project/unproject
       23-12-97 : FMN ; Suppression TelSetFrontFaceAttri et TelSetBackFaceAttri 
       30-12-97 : FMN ; CTS18312: Correction back material
       04-05-98 : CAL ; Contournement bug SGI octane bavure de pixels (PRO12899)
       30-09-98 : CAL ; Optimisation pour eviter de charger inutilement
			les matrices de la vue.
       19-10-98 : FMN ; Suppression de glPixelTransferi dans TelEnable() car cela
			rentre en conflit avec l'utilisation d'une image de fond.
       02.14.100 : JR : Warnings on WNT truncations from double to float
       08-03-01 : GG  ; BUC60823 Avoid crash in the normal computation method
			when a face has confused or aligned points.

************************************************************************/

#define IMP190100	/*GG To avoid too many REDRAW in immediat mode,
//			Add TelMakeFrontAndBackBufCurrent() function
*/

/*----------------------------------------------------------------------*/
/*
 * Includes
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef WNT
# include <X11/Xlib.h>
#else
# define STRICT
# include <windows.h>
#endif  /* WNT */


#include <GL/gl.h>
#include <GL/glu.h>
#ifndef WNT
#include <GL/glx.h>
#endif /* WNT */

#include <InterfaceGraphic_Graphic3d.hxx>
#include <InterfaceGraphic_Visual3d.hxx>

#include <OpenGl_tgl_all.h>
#include <OpenGl_cmn_memory.h>
#include <OpenGl_tsm.h>
#include <OpenGl_tsm_ws.h>
#include <OpenGl_telem.h>
#include <OpenGl_telem_attri.h>
#include <OpenGl_telem_util.h>
#include <OpenGl_telem_view.h>
#include <OpenGl_tgl_tox.h>
#include <OpenGl_tgl_subrvis.h>
#include <OpenGl_txgl.h>
#include <OpenGl_LightBox.h>

/*----------------------------------------------------------------------*/
/*
 * Constantes
 */

#define NO_TRACE
#define CALL_DEF_DELTA 10
#define NO_COPYBUFFER

/*----------------------------------------------------------------------*/
/*
 * Variables statiques
 */
 
static Tint call_back_buffer_restored = TOff;

#ifndef WNT

/*
 * Wrappers and utilities used to select between pixmap and gl double buffering
 */

/* Cache some pixmap info for pixmap double buffering */

static Display *window_display;	/* the display in use */
static Window window_id;	/* the window to copy the pixmap to */
static Pixmap pixmap_id;	/* the pixmap id */
static GLXPixmap glx_pixmap;	/* the glx pixmap */
static int
	window_width,		/* window width and height for XCopyArea */
	window_height,
	window_depth;

static GC window_gc;		/* GC for XCopyArea */

static GLXContext glx_context;	/* GL Context */

static int usePixmapDB = 0;	/* True if doing pixmap double buffering */

/*----------------------------------------------------------------------*/

void TelSetPixmapDBParams(Display *dpy,
			  Window window,
			  int width, int height, int depth, GC gc,
			  Pixmap pixmap,
			  GLXPixmap glxpixmap,
			  GLXContext ctx)

{
    window_display = dpy;
    window_id = window;
    window_width = width;
    window_height = height;
    window_depth = depth;
    window_gc = gc;

    pixmap_id = pixmap;

    glx_pixmap = glxpixmap;

    glx_context = ctx;
}

GLXPixmap TelGetGLXPixmap()
{
    return glx_pixmap;
}

void TelSetPixmapDB(int flag)
{
    usePixmapDB = flag;
}

int TelTestPixmapDB()
{
    return usePixmapDB;
}

void TelDrawBuffer(GLenum buf)
{
    if (usePixmapDB)
        glDrawBuffer(GL_FRONT);
    else
        glDrawBuffer(buf);
}

#endif /* WNT */

/*----------------------------------------------------------------------*/

void TelMakeFrontBufCurrent(Tint WsId)
{
#ifndef WNT
    if (usePixmapDB)
    {
	glXMakeCurrent(window_display,window_id, glx_context);
	glDrawBuffer(GL_FRONT);
    }
    else
#endif /* WNT */
    {
	glDrawBuffer(GL_FRONT);
    }
}

void TelMakeBackBufCurrent(Tint WsId)
{
#ifndef WNT
    if (usePixmapDB)
    {
	glXMakeCurrent(window_display,glx_pixmap, glx_context);
	glDrawBuffer(GL_BACK);
    }
    else
#endif /* WNT */
    {
	glDrawBuffer(GL_BACK);
    }
}

#ifdef IMP190100
void TelMakeFrontAndBackBufCurrent(Tint WsId)
{
#ifndef WNT
    if (usePixmapDB)
    {
	glXMakeCurrent(window_display,window_id, glx_context);
	glDrawBuffer(GL_FRONT_AND_BACK);
    }
    else
#endif /* WNT */
    {
	glDrawBuffer(GL_FRONT_AND_BACK);
    }
}
#endif

/*----------------------------------------------------------------------*/
Tint
TelRemdupnames(Tint *ls, Tint num )
{
    register  Tint  *ap, *bp, n;
    
    if( num < 2 )
    return num;
    
    ap = bp = ls+1;
    n = num-1;
    while( n-- )
    {
    if( ap[-1] != *bp )
    *ap++ = *bp++;
    else
    bp++;
    }
    
    return ap-ls;
}

/*----------------------------------------------------------------------*/
#ifdef BUC60823
#define GPRECIS 0.000001
Tint TelGetPolygonNormal(tel_point pnts, Tint* indexs, Tint npnt, Tfloat *norm ) {
    Tint status=0;
   
    norm[0] = norm[1] = norm[2] = 0.;
    if( npnt > 2 ) { 
      Tfloat a[3], b[3], c[3];
      Tint i,j,i0,ii=0,jj;

      i0 = 0; if( indexs ) i0 = indexs[0];
      for( i=1 ; i<npnt ; i++ ) {
	ii = i; if( indexs ) ii = indexs[i];
        vecsub( a, pnts[ii].xyz, pnts[i0].xyz );
	if( vecmg2(a) > GPRECIS ) break;
      }
      if( i < npnt-1 ) {
        for( j=i+1 ; j<npnt ; j++ ) {
	  jj = j; if( indexs ) jj = indexs[j];
          vecsub( b, pnts[jj].xyz, pnts[i0].xyz );
          vecsub( c, pnts[jj].xyz, pnts[ii].xyz );
	  if( (vecmg2(b) > GPRECIS) && (vecmg2(c) > GPRECIS) ) break;
        }
	if( j < npnt ) {
	  Tfloat d;
          veccrs( norm, a, b );
          d = vecnrmd( norm, d );
          status = (d > 0.) ? 1 : 0;
	}
      }
    }
#ifdef DEB
    if( !status )
      printf(" *** OpenGl_TelGetPolygonNormal.has found confused or aligned points\n");
#endif

    return status;
}

Tint TelGetNormal(Tfloat *data1, Tfloat *data2, Tfloat *data3, Tfloat *norm ) {
    Tfloat a[3], b[3];
    Tint status=0;

    norm[0] = norm[1] = norm[2] = 0.;
    vecsub( a, data2, data1 );
    vecsub( b, data3, data2 );
    if( (vecmg2(a) > GPRECIS) && (vecmg2(b) > GPRECIS) ) {
      Tfloat d;
      veccrs( norm, a, b );
      d = vecnrmd( norm, d );
      status = (d > 0.) ? 1 : 0;
    }
#ifdef DEB
    if( !status )
      printf(" *** OpenGl_TelGetNormal.has found confused or aligned points\n");
#endif

    return status;
}
#else
void
TelGetNormal(Tfloat *data1, Tfloat *data2, Tfloat *data3, Tfloat *norm ) {
    Tfloat a[3], b[3];
    
    vecsub( a, data2, data1 );
    vecsub( b, data3, data2 );
    veccrs( norm, a, b );
}
#endif

/*----------------------------------------------------------------------*/
Tint
TelIsBackFace(Tmatrix3 n, Tfloat *nrm )
{
    Tfloat    r[4], m[4];
    
    veccpy(m,nrm);
    m[3] = ( float )1.0;
    
    TelTranpt3( r, m, n );
    
    return r[2] < 0.0;
}

/*----------------------------------------------------------------------*/
void
TelTransposemat3 (Tmatrix3 a)
{
    Tint row, col;
    Tmatrix3 res;
    Tint dim = 4;

    /* transposition de la sous-matrice dim x dim */
    for (row = 0; row < dim; row++)
	for (col = 0; col < dim; col++)
	    res[row][col] = a[col][row];

    /* copie du resultat */
    matcpy (a, res);

    return;
}

/*----------------------------------------------------------------------*/
void
TelMultiplymat3 (Tmatrix3 c, Tmatrix3 a, Tmatrix3 b)
{
    Tint row, col, i;
    Tmatrix3 res;
    Tint dim = 4;

    /* on multiplie d'abord les 2 matrices dim x dim */
    for (row = 0; row < dim; row++) {
	for (col = 0; col < dim; col++) {
	    Tfloat sum = ( float )0.0;
	    for (i = 0; i < dim; i++)
		sum += a[row][i] * b[i][col];
	    res[row][col] = sum;
	}
    }

    /* on copie ensuite le resultat */
    matcpy (c, res);

    return;
}

/*----------------------------------------------------------------------*/
void
TelTranpt3(Tfloat tpt[4], Tfloat pt[4], Tmatrix3 mat )
{
    register  long  i, j;
    Tfloat    sum;
    
    for( i = 0; i < 4; i++ )
    {
    for( j = 0, sum = ( float )0.0; j < 4; j++ )
    {
    sum += pt[j] * mat[j][i];
    }
    tpt[i] = sum;
    }
    return;
}

/*----------------------------------------------------------------------*/
void
TelInitWS(Tint ws, Tint w, Tint h, Tfloat bgcolr, Tfloat bgcolg, Tfloat bgcolb )
{
    CMN_KEY_DATA data;

    TsmGetWSAttri( ws, WSDbuff, &data );

    glMatrixMode(GL_MODELVIEW);
    glViewport( 0, 0, w, h);

	/*
	 * CAL mai 1998
	 * Contournement bug SGI sur Octane (PRO12899)
	 * Bavures de pixels lors de la copie de vue 3d
	 */
	glDisable (GL_SCISSOR_TEST);

    #ifdef TRACE
    printf("OPENGL: TelInitWS: glClearColor %d \n", ws);
    #endif
    if( data.ldata == TOn )
    {
#ifndef WNT
	if (TelTestPixmapDB())
	{
	    glDrawBuffer(GL_FRONT);
	    glClearColor(bgcolr, bgcolg, bgcolb, 1.0);
	    glClear(GL_COLOR_BUFFER_BIT);
	}
	else
	{
	    glDrawBuffer(GL_FRONT_AND_BACK);
	    glClearColor(bgcolr, bgcolg, bgcolb, ( float )1.0);
	    glClear(GL_COLOR_BUFFER_BIT);
	    glDrawBuffer(GL_BACK);
	}
#else
	glDrawBuffer(GL_FRONT_AND_BACK);
	glClearColor(bgcolr, bgcolg, bgcolb, ( float )1.0);
	glClear(GL_COLOR_BUFFER_BIT);
	glDrawBuffer(GL_BACK);
#endif /* WNT */
    }
    else
    {
	glClearColor(bgcolr, bgcolg, bgcolb, ( float )1.0);
	glClear(GL_COLOR_BUFFER_BIT);
    }
    return;
}


/*----------------------------------------------------------------------*/
void TelSwapBuffers ( Tint ws ) {

#ifndef WNT

    CMN_KEY_DATA data;
   
    if (TelTestPixmapDB())
    {
        glFlush();
        XCopyArea(call_thedisplay, pixmap_id, window_id,
                  window_gc, 0, 0,
                  window_width, window_height, 0, 0);
    }
    else
    {
	TsmGetWSAttri( ws, WSWindow, &data );
        glXSwapBuffers ( call_thedisplay, data.ldata );
    }
 
#else
    
    SwapBuffers ( wglGetCurrentDC () );
    TelFlush(0);

#endif  /* WNT */

    TelSetBackBufferRestored (TOff);

    #ifdef TRACE
    printf("OPENGL: TelSwapBuffers: glXSwapBuffers %d \n", ws);
    #endif

    return;

}  /* end TelSwapBuffers */

/*----------------------------------------------------------------------*/
Tint
TelBackBufferRestored ()
{
    return call_back_buffer_restored;
}

/*----------------------------------------------------------------------*/
void
TelSetBackBufferRestored (Tint flag)
{
#ifdef TRACE
	printf("OPENGL: TelSetBackBufferRestored(%d): \n",flag);
#endif
    call_back_buffer_restored = flag;
}

/*----------------------------------------------------------------------*/
void
TelCopyBuffers(Tint ws, GLenum from, GLenum to,
	       Tfloat xm, Tfloat ym, Tfloat zm, Tfloat XM, Tfloat YM, Tfloat ZM, Tint flag)
{
    CMN_KEY_DATA key;
    Tint w, h;

#ifdef TRACE
	printf("OPENGL: TelCopyBuffers: \n");
#endif

	if (to == GL_BACK) TelSetBackBufferRestored (TOff);

#ifndef WNT
	if (TelTestPixmapDB())
	{
#ifdef TRACE
	    printf("OPENGL: TelSwapBuffers: glFlush \n");
#endif
	    glFlush();
	    XCopyArea(window_display, pixmap_id, window_id,
		    window_gc, 0, 0,
		    window_width, window_height, 0, 0);
	    return;
	}
#endif /* WNT */

	TsmGetWSAttri (ws, WSWidth, &key);
	w = key.ldata;
	TsmGetWSAttri (ws, WSHeight, &key);
	h = key.ldata;

	glMatrixMode (GL_PROJECTION);
	glPushMatrix ();
	glLoadIdentity ();
	gluOrtho2D ((GLdouble) 0., (GLdouble) w, 0., (GLdouble) h);
	glMatrixMode (GL_MODELVIEW);
	glPushMatrix ();
	glLoadIdentity ();

	TelDisable (ws);
	if (flag) 
	{
	    /*
	     * calcul de la projection de la boite
	     * et copie du rectangle projete
	     */
	    Tint i;
	    GLsizei width, height;
	    Tfloat xmr, ymr, XMR, YMR;
	    Tfloat xr[8], yr[8];
	    /*
	     * Projection de la boite englobante
	     */
	    if ((TelProjectionRaster (ws, xm, ym, zm, &xr[0], &yr[0]) == TSuccess)
	    &&  (TelProjectionRaster (ws, xm, YM, zm, &xr[1], &yr[1]) == TSuccess)
	    &&  (TelProjectionRaster (ws, XM, YM, zm, &xr[2], &yr[2]) == TSuccess)
	    &&  (TelProjectionRaster (ws, XM, ym, zm, &xr[3], &yr[3]) == TSuccess)
	    &&  (TelProjectionRaster (ws, xm, ym, ZM, &xr[4], &yr[4]) == TSuccess)
	    &&  (TelProjectionRaster (ws, xm, YM, ZM, &xr[5], &yr[5]) == TSuccess)
	    &&  (TelProjectionRaster (ws, XM, YM, ZM, &xr[6], &yr[6]) == TSuccess)
	    &&  (TelProjectionRaster (ws, XM, ym, ZM, &xr[7], &yr[7]) == TSuccess)) 
	    {
		xmr = ymr = (float ) shortreallast ();
		XMR = YMR = (float ) shortrealfirst ();
		/*
		 * Recherche du rectangle projete
		 */
		for (i=0; i<8; i++) {
			if (xmr > xr[i]) xmr = xr[i];
			if (ymr > yr[i]) ymr = yr[i];
			if (XMR < xr[i]) XMR = xr[i];
			if (YMR < yr[i]) YMR = yr[i];
		}
		/* pour eviter les bavures de pixels ! */
		xmr--;ymr--;
		XMR++;YMR++;
    
		/*
		 * Ajout CAL : 10/05/96
		 * Si les MinMax viennent d'un ensemble de markers
		 * on ne tient pas compte du scale factor de ceux-ci
		 * dans les valeurs de MinMax. En effet, ce facteur
		 * est dans l'espace pixel et les MinMax dans l'espace
		 * du modele. Donc ajout d'un delta de pixels
		 * en esperant que les applis n'utilisent pas des
		 * markers tres gros !
		 */
		xmr -= CALL_DEF_DELTA; ymr -= CALL_DEF_DELTA;
		XMR += CALL_DEF_DELTA; YMR += CALL_DEF_DELTA;
    
		/*
		 * Le rectangle projete peut-etre clippe
		 */
		width = (GLsizei) (XMR-xmr+1);
		height = (GLsizei) (YMR-ymr+1);
#ifdef COPYBUFFER
		printf ("avant clipping\n");
		printf ("xm, ym, zm : %f, %f, %f\n", xm, ym, zm);
		printf ("XM, YM, ZM : %f, %f, %f\n", XM, YM, ZM);
		printf ("taille fenetre : %d, %d\n", w, h);
		printf ("xmr, ymr by GLU : %f, %f\n", xmr, ymr);
		printf ("YMR, YMR by GLU : %f, %f\n", XMR, YMR);
		printf ("copie x, y, dx, dy : %d, %d, %d, %d\n\n",
			(int) xmr, (int) ymr, (int) width, (int) height);
#endif
		/*
		 * (xmr,ymr) coin inferieur gauche
		 * (XMR,YMR) coin superieur droit
		 */
		/* cas ou 1 coin est en dehors de la fenetre */
		if (xmr < 0) { width  = (GLsizei) (XMR+1); xmr = 0; }
		if (ymr < 0) { height = (GLsizei) (YMR+1); ymr = 0; }
		if (XMR > w) { width  = (GLsizei) (w-xmr+1); }
		if (YMR > h) { height = (GLsizei) (h-ymr+1); }
    
		/* cas ou les 2 coins sont en dehors de la fenetre */
		if (XMR < 0) { xmr = 0; width = height = 1; }
		if (YMR < 0) { ymr = 0; width = height = 1; }
		if (xmr > w) { xmr = 0; width = height = 1; }
		if (ymr > h) { ymr = 0; width = height = 1; }
#ifdef COPYBUFFER
		printf ("apres clipping\n");
		printf ("xmr, ymr by GLU : %f, %f\n", xmr, ymr);
		printf ("YMR, YMR by GLU : %f, %f\n", XMR, YMR);
		printf ("copie x, y, dx, dy : %d, %d, %d, %d\n\n",
			(int) xmr, (int) ymr, (int) width, (int) height);
#endif
		glDrawBuffer (to);
		glReadBuffer (from);
		/* copie partielle */
		glRasterPos2i ((GLint) xmr, (GLint) ymr);
		glCopyPixels ((GLint) xmr, (GLint) ymr, width, height, GL_COLOR);
		/* TelFlush (1); */
	    }
	    else 
	    {
		glDrawBuffer (to);
		/* TelClearViews (ws); */
		glReadBuffer (from);
		/* copie complete */
		glRasterPos2i (0, 0);
		glCopyPixels (0, 0, w+1, h+1, GL_COLOR);
		/* TelFlush (1); */
	    }
	}
	else 
	{
	    glDrawBuffer (to);
	    /* TelClearViews (ws); */
	    glReadBuffer (from);
	    /* copie complete */
	    glRasterPos2i (0, 0);
	    glCopyPixels (0, 0, w+1, h+1, GL_COLOR);
	    /* TelFlush (1); */
	}
	TelEnable (ws);

	glMatrixMode (GL_PROJECTION);
	glPopMatrix ();
	glMatrixMode (GL_MODELVIEW);
	glPopMatrix ();
    
	glDrawBuffer (GL_BACK);
	return;
}

/*----------------------------------------------------------------------*/
void
TelReadImage(Tint ws, GLenum from, Tint posx, Tint posy, Tint width, Tint height, unsigned int *image)
{
    CMN_KEY_DATA key;
    Tint w, h;

#ifdef TRACE
printf("OPENGL: TelReadImage: %d %d %d %d \n", posx, posy, width, height);
#endif

    if (image !=NULL)
    {
	TsmGetWSAttri (ws, WSWidth, &key);
	w = key.ldata;
	TsmGetWSAttri (ws, WSHeight, &key);
	h = key.ldata;

	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	gluOrtho2D ((GLdouble) 0., (GLdouble) w, 0., (GLdouble) h);
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity ();
	
	glReadBuffer(from); 
	
	glRasterPos2i (posx, posy);
	TelDisable (ws);
	glReadPixels (posx, posy, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
	TelEnable (ws);
    
	glReadBuffer(GL_BACK);        
    }
    
    return;
}

/*----------------------------------------------------------------------*/
void
TelDrawImage(Tint ws, GLenum to, Tint posx, Tint posy, Tint width, Tint height, unsigned int *image)
{
    CMN_KEY_DATA key;
    Tint w, h;

#ifdef TRACE
printf("OPENGL: TelDrawImage: %d %d %d %d \n", posx, posy, width, height);
#endif

    if (image !=NULL)
    {
	TsmGetWSAttri (ws, WSWidth, &key);
	w = key.ldata;
	TsmGetWSAttri (ws, WSHeight, &key);
	h = key.ldata;

	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	gluOrtho2D ((GLdouble) 0., (GLdouble) w, 0., (GLdouble) h);
	glMatrixMode (GL_MODELVIEW);
	glLoadIdentity ();
	
	glDrawBuffer(to);
	
	glRasterPos2i (posx, posy);
	TelDisable (ws);
	glDrawPixels (width, height, GL_RGBA, GL_UNSIGNED_BYTE, image);
	TelEnable (ws);

	glDrawBuffer(GL_BACK);     
    }	    
    return;
}

/*----------------------------------------------------------------------*/
void
TelEnable (Tint ws)
{
    /*glPixelTransferi (GL_MAP_COLOR, GL_TRUE);*/

    /* GL_DITHER on/off pour le trace */
    if (TxglGetDither())
	    glEnable (GL_DITHER);
    else
	    glDisable (GL_DITHER);

    return;
}

/*----------------------------------------------------------------------*/
void
TelDisable (Tint ws)
{
    glDisable (GL_DITHER);
    glPixelTransferi (GL_MAP_COLOR, GL_FALSE);

    /*
     * Disable stuff that's likely to slow down glDrawPixels.
     * (Omit as much of this as possible, when you know in advance
     * that the OpenGL state will already be set correctly.)
     */
    glDisable(GL_ALPHA_TEST);
    glDisable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_FOG);
    LightOff();
    
    glDisable(GL_LOGIC_OP);
    glDisable(GL_STENCIL_TEST);
    glDisable(GL_TEXTURE_1D);
    glDisable(GL_TEXTURE_2D);
    glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
    glPixelTransferi(GL_RED_SCALE, 1);
    glPixelTransferi(GL_RED_BIAS, 0);
    glPixelTransferi(GL_GREEN_SCALE, 1);
    glPixelTransferi(GL_GREEN_BIAS, 0);
    glPixelTransferi(GL_BLUE_SCALE, 1);
    glPixelTransferi(GL_BLUE_BIAS, 0);
    glPixelTransferi(GL_ALPHA_SCALE, 1);
    glPixelTransferi(GL_ALPHA_BIAS, 0);
    
    /*
     * Disable extensions that could slow down glDrawPixels.
     * (Actually, you should check for the presence of the proper
     * extension before making these calls.  I've omitted that
     * code for simplicity.)
     */

#ifdef GL_EXT_convolution
    glDisable(GL_CONVOLUTION_1D_EXT);
    glDisable(GL_CONVOLUTION_2D_EXT);
    glDisable(GL_SEPARABLE_2D_EXT);
#endif

#ifdef GL_EXT_histogram
    glDisable(GL_HISTOGRAM_EXT);
    glDisable(GL_MINMAX_EXT);
#endif

#ifdef GL_EXT_texture3D
    glDisable(GL_TEXTURE_3D_EXT);
#endif

    return;
}

/*----------------------------------------------------------------------*/
TStatus
TelProjectionRaster(Tint ws, Tfloat x, Tfloat y, Tfloat z, Tfloat *xr, Tfloat *yr)
{
    Tint w, h;
    CMN_KEY_DATA key;
    Tint vid;          /* View index */
    TEL_VIEW_REP vrep; /* View definition */
    
    GLint status;
    
    int i, j, k;
    GLdouble objx, objy, objz;
    GLdouble modelMatrix[16], projMatrix[16];
    GLint viewport[4];
    GLdouble winx, winy, winz;
    
    vid = ws;

    if (TelGetViewRepresentation (ws, vid, &vrep) != TSuccess)
	    return TFailure;

    TsmGetWSAttri (ws, WSWidth, &key);
    w = key.ldata;
    TsmGetWSAttri (ws, WSHeight, &key);
    h = key.ldata;

    objx = ( GLdouble )x; objy = ( GLdouble )y; objz = ( GLdouble )z;

    for (k = 0, i = 0; i < 4; i++)
	    for (j = 0; j < 4; j++, k++)
		    modelMatrix[k] = ( GLdouble )vrep.orientation_matrix[i][j];

    for (k = 0, i = 0; i < 4; i++)
	    for (j = 0; j < 4; j++, k++)
		    projMatrix[k] = ( GLdouble )vrep.mapping_matrix[i][j];

    viewport[0] = 0;
    viewport[1] = 0;
    viewport[2] = w;
    viewport[3] = h;

    /*
     * glGetIntegerv (GL_VIEWPORT, viewport);
     * glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
     * glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
     */

    status = gluProject (objx, objy, objz,
	    modelMatrix, projMatrix, viewport,
	    &winx, &winy, &winz);

    if (status == GL_TRUE) {
	*xr = ( Tfloat )winx;
	*yr = ( Tfloat )winy;
	return TSuccess;
    }
    else 
    {
	*xr = 0.0F;
	*yr = 0.0F;
	return TFailure;
    }
}

/*----------------------------------------------------------------------*/
TStatus
TelUnProjectionRaster(Tint ws, Tint xr, Tint yr, Tfloat *x, Tfloat *y, Tfloat *z)
{
    Tint w, h;
    CMN_KEY_DATA key;
    Tint vid;          /* View index */
    TEL_VIEW_REP vrep; /* View definition */
    
    int i, j, k;
    GLdouble objx, objy, objz;
    GLdouble modelMatrix[16], projMatrix[16];
    GLint viewport[4];
    GLdouble winx, winy, winz;
    GLint status;

    vid = ws;

    if (TelGetViewRepresentation (ws, vid, &vrep) != TSuccess)
	    return TFailure;

    TsmGetWSAttri (ws, WSWidth, &key);
    w = key.ldata;
    TsmGetWSAttri (ws, WSHeight, &key);
    h = key.ldata;

    winx = ( GLdouble )xr; winy = ( GLdouble )yr; winz = ( GLdouble )0.0;

    for (k = 0, i = 0; i < 4; i++)
	    for (j = 0; j < 4; j++, k++)
		    modelMatrix[k] = ( GLdouble )vrep.orientation_matrix[i][j];

    for (k = 0, i = 0; i < 4; i++)
	    for (j = 0; j < 4; j++, k++)
		    projMatrix[k] = ( GLdouble )vrep.mapping_matrix[i][j];

    viewport[0] = 0;
    viewport[1] = 0;
    viewport[2] = w;
    viewport[3] = h;

    /*
     * glGetIntegerv (GL_VIEWPORT, viewport);
     * glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
     * glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
     */

    status = gluUnProject (winx, winy, winz, modelMatrix, projMatrix, viewport,
	    &objx, &objy, &objz);
    
    if (status == GL_TRUE) {
	    *x = ( Tfloat )objx;
	    *y = ( Tfloat )objy;
	    *z = ( Tfloat )objz;

    return TSuccess;
    }
    else {
	    *x = 0.0F;
	    *y = 0.0F;
	    *z = 0.0F;

	    return TFailure;
    }
}

/*----------------------------------------------------------------------*/
void
TelFlush(Tint wait)
{
    if (wait)
    {    
#ifdef TRACE
	printf("OPENGL: TelFlush: glFinish \n");
#endif
	glFinish ();
    }
    else
    {
#ifdef TRACE
	printf("OPENGL: TelFlush: glFlush \n");
#endif
	glFlush();
    }
    return;
}

/*----------------------------------------------------------------------*/
Tint
TelIsBackFacePerspective(Tmatrix3 n, Tfloat *p1, Tfloat *p2, Tfloat *p3 )
{
    Tfloat    r1[4], r2[4], r3[4], m[4], norm[4];
    
    veccpy( m, p1 );
    m[3] = ( float )1.0;
    TelTranpt3( r1, m, n );
    r1[0] /= r1[3];
    r1[1] /= r1[3];
    r1[2] /= r1[3];
    
    veccpy( m, p2 );
    m[3] = ( float )1.0;
    TelTranpt3( r2, m, n );
    r2[0] /= r2[3];
    r2[1] /= r2[3];
    r2[2] /= r2[3];
    
    veccpy( m, p3 );
    m[3] = ( float )1.0;
    TelTranpt3( r3, m, n );
    r3[0] /= r3[3];
    r3[1] /= r3[3];
    r3[2] /= r3[3];
    TelGetNormal( r1, r2, r3, norm );
    
    return norm[2] < 0.0;
}

/*----------------------------------------------------------------------*/
