/* context.c */

/*
 * Mesa 3-D graphics library
 * Version:  1.2
 * Copyright (C) 1995  Brian Paul  (brianp@ssec.wisc.edu)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


/*
$Id: context.c,v 1.21 1995/06/19 14:52:37 brianp Exp $

$Log: context.c,v $
 * Revision 1.21  1995/06/19  14:52:37  brianp
 * initialize current texture coordinate, per Asif Khan
 *
 * Revision 1.20  1995/06/05  20:26:24  brianp
 * added Unfilled field to gl_polygon struct
 *
 * Revision 1.19  1995/05/22  21:02:41  brianp
 * Release 1.2
 *
 * Revision 1.18  1995/05/17  13:52:37  brianp
 * implemented glIndexMask(0) and glColorMask(0,0,0,0)
 *
 * Revision 1.17  1995/05/17  13:17:22  brianp
 * changed default CC.Mode value to allow use of real OpenGL headers
 * removed need for CC.MajorMode variable
 *
 * Revision 1.16  1995/05/15  16:07:01  brianp
 * implemented shared/nonshared display lists
 *
 * Revision 1.15  1995/05/12  16:30:14  brianp
 * Texture images stored as bytes, not floats
 *
 * Revision 1.14  1995/04/17  13:51:19  brianp
 * added gl_copy_context() function
 *
 * Revision 1.13  1995/03/27  20:31:26  brianp
 * new Texture.Enabled scheme
 *
 * Revision 1.12  1995/03/24  16:59:56  brianp
 * added gl_update_pixel_logic
 *
 * Revision 1.11  1995/03/24  16:11:41  brianp
 * fixed logicop bug in gl_update_rasterflags
 *
 * Revision 1.10  1995/03/16  20:36:38  brianp
 * added call to gl_update_rasterflags in gl_set_context
 *
 * Revision 1.9  1995/03/10  16:26:43  brianp
 * updated for bleding extensions
 *
 * Revision 1.8  1995/03/09  21:40:14  brianp
 * added ModelViewInvValid initializer
 * added ComputePlane test to gl_update_rasterflags
 *
 * Revision 1.7  1995/03/09  19:07:16  brianp
 * added MESA_DEBUG env var support
 *
 * Revision 1.6  1995/03/08  15:10:02  brianp
 * added support for dd_logicop
 *
 * Revision 1.5  1995/03/04  19:29:44  brianp
 * 1.1 beta revision
 *
 * Revision 1.4  1995/03/02  19:17:54  brianp
 * new RasterMask logic, fixed some comments
 *
 * Revision 1.3  1995/02/27  22:48:28  brianp
 * modified for PB
 *
 * Revision 1.2  1995/02/24  15:19:23  brianp
 * *** empty log message ***
 *
 * Revision 1.1  1995/02/24  14:18:45  brianp
 * Initial revision
 *
 */


/*
 * The gl_context structure holds the current state of the library.
 * Typically, there will be a gl_context structure associated with each
 * window into which we're rendering:
 *    When we open a new rendering window we need a new gl_context.
 *    When we close a rendering window we destroy its gl_context.
 *    When we switch rendering to a different window we change gl_context.
 *
 * Throughout this implementation, references are made to CC which is
 * the Current Context.  Some information is shared among all contexts:
 *     Texture Images         (incorrect?)
 *     Display Lists          (incorrect)
 *     Evaluator definitions  (incorrect?)
 */



#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "context.h"
#include "dd.h"
#include "eval.h"
#include "list.h"
#include "macros.h"
#include "pb.h"


struct gl_context CC;              /* Copy of Current Context (PUBLIC) */

static struct gl_context *CCptr;   /* Pointer to Current Context (PRIVATE) */




/*
 * Allocate and initialize a display list group.
 */
static struct gl_list_group *alloc_display_list_group( void )
{
   struct gl_list_group *lg;
   GLuint i;

