-Import tkreuzer's time implementation from AMD64 branch
[reactos.git] / rostests / dibtests / stretchblt / stretchblt.cpp
1
2 // ------------------------------------------------------------------
3 // Windows 2000 Graphics API Black Book
4 // Chapter 1 - Listing 1.5 (StretchBlt Zooming Demo)
5 //
6 // Created by Damon Chandler <dmc27@ee.cornell.edu>
7 // Updates can be downloaded at: <www.coriolis.com>
8 //
9 // Please do not hesistate to e-mail me at dmc27@ee.cornell.edu
10 // if you have any questions about this code.
11 // ------------------------------------------------------------------
12
13 // Modified by Aleksey Bragin (aleksey at studiocerebral.com)
14 // to support non-uniform scaling, and output via sretchdibits
15 // (type something in the command line to invoke this mode,
16 // in future it will be source BPP)
17
18 //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
19 #include <windows.h>
20 #include <stdio.h>
21 //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
22
23
24 HWND HListBox = NULL;
25 HWND VListBox = NULL;
26 const int ID_LISTBOX = 101;
27 const int ID_LISTBOX2 = 102;
28 BOOL useDIBits=FALSE; // How to display the image - via StretchDIBits
29
30 HINSTANCE HInst;
31 HINSTANCE HPrevInst;
32 TCHAR *cmdline;
33 const char* WndClassName = "GMainWnd";
34 LRESULT CALLBACK MainWndProc(HWND HWnd, UINT Msg, WPARAM WParam,
35 LPARAM LParam);
36
37
38 int APIENTRY WinMain(HINSTANCE HInstance, HINSTANCE HPrevInstance,
39 LPTSTR lpCmdLine, int nCmdShow)
40 {
41 HInst = HInstance;
42 HPrevInst = HPrevInstance;
43 cmdline = lpCmdLine;
44
45 WNDCLASS wc;
46 memset(&wc, 0, sizeof(WNDCLASS));
47
48 wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
49 wc.lpfnWndProc = MainWndProc;
50 wc.hInstance = HInstance;
51 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
52 wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1);
53 wc.lpszClassName = WndClassName;
54
55 if (RegisterClass(&wc))
56 {
57 HWND HWnd =
58 CreateWindow(WndClassName, TEXT("StretchBlt NonUniform Zooming Demo"),
59 WS_OVERLAPPEDWINDOW | WS_CAPTION |
60 WS_VISIBLE | WS_CLIPSIBLINGS,
61 0, 0, 675, 560,
62 NULL, NULL, HInst, NULL);
63
64 if (HWnd)
65 {
66 HListBox =
67 CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", "",
68 LBS_NOTIFY | WS_CHILD | WS_VISIBLE,
69 530, 5, 130, 150, HWnd,
70 reinterpret_cast<HMENU>(ID_LISTBOX),
71 HInst, NULL);
72 VListBox =
73 CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", "",
74 LBS_NOTIFY | WS_CHILD | WS_VISIBLE,
75 530, 5+170, 130, 150, HWnd,
76 reinterpret_cast<HMENU>(ID_LISTBOX2),
77 HInst, NULL);
78
79 if (HListBox && VListBox)
80 {
81 // horizontal zoom
82 SNDMSG(HListBox, LB_ADDSTRING, 0,
83 reinterpret_cast<LPARAM>("Zoom 25%"));
84 SNDMSG(HListBox, LB_ADDSTRING, 0,
85 reinterpret_cast<LPARAM>("Zoom 50%"));
86 SNDMSG(HListBox, LB_ADDSTRING, 0,
87 reinterpret_cast<LPARAM>("Zoom 75%"));
88 SNDMSG(HListBox, LB_ADDSTRING, 0,
89 reinterpret_cast<LPARAM>("Zoom 100%"));
90 SNDMSG(HListBox, LB_ADDSTRING, 0,
91 reinterpret_cast<LPARAM>("Zoom 125%"));
92 SNDMSG(HListBox, LB_ADDSTRING, 0,
93 reinterpret_cast<LPARAM>("Zoom 150%"));
94 SNDMSG(HListBox, LB_ADDSTRING, 0,
95 reinterpret_cast<LPARAM>("Zoom 200%"));
96 SNDMSG(HListBox, LB_ADDSTRING, 0,
97 reinterpret_cast<LPARAM>("Zoom 300%"));
98 // vertical zoom
99 SNDMSG(VListBox, LB_ADDSTRING, 0,
100 reinterpret_cast<LPARAM>("Zoom 25%"));
101 SNDMSG(VListBox, LB_ADDSTRING, 0,
102 reinterpret_cast<LPARAM>("Zoom 50%"));
103 SNDMSG(VListBox, LB_ADDSTRING, 0,
104 reinterpret_cast<LPARAM>("Zoom 75%"));
105 SNDMSG(VListBox, LB_ADDSTRING, 0,
106 reinterpret_cast<LPARAM>("Zoom 100%"));
107 SNDMSG(VListBox, LB_ADDSTRING, 0,
108 reinterpret_cast<LPARAM>("Zoom 125%"));
109 SNDMSG(VListBox, LB_ADDSTRING, 0,
110 reinterpret_cast<LPARAM>("Zoom 150%"));
111 SNDMSG(VListBox, LB_ADDSTRING, 0,
112 reinterpret_cast<LPARAM>("Zoom 200%"));
113 SNDMSG(VListBox, LB_ADDSTRING, 0,
114 reinterpret_cast<LPARAM>("Zoom 300%"));
115
116 }
117
118 ShowWindow(HWnd, nCmdShow);
119 UpdateWindow(HWnd);
120
121 MSG msg;
122 while (GetMessage(&msg, NULL, 0, 0))
123 {
124 TranslateMessage(&msg);
125 DispatchMessage(&msg);
126 }
127 }
128 }
129 return 0;
130 }
131 //------------------------------------------------------------------
132
133
134 // image related
135 BITMAP bmp;
136 BITMAPINFO bmInfo;
137 char *bbits = NULL; // bitmap bits
138 const char* filename = "LENA.BMP";
139 HDC HMemDC = NULL;
140 HBITMAP HOldBmp = NULL;
141
142 // zooming related
143 float zoom_factor_h = 0.5;
144 float zoom_factor_v = 0.5;
145 RECT RDest = {5, 5, 0, 0};
146 enum {ID_ZOOM25, ID_ZOOM50, ID_ZOOM75, ID_ZOOM100,
147 ID_ZOOM125, ID_ZOOM150, ID_ZOOM200, ID_ZOOM300};
148
149 LRESULT CALLBACK MainWndProc(HWND HWnd, UINT Msg, WPARAM WParam,
150 LPARAM LParam)
151 {
152 switch (Msg)
153 {
154 case WM_CREATE:
155 {
156 // check commandline
157 if (strlen(cmdline) != 0)
158 {
159
160 useDIBits = TRUE;
161 }
162 else
163 useDIBits = FALSE;
164
165 // create a memory DC
166 HMemDC = CreateCompatibleDC(NULL);
167 if (HMemDC)
168 {
169 // load a bitmap from file
170 HBITMAP HBmp =
171 static_cast<HBITMAP>(
172 LoadImage(HInst, filename, IMAGE_BITMAP,
173 0, 0, LR_LOADFROMFILE)
174 );
175 if (HBmp)
176 {
177 // extract dimensions of the bitmap
178 GetObject(HBmp, sizeof(BITMAP), &bmp);
179
180 // fill the BITMAPINFO stucture for further use by StretchDIBits
181 bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
182 bmInfo.bmiHeader.biWidth = bmp.bmWidth;
183 bmInfo.bmiHeader.biHeight = bmp.bmHeight;
184 bmInfo.bmiHeader.biPlanes = 1;//bmp.bmPlanes;
185 bmInfo.bmiHeader.biBitCount = bmp.bmBitsPixel;
186 bmInfo.bmiHeader.biCompression = BI_RGB;
187 bmInfo.bmiHeader.biSizeImage = 0;
188 bmInfo.bmiHeader.biXPelsPerMeter = 0;
189 bmInfo.bmiHeader.biClrImportant = 0;
190 bmInfo.bmiHeader.biClrUsed = 0;
191
192 // associate the bitmap with the memory DC
193 HOldBmp = static_cast<HBITMAP>(
194 SelectObject(HMemDC, HBmp)
195 );
196
197 if (useDIBits)
198 {
199 bbits = new char[bmp.bmHeight*bmp.bmWidthBytes*(bmp.bmBitsPixel / 8)];
200 //GetDIBits(HMemDC, HBmp, 0, bmp.bmHeight, bbits, &bmInfo, DIB_RGB_COLORS);
201
202 // Here goes a temp hack, since GetDIBits doesn't exist in ReactOS yet
203 FILE *f = fopen(filename, "rb");
204 BITMAPFILEHEADER bmpHeader;
205
206 fread(&bmpHeader, sizeof(BITMAPFILEHEADER), 1, f);
207 fread(&bmInfo, sizeof(BITMAPINFO), 1, f);
208 fseek(f, bmpHeader.bfOffBits, SEEK_SET);
209 fread(bbits, bmp.bmHeight*bmp.bmWidthBytes*(bmp.bmBitsPixel / 8), 1, f);
210
211 fclose(f);
212 }
213 }
214 }
215 }
216 case WM_COMMAND:
217 {
218 if (WParam == MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) ||
219 WParam == MAKEWPARAM(ID_LISTBOX2, LBN_SELCHANGE))
220 {
221 switch (SNDMSG(HListBox, LB_GETCURSEL, 0, 0))
222 {
223 case ID_ZOOM25: zoom_factor_h = 0.25; break;
224 case ID_ZOOM50: zoom_factor_h = 0.50; break;
225 case ID_ZOOM75: zoom_factor_h = 0.75; break;
226 case ID_ZOOM100: zoom_factor_h = 1.00; break;
227 case ID_ZOOM125: zoom_factor_h = 1.25; break;
228 case ID_ZOOM150: zoom_factor_h = 1.50; break;
229 case ID_ZOOM200: zoom_factor_h = 2.00; break;
230 case ID_ZOOM300: zoom_factor_h = 3.00; break;
231 }
232
233 switch (SNDMSG(VListBox, LB_GETCURSEL, 0, 0))
234 {
235 case ID_ZOOM25: zoom_factor_v = 0.25; break;
236 case ID_ZOOM50: zoom_factor_v = 0.50; break;
237 case ID_ZOOM75: zoom_factor_v = 0.75; break;
238 case ID_ZOOM100: zoom_factor_v = 1.00; break;
239 case ID_ZOOM125: zoom_factor_v = 1.25; break;
240 case ID_ZOOM150: zoom_factor_v = 1.50; break;
241 case ID_ZOOM200: zoom_factor_v = 2.00; break;
242 case ID_ZOOM300: zoom_factor_v = 3.00; break;
243 }
244
245 // calculate the new width and height
246 const int new_width =
247 static_cast<int>(zoom_factor_h * bmp.bmWidth);
248 const int new_height =
249 static_cast<int>(zoom_factor_v * bmp.bmHeight);
250
251 // is zooming in?
252 bool zoom_in = (new_width > RDest.right - RDest.left);
253
254 // caculate the area that needs to be updated
255 RECT RUpdate = {
256 RDest.left, RDest.top,
257 RDest.left + max(new_width, RDest.right - RDest.left),
258 RDest.top + max(new_height, RDest.bottom - RDest.top)
259 };
260
261 // adjust the dimenstions of the
262 // destination rectangle
263 RDest.right = RDest.left + new_width;
264 RDest.bottom = RDest.top + new_height;
265
266 // create an update region from the XOR combination
267 // of the update and destination rectangles
268 HRGN HUpdateRgn = CreateRectRgnIndirect(&RUpdate);
269 HRGN HDestRgn = CreateRectRgnIndirect(&RDest);
270 int result =
271 CombineRgn(HUpdateRgn, HUpdateRgn, HDestRgn, RGN_XOR);
272
273 // incite a repaint
274 if (result != NULLREGION && result != ERROR)
275 {
276 InvalidateRgn(HWnd, HUpdateRgn, true);
277 RedrawWindow(HWnd, &RDest, NULL, RDW_NOERASE | RDW_INVALIDATE);
278 }
279 else if (result == NULLREGION)
280 {
281 InvalidateRect(HWnd, &RUpdate, zoom_in ? false : true);
282 }
283
284 // clean up
285 DeleteObject(HUpdateRgn);
286 DeleteObject(HDestRgn);
287 }
288 break;
289 }
290 case WM_PAINT:
291 {
292 PAINTSTRUCT ps;
293 const HDC Hdc = BeginPaint(HWnd, &ps);
294 #if 0
295 try
296 #endif
297 {
298 //
299 // TODO: add palette support (see Chapter 9)...
300 //
301 if (useDIBits)
302 {
303 if (RDest.right - RDest.left > 0)
304 {
305 if (zoom_factor_h < 1.0 || zoom_factor_v < 1.0)
306 {
307 SetStretchBltMode(Hdc, COLORONCOLOR);
308 }
309
310 // render the zoomed image
311 StretchDIBits(Hdc, RDest.left, RDest.top,
312 RDest.right - RDest.left,
313 RDest.bottom - RDest.top,
314 0, 0,
315 bmp.bmWidth, bmp.bmHeight,
316 bbits, &bmInfo,
317 DIB_RGB_COLORS,
318 SRCCOPY);
319 }
320 }
321 else
322 {
323 if (RDest.right - RDest.left > 0)
324 {
325
326 // use BitBlt when not zooming
327 if (zoom_factor_h == 1.0 && zoom_factor_v == 1.0)
328 {
329 BitBlt(Hdc, RDest.left, RDest.top,
330 RDest.right - RDest.left,
331 RDest.bottom - RDest.top,
332 HMemDC, 0, 0,
333 SRCCOPY);
334 }
335 else
336 {
337 if (zoom_factor_h < 1.0 || zoom_factor_v < 1.0)
338 {
339 SetStretchBltMode(Hdc, COLORONCOLOR);
340 }
341
342 // render the zoomed image
343 StretchBlt(Hdc, RDest.left, RDest.top,
344 RDest.right - RDest.left,
345 RDest.bottom - RDest.top,
346 HMemDC, 0, 0,
347 bmp.bmWidth, bmp.bmHeight,
348 SRCCOPY);
349 }
350 }
351 }
352 }
353 #if 0
354 catch (...)
355 #endif
356 {
357 EndPaint(HWnd, &ps);
358 }
359 EndPaint(HWnd, &ps);
360 break;
361 }
362 case WM_DESTROY:
363 {
364 // clean up
365 DeleteObject(SelectObject(HMemDC, HOldBmp));
366 DeleteDC(HMemDC);
367
368 if (bbits)
369 delete[] bbits;
370
371 PostQuitMessage(0);
372 return 0;
373 }
374 }
375 return DefWindowProc(HWnd, Msg, WParam, LParam);
376 }
377 //------------------------------------------------------------------
378
379
380