// DispFuncsDll.cpp : Defines the exported functions for the DLL application.
//


#include "DispFuncsDll.h"

namespace Disp
{

	int DispFuncs::LoadFromBmp(HDC hDC,LPCTSTR file)
	{
		HANDLE hImg=LoadImage(0,file,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
		if (hImg == 0)
		{
			return FALSE;
		}
		HDC dcmem = CreateCompatibleDC ( NULL );
		if (SelectObject ( dcmem, hImg ) == 0 )
		{	
			DeleteDC ( dcmem ); 
			return FALSE;
		}
		BITMAP bm;
		//ładowanie do bitmapy
		GetObject ( hImg, sizeof(bm), &bm );
		if ( BitBlt ( hDC, 0, 0, bm.bmWidth, bm.bmHeight, dcmem,0, 0, SRCCOPY ) == 0 )
		{
			DeleteDC ( dcmem ); 
			return FALSE; 
		}
		DeleteDC ( dcmem );
		return TRUE;
	}

	DetectResult  DispFuncs::Detect(HWND hWnd, CvCapture *capture,char* fileName,int b_width,int b_height,CvPoint2D32f *corners)
	{
		DetectResult result=DetectionSuccess;
		HDC hDC = GetDC ( hWnd );
		IplImage  *image = 0;
		IplImage *neg_img,*cpy_img;

		if (!capture)
		{
			capture = cvCaptureFromCAM( CV_CAP_ANY );
			if ( !capture )
			{
				MessageBox(hWnd, L"Nie mozna uzyskac dostepu do kamery",L"Failed", MB_OK);
				result=DetectionError;
				goto done;
			}
			image = cvQueryFrame( capture );
			//dopasowywanie okna programu do obrazu z kamery
			SetWindowPos(hWnd,0,0,0,image->width,image->height,SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
		}
		IplImage *pic = cvLoadImage(fileName);
		if (!pic)
		{
			MessageBox(hWnd, L"Brak obrazu do wczytania",L"Failed", MB_OK);
			result=DetectionError;
			goto done;
		}
		int b_squares = b_width*b_height;
		CvSize b_size = cvSize( b_width, b_height );
		//macierz transformacji punktow
		CvMat* warp_matrix = cvCreateMat(3,3,CV_32FC1);
	
		int corner_count;
		image = cvQueryFrame( capture );
		if( !image ) goto done;

		//szary obraz potrzebny do identyfikacji wzoru kratownicy
		IplImage* gray = cvCreateImage( cvGetSize(image), image->depth, 1);
		int found = cvFindChessboardCorners(image, b_size, corners, &corner_count,        
										CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
 
		cvCvtColor(image, gray, CV_BGR2GRAY);
   
		//zapisywanie znalezionych punktow - rogów
		cvFindCornerSubPix(gray, corners, corner_count,  cvSize(11,11),cvSize(-1,-1),    
										cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 0.1 ));
		if( corner_count == b_squares )
		{
			CvPoint2D32f p[4];
			CvPoint2D32f q[4];
 
			IplImage* blank  = cvCreateImage( cvGetSize(pic), 8, 3);
			cvZero(blank);
			cvNot(blank,blank);
     
			//punkty przed transformacją 
			q[0].x= (float) pic->width * 0;
			q[0].y= (float) pic->height * 0;
			q[1].x= (float) pic->width;
			q[1].y= (float) pic->height * 0;
 
			q[2].x= (float) pic->width;
			q[2].y= (float) pic->height;
			q[3].x= (float) pic->width * 0;
			q[3].y= (float) pic->height;
   
			//punkty do których ma prowadzić transformacja - znalezione we wzrocu
			p[0].x= corners[0].x;
			p[0].y= corners[0].y;
			p[1].x= corners[4].x;
			p[1].y= corners[4].y;
     
			p[2].x= corners[19].x;
			p[2].y= corners[19].y;
			p[3].x= corners[15].x;
			p[3].y= corners[15].y;
	
			//obliczanie macierzy trasformacji
			cvGetPerspectiveTransform(q,p,warp_matrix);
			//obrazy potrzebne do zlozenia koncowego obrazu
			cpy_img = cvCreateImage( cvGetSize(image), 8, 3 );
			neg_img = cvCreateImage( cvGetSize(image), 8, 3 );
			cvZero(neg_img);
			cvZero(cpy_img);
 
			cvWarpPerspective( pic, neg_img, warp_matrix);
			cvWarpPerspective( blank, cpy_img, warp_matrix);
			cvNot(cpy_img,cpy_img);
			cvAnd(cpy_img,image,cpy_img);
			cvOr(cpy_img,neg_img,image);

			cvReleaseImage(&neg_img);
			cvReleaseImage(&cpy_img);	
			cvReleaseImage(&blank);
		}
		else
		{
			result=DetectionFail;
		}

		//zapisywanie do pliku 
		if (!cvSaveImage("img.bmp",image))
		{
			MessageBox(hWnd,L"Zapis do pliku nie powiodl sie",L"Failed",MB_OK);
			result=DetectionError;
			goto done;
		}	
		//- ladowanie do Device Context
		if (!LoadFromBmp(GetDC ( hWnd ),L"img.bmp"))
		{
			MessageBox(hWnd,L"Nie mozna zaladowac pliku do DC",L"Failed",MB_OK);
			result=DetectionError;
			goto done;
		}

	done:
		cvReleaseImage(&pic);
		cvReleaseImage(&image);
		cvReleaseMat(&warp_matrix);
		return result;
	}

	int DispFuncs::RotateScreen(int orientation)
	{
		DEVMODE dm;
	   //inicjalizacja DEVMODE
	   ZeroMemory(&dm, sizeof(dm));
	   dm.dmSize = sizeof(dm);

	   if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
	   {
				if( orientation==DMDO_90 || orientation==DMDO_270)
				{
				  //dla orientacji 90 i 270 trzeba zamienic wysokosc i szerokosc
				  DWORD dwTemp = dm.dmPelsHeight;
				  dm.dmPelsHeight= dm.dmPelsWidth;
				  dm.dmPelsWidth = dwTemp;
				}
			  switch (orientation)
			  {
			  case DMDO_270:
				  dm.dmDisplayOrientation = DMDO_270;
				 break;
			  case DMDO_180:
					dm.dmDisplayOrientation = DMDO_180;
				 break;
			  case DMDO_90:
					dm.dmDisplayOrientation = DMDO_90;
				 break;
			  case DMDO_DEFAULT:
					//powracamy do pierwotnej orientacji
					//jesli powracamy z 90 lub 270 musimy zamienic wysokosc z szerokoscia
					if(dm.dmDisplayOrientation==DMDO_90 ||dm.dmDisplayOrientation==DMDO_270)
					{
						DWORD dwTemp = dm.dmPelsHeight;
						dm.dmPelsHeight= dm.dmPelsWidth;
						dm.dmPelsWidth = dwTemp;
					}
					dm.dmDisplayOrientation = DMDO_DEFAULT;
				 break;
			  default:
					return FALSE;
				 break;
		  }
		  long lRet = ChangeDisplaySettings(&dm, 0);
		  if (DISP_CHANGE_SUCCESSFUL == lRet)
		  {
			 return TRUE;
		  }
		  else
		  {
			  return FALSE;
		  }
	   }
	   else
	   {
		return FALSE;
	   }
	}

	CaptureImageResult DispFuncs::CaptureAnImage(HWND hWnd,HWND app,LPCWSTR fileName)
	{
		CaptureImageResult result=CaptureSuccess;
		HDC hdcScreen;
		HDC hdcWindow;
		HDC hdcMemDC = NULL;
		HBITMAP hbmScreen = NULL;
		BITMAP bmpScreen;
    
		//jesli app jest oknem wez jego device context
		if(IsWindow(app))
		{
			hdcScreen=GetDC(app);
		}
		else
		{
			//w innym wypadku weź device context NULL -> caly obszar pulpitu
			hdcScreen = GetDC(NULL);
		}
		//device context - naszego okna gdzie bedzie wyswietlana bitmapa
		hdcWindow = GetDC(hWnd);

		// Create a compatible DC which is used in a BitBlt from the window DC
		hdcMemDC = CreateCompatibleDC(hdcWindow); 

		if(!hdcMemDC)
		{
			MessageBox(hWnd, L"Nie udalo sie stworzyc hdcMemDC",L"Failed", MB_OK);
			result=CaptureError;
			goto done;
		}

		//obszar okna ap by obliczyc wymiary pliku
		int x,y;
		if (IsWindow(app))
		{
			RECT rcApp;
			GetWindowRect(app,&rcApp);
			x=rcApp.right-rcApp.left;
			y=rcApp.bottom-rcApp.top;
		}
		else
		{
			//jesli caly pulpit to pobieramy rozdzielczosc
			x=GetSystemMetrics (SM_CXSCREEN);
			y=GetSystemMetrics (SM_CYSCREEN);
		}

		//tworzymy hbitmap na podstawie device context
		hbmScreen = CreateCompatibleBitmap(hdcScreen, x,y);
		if(!hbmScreen)
		{
			MessageBox(hWnd, L"CreateCompatibleBitmap Failed",L"Failed", MB_OK);
			result=CaptureError;
			goto done;
		}

		//powiazanie bitmapy z hdcMemDC
		SelectObject(hdcMemDC,hbmScreen);

		//transfer -pikseli z dc hdcScreen (app lub pulpit) do hdcMemDC)
		if(!BitBlt(hdcMemDC, 
				   0,0, 
				   x,y, 
				   hdcScreen, 
				   0,0,
				   SRCCOPY))
		{
			MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
			result=CaptureError;
			goto done;
		}

		//z HBITMAP przechodzimy na bitmape BITMAP
		GetObject(hbmScreen,sizeof(BITMAP),&bmpScreen);
    
		//nagłówki pliku bmp
		BITMAPFILEHEADER   bmfHeader;    
		BITMAPINFOHEADER   bi;
     
		bi.biSize = sizeof(BITMAPINFOHEADER);    
		bi.biWidth = bmpScreen.bmWidth;    
		bi.biHeight = bmpScreen.bmHeight;  
		bi.biPlanes = 1;    
		bi.biBitCount = 32;    
		bi.biCompression = BI_RGB;    
		bi.biSizeImage = 0;  
		bi.biXPelsPerMeter = 0;    
		bi.biYPelsPerMeter = 0;    
		bi.biClrUsed = 0;    
		bi.biClrImportant = 0;

		//rozmiar bitmapy
		DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;

		//buffor
		HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize); 
		char *lpbitmap = (char *)GlobalLock(hDIB);    

		// kopiujemy bity z bitmapy do buffora, wskazywanego przez lpbitmap).
		GetDIBits(hdcWindow, hbmScreen, 0,
			(UINT)bmpScreen.bmHeight,
			lpbitmap,
			(BITMAPINFO *)&bi, DIB_RGB_COLORS);

		//tworzymy plik - uchwyt do pliku
		HANDLE hFile = CreateFile(fileName,
			GENERIC_WRITE,
			0,
			NULL,
			CREATE_ALWAYS,
			FILE_ATTRIBUTE_NORMAL, NULL);   
    
		// do rozmiaru bitmapy dodajemy rozmiar nagłówków - całkowity rozmiar pliku
		DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
 
		//Offset do miejsca gdzie dane bitmapy (obraz) sie zaczynaja
		bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); 
    
		//rozmiar pliku
		bmfHeader.bfSize = dwSizeofDIB; 
    
		//bfType must always be BM for Bitmaps
		bmfHeader.bfType = 0x4D42; //BM   
	
		//zapisujemy plik
		DWORD dwBytesWritten = 0;
		WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
		WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
		WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
    
		GlobalUnlock(hDIB);    
		GlobalFree(hDIB);

		CloseHandle(hFile);

	done:
		DeleteObject(hbmScreen);
		DeleteObject(hdcMemDC);
		ReleaseDC(NULL,hdcScreen);
		ReleaseDC(hWnd,hdcWindow);
		return result;
	}

}