/*
 * $Id: $
 */

/*
 * Mesa 3-D graphics library
 * Version:  3.0
 * 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.
 */

#include <stdlib.h>
#include <stdio.h>
#include <gl/gl.h>
#include "context.h"
#include "dd.h"
#include "xform.h"
#include "macros.h"
#include "vb.h"

#include <AOS/amigamesa.h>

static void amigaStandardResizeDB(GLcontext *ctx, GLuint * width, GLuint * height);
static void amigaStandardResize(GLcontext *ctx, GLuint * width, GLuint * height);

/**********************************************************************/
/*****                Miscellaneous device driver funcs           *****/
/**********************************************************************/

static const char *amigaRendererString(void)
{
  return "Native standard\n";
}

static const char *amigaRendererStringDB(void)
{
  return "Native fast\n";
}

static void amigaClearIndex(GLcontext *ctx, GLuint index)
{
  /*
   * implement glClearIndex 
   * usually just save the value in the context struct 
   */
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;

  DEBUGOUT(1, "amigaClearIndex(%d)\n", index);

  amesa->clearpixel = amesa->penconv[index];
}

static void amigaClearColor(GLcontext *ctx,
			    GLubyte r, GLubyte g, GLubyte b, GLubyte a)
{
  /*
   * implement glClearColor 
   * color components are floats in [0,1] 
   * usually just save the value in the context struct 
   *
   * @@@ TODO FREE COLOR IF NOT USED 
   */
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;

  DEBUGOUT(1, "amigaClearColor(%d, %d, %d, %d)\n", r, g, b, a);

  amesa->clearpixel = PL_RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b);
}

static GLbitfield amigaClear(GLcontext *ctx, GLbitfield mask, GLboolean all,
			     GLint x, GLint y, GLint width, GLint height)
{
  /*
   * Clear the specified region of the color buffer using the clear color
   * or index as specified by one of the two functions above.
   * If all==GL_TRUE, clear whole buffer
   */
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;

  DEBUGOUT(1, "amigaClear(%d, %d, %d, %d, %d)\n", all, FIXx(x), FIXy(y), width, height);

  SetAPen(amesa->rp, amesa->clearpixel);
  if (all) {
    struct gl_viewport_attrib *vport = &amesa->gl_ctx->Viewport;

    DEBUGOUT(2, " RectFill(%d,%d,%d,%d);\n",
	     FIXx(vport->X),
	     FIXy(vport->Y) - vport->Height,
	     FIXx(vport->X) + vport->Width - 1,
	     FIXy(vport->Y) - 1);

    RectFill(amesa->rp, FIXx(vport->X),
			FIXy(vport->Y) - vport->Height,
			FIXx(vport->X) + vport->Width - 1,
			FIXy(vport->Y) - 1);
#if 0
    if (amesa->visual->rgb_flag) {
      int I;
      for(I = 0; I <= 255; I++) {
      /* Dealocate pens is in RGB mode */
        while (amesa->mypen[I]) {
        /* TODO This may free some others pen also */
          amesa->mypen[I] -= 1;
          ReleasePen(amesa->Screen->ViewPort.ColorMap, I);
        }
      }
    }
#endif
  }
  else {
    if (amesa->rp != 0) {
      DEBUGOUT(2, " RectFill(%d,%d,%d,%d);\n",
	       FIXx(x),
	       FIXy(y) - height,
	       FIXx(x) + width - 1,
	       FIXy(y) - 1);

      RectFill(amesa->rp, FIXx(x),
			  FIXy(y) - height,
			  FIXx(x) + width - 1,
			  FIXy(y) - 1);
    }
    else
      printf("Serius error amesa->rp=0 detected in amigaClear() in file amigamesa.c\n");
  }

  return mask & (~GL_COLOR_BUFFER_BIT);
}

static GLbitfield amigaClearDB(GLcontext *ctx, GLbitfield mask, GLboolean all,
			       GLint x, GLint y, GLint width, GLint height)
{
  /*
   * Clear the specified region of the color buffer using the clear color
   * or index as specified by one of the two functions above.
   * If all==GL_TRUE, clear whole buffer
   */
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  register unsigned char *db;
  register unsigned char col = amesa->clearpixel;

  DEBUGOUT(1, "amigaClearDB(%d, %d, %d, %d, %d)\n", all, FIXx(x), FIXy(y), width, height);

  /*  SetAPen(amesa->rp,amesa->clearpixel); */
  if (all) {
    int size = (amesa->RealWidth * amesa->RealHeight) - 1;

    db = amesa->BackArray;
    while(size-- >= 0) {
      *db++ = col;
    }
  }
  else {
    int x1, y1, x2, y2, last;

    x = FIXx(x);
    y2 = FIXy(y);
    x2 = x + width;
    last = amesa->RealWidth - (x2 - x);
    y = y2 - height;
    db = amesa->BackArray + (y * amesa->RealWidth) + x;

    for (y1 = y; y1 < y2; y1++) {
      for (x1 = x; x1 < x2; x1++) {
	*db++ = col;
      }
      db += last;
    }
  }

  return mask & (~GL_COLOR_BUFFER_BIT);
}

static void amigaSetIndex(GLcontext *ctx, GLuint index)
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;

  DEBUGOUT(1, "amigaSetIndex(%d)\n", index);

  /*
   * Set the amesa color index. 
   */
  amesa->pixel = amesa->penconv[(unsigned char)index];
}

static void amigaSetColor(GLcontext *ctx, GLubyte r, GLubyte g, GLubyte b, GLubyte a)
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;

  DEBUGOUT(1, "amigaSetColor(%d, %d, %d, %d)\n", r, g, b, a);

  /*
   * Set the current RGBA color. 
   * r is in 0..255.RedScale 
   * g is in 0..255.GreenScale 
   * b is in 0..255.BlueScale 
   * a is in 0..255.AlphaScale 
   */
  amesa->pixel = PL_RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b);
}

static GLboolean amigaIndexMask(GLcontext *ctx, GLuint mask)
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;

  DEBUGOUT(1, "amigaIndexMask(0x%x)\n", mask);

  /*
   * implement glIndexMask if possible, else return GL_FALSE 
   */
  amesa->rp->Mask = (unsigned char) mask;

  return (GL_TRUE);
}

static GLboolean amigaColorMask(GLcontext *ctx, GLboolean rmask, GLboolean gmask,
				GLboolean bmask, GLboolean amask)
{
  /*
   * implement glColorMask if possible, else return GL_FALSE 
   */
  return (GL_FALSE);
}

/**********************************************************************/
/*****            Accelerated point, line, polygon rendering        *****/
/**********************************************************************/

/*
 *  Render a number of points by some hardware/OS accerated method
 */

static void amigaFastPointsFunction(GLcontext *ctx, GLuint first, GLuint last)
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  struct vertex_buffer *VB = ctx->VB;
  register unsigned long *penconv = amesa->penconv;
  int i;
  register struct RastPort *rp = amesa->rp;

  DEBUGOUT(1, "amigaFastPointsFunction: ");
  if (VB->MonoColor) {
    /*
     * draw all points using the current color (setColor) 
     */
    SetAPen(rp, amesa->pixel);
    DEBUGOUT(1, "VB->MonoColor\n");
    for (i = first; i <= last; i++) {
      if (VB->ClipMask[i] == 0) {
	/*
	 * compute window coordinate 
	 */
	int x, y;

	x = FIXx((GLint) (VB->Win[i][0]));
	y = FIXy((GLint) (VB->Win[i][1]));
	WritePixel(rp, x, y);
	DEBUGOUT(3, "  WritePixel(%d, %d)\n", x, y);
      }
    }
  }
  else {
    /*
     * each point is a different color 
     */
    DEBUGOUT(1, "!VB.MonoColor\n");
    for (i = first; i <= last; i++) {
      if (VB->ClipMask[i] == 0) {
	int x, y;

	x = FIXx((GLint) (VB->Win[i][0]));
	y = FIXy((GLint) (VB->Win[i][1]));
	SetAPen(rp, penconv[(unsigned char)(*VB->Color[i])]);
	WritePixel(rp, x, y);
	DEBUGOUT(3, "  WritePixel(%d, %d)\n", x, y);
      }
    }
  }
}