   lg = (struct gl_list_group*) malloc( sizeof(struct gl_list_group) );
   for (i=0;i<MAX_DISPLAYLISTS;i++) {
      lg->List[i] = NULL;
      lg->Reserved[i] = GL_FALSE;
   }
   lg->RefCount = 0;
   return lg;
}



/*
 * Initialize the nth light.  Note that the defaults for light 0 are
 * different than the other lights.
 */
static void init_light( struct gl_light *l, GLuint n )
{
   ASSIGN_4V( l->Ambient, 0.0, 0.0, 0.0, 1.0 );
   if (n==0) {
      ASSIGN_4V( l->Diffuse, 1.0, 1.0, 1.0, 1.0 );
      ASSIGN_4V( l->Specular, 1.0, 1.0, 1.0, 1.0 );
   }
   else {
      ASSIGN_4V( l->Diffuse, 0.0, 0.0, 0.0, 1.0 );
      ASSIGN_4V( l->Specular, 0.0, 0.0, 0.0, 1.0 );
   }
   ASSIGN_4V( l->Position, 0.0, 0.0, 1.0, 0.0 );
   ASSIGN_3V( l->Direction, 0.0, 0.0, -1.0 );
   l->SpotExponent = 0.0;
   l->SpotCutoff = 180.0;
   l->ConstantAttenuation = 1.0;
   l->LinearAttenuation = 0.0;
   l->QuadraticAttenuation = 0.0;
   l->Enabled = GL_FALSE;
}



static void init_lightmodel( struct gl_lightmodel *lm )
{
   ASSIGN_4V( lm->Ambient, 0.2, 0.2, 0.2, 1.0 );
   lm->LocalViewer = GL_FALSE;
   lm->TwoSide = GL_FALSE;
}


static void init_material( struct gl_material *m )
{
   GLint i;

   /* loop over front and back face parameters */
   for (i=0;i<2;i++) {
      ASSIGN_4V( m->Ambient[i],  0.2, 0.2, 0.2, 1.0 );
      ASSIGN_4V( m->Diffuse[i],  0.8, 0.8, 0.8, 1.0 );
      ASSIGN_4V( m->Specular[i], 0.0, 0.0, 0.0, 1.0 );
      ASSIGN_4V( m->Emission[i], 0.0, 0.0, 0.0, 1.0 );
      m->Shininess[i] = 0.0;
      m->AmbientIndex[i] = 0;
      m->DiffuseIndex[i] = 1;
      m->SpecularIndex[i] = 1;
   }
}




/*
 * Initialize a gl_context structure to default values.
 */
