#include "Varia.h"

#include <stdio.h>

bool filetest(const char* filename)
{
	FILE* plik_test;
	if((plik_test=fopen(filename,"r"))==NULL) return false;
	else fclose(plik_test);
	return true;
} 

#include <stdexcept>

unsigned long* WczytajTeksture(HWND uchwytOkna,char* nazwaPliku,int& teksturaSzer,int& teksturaWys,bool zZasobow,unsigned char alfa)
{
	//niezbyt elegancko jest tworzyc new w funkcji (zapomina sie o delete)
	//ale dzieki temu nie trzeba rozbijac na dwie czesci (pobieranie obrazu i czytanie)
	//nie trzeba zwracac informacji o obrazie, bo zawsze zwracamy tablice RGBA
	try
	{
		//czytanie bitmapy z pliku lub z zasobow
		char komunikat[1024] = "Brak pliku tekstury ";
		strcat(komunikat,nazwaPliku);
		if (!zZasobow && !filetest(nazwaPliku)) throw std::invalid_argument(komunikat);
		HBITMAP uchwytObrazu = (HBITMAP)LoadImage(GetModuleHandle(NULL),nazwaPliku,IMAGE_BITMAP,0,0,(zZasobow?0:LR_LOADFROMFILE) | LR_CREATEDIBSECTION);
		
		//informacje o bitmapie
		BITMAP obraz;		
		GetObject(uchwytObrazu,sizeof(BITMAP),&obraz);
		teksturaSzer=obraz.bmWidth;
		teksturaWys=obraz.bmHeight;

		//informacja o ilosci bitow na piksel
		//char bufor[256];
		//ShowMessage(_gcvt(obraz.bmBitsPixel,10,bufor));		

		unsigned long* tekstura=new unsigned long[teksturaSzer*teksturaWys];
		switch(obraz.bmBitsPixel)
		{
			case 24:
				{
				unsigned char* tekstura24bppBRG=new unsigned char[obraz.bmWidthBytes*teksturaWys];
				memcpy(tekstura24bppBRG,obraz.bmBits,teksturaSzer*teksturaWys*3);
				//gdybym zwrocil tekstura24bppBRG zrzutowane na unsigned long*, to powinienem uzywac do wyswietlania GL_BGR_EXT
				
				//konwersja na RGBA
				for(int ih=0;ih<teksturaWys;ih++)	//kolejnosc i tak dowolna, bo tablica jednowymiarowa	
					for(int iw=0;iw<teksturaSzer;iw++)		
					{
						int i=3*iw+(ih*obraz.bmWidthBytes); //uwzglednia uzupelnianie do WORD
						unsigned char A=alfa;
						unsigned char B=tekstura24bppBRG[i];
						unsigned char G=tekstura24bppBRG[i+1];
						unsigned char R=tekstura24bppBRG[i+2];

						/*
						//jezeli konwersja na BW
						unsigned char jasnosc=(R+G+B)/3;
						R=jasnosc;
						B=jasnosc;
						G=jasnosc;
						*/

						tekstura[iw+(ih*teksturaSzer)]=(A << 24) + (B << 16) + (G << 8) + (R);
					}
				delete [] tekstura24bppBRG;
				}
				break;

			case 1:	//monochromatyczne
				{
				unsigned char* tekstura1bppMono=new unsigned char[obraz.bmWidthBytes*teksturaWys];
				memcpy(tekstura1bppMono,obraz.bmBits,obraz.bmWidthBytes*teksturaWys);				
				
				//konwersja na RGBA				
				for(int ih=0;ih<teksturaWys;ih++)		
					for(int iw=0;iw<teksturaSzer;iw++)
					{
						int i=iw/8+(ih*obraz.bmWidthBytes); //uwzglednia uzupelnianie do WORD
						int numerBitu=iw % 8;
						unsigned char A=alfa;
						bool bitZapalony=((tekstura1bppMono[i] << numerBitu) & 128)==128;
						//ignorujemy palete i tworzymy obraz czarno-bialy
						unsigned char B=bitZapalony?255:0;
						unsigned char G=bitZapalony?255:0;
						unsigned char R=bitZapalony?255:0;
						tekstura[iw+(ih*teksturaSzer)]=(A << 24) + (B << 16) + (G << 8) + (R);
					}
				delete [] tekstura1bppMono;
				}
				break;

			case 8: //256 kolorow, wymaga palety barw (tabeli kolorow)
				{
					unsigned char* tekstura8bppPalette=new unsigned char[obraz.bmWidthBytes*teksturaWys];
					memcpy(tekstura8bppPalette,obraz.bmBits,obraz.bmWidthBytes*teksturaWys);				
					//memcpy(tekstura,tekstura8bppPalette,obraz.bmWidthBytes*teksturaWys);				

					//pobranie tabeli kolorow (pomijamy czytanie BITMAPINFO)
					HDC uchwyt=CreateCompatibleDC(GetDC(uchwytOkna));
					SelectObject(uchwyt,uchwytObrazu);
					RGBQUAD tabelaKolorow[256];
					GetDIBColorTable(uchwyt,0,256,tabelaKolorow);
								
					/*					
					//standardowa paleta kolorow z systemu
					//HPALETTE uchwytPalety=(HPALETTE)GetStockObject(DEFAULT_PALETTE); 
					PALETTEENTRY tabelaKolorow[256];
					GetSystemPaletteEntries(GetDC(uchwytOkna),0,256,tabelaKolorow);
					*/				
							
					for(int ih=0;ih<teksturaWys;ih++)	//kolejnosc i tak dowolna, bo tablica jednowymiarowa	
						for(int iw=0;iw<teksturaSzer;iw++)		
						{
							int i=iw+(ih*obraz.bmWidthBytes); //uwzglednia uzupelnianie do WORD
							unsigned char A=alfa;
							unsigned char R=tabelaKolorow[tekstura8bppPalette[i]].rgbRed;
							unsigned char G=tabelaKolorow[tekstura8bppPalette[i]].rgbGreen;
							unsigned char B=tabelaKolorow[tekstura8bppPalette[i]].rgbBlue;
							tekstura[iw+(ih*teksturaSzer)]=(A << 24) + (B << 16) + (G << 8) + (R);						
						}
					delete [] tekstura8bppPalette;
				}
				break;

			case 4: //16 kolorow (paleta barw jak w Paint)
				{
					unsigned char* tekstura4bppPalette=new unsigned char[obraz.bmWidthBytes*teksturaWys];
					memcpy(tekstura4bppPalette,obraz.bmBits,obraz.bmWidthBytes*teksturaWys);				
					
					//pobranie tabeli kolorow (pomijamy czytanie BITMAPINFO)
					HDC uchwyt=CreateCompatibleDC(GetDC(uchwytOkna));
					SelectObject(uchwyt,uchwytObrazu);
					RGBQUAD tabelaKolorow[16];
					GetDIBColorTable(uchwyt,0,16,tabelaKolorow);
								
					for(int ih=0;ih<teksturaWys;ih++)	//kolejnosc i tak dowolna, bo tablica jednowymiarowa	
						for(int iw=0;iw<teksturaSzer;iw++)		
						{
							int i=iw/2+(ih*obraz.bmWidthBytes); //uwzglednia uzupelnianie do WORD
							bool pierwszaPolowaBajtu=!(iw % 2);
							unsigned char A=alfa;
							int numerKoloruZPalety=(pierwszaPolowaBajtu)?((tekstura4bppPalette[i] & 0xF0)>>4):(tekstura4bppPalette[i] & 0x0F);
							unsigned char R=tabelaKolorow[numerKoloruZPalety].rgbRed;
							unsigned char G=tabelaKolorow[numerKoloruZPalety].rgbGreen;
							unsigned char B=tabelaKolorow[numerKoloruZPalety].rgbBlue;
							tekstura[iw+(ih*teksturaSzer)]=(A << 24) + (B << 16) + (G << 8) + (R);						
					}
					delete [] tekstura4bppPalette;
				}
				break;
			
			default: throw std::exception("Nieobslugiwany format bitmapy"); break;
		}
		
		DeleteObject(uchwytObrazu);

		return tekstura;
   	}
	catch(const std::exception& exc)
    {
		char komunikat[256]="Błąd podczas pobierania tekstury:\n";
		strcat(komunikat,exc.what());
		MessageBox(NULL,komunikat,"Błąd teksturowania",NULL); 
		return NULL;
	}
}
