1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
#include <vector>
#include <iostream>
#include <stdexcept>
#include <windows.h>
using namespace std;
#define SHOWERR(x) MessageBox(0,x,"ERROR",MB_OK|MB_ICONEXCLAMATION)
typedef uint8_t uint8;
//this structure holds the rgba values of a color (standard bmp color order)
struct color{
uint8 b,g,r,x;
color(uint8 R,uint8 G,uint8 B,uint8 X=255):b(B),g(G),r(R),x(X){}
color():b(0),g(0),r(0),x(255){}
color(RGBQUAD rgb):b(rgb.rgbBlue),g(rgb.rgbGreen),r(rgb.rgbRed),x(rgb.rgbReserved){}}c_trans(0,0,0,0);
//this structure holds the necessary code and variables for image-handling
struct surface{
vector<color*> data;
int bpp;//bits per pixel
int bpr;//bytes per row (including alignment)
int transparent;
int transparency;
int delay;
int width,height;
RGBQUAD* palette;
BITMAPINFO* bmi;
surface():bpp(0),width(0),height(0),palette(NULL),bmi(NULL){}
~surface();
int draw(int,int,HDC,unsigned);
bool load(char*);
color& operator()(int,int,unsigned);};
surface::~surface(){
int x=0,size=data.size();
for(;x<size;++x){
delete[] data[x];}
delete[] palette;
delete bmi;}
int surface::draw(int x,int y,HDC hdc,unsigned frame=0){
if(frame>=data.size()){
throw std::out_of_range("surface::draw(x,y,HDC,frame=0)");}
return SetDIBitsToDevice(hdc,x,y,width,height,0,0,0,height,(void*)data[frame],bmi,DIB_RGB_COLORS);}
color& surface::operator()(int x,int y,unsigned frame=0){
if(x>width || y>height || frame>data.size()){
throw std::out_of_range("surface::operator()(x,y,frame=0)");}
return data[frame][y*width+x];}
bool load_bmp(HANDLE file,surface& img){
//---All this stuff is exactly as it was before
DWORD read;
//load file header
BITMAPFILEHEADER bfh;
ReadFile(file,&bfh,sizeof(BITMAPFILEHEADER),&read,NULL);
if(read!=sizeof(BITMAPFILEHEADER)){
SHOWERR("ERROR: Failed to read the BMP file header");
return false;}
if(bfh.bfType!=0x4D42){//'BM'
SHOWERR("ERROR: BMP file is invalid");
return false;}
//load info header
BITMAPINFOHEADER bih;
ReadFile(file,&bih,sizeof(BITMAPINFOHEADER),&read,NULL);
if(read!=sizeof(BITMAPINFOHEADER)){
SHOWERR("ERROR: Failed to read the BMP file header");
return false;}
if(bih.biCompression!=0){
SHOWERR("ERROR: BMP file uses an unsupported form of compression");
return false;}
//---New stuff starts here
RGBQUAD* color_table=NULL;
unsigned size=0;
if(bih.biBitCount<16){
if(bih.biClrUsed==0){
size=1<<bih.biBitCount;
color_table=new RGBQUAD[size];}
else{
size=bih.biClrUsed;
color_table=new RGBQUAD[bih.biClrUsed];}
ReadFile(file,color_table,size,&read,NULL);}
//load data
color* data;
char byte;
short word;
unsigned x=0;
int y,z;
unsigned bpr=(bih.biBitCount*bih.biWidth)/8;
//integer alignment
bpr+=(4-bpr%4)%4;
//support for multiple bpp values
if(bih.biHeight>0){
SetFilePointer(file,bih.biSizeImage-bpr,NULL,FILE_CURRENT);}
switch(bih.biBitCount){
//--- I have other bit count cases here, but they're not finished yet
case 24:
case 32:
size=bih.biSizeImage/4;
data=new color[size];
for(z=0;z<bih.biHeight;++z){
ReadFile(file,data+z*bih.biWidth+x,bih.biWidth*sizeof(color)+bpr,&read,NULL);
if(bih.biHeight>0){
SetFilePointer(file,-(bpr+bih.biWidth)*2,NULL,FILE_CURRENT);}}
break;}
//fill surface with data
img.bmi=new BITMAPINFO;
img.bmi->bmiHeader=bih;
img.data.push_back(data);
img.bpp=32;
img.width=bih.biWidth;
img.height=(bih.biHeight>0?-bih.biHeight:bih.biHeight);
return true;}
char* get_ext(char* fname,char* ext,unsigned len=0){
if(len==0){
len=strlen(fname);}
--len;
unsigned x;
for(x=len;fname[x]!='.' && x>0;--x){}
++x;
ext=new char[len-x+1];
memcpy(ext,fname+x,len-x+1);
return ext;}
bool surface::load(char* fname){
HANDLE file=CreateFile(fname,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(file==INVALID_HANDLE_VALUE){
SHOWERR("ERROR: Couldn't load image file");
return false;}
char* ext=NULL;
ext=get_ext(fname,ext);
bool loaded=false;
if(!memcmp(ext,"bmp",3)){
loaded=load_bmp(file,*this);}
else{
SHOWERR("ERROR: File format not supported.\n\nSupported file formats:\n\t.BMP");
return false;}
delete[] ext;
CloseHandle(file);
return loaded;}
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
PAINTSTRUCT ps;
HDC hdc;
surface img;
int WINAPI WinMain(HINSTANCE hinst,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
MSG msg;
WNDCLASS wc={0};
wc.lpszClassName=TEXT("Center");
wc.hInstance=hinst;
wc.hbrBackground=GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc= WndProc;
wc.hCursor=LoadCursor(0,IDC_ARROW);
RegisterClass(&wc);
HWND hwnd=CreateWindow(wc.lpszClassName,TEXT("Center"),WS_OVERLAPPEDWINDOW|WS_VISIBLE,100,100,250,150,0,0,hinst,0);
HANDLE file=OPENFILER("mybmp.bmp");
if(file==INVALID_HANDLE_VALUE){
SHOWERR("ERROR: Failed to load BMP file");
exit(1);}
if(!load_bmp(file,img)){
exit(2);}
InvalidateRect(hwnd,NULL,false);
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);}
return msg.wParam;}
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
switch(msg){
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
img.draw(0,0,hdc,0);
EndPaint(hwnd,&ps);
return 0;}
return DefWindowProc(hwnd,msg,wParam,lParam);}
|