OSDN Git Service

f87a2cfc4af5c258cfa4488caa3346c2ccc07a6a
[csp-qt/common_source_project-fm7.git] / source / src / win32_screen.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.08.18 -
6
7         [ win32 screen ]
8 */
9
10 #include "emu.h"
11 #include "vm/vm.h"
12
13 #define RESULT_SUCCESS  1
14 #define RESULT_FULL     2
15 #define RESULT_ERROR    3
16
17 unsigned __stdcall rec_video_thread(void *lpx);
18
19 #ifdef USE_CRT_FILTER
20 static uint8 r0[2048], g0[2048], b0[2048], t0[2048];
21 static uint8 r1[2048], g1[2048], b1[2048];
22 #endif
23
24 void EMU::initialize_screen()
25 {
26         screen_width = SCREEN_WIDTH;
27         screen_height = SCREEN_HEIGHT;
28         screen_width_aspect = SCREEN_WIDTH_ASPECT;
29         screen_height_aspect = SCREEN_HEIGHT_ASPECT;
30         window_width = WINDOW_WIDTH;
31         window_height = WINDOW_HEIGHT;
32         screen_size_changed = true;
33         
34         source_width = source_height = -1;
35         source_width_aspect = source_height_aspect = -1;
36         stretch_pow_x = stretch_pow_y = -1;
37         stretch_screen = false;
38         
39         // create dib sections
40         HDC hdc = GetDC(main_window_handle);
41         create_dib_section(hdc, screen_width, screen_height, &hdcDib, &hBmp, &hOldBmp, &lpBuf, &lpBmp, &lpDib);
42 #ifdef USE_SCREEN_ROTATE
43         create_dib_section(hdc, screen_height, screen_width, &hdcDibRotate, &hBmpRotate, &hOldBmpRotate, &lpBufRotate, &lpBmpRotate, &lpDibRotate);
44 #endif
45         ReleaseDC(main_window_handle, hdc);
46         
47         hdcDibStretch1 = hdcDibStretch2 = NULL;
48         hBmpStretch1 = hOldBmpStretch1 = hBmpStretch2 = hOldBmpStretch2 = NULL;
49         lpBufStretch1 = lpBufStretch2 = NULL;
50         
51         // initialize d3d9
52         lpd3d9 = NULL;
53         lpd3d9Device = NULL;
54         lpd3d9Surface = NULL;
55         lpd3d9OffscreenSurface = NULL;
56         lpd3d9Buffer = NULL;
57         render_to_d3d9Buffer = false;
58         use_d3d9 = config.use_d3d9;
59         wait_vsync = config.wait_vsync;
60         
61         // initialize video recording
62         now_rec_video = false;
63         hdcDibRec = NULL;
64         pAVIStream = NULL;
65         pAVICompressed = NULL;
66         pAVIFile = NULL;
67         
68         // initialize update flags
69         first_draw_screen = false;
70         first_invalidate = self_invalidate = false;
71         
72 #ifdef USE_CRT_FILTER
73         // initialize crtc filter
74         memset(r1, 0, sizeof(r1));
75         memset(g1, 0, sizeof(g1));
76         memset(b1, 0, sizeof(b1));
77 #endif
78 }
79
80 #define release_dib_section(hdcdib, hbmp, holdbmp, lpbuf) { \
81         if(hdcdib != NULL && holdbmp != NULL) { \
82                 SelectObject(hdcdib, holdbmp); \
83         } \
84         if(hbmp != NULL) { \
85                 DeleteObject(hbmp); \
86                 hbmp = NULL; \
87         } \
88         if(lpbuf != NULL) { \
89                 GlobalFree(lpbuf); \
90                 lpbuf = NULL; \
91         } \
92         if(hdcdib != NULL) { \
93                 DeleteDC(hdcdib); \
94                 hdcdib = NULL; \
95         } \
96 }
97
98 #define release_d3d9() { \
99         if(lpd3d9OffscreenSurface != NULL) { \
100                 lpd3d9OffscreenSurface->Release(); \
101                 lpd3d9OffscreenSurface = NULL; \
102         } \
103         if(lpd3d9Surface != NULL) { \
104                 lpd3d9Surface->Release(); \
105                 lpd3d9Surface = NULL; \
106         } \
107         if(lpd3d9Device != NULL) { \
108                 lpd3d9Device->Release(); \
109                 lpd3d9Device = NULL; \
110         } \
111         if(lpd3d9 != NULL) { \
112                 lpd3d9->Release(); \
113                 lpd3d9 = NULL; \
114         } \
115 }
116
117 #define release_d3d9_surface() { \
118         if(lpd3d9OffscreenSurface != NULL) { \
119                 lpd3d9OffscreenSurface->Release(); \
120                 lpd3d9OffscreenSurface = NULL; \
121         } \
122         if(lpd3d9Surface != NULL) { \
123                 lpd3d9Surface->Release(); \
124                 lpd3d9Surface = NULL; \
125         } \
126 }
127
128 void EMU::release_screen()
129 {
130         // stop video recording
131         stop_rec_video();
132         
133         // release dib sections
134         release_dib_section(hdcDib, hBmp, hOldBmp, lpBuf);
135 #ifdef USE_SCREEN_ROTATE
136         release_dib_section(hdcDibRotate, hBmpRotate, hOldBmpRotate, lpBufRotate);
137 #endif
138         release_dib_section(hdcDibStretch1, hBmpStretch1, hOldBmpStretch1, lpBufStretch1);
139         release_dib_section(hdcDibStretch2, hBmpStretch2, hOldBmpStretch2, lpBufStretch2);
140         
141         // release d3d9
142         release_d3d9();
143 }
144
145 void EMU::create_dib_section(HDC hdc, int width, int height, HDC *hdcDib, HBITMAP *hBmp, HBITMAP *hOldBmp, LPBYTE *lpBuf, scrntype **lpBmp, LPBITMAPINFO *lpDib)
146 {
147         *hdcDib = CreateCompatibleDC(hdc);
148         *lpBuf = (LPBYTE)GlobalAlloc(GPTR, sizeof(BITMAPINFO));
149         *lpDib = (LPBITMAPINFO)(*lpBuf);
150         memset(&(*lpDib)->bmiHeader, 0, sizeof(BITMAPINFOHEADER));
151         (*lpDib)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
152         (*lpDib)->bmiHeader.biWidth = width;
153         (*lpDib)->bmiHeader.biHeight = height;
154         (*lpDib)->bmiHeader.biPlanes = 1;
155 #if defined(_RGB555)
156         (*lpDib)->bmiHeader.biBitCount = 16;
157         (*lpDib)->bmiHeader.biCompression = BI_RGB;
158         (*lpDib)->bmiHeader.biSizeImage = width * height * 2;
159 #elif defined(_RGB565)
160         (*lpDib)->bmiHeader.biBitCount = 16;
161         (*lpDib)->bmiHeader.biCompression = BI_BITFIELDS;
162         LPDWORD lpBf = (LPDWORD)*lpDib->bmiColors;
163         lpBf[0] = 0x1f << 11;
164         lpBf[1] = 0x3f << 5;
165         lpBf[2] = 0x1f << 0;
166         (*lpDib)->bmiHeader.biSizeImage = width * height * 2;
167 #elif defined(_RGB888)
168         (*lpDib)->bmiHeader.biBitCount = 32;
169         (*lpDib)->bmiHeader.biCompression = BI_RGB;
170         (*lpDib)->bmiHeader.biSizeImage = width * height * 4;
171 #endif
172         (*lpDib)->bmiHeader.biXPelsPerMeter = 0;
173         (*lpDib)->bmiHeader.biYPelsPerMeter = 0;
174         (*lpDib)->bmiHeader.biClrUsed = 0;
175         (*lpDib)->bmiHeader.biClrImportant = 0;
176         *hBmp = CreateDIBSection(hdc, *lpDib, DIB_RGB_COLORS, (PVOID*)&(*lpBmp), NULL, 0);
177         *hOldBmp = (HBITMAP)SelectObject(*hdcDib, *hBmp);
178 }
179
180 int EMU::get_window_width(int mode)
181 {
182 #ifdef USE_SCREEN_ROTATE
183         if(config.monitor_type) {
184                 return window_height + screen_height_aspect * mode;
185         }
186 #endif
187         return window_width + screen_width_aspect * mode;
188 }
189
190 int EMU::get_window_height(int mode)
191 {
192 #ifdef USE_SCREEN_ROTATE
193         if(config.monitor_type) {
194                 return window_width + screen_width_aspect * mode;
195         }
196 #endif
197         return window_height + screen_height_aspect * mode;
198 }
199
200 void EMU::set_display_size(int width, int height, bool window_mode)
201 {
202 RETRY:
203         bool display_size_changed = false;
204         bool stretch_changed = false;
205         int prev_stretched_width = stretched_width;
206         int prev_stretched_height = stretched_height;
207         
208         if(width != -1 && (display_width != width || display_height != height)) {
209                 display_width = width;
210                 display_height = height;
211                 display_size_changed = stretch_changed = true;
212         }
213         if(use_d3d9 != config.use_d3d9) {
214                 if(!(use_d3d9 = config.use_d3d9)) {
215                         release_d3d9();
216                 }
217                 display_size_changed = stretch_changed = true;
218         }
219         if(wait_vsync != config.wait_vsync) {
220                 wait_vsync = config.wait_vsync;
221                 display_size_changed = stretch_changed = true;
222         }
223         
224         // virtual machine renders to d3d9 buffer directly???
225         render_to_d3d9Buffer = use_d3d9;
226         
227 #ifdef USE_SCREEN_ROTATE
228         if(config.monitor_type) {
229                 hdcDibSource = hdcDibRotate;
230                 lpBmpSource = lpBmpRotate;
231                 lpDibSource = lpDibRotate;
232                 pbmInfoHeader = &lpDibRotate->bmiHeader;
233                 
234                 stretch_changed |= (source_width != screen_height);
235                 stretch_changed |= (source_height != screen_width);
236                 stretch_changed |= (source_width_aspect != screen_height_aspect);
237                 stretch_changed |= (source_height_aspect != screen_width_aspect);
238                 
239                 source_width = screen_height;
240                 source_height = screen_width;
241                 source_width_aspect = screen_height_aspect;
242                 source_height_aspect = screen_width_aspect;
243                 
244                 render_to_d3d9Buffer = false;
245         } else {
246 #endif
247                 hdcDibSource = hdcDib;
248                 lpBmpSource = lpBmp;
249                 lpDibSource = lpDib;
250                 pbmInfoHeader = &lpDib->bmiHeader;
251                 
252                 stretch_changed |= (source_width != screen_width);
253                 stretch_changed |= (source_height != screen_height);
254                 stretch_changed |= (source_width_aspect != screen_width_aspect);
255                 stretch_changed |= (source_height_aspect != screen_height_aspect);
256                 
257                 source_width = screen_width;
258                 source_height = screen_height;
259                 source_width_aspect = screen_width_aspect;
260                 source_height_aspect = screen_height_aspect;
261 #ifdef USE_SCREEN_ROTATE
262         }
263 #endif
264         
265         if(config.stretch_type == 1 && !window_mode) {
266                 // fit to full screen (aspect)
267                 stretched_width = (display_height * source_width_aspect) / source_height_aspect;
268                 stretched_height = display_height;
269                 if(stretched_width > display_width) {
270                         stretched_width = display_width;
271                         stretched_height = (display_width * source_height_aspect) / source_width_aspect;
272                 }
273         } else if(config.stretch_type == 2 && !window_mode) {
274                 // fit to full screen (fill)
275                 stretched_width = display_width;
276                 stretched_height = display_height;
277         } else {
278                 // dot by dot
279                 int tmp_pow_x = display_width / source_width_aspect;
280                 int tmp_pow_y = display_height / source_height_aspect;
281                 int tmp_pow = 1;
282                 if(tmp_pow_y >= tmp_pow_x && tmp_pow_x > 1) {
283                         tmp_pow = tmp_pow_x;
284                 } else if(tmp_pow_x >= tmp_pow_y && tmp_pow_y > 1) {
285                         tmp_pow = tmp_pow_y;
286                 }
287                 stretched_width = source_width_aspect * tmp_pow;
288                 stretched_height = source_height_aspect * tmp_pow;
289         }
290         screen_dest_x = (display_width - stretched_width) / 2;
291         screen_dest_y = (display_height - stretched_height) / 2;
292         
293         stretch_changed |= (prev_stretched_width != stretched_width);
294         stretch_changed |= (prev_stretched_height != stretched_height);
295         
296         int new_pow_x = 1, new_pow_y = 1;
297         while(stretched_width > source_width * new_pow_x) {
298                 new_pow_x++;
299         }
300         while(stretched_height > source_height * new_pow_y) {
301                 new_pow_y++;
302         }
303 //      if(!use_d3d9 && new_pow_x > 1 && new_pow_y > 1) {
304 //              // support high quality stretch only for x1 window size in gdi mode
305 //              new_pow_x = new_pow_y = 1;
306 //      }
307         if(stretch_pow_x != new_pow_x || stretch_pow_y != new_pow_y) {
308                 stretch_pow_x = new_pow_x;
309                 stretch_pow_y = new_pow_y;
310                 stretch_changed = true;
311         }
312         if(stretch_pow_x != 1 || stretch_pow_y != 1) {
313                 render_to_d3d9Buffer = false;
314         }
315         
316         if(stretch_changed) {
317                 release_dib_section(hdcDibStretch1, hBmpStretch1, hOldBmpStretch1, lpBufStretch1);
318                 release_dib_section(hdcDibStretch2, hBmpStretch2, hOldBmpStretch2, lpBufStretch2);
319                 stretch_screen = false;
320                 
321                 if(stretch_pow_x != 1 || stretch_pow_y != 1) {
322                         HDC hdc = GetDC(main_window_handle);
323                         create_dib_section(hdc, source_width * stretch_pow_x, source_height * stretch_pow_y, &hdcDibStretch1, &hBmpStretch1, &hOldBmpStretch1, &lpBufStretch1, &lpBmpStretch1, &lpDibStretch1);
324                         SetStretchBltMode(hdcDibStretch1, COLORONCOLOR);
325                         if(!use_d3d9) {
326                                 create_dib_section(hdc, stretched_width, stretched_height, &hdcDibStretch2, &hBmpStretch2, &hOldBmpStretch2, &lpBufStretch2, &lpBmpStretch2, &lpDibStretch2);
327                                 SetStretchBltMode(hdcDibStretch2, HALFTONE);
328                         }
329                         ReleaseDC(main_window_handle, hdc);
330                         stretch_screen = true;
331                 }
332                 
333                 if(use_d3d9 && display_size_changed) {
334                         // release and initialize d3d9
335                         release_d3d9();
336                         
337                         if((lpd3d9 = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) {
338                                 MessageBox(main_window_handle, _T("Failed to initialize Direct3D9"), _T(DEVICE_NAME), MB_OK | MB_ICONWARNING);
339                                 config.use_d3d9 = false;
340                                 goto RETRY;
341                         } else {
342                                 // initialize present params
343                                 D3DPRESENT_PARAMETERS d3dpp;
344                                 ZeroMemory(&d3dpp, sizeof(d3dpp));
345                                 d3dpp.BackBufferWidth = display_width;
346                                 d3dpp.BackBufferHeight = display_height;
347                                 d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;//D3DFMT_UNKNOWN;
348                                 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
349                                 d3dpp.hDeviceWindow = main_window_handle;
350                                 d3dpp.Windowed = TRUE;
351                                 d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
352                                 d3dpp.PresentationInterval = config.wait_vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
353                                 
354                                 // create d3d9 device
355                                 HRESULT hr = lpd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, main_window_handle, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &lpd3d9Device);
356                                 if(hr != D3D_OK) {
357                                         hr = lpd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, main_window_handle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &lpd3d9Device);
358                                         if(hr != D3D_OK) {
359                                                 hr = lpd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, main_window_handle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &lpd3d9Device);
360                                         }
361                                 }
362                                 if(hr != D3D_OK) {
363                                         MessageBox(main_window_handle, _T("Failed to create a Direct3D9 device"), _T(DEVICE_NAME), MB_OK | MB_ICONWARNING);
364                                         config.use_d3d9 = false;
365                                         goto RETRY;
366                                 }
367                         }
368                 }
369                 if(use_d3d9 && lpd3d9Device != NULL) {
370                         // release and create d3d9 surfaces
371                         release_d3d9_surface();
372                         
373                         HRESULT hr = lpd3d9Device->CreateOffscreenPlainSurface(source_width * stretch_pow_x, source_height * stretch_pow_y, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &lpd3d9Surface, NULL);
374                         if(hr == D3D_OK) {
375                                 hr = lpd3d9Device->CreateOffscreenPlainSurface(source_width * stretch_pow_x, source_height * stretch_pow_y, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &lpd3d9OffscreenSurface, NULL);
376                         }
377                         if(hr == D3D_OK) {
378                                 lpd3d9Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 0.0, 0);
379                         } else {
380                                 MessageBox(main_window_handle, _T("Failed to create a Direct3D9 offscreen surface"), _T(DEVICE_NAME), MB_OK | MB_ICONWARNING);
381                                 config.use_d3d9 = false;
382                                 goto RETRY;
383                         }
384                 }
385                 if(stretch_screen) {
386                         render_to_d3d9Buffer = false;
387                 }
388         }
389         
390         first_draw_screen = false;
391         first_invalidate = true;
392         screen_size_changed = false;
393         
394 #ifdef USE_CRT_FILTER
395         memset(r1, 0, sizeof(r1));
396         memset(g1, 0, sizeof(g1));
397         memset(b1, 0, sizeof(b1));
398 #endif
399 }
400
401 void EMU::change_screen_size(int sw, int sh, int swa, int sha, int ww, int wh)
402 {
403         // virtual machine changes the screen size
404         if(screen_width != sw || screen_height != sh) {
405                 screen_width = sw;
406                 screen_height = sh;
407                 screen_width_aspect = (swa != -1) ? swa : sw;
408                 screen_height_aspect = (sha != -1) ? sha : sh;
409                 window_width = ww;
410                 window_height = wh;
411                 screen_size_changed = true;
412                 
413                 // re-create dib sections
414                 HDC hdc = GetDC(main_window_handle);
415                 release_dib_section(hdcDib, hBmp, hOldBmp, lpBuf);
416                 create_dib_section(hdc, screen_width, screen_height, &hdcDib, &hBmp, &hOldBmp, &lpBuf, &lpBmp, &lpDib);
417 #ifdef USE_SCREEN_ROTATE
418                 release_dib_section(hdcDibRotate, hBmpRotate, hOldBmpRotate, lpBufRotate);
419                 create_dib_section(hdc, screen_height, screen_width, &hdcDibRotate, &hBmpRotate, &hOldBmpRotate, &lpBufRotate, &lpBmpRotate, &lpDibRotate);
420 #endif
421                 ReleaseDC(main_window_handle, hdc);
422                 
423                 // stop recording
424                 if(now_rec_video) {
425                         stop_rec_video();
426                         stop_rec_sound();
427                 }
428                 
429                 // change the window size
430                 PostMessage(main_window_handle, WM_RESIZE, 0L, 0L);
431         }
432 }
433
434 int EMU::draw_screen()
435 {
436         // don't draw screen before new screen size is applied to buffers
437         if(screen_size_changed) {
438                 return 0;
439         }
440         
441         // check avi file recording timing
442         if(now_rec_video && rec_video_run_frames <= 0) {
443                 return 0;
444         }
445         
446         // lock offscreen surface
447         D3DLOCKED_RECT pLockedRect;
448         if(use_d3d9 && lpd3d9OffscreenSurface != NULL && lpd3d9OffscreenSurface->LockRect(&pLockedRect, NULL, 0) == D3D_OK) {
449                 lpd3d9Buffer = (scrntype *)pLockedRect.pBits;
450         } else {
451                 lpd3d9Buffer = NULL;
452         }
453         
454         // draw screen
455         vm->draw_screen();
456         
457         // screen size was changed in vm->draw_screen()
458         if(screen_size_changed) {
459                 // unlock offscreen surface
460                 if(use_d3d9 && lpd3d9Buffer != NULL) {
461                         lpd3d9Buffer = NULL;
462                         lpd3d9OffscreenSurface->UnlockRect();
463                 }
464                 return 0;
465         }
466         
467 #ifdef USE_SCREEN_ROTATE
468         // rotate screen
469         if(config.monitor_type) {
470                 for(int y = 0; y < screen_height; y++) {
471                         scrntype* src = lpBmp + screen_width * (screen_height - y - 1);
472                         scrntype* out = lpBmpRotate + screen_height * (screen_width - 1) + (screen_height - y - 1);
473                         for(int x = 0; x < screen_width; x++) {
474                                 *out = src[x];
475                                 out -= screen_height;
476                         }
477                 }
478         }
479 #endif  
480         
481         // stretch screen
482         if(stretch_screen) {
483                 scrntype* src = lpBmpSource + source_width * (source_height - 1);
484                 scrntype* out = lpBmpStretch1 + source_width * stretch_pow_x * (source_height * stretch_pow_y - 1);
485                 int data_len = source_width * stretch_pow_x;
486 #ifdef USE_CRT_FILTER
487                 #define _3_8(v) (((((v) * 3) >> 3) * 180) >> 8)
488                 #define _5_8(v) (((((v) * 3) >> 3) * 180) >> 8)
489                 #define _8_8(v) (((v) * 180) >> 8)
490                 
491                 if(config.crt_filter && stretch_pow_x == 3 && stretch_pow_y == 3) {
492                         r1[0] = g1[0] = b1[0] = r1[source_width + 1] = g1[source_width + 1] = b1[source_width + 1] = 0;
493                         
494                         if(!screen_skip_line) {
495                                 for(int y = 0; y < source_height; y++) {
496                                         for(int x = 1; x <= source_width; x++) {
497                                                 uint32 c = src[x - 1];
498                                                 t0[x] = (c >> 24) & 0xff;
499                                                 r0[x] = (c >> 16) & 0xff;
500                                                 g0[x] = (c >>  8) & 0xff;
501                                                 b0[x] = (c      ) & 0xff;
502                                                 r1[x] = (c >> 19) & 0x1f;
503                                                 g1[x] = (c >> 11) & 0x1f;
504                                                 b1[x] = (c >>  3) & 0x1f;
505                                         }
506                                         scrntype* out1 = out;
507                                         out -= data_len;
508                                         scrntype* out2 = out;
509                                         out -= data_len;
510                                         scrntype* out3 = out;
511                                         out -= data_len;
512                                         for(int x = 1, xx = 0; x <= source_width; x++, xx += 3) {
513                                                 uint32 r = r1[x - 1] + r0[x] + r1[x + 1];
514                                                 uint32 g = g1[x - 1] + g0[x] + g1[x + 1];
515                                                 uint32 b = b1[x - 1] + b0[x] + b1[x + 1];
516                                                 out1[xx    ] = out2[xx    ] = (32 + _8_8(r)) << 16;
517                                                 out1[xx + 1] = out2[xx + 1] = (32 + _8_8(g)) << 8;
518                                                 out1[xx + 2] = out2[xx + 2] = (32 + _8_8(b));
519                                                 if(t0[x]) {
520                                                         out3[xx    ] = (32 + _8_8(r)) << 16;
521                                                         out3[xx + 1] = (32 + _8_8(g)) << 8;
522                                                         out3[xx + 2] = (32 + _8_8(b));
523                                                 } else {
524                                                         out3[xx    ] = (32 + _5_8(r)) << 16;
525                                                         out3[xx + 1] = (32 + _5_8(g)) << 8;
526                                                         out3[xx + 2] = (32 + _5_8(b));
527                                                 }
528                                         }
529                                         src -= source_width;
530                                 }
531                         } else {
532                                 for(int y = 0; y < source_height; y += 2) {
533                                         for(int x = 1; x <= source_width; x++) {
534                                                 uint32 c = src[x - 1];
535                                                 t0[x] = (c >> 24) & 0xff;
536                                                 r0[x] = (c >> 16) & 0xff;
537                                                 g0[x] = (c >>  8) & 0xff;
538                                                 b0[x] = (c      ) & 0xff;
539                                                 r1[x] = (c >> 20) & 0x0f;
540                                                 g1[x] = (c >> 12) & 0x0f;
541                                                 b1[x] = (c >>  4) & 0x0f;
542                                         }
543                                         scrntype* out1 = out;
544                                         out -= data_len;
545                                         scrntype* out2 = out;
546                                         out -= data_len;
547                                         scrntype* out3 = out;
548                                         out -= data_len;
549                                         scrntype* out4 = out;
550                                         out -= data_len;
551                                         scrntype* out5 = out;
552                                         out -= data_len;
553                                         scrntype* out6 = out;
554                                         out -= data_len;
555                                         for(int x = 1, xx = 0; x <= source_width; x++, xx += 3) {
556                                                 uint32 r = r1[x - 1] + r0[x] + r1[x + 1];
557                                                 uint32 g = g1[x - 1] + g0[x] + g1[x + 1];
558                                                 uint32 b = b1[x - 1] + b0[x] + b1[x + 1];
559                                                 out1[xx    ] = out2[xx    ] = out3[xx    ] = out4[xx    ] = (32 + _8_8(r)) << 16;
560                                                 out1[xx + 1] = out2[xx + 1] = out3[xx + 1] = out4[xx + 1] = (32 + _8_8(g)) << 8;
561                                                 out1[xx + 2] = out2[xx + 2] = out3[xx + 2] = out4[xx + 2] = (32 + _8_8(b));
562                                                 if(t0[x]) {
563                                                         out5[xx    ] = out6[xx    ] = (32 + _8_8(r)) << 16;
564                                                         out5[xx + 1] = out6[xx + 1] = (32 + _8_8(g)) << 8;
565                                                         out5[xx + 2] = out6[xx + 2] = (32 + _8_8(b));
566                                                 } else {
567                                                         out5[xx    ] = out6[xx    ] = (32 + _5_8(r)) << 16;
568                                                         out5[xx + 1] = out6[xx + 1] = (32 + _5_8(g)) << 8;
569                                                         out5[xx + 2] = out6[xx + 2] = (32 + _5_8(b));
570                                                 }
571                                         }
572                                         src -= source_width * 2;
573                                 }
574                         }
575                 } else if(config.crt_filter && stretch_pow_x == 2 && stretch_pow_y == 2) {
576                         if(!screen_skip_line) {
577                                 for(int y = 0; y < source_height; y++) {
578                                         for(int x = 1; x <= source_width; x++) {
579                                                 uint32 c = src[x - 1];
580                                                 t0[x] = (c >> 24) & 0xff;
581                                                 r0[x] = (c >> 16) & 0xff;
582                                                 g0[x] = (c >>  8) & 0xff;
583                                                 b0[x] = (c      ) & 0xff;
584                                                 r1[x] = (c >> 19) & 0x1f;
585                                                 g1[x] = (c >> 11) & 0x1f;
586                                                 b1[x] = (c >>  3) & 0x1f;
587                                         }
588                                         scrntype* out1 = out;
589                                         out -= data_len;
590                                         scrntype* out2 = out;
591                                         out -= data_len;
592                                         for(int x = 1, xx = 0; x <= source_width; x++, xx += 2) {
593                                                 uint32 r = r1[x - 1] + r0[x] + r1[x + 1];
594                                                 uint32 g = g1[x - 1] + g0[x] + g1[x + 1];
595                                                 uint32 b = b1[x - 1] + b0[x] + b1[x + 1];
596                                                 out1[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));
597                                                 out1[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));
598                                                 if(t0[x]) {
599                                                         out2[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));
600                                                         out2[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));
601                                                 } else {
602                                                         out2[xx    ] = RGB_COLOR(32 + _3_8(r), 32 + _3_8(g), 32 + _3_8(b));
603                                                         out2[xx + 1] = RGB_COLOR(16 + _3_8(r), 16 + _3_8(g), 16 + _3_8(b));
604                                                 }
605                                         }
606                                         src -= source_width;
607                                 }
608                         } else {
609                                 for(int y = 0; y < source_height; y += 2) {
610                                         for(int x = 1; x <= source_width; x++) {
611                                                 uint32 c = src[x - 1];
612                                                 t0[x] = (c >> 24) & 0xff;
613                                                 r0[x] = (c >> 16) & 0xff;
614                                                 g0[x] = (c >>  8) & 0xff;
615                                                 b0[x] = (c      ) & 0xff;
616                                                 r1[x] = (c >> 19) & 0x1f;
617                                                 g1[x] = (c >> 11) & 0x1f;
618                                                 b1[x] = (c >>  3) & 0x1f;
619                                         }
620                                         scrntype* out1 = out;
621                                         out -= data_len;
622                                         scrntype* out2 = out;
623                                         out -= data_len;
624                                         scrntype* out3 = out;
625                                         out -= data_len;
626                                         scrntype* out4 = out;
627                                         out -= data_len;
628                                         for(int x = 1, xx = 0; x <= source_width; x++, xx += 2) {
629                                                 uint32 r = r1[x - 1] + r0[x] + r1[x + 1];
630                                                 uint32 g = g1[x - 1] + g0[x] + g1[x + 1];
631                                                 uint32 b = b1[x - 1] + b0[x] + b1[x + 1];
632                                                 out1[xx    ] = out2[xx    ] = out3[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));
633                                                 out1[xx + 1] = out2[xx + 1] = out3[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));
634                                                 if(t0[x]) {
635                                                         out4[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));
636                                                         out4[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));
637                                                 } else {
638                                                         out4[xx    ] = RGB_COLOR(32 + _3_8(r), 32 + _3_8(g), 32 + _3_8(b));
639                                                         out4[xx + 1] = RGB_COLOR(16 + _3_8(r), 16 + _3_8(g), 16 + _3_8(b));
640                                                 }
641                                         }
642                                         src -= source_width * 2;
643                                 }
644                         }
645                 } else
646 #endif
647                 for(int y = 0; y < source_height; y++) {
648                         if(stretch_pow_x != 1) {
649                                 scrntype* out_tmp = out;
650                                 for(int x = 0; x < source_width; x++) {
651                                         scrntype c = src[x];
652                                         for(int px = 0; px < stretch_pow_x; px++) {
653                                                 out_tmp[px] = c;
654                                         }
655                                         out_tmp += stretch_pow_x;
656                                 }
657                         } else {
658                                 // faster than memcpy()
659                                 for(int x = 0; x < source_width; x++) {
660                                         out[x] = src[x];
661                                 }
662                         }
663                         if(stretch_pow_y != 1) {
664                                 scrntype* src_tmp = out;
665                                 for(int py = 1; py < stretch_pow_y; py++) {
666                                         out -= data_len;
667                                         // about 10% faster than memcpy()
668                                         for(int x = 0; x < data_len; x++) {
669                                                 out[x] = src_tmp[x];
670                                         }
671                                 }
672                         }
673                         src -= source_width;
674                         out -= data_len;
675                 }
676                 if(!use_d3d9) {
677                         StretchBlt(hdcDibStretch2, 0, 0, stretched_width, stretched_height, hdcDibStretch1, 0, 0, source_width * stretch_pow_x, source_height * stretch_pow_y, SRCCOPY);
678                 }
679         }
680         first_draw_screen = true;
681         
682         // copy bitmap to d3d9 offscreen surface
683         if(use_d3d9 && lpd3d9Buffer != NULL) {
684                 if(!(render_to_d3d9Buffer && !now_rec_video)) {
685                         scrntype *src = stretch_screen ? lpBmpStretch1 : lpBmpSource;
686                         src += source_width * stretch_pow_x * (source_height * stretch_pow_y - 1);
687                         scrntype *out = lpd3d9Buffer;
688                         int data_len = source_width * stretch_pow_x;
689                         
690                         for(int y = 0; y < source_height * stretch_pow_y; y++) {
691                                 for(int i = 0; i < data_len; i++) {
692                                         out[i] = src[i];
693                                 }
694                                 src -= data_len;
695                                 out += data_len;
696                         }
697                 }
698                 // unlock offscreen surface
699                 lpd3d9Buffer = NULL;
700                 lpd3d9OffscreenSurface->UnlockRect();
701         }
702         
703         // invalidate window
704         InvalidateRect(main_window_handle, NULL, first_invalidate);
705         UpdateWindow(main_window_handle);
706         self_invalidate = true;
707         
708         // record avi file
709         if(now_rec_video) {
710                 static double frames = 0;
711                 static int prev_video_fps = -1;
712 #ifdef SUPPORT_VARIABLE_TIMING
713                 static double prev_vm_fps = -1;
714                 double vm_fps = vm->frame_rate();
715                 if(prev_video_fps != rec_video_fps || prev_vm_fps != vm_fps) {
716                         prev_video_fps = rec_video_fps;
717                         prev_vm_fps = vm_fps;
718                         frames = vm_fps / rec_video_fps;
719                 }
720 #else
721                 if(prev_video_fps != rec_video_fps) {
722                         prev_video_fps = rec_video_fps;
723                         frames = FRAMES_PER_SEC / rec_video_fps;
724                 }
725 #endif
726                 int counter = 0;
727                 if(use_video_thread) {
728                         while(rec_video_run_frames > 0) {
729                                 rec_video_run_frames -= frames;
730                                 rec_video_frames += frames;
731                                 counter++;
732                         }
733                         if(counter != 0) {
734                                 if(hVideoThread != (HANDLE)0) {
735                                         if(video_thread_param.result == 0) {
736                                                 WaitForSingleObject(hVideoThread, INFINITE);
737                                         }
738                                         hVideoThread = (HANDLE)0;
739                                         
740                                         if(video_thread_param.result == RESULT_FULL) {
741                                                 stop_rec_video();
742                                                 if(!start_rec_video(-1)) {
743                                                         return 0;
744                                                 }
745                                         } else if(video_thread_param.result == RESULT_ERROR) {
746                                                 stop_rec_video();
747                                                 return 0;
748                                         }
749                                 }
750                                 BitBlt(hdcDibRec, 0, 0, source_width, source_height, hdcDibSource, 0, 0, SRCCOPY);
751                                 video_thread_param.frames += counter;
752                                 video_thread_param.result = 0;
753                                 if((hVideoThread = (HANDLE)_beginthreadex(NULL, 0, rec_video_thread, &video_thread_param, 0, NULL)) == (HANDLE)0) {
754                                         stop_rec_video();
755                                         return 0;
756                                 }
757                         }
758                 } else {
759                         while(rec_video_run_frames > 0) {
760                                 LONG lBytesWritten;
761                                 if(AVIStreamWrite(pAVICompressed, lAVIFrames++, 1, (LPBYTE)lpBmpSource, pbmInfoHeader->biSizeImage, AVIIF_KEYFRAME, NULL, &lBytesWritten) == AVIERR_OK) {
762                                         // if avi file size > (2GB - 16MB), create new avi file
763                                         if((dwAVIFileSize += lBytesWritten) >= 2130706432) {
764                                                 stop_rec_video();
765                                                 if(!start_rec_video(-1)) {
766                                                         break;
767                                                 }
768                                         }
769                                         rec_video_run_frames -= frames;
770                                         rec_video_frames += frames;
771                                         counter++;
772                                 } else {
773                                         stop_rec_video();
774                                         break;
775                                 }
776                         }
777                 }
778                 return counter;
779         } else {
780                 return 1;
781         }
782 }
783
784 scrntype* EMU::screen_buffer(int y)
785 {
786         if(use_d3d9 && lpd3d9Buffer != NULL && render_to_d3d9Buffer && !now_rec_video) {
787                 return lpd3d9Buffer + screen_width * y;
788         }
789         return lpBmp + screen_width * (screen_height - y - 1);
790 }
791
792 void EMU::update_screen(HDC hdc)
793 {
794 #ifdef USE_BITMAP
795         if(first_invalidate || !self_invalidate) {
796                 HDC hmdc = CreateCompatibleDC(hdc);
797                 HBITMAP hBitmap = LoadBitmap(instance_handle, _T("IDI_BITMAP1"));
798                 BITMAP bmp;
799                 GetObject(hBitmap, sizeof(BITMAP), &bmp);
800                 int w = (int)bmp.bmWidth;
801                 int h = (int)bmp.bmHeight;
802                 HBITMAP hOldBitmap = (HBITMAP)SelectObject(hmdc, hBitmap);
803                 BitBlt(hdc, 0, 0, w, h, hmdc, 0, 0, SRCCOPY);
804                 SelectObject(hmdc, hOldBitmap);
805                 DeleteObject(hBitmap);
806                 DeleteDC(hmdc);
807         }
808 #endif
809         if(first_draw_screen) {
810 #ifdef USE_LED
811                 // 7-seg LEDs
812                 for(int i = 0; i < MAX_LEDS; i++) {
813                         int x = leds[i].x;
814                         int y = leds[i].y;
815                         int w = leds[i].width;
816                         int h = leds[i].height;
817                         BitBlt(hdc, x, y, w, h, hdcDib, x, y, SRCCOPY);
818                 }
819 #else
820 #ifdef USE_ACCESS_LAMP
821                 // get access lamps status of drives
822                 int status = vm->access_lamp() & 7;
823                 static int prev_status = 0;
824                 bool render_in = (status != 0);
825                 bool render_out = (prev_status != status);
826                 prev_status = status;
827                 
828                 COLORREF crColor = RGB((status & 1) ? 255 : 0, (status & 2) ? 255 : 0, (status & 4) ? 255 : 0);
829                 int right_bottom_x = screen_dest_x + stretched_width;
830                 int right_bottom_y = screen_dest_y + stretched_height;
831 #endif
832                 // standard screen
833                 if(use_d3d9) {
834                         LPDIRECT3DSURFACE9 lpd3d9BackSurface = NULL;
835                         if(lpd3d9Device != NULL && lpd3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &lpd3d9BackSurface) == D3D_OK && lpd3d9BackSurface != NULL) {
836                                 RECT rectSrc = { 0, 0, source_width * stretch_pow_x, source_height * stretch_pow_y };
837                                 RECT rectDst = { screen_dest_x, screen_dest_y, screen_dest_x + stretched_width, screen_dest_y + stretched_height };
838                                 
839                                 lpd3d9Device->UpdateSurface(lpd3d9OffscreenSurface, NULL, lpd3d9Surface, NULL);
840                                 lpd3d9Device->StretchRect(lpd3d9Surface, &rectSrc, lpd3d9BackSurface, &rectDst, stretch_screen ? D3DTEXF_LINEAR : D3DTEXF_POINT);
841 #ifdef USE_ACCESS_LAMP
842                                 // draw access lamps
843                                 if(render_in || render_out) {
844                                         HDC hDC = 0;
845                                         for(int y = display_height - 6; y < display_height; y++) {
846                                                 for(int x = display_width - 6; x < display_width; x++) {
847                                                         if((x < right_bottom_x && y < right_bottom_y) ? render_in : render_out) {
848                                                                 if(hDC == 0 && lpd3d9BackSurface->GetDC(&hDC) != D3D_OK) {
849                                                                         goto quit;
850                                                                 }
851                                                                 SetPixelV(hDC, x, y, crColor);
852                                                         }
853                                                 }
854                                         }
855 quit:
856                                         if(hDC != 0) {
857                                                 lpd3d9BackSurface->ReleaseDC(hDC);
858                                         }
859                                 }
860 #endif
861                                 lpd3d9BackSurface->Release();
862                                 lpd3d9Device->Present(NULL, NULL, NULL, NULL);
863                         }
864                 } else {
865                         if(stretch_screen) {
866                                 BitBlt(hdc, screen_dest_x, screen_dest_y, stretched_width, stretched_height, hdcDibStretch2, 0, 0, SRCCOPY);
867                         } else if(stretched_width == source_width && stretched_height == source_height) {
868                                 BitBlt(hdc, screen_dest_x, screen_dest_y, stretched_width, stretched_height, hdcDibSource, 0, 0, SRCCOPY);
869                         } else {
870                                 StretchBlt(hdc, screen_dest_x, screen_dest_y, stretched_width, stretched_height, hdcDibSource, 0, 0, source_width, source_height, SRCCOPY);
871                         }
872 #ifdef USE_ACCESS_LAMP
873                         // draw access lamps
874                         if(render_in || render_out) {
875                                 for(int y = display_height - 6; y < display_height; y++) {
876                                         for(int x = display_width - 6; x < display_width; x++) {
877                                                 if((x < right_bottom_x && y < right_bottom_y) ? render_in : render_out) {
878                                                         SetPixelV(hdc, x, y, crColor);
879                                                 }
880                                         }
881                                 }
882                         }
883 #endif
884                 }
885 #endif
886                 first_invalidate = self_invalidate = false;
887         }
888 }
889
890 void EMU::capture_screen()
891 {
892         if(use_d3d9 && render_to_d3d9Buffer && !now_rec_video) {
893                 // virtual machine may render screen to d3d9 buffer directly...
894                 vm->draw_screen();
895         }
896         
897         // create file name
898         SYSTEMTIME sTime;
899         GetLocalTime(&sTime);
900         
901         _TCHAR file_name[_MAX_PATH];
902         _stprintf_s(file_name, _MAX_PATH, _T("%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.bmp"), sTime.wYear, sTime.wMonth, sTime.wDay, sTime.wHour, sTime.wMinute, sTime.wSecond);
903         
904         // create bitmap
905         BITMAPFILEHEADER bmFileHeader = { (WORD)(TEXT('B') | TEXT('M') << 8) };
906         bmFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
907         bmFileHeader.bfSize = bmFileHeader.bfOffBits + pbmInfoHeader->biSizeImage;
908         
909         DWORD dwSize;
910         HANDLE hFile = CreateFile(bios_path(file_name), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
911         WriteFile(hFile, &bmFileHeader, sizeof(BITMAPFILEHEADER), &dwSize, NULL);
912         WriteFile(hFile, lpDibSource, sizeof(BITMAPINFOHEADER), &dwSize, NULL);
913         WriteFile(hFile, lpBmpSource, pbmInfoHeader->biSizeImage, &dwSize, NULL);
914         CloseHandle(hFile);
915 }
916
917 bool EMU::start_rec_video(int fps)
918 {
919         if(fps > 0) {
920                 rec_video_fps = fps;
921                 rec_video_run_frames = rec_video_frames = 0;
922         } else {
923                 fps = rec_video_fps;
924         }
925         bool show_dialog = (fps > 0);
926         
927         // create file name
928         SYSTEMTIME sTime;
929         GetLocalTime(&sTime);
930         
931         _stprintf_s(video_file_name, _MAX_PATH, _T("%d-%0.2d-%0.2d_%0.2d-%0.2d-%0.2d.avi"), sTime.wYear, sTime.wMonth, sTime.wDay, sTime.wHour, sTime.wMinute, sTime.wSecond);
932         
933         // initialize vfw
934         AVIFileInit();
935         if(AVIFileOpen(&pAVIFile, bios_path(video_file_name), OF_WRITE | OF_CREATE, NULL) != AVIERR_OK) {
936                 return false;
937         }
938         use_video_thread = false;
939         
940         // stream header
941         AVISTREAMINFO strhdr;
942         memset(&strhdr, 0, sizeof(strhdr));
943         strhdr.fccType = streamtypeVIDEO;       // vids
944         strhdr.fccHandler = 0;
945         strhdr.dwScale = 1;
946         strhdr.dwRate = fps;
947         strhdr.dwSuggestedBufferSize = pbmInfoHeader->biSizeImage;
948         SetRect(&strhdr.rcFrame, 0, 0, source_width, source_height);
949         if(AVIFileCreateStream(pAVIFile, &pAVIStream, &strhdr) != AVIERR_OK) {
950                 stop_rec_video();
951                 return false;
952         }
953         
954         // compression
955         AVICOMPRESSOPTIONS FAR * pOpts[1];
956         pOpts[0] = &opts;
957         if(show_dialog && !AVISaveOptions(main_window_handle, ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE, 1, &pAVIStream, (LPAVICOMPRESSOPTIONS FAR *)&pOpts)) {
958                 AVISaveOptionsFree(1, (LPAVICOMPRESSOPTIONS FAR *)&pOpts);
959                 stop_rec_video();
960                 return false;
961         }
962         if(AVIMakeCompressedStream(&pAVICompressed, pAVIStream, &opts, NULL) != AVIERR_OK) {
963                 stop_rec_video();
964                 return false;
965         }
966         if(AVIStreamSetFormat(pAVICompressed, 0, &lpDibSource->bmiHeader, lpDibSource->bmiHeader.biSize + lpDibSource->bmiHeader.biClrUsed * sizeof(RGBQUAD)) != AVIERR_OK) {
967                 stop_rec_video();
968                 return false;
969         }
970         dwAVIFileSize = 0;
971         lAVIFrames = 0;
972         
973         SYSTEM_INFO info;
974         GetSystemInfo(&info);
975         
976         if(info.dwNumberOfProcessors > 1) {
977                 use_video_thread = true;
978                 hVideoThread = (HANDLE)0;
979                 video_thread_param.pAVICompressed = pAVICompressed;
980                 video_thread_param.lpBmpSource = lpBmpSource;
981                 video_thread_param.pbmInfoHeader = pbmInfoHeader;
982                 video_thread_param.dwAVIFileSize = 0;
983                 video_thread_param.lAVIFrames = 0;
984                 video_thread_param.frames = 0;
985                 video_thread_param.result = 0;
986                 
987                 HDC hdc = GetDC(main_window_handle);
988                 create_dib_section(hdc, source_width, source_height, &hdcDibRec, &hBmpRec, &hOldBmpRec, &lpBufRec, &lpBmpRec, &lpDibRec);
989                 ReleaseDC(main_window_handle, hdc);
990         }
991         now_rec_video = true;
992         return true;
993 }
994
995 void EMU::stop_rec_video()
996 {
997         // release thread
998         if(use_video_thread) {
999                 if(hVideoThread != (HANDLE)0) {
1000                         WaitForSingleObject(hVideoThread, INFINITE);
1001                         hVideoThread = (HANDLE)0;
1002                 }
1003                 if(hdcDibRec) {
1004                         release_dib_section(hdcDibRec, hBmpRec, hOldBmpRec, lpBufRec);
1005                 }
1006         }
1007         
1008         // release vfw
1009         if(pAVIStream) {
1010                 AVIStreamClose(pAVIStream);
1011         }
1012         if(pAVICompressed) {
1013                 AVIStreamClose(pAVICompressed);
1014         }
1015         if(pAVIFile) {
1016                 AVIFileClose(pAVIFile);
1017                 AVIFileExit();
1018         }
1019         pAVIStream = NULL;
1020         pAVICompressed = NULL;
1021         pAVIFile = NULL;
1022         
1023         // repair header
1024         if(now_rec_video) {
1025                 FILE* fp = NULL;
1026                 if(_tfopen_s(&fp, bios_path(video_file_name), _T("r+b")) == 0) {
1027                         // copy fccHandler
1028                         uint8 buf[4];
1029                         fseek(fp, 0xbc, SEEK_SET);
1030                         if(ftell(fp) == 0xbc) {
1031                                 fread(buf, 4, 1, fp);
1032                                 fseek(fp, 0x70, SEEK_SET);
1033                                 fwrite(buf, 4, 1, fp);
1034                         }
1035                         fclose(fp);
1036                 }
1037         }
1038         now_rec_video = false;
1039 }
1040
1041 void EMU::restart_rec_video()
1042 {
1043         bool tmp = now_rec_video;
1044         stop_rec_video();
1045         if(tmp) start_rec_video(-1);
1046 }
1047
1048 unsigned __stdcall rec_video_thread(void *lpx)
1049 {
1050         volatile video_thread_t *p = (video_thread_t *)lpx;
1051         LONG lBytesWritten;
1052         int result = RESULT_SUCCESS;
1053         
1054         while(p->frames > 0) {
1055                 if(AVIStreamWrite(p->pAVICompressed, p->lAVIFrames++, 1, (LPBYTE)p->lpBmpSource, p->pbmInfoHeader->biSizeImage, AVIIF_KEYFRAME, NULL, &lBytesWritten) == AVIERR_OK) {
1056                         p->frames--;
1057                         // if avi file size > (2GB - 16MB), create new avi file
1058                         if((p->dwAVIFileSize += lBytesWritten) >= 2130706432) {
1059                                 result = RESULT_FULL;
1060                                 break;
1061                         }
1062                 } else {
1063                         result = RESULT_ERROR;
1064                         break;
1065                 }
1066         }
1067         p->result = result;
1068         _endthreadex(0);
1069         return 0;
1070 }
1071