#include "stdafx.h"

simpledib::dib::dib()
{
	memset(this, 0, sizeof(*this));
}

simpledib::dib::~dib()
{
	destroy();
}

void simpledib::dib::destroy(bool del_bmp)
{
	if (m_hdc && m_ownData) {
		SelectObject(m_hdc, m_oldBmp);
		if (del_bmp)
			DeleteObject(m_bmp);
		DeleteDC(m_hdc);
	}
	else if (m_restore_view_port && m_hdc) {
		::SetWindowOrgEx(m_hdc, m_oldViewPort.x, m_oldViewPort.y, NULL);
	}

	memset(this, 0, sizeof(*this));
}

bool simpledib::dib::create(int width, int height, bool topdowndib)
{
	destroy();

	BITMAPINFO bmp_info;
	bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmp_info.bmiHeader.biWidth = width;
	bmp_info.bmiHeader.biHeight = height * (topdowndib ? -1 : 1);
	bmp_info.bmiHeader.biPlanes = 1;
	bmp_info.bmiHeader.biBitCount = 32;
	bmp_info.bmiHeader.biCompression = BI_RGB;
	bmp_info.bmiHeader.biSizeImage = 0;
	bmp_info.bmiHeader.biXPelsPerMeter = 0;
	bmp_info.bmiHeader.biYPelsPerMeter = 0;
	bmp_info.bmiHeader.biClrUsed = 0;
	bmp_info.bmiHeader.biClrImportant = 0;

	m_hdc = CreateCompatibleDC(NULL);

	m_bmp = ::CreateDIBSection(m_hdc, &bmp_info, DIB_RGB_COLORS, (LPVOID *)&m_bits, 0, 0);
	if (m_bits && m_bmp) {
		m_oldBmp = (HBITMAP)::SelectObject(m_hdc, m_bmp);
	}
	else {
		DeleteDC(m_hdc);
		m_hdc = nullptr;
	}

	if (!m_hdc)
		return false;
	
	m_width = width;
	m_height = height;
	m_ownData = true;
	return true;
}

/*
bool simpledib::dib::create( HDC hdc, HBITMAP bmp, LPRGBQUAD bits, int width, int height, int shift_x, int shift_y )
{
	destroy();

	m_bmp		= bmp;
	m_hdc		= hdc;
	m_bits		= bits;
	m_width		= width;
	m_height	= height;
	m_ownData	= FALSE;

	SetWindowOrgEx(m_hdc, -shift_x, -shift_y, &m_oldViewPort);
	m_restore_view_port = TRUE;
	return true;
}

*/
bool simpledib::dib::create(HDC hdc, HBITMAP bmp, LPRGBQUAD bits, int width, int height)
{
	destroy();

	m_bmp = bmp;
	m_hdc = hdc;
	m_bits = bits;
	m_width = width;
	m_height = height;
	m_ownData = m_restore_view_port = false;
	return true;
}

void simpledib::dib::clear()
{
	if (m_bits)
		memset(m_bits, 0, m_width * m_height * 4);
}

void simpledib::dib::draw(HDC hdc, int x, int y)
{
	BLENDFUNCTION bf;
	bf.BlendOp = AC_SRC_OVER;
	bf.BlendFlags = 0;
	bf.AlphaFormat = AC_SRC_ALPHA;
	bf.SourceConstantAlpha = 255;

	AlphaBlend(hdc, x, y, m_width, m_height, m_hdc, 0, 0, m_width, m_height, bf);
}

void simpledib::dib::draw(HDC hdc, LPRECT rcDraw)
{
	BLENDFUNCTION bf;
	bf.BlendOp = AC_SRC_OVER;
	bf.BlendFlags = 0;
	bf.AlphaFormat = AC_SRC_ALPHA;
	bf.SourceConstantAlpha = 255;

	AlphaBlend(hdc,
		rcDraw->left, rcDraw->top,
		rcDraw->right - rcDraw->left,
		rcDraw->bottom - rcDraw->top, m_hdc,

		rcDraw->left, rcDraw->top,
		rcDraw->right - rcDraw->left,
		rcDraw->bottom - rcDraw->top,
		bf);
}

HDC simpledib::dib::beginPaint(HDC hdc, LPRECT rcDraw)
{
	if (!create(rcDraw->right - rcDraw->left, rcDraw->bottom - rcDraw->top, true))
		return nullptr;

	m_hTargetDC = hdc;
	m_rcTarget = *rcDraw;
	SetWindowOrgEx(m_hdc, rcDraw->left, rcDraw->top, &m_oldViewPort);
	return m_hdc;
}

void simpledib::dib::endPaint(bool copy)
{
	SetWindowOrgEx(m_hdc, m_oldViewPort.x, m_oldViewPort.y, NULL);

	if (!copy) {
		BLENDFUNCTION bf = {};
		bf.BlendOp = AC_SRC_OVER;
		bf.AlphaFormat = AC_SRC_ALPHA;
		bf.SourceConstantAlpha = 255;

		AlphaBlend(m_hTargetDC, m_rcTarget.left, m_rcTarget.top,
			m_rcTarget.right - m_rcTarget.left,
			m_rcTarget.bottom - m_rcTarget.top, m_hdc,
			0, 0,
			m_rcTarget.right - m_rcTarget.left,
			m_rcTarget.bottom - m_rcTarget.top,
			bf);
	}
	else {
		BitBlt(m_hTargetDC, m_rcTarget.left, m_rcTarget.top,
			m_rcTarget.right - m_rcTarget.left,
			m_rcTarget.bottom - m_rcTarget.top, m_hdc, 0, 0, SRCCOPY);
	}

	m_hTargetDC = NULL;
	destroy();
}

HBITMAP simpledib::dib::detach_bitmap()
{
	HBITMAP bmp = m_bmp;
	destroy(false);
	return bmp;
}