void gl_initialize_context( struct gl_context *c )
{
   static GLfloat identity[16] = {
	1.0, 0.0, 0.0, 0.0,
	0.0, 1.0, 0.0, 0.0,
	0.0, 0.0, 1.0, 0.0,
	0.0, 0.0, 0.0, 1.0
   };
   GLuint i;

   if (c) {
      ASSIGN_4V( c->Accum.ClearColor, 0.0, 0.0, 0.0, 0.0 );

      c->Color.IndexMask = 0xffffffff;
      c->Color.ColorMask = 0xf;
      c->Color.ClearIndex = 0;
      ASSIGN_4V( c->Color.ClearColor, 0.0, 0.0, 0.0, 0.0 );
      c->Color.DrawBuffer = GL_FRONT;
      c->Color.AlphaEnabled = GL_FALSE;
      c->Color.AlphaFunc = GL_ALWAYS;
      c->Color.AlphaRef = 0.0;
      c->Color.BlendEnabled = GL_FALSE;
      c->Color.BlendSrc = GL_ONE;
      c->Color.BlendDst = GL_ZERO;
      c->Color.BlendEquation = GL_FUNC_ADD_EXT;
      ASSIGN_4V( c->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 );
      c->Color.LogicOpEnabled = GL_FALSE;
      c->Color.SWLogicOpEnabled = GL_FALSE;
      c->Color.LogicOp = GL_COPY;
      c->Color.DitherFlag = GL_FALSE;  /* TODO: this should be GL_TRUE */

      c->Current.Index = 1;
      ASSIGN_3V( c->Current.Normal, 0.0, 0.0, 1.0 );
      ASSIGN_4V( c->Current.Color, 1.0, 1.0, 1.0, 1.0 );
      ASSIGN_4V( c->Current.RasterPos, 0.0, 0.0, 0.0, 1.0 );
      c->Current.RasterPosValid = GL_TRUE;
      c->Current.RasterIndex = 1;
      ASSIGN_4V( c->Current.TexCoord, 0.0, 0.0, 0.0, 1.0 );
      ASSIGN_4V( c->Current.RasterColor, 1.0, 1.0, 1.0, 1.0 );
      c->Current.EdgeFlag = GL_TRUE;

      c->Depth.Test = GL_FALSE;
      c->Depth.Clear = 1.0;
      c->Depth.Func = GL_LESS;
      c->Depth.Mask = GL_TRUE;

      c->Fog.Enabled = GL_FALSE;
      c->Fog.Mode = GL_EXP;
      ASSIGN_4V( c->Fog.Color, 0.0, 0.0, 0.0, 0.0 );
      c->Fog.Index = 0.0;
      c->Fog.Density = 1.0;
      c->Fog.Start = 0.0;
      c->Fog.End = 1.0;

      c->Hint.PerspectiveCorrection = GL_DONT_CARE;
      c->Hint.PointSmooth = GL_DONT_CARE;
      c->Hint.LineSmooth = GL_DONT_CARE;
      c->Hint.PolygonSmooth = GL_DONT_CARE;
      c->Hint.Fog = GL_DONT_CARE;

      for (i=0;i<MAX_LIGHTS;i++) {
	 init_light( &c->Light.Light[i], i );
      }
      init_lightmodel( &c->Light.Model );
      init_material( &c->Light.Material );
      c->Light.ShadeModel = GL_SMOOTH;
      c->Light.Enabled = GL_FALSE;
      c->Light.ColorMaterialFace = GL_FRONT_AND_BACK;
      c->Light.ColorMaterialMode = GL_AMBIENT_AND_DIFFUSE;
      c->Light.ColorMaterialEnabled = GL_FALSE;

      c->Line.SmoothFlag = GL_FALSE;
      c->Line.StippleFlag = GL_FALSE;
      c->Line.Width = 1.0;
      c->Line.StipplePattern = 0xffff;
      c->Line.StippleFactor = 1;

      c->List.ListBase = 0;

      c->Pixel.RedBias = 0.0;
      c->Pixel.RedScale = 1.0;
      c->Pixel.GreenBias = 0.0;
      c->Pixel.GreenScale = 1.0;
      c->Pixel.BlueBias = 0.0;
      c->Pixel.BlueScale = 1.0;
      c->Pixel.AlphaBias = 0.0;
      c->Pixel.AlphaScale = 1.0;
      c->Pixel.DepthBias = 0.0;
      c->Pixel.DepthScale = 1.0;
      c->Pixel.IndexOffset = 0;
      c->Pixel.IndexShift = 0;
      c->Pixel.ZoomX = 1.0;
      c->Pixel.ZoomY = 1.0;
      c->Pixel.MapColorFlag = GL_FALSE;
      c->Pixel.MapStencilFlag = GL_FALSE;
      c->Pixel.MapStoSsize = 1;
      c->Pixel.MapItoIsize = 1;
      c->Pixel.MapItoRsize = 1;
      c->Pixel.MapItoGsize = 1;
      c->Pixel.MapItoBsize = 1;
      c->Pixel.MapItoAsize = 1;
      c->Pixel.MapRtoRsize = 1;
      c->Pixel.MapGtoGsize = 1;
      c->Pixel.MapBtoBsize = 1;
      c->Pixel.MapAtoAsize = 1;
      c->Pixel.MapStoS[0] = 0;
      c->Pixel.MapItoI[0] = 0;
      c->Pixel.MapItoR[0] = 0.0;
      c->Pixel.MapItoG[0] = 0.0;
      c->Pixel.MapItoB[0] = 0.0;
      c->Pixel.MapItoA[0] = 0.0;
      c->Pixel.MapRtoR[0] = 0.0;
      c->Pixel.MapGtoG[0] = 0.0;
      c->Pixel.MapBtoB[0] = 0.0;
      c->Pixel.MapAtoA[0] = 0.0;


      c->Point.SmoothFlag = GL_FALSE;
      c->Point.Size = 1.0;

      c->Polygon.CullFlag = GL_FALSE;
      c->Polygon.CullFaceMode = GL_BACK;
      c->Polygon.FrontFace = GL_CCW;
      c->Polygon.FrontMode = GL_FILL;
      c->Polygon.BackMode = GL_FILL;
      c->Polygon.Unfilled = GL_FALSE;
      c->Polygon.SmoothFlag = GL_FALSE;
      c->Polygon.StippleFlag = GL_FALSE;

      memset( (void *) c->PolygonStipple, 0xff, 32*sizeof(GLuint) );

      c->Scissor.Enabled = GL_FALSE;
      c->Scissor.X = 0;
      c->Scissor.Y = 0;
      c->Scissor.Width = 0;
      c->Scissor.Height = 0;

      c->Stencil.Enabled = GL_FALSE;
      c->Stencil.Function = GL_ALWAYS;
      c->Stencil.Ref = 0;
      c->Stencil.ValueMask = 0xffffffff;
      c->Stencil.FailFunc = GL_KEEP;
      c->Stencil.ZPassFunc = GL_KEEP;
      c->Stencil.ZFailFunc = GL_KEEP;
      c->Stencil.Clear = 0;
      c->Stencil.WriteMask = 0xffffffff;

      c->Texture.Enabled = 0;
      c->Texture.EnvMode = GL_MODULATE;
      ASSIGN_4V( c->Texture.EnvColor, 0.0, 0.0, 0.0, 0.0 );
      ASSIGN_4V( c->Texture.BorderColor, 0.0, 0.0, 0.0, 0.0 );
      c->Texture.TexGenEnabledS = GL_FALSE;
      c->Texture.TexGenEnabledT = GL_FALSE;
      c->Texture.TexGenEnabledR = GL_FALSE;
      c->Texture.TexGenEnabledQ = GL_FALSE;
      c->Texture.GenModeS = GL_EYE_LINEAR;
      c->Texture.GenModeT = GL_EYE_LINEAR;
      c->Texture.GenModeR = GL_EYE_LINEAR;
      c->Texture.GenModeQ = GL_EYE_LINEAR;
      ASSIGN_4V( c->Texture.ObjectPlaneS, 1.0, 0.0, 0.0, 0.0 );
      ASSIGN_4V( c->Texture.ObjectPlaneT, 0.0, 1.0, 0.0, 0.0 );
      ASSIGN_4V( c->Texture.ObjectPlaneR, 0.0, 0.0, 0.0, 0.0 );
      ASSIGN_4V( c->Texture.ObjectPlaneQ, 0.0, 0.0, 0.0, 0.0 );
      ASSIGN_4V( c->Texture.EyePlaneS, 1.0, 0.0, 0.0, 0.0 );
      ASSIGN_4V( c->Texture.EyePlaneT, 0.0, 1.0, 0.0, 0.0 );
      ASSIGN_4V( c->Texture.EyePlaneR, 0.0, 0.0, 0.0, 0.0 );
      ASSIGN_4V( c->Texture.EyePlaneQ, 0.0, 0.0, 0.0, 0.0 );
      c->Texture.WrapS1D = GL_REPEAT;
      c->Texture.WrapT1D = GL_REPEAT;
      c->Texture.WrapS2D = GL_REPEAT;
      c->Texture.WrapT2D = GL_REPEAT;
      c->Texture.MinFilter1D = GL_NEAREST_MIPMAP_LINEAR;
      c->Texture.MagFilter1D = GL_LINEAR;
      c->Texture.MinFilter2D = GL_NEAREST_MIPMAP_LINEAR;
      c->Texture.MagFilter2D = GL_LINEAR;

      c->Transform.MatrixMode = GL_MODELVIEW;
      c->Transform.Normalize = GL_TRUE;
      for (i=0;i<MAX_CLIP_PLANES;i++) {
	 c->Transform.ClipEnabled[i] = GL_FALSE;
         ASSIGN_4V( c->Transform.ClipEquation[i], 0.0, 0.0, 0.0, 0.0 );
      }
      c->Transform.AnyClip = GL_FALSE;

      c->Viewport.X = 0;
      c->Viewport.Y = 0;
      c->Viewport.Width = 0;
      c->Viewport.Height = 0;   
      c->Viewport.Near = 0.0;
      c->Viewport.Far = 1.0;
      c->Viewport.Sx = 0.0;  /* Sx, Tx, Sy, Ty are computed later */
      c->Viewport.Tx = 0.0;
      c->Viewport.Sy = 0.0;
      c->Viewport.Ty = 0.0;
      c->Viewport.Sz = 0.5;
      c->Viewport.Tz = 0.5;

      c->PackAlignment = 4;
      c->PackRowLength = 0;
      c->PackSkipPixels = 0;
      c->PackSkipRows = 0;
      c->PackSwapBytes = GL_FALSE;
      c->PackLSBFirst = GL_FALSE;
      c->UnpackAlignment = 4;
      c->UnpackRowLength = 0;
      c->UnpackSkipPixels = 0;
      c->UnpackSkipRows = 0;
      c->UnpackSwapBytes = GL_FALSE;
      c->UnpackLSBFirst = GL_FALSE;
      c->RenderMode = GL_RENDER;

      c->FeedbackType = GL_2D;   /* TODO: verify */
      c->FeedbackBuffer = NULL;
      c->FeedbackBufferSize = 0;
      c->FeedbackCount = 0;

      c->SelectBuffer = NULL;
      c->SelectBufferSize = 0;
      c->SelectBufferCount = 0;
      c->SelectHits = 0;
      c->NameStackDepth = 0;

      c->AttribStackDepth = 0;
      c->Mode = GL_BITMAP;

      c->ModelViewStackDepth = 0;
      MEMCPY( c->ModelViewMatrix, identity, 16*sizeof(GLfloat) );
      MEMCPY( c->ModelViewInv, identity, 16*sizeof(GLfloat) );
      c->ModelViewInvValid = GL_TRUE;

      c->ProjectionStackDepth = 0;
      MEMCPY( c->ProjectionMatrix, identity, 16*sizeof(GLfloat) );

      c->TextureStackDepth = 0;
      MEMCPY( c->TextureMatrix, identity, 16*sizeof(GLfloat) );

      for (i=0;i<MAX_TEXTURE_LEVELS;i++) {
	 c->TextureComponents1D[i] = 0;
	 c->TextureWidth1D[i] = 0;
	 c->TextureBorder1D[i] = 0;
	 c->TextureImage1D[i] = NULL;
	 c->TextureImage1DDeleteFlag[i] = GL_FALSE;
	 c->TextureComponents2D[i] = 0;
	 c->TextureWidth2D[i] = 0;
	 c->TextureHeight2D[i] = 0;
	 c->TextureBorder2D[i] = 0;
	 c->TextureImage2D[i] = NULL;
	 c->TextureImage2DDeleteFlag[i] = GL_FALSE;
      }

      c->PointFunc = NULL;
      c->LineFunc = NULL;
      c->PolygonFunc = NULL;
      c->AuxPolygonFunc = NULL;

      c->CallDepth = 0;
      c->ExecuteFlag = GL_TRUE;
      c->CompileFlag = GL_FALSE;

      c->BufferWidth = 0;
      c->BufferHeight = 0;
      c->DepthBuffer = NULL;
      c->AccumBuffer = NULL;
      c->StencilBuffer = NULL;

      c->ErrorValue = GL_NO_ERROR;

      gl_update_rasterflags();

      /* etc. */
   }
}