static points_func amigaChoosePointsFunction(GLcontext *ctx)
{
  DEBUGOUT(1, "amigaChoosePointsFunction\n");
  /*
   * Examine the current rendering state and return a pointer to a 
   * fast point-rendering function if possible. 
   */
  if (ctx->Point.Size == 1.0 && !ctx->Point.SmoothFlag && ctx->RasterMask == 0
      && !ctx->Texture.Enabled					/*
								 * &&  ETC, ETC 
								 */ ) {
    return amigaFastPointsFunction;
  }
  else {
    return NULL;
  }
}

static points_func amigaChoosePointsFunctionDB(GLcontext *ctx)
{
  return NULL;
}

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

 /*
  *  Render a line by some hardware/OS accerated method 
  */

static void amigaFastLineFunction(GLcontext *ctx, GLuint v0, GLuint v1, GLuint pv)
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  register unsigned long *penconv = amesa->penconv;
  struct vertex_buffer *VB = ctx->VB;
  int x0, y0, x1, y1;

  DEBUGOUT(1, "amigaFastLineFunction\n");

  if (VB->MonoColor)
    SetAPen(amesa->rp, amesa->pixel);
  else
    SetAPen(amesa->rp, penconv[*VB->Color[pv]]);

  x0 = FIXx((int)(VB->Win[v0][0]));
  y0 = FIXy((int)(VB->Win[v0][1]));
  x1 = FIXx((int)(VB->Win[v1][0]));
  y1 = FIXy((int)(VB->Win[v1][1]));

  Move(amesa->rp, x0, y0);
  DEBUGOUT(2, " Move(%d, %d)\n", x0, y0);
  Draw(amesa->rp, x1, y1);
  DEBUGOUT(2, " Draw(%d, %d)\n", x1, y1);
}

static line_func amigaChooseLineFunction(GLcontext *ctx)
{
  DEBUGOUT(1, "amigaChooseLineFunction()\n");

  /*
   * Examine the current rendering state and return a pointer to a 
   * fast line-rendering function if possible. 
   */

  if (ctx->Line.Width == 1.0 && !ctx->Line.SmoothFlag && !ctx->Line.StippleFlag
      && ctx->Light.ShadeModel == GL_FLAT && ctx->RasterMask == 0
      && !ctx->Texture.Enabled					/*
								 * &&  ETC, ETC 
								 */ ) {
    return amigaFastLineFunction;
  }
  else {
    return NULL;
  }
}

static line_func amigaChooseLineFunctionDB(GLcontext *ctx)
{
  return NULL;
}

/**********************************************************************/
/*****                  Optimized polygon rendering               *****/
/**********************************************************************/

/*
 * Draw a filled polygon of a single color. If there is hardware/OS support
 * for polygon drawing use that here.   Otherwise, call a function in
 * polygon.c to do the drawing.
 */

static triangle_func amigaChooseTriangleFunction(GLcontext *ctx)
{
  DEBUGOUT(1, "amigaChooseTriangleFunction\n");
  /*
   * Examine the current rendering state and return a pointer to a 
   * fast polygon-rendering function if possible. 
   */
  return NULL;
}

static triangle_func amigaChooseTriangleFunctionDB(GLcontext *ctx)
{
  return NULL;
}

/**********************************************************************/
/*****        write spans of RGBA pixels                          *****/
/**********************************************************************/

static void amigaWriteRGBASpan(const GLcontext *ctx, GLuint n, GLint x, GLint y,
			       CONST GLubyte rgba[][4], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  unsigned char *dp;
  register struct RastPort *rp = amesa->rp;

  y = FIXy(y);
  x = FIXx(x);
  DEBUGOUT(1, "amigaWriteRGBASpan(%d, %d, %d): ", n, x, y);

  if ((dp = amesa->imageline) && amesa->temprp) {		/*  if imageline allocated then use fastversion  */
    DEBUGOUT(1, "FAST ");
    if (mask) {
      int i, ant;

      DEBUGOUT(1, "mask\n");
      ant = 0;
      for (i = 0; i < n; i++) {					/*  draw pixel (x[i],y[i])  */
	if (*mask++) {
	  ant++;
	  *dp++ = PL_RGBA((unsigned char)rgba[i][0], (unsigned char)rgba[i][1], (unsigned char)rgba[i][2]);
	}
	else {
	  if (ant) {
	    WritePixelLine8(rp, x, y, ant, amesa->imageline, amesa->temprp);
	    DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", ant, x, y);
	    dp = amesa->imageline;
	    x += ant;
	    ant = 0;
	  }
	  else
	    x++;
	}
      }

      if (ant) {
	WritePixelLine8(rp, x, y, ant, amesa->imageline, amesa->temprp);
	DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", ant, x, y);
      }
    }
    else {
      int i;

      DEBUGOUT(1, "nomask\n");
      for (i = n - 1; i >= 0; i--) {					/*  draw pixel (x[i],y[i]) */
	*dp++ = PL_RGBA((unsigned char)rgba[0][0], (unsigned char)rgba[0][1], (unsigned char)rgba[0][2]);
	((ULONG *)rgba)++;
      }
      WritePixelLine8(rp, x, y, n, amesa->imageline, amesa->temprp);
      DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", n, x, y);
    }

  }
  else {							/*  Slower version  */
    DEBUGOUT(1, "SLOW ");
    if (mask) {
      int i;

      DEBUGOUT(1, "mask\n");
      /* draw some pixels */
      for (i = 0; i < n; i++, x++) {
	if (*mask++) {
	  /* draw pixel x,y using color rgba[i][0]/rgba[i][1]/rgba[i][2]/rgba[i][3] */
	  SetAPen(rp, PL_RGBA((unsigned char)rgba[i][0], (unsigned char)rgba[i][1], (unsigned char)rgba[i][2]));
	  WritePixel(rp, x, y);
	  DEBUGOUT(3, "  WritePixel(%d, %d)\n", x, y);
	}
      }
    }
    else {
      int i;

      DEBUGOUT(1, "nomask\n");
      /* draw all pixels */
      for (i = n - 1; i >= 0; i--, x++) {
	/* draw pixel x,y using color rgba[i][0]/rgba[i][1]/rgba[i][2]/rgba[i][3] */
	SetAPen(rp, PL_RGBA((unsigned char)rgba[0][0], (unsigned char)rgba[0][1], (unsigned char)rgba[0][2]));
	((ULONG *)rgba)++;
	WritePixel(rp, x, y);
	DEBUGOUT(3, "  WritePixe(%d, %d)\n", x, y);
      }
    }
  }
}

static void amigaWriteRGBSpan(const GLcontext *ctx, GLuint n, GLint x, GLint y,
			      CONST GLubyte rgb[][3], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  unsigned char *dp;
  register struct RastPort *rp = amesa->rp;

  y = FIXy(y);
  x = FIXx(x);
  DEBUGOUT(1, "amigaWriteRGBSpan(%d, %d, %d): ", n, x, y);

  if ((dp = amesa->imageline) && amesa->temprp) {		/*  if imageline allocated then use fastversion  */
    DEBUGOUT(1, "FAST ");
    if (mask) {
      int i, ant;

      DEBUGOUT(1, "mask\n");
      ant = 0;
      for (i = 0; i < n; i++) {					/*  draw pixel (x[i],y[i])  */
	if (*mask++) {
	  ant++;
	  *dp++ = PL_RGBA((unsigned char)rgb[i][0], (unsigned char)rgb[i][1], (unsigned char)rgb[i][2]);
	}
	else {
	  if (ant) {
	    WritePixelLine8(rp, x, y, ant, amesa->imageline, amesa->temprp);
	    DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", ant, x, y);
	    dp = amesa->imageline;
	    x += ant;
	    ant = 0;
	  }
	  else
	    x++;
	}
      }

      if (ant) {
	WritePixelLine8(rp, x, y, ant, amesa->imageline, amesa->temprp);
	DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", ant, x, y);
      }
    }
    else {
      int i;

      DEBUGOUT(1, "nomask\n");
      for (i = n - 1; i >= 0; i--) {
	*dp++ = PL_RGBA((unsigned char)rgb[0][0], (unsigned char)rgb[0][1], (unsigned char)rgb[0][2]);
	((unsigned char *)rgb) += 3;
      }
      WritePixelLine8(rp, x, y, n, amesa->imageline, amesa->temprp);
      DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", n, x, y);
    }
  }
  else {							/*  Slower version  */
    DEBUGOUT(1, "SLOW ");
    if (mask) {
      int i;

      DEBUGOUT(1, "mask\n");
      /* draw some pixels */
      for (i = 0; i < n; i++, x++) {
	if (*mask++) {
	  /* draw pixel x,y using color rgb[i][0]/rgb[i][1]/rgb[i][2]/rgb[i][3] */
	  SetAPen(rp, PL_RGBA((unsigned char)rgb[i][0], (unsigned char)rgb[i][1], (unsigned char)rgb[i][2]));
	  WritePixel(rp, x, y);
	  DEBUGOUT(3, "  WritePixel(%d, %d)\n", x, y);
	}
      }
    }
    else {
      int i;

      DEBUGOUT(1, "nomask\n");
      /* draw all pixels */
      for (i = n - 1; i >= 0; i--, x++) {
	/* draw pixel x,y using color rgb[i][0]/rgb[i][1]/rgb[i][2]/rgb[i][3] */
	SetAPen(rp, PL_RGBA((unsigned char)rgb[0][0], (unsigned char)rgb[0][1], (unsigned char)rgb[0][2]));
	((unsigned char *)rgb) += 3;
	WritePixel(rp, x, y);
	DEBUGOUT(3, "  WritePixel(%d, %d)\n", x, y);
      }
    }
  }
}

