/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/*****************************************************************************
 *
 * SOURCE FILE NAME = TMPPUT.C
 *
 * AUTHOR           = Joe Celi
 *
 * DATE CREATED     = 6/9/94
 *
 *
 * VERSION = V2.1
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS
 *
 * NOTES        All HW level I/O has been stripped out!
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_WIN
#define INCL_GPI
#define INCL_DOS
#define INCL_VMANDDI
#define INCL_GRADDIO
#include <os2.h>
#include <string.h>
#include "next.h"
#include "endive.h"
#include "template.h"

extern FBINFO          FBInfo;
extern PUTIMAGEINFO    PutInfo;
extern M2SINFO         M2S;
extern BOOL            fInterpolation;
extern BOOL            fForceInterpolation;
extern BOOL            fForcedIntState;
extern BOOL            fForeground;
extern BYTE            bPelToDWORDShift;
extern LONG            lExtraScans;

/*****************************************************************************
 *
 *  FUNCTION NAME:        PutImage()
 *
 *  DESCRIPTIVE NAME:
 *
 *  FUNCTION:             Blast a frame to the screen.
 *
 *  ENTRY POINT:
 *
 *  INPUT:                PIMAGEPACK
 *
 *  EXIT-NORMAL:          RC_SUCCESS
 *
 *  EXIT-ERROR:           RC_ERROR
 *
 *  EFFECTS:
 *
 *  NOTES:                The format of the input image can vary BUT
 *                        it should always be in one of the formats
 *                        we supplied via the ENDIVE_QUERY function.
 *
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES:
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES:
 *
 ****************************************************************************/

ULONG PutImage( PIMAGEPACK p )
{

   ULONG  i;

   /* Weed out some possible paramater errors! */
   if( (!fForeground)                       ||
       (!p->ulDstXext)                      ||
       (!p->ulDstYext)                      ||
       (!p->ulSrcXext)                      ||
       (!p->ulSrcYext)                      ||
       (!p->pPutBuf->ulBytesPerScan) )
   {
      return(RC_ERROR);
   }

   /*
   ** Check to see if the ENDIVE wants us to use the
   ** HW interpolation.  The source image could be pre-
   ** dithered.  In that case ENDIVE will not ask us to
   ** use HW interpolation.
   **
   ** If this flag is off use HW interpolation if it is
   ** available (this depends on the video mode).
   **
   */
   if(p->ulFlags & IPF_DONT_INTERPOLATE)
   {
      PutInfo.fUseHWInterpol = FALSE;
   }
   else
   {
      PutInfo.fUseHWInterpol = fInterpolation;
   }

   /*
   ** This flag is only set via the undocumented API.
   ** This allows us to demonstrate the HW interpolation
   ** by toggling it on and off via an app.
   */
   if(fForceInterpolation)
      PutInfo.fUseHWInterpol = fForcedIntState;

   /* Image input color format */
   switch(p->pPutBuf->pColorInfo->fccColorEncoding)
   {
      case FOURCC_R565:
      case FOURCC_R555:
         PutInfo.bPF = 2;
         break;

      case FOURCC_RGB3:
      case FOURCC_BGR3:
         PutInfo.bPF = 3;
         break;

      case FOURCC_RGB4:
      case FOURCC_BGR4:
         PutInfo.bPF = 4;
         break;

      case FOURCC_LUT8:
         if(FBInfo.ulBPP != 8)
            return(RC_ERROR);
         PutInfo.bPF = 1;
         break;

      default:
         return(RC_ERROR);                   /* Image input not supported */

   }

   /* NOTE: POWERPLAY32 does not run in 24 bpp modes */
   switch(FBInfo.ulBPP)
   {
      case 8:
         /* Logic removed */
         break;

      case 16:
         /* Logic removed */
         break;

      default:
         return(RC_ERROR);
   }

   /*
   ** Adjust for bottom up blits.
   */
   if(p->pPutBuf->ulFlags & IBF_Y_ORG_BOTTOM)
   {
      PutInfo.ulDstOff = (p->ptlDstOrg.y + p->ulDstYext) *
                         (FBInfo.ulScanLineBytes >> 2) +
                         (p->ptlDstOrg.x >> bPelToDWORDShift);
   }
   else
   {
      PutInfo.ulDstOff = p->ptlDstOrg.y * (FBInfo.ulScanLineBytes >> 2) +
                         (p->ptlDstOrg.x >> bPelToDWORDShift);
   }

   for(i = 0; i < p->cVisRects; i++)
   {

      /*
      ** Check for invalid visible region coordinates.
      */
      if( (p->prctlVis[i].xLeft < 0)              ||
          (p->prctlVis[i].xRight > FBInfo.ulXres) ||
          (p->prctlVis[i].yTop < 0)               ||
          (p->prctlVis[i].yBottom > FBInfo.ulYres) )
      {
         return(RC_ERROR);
      }

      /*
      ** Check to see if the image is out of the visible region
      ** NOTE: The visible rectangles are inclusive/exclusive.
      */
      if( (p->ptlDstOrg.x >= p->prctlVis[i].xRight)                    ||
          (p->ptlDstOrg.y >= p->prctlVis[i].yBottom)                   ||
          ((p->ptlDstOrg.x + p->ulDstXext - 1) < p->prctlVis[i].xLeft) ||
          ((p->ptlDstOrg.y + p->ulDstYext - 1) < p->prctlVis[i].yTop) )
      {
         continue;
      }

      /*
      ** Removed POWERPLAY32 specific clipper calculation logic!
      ** This logic was performed here to achieve some HW/CPU
      ** overlap.  While POWERPLAY32 was busy with the blit we
      ** could calculate the next set of clipper values.
      */

      if(p->pPutBuf->ulType == IBT_SRC_VRAM)
      {
         if(ScreenToScreen(p, i))
            return(RC_ERROR);
      }
      else
      {
         if(MemToScreen(p, i))
            return(RC_ERROR);
      }

   }
   return(RC_SUCCESS);

} /* end of PutImage */