/*
 * Allocate and initialize a gl_context structure.
 */
struct gl_context *gl_new_context( struct gl_context *shareList )
{
   struct gl_context *c;

   /* do some implementation tests */
   assert( sizeof(GLbyte)==1 );
   assert( sizeof(GLshort)==2 );
   assert( sizeof(GLint)==4 );
   assert( sizeof(GLubyte)==1 );
   assert( sizeof(GLushort)==2 );
   assert( sizeof(GLuint)==4 );

   gl_init_lists();
   gl_init_eval();

   c = (struct gl_context *) malloc( sizeof(struct gl_context) );
   if (c) {
      gl_initialize_context( c );
      if (shareList) {
	 /* share the group of display lists of another context */
	 c->ListGroup = shareList->ListGroup;
	 c->ListGroup->RefCount++;
      }
      else {
	 /* allocate new group of display lists */
	 c->ListGroup = alloc_display_list_group();
      }
   }
   return c;
}



/*
 * Destroy a gl_context structure.
 */
void gl_destroy_context( struct gl_context *c )
{
   if (c) {

      //if (c->DepthBuffer)
	 //free(c->DepthBuffer);
      GlobalUnlock(c->hDepthMem);
      GlobalFree(c->hDepthMem);

      if (c->AccumBuffer)
	 free(c->AccumBuffer);
      c->ListGroup->RefCount--;
      if (c->ListGroup->RefCount==0) {
	 /* free display list group */
	 free( c->ListGroup );
      }
      free( (void *) c );
      if (c==CCptr) {
         CCptr = NULL;
      }
   }
}