static void amigaWriteCI32Span(const GLcontext *ctx, GLuint n, GLint x, GLint y,
			       const GLuint index[],
			       const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  unsigned char *dp;
  unsigned long *penconv = amesa->penconv;
  register struct RastPort *rp = amesa->rp;

  y = FIXy(y);
  x = FIXx(x);
  DEBUGOUT(1, "amigaWriteCI32Span(%d, %d, %d): ", n, x, y);

  if ((dp = amesa->imageline) && amesa->temprp) {		/*  if imageline and temporary rastport have been */
    int ant, i;							/*  allocated then use fastversion  */

    DEBUGOUT(1, "FAST\n");
    ant = 0;
    for (i = 0; i < n; i++) {					/*  draw pixel (x[i],y[i]) using index[i]  */
      if (*mask++) {
	ant++;
	*dp++ = penconv[(unsigned char)index[i]];
	DEBUGOUT(4, "   index[%d] = 0x%x\n", i, index[i]);
      }
      else {
	if (ant) {
	  WritePixelLine8(rp, x, y, ant, amesa->imageline, amesa->temprp);
	  DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", ant, x, y);
	  dp = amesa->imageline;
	  x += ant;
	  ant = 0;
	}
	else
	  x++;
      }
    }
    if (ant) {
      WritePixelLine8(rp, x, y, ant, amesa->imageline, amesa->temprp);
      DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", ant, x, y);
    }
  }
  else {							/*  Slower  */
    int i;

    DEBUGOUT(1, "SLOW\n");
    for (i = 0; i < n; i++, x++) {
      if (*mask++) {
	/* draw pixel (x[i],y[i]) using index[i] */
	SetAPen(rp, penconv[(unsigned char)index[i]]);
	DEBUGOUT(4, "   index[%d] = 0x%x\n", i, index[i]);
	WritePixel(rp, x, y);
	DEBUGOUT(3, "  WritePixel(%d, %d)\n", x, y);
      }
    }
  }
}

static void amigaWriteCI8Span(const GLcontext *ctx, GLuint n, GLint x, GLint y,
			      const GLubyte index[],
			      const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  unsigned char *dp;
  unsigned long *penconv = amesa->penconv;
  register struct RastPort *rp = amesa->rp;

  y = FIXy(y);
  x = FIXx(x);
  DEBUGOUT(1, "amigaWriteCI8Span(%d, %d, %d): ", n, x, y);

  if ((dp = amesa->imageline) && amesa->temprp) {		/*  if imageline and temporary rastport have been */
    int ant, i;							/*  allocated then use fastversion  */

    DEBUGOUT(1, "FAST\n");
    ant = 0;
    for (i = 0; i < n; i++) {					/*  draw pixel (x[i],y[i]) using index[i]  */
      if (*mask++) {
	ant++;
	*dp++ = penconv[(unsigned char)index[i]];
      }
      else {
	if (ant) {
	  WritePixelLine8(rp, x, y, ant, amesa->imageline, amesa->temprp);
          DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", n, x, y);
	  dp = amesa->imageline;
	  x += ant;
	  ant = 0;
	}
	else
	  x++;
      }
    }
    if (ant) {
      WritePixelLine8(rp, x, y, ant, amesa->imageline, amesa->temprp);
      DEBUGOUT(3, "  WritePixelLine8(%d, %d, %d)\n", n, x, y);
    }
  }
  else {							/*  Slower  */
    int i;

    DEBUGOUT(1, "SLOW\n");
    for (i = 0; i < n; i++, x++) {
      if (*mask++) {
	/* draw pixel (x[i],y[i]) using index[i] */
	SetAPen(rp, penconv[(unsigned char)index[i]]);
	WritePixel(rp, x, y);
	DEBUGOUT(3, "  WritePixel(%d, %d)\n", x, y);
      }
    }
  }
}

static void amigaWriteMonoCISpan(const GLcontext *ctx, GLuint n, GLint x, GLint y, const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;

  y = FIXy(y);
  x = FIXx(x);
  DEBUGOUT(1, "amigaWriteMonoCISpan(%d, %d, %d): \n", n, x, y);

  SetAPen(amesa->rp, amesa->pixel);

  i = 0;
  while (i < n) {
    while (!*mask++ && i < n) {
      i++;
      x++;
    }

    if (i < n) {
      Move(amesa->rp, x, y);
      DEBUGOUT(3, "  Move(%d, %d)\n", x, y);
      while (*mask++ && i < n) {
	i++;
	x++;
      }
      Draw(amesa->rp, x, y);
      DEBUGOUT(3, "  Draw(%d, %d)\n", x, y);
    }
  }
}

/**********************************************************************/
/*****        write spans of RGBA pixels doublebuffered           *****/
/**********************************************************************/

static void amigaWriteRGBASpanDB(const GLcontext *ctx, GLuint n, GLint x, GLint y,
				 CONST GLubyte rgba[][4], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register unsigned char *db;

  DEBUGOUT(1, "amigaWriteRGBASpanDB(%d, %d, %d)\n", n, FIXx(x), FIXy(y));

  db = amesa->BackArray + FIXxy(x, y);

  /* Slower */
  if (mask) {
    for (i = 0; i < n; i++) {
      if (*mask++) {
	/* draw pixel (x[i],y[i]) using index[i] */
	*db = PL_RGBA((unsigned char)rgba[i][0], (unsigned char)rgba[i][1], (unsigned char)rgba[i][2]);
      }
      db++;
    }
  }
  else {
    for (i = n - 1; i >= 0; i--) {					/*  draw pixel (x[i],y[i]) */
      *db++ = PL_RGBA((unsigned char)rgba[0][0], (unsigned char)rgba[0][1], (unsigned char)rgba[0][2]);
      ((ULONG *)rgba)++;
    }
  }
}

static void amigaWriteRGBSpanDB(const GLcontext *ctx, GLuint n, GLint x, GLint y,
				CONST GLubyte rgb[][3], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register unsigned char *db;

  DEBUGOUT(1, "amigaWriteRGBSpanDB(%d, %d, %d)\n", n, FIXx(x), FIXy(y));

  db = amesa->BackArray + FIXxy(x, y);
  /*
   * Slower 
   */
  if (mask) {
    for (i = 0; i < n; i++) {
      if (*mask++) {
	/* draw pixel (x[i],y[i]) using index[i] */
	*db = PL_RGBA((unsigned char)rgb[i][0], (unsigned char)rgb[i][1], (unsigned char)rgb[i][2]);
      }
      db++;
    }
  }
  else {
    for (i = n - 1; i >= 0; i--)					/*  draw pixel (x[i],y[i]) */
      *db++ = PL_RGBA((unsigned char)rgb[0][0], (unsigned char)rgb[0][1], (unsigned char)rgb[0][2]);
      ((unsigned char *)rgb) += 3;
  }
}