/*****************************************************************************
 *
 *  FUNCTION NAME:    MemToScreen()
 *
 *
 *  DESCRIPTIVE NAME:
 *
 *  FUNCTION:
 *
 *  ENTRY POINT:
 *
 *  INPUT:          pPIP - Pointer to the PIMAGEPACK data structure
 *
 *                  ulVisRectIndex - This ULONG can be used by this
 *                                   routine to optimize.  The higher
 *                                   level routine (PutImage) will call
 *                                   this routine for each visible rectangle.
 *                                   This routine can optimize based on the
 *                                   fact when ulVisRectIndex is greater then
 *                                   zero, the contents of the PIMAGEPACK
 *                                   data structure have not changed since the
 *                                   previous call.  Therefore, we may not have
 *                                   to reset all of the registers needed to
 *                                   blit this frame.
 *
 *  EXIT-NORMAL:
 *
 *  EXIT-ERROR:
 *
 *  EFFECTS:
 *
 *  NOTES:
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES:
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES:
 *
 ****************************************************************************/

ULONG MemToScreen( PIMAGEPACK pPIP, ULONG ulVisRectIndex )
{
   ULONG         ulImgOff;
   ULONG         cScansToDo;
   POINTL        ptlCurSrcPos;
   ULONG         ulCurCellHeight;
   BOOL          fFirst = TRUE;

   /*
   ** Before we modify any registers - wait for last operation to finish
   */
   WaitForHW();

   if(!ulVisRectIndex)
   {

      /*
      ** Check for error conditions.
      **
      ** If we don't have an offscreen buffer to work with
      ** then we cannot accelerate this operation.
      **
      ** If there is not enough room in the work buffer to fit one
      ** scan line then we cannot handle this operation.
      **
      */
      if((!pPIP->cWBBytes) || (pPIP->pPutBuf->ulBytesPerScan > pPIP->cWBBytes))
      {
         return(RC_ERROR);
      }

      M2S.ulWBOff = pPIP->ptlWBOrg.y * FBInfo.ulScanLineBytes +
                    ((pPIP->ptlWBOrg.x * FBInfo.ulBPP) >> 3);

      M2S.pbWBStart = pPIP->pVirtVRAM + M2S.ulWBOff;

      /*
      ** We will set up the cell height to the number of source
      ** scan lines that we can handle during each band.
      */
      M2S.cMaxScansPerPass = pPIP->cWBBytes / pPIP->pPutBuf->ulBytesPerScan;

      if(PutInfo.fUseHWInterpol)
         M2S.cBands = (pPIP->ulSrcYext + M2S.cMaxScansPerPass - 2) /
                          (M2S.cMaxScansPerPass - 1);
      else
         M2S.cBands = (pPIP->ulSrcYext + M2S.cMaxScansPerPass - 1) /
                          M2S.cMaxScansPerPass;

      M2S.ulCellHeight = M2S.cMaxScansPerPass;

      /*
      ** Adjust for for bottom up blits!
      ** Logic removed!
      */
   }

   /* Set the clipper */

   ulCurCellHeight = M2S.ulCellHeight;
   cScansToDo = pPIP->ulSrcYext;
   ptlCurSrcPos = pPIP->ptlSrcOrg;
   while(cScansToDo)
   {

      ulImgOff = (ptlCurSrcPos.y * pPIP->pPutBuf->ulBytesPerScan) +
                 (ptlCurSrcPos.x * PutInfo.bPF);


      memcpy( M2S.pbWBStart,
              pPIP->pPutBuf->pBits + ulImgOff,
              ulCurCellHeight * pPIP->pPutBuf->ulBytesPerScan );

      if(PutInfo.fUseHWInterpol)
      {
         if(fFirst)                                /* 1st pass uses all lines */
            cScansToDo -= ulCurCellHeight;
         else if (cScansToDo != ulCurCellHeight)   /* Mid passes use (max-1)  */
            cScansToDo -= ulCurCellHeight - 1;
         else                                      /* Last pass               */
            cScansToDo = 0;
         ptlCurSrcPos.y += ulCurCellHeight - 1;
      }
      else
      {
         cScansToDo -= ulCurCellHeight;
         ptlCurSrcPos.y += ulCurCellHeight;
      }

      fFirst = FALSE;

      /*
      ** Wait for this row to finish before starting next one.
      */
      WaitForHW();

   }
   return(RC_SUCCESS);

} /* end of MemToScreen */