/*
 * Set the current context.
 */
void gl_set_context( struct gl_context *c )
{
   if (c) {
      /* "write back" current context */
      if (CCptr) {
         MEMCPY( CCptr, &CC, sizeof(struct gl_context) );
      }
      /* "load" new context */
      CCptr = c;
      MEMCPY( &CC, c, sizeof(struct gl_context) );
   }
   gl_update_rasterflags();
   gl_init_pb( GL_BITMAP );
}



/*
 * Copy attribute groups from one context to another.
 * Input:  src - source context
 *         dst - destination context
 *         mask - bitwise OR of GL_*_BIT flags
 */
void gl_copy_context( struct gl_context *src, struct gl_context *dst,
		      GLuint mask )
{
   if (src==CCptr) {
      src = &CC;
   }
   else if (dst==CCptr) {
      dst = &CC;
   }

   if (mask & GL_ACCUM_BUFFER_BIT) {
      MEMCPY( &dst->Accum, &src->Accum, sizeof(struct gl_accum_attrib) );
   }
   if (mask & GL_COLOR_BUFFER_BIT) {
      MEMCPY( &dst->Color, &src->Color, sizeof(struct gl_colorbuffer_attrib) );
   }
   if (mask & GL_CURRENT_BIT) {
      MEMCPY( &dst->Current, &src->Current, sizeof(struct gl_current_attrib) );
   }
   if (mask & GL_DEPTH_BUFFER_BIT) {
      MEMCPY( &dst->Depth, &src->Depth, sizeof(struct gl_depthbuffer_attrib) );
   }
   if (mask & GL_ENABLE_BIT) {
      /* no op */
   }
   if (mask & GL_EVAL_BIT) {
      MEMCPY( &dst->Eval, &src->Eval, sizeof(struct gl_eval_attrib) );
   }
   if (mask & GL_FOG_BIT) {
      MEMCPY( &dst->Fog, &src->Fog, sizeof(struct gl_fog_attrib) );
   }
   if (mask & GL_HINT_BIT) {
      MEMCPY( &dst->Hint, &src->Hint, sizeof(struct gl_hint_attrib) );
   }
   if (mask & GL_LIGHTING_BIT) {
      MEMCPY( &dst->Light, &src->Light, sizeof(struct gl_light_attrib) );
   }
   if (mask & GL_LINE_BIT) {
      MEMCPY( &dst->Line, &src->Line, sizeof(struct gl_line_attrib) );
   }
   if (mask & GL_LIST_BIT) {
      MEMCPY( &dst->List, &src->List, sizeof(struct gl_list_attrib) );
   }
   if (mask & GL_PIXEL_MODE_BIT) {
      MEMCPY( &dst->Pixel, &src->Pixel, sizeof(struct gl_pixel_attrib) );
   }
   if (mask & GL_POINT_BIT) {
      MEMCPY( &dst->Point, &src->Point, sizeof(struct gl_point_attrib) );
   }
   if (mask & GL_POLYGON_BIT) {
      MEMCPY( &dst->Polygon, &src->Polygon, sizeof(struct gl_polygon_attrib) );
   }
   if (mask & GL_POLYGON_STIPPLE_BIT) {
      MEMCPY( &dst->PolygonStipple, &src->PolygonStipple, 32*sizeof(GLuint) );
   }
   if (mask & GL_SCISSOR_BIT) {
      MEMCPY( &dst->Scissor, &src->Scissor, sizeof(struct gl_scissor_attrib) );
   }
   if (mask & GL_STENCIL_BUFFER_BIT) {
      MEMCPY( &dst->Stencil, &src->Stencil, sizeof(struct gl_stencil_attrib) );
   }
   if (mask & GL_TEXTURE_BIT) {
      MEMCPY( &dst->Texture, &src->Texture, sizeof(struct gl_texture_attrib) );
   }
   if (mask & GL_TRANSFORM_BIT) {
      MEMCPY( &dst->Transform, &src->Transform, sizeof(struct gl_transform_attrib) );
   }
   if (mask & GL_VIEWPORT_BIT) {
      MEMCPY( &dst->Viewport, &src->Viewport, sizeof(struct gl_viewport_attrib) );
   }
}