static void amigaWriteCI32SpanDB(const GLcontext *ctx, GLuint n, GLint x, GLint y,
				 const GLuint index[],
				 const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register unsigned char *db;
  register unsigned long *penconv = amesa->penconv;

  DEBUGOUT(1, "amigaWriteCI32SpanDB(%d, %d, %d)\n", n, FIXx(x), FIXy(y));

  db = amesa->BackArray + FIXxy(x, y);

  /* Slower */
  if (mask) {
    for (i = 0; i < n; i++) {
      if (*mask++) {
	/* draw pixel (x[i],y[i]) using index[i] */
	*db = penconv[(unsigned char)index[i]];
	DEBUGOUT(4, "   index[%d] = 0x%x\n", i, index[i]);
      }
      db++;
    }
  }
  else
    for (i = n - 1; i >= 0; i--) {
      /* draw pixel (x[i],y[i]) using index[i] */
      DEBUGOUT(4, "   index[%d] = 0x%x\n", n - i + 1, *index);
      *db++ = penconv[(unsigned char)*index++];
    }
}

static void amigaWriteCI8SpanDB(const GLcontext *ctx, GLuint n, GLint x, GLint y,
				const GLubyte index[],
				const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register unsigned char *db;
  register unsigned long *penconv = amesa->penconv;

  DEBUGOUT(1, "amigaWriteCI8SpanDB(%d, %d, %d)\n", n, FIXx(x), FIXy(y));

  db = amesa->BackArray + FIXxy(x, y);

  /* Slower */
  if (mask) {
    for (i = 0; i < n; i++) {
      if (*mask++) {
	/* draw pixel (x[i],y[i]) using index[i] */
	*db = penconv[(unsigned char)index[i]];
      }
      db++;
    }
  }
  else
    for (i = n - 1; i >= 0; i--) {
      /* draw pixel (x[i],y[i]) using index[i] */
      *db++ = penconv[(unsigned char)*index++];
    }
}

static void amigaWriteMonoCISpanDB(const GLcontext *ctx, GLuint n, GLint x, GLint y,
				   const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register unsigned char *db;

  DEBUGOUT(1, "amigaWriteMonoCISpanDB(%d, %d, %d)\n", n, FIXx(x), FIXy(y));

  db = amesa->BackArray + FIXxy(x, y);

  /* Slower */
  if (mask) {
    /* draw pixel (x[i],y[i]) using index[i] */
    for (i = n - 1; i >= 0; i--) {
      if (*mask++) {
	*db = amesa->pixel;
      }
      db++;
    }
  }
  else
    /* draw pixel (x[i],y[i]) using index[i] */
    for (i = n - 1; i >= 0; i--)
      *db++ = amesa->pixel;
}

/**********************************************************************/
/*****        read spans of RGBA pixels                           *****/
/**********************************************************************/
/* Here we should check if the size of the colortable is <256 */

static void amigaReadRGBASpan(const GLcontext *ctx, GLuint n, GLint x, GLint y,
			      GLubyte rgba[][4])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  register unsigned char *db;

  y = FIXy(y);
  x = FIXx(x);
  DEBUGOUT(1, "amigaReadRGBASpan(%d, %d, %d)\n", n, x, y);

  if ((db = amesa->imageline) && amesa->temprp) {
    int i;

    ReadPixelLine8(amesa->rp, x, y, n, db, amesa->temprp);
    DEBUGOUT(3, "  ReadPixelLine8(%d, %d, %d)\n", n, x, y);
    for (i = n - 1; i >= 0; i--)
      *((ULONG *)rgba)++ = GetIndex(*db++);
  }
  else {
    int i;

    for (i = n - 1; i >= 0; i--, x++) {
      *((ULONG *)rgba)++ = GetIndex(ReadPixel(amesa->rp, x, y));
      DEBUGOUT(3, "  ReadPixel(%d, %d)\n", x, y);
    }
  }
}

static void amigaReadCI32Span(const GLcontext *ctx, GLuint n, GLint x, GLint y, GLuint index[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  register unsigned char *db;

  y = FIXy(y);
  x = FIXx(x);
  DEBUGOUT(1, "amigaReadCI32Span(%d, %d, %d)\n", n, x, y);

  if (amesa->temprp && (db = amesa->imageline)) {
    int i;

    ReadPixelLine8(amesa->rp, x, y, n, db, amesa->temprp);
    DEBUGOUT(3, "  ReadPixelLine8(%d, %d, %d)\n", n, x, y);
    for (i = n - 1; i >= 0; i--)
      *index++ = *db++;
  }
  else {
    int i;

    for (i = n - 1; i >= 0; i--, x++) {
      *index++ = ReadPixel(amesa->rp, x, y);
      DEBUGOUT(3, "  ReadPixel(%d, %d)\n", x, y);
    }
  }
}

/**********************************************************************/
/*****        read spans of RGBA pixels doublebuffered            *****/
/**********************************************************************/

static void amigaReadRGBASpanDB(const GLcontext *ctx, GLuint n, GLint x, GLint y,
			        GLubyte rgba[][4])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register unsigned char *db;

  DEBUGOUT(1, "amigaReadRGBASpanDB(%d, %d, %d)\n", n, FIXx(x), FIXy(y));

  db = amesa->BackArray + FIXxy(x, y);

  for (i = n - 1; i >= 0; i--, x++)
    *((ULONG *)rgba)++ = GetIndex(*db++);
}

static void amigaReadCI32SpanDB(const GLcontext *ctx, GLuint n, GLint x, GLint y, GLuint index[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register unsigned char *db;

  DEBUGOUT(1, "amigaReadCI32SpanDB(%d, %d, %d)\n", n, FIXx(x), FIXy(y));

  db = amesa->BackArray + FIXxy(x, y);

  for (i = n - 1; i >= 0; i--)
    *index++ = *db++;
}

/**********************************************************************/
/*****        write arrays of RGBA pixels                         *****/
/**********************************************************************/

static void amigaWriteRGBAPixels(const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[],
				 CONST GLubyte rgba[][4], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register struct RastPort *rp = amesa->rp;

  DEBUGOUT(1, "amigaWriteRGBAPixels(%d)\n", n);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      /* write pixel x[i], y[i] using rgba[i][0],rgba[i][1],rgba[i][2],rgba[i][3] */
      SetAPen(rp, PL_RGBA((unsigned char)rgba[i][0], (unsigned char)rgba[i][1], (unsigned char)rgba[i][2]));
      WritePixel(rp, FIXx(x[i]), FIXy(y[i]));
      DEBUGOUT(3, "  WritePixel(%d, %d)\n", FIXx(x[i]), FIXy(y[i]));
    }
  }
}

static void amigaWriteCI32Pixels(const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[],
				 const GLuint index[], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  register unsigned long *penconv = amesa->penconv;
  int i;
  register struct RastPort *rp = amesa->rp;

  DEBUGOUT(1, "amigaWriteCI32Pixels(%d)\n", n);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      SetAPen(rp, penconv[(unsigned char)index[i]]);
      DEBUGOUT(4, "   index[%d] = 0x%x\n", i, index[i]);
      WritePixel(rp, FIXx(x[i]), FIXy(y[i]));
      DEBUGOUT(3, "  WritePixel(%d, %d)\n", FIXx(x[i]), FIXy(y[i]));
    }
  }
}

static void amigaWriteMonoCIPixels(const GLcontext *ctx, GLuint n,
				   const GLint x[], const GLint y[],
				   const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register struct RastPort *rp = amesa->rp;

  DEBUGOUT(1, "amigaWriteMonoCIPixels(%d)\n", n);

  SetAPen(rp, amesa->pixel);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      /* write pixel x[i], y[i] using current index */
      WritePixel(rp, FIXx(x[i]), FIXy(y[i]));
      DEBUGOUT(3, "  WritePixel(%d, %d)\n", FIXx(x[i]), FIXy(y[i]));
    }
  }
}

/**********************************************************************/
/*****        write arrays of RGBA pixels doublebuffered          *****/
/**********************************************************************/

static void amigaWriteRGBAPixelsDB(const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[],
				   CONST GLubyte rgba[][4], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;

  DEBUGOUT(1, "amigaWriteRGBAPixelsDB(%d)\n", n);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      amesa->BackArray[FIXxy(x[i], y[i])] = PL_RGBA((unsigned char)rgba[i][0], (unsigned char)rgba[i][1], (unsigned char)rgba[i][2]);
    }
  }
}

static void amigaWriteCI32PixelsDB(const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[],
				   const GLuint index[], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  register unsigned long *penconv = amesa->penconv;
  int i;

  DEBUGOUT(1, "amigaWriteCI32PixelsDB(%d)\n", n);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      amesa->BackArray[FIXxy(x[i], y[i])] = penconv[(unsigned char)index[i]];
      DEBUGOUT(4, "   index[%d] = 0x%x\n", i, index[i]);
    }
  }
}

