// =============================================================================
// 							Class Implementation : COXSplashWnd
// =============================================================================
//

// Version: 9.3

// This software along with its related components, documentation and files ("The Libraries")
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.                      

// //////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "OXSplashWnd.h"

#ifdef OX_SPLASHWND_JPEG
#include "OXDIB.h"
#endif
#include <afxtempl.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// helper class COXSplashWndDIB

// Data members -------------------------------------------------------------
// protected:
	// DDB members:

	// CBitmap* m_pBitmap;
	// --- The loaded DDB bitmap 

	// CPalette* m_pPalette;		
	// --- The palette to use with the bitmap

	// DIB members:

	// BITMAPINFOHEADER m_bmih;	
	// --- The original bitmap header
	// CByteArray m_bits;			
	// --- The original bitmap bits
	// DWORD m_nWidthBits;			
	// --- Bits per scan line

	// The following members are used for quick access

	// int m_xMax;
	// --- Maximum x value in bitmap (zero-based)

	// int m_yMax; 
	// --- Maximum y value in bitmap (zero-based)

	// int m_nBitCount;
	// --- Bitmap bitcount

	// int m_nRightShift;
	// --- 8 - m_nBitCount

	// BOOL m_bTopdown;
	// --- Whether the bits are organized top-down or not

	// BYTE* m_pBits0;
	// ---- Pointer to the actual bits
// private:

// Member functions ---------------------------------------------------------
// public:
COXSplashWndDIB::COXSplashWndDIB()
	:
	m_pBitmap(NULL),
	m_pPalette(NULL),
	m_nWidthBits(0),
	m_xMax(0),
	m_yMax(0),
	m_nBitCount(0),
	m_nRightShift(0),
	m_bTopdown(FALSE),
	m_pBits0(NULL)
	{
	::ZeroMemory(&m_bmih, sizeof(m_bmih));
	}

COXSplashWndDIB::~COXSplashWndDIB()
	{
	delete m_pBitmap;
	delete m_pPalette;
	}

CBitmap* COXSplashWndDIB::GetBitmap()
	{
	return m_pBitmap;
	}

BOOL COXSplashWndDIB::GetBitmapInfo(BITMAP& bm)
	{
	if (m_pBitmap == NULL) 
		return FALSE;

	m_pBitmap->GetBitmap(&bm);
	return TRUE;
	}