/*
 * This is Mesa's error handler.  Normally, all that's done is the updating
 * of the current error value.  If Mesa is compiled with -DDEBUG or if the
 * environment variable "MESA_DEBUG" is defined then a real error message
 * is printed to stderr.
 * Input:  error - the error value
 *         s - a diagnostic string
 */
void gl_error( GLenum error, char *s )
{
   GLboolean debug;

#ifdef DEBUG
   debug = GL_TRUE;
#else
   if (getenv("MESA_DEBUG")) {
      debug = GL_TRUE;
   }
   else {
      debug = GL_FALSE;
   }
#endif

   if (debug) {
      char errstr[1000];

      switch (error) {
	 case GL_NO_ERROR:
	    strcpy( errstr, "GL_NO_ERROR" );
	    break;
	 case GL_INVALID_VALUE:
	    strcpy( errstr, "GL_INVALID_VALUE" );
	    break;
	 case GL_INVALID_ENUM:
	    strcpy( errstr, "GL_INVALID_ENUM" );
	    break;
	 case GL_INVALID_OPERATION:
	    strcpy( errstr, "GL_INVALID_OPERATION" );
	    break;
	 case GL_STACK_OVERFLOW:
	    strcpy( errstr, "GL_STACK_OVERFLOW" );
	    break;
	 case GL_STACK_UNDERFLOW:
	    strcpy( errstr, "GL_STACK_UNDERFLOW" );
	    break;
	 case GL_OUT_OF_MEMORY:
	    strcpy( errstr, "GL_OUT_OF_MEMORY" );
	    break;
	 default:
	    strcpy( errstr, "unknown" );
	    break;
      }
      fprintf( stderr, "Mesa Error (%s): %s\n", errstr, s );
   }

   if (CC.ErrorValue==GL_NO_ERROR) {
      CC.ErrorValue = error;
   }
}