static void amigaWriteMonoCIPixelsDB(const GLcontext *ctx, GLuint n,
				     const GLint x[], const GLint y[],
				     const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;

  DEBUGOUT(1, "amigaWriteMonoCIPixelsDB(%d)\n", n);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      amesa->BackArray[FIXxy(x[i], y[i])] = amesa->pixel;
    }
  }
}

/**********************************************************************/
/*****                       Read arrays of pixels                          *****/
/**********************************************************************/
/* Read an array of color index pixels. */

static void amigaReadRGBAPixels(const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[],
				GLubyte rgba[][4], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register struct RastPort *rp = amesa->rp;

  DEBUGOUT(1, "amigaReadRGBAPixels(%d)\n", n);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      *((ULONG *)(&rgba[i][0])) = GetIndex(ReadPixel(rp, FIXx(x[i]), FIXy(y[i])));
      DEBUGOUT(3, "  ReadPixel(%d, %d)\n", FIXx(x[i]), FIXy(y[i]));
    }
  }
}

static void amigaReadCI32Pixels(const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[],
				GLuint index[], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;
  register struct RastPort *rp = amesa->rp;

  DEBUGOUT(1, "amigaReadCI32Pixels(%d)\n", n);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      /* index[i] = read_pixel x[i], y[i] */
      index[i] = ReadPixel(rp, FIXx(x[i]), FIXy(y[i]));
      DEBUGOUT(3, "  ReadPixel(%d, %d)\n", FIXx(x[i]), FIXy(y[i]));
    }
  }
}

/**********************************************************************/
/***** Read arrays of pixels doublebuffered                       *****/
/**********************************************************************/
/* Read an array of color index pixels. */

static void amigaReadRGBAPixelsDB(const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[],
				GLubyte rgba[][4], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;

  DEBUGOUT(1, "amigaReadRGBAPixelsDB(%d)\n", n);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      *((ULONG *) & rgba[i][0]) = GetIndex(amesa->BackArray[FIXxy(x[i], y[i])]);
    }
  }
}

static void amigaReadCI32PixelsDB(const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[],
				GLuint index[], const GLubyte mask[])
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;
  int i;

  DEBUGOUT(1, "amigaReadCI32PixelsDB(%d)\n", n);

  for (i = 0; i < n; i++) {
    if (*mask++) {
      /* index[i] = read_pixel x[i], y[i] */
      index[i] = amesa->BackArray[FIXxy(x[i], y[i])];
    }
  }
}

/**********************************************************************/
/*****                  amiga/Mesa Private Functions                        *****/
/**********************************************************************/

static GLboolean amigaSetBuffer(GLcontext *ctx, GLenum mode)
{
  /*
   * set the current drawing/reading buffer, return GL_TRUE or GL_FALSE 
   * for success/failure 
   *
   * TODO implemed a set of buffers 
   */
  if (mode == GL_FRONT) {
    return (GL_TRUE);
  }
  else if (mode == GL_BACK) {
    return (GL_TRUE);
  }
  else {
    return (GL_FALSE);
  }
}

BOOL allocTempRPort(struct amigamesa_context * amesa)
{
  struct RastPort *temprp;

  DEBUGOUT(1, "allocTempRPort()\n");

  if ((temprp = AllocVecPooled(amesaPool, sizeof(struct RastPort)))) {
    CopyMem(amesa->rp, temprp, sizeof(struct RastPort));

    temprp->Layer = NULL;

    if ((temprp->BitMap = AllocBitMap(amesa->FixedWidth, 1,
				      amesa->rp->BitMap->Depth, BMF_MINPLANES, amesa->rp->BitMap))) {
      /*  temprp->BytesPerRow == (((width+15)>>4)<<1) */
      amesa->temprp = temprp;
      return TRUE;
    }
    FreeVecPooled(amesaPool, (ULONG *)temprp);
  }
  printf("Error allocating temporary rastport");
  return FALSE;
}

void freeTempRPort(struct amigamesa_context *amesa)
{
  DEBUGOUT(1, "freeTempRPort\n");

  if (amesa->temprp) {
    FreeBitMap(amesa->temprp->BitMap);
    FreeVecPooled(amesaPool, (ULONG *)amesa->temprp);
  }
  amesa->temprp = NULL;
}

/*
 * Create a new rastport to use as a back buffer.
 * Input:  width, height - size in pixels
 *        depth - number of bitplanes
 */

struct RastPort *makeRPort(int width, int height, int depth, struct BitMap *friendbm)
{
  struct RastPort *rp;
  struct BitMap *bm;

  if ((bm = AllocBitMap(width, height, depth, BMF_CLEAR | BMF_MINPLANES, friendbm))) {
    if ((rp = (struct RastPort *)AllocVecPooled(amesaPool, sizeof(struct RastPort)))) {
      InitRastPort(rp);
      rp->BitMap = bm;
      return rp;
    }
    else {
      FreeBitMap(bm);
      return 0;
    }
  }
  else
    return 0;
}

/*
 * Deallocate a rastport.
 */

void destroyRPort(struct RastPort *rp)
{
  WaitBlit();
  FreeBitMap(rp->BitMap);
  free(rp);
}

/*
 * Color_buf is a array of pens equals the drawing area
 * it's for faster dubbelbuffer rendering
 * Whent it's time for bufferswitch just use c2p and copy.
 */

unsigned char *allocPenBackArray(int width, int height, int bytes)
{
  unsigned char *ret = (AllocVecPooled(amesaPool, width * height * bytes));

  BltClear(ret, width * height * bytes, 1);
  return ret;
}

void destroyPenBackArray(unsigned char * buf)
{
  FreeVecPooled(amesaPool, (ULONG *)buf);
}

/*
 * Construct a temporary raster for use by the given rasterport.
 * Temp rasters are used for polygon drawing.
 */

BOOL makeTempRaster(struct RastPort *rp)
{
  BOOL OK = TRUE;
  unsigned long width, height;
  PLANEPTR p;
  struct TmpRas *tmpras;

  if (rp == 0) {
    printf("Zero rp\n");
    return (FALSE);
  }
  width = rp->BitMap->BytesPerRow * 8;
  height = rp->BitMap->Rows;

  /*
   * allocate structures 
   */
  if ((p = AllocRaster(width, height))) {
    if ((tmpras = (struct TmpRas *)AllocVecPooled(amesaPool, sizeof(struct TmpRas)))) {
      if (InitTmpRas(tmpras, p, ((width + 15) >> 4) * height)) {
	rp->TmpRas = tmpras;
      }
      else
	OK = FALSE;
    }
    else
      OK = FALSE;
  }
  else
    return (FALSE);

  if (OK)
    return (TRUE);
  else {
    printf("Error when allocationg TmpRas\n");
    if (tmpras)
      FreeVecPooled(amesaPool, (ULONG *)tmpras);
    if (p)
      FreeRaster(p, width, height);
    return (FALSE);
  }
}

BOOL allocArea(struct RastPort *rp)
{
  BOOL OK = TRUE;
  struct AreaInfo *areainfo;
  UWORD *pattern;
  APTR vbuffer;

  areainfo = (struct AreaInfo *)AllocVecPooled(amesaPool, sizeof(struct AreaInfo));
  if (areainfo != 0) {
    pattern = (UWORD *) AllocVecPooled(amesaPool, sizeof(UWORD));
    if (pattern != 0) {
      *pattern = 0xffff;					/*  @@@ org: 0xffffffff */

      vbuffer = (APTR) AllocVecPooled(amesaPool, MAX_POLYGON * 5 * sizeof(WORD));
      if (vbuffer != 0) {
	/*
	 * initialize 
	 */
	InitArea(areainfo, vbuffer, MAX_POLYGON);
	/*
	 * bind to rastport 
	 */
	rp->AreaPtrn = pattern;
	rp->AreaInfo = areainfo;
	rp->AreaPtSz = 0;
      }
      else
	OK = FALSE;
    }
    else
      OK = FALSE;
  }
  else
    OK = FALSE;

  if (OK)
    return (OK);
  else {
    printf("Error when allocationg AreaBuffers\n");
    if (areainfo) {
      FreeVecPooled(amesaPool, (ULONG *)areainfo);
      if (pattern) {
        FreeVecPooled(amesaPool, (ULONG *)pattern);
        if (vbuffer)
          FreeVecPooled(amesaPool, (ULONG *)vbuffer);
      }
    }
    return (OK);
  }
}