/*****************************************************************************
 *
 *  FUNCTION NAME:    ScreenToScreen()
 *
 *
 *  DESCRIPTIVE NAME:
 *
 *  FUNCTION:
 *
 *  ENTRY POINT:
 *
 *  INPUT:          pPIP - Pointer to the PIMAGEPACK data structure
 *
 *                  ulVisRectIndex - This ULONG can be used by this
 *                                   routine to optimize.  The higher
 *                                   level routine (PutImage) will call
 *                                   this routine for each visible rectangle.
 *                                   This routine can optimize based on the
 *                                   fact when ulVisRectIndex is greater then
 *                                   zero, the contents of the PIMAGEPACK
 *                                   data structure have not changed since the
 *                                   previous call.  Therefore, we may not have
 *                                   to reset all of the registers needed to
 *                                   blit this frame.
 *
 *  EXIT-NORMAL:
 *
 *  EXIT-ERROR:
 *
 *  EFFECTS:
 *
 *  NOTES:
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES:
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES:
 *
 ****************************************************************************/

ULONG ScreenToScreen( PIMAGEPACK pPIP, ULONG ulVisRectIndex )
{
   ULONG         ulSrcOffset;

   /*
   ** Before we modify any registers - wait for last operation to finish
   */
   WaitForHW();

   if(!ulVisRectIndex)
   {

      /*
      ** Calc the source bitmap address
      **
      ** NOTE: We do not have to worry about this for
      **       the follow on vis rects.  Once we set
      **       the HW to this value it will remember
      **       it.
      */
      ulSrcOffset = pPIP->ptlSrcOrg.y * FBInfo.ulScanLineBytes +
                    ((pPIP->ptlSrcOrg.x * FBInfo.ulBPP) >> 3);

   }

   /*
   ** Set the clipper
   ** Logic removed!
   */

   /*
   ** Perform the blit
   ** Logic removed!
   */

   return(RC_SUCCESS);

} /* end of ScreenToScreen */