/*
 * Since the device driver may or may not support pixel logic ops we
 * have to make some extensive tests whenever glLogicOp, glBlendFunc,
 * glBlendEquation, glEn/Disable( GL_LOGIC_OP ), glEn/Disable( GL_BLEND ),
 * or glPopAttrib is called.
 */
void gl_update_pixel_logic( void )
{
   if (CC.RGBAflag) {
      /* RGBA mode blending w/ Logic Op */
      if (CC.Color.BlendEnabled && CC.Color.BlendEquation==GL_LOGIC_OP) {
	 if (dd_logicop( CC.Color.LogicOp )) {
	    /* Device driver can do logic, don't have to do it in software */
	    CC.Color.SWLogicOpEnabled = GL_FALSE;
	 }
	 else {
	    /* Device driver can't do logic op so we do it in software */
	    CC.Color.SWLogicOpEnabled = GL_TRUE;
	 }
      }
      else {
	 /* no logic op */
	 (void) dd_logicop( GL_COPY );
	 CC.Color.SWLogicOpEnabled = GL_FALSE;
      }
   }
   else {
      /* CI mode Logic Op */
      if (CC.Color.LogicOpEnabled) {
	 if (dd_logicop( CC.Color.LogicOp )) {
	    /* Device driver can do logic, don't have to do it in software */
	    CC.Color.SWLogicOpEnabled = GL_FALSE;
	 }
	 else {
	    /* Device driver can't do logic op so we do it in software */
	    CC.Color.SWLogicOpEnabled = GL_TRUE;
	 }
      }
      else {
	 /* no logic op */
	 (void) dd_logicop( GL_COPY );
	 CC.Color.SWLogicOpEnabled = GL_FALSE;
      }
   }
}