static void freeArea(struct RastPort *rp)
{
  if (rp->AreaInfo) {
    if (rp->AreaInfo->VctrTbl)
      FreeVecPooled(amesaPool, (ULONG *)rp->AreaInfo->VctrTbl);
    if (rp->AreaPtrn) {
      FreeVecPooled(amesaPool, (ULONG *)rp->AreaPtrn);
      rp->AreaPtrn = NULL;
    }
    FreeVecPooled(amesaPool, (ULONG *)rp->AreaInfo);
    rp->AreaInfo = NULL;
  }
}

/*
 * Destroy a temp raster.
 */

void destroyTempRaster(struct RastPort *rp)
{
  /*
   * bitmap 
   */

  unsigned long width, height;

  width = rp->BitMap->BytesPerRow * 8;
  height = rp->BitMap->Rows;

  if (rp->TmpRas) {
    if (rp->TmpRas->RasPtr)
      FreeRaster(rp->TmpRas->RasPtr, width, height);
    FreeVecPooled(amesaPool, (ULONG *)rp->TmpRas);
    rp->TmpRas = NULL;

  }
}

void AllocOneLine(struct amigamesa_context *amesa)
{
  if (amesa->imageline)
    FreeVecPooled(amesaPool, (ULONG *)amesa->imageline);
  if (amesa->depth <= 8) {
    amesa->imageline = AllocVecPooled(amesaPool, (amesa->width + 15) & 0xfffffff0);		/*  One Line  */
  }
  else {
    amesa->imageline = AllocVecPooled(amesaPool, ((amesa->width + 3) & 0xfffffff0) * 4);	/*  One Line  */
  }
}

void FreeOneLine(struct amigamesa_context *amesa)
{
  if (amesa->imageline) {
    FreeVecPooled(amesaPool, (ULONG *)amesa->imageline);
    amesa->imageline = NULL;
  }
}

/**********************************************************************/
/*****                  amiga/Mesa private init/despose/resize       *****/
/**********************************************************************/

static void amigaStandardResize(GLcontext *ctx, GLuint * width, GLuint * height)
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;

  *width = amesa->width;
  *height = amesa->height;
  DEBUGOUT(1, "amigaStandardResize(%d, %d)\n", *width, *height);

  if (!((amesa->width == (amesa->front_rp->Layer->bounds.MaxX - amesa->front_rp->Layer->bounds.MinX + 1 - amesa->left - amesa->right)) &&
	(amesa->height == (amesa->front_rp->Layer->bounds.MaxY - amesa->front_rp->Layer->bounds.MinY + 1 - amesa->bottom - amesa->top)))) {
    FreeOneLine(amesa);

    amesa->FixedWidth = amesa->RealWidth = amesa->front_rp->Layer->bounds.MaxX - amesa->front_rp->Layer->bounds.MinX + 1;
    amesa->FixedHeight = amesa->RealHeight = amesa->front_rp->Layer->bounds.MaxY - amesa->front_rp->Layer->bounds.MinY + 1;

    *width = amesa->width = amesa->RealWidth - amesa->left - amesa->right;
    *height = amesa->height = amesa->RealHeight - amesa->bottom - amesa->top;
    amesa->depth = GetBitMapAttr(amesa->front_rp->BitMap, BMA_DEPTH);
    DEBUGOUT(2, " Resize(%d, %d)\n", *width, *height);

    if (amesa->depth <= 8) {
      destroyTempRaster(amesa->rp);				/*  deallocate temp raster  */
      freeTempRPort(amesa);
    }

    if (amesa->visual->db_flag) {
      if (amesa->back_rp) {					/*  Free double buffer  */
	destroyRPort(amesa->back_rp);
      }
      if ((amesa->back_rp = makeRPort(amesa->RealWidth, amesa->RealHeight, amesa->depth, amesa->rp->BitMap)) == NULL) {
	amesa->rp = amesa->front_rp;
	printf("To little mem free. Couldn't allocate Dubblebuffer in this size.\n");
      }
      else {
	amesa->rp = amesa->back_rp;
      }
    }

    if (amesa->depth <= 8) {
      if (!makeTempRaster(amesa->rp))
        printf("Error allocating TmpRasterPort\n");
      allocTempRPort(amesa);
    }

    AllocOneLine(amesa);
  }
}

static void amigaStandardResizeDB(GLcontext *ctx, GLuint * width, GLuint * height)
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;

  *width = amesa->width;
  *height = amesa->height;
  DEBUGOUT(1, "amigaStandardResizeDB(%d, %d)\n", *width, *height);

  if (!((amesa->width == (amesa->rp->Layer->bounds.MaxX - amesa->rp->Layer->bounds.MinX + 1 - amesa->left - amesa->right)) &&
	(amesa->height == (amesa->rp->Layer->bounds.MaxY - amesa->rp->Layer->bounds.MinY + 1 - amesa->bottom - amesa->top)))) {
    freeTempRPort(amesa);

    amesa->RealWidth = amesa->rp->Layer->bounds.MaxX - amesa->rp->Layer->bounds.MinX + 1;
    amesa->RealHeight = amesa->rp->Layer->bounds.MaxY - amesa->rp->Layer->bounds.MinY + 1;
    amesa->FixedWidth = ((amesa->RealWidth + 15) >> 4) << 4;
    amesa->FixedHeight = amesa->RealHeight;

    *width = amesa->width = amesa->RealWidth - amesa->left - amesa->right;
    *height = amesa->height = amesa->RealHeight - amesa->bottom - amesa->top;
    amesa->depth = GetBitMapAttr(amesa->rp->BitMap, BMA_DEPTH);
    DEBUGOUT(2, " Resize(%d, %d)\n", *width, *height);

    if (amesa->visual->db_flag && amesa->BackArray) {
      destroyPenBackArray(amesa->BackArray);
      if (!(amesa->BackArray = allocPenBackArray(amesa->RealWidth, amesa->RealHeight, amesa->depth <= 8 ? 1 : 4))) {
	printf("amigaMesa Error Can't allocate new PenArray in that size.\n");
	/*       amigaStandardInit(amesa); */
      }
    }

    if (amesa->depth <= 8)
      allocTempRPort(amesa);

    DEBUGOUT(1, " amesa->RealWidth =%d\n", amesa->RealWidth);
    DEBUGOUT(1, " amesa->RealHeight=%d\n", amesa->RealHeight);
    DEBUGOUT(1, " amesa->width =%d\n", amesa->width);
    DEBUGOUT(1, " amesa->height=%d\n", amesa->height);
    DEBUGOUT(1, " amesa->left  =%d\n", amesa->left);
    DEBUGOUT(1, " amesa->bottom=%d\n", amesa->bottom);
    DEBUGOUT(1, " amesa->right =%d\n", amesa->right);
    DEBUGOUT(1, " amesa->top   =%d\n", amesa->top);
    DEBUGOUT(1, " amesa->depth =%d\n", amesa->depth);
  }
}

void amigaStandardDispose(struct amigamesa_context *amesa)
{
  DEBUGOUT(1, "amigaStandardDispose\n");

  FreeOneLine(amesa);
  if (amesa->depth <= 8) {
    FreeCMap(amesa->Screen);
    freeArea(amesa->rp);
    destroyTempRaster(amesa->rp);
    freeTempRPort(amesa);
  }

  if (amesa->visual->rgb_flag) {
    if (amesa->rgb_buffer) {
      FreeVecPooled(amesaPool, (ULONG *)amesa->rgb_buffer);
    }
  }

  if (amesa->back_rp) {
    destroyRPort(amesa->back_rp);
    amesa->back_rp = NULL;
  }
}

void amigaStandardDisposeDB(struct amigamesa_context *amesa)
{
  DEBUGOUT(1, "amigaStandardDisposeDB\n");
  /*  printf("I'm closing down\n");getchar(); */

  if (amesa->depth <= 8) {
    FreeCMap(amesa->Screen);
    freeTempRPort(amesa);
  }

  if (amesa->BackArray) {
    destroyPenBackArray(amesa->BackArray);
  }
}

