
 /* SD_BufferSubs.c
    - Functions for handling external drivers -
    (c) 1990-94 by Andreas R. Kleinert
    Last changes : 28.09.1994
 */

#include "svdriver.h"

ULONG __saveds __asm SVD_SetGfxBuffer(      register __a1 struct SVDriverHandle *SVDriverHandle_a1, register __a2 struct SV_GfxBuffer *buffer, register __a3 ULONG future);
ULONG __saveds __asm SVD_DisplayGfxBuffer(  register __a1 struct SVDriverHandle *SVDriverHandle_a1, register __a2 ULONG future);

long __saveds __stdargs SVLI_SVDScreen(struct SVDriverHandle *SVDriverHandle, ULONG ai_mode_id);
long __saveds __stdargs SVLI_SVDSetCMAP(struct SVDriverHandle *SVDriverHandle, struct Screen *screen, long colornum);


/* *************************************************** */
/* *						     * */
/* * SVD_SetGfxBuffer :                              * */
/* *						     * */
/* *************************************************** */

ULONG __saveds __asm SVD_SetGfxBuffer(  register __a1 struct SVDriverHandle *SVDriverHandle_a1, register __a2 struct SV_GfxBuffer *buffer, register __a3 ULONG future)
{
 struct SVDriverHandle *SVDriverHandle = SVDriverHandle_a1;
 ULONG retval = SVERR_NO_ERROR;

 if(!SVDriverHandle) return(SVERR_NO_HANDLE);

 if(!buffer) return(SVERR_ILLEGAL_ACCESS);

 SVDriverHandle->ah_SV_GfxBuffer = buffer;

 return(retval);
}

/* *************************************************** */
/* *						     * */
/* * SVD_DisplayGfxBuffer :                          * */
/* *						     * */
/* *************************************************** */