/*
 * Recompute the value of CC.RasterMask, CC.ClipMask, etc. according to
 * the current context.
 */
void gl_update_rasterflags( void )
{
   GLuint old_flags;


   old_flags = CC.RasterMask;
   CC.RasterMask = 0;

   if (CC.Color.AlphaEnabled)		CC.RasterMask |= ALPHA_BIT;
   if (CC.Color.BlendEnabled)		CC.RasterMask |= BLEND_BIT;
   if (CC.Depth.Test)			CC.RasterMask |= DEPTH_BIT;
   if (CC.Color.DitherFlag)		CC.RasterMask |= DITHER_BIT;
   if (CC.Fog.Enabled)			CC.RasterMask |= FOG_BIT;
   if (CC.Color.SWLogicOpEnabled)	CC.RasterMask |= LOGIC_OP_BIT;
   if (CC.Scissor.Enabled)		CC.RasterMask |= SCISSOR_BIT;
   if (CC.Stencil.Enabled)		CC.RasterMask |= STENCIL_BIT;

   CC.PointFunc = NULL;
   CC.LineFunc = NULL;
   CC.PolygonFunc = NULL;


   /* Recompute ClipMask (what has to be interpolated when clipping) */
   CC.ClipMask = 0;
   if (CC.Texture.Enabled) {
      CC.ClipMask |= CLIP_TEXTURE_BIT;
   }
   if (CC.Light.ShadeModel==GL_SMOOTH) {
      if (CC.RGBAflag) {
	 CC.ClipMask |= CLIP_FCOLOR_BIT;
	 if (CC.Light.Model.TwoSide) {
	    CC.ClipMask |= CLIP_BCOLOR_BIT;
	 }
      }
      else {
	 CC.ClipMask |= CLIP_FINDEX_BIT;
	 if (CC.Light.Model.TwoSide) {
	    CC.ClipMask |= CLIP_BINDEX_BIT;
	 }
      }
   }


   /* Check if the equation of the plane for polygons has to be computed. */
   CC.ComputePlane = CC.Depth.Test
                  || CC.Polygon.CullFlag || CC.Light.Model.TwoSide
                  || CC.Texture.Enabled;
}