BOOL COXSplashWndDIB::LoadResource(LPCTSTR lpszResourceName, BOOL bPrepareGetPixel)
{
	BOOL bResult = FALSE;

	HINSTANCE hInstance = NULL;
    HRSRC hRsrc = NULL;
    HGLOBAL hGlobal = NULL;
    HBITMAP hBitmapFinal = NULL;
	HPALETTE hPal = NULL;
    LPBITMAPINFOHEADER lpbi = NULL;
    HDC hdc = NULL;
    int iNumColors = 0;

	if (m_pBitmap != NULL)	
	{ 
		delete m_pBitmap;	 
		m_pBitmap  = NULL;
	}
	if (m_pPalette != NULL)	
	{ 
		delete m_pPalette; 
		m_pPalette = NULL;
	}

	hInstance = AfxFindResourceHandle(lpszResourceName, RT_BITMAP);
	if (hInstance != NULL)
		hRsrc = ::FindResource(hInstance, lpszResourceName, RT_BITMAP);
	if (hRsrc != NULL)
		hGlobal = ::LoadResource(hInstance, hRsrc);

	if (hGlobal != NULL)
	{
		lpbi = (LPBITMAPINFOHEADER)::LockResource(hGlobal);
		if (lpbi != NULL)
		{
			hdc = ::GetDC(NULL);
			if (hdc != NULL)
			{
				hPal = CreateDIBPalette ((LPBITMAPINFO)lpbi, iNumColors);
				if ((hPal == NULL) && (::GetDeviceCaps(hdc, SIZEPALETTE) == 256))
				{
					// .... Trying to show bitmap without palette on 256-color display
					//      so let's use halftone palette (better than nothing)
					hPal = ::CreateHalftonePalette(hdc);
				}
				if (hPal != NULL)
				{
					::SelectPalette(hdc, hPal, FALSE);
					::RealizePalette(hdc);
				}
		
				hBitmapFinal = ::CreateDIBitmap(hdc, (LPBITMAPINFOHEADER)lpbi,
					(LONG)CBM_INIT,	(LPSTR)lpbi + lpbi->biSize + 
					iNumColors * sizeof(RGBQUAD), (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
				if (hBitmapFinal != NULL)
				{
					m_pBitmap = new CBitmap;
					m_pBitmap->Attach(hBitmapFinal);
					if (hPal != NULL)
					{
						m_pPalette = new CPalette;
						m_pPalette->Attach(hPal);
					}
					if (bPrepareGetPixel)
						PrepareGetPixel(*lpbi, iNumColors);
					bResult = TRUE;
				}
				else
				{
					if(hPal!=NULL)
						::DeleteObject((HGDIOBJ)hPal);
				}

				::ReleaseDC(NULL,hdc);
			}
			::UnlockResource(hGlobal);
		}
		::FreeResource(hGlobal);
	}

    return bResult;
} 

#ifdef OX_SPLASHWND_JPEG
BOOL COXSplashWndDIB::LoadJPEGFile(LPCTSTR lpszFileName, BOOL bPrepareGetPixel)
{
	BOOL bResult = FALSE;

    HBITMAP hBitmapFinal = NULL;
	HPALETTE hPal = NULL;
    LPBITMAPINFOHEADER lpbi = NULL;
    HDC hdc = NULL;
    int iNumColors = 0;

	COXDIB dib;
	if(!dib.ReadJPEG(lpszFileName))
		return FALSE;
	CMemFile memFile;
	if (!dib.Write(&memFile,FALSE))
	{
		memFile.Close();
		return FALSE;
	}

	if (m_pBitmap != NULL)	
	{ 
		delete m_pBitmap;	 
		m_pBitmap  = NULL;
	}
	if (m_pPalette != NULL)	
	{ 
		delete m_pPalette; 
		m_pPalette = NULL;
	}

	if(memFile.GetLength()>0)
	{
		BYTE* pBuffer=(BYTE*)memFile.Detach();
		if(pBuffer!=NULL)
		{
			pBuffer=pBuffer+14;
			lpbi=(LPBITMAPINFOHEADER)pBuffer;
		
			hdc=::GetDC(NULL);
			if(hdc!=NULL)
			{
				hPal=CreateDIBPalette((LPBITMAPINFO)lpbi,iNumColors);
				if((hPal==NULL) && (::GetDeviceCaps(hdc,SIZEPALETTE)==256))
				{
					// .... Trying to show bitmap without palette on 256-color display
					//      so let's use halftone palette (better than nothing)
					hPal=::CreateHalftonePalette(hdc);
				}
				if(hPal!=NULL)
				{
					SelectPalette(hdc,hPal,FALSE);
					RealizePalette(hdc);
				}
		
				hBitmapFinal=::CreateDIBitmap(hdc,(LPBITMAPINFOHEADER)lpbi,
					(LONG)CBM_INIT,(LPSTR)lpbi+lpbi->biSize+
					iNumColors * sizeof(RGBQUAD),(LPBITMAPINFO)lpbi,DIB_RGB_COLORS);
				if(hBitmapFinal!=NULL)
				{
					m_pBitmap=new CBitmap;
					m_pBitmap->Attach(hBitmapFinal);
					if(hPal!=NULL)
					{
						m_pPalette=new CPalette;
						m_pPalette->Attach(hPal);
					}
					if (bPrepareGetPixel)
						PrepareGetPixel(*lpbi, iNumColors);
					bResult=TRUE;
				}
				else
				{
					if(hPal!=NULL)
						::DeleteObject((HGDIOBJ)hPal);
				}

				::ReleaseDC(NULL,hdc);
			}
			::free(pBuffer-14);
		}
	}

    return bResult;


}
#endif
BOOL COXSplashWndDIB::LoadFile(LPCTSTR lpszFileName, BOOL bPrepareGetPixel)
{
	BOOL bResult = FALSE;

    HBITMAP hBitmapFinal = NULL;
	HPALETTE hPal = NULL;
    LPBITMAPINFOHEADER lpbi = NULL;
    HDC hdc = NULL;
    int iNumColors = 0;

	CFile file;
	CMemFile memFile;
	CFileException fileException;
	if(!file.Open(lpszFileName,CFile::modeRead|CFile::shareDenyWrite,&fileException))
	{
		TRACE(_T("COXSplashWndDIB::LoadFile : Could not open DIB file : %s\n"), 
			lpszFileName);
		return FALSE;
	}
	if(!CopyFile(&memFile,&file))
	{
		TRACE(_T("COXSplashWndDIB::LoadFile : Could not copy DIB file : %s\n"), 
			lpszFileName);
		return FALSE;
	}
	file.Close();

	if (m_pBitmap != NULL)	
	{ 
		delete m_pBitmap;	 
		m_pBitmap  = NULL;
	}
	if (m_pPalette != NULL)	
	{ 
		delete m_pPalette; 
		m_pPalette = NULL;
	}

	if(memFile.GetLength()>0)
	{
		BYTE* pBuffer=(BYTE*)memFile.Detach();
		if(pBuffer!=NULL)
		{
			pBuffer=pBuffer+14;
			lpbi=(LPBITMAPINFOHEADER)pBuffer;
		
			hdc=::GetDC(NULL);
			if(hdc!=NULL)
			{
				hPal=CreateDIBPalette((LPBITMAPINFO)lpbi,iNumColors);
				if((hPal==NULL) && (::GetDeviceCaps(hdc,SIZEPALETTE)==256))
				{
					// .... Trying to show bitmap without palette on 256-color display
					//      so let's use halftone palette (better than nothing)
					hPal=::CreateHalftonePalette(hdc);
				}
				if(hPal!=NULL)
				{
					SelectPalette(hdc,hPal,FALSE);
					RealizePalette(hdc);
				}
		
				hBitmapFinal=::CreateDIBitmap(hdc,(LPBITMAPINFOHEADER)lpbi,
					(LONG)CBM_INIT,(LPSTR)lpbi+lpbi->biSize+
					iNumColors * sizeof(RGBQUAD),(LPBITMAPINFO)lpbi,DIB_RGB_COLORS);
				if(hBitmapFinal!=NULL)
				{
					m_pBitmap=new CBitmap;
					m_pBitmap->Attach(hBitmapFinal);
					if(hPal!=NULL)
					{
						m_pPalette=new CPalette;
						m_pPalette->Attach(hPal);
					}
					if (bPrepareGetPixel)
						PrepareGetPixel(*lpbi, iNumColors);
					bResult=TRUE;
				}
				else
				{
					if(hPal!=NULL)
						::DeleteObject((HGDIOBJ)hPal);
				}

				::ReleaseDC(NULL,hdc);
			}
			::free(pBuffer-14);
		}
	}

    return bResult;
} 


HPALETTE COXSplashWndDIB::CreateDIBPalette (LPBITMAPINFO lpbmi, int& nNumColors)
	{ 
	LPBITMAPINFOHEADER  lpbi = NULL;
	LPLOGPALETTE     lpPal = NULL;
	HANDLE           hLogPal = NULL;   
	HPALETTE         hPal = NULL;   
	int              i = 0;   

	// ... Initialize return variable
	nNumColors = 0;
   
	lpbi = (LPBITMAPINFOHEADER)lpbmi;   
	if (lpbi->biBitCount <= 8)
		nNumColors = (1 << lpbi->biBitCount);   
	else   
		nNumColors = 0;  // No palette needed for 24 BPP DIB   
   
	if (lpbi->biClrUsed > 0)   
		nNumColors = lpbi->biClrUsed;  // Use biClrUsed
   
	if (nNumColors != 0)
		{
		hLogPal = ::GlobalAlloc (GHND, sizeof (LOGPALETTE) +      
								  sizeof (PALETTEENTRY) * nNumColors);   
		lpPal = (LPLOGPALETTE) ::GlobalLock (hLogPal);      
		lpPal->palVersion    = (WORD)0x300;      
		lpPal->palNumEntries = (WORD)nNumColors;      
   
		for (i = 0;  i < nNumColors;  i++)      
			{
			lpPal->palPalEntry[i].peRed   = lpbmi->bmiColors[i].rgbRed;   	  
			lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen; 	    
			lpPal->palPalEntry[i].peBlue  = lpbmi->bmiColors[i].rgbBlue;  	   
			lpPal->palPalEntry[i].peFlags = 0;   	  
			}   	  
		hPal = ::CreatePalette (lpPal);      
		::GlobalUnlock (hLogPal);      
		::GlobalFree   (hLogPal);      
		}
	return hPal;   
	} 

BOOL COXSplashWndDIB::Draw(CDC* pDC)
{
	if (m_pBitmap == NULL)
		return FALSE;

	CDC dcImage;
	if (!dcImage.CreateCompatibleDC(pDC))
		return FALSE;

	if (m_pPalette != NULL)
	{
		dcImage.SelectPalette(m_pPalette, FALSE);
		dcImage.RealizePalette();
		pDC->SelectPalette(m_pPalette, FALSE);
		pDC->RealizePalette();
	}

	BITMAP bm;
	m_pBitmap->GetBitmap(&bm);
	CBitmap* pOldBitmap = dcImage.SelectObject(m_pBitmap);
	pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCCOPY);
	dcImage.SelectObject(pOldBitmap);

	return TRUE;
}

COLORREF COXSplashWndDIB::GetPixel(POINT pt) 
{ 
	return GetPixel(pt.x, pt.y);
}

COLORREF COXSplashWndDIB::GetPixel(int x, int y)
{
	UINT nBitStart = 0;
	BYTE* pPixel = NULL;

	if (x < 0 || m_xMax < x || y < 0 || m_yMax < y)
		return CLR_INVALID;

	// retrieve bit data
	nBitStart = m_nBitCount * x + m_nWidthBits * (m_bTopdown ? y : (m_yMax - y));
	pPixel = m_pBits0 + (nBitStart >> 3);

	if (m_nBitCount == 24)
		return RGB(*(pPixel+2), *(pPixel+1), *pPixel);

	ASSERT(m_pPalette && (m_nBitCount == 1 || 
						  m_nBitCount == 4 || 
						  m_nBitCount == 8));
	BYTE nIndex = 0;
	nIndex = *pPixel;
	if (m_nBitCount < 8)
	{
		nIndex <<= (nBitStart & 7);
		nIndex >>= m_nRightShift;
	}

	PALETTEENTRY pe;
	if (m_pPalette->GetPaletteEntries(nIndex, 1, &pe))
		return RGB(pe.peRed, pe.peGreen, pe.peBlue);

	return CLR_INVALID;
}

// protected:
void COXSplashWndDIB::PrepareGetPixel(BITMAPINFOHEADER& bmih, int iNumColors)
	// --- In      : bmih: The DIB
	//				 nNumColors : Number of colors in palette
	// --- Out     : 
	// --- Returns : 
	// --- Effect  : Prepares some internal variables for future GetPixel() calls.
{
	// ... others are not supported
	ASSERT(bmih.biCompression == BI_RGB);

	::CopyMemory(&m_bmih, &bmih, bmih.biSize);

	// DWROD aligned
	DWORD nWidthDWORD = (bmih.biWidth * bmih.biBitCount + 31) >> 5;
	m_nWidthBits = nWidthDWORD << 5;

	DWORD nSizeImage = (nWidthDWORD << 2) * abs(bmih.biHeight);
	m_bits.SetSize(nSizeImage);
	::CopyMemory(m_bits.GetData(), 
		(BYTE*)&bmih + bmih.biSize + iNumColors * sizeof(RGBQUAD), nSizeImage);

	// fill up cache values for GetPixel()
	m_xMax = m_bmih.biWidth - 1;
	m_yMax = abs(m_bmih.biHeight) - 1;
	m_bTopdown = (m_bmih.biHeight < 0);
	m_pBits0 = m_bits.GetData();
	m_nBitCount = m_bmih.biBitCount;
	m_nRightShift = 8 - m_bmih.biBitCount;
}


BOOL COXSplashWndDIB::CopyFile(CFile* pDestFile, CFile* pSourceFile) 
{
	ASSERT(pDestFile!=NULL);
	ASSERT(pSourceFile!=NULL);

	// use buffers
	const int nBufferLength = 1024;
	BYTE pBuffer[nBufferLength + 1];
	int nLengthRead(0);
	BOOL bSuccess = TRUE;

	TRY
	{
		do
		{
			nLengthRead = pSourceFile->Read(pBuffer, nBufferLength);
			pDestFile->Write(pBuffer, nLengthRead);
		}
		while (nLengthRead == nBufferLength);	// So while not EOF
	}
	CATCH(CFileException, pxFile)
	{
		TRACE(_T("COXSplashWndDIB::CopyFile : Catching FileException (%XH)\n"),
			pxFile->m_cause);
		bSuccess = FALSE;
	}
	END_CATCH      

	return bSuccess;
}

/////////////////////////////////////////////////////////////////////////////