ULONG __saveds __asm SVD_DisplayGfxBuffer(  register __a1 struct SVDriverHandle *SVDriverHandle_a1, register __a2 ULONG future)
{
 struct SVDriverHandle *SVDriverHandle = SVDriverHandle_a1;
 ULONG retval = SVERR_NO_ERROR;
 ULONG width, height, depth, colnum, linebytes, bmpwidth, mode_id, j;
 UBYTE *buffer, *bufferptr, *planeptr;

 struct RastPort *rp;
 struct BitMap	 *bm;
 struct ViewPort *vp;

 if(!SVDriverHandle->ah_SV_GfxBuffer) return(SVERR_ILLEGAL_ACCESS);

 bufferptr = buffer = SVDriverHandle->ah_SV_GfxBuffer->svgfx_Buffer;
 if(!buffer) return(SVERR_ILLEGAL_ACCESS);

 if(SVDriverHandle->ah_SV_GfxBuffer->svgfx_BufferType > SVGFX_BUFFERTYPE_ONEPLANE) return(SVERR_ACTION_NOT_SUPPORTED);

 /* Open Screen */

 mode_id = SVDriverHandle->ah_SV_GfxBuffer->svgfx_ViewMode32;

 if(!SVLI_SVDScreen(SVDriverHandle, mode_id)) return(SVERR_NO_SCREEN);

 rp = (struct RastPort *) &(SVDriverHandle->ah_Screen->RastPort);
 bm = (struct BitMap   *) SVDriverHandle->ah_Screen->RastPort.BitMap;
 vp = (struct ViewPort *) &(SVDriverHandle->ah_Screen->ViewPort);

 width     = SVDriverHandle->ah_SV_GfxBuffer->svgfx_Width;
 height    = SVDriverHandle->ah_SV_GfxBuffer->svgfx_Height;
 depth     = SVDriverHandle->ah_SV_GfxBuffer->svgfx_ColorDepth;
 colnum    = 1 << depth;

 bmpwidth = ((width + 31) >> 5) << 5;

 if(SVDriverHandle->ah_SV_GfxBuffer->svgfx_BufferType == SVGFX_BUFFERTYPE_BITPLANE)
       linebytes = (long) SVDriverHandle->ah_SV_GfxBuffer->svgfx_BytesPerLine;
  else linebytes = (long) bm->BytesPerRow;


 /* Read Palette */

 SVLI_SVDSetCMAP(SVDriverHandle, SVDriverHandle->ah_Screen, colnum);


 /* Decoding */

 planeptr  = (UBYTE *) N;

 if(SVDriverHandle->ah_SV_GfxBuffer->svgfx_BufferType == SVGFX_BUFFERTYPE_BITPLANE)
  {
   if(linebytes == bm->BytesPerRow)
    {
     ULONG prod_1 = height * linebytes;

     for(j=0;j<depth;j++) CopyMem(bufferptr + j*prod_1, bm->Planes[j], prod_1);
    }else
    {
              ULONG copybytes, pskipbytes, buf_ptradd1;
     register ULONG i, j;
     register UBYTE *bptr, *pptr;

     pskipbytes = bm->BytesPerRow;

     if(pskipbytes < linebytes) copybytes = pskipbytes;
      else                      copybytes = linebytes;

     buf_ptradd1 = height*linebytes;

     for(j=0;j<depth;j++)
      {
       bptr = (UBYTE *) bufferptr + (buf_ptradd1 * j);
       pptr = (UBYTE *) bm->Planes[j];

       for(i=0; i<height; i++)
        {
         CopyMem(bptr, pptr, copybytes);

         bptr += linebytes;
         pptr += pskipbytes;
        }
      }
    }
  }

 if(SVDriverHandle->ah_SV_GfxBuffer->svgfx_BufferType == SVGFX_BUFFERTYPE_ONEPLANE)
  {
   if(depth <= 8)
    {
     /* Maybe, there are Graphic Cards, which allow 8 Bits colordepth
        via an intuition-compatible AGA-emulation, but nevertheless
        we cannot use V39-functions as in AGA.svdriver !!!
     */

     struct RastPort *tmp_rp;
     UBYTE           *bptr;
     UBYTE           *linebuffer;
     UWORD            i, j;

     linebuffer = (APTR) AllocVec(width, MEMF_CLEAR|MEMF_PUBLIC);
     if(linebuffer)
      {
       tmp_rp = (APTR) AllocVec(sizeof(struct RastPort), MEMF_CLEAR|MEMF_PUBLIC);
       if(tmp_rp)
        {
         InitRastPort(tmp_rp);

         tmp_rp->BitMap = AllocVec(sizeof(struct BitMap), MEMF_CLEAR|MEMF_PUBLIC);
         if(tmp_rp->BitMap)
          {
           InitBitMap(tmp_rp->BitMap, depth, bmpwidth, 1);

           for(i=0; i<depth; i++)
            {
             tmp_rp->BitMap->Planes[i] = (APTR) AllocRaster(bmpwidth, 1);
             if(!tmp_rp->BitMap->Planes[i])
              {
               retval = SVERR_NO_MEMORY;

               break;
              }
            }

           if(!retval)
            {
             ULONG wm8 = (width>>3)<<3;

             bptr = bufferptr;

             for(j=0; j<height; j++, bptr+=width)
              {
               CopyMem(bptr, linebuffer, width);

               WritePixelLine8(rp, 0, j, wm8, linebuffer, tmp_rp);
              }
            }

           for(i=0; i<8; i++) if(tmp_rp->BitMap->Planes[i]) FreeRaster(tmp_rp->BitMap->Planes[i], bmpwidth, 1);

           FreeVec(tmp_rp->BitMap);
          }else retval = SVERR_NO_MEMORY;

         FreeVec(tmp_rp);
        }else retval = SVERR_NO_MEMORY;

       FreeVec(linebuffer);

      }else retval = SVERR_NO_MEMORY;

    }else
    {
     /* Insert code for handling color depths > 8
        (future AGA or AAA features ?)
     */

     retval = SVERR_UNKNOWN_PARAMETERS;
    }
  }

 ScreenToFront(SVDriverHandle->ah_Screen);

 return(retval);
}

/* *************************************************** */
/* *						     * */
/* * SVLI_SVDScreen : SVD Screen Opening Function    * */
/* *						     * */
/* *************************************************** */

struct TextAttr __aligned chip topazfont = { (STRPTR) "topaz.font", TOPAZ_EIGHTY, FS_NORMAL, FPF_ROMFONT };