void amigaStandardSwapBuffer(struct amigamesa_context *amesa)
{
  DEBUGOUT(1, "amigaStandardSwapBuffer()\n");

  if (amesa->back_rp) {
    unsigned char minterm = 0xc0;
    struct gl_viewport_attrib *vport = &amesa->gl_ctx->Viewport;

    /*  int x = amesa->left; */
    /*  int y = amesa->RealHeight - amesa->bottom - amesa->height; */

    ClipBlit(amesa->back_rp,
	     FIXx(vport->X),
	     FIXy(vport->Y) - vport->Height,	/*  from  */
	     amesa->front_rp,
	     FIXx(vport->X),
	     FIXy(vport->Y) - vport->Height,	/*  to  */
	     vport->Width,
	     vport->Height,						/*  size  */
	     minterm);
    DEBUGOUT(2, " ClipBlit(%lx, %d, %d, %lx, %d, %d, %d, %d)\n",
	     amesa->back_rp,
	     FIXx(vport->X),
	     FIXy(vport->Y) - vport->Height,
	     amesa->front_rp,
	     FIXx(vport->X),
	     FIXy(vport->Y) - vport->Height,
	     vport->Width,
	     vport->Height);
    /*
     * TODO Use these cordinates insted more efficent if you only use part of screen
     * RectFill(amesa->rp,FIXx(CC.Viewport.X),FIXy(CC.Viewport.Y)-CC.Viewport.Height+1,FIXx(CC.Viewport.X)+CC.Viewport.Width-1,FIXy(CC.Viewport.Y));
     */
  }
  else {
    DEBUGOUT(2, " no amesa->back_rp\n");
  }
}

void amigaStandardSwapBufferDB(struct amigamesa_context *amesa)
{
  struct gl_viewport_attrib *vport = &amesa->gl_ctx->Viewport;

  DEBUGOUT(1, "amigaStandardSwapBufferDB()\n");
  DEBUGOUT(2, " WritePixelArray8(%d, %d, %d, %d);\n",
	   FIXx(vport->X),
	   FIXy(vport->Y) - vport->Height,
	   FIXx(vport->X) + vport->Width - 1,
	   FIXy(vport->Y) - 1);

  WritePixelArray8(amesa->rp,
		   FIXx(vport->X),
		   FIXy(vport->Y) - vport->Height,
		   FIXx(vport->X) + vport->Width - 1,
		   FIXy(vport->Y) - 1,
		   amesa->BackArray,
		   amesa->temprp);
  /*WriteChunkyPixels(amesa->rp,
		    FIXx(vport->X),
		    FIXy(vport->Y) - vport->Height,
		    FIXx(vport->X) + vport->Width - 1,
		    FIXy(vport->Y) - 1,
		    amesa->BackArray,
		    amesa->RealWidth);*/
}

static void amigaFinish(void)
{
  /* implements glFinish if possible */
}

static void amigaFlush(GLcontext *ctx)
{
  amigaMesaContext amesa = (amigaMesaContext) ctx->DriverCtx;

  /* implements glFlush if possible */
  /* amigaStandardSwapBufferDB(ctx->DriverCtx); */
  (*amesa->SwapBuffer)(amesa);
}

BOOL
amigaStandardInit(struct amigamesa_context *amesa, struct TagItem *tagList)
{
  DEBUGOUT(1, "amigaStandardInit()\n");

  if (!(amesa->window = (struct Window *)GetTagData(AMA_Window, 0, tagList))) {
    if (!(amesa->rp = (struct RastPort *)GetTagData(AMA_RastPort, 0, tagList))) {
      LastError = AMESA_RASTPORT_TAG_MISSING;
      return (FALSE);
    }
    if (!(amesa->Screen = (struct Screen *)GetTagData(AMA_Screen, 0, tagList))) {
      LastError = AMESA_SCREEN_TAG_MISSING;
      return (FALSE);
    }
  }
  else {
    amesa->rp = amesa->window->RPort;
    amesa->Screen = amesa->window->WScreen;
  }

  amesa->depth = GetBitMapAttr(amesa->rp->BitMap, BMA_DEPTH);

  amesa->FixedWidth = amesa->RealWidth = amesa->rp->Layer->bounds.MaxX - amesa->rp->Layer->bounds.MinX + 1;
  amesa->FixedHeight = amesa->RealHeight = amesa->rp->Layer->bounds.MaxY - amesa->rp->Layer->bounds.MinY + 1;

  amesa->left = GetTagData(AMA_Left, 0, tagList);
  amesa->bottom = GetTagData(AMA_Bottom, 0, tagList);
  amesa->right = GetTagData(AMA_Right, 0, tagList);
  amesa->top = GetTagData(AMA_Top, 0, tagList);
  amesa->width = GetTagData(AMA_Width, amesa->RealWidth - amesa->left - amesa->right, tagList);
  amesa->height = GetTagData(AMA_Height, amesa->RealHeight - amesa->bottom - amesa->top, tagList);

  if (!amesa->right)
    amesa->right = amesa->RealWidth - amesa->left - amesa->width;
  if (!amesa->top)
    amesa->top = amesa->RealHeight - amesa->bottom - amesa->height;

  amesa->front_rp = amesa->rp;
  amesa->back_rp = NULL;
  /*  amesa->rp = amesa->front_rp; */

  /*  amesa->gl_ctx->BufferWidth = amesa->width; */
  /*  amesa->gl_ctx->BufferHeight = amesa->height; */
  amesa->pixel = 0;							/*  current drawing pen  */

  AllocCMap(amesa->Screen);

  if (amesa->visual->db_flag == GL_TRUE) {
    DEBUGOUT(1, "doublebuffering inside amigastandard");
    if ((amesa->back_rp = makeRPort(amesa->RealWidth, amesa->RealHeight, amesa->depth, amesa->rp->BitMap)) != NULL) {
      amesa->gl_ctx->Color.DrawBuffer = GL_BACK;
      amesa->rp = amesa->back_rp;
    }
    else {
      printf("makeRPort failed\n");
      amesa->gl_ctx->Color.DrawBuffer = GL_FRONT;
    }
  }
  else {
    amesa->gl_ctx->Color.DrawBuffer = GL_FRONT;
  }
  AllocOneLine(amesa);						/*  A linebuffer for WritePixelLine  */

  if (!makeTempRaster(amesa->rp))
    printf("Error allocating TmpRastPort\n");
  allocTempRPort(amesa);
  allocArea(amesa->rp);

  amesa->InitDD = amigaStandardDDPointers;				/*  standard drawing */
  amesa->Dispose = amigaStandardDispose;
  amesa->SwapBuffer = amigaStandardSwapBuffer;
  (*amesa->InitDD)(amesa->gl_ctx);

  DEBUGOUT(1, " amesa->RealWidth =%d\n", amesa->RealWidth);
  DEBUGOUT(1, " amesa->RealHeight=%d\n", amesa->RealHeight);
  DEBUGOUT(1, " amesa->width =%d\n", amesa->width);
  DEBUGOUT(1, " amesa->height=%d\n", amesa->height);
  DEBUGOUT(1, " amesa->left  =%d\n", amesa->left);
  DEBUGOUT(1, " amesa->bottom=%d\n", amesa->bottom);
  DEBUGOUT(1, " amesa->right =%d\n", amesa->right);
  DEBUGOUT(1, " amesa->top   =%d\n", amesa->top);
  DEBUGOUT(1, " amesa->depth =%d\n", amesa->depth);

  return (TRUE);
}

