//////////////////////////////////////////////////////////////////////////
//                                                                      //
//              INTEL CORPORATION PROPRIETARY INFORMATION               //
//                                                                      //
//      This software is supplied under the terms of a license          //
//      agreement or nondisclosure agreement with Intel Corporation     //
//      and may not be copied or disclosed except in accordance         //
//      with the terms of that agreement.                               //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <dciddi.h>
#include "dcihdw.h"
#include "debug.h"

/* This struct, BANK, needed for ClipBlit() */
typedef struct 
{
	POINT   pt;         // x, y cordinate of posn within band
	DWORD   dOffset;    // offset from beginning of image (for YVU formats)
	WORD    wWidth;     // width of scanline in image
	WORD    wHeight;    // number of scanlines in image
	WORD    wBPP;       // Bytes Per Pixel
	WORD    wBPS;       // Bytes Per Scanline
	WORD    wSel;       // selector of bank
	DWORD   dStart;     // start offset
	DWORD   dStride;    // stride
}   BANK;

/* Local Functions */
POINT Offset2Point(BANK FAR *bank, DWORD dwibOff );
void InitializeBank(BANK FAR *, LPOFFINSTINFO oinst );

void FAR ClipBlit( LPOFFINSTINFO oinst )
{   
	DWORD   dwibSrc = 0,         
			dwibDst = 0,
			dwibTmpOff = 0,
			dwcBytesPerLine,
			dwcLines,           
			dwcRemainder = 0;
	int     iWall = oinst->iInfoWall,
			iDoor=0;
	BANK    FrameBuf;
	BOOL    bNeedSwitch = TRUE,
			bNewStripe = TRUE;
	
	// there should be valid data in minst->lpSysBuf already before coming here.
	// init frame buffer vars
	InitializeBank( (BANK FAR*) &FrameBuf, oinst);       

/*	// we have a new cliplist so init InfoList and then toggle bNewList flag
	if (oinst->bNewList)
	{
	    iWall = InitializeInfoList( (RECTL FAR *) oinst->lpClip, 
							(LPCLIPRECTINFO) oinst->lpClipInfo, 
							(WORD) (oinst->rDst.right - oinst->rDst.left), 
 						    FrameBuf.wBPP,
							(int)oinst->cRects,
                            &(oinst->rDst));
		oinst->bNewList = FALSE;
		oinst->iInfoWall = iWall;
	} else
		iWall = oinst->iInfoWall;
*/		                    
	// calc buffer stride, in bytes. needed for asm routine
	dwcBytesPerLine = (DWORD) ((oinst->rDst.right - oinst->rDst.left) * 
								(oinst->OffSurface.dciInfo.dwBitCount>>3));

	// Setup what can be setup now.
	FrameBuf.wSel = oinst->wSelScrn;
	FrameBuf.dStride = oinst->lStrideScrn;
                                     
	// traverse through lpInfo til' the end is reached
	while (iWall != -1)
	{           
		// reset dwibSrc to offset that's first byte to write in this strip
		// set dwibSrc to take into account no. of lines to skip AS WELL AS no. of 
		// columns to skip before hitting real, displayable area - dwibSrc addresses the 
		// image in system memory.

		dwibSrc += (oinst->lpClipInfo[iDoor].dwcGap * dwcBytesPerLine) + oinst->lpClipInfo[iDoor+1].dwcGap;
		// reset dwibDst to a similar location as dwibSrc, except dwibDst points to 
		// the screen, not system memory, where (0,0) marks the upper left corner of the
		// display window.
		dwibDst += (oinst->lpClipInfo[iDoor].dwcGap * oinst->lStrideScrn) + oinst->lpClipInfo[iDoor+1].dwcGap;

		// dwcLines marks the number of similar width rows to be written            
		dwcLines  = oinst->lpClipInfo[iWall].dwcLen;
		
		while (dwcLines)
		{                           
			// first time we enter here, bNeedSwitch is always true.
			if (bNeedSwitch)
			{   
				FrameBuf.pt = Offset2Point((BANK FAR*)&FrameBuf, dwibSrc);  

				// Need to offset following not just according to dwibSrc but
				//	also according to framebuffer memory which starts at (0,0).
				dwibDst = (DWORD)((oinst->rDst.left + FrameBuf.pt.x) * FrameBuf.wBPP) +
					(DWORD)((oinst->rDst.top  + FrameBuf.pt.y) * FrameBuf.dStride);
							
				bNeedSwitch = FALSE;
			}
				
			if (bNewStripe)
			{   // this is to make sure the existing asm routines do not have to change ... 
				// we want to munch dwibSrc so that we feed the first valid point to GetDMA,
				// but when it comes to using it, we want to go back to what we had earlier, where
				// dwibSrc points to the first point on the strip.
				dwibSrc    -= oinst->lpClipInfo[iDoor+1].dwcGap;
				dwibDst    -= oinst->lpClipInfo[iDoor+1].dwcGap;
				bNewStripe  = FALSE;
			}
			cblitLines(oinst->wSelCBlit, 
				(LPDWORD)&dwibSrc, 
				dwcBytesPerLine,   
				FrameBuf.wSel,
				(LPDWORD)&dwibDst, 
				FrameBuf.dStride,  
				(LPCLIPRECTINFO)&(oinst->lpClipInfo[iDoor]),                           
				dwcLines
				);						
			dwcLines = 0;
		} // strip done -  end while dwclines       
		
		iDoor      = (int) iWall + 1;       
		iWall      = (int) oinst->lpClipInfo[iWall].dwfWall;
		bNewStripe = TRUE;
	} // frame done end iwall != -1

} // ClipBlit()


void InitializeBank(BANK FAR *bank, LPOFFINSTINFO oinst)
{
	bank->pt.x      = 0;
	bank->pt.y      = 0;
	bank->dOffset   = 0L;                                  
	bank->wWidth    = (WORD)(oinst->rDst.right - oinst->rDst.left);

	// do all but last BAND worth. These done with no interpolation
	bank->wHeight   = (WORD)(oinst->rDst.bottom - oinst->rDst.top); 
	bank->wBPP      = (WORD)(oinst->OffSurface.dciInfo.dwBitCount>>3);                 
	bank->wBPS      = bank->wWidth * bank->wBPP;        
	bank->dStride   = 0L;                           
} 


/*
 * Offset2Point() given a BANK and an offset in the src buffer, returns the point in the image
 */
POINT Offset2Point( BANK FAR *bank, DWORD dwibOff )
{
	POINT ptTmp;
	DWORD dw;
	
	dw      = (dwibOff%((DWORD)(bank->wBPS)))/((DWORD)(bank->wBPP));    // integer div
	ptTmp.x = (int) dw;
	dw      = dwibOff/((DWORD)(bank->wBPS));                            // integer div
	ptTmp.y = (int) dw;
	
	return ptTmp;
}