long __saveds __stdargs SVLI_SVDScreen(struct SVDriverHandle *SVDriverHandle, ULONG ai_mode_id)
{
 long ai_width, ai_height, ai_depth;
 struct Rectangle __aligned rect;

 if(!SVDriverHandle->ah_SV_GfxBuffer) return(FALSE);


 /* Get and set Standard Screen Dimensions */

 ai_width  = SVDriverHandle->ah_SV_GfxBuffer->svgfx_Width;
 ai_height = SVDriverHandle->ah_SV_GfxBuffer->svgfx_Height;
 ai_depth  = SVDriverHandle->ah_SV_GfxBuffer->svgfx_ColorDepth;


 /* Get and/or set Screen, Window and IDCMP Flags */

 if(!SVDriverHandle->ah_ScreenType)  SVDriverHandle->ah_ScreenType  = CUSTOMSCREEN;
 if(!SVDriverHandle->ah_WindowIDCMP) SVDriverHandle->ah_WindowIDCMP = IDCMP_MOUSEBUTTONS | IDCMP_VANILLAKEY;
 if(!SVDriverHandle->ah_WindowFlags) SVDriverHandle->ah_WindowFlags = WFLG_BACKDROP | WFLG_BORDERLESS | WFLG_NOCAREREFRESH | WFLG_SIMPLE_REFRESH;

 if(!QueryOverscan(ai_mode_id, &rect, OSCAN_TEXT))
  {
   rect.MinX = 0;
   rect.MaxX = ai_width;
   rect.MinY = 0;
   rect.MaxY = ai_height;
  }

 /* Open Screen like needed for SVD Displaying */

 SVDriverHandle->ah_Screen = OpenScreenTags( NULL, SA_Left,        0,
                         			   SA_Top,	   0,
                        			   SA_Width,	   ai_width,
				                   SA_Height,	   ai_height,
				                   SA_Depth,	   ai_depth,
				                   SA_Font,	  &topazfont,
				                   SA_Type,	   SVDriverHandle->ah_ScreenType,
				                   SA_DisplayID,   ai_mode_id,
				                   SA_Title,	   "Please wait ...",
				                   SA_AutoScroll,  TRUE,
				                   SA_DClip,       &rect,
				                   SA_Behind,      TRUE,
				                   TAG_END );

 if(!SVDriverHandle->ah_Screen) return(FALSE);


 /* Open Window like needed for SVD Displaying */

 SVDriverHandle->ah_Window = OpenWindowTags(N,
			    WA_Left,	     0,
			    WA_Top,	     0,
			    WA_Width,	     SVDriverHandle->ah_Screen->Width,
			    WA_Height,	     SVDriverHandle->ah_Screen->Height,
			    WA_DetailPen,    1,
			    WA_BlockPen,     2,
			    WA_IDCMP,	     SVDriverHandle->ah_WindowIDCMP,
			    WA_Flags,	     SVDriverHandle->ah_WindowFlags,
			    WA_CustomScreen, SVDriverHandle->ah_Screen,
			    TAG_END,	     N);

 if(!SVDriverHandle->ah_Window) return(FALSE);

 ActivateWindow(SVDriverHandle->ah_Window);

 return(TRUE);
}

/* *************************************************** */
/* *						     * */
/* * SVLI_SVDSetCMAP : Set ColorMap (RGB8 / RGB 32)  * */
/* *						     * */
/* *************************************************** */

long __saveds __stdargs SVLI_SVDSetCMAP(struct SVDriverHandle *SVDriverHandle, struct Screen *screen, long colornum)
{
 struct ViewPort *vp;
 long i;

 if(SVDriverHandle && screen)
  {
   vp = (struct ViewPort *) &(screen->ViewPort);

   if(OS_VER < 39)
    {
     /* Standard / ECS "4 Bit of 12 Bit" Colors (RGB4) */

     for(i=0;i<colornum;i++) SetRGB4(vp, i, SVDriverHandle->ah_SV_GfxBuffer->svgfx_Colors[i][0]>>4, SVDriverHandle->ah_SV_GfxBuffer->svgfx_Colors[i][1]>>4, SVDriverHandle->ah_SV_GfxBuffer->svgfx_Colors[i][2]>>4);
    }else
    {
     /* AGA "8 Bit of 32 Bit" Colors (RGB32) */

     ULONG r,g,b;

     for(i=0;i<colornum;i++)
      {
       r  = (ULONG) SVDriverHandle->ah_SV_GfxBuffer->svgfx_Colors[i][0];
       r |= (r<<24 | r<<16 | r<<8);

       g  = (ULONG) SVDriverHandle->ah_SV_GfxBuffer->svgfx_Colors[i][1];
       g |= (g<<24 | g<<16 | g<<8);

       b  = (ULONG) SVDriverHandle->ah_SV_GfxBuffer->svgfx_Colors[i][2];
       b |= (b<<24 | b<<16 | b<<8);

       SetRGB32(vp, i, r, g, b);
      }
    }
  }

 return(FALSE);
}