BOOL
amigaStandardInitDB(struct amigamesa_context * amesa, struct TagItem * tagList)
{
  DEBUGOUT(1, "amigaStandardInitDB()\n");

  if (!(amesa->window = (struct Window *)GetTagData(AMA_Window, 0, tagList))) {
    if (!(amesa->rp = (struct RastPort *)GetTagData(AMA_RastPort, 0, tagList))) {
      LastError = AMESA_RASTPORT_TAG_MISSING;
      return (FALSE);
    }
    if (!(amesa->Screen = (struct Screen *)GetTagData(AMA_Screen, 0, tagList))) {
      LastError = AMESA_SCREEN_TAG_MISSING;
      return (FALSE);
    }
  }
  else {
    amesa->rp = amesa->window->RPort;
    amesa->Screen = amesa->window->WScreen;
  }

  amesa->depth = GetBitMapAttr(amesa->rp->BitMap, BMA_DEPTH);

  amesa->RealWidth = amesa->rp->Layer->bounds.MaxX - amesa->rp->Layer->bounds.MinX + 1;
  amesa->RealHeight = amesa->rp->Layer->bounds.MaxY - amesa->rp->Layer->bounds.MinY + 1;
  amesa->FixedWidth = ((amesa->RealWidth + 15) >> 4) << 4;
  amesa->FixedHeight = amesa->RealHeight;

  amesa->left = GetTagData(AMA_Left, 0, tagList);
  amesa->bottom = GetTagData(AMA_Bottom, 0, tagList);
  amesa->right = GetTagData(AMA_Right, 0, tagList);
  amesa->top = GetTagData(AMA_Top, 0, tagList);
  amesa->width = GetTagData(AMA_Width, amesa->RealWidth - amesa->left - amesa->right, tagList);
  amesa->height = GetTagData(AMA_Height, amesa->RealHeight - amesa->bottom - amesa->top, tagList);

  if (!amesa->right)
    amesa->right = amesa->RealWidth - amesa->left - amesa->width;
  if (!amesa->top)
    amesa->top = amesa->RealHeight - amesa->bottom - amesa->height;

  /*  amesa->gl_ctx->BufferWidth = amesa->width; */
  /*  amesa->gl_ctx->BufferHeight = amesa->height; */
  amesa->pixel = 0;							/* current drawing pen */

  AllocCMap(amesa->Screen);						/*  colormap  */
  allocTempRPort(amesa);

  if (amesa->visual->db_flag) {
    amesa->BackArray = allocPenBackArray(amesa->FixedWidth, amesa->FixedHeight, amesa->depth <= 8 ? 1 : 4);
    DEBUGOUT(1, "byte array at -------->0x%x ends at 0x%x size=0x%x (%d)\n", amesa->BackArray, amesa->BackArray + (((amesa->RealWidth + 15) >> 4) << 4) * (amesa->RealHeight + 1), (((amesa->RealWidth + 15) >> 4) << 4) * (amesa->RealHeight + 1), (((amesa->RealWidth + 15) >> 4) << 4) * (amesa->RealHeight + 1));
    amesa->gl_ctx->Color.DrawBuffer = GL_BACK;
  }
  else {
    amesa->gl_ctx->Color.DrawBuffer = GL_FRONT;
    return (FALSE);
  }

  amesa->InitDD = amigaFasterDDPointers;				/*  fast drawing */
  amesa->Dispose = amigaStandardDisposeDB;
  amesa->SwapBuffer = amigaStandardSwapBufferDB;
  (*amesa->InitDD)(amesa->gl_ctx);

  DEBUGOUT(1, " amesa->RealWidth =%d\n", amesa->RealWidth);
  DEBUGOUT(1, " amesa->RealHeight=%d\n", amesa->RealHeight);
  DEBUGOUT(1, " amesa->width =%d\n", amesa->width);
  DEBUGOUT(1, " amesa->height=%d\n", amesa->height);
  DEBUGOUT(1, " amesa->left  =%d\n", amesa->left);
  DEBUGOUT(1, " amesa->bottom=%d\n", amesa->bottom);
  DEBUGOUT(1, " amesa->right =%d\n", amesa->right);
  DEBUGOUT(1, " amesa->top   =%d\n", amesa->top);
  DEBUGOUT(1, " amesa->depth =%d\n", amesa->depth);

  return (TRUE);
}

/**********************************************************************/
/**********************************************************************/
/*
 * Initialize all the pointers in the DD struct.  Do this whenever   
 * a new context is made current or we change buffers via setBuffer! 
 */
void amigaStandardDDPointers(GLcontext *ctx)
{
  /*  amigaMesaContext amesa = ctx->DriverCtx; */
  DEBUGOUT(1, "amigaStandardDDPointers()\n");

  ctx->Driver.RendererString = amigaRendererString;

  ctx->Driver.UpdateState = amigaStandardDDPointers;
  ctx->Driver.ClearIndex = amigaClearIndex;
  ctx->Driver.ClearColor = amigaClearColor;
  ctx->Driver.Clear = amigaClear;

  ctx->Driver.Index = amigaSetIndex;
  ctx->Driver.Color = amigaSetColor;

  ctx->Driver.IndexMask = amigaIndexMask;
  ctx->Driver.ColorMask = amigaColorMask;

  ctx->Driver.SetBuffer = amigaSetBuffer;
  ctx->Driver.GetBufferSize = amigaStandardResize;

  ctx->Driver.PointsFunc = amigaChoosePointsFunction(ctx);
  ctx->Driver.LineFunc = amigaChooseLineFunction(ctx);
  ctx->Driver.TriangleFunc = amigaChooseTriangleFunction(ctx);

  /*
   * Pixel/span writing functions: 
   */
  ctx->Driver.WriteRGBASpan = amigaWriteRGBASpan;
  ctx->Driver.WriteRGBSpan = amigaWriteRGBSpan;
  ctx->Driver.WriteCI32Span = amigaWriteCI32Span;
  ctx->Driver.WriteCI8Span = amigaWriteCI8Span;
  ctx->Driver.WriteMonoRGBASpan = amigaWriteMonoCISpan;
  ctx->Driver.WriteMonoCISpan = amigaWriteMonoCISpan;

  ctx->Driver.WriteRGBAPixels = amigaWriteRGBAPixels;
  ctx->Driver.WriteCI32Pixels = amigaWriteCI32Pixels;
  ctx->Driver.WriteMonoRGBAPixels = amigaWriteMonoCIPixels;
  ctx->Driver.WriteMonoCIPixels = amigaWriteMonoCIPixels;

  /*
   * Pixel/span reading functions: 
   */
  ctx->Driver.ReadRGBASpan = amigaReadRGBASpan;
  ctx->Driver.ReadCI32Span = amigaReadCI32Span;

  ctx->Driver.ReadRGBAPixels = amigaReadRGBAPixels;
  ctx->Driver.ReadCI32Pixels = amigaReadCI32Pixels;
}

void amigaFasterDDPointers(GLcontext *ctx)
{
  /*  amigaMesaContext amesa = ctx->DriverCtx; */
  DEBUGOUT(1, "amigaFasterDDPointers()\n");

  ctx->Driver.RendererString = amigaRendererStringDB;

  ctx->Driver.UpdateState = amigaFasterDDPointers;
  ctx->Driver.ClearIndex = amigaClearIndex;
  ctx->Driver.ClearColor = amigaClearColor;
  ctx->Driver.Clear = amigaClearDB;

  ctx->Driver.Index = amigaSetIndex;
  ctx->Driver.Color = amigaSetColor;

  ctx->Driver.IndexMask = amigaIndexMask;
  ctx->Driver.ColorMask = amigaColorMask;

  ctx->Driver.SetBuffer = amigaSetBuffer;
  ctx->Driver.GetBufferSize = amigaStandardResizeDB;

  ctx->Driver.Flush = amigaFlush;

  ctx->Driver.PointsFunc = amigaChoosePointsFunctionDB(ctx);
  ctx->Driver.LineFunc = amigaChooseLineFunctionDB(ctx);
  ctx->Driver.TriangleFunc = amigaChooseTriangleFunctionDB(ctx);

  /*
   * Pixel/span writing functions: 
   */
  ctx->Driver.WriteRGBASpan = amigaWriteRGBASpanDB;
  ctx->Driver.WriteRGBSpan = amigaWriteRGBSpanDB;
  ctx->Driver.WriteCI32Span = amigaWriteCI32SpanDB;
  ctx->Driver.WriteCI8Span = amigaWriteCI8SpanDB;
  ctx->Driver.WriteMonoRGBASpan = amigaWriteMonoCISpanDB;
  ctx->Driver.WriteMonoCISpan = amigaWriteMonoCISpanDB;

  ctx->Driver.WriteRGBAPixels = amigaWriteRGBAPixelsDB;
  ctx->Driver.WriteCI32Pixels = amigaWriteCI32PixelsDB;
  ctx->Driver.WriteMonoRGBAPixels = amigaWriteMonoCIPixelsDB;
  ctx->Driver.WriteMonoCIPixels = amigaWriteMonoCIPixelsDB;

  /*
   * Pixel/span reading functions: 
   */
  ctx->Driver.ReadRGBASpan = amigaReadRGBASpanDB;
  ctx->Driver.ReadCI32Span = amigaReadCI32SpanDB;

  ctx->Driver.ReadRGBAPixels = amigaReadRGBAPixelsDB;
  ctx->Driver.ReadCI32Pixels = amigaReadCI32PixelsDB;
}

#undef DEBUGPRINT
