OSDN Git Service

[General] Convert sourcecode's CRLF format: DOS(WINDOWS) to Unix, to apply patches...
[csp-qt/common_source_project-fm7.git] / source / src / win32_screen.cpp
index 49b998a..f87a2cf 100644 (file)
-/*\r
-       Skelton for retropc emulator\r
-\r
-       Author : Takeda.Toshiya\r
-       Date   : 2006.08.18 -\r
-\r
-       [ win32 screen ]\r
-*/\r
-\r
-#include "emu.h"\r
-#include "vm/vm.h"\r
-\r
-#define RESULT_SUCCESS 1\r
-#define RESULT_FULL    2\r
-#define RESULT_ERROR   3\r
-\r
-unsigned __stdcall rec_video_thread(void *lpx);\r
-\r
-#ifdef USE_CRT_FILTER\r
-static uint8 r0[2048], g0[2048], b0[2048], t0[2048];\r
-static uint8 r1[2048], g1[2048], b1[2048];\r
-#endif\r
-\r
-void EMU::initialize_screen()\r
-{\r
-       screen_width = SCREEN_WIDTH;\r
-       screen_height = SCREEN_HEIGHT;\r
-       screen_width_aspect = SCREEN_WIDTH_ASPECT;\r
-       screen_height_aspect = SCREEN_HEIGHT_ASPECT;\r
-       window_width = WINDOW_WIDTH;\r
-       window_height = WINDOW_HEIGHT;\r
-       screen_size_changed = true;\r
-       \r
-       source_width = source_height = -1;\r
-       source_width_aspect = source_height_aspect = -1;\r
-       stretch_pow_x = stretch_pow_y = -1;\r
-       stretch_screen = false;\r
-       \r
-       // create dib sections\r
-       HDC hdc = GetDC(main_window_handle);\r
-       create_dib_section(hdc, screen_width, screen_height, &hdcDib, &hBmp, &hOldBmp, &lpBuf, &lpBmp, &lpDib);\r
-#ifdef USE_SCREEN_ROTATE\r
-       create_dib_section(hdc, screen_height, screen_width, &hdcDibRotate, &hBmpRotate, &hOldBmpRotate, &lpBufRotate, &lpBmpRotate, &lpDibRotate);\r
-#endif\r
-       ReleaseDC(main_window_handle, hdc);\r
-       \r
-       hdcDibStretch1 = hdcDibStretch2 = NULL;\r
-       hBmpStretch1 = hOldBmpStretch1 = hBmpStretch2 = hOldBmpStretch2 = NULL;\r
-       lpBufStretch1 = lpBufStretch2 = NULL;\r
-       \r
-       // initialize d3d9\r
-       lpd3d9 = NULL;\r
-       lpd3d9Device = NULL;\r
-       lpd3d9Surface = NULL;\r
-       lpd3d9OffscreenSurface = NULL;\r
-       lpd3d9Buffer = NULL;\r
-       render_to_d3d9Buffer = false;\r
-       use_d3d9 = config.use_d3d9;\r
-       wait_vsync = config.wait_vsync;\r
-       \r
-       // initialize video recording\r
-       now_rec_video = false;\r
-       hdcDibRec = NULL;\r
-       pAVIStream = NULL;\r
-       pAVICompressed = NULL;\r
-       pAVIFile = NULL;\r
-       \r
-       // initialize update flags\r
-       first_draw_screen = false;\r
-       first_invalidate = self_invalidate = false;\r
-       \r
-#ifdef USE_CRT_FILTER\r
-       // initialize crtc filter\r
-       memset(r1, 0, sizeof(r1));\r
-       memset(g1, 0, sizeof(g1));\r
-       memset(b1, 0, sizeof(b1));\r
-#endif\r
-}\r
-\r
-#define release_dib_section(hdcdib, hbmp, holdbmp, lpbuf) { \\r
-       if(hdcdib != NULL && holdbmp != NULL) { \\r
-               SelectObject(hdcdib, holdbmp); \\r
-       } \\r
-       if(hbmp != NULL) { \\r
-               DeleteObject(hbmp); \\r
-               hbmp = NULL; \\r
-       } \\r
-       if(lpbuf != NULL) { \\r
-               GlobalFree(lpbuf); \\r
-               lpbuf = NULL; \\r
-       } \\r
-       if(hdcdib != NULL) { \\r
-               DeleteDC(hdcdib); \\r
-               hdcdib = NULL; \\r
-       } \\r
-}\r
-\r
-#define release_d3d9() { \\r
-       if(lpd3d9OffscreenSurface != NULL) { \\r
-               lpd3d9OffscreenSurface->Release(); \\r
-               lpd3d9OffscreenSurface = NULL; \\r
-       } \\r
-       if(lpd3d9Surface != NULL) { \\r
-               lpd3d9Surface->Release(); \\r
-               lpd3d9Surface = NULL; \\r
-       } \\r
-       if(lpd3d9Device != NULL) { \\r
-               lpd3d9Device->Release(); \\r
-               lpd3d9Device = NULL; \\r
-       } \\r
-       if(lpd3d9 != NULL) { \\r
-               lpd3d9->Release(); \\r
-               lpd3d9 = NULL; \\r
-       } \\r
-}\r
-\r
-#define release_d3d9_surface() { \\r
-       if(lpd3d9OffscreenSurface != NULL) { \\r
-               lpd3d9OffscreenSurface->Release(); \\r
-               lpd3d9OffscreenSurface = NULL; \\r
-       } \\r
-       if(lpd3d9Surface != NULL) { \\r
-               lpd3d9Surface->Release(); \\r
-               lpd3d9Surface = NULL; \\r
-       } \\r
-}\r
-\r
-void EMU::release_screen()\r
-{\r
-       // stop video recording\r
-       stop_rec_video();\r
-       \r
-       // release dib sections\r
-       release_dib_section(hdcDib, hBmp, hOldBmp, lpBuf);\r
-#ifdef USE_SCREEN_ROTATE\r
-       release_dib_section(hdcDibRotate, hBmpRotate, hOldBmpRotate, lpBufRotate);\r
-#endif\r
-       release_dib_section(hdcDibStretch1, hBmpStretch1, hOldBmpStretch1, lpBufStretch1);\r
-       release_dib_section(hdcDibStretch2, hBmpStretch2, hOldBmpStretch2, lpBufStretch2);\r
-       \r
-       // release d3d9\r
-       release_d3d9();\r
-}\r
-\r
-void EMU::create_dib_section(HDC hdc, int width, int height, HDC *hdcDib, HBITMAP *hBmp, HBITMAP *hOldBmp, LPBYTE *lpBuf, scrntype **lpBmp, LPBITMAPINFO *lpDib)\r
-{\r
-       *hdcDib = CreateCompatibleDC(hdc);\r
-       *lpBuf = (LPBYTE)GlobalAlloc(GPTR, sizeof(BITMAPINFO));\r
-       *lpDib = (LPBITMAPINFO)(*lpBuf);\r
-       memset(&(*lpDib)->bmiHeader, 0, sizeof(BITMAPINFOHEADER));\r
-       (*lpDib)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\r
-       (*lpDib)->bmiHeader.biWidth = width;\r
-       (*lpDib)->bmiHeader.biHeight = height;\r
-       (*lpDib)->bmiHeader.biPlanes = 1;\r
-#if defined(_RGB555)\r
-       (*lpDib)->bmiHeader.biBitCount = 16;\r
-       (*lpDib)->bmiHeader.biCompression = BI_RGB;\r
-       (*lpDib)->bmiHeader.biSizeImage = width * height * 2;\r
-#elif defined(_RGB565)\r
-       (*lpDib)->bmiHeader.biBitCount = 16;\r
-       (*lpDib)->bmiHeader.biCompression = BI_BITFIELDS;\r
-       LPDWORD lpBf = (LPDWORD)*lpDib->bmiColors;\r
-       lpBf[0] = 0x1f << 11;\r
-       lpBf[1] = 0x3f << 5;\r
-       lpBf[2] = 0x1f << 0;\r
-       (*lpDib)->bmiHeader.biSizeImage = width * height * 2;\r
-#elif defined(_RGB888)\r
-       (*lpDib)->bmiHeader.biBitCount = 32;\r
-       (*lpDib)->bmiHeader.biCompression = BI_RGB;\r
-       (*lpDib)->bmiHeader.biSizeImage = width * height * 4;\r
-#endif\r
-       (*lpDib)->bmiHeader.biXPelsPerMeter = 0;\r
-       (*lpDib)->bmiHeader.biYPelsPerMeter = 0;\r
-       (*lpDib)->bmiHeader.biClrUsed = 0;\r
-       (*lpDib)->bmiHeader.biClrImportant = 0;\r
-       *hBmp = CreateDIBSection(hdc, *lpDib, DIB_RGB_COLORS, (PVOID*)&(*lpBmp), NULL, 0);\r
-       *hOldBmp = (HBITMAP)SelectObject(*hdcDib, *hBmp);\r
-}\r
-\r
-int EMU::get_window_width(int mode)\r
-{\r
-#ifdef USE_SCREEN_ROTATE\r
-       if(config.monitor_type) {\r
-               return window_height + screen_height_aspect * mode;\r
-       }\r
-#endif\r
-       return window_width + screen_width_aspect * mode;\r
-}\r
-\r
-int EMU::get_window_height(int mode)\r
-{\r
-#ifdef USE_SCREEN_ROTATE\r
-       if(config.monitor_type) {\r
-               return window_width + screen_width_aspect * mode;\r
-       }\r
-#endif\r
-       return window_height + screen_height_aspect * mode;\r
-}\r
-\r
-void EMU::set_display_size(int width, int height, bool window_mode)\r
-{\r
-RETRY:\r
-       bool display_size_changed = false;\r
-       bool stretch_changed = false;\r
-       int prev_stretched_width = stretched_width;\r
-       int prev_stretched_height = stretched_height;\r
-       \r
-       if(width != -1 && (display_width != width || display_height != height)) {\r
-               display_width = width;\r
-               display_height = height;\r
-               display_size_changed = stretch_changed = true;\r
-       }\r
-       if(use_d3d9 != config.use_d3d9) {\r
-               if(!(use_d3d9 = config.use_d3d9)) {\r
-                       release_d3d9();\r
-               }\r
-               display_size_changed = stretch_changed = true;\r
-       }\r
-       if(wait_vsync != config.wait_vsync) {\r
-               wait_vsync = config.wait_vsync;\r
-               display_size_changed = stretch_changed = true;\r
-       }\r
-       \r
-       // virtual machine renders to d3d9 buffer directly???\r
-       render_to_d3d9Buffer = use_d3d9;\r
-       \r
-#ifdef USE_SCREEN_ROTATE\r
-       if(config.monitor_type) {\r
-               hdcDibSource = hdcDibRotate;\r
-               lpBmpSource = lpBmpRotate;\r
-               lpDibSource = lpDibRotate;\r
-               pbmInfoHeader = &lpDibRotate->bmiHeader;\r
-               \r
-               stretch_changed |= (source_width != screen_height);\r
-               stretch_changed |= (source_height != screen_width);\r
-               stretch_changed |= (source_width_aspect != screen_height_aspect);\r
-               stretch_changed |= (source_height_aspect != screen_width_aspect);\r
-               \r
-               source_width = screen_height;\r
-               source_height = screen_width;\r
-               source_width_aspect = screen_height_aspect;\r
-               source_height_aspect = screen_width_aspect;\r
-               \r
-               render_to_d3d9Buffer = false;\r
-       } else {\r
-#endif\r
-               hdcDibSource = hdcDib;\r
-               lpBmpSource = lpBmp;\r
-               lpDibSource = lpDib;\r
-               pbmInfoHeader = &lpDib->bmiHeader;\r
-               \r
-               stretch_changed |= (source_width != screen_width);\r
-               stretch_changed |= (source_height != screen_height);\r
-               stretch_changed |= (source_width_aspect != screen_width_aspect);\r
-               stretch_changed |= (source_height_aspect != screen_height_aspect);\r
-               \r
-               source_width = screen_width;\r
-               source_height = screen_height;\r
-               source_width_aspect = screen_width_aspect;\r
-               source_height_aspect = screen_height_aspect;\r
-#ifdef USE_SCREEN_ROTATE\r
-       }\r
-#endif\r
-       \r
-       if(config.stretch_type == 1 && !window_mode) {\r
-               // fit to full screen (aspect)\r
-               stretched_width = (display_height * source_width_aspect) / source_height_aspect;\r
-               stretched_height = display_height;\r
-               if(stretched_width > display_width) {\r
-                       stretched_width = display_width;\r
-                       stretched_height = (display_width * source_height_aspect) / source_width_aspect;\r
-               }\r
-       } else if(config.stretch_type == 2 && !window_mode) {\r
-               // fit to full screen (fill)\r
-               stretched_width = display_width;\r
-               stretched_height = display_height;\r
-       } else {\r
-               // dot by dot\r
-               int tmp_pow_x = display_width / source_width_aspect;\r
-               int tmp_pow_y = display_height / source_height_aspect;\r
-               int tmp_pow = 1;\r
-               if(tmp_pow_y >= tmp_pow_x && tmp_pow_x > 1) {\r
-                       tmp_pow = tmp_pow_x;\r
-               } else if(tmp_pow_x >= tmp_pow_y && tmp_pow_y > 1) {\r
-                       tmp_pow = tmp_pow_y;\r
-               }\r
-               stretched_width = source_width_aspect * tmp_pow;\r
-               stretched_height = source_height_aspect * tmp_pow;\r
-       }\r
-       screen_dest_x = (display_width - stretched_width) / 2;\r
-       screen_dest_y = (display_height - stretched_height) / 2;\r
-       \r
-       stretch_changed |= (prev_stretched_width != stretched_width);\r
-       stretch_changed |= (prev_stretched_height != stretched_height);\r
-       \r
-       int new_pow_x = 1, new_pow_y = 1;\r
-       while(stretched_width > source_width * new_pow_x) {\r
-               new_pow_x++;\r
-       }\r
-       while(stretched_height > source_height * new_pow_y) {\r
-               new_pow_y++;\r
-       }\r
-//     if(!use_d3d9 && new_pow_x > 1 && new_pow_y > 1) {\r
-//             // support high quality stretch only for x1 window size in gdi mode\r
-//             new_pow_x = new_pow_y = 1;\r
-//     }\r
-       if(stretch_pow_x != new_pow_x || stretch_pow_y != new_pow_y) {\r
-               stretch_pow_x = new_pow_x;\r
-               stretch_pow_y = new_pow_y;\r
-               stretch_changed = true;\r
-       }\r
-       if(stretch_pow_x != 1 || stretch_pow_y != 1) {\r
-               render_to_d3d9Buffer = false;\r
-       }\r
-       \r
-       if(stretch_changed) {\r
-               release_dib_section(hdcDibStretch1, hBmpStretch1, hOldBmpStretch1, lpBufStretch1);\r
-               release_dib_section(hdcDibStretch2, hBmpStretch2, hOldBmpStretch2, lpBufStretch2);\r
-               stretch_screen = false;\r
-               \r
-               if(stretch_pow_x != 1 || stretch_pow_y != 1) {\r
-                       HDC hdc = GetDC(main_window_handle);\r
-                       create_dib_section(hdc, source_width * stretch_pow_x, source_height * stretch_pow_y, &hdcDibStretch1, &hBmpStretch1, &hOldBmpStretch1, &lpBufStretch1, &lpBmpStretch1, &lpDibStretch1);\r
-                       SetStretchBltMode(hdcDibStretch1, COLORONCOLOR);\r
-                       if(!use_d3d9) {\r
-                               create_dib_section(hdc, stretched_width, stretched_height, &hdcDibStretch2, &hBmpStretch2, &hOldBmpStretch2, &lpBufStretch2, &lpBmpStretch2, &lpDibStretch2);\r
-                               SetStretchBltMode(hdcDibStretch2, HALFTONE);\r
-                       }\r
-                       ReleaseDC(main_window_handle, hdc);\r
-                       stretch_screen = true;\r
-               }\r
-               \r
-               if(use_d3d9 && display_size_changed) {\r
-                       // release and initialize d3d9\r
-                       release_d3d9();\r
-                       \r
-                       if((lpd3d9 = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) {\r
-                               MessageBox(main_window_handle, _T("Failed to initialize Direct3D9"), _T(DEVICE_NAME), MB_OK | MB_ICONWARNING);\r
-                               config.use_d3d9 = false;\r
-                               goto RETRY;\r
-                       } else {\r
-                               // initialize present params\r
-                               D3DPRESENT_PARAMETERS d3dpp;\r
-                               ZeroMemory(&d3dpp, sizeof(d3dpp));\r
-                               d3dpp.BackBufferWidth = display_width;\r
-                               d3dpp.BackBufferHeight = display_height;\r
-                               d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;//D3DFMT_UNKNOWN;\r
-                               d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;\r
-                               d3dpp.hDeviceWindow = main_window_handle;\r
-                               d3dpp.Windowed = TRUE;\r
-                               d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;\r
-                               d3dpp.PresentationInterval = config.wait_vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;\r
-                               \r
-                               // create d3d9 device\r
-                               HRESULT hr = lpd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, main_window_handle, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &lpd3d9Device);\r
-                               if(hr != D3D_OK) {\r
-                                       hr = lpd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, main_window_handle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &lpd3d9Device);\r
-                                       if(hr != D3D_OK) {\r
-                                               hr = lpd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, main_window_handle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &lpd3d9Device);\r
-                                       }\r
-                               }\r
-                               if(hr != D3D_OK) {\r
-                                       MessageBox(main_window_handle, _T("Failed to create a Direct3D9 device"), _T(DEVICE_NAME), MB_OK | MB_ICONWARNING);\r
-                                       config.use_d3d9 = false;\r
-                                       goto RETRY;\r
-                               }\r
-                       }\r
-               }\r
-               if(use_d3d9 && lpd3d9Device != NULL) {\r
-                       // release and create d3d9 surfaces\r
-                       release_d3d9_surface();\r
-                       \r
-                       HRESULT hr = lpd3d9Device->CreateOffscreenPlainSurface(source_width * stretch_pow_x, source_height * stretch_pow_y, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &lpd3d9Surface, NULL);\r
-                       if(hr == D3D_OK) {\r
-                               hr = lpd3d9Device->CreateOffscreenPlainSurface(source_width * stretch_pow_x, source_height * stretch_pow_y, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &lpd3d9OffscreenSurface, NULL);\r
-                       }\r
-                       if(hr == D3D_OK) {\r
-                               lpd3d9Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 0.0, 0);\r
-                       } else {\r
-                               MessageBox(main_window_handle, _T("Failed to create a Direct3D9 offscreen surface"), _T(DEVICE_NAME), MB_OK | MB_ICONWARNING);\r
-                               config.use_d3d9 = false;\r
-                               goto RETRY;\r
-                       }\r
-               }\r
-               if(stretch_screen) {\r
-                       render_to_d3d9Buffer = false;\r
-               }\r
-       }\r
-       \r
-       first_draw_screen = false;\r
-       first_invalidate = true;\r
-       screen_size_changed = false;\r
-       \r
-#ifdef USE_CRT_FILTER\r
-       memset(r1, 0, sizeof(r1));\r
-       memset(g1, 0, sizeof(g1));\r
-       memset(b1, 0, sizeof(b1));\r
-#endif\r
-}\r
-\r
-void EMU::change_screen_size(int sw, int sh, int swa, int sha, int ww, int wh)\r
-{\r
-       // virtual machine changes the screen size\r
-       if(screen_width != sw || screen_height != sh) {\r
-               screen_width = sw;\r
-               screen_height = sh;\r
-               screen_width_aspect = (swa != -1) ? swa : sw;\r
-               screen_height_aspect = (sha != -1) ? sha : sh;\r
-               window_width = ww;\r
-               window_height = wh;\r
-               screen_size_changed = true;\r
-               \r
-               // re-create dib sections\r
-               HDC hdc = GetDC(main_window_handle);\r
-               release_dib_section(hdcDib, hBmp, hOldBmp, lpBuf);\r
-               create_dib_section(hdc, screen_width, screen_height, &hdcDib, &hBmp, &hOldBmp, &lpBuf, &lpBmp, &lpDib);\r
-#ifdef USE_SCREEN_ROTATE\r
-               release_dib_section(hdcDibRotate, hBmpRotate, hOldBmpRotate, lpBufRotate);\r
-               create_dib_section(hdc, screen_height, screen_width, &hdcDibRotate, &hBmpRotate, &hOldBmpRotate, &lpBufRotate, &lpBmpRotate, &lpDibRotate);\r
-#endif\r
-               ReleaseDC(main_window_handle, hdc);\r
-               \r
-               // stop recording\r
-               if(now_rec_video) {\r
-                       stop_rec_video();\r
-                       stop_rec_sound();\r
-               }\r
-               \r
-               // change the window size\r
-               PostMessage(main_window_handle, WM_RESIZE, 0L, 0L);\r
-       }\r
-}\r
-\r
-int EMU::draw_screen()\r
-{\r
-       // don't draw screen before new screen size is applied to buffers\r
-       if(screen_size_changed) {\r
-               return 0;\r
-       }\r
-       \r
-       // check avi file recording timing\r
-       if(now_rec_video && rec_video_run_frames <= 0) {\r
-               return 0;\r
-       }\r
-       \r
-       // lock offscreen surface\r
-       D3DLOCKED_RECT pLockedRect;\r
-       if(use_d3d9 && lpd3d9OffscreenSurface != NULL && lpd3d9OffscreenSurface->LockRect(&pLockedRect, NULL, 0) == D3D_OK) {\r
-               lpd3d9Buffer = (scrntype *)pLockedRect.pBits;\r
-       } else {\r
-               lpd3d9Buffer = NULL;\r
-       }\r
-       \r
-       // draw screen\r
-       vm->draw_screen();\r
-       \r
-       // screen size was changed in vm->draw_screen()\r
-       if(screen_size_changed) {\r
-               // unlock offscreen surface\r
-               if(use_d3d9 && lpd3d9Buffer != NULL) {\r
-                       lpd3d9Buffer = NULL;\r
-                       lpd3d9OffscreenSurface->UnlockRect();\r
-               }\r
-               return 0;\r
-       }\r
-       \r
-#ifdef USE_SCREEN_ROTATE\r
-       // rotate screen\r
-       if(config.monitor_type) {\r
-               for(int y = 0; y < screen_height; y++) {\r
-                       scrntype* src = lpBmp + screen_width * (screen_height - y - 1);\r
-                       scrntype* out = lpBmpRotate + screen_height * (screen_width - 1) + (screen_height - y - 1);\r
-                       for(int x = 0; x < screen_width; x++) {\r
-                               *out = src[x];\r
-                               out -= screen_height;\r
-                       }\r
-               }\r
-       }\r
-#endif \r
-       \r
-       // stretch screen\r
-       if(stretch_screen) {\r
-               scrntype* src = lpBmpSource + source_width * (source_height - 1);\r
-               scrntype* out = lpBmpStretch1 + source_width * stretch_pow_x * (source_height * stretch_pow_y - 1);\r
-               int data_len = source_width * stretch_pow_x;\r
-#ifdef USE_CRT_FILTER\r
-               #define _3_8(v) (((((v) * 3) >> 3) * 180) >> 8)\r
-               #define _5_8(v) (((((v) * 3) >> 3) * 180) >> 8)\r
-               #define _8_8(v) (((v) * 180) >> 8)\r
-               \r
-               if(config.crt_filter && stretch_pow_x == 3 && stretch_pow_y == 3) {\r
-                       r1[0] = g1[0] = b1[0] = r1[source_width + 1] = g1[source_width + 1] = b1[source_width + 1] = 0;\r
-                       \r
-                       if(!screen_skip_line) {\r
-                               for(int y = 0; y < source_height; y++) {\r
-                                       for(int x = 1; x <= source_width; x++) {\r
-                                               uint32 c = src[x - 1];\r
-                                               t0[x] = (c >> 24) & 0xff;\r
-                                               r0[x] = (c >> 16) & 0xff;\r
-                                               g0[x] = (c >>  8) & 0xff;\r
-                                               b0[x] = (c      ) & 0xff;\r
-                                               r1[x] = (c >> 19) & 0x1f;\r
-                                               g1[x] = (c >> 11) & 0x1f;\r
-                                               b1[x] = (c >>  3) & 0x1f;\r
-                                       }\r
-                                       scrntype* out1 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out2 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out3 = out;\r
-                                       out -= data_len;\r
-                                       for(int x = 1, xx = 0; x <= source_width; x++, xx += 3) {\r
-                                               uint32 r = r1[x - 1] + r0[x] + r1[x + 1];\r
-                                               uint32 g = g1[x - 1] + g0[x] + g1[x + 1];\r
-                                               uint32 b = b1[x - 1] + b0[x] + b1[x + 1];\r
-                                               out1[xx    ] = out2[xx    ] = (32 + _8_8(r)) << 16;\r
-                                               out1[xx + 1] = out2[xx + 1] = (32 + _8_8(g)) << 8;\r
-                                               out1[xx + 2] = out2[xx + 2] = (32 + _8_8(b));\r
-                                               if(t0[x]) {\r
-                                                       out3[xx    ] = (32 + _8_8(r)) << 16;\r
-                                                       out3[xx + 1] = (32 + _8_8(g)) << 8;\r
-                                                       out3[xx + 2] = (32 + _8_8(b));\r
-                                               } else {\r
-                                                       out3[xx    ] = (32 + _5_8(r)) << 16;\r
-                                                       out3[xx + 1] = (32 + _5_8(g)) << 8;\r
-                                                       out3[xx + 2] = (32 + _5_8(b));\r
-                                               }\r
-                                       }\r
-                                       src -= source_width;\r
-                               }\r
-                       } else {\r
-                               for(int y = 0; y < source_height; y += 2) {\r
-                                       for(int x = 1; x <= source_width; x++) {\r
-                                               uint32 c = src[x - 1];\r
-                                               t0[x] = (c >> 24) & 0xff;\r
-                                               r0[x] = (c >> 16) & 0xff;\r
-                                               g0[x] = (c >>  8) & 0xff;\r
-                                               b0[x] = (c      ) & 0xff;\r
-                                               r1[x] = (c >> 20) & 0x0f;\r
-                                               g1[x] = (c >> 12) & 0x0f;\r
-                                               b1[x] = (c >>  4) & 0x0f;\r
-                                       }\r
-                                       scrntype* out1 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out2 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out3 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out4 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out5 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out6 = out;\r
-                                       out -= data_len;\r
-                                       for(int x = 1, xx = 0; x <= source_width; x++, xx += 3) {\r
-                                               uint32 r = r1[x - 1] + r0[x] + r1[x + 1];\r
-                                               uint32 g = g1[x - 1] + g0[x] + g1[x + 1];\r
-                                               uint32 b = b1[x - 1] + b0[x] + b1[x + 1];\r
-                                               out1[xx    ] = out2[xx    ] = out3[xx    ] = out4[xx    ] = (32 + _8_8(r)) << 16;\r
-                                               out1[xx + 1] = out2[xx + 1] = out3[xx + 1] = out4[xx + 1] = (32 + _8_8(g)) << 8;\r
-                                               out1[xx + 2] = out2[xx + 2] = out3[xx + 2] = out4[xx + 2] = (32 + _8_8(b));\r
-                                               if(t0[x]) {\r
-                                                       out5[xx    ] = out6[xx    ] = (32 + _8_8(r)) << 16;\r
-                                                       out5[xx + 1] = out6[xx + 1] = (32 + _8_8(g)) << 8;\r
-                                                       out5[xx + 2] = out6[xx + 2] = (32 + _8_8(b));\r
-                                               } else {\r
-                                                       out5[xx    ] = out6[xx    ] = (32 + _5_8(r)) << 16;\r
-                                                       out5[xx + 1] = out6[xx + 1] = (32 + _5_8(g)) << 8;\r
-                                                       out5[xx + 2] = out6[xx + 2] = (32 + _5_8(b));\r
-                                               }\r
-                                       }\r
-                                       src -= source_width * 2;\r
-                               }\r
-                       }\r
-               } else if(config.crt_filter && stretch_pow_x == 2 && stretch_pow_y == 2) {\r
-                       if(!screen_skip_line) {\r
-                               for(int y = 0; y < source_height; y++) {\r
-                                       for(int x = 1; x <= source_width; x++) {\r
-                                               uint32 c = src[x - 1];\r
-                                               t0[x] = (c >> 24) & 0xff;\r
-                                               r0[x] = (c >> 16) & 0xff;\r
-                                               g0[x] = (c >>  8) & 0xff;\r
-                                               b0[x] = (c      ) & 0xff;\r
-                                               r1[x] = (c >> 19) & 0x1f;\r
-                                               g1[x] = (c >> 11) & 0x1f;\r
-                                               b1[x] = (c >>  3) & 0x1f;\r
-                                       }\r
-                                       scrntype* out1 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out2 = out;\r
-                                       out -= data_len;\r
-                                       for(int x = 1, xx = 0; x <= source_width; x++, xx += 2) {\r
-                                               uint32 r = r1[x - 1] + r0[x] + r1[x + 1];\r
-                                               uint32 g = g1[x - 1] + g0[x] + g1[x + 1];\r
-                                               uint32 b = b1[x - 1] + b0[x] + b1[x + 1];\r
-                                               out1[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));\r
-                                               out1[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));\r
-                                               if(t0[x]) {\r
-                                                       out2[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));\r
-                                                       out2[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));\r
-                                               } else {\r
-                                                       out2[xx    ] = RGB_COLOR(32 + _3_8(r), 32 + _3_8(g), 32 + _3_8(b));\r
-                                                       out2[xx + 1] = RGB_COLOR(16 + _3_8(r), 16 + _3_8(g), 16 + _3_8(b));\r
-                                               }\r
-                                       }\r
-                                       src -= source_width;\r
-                               }\r
-                       } else {\r
-                               for(int y = 0; y < source_height; y += 2) {\r
-                                       for(int x = 1; x <= source_width; x++) {\r
-                                               uint32 c = src[x - 1];\r
-                                               t0[x] = (c >> 24) & 0xff;\r
-                                               r0[x] = (c >> 16) & 0xff;\r
-                                               g0[x] = (c >>  8) & 0xff;\r
-                                               b0[x] = (c      ) & 0xff;\r
-                                               r1[x] = (c >> 19) & 0x1f;\r
-                                               g1[x] = (c >> 11) & 0x1f;\r
-                                               b1[x] = (c >>  3) & 0x1f;\r
-                                       }\r
-                                       scrntype* out1 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out2 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out3 = out;\r
-                                       out -= data_len;\r
-                                       scrntype* out4 = out;\r
-                                       out -= data_len;\r
-                                       for(int x = 1, xx = 0; x <= source_width; x++, xx += 2) {\r
-                                               uint32 r = r1[x - 1] + r0[x] + r1[x + 1];\r
-                                               uint32 g = g1[x - 1] + g0[x] + g1[x + 1];\r
-                                               uint32 b = b1[x - 1] + b0[x] + b1[x + 1];\r
-                                               out1[xx    ] = out2[xx    ] = out3[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));\r
-                                               out1[xx + 1] = out2[xx + 1] = out3[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));\r
-                                               if(t0[x]) {\r
-                                                       out4[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));\r
-                                                       out4[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));\r
-                                               } else {\r
-                                                       out4[xx    ] = RGB_COLOR(32 + _3_8(r), 32 + _3_8(g), 32 + _3_8(b));\r
-                                                       out4[xx + 1] = RGB_COLOR(16 + _3_8(r), 16 + _3_8(g), 16 + _3_8(b));\r
-                                               }\r
-                                       }\r
-                                       src -= source_width * 2;\r
-                               }\r
-                       }\r
-               } else\r
-#endif\r
-               for(int y = 0; y < source_height; y++) {\r
-                       if(stretch_pow_x != 1) {\r
-                               scrntype* out_tmp = out;\r
-                               for(int x = 0; x < source_width; x++) {\r
-                                       scrntype c = src[x];\r
-                                       for(int px = 0; px < stretch_pow_x; px++) {\r
-                                               out_tmp[px] = c;\r
-                                       }\r
-                                       out_tmp += stretch_pow_x;\r
-                               }\r
-                       } else {\r
-                               // faster than memcpy()\r
-                               for(int x = 0; x < source_width; x++) {\r
-                                       out[x] = src[x];\r
-                               }\r
-                       }\r
-                       if(stretch_pow_y != 1) {\r
-                               scrntype* src_tmp = out;\r
-                               for(int py = 1; py < stretch_pow_y; py++) {\r
-                                       out -= data_len;\r
-                                       // about 10% faster than memcpy()\r
-                                       for(int x = 0; x < data_len; x++) {\r
-                                               out[x] = src_tmp[x];\r
-                                       }\r
-                               }\r
-                       }\r
-                       src -= source_width;\r
-                       out -= data_len;\r
-               }\r
-               if(!use_d3d9) {\r
-                       StretchBlt(hdcDibStretch2, 0, 0, stretched_width, stretched_height, hdcDibStretch1, 0, 0, source_width * stretch_pow_x, source_height * stretch_pow_y, SRCCOPY);\r
-               }\r
-       }\r
-       first_draw_screen = true;\r
-       \r
-       // copy bitmap to d3d9 offscreen surface\r
-       if(use_d3d9 && lpd3d9Buffer != NULL) {\r
-               if(!(render_to_d3d9Buffer && !now_rec_video)) {\r
-                       scrntype *src = stretch_screen ? lpBmpStretch1 : lpBmpSource;\r
-                       src += source_width * stretch_pow_x * (source_height * stretch_pow_y - 1);\r
-                       scrntype *out = lpd3d9Buffer;\r
-                       int data_len = source_width * stretch_pow_x;\r
-                       \r
-                       for(int y = 0; y < source_height * stretch_pow_y; y++) {\r
-                               for(int i = 0; i < data_len; i++) {\r
-                                       out[i] = src[i];\r
-                               }\r
-                               src -= data_len;\r
-                               out += data_len;\r
-                       }\r
-               }\r
-               // unlock offscreen surface\r
-               lpd3d9Buffer = NULL;\r
-               lpd3d9OffscreenSurface->UnlockRect();\r
-       }\r
-       \r
-       // invalidate window\r
-       InvalidateRect(main_window_handle, NULL, first_invalidate);\r
-       UpdateWindow(main_window_handle);\r
-       self_invalidate = true;\r
-       \r
-       // record avi file\r
-       if(now_rec_video) {\r
-               static double frames = 0;\r
-               static int prev_video_fps = -1;\r
-#ifdef SUPPORT_VARIABLE_TIMING\r
-               static double prev_vm_fps = -1;\r
-               double vm_fps = vm->frame_rate();\r
-               if(prev_video_fps != rec_video_fps || prev_vm_fps != vm_fps) {\r
-                       prev_video_fps = rec_video_fps;\r
-                       prev_vm_fps = vm_fps;\r
-                       frames = vm_fps / rec_video_fps;\r
-               }\r
-#else\r
-               if(prev_video_fps != rec_video_fps) {\r
-                       prev_video_fps = rec_video_fps;\r
-                       frames = FRAMES_PER_SEC / rec_video_fps;\r
-               }\r
-#endif\r
-               int counter = 0;\r
-               if(use_video_thread) {\r
-                       while(rec_video_run_frames > 0) {\r
-                               rec_video_run_frames -= frames;\r
-                               rec_video_frames += frames;\r
-                               counter++;\r
-                       }\r
-                       if(counter != 0) {\r
-                               if(hVideoThread != (HANDLE)0) {\r
-                                       if(video_thread_param.result == 0) {\r
-                                               WaitForSingleObject(hVideoThread, INFINITE);\r
-                                       }\r
-                                       hVideoThread = (HANDLE)0;\r
-                                       \r
-                                       if(video_thread_param.result == RESULT_FULL) {\r
-                                               stop_rec_video();\r
-                                               if(!start_rec_video(-1)) {\r
-                                                       return 0;\r
-                                               }\r
-                                       } else if(video_thread_param.result == RESULT_ERROR) {\r
-                                               stop_rec_video();\r
-                                               return 0;\r
-                                       }\r
-                               }\r
-                               BitBlt(hdcDibRec, 0, 0, source_width, source_height, hdcDibSource, 0, 0, SRCCOPY);\r
-                               video_thread_param.frames += counter;\r
-                               video_thread_param.result = 0;\r
-                               if((hVideoThread = (HANDLE)_beginthreadex(NULL, 0, rec_video_thread, &video_thread_param, 0, NULL)) == (HANDLE)0) {\r
-                                       stop_rec_video();\r
-                                       return 0;\r
-                               }\r
-                       }\r
-               } else {\r
-                       while(rec_video_run_frames > 0) {\r
-                               LONG lBytesWritten;\r
-                               if(AVIStreamWrite(pAVICompressed, lAVIFrames++, 1, (LPBYTE)lpBmpSource, pbmInfoHeader->biSizeImage, AVIIF_KEYFRAME, NULL, &lBytesWritten) == AVIERR_OK) {\r
-                                       // if avi file size > (2GB - 16MB), create new avi file\r
-                                       if((dwAVIFileSize += lBytesWritten) >= 2130706432) {\r
-                                               stop_rec_video();\r
-                                               if(!start_rec_video(-1)) {\r
-                                                       break;\r
-                                               }\r
-                                       }\r
-                                       rec_video_run_frames -= frames;\r
-                                       rec_video_frames += frames;\r
-                                       counter++;\r
-                               } else {\r
-                                       stop_rec_video();\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-               return counter;\r
-       } else {\r
-               return 1;\r
-       }\r
-}\r
-\r
-scrntype* EMU::screen_buffer(int y)\r
-{\r
-       if(use_d3d9 && lpd3d9Buffer != NULL && render_to_d3d9Buffer && !now_rec_video) {\r
-               return lpd3d9Buffer + screen_width * y;\r
-       }\r
-       return lpBmp + screen_width * (screen_height - y - 1);\r
-}\r
-\r
-void EMU::update_screen(HDC hdc)\r
-{\r
-#ifdef USE_BITMAP\r
-       if(first_invalidate || !self_invalidate) {\r
-               HDC hmdc = CreateCompatibleDC(hdc);\r
-               HBITMAP hBitmap = LoadBitmap(instance_handle, _T("IDI_BITMAP1"));\r
-               BITMAP bmp;\r
-               GetObject(hBitmap, sizeof(BITMAP), &bmp);\r
-               int w = (int)bmp.bmWidth;\r
-               int h = (int)bmp.bmHeight;\r
-               HBITMAP hOldBitmap = (HBITMAP)SelectObject(hmdc, hBitmap);\r
-               BitBlt(hdc, 0, 0, w, h, hmdc, 0, 0, SRCCOPY);\r
-               SelectObject(hmdc, hOldBitmap);\r
-               DeleteObject(hBitmap);\r
-               DeleteDC(hmdc);\r
-       }\r
-#endif\r
-       if(first_draw_screen) {\r
-#ifdef USE_LED\r
-               // 7-seg LEDs\r
-               for(int i = 0; i < MAX_LEDS; i++) {\r
-                       int x = leds[i].x;\r
-                       int y = leds[i].y;\r
-                       int w = leds[i].width;\r
-                       int h = leds[i].height;\r
-                       BitBlt(hdc, x, y, w, h, hdcDib, x, y, SRCCOPY);\r
-               }\r
-#else\r
-#ifdef USE_ACCESS_LAMP\r
-               // get access lamps status of drives\r
-               int status = vm->access_lamp() & 7;\r
-               static int prev_status = 0;\r
-               bool render_in = (status != 0);\r
-               bool render_out = (prev_status != status);\r
-               prev_status = status;\r
-               \r
-               COLORREF crColor = RGB((status & 1) ? 255 : 0, (status & 2) ? 255 : 0, (status & 4) ? 255 : 0);\r
-               int right_bottom_x = screen_dest_x + stretched_width;\r
-               int right_bottom_y = screen_dest_y + stretched_height;\r
-#endif\r
-               // standard screen\r
-               if(use_d3d9) {\r
-                       LPDIRECT3DSURFACE9 lpd3d9BackSurface = NULL;\r
-                       if(lpd3d9Device != NULL && lpd3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &lpd3d9BackSurface) == D3D_OK && lpd3d9BackSurface != NULL) {\r
-                               RECT rectSrc = { 0, 0, source_width * stretch_pow_x, source_height * stretch_pow_y };\r
-                               RECT rectDst = { screen_dest_x, screen_dest_y, screen_dest_x + stretched_width, screen_dest_y + stretched_height };\r
-                               \r
-                               lpd3d9Device->UpdateSurface(lpd3d9OffscreenSurface, NULL, lpd3d9Surface, NULL);\r
-                               lpd3d9Device->StretchRect(lpd3d9Surface, &rectSrc, lpd3d9BackSurface, &rectDst, stretch_screen ? D3DTEXF_LINEAR : D3DTEXF_POINT);\r
-#ifdef USE_ACCESS_LAMP\r
-                               // draw access lamps\r
-                               if(render_in || render_out) {\r
-                                       HDC hDC = 0;\r
-                                       for(int y = display_height - 6; y < display_height; y++) {\r
-                                               for(int x = display_width - 6; x < display_width; x++) {\r
-                                                       if((x < right_bottom_x && y < right_bottom_y) ? render_in : render_out) {\r
-                                                               if(hDC == 0 && lpd3d9BackSurface->GetDC(&hDC) != D3D_OK) {\r
-                                                                       goto quit;\r
-                                                               }\r
-                                                               SetPixelV(hDC, x, y, crColor);\r
-                                                       }\r
-                                               }\r
-                                       }\r
-quit:\r
-                                       if(hDC != 0) {\r
-                                               lpd3d9BackSurface->ReleaseDC(hDC);\r
-                                       }\r
-                               }\r
-#endif\r
-                               lpd3d9BackSurface->Release();\r
-                               lpd3d9Device->Present(NULL, NULL, NULL, NULL);\r
-                       }\r
-               } else {\r
-                       if(stretch_screen) {\r
-                               BitBlt(hdc, screen_dest_x, screen_dest_y, stretched_width, stretched_height, hdcDibStretch2, 0, 0, SRCCOPY);\r
-                       } else if(stretched_width == source_width && stretched_height == source_height) {\r
-                               BitBlt(hdc, screen_dest_x, screen_dest_y, stretched_width, stretched_height, hdcDibSource, 0, 0, SRCCOPY);\r
-                       } else {\r
-                               StretchBlt(hdc, screen_dest_x, screen_dest_y, stretched_width, stretched_height, hdcDibSource, 0, 0, source_width, source_height, SRCCOPY);\r
-                       }\r
-#ifdef USE_ACCESS_LAMP\r
-                       // draw access lamps\r
-                       if(render_in || render_out) {\r
-                               for(int y = display_height - 6; y < display_height; y++) {\r
-                                       for(int x = display_width - 6; x < display_width; x++) {\r
-                                               if((x < right_bottom_x && y < right_bottom_y) ? render_in : render_out) {\r
-                                                       SetPixelV(hdc, x, y, crColor);\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-#endif\r
-               }\r
-#endif\r
-               first_invalidate = self_invalidate = false;\r
-       }\r
-}\r
-\r
-void EMU::capture_screen()\r
-{\r
-       if(use_d3d9 && render_to_d3d9Buffer && !now_rec_video) {\r
-               // virtual machine may render screen to d3d9 buffer directly...\r
-               vm->draw_screen();\r
-       }\r
-       \r
-       // create file name\r
-       SYSTEMTIME sTime;\r
-       GetLocalTime(&sTime);\r
-       \r
-       _TCHAR file_name[_MAX_PATH];\r
-       _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);\r
-       \r
-       // create bitmap\r
-       BITMAPFILEHEADER bmFileHeader = { (WORD)(TEXT('B') | TEXT('M') << 8) };\r
-       bmFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);\r
-       bmFileHeader.bfSize = bmFileHeader.bfOffBits + pbmInfoHeader->biSizeImage;\r
-       \r
-       DWORD dwSize;\r
-       HANDLE hFile = CreateFile(bios_path(file_name), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\r
-       WriteFile(hFile, &bmFileHeader, sizeof(BITMAPFILEHEADER), &dwSize, NULL);\r
-       WriteFile(hFile, lpDibSource, sizeof(BITMAPINFOHEADER), &dwSize, NULL);\r
-       WriteFile(hFile, lpBmpSource, pbmInfoHeader->biSizeImage, &dwSize, NULL);\r
-       CloseHandle(hFile);\r
-}\r
-\r
-bool EMU::start_rec_video(int fps)\r
-{\r
-       if(fps > 0) {\r
-               rec_video_fps = fps;\r
-               rec_video_run_frames = rec_video_frames = 0;\r
-       } else {\r
-               fps = rec_video_fps;\r
-       }\r
-       bool show_dialog = (fps > 0);\r
-       \r
-       // create file name\r
-       SYSTEMTIME sTime;\r
-       GetLocalTime(&sTime);\r
-       \r
-       _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);\r
-       \r
-       // initialize vfw\r
-       AVIFileInit();\r
-       if(AVIFileOpen(&pAVIFile, bios_path(video_file_name), OF_WRITE | OF_CREATE, NULL) != AVIERR_OK) {\r
-               return false;\r
-       }\r
-       use_video_thread = false;\r
-       \r
-       // stream header\r
-       AVISTREAMINFO strhdr;\r
-       memset(&strhdr, 0, sizeof(strhdr));\r
-       strhdr.fccType = streamtypeVIDEO;       // vids\r
-       strhdr.fccHandler = 0;\r
-       strhdr.dwScale = 1;\r
-       strhdr.dwRate = fps;\r
-       strhdr.dwSuggestedBufferSize = pbmInfoHeader->biSizeImage;\r
-       SetRect(&strhdr.rcFrame, 0, 0, source_width, source_height);\r
-       if(AVIFileCreateStream(pAVIFile, &pAVIStream, &strhdr) != AVIERR_OK) {\r
-               stop_rec_video();\r
-               return false;\r
-       }\r
-       \r
-       // compression\r
-       AVICOMPRESSOPTIONS FAR * pOpts[1];\r
-       pOpts[0] = &opts;\r
-       if(show_dialog && !AVISaveOptions(main_window_handle, ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE, 1, &pAVIStream, (LPAVICOMPRESSOPTIONS FAR *)&pOpts)) {\r
-               AVISaveOptionsFree(1, (LPAVICOMPRESSOPTIONS FAR *)&pOpts);\r
-               stop_rec_video();\r
-               return false;\r
-       }\r
-       if(AVIMakeCompressedStream(&pAVICompressed, pAVIStream, &opts, NULL) != AVIERR_OK) {\r
-               stop_rec_video();\r
-               return false;\r
-       }\r
-       if(AVIStreamSetFormat(pAVICompressed, 0, &lpDibSource->bmiHeader, lpDibSource->bmiHeader.biSize + lpDibSource->bmiHeader.biClrUsed * sizeof(RGBQUAD)) != AVIERR_OK) {\r
-               stop_rec_video();\r
-               return false;\r
-       }\r
-       dwAVIFileSize = 0;\r
-       lAVIFrames = 0;\r
-       \r
-       SYSTEM_INFO info;\r
-       GetSystemInfo(&info);\r
-       \r
-       if(info.dwNumberOfProcessors > 1) {\r
-               use_video_thread = true;\r
-               hVideoThread = (HANDLE)0;\r
-               video_thread_param.pAVICompressed = pAVICompressed;\r
-               video_thread_param.lpBmpSource = lpBmpSource;\r
-               video_thread_param.pbmInfoHeader = pbmInfoHeader;\r
-               video_thread_param.dwAVIFileSize = 0;\r
-               video_thread_param.lAVIFrames = 0;\r
-               video_thread_param.frames = 0;\r
-               video_thread_param.result = 0;\r
-               \r
-               HDC hdc = GetDC(main_window_handle);\r
-               create_dib_section(hdc, source_width, source_height, &hdcDibRec, &hBmpRec, &hOldBmpRec, &lpBufRec, &lpBmpRec, &lpDibRec);\r
-               ReleaseDC(main_window_handle, hdc);\r
-       }\r
-       now_rec_video = true;\r
-       return true;\r
-}\r
-\r
-void EMU::stop_rec_video()\r
-{\r
-       // release thread\r
-       if(use_video_thread) {\r
-               if(hVideoThread != (HANDLE)0) {\r
-                       WaitForSingleObject(hVideoThread, INFINITE);\r
-                       hVideoThread = (HANDLE)0;\r
-               }\r
-               if(hdcDibRec) {\r
-                       release_dib_section(hdcDibRec, hBmpRec, hOldBmpRec, lpBufRec);\r
-               }\r
-       }\r
-       \r
-       // release vfw\r
-       if(pAVIStream) {\r
-               AVIStreamClose(pAVIStream);\r
-       }\r
-       if(pAVICompressed) {\r
-               AVIStreamClose(pAVICompressed);\r
-       }\r
-       if(pAVIFile) {\r
-               AVIFileClose(pAVIFile);\r
-               AVIFileExit();\r
-       }\r
-       pAVIStream = NULL;\r
-       pAVICompressed = NULL;\r
-       pAVIFile = NULL;\r
-       \r
-       // repair header\r
-       if(now_rec_video) {\r
-               FILE* fp = NULL;\r
-               if(_tfopen_s(&fp, bios_path(video_file_name), _T("r+b")) == 0) {\r
-                       // copy fccHandler\r
-                       uint8 buf[4];\r
-                       fseek(fp, 0xbc, SEEK_SET);\r
-                       if(ftell(fp) == 0xbc) {\r
-                               fread(buf, 4, 1, fp);\r
-                               fseek(fp, 0x70, SEEK_SET);\r
-                               fwrite(buf, 4, 1, fp);\r
-                       }\r
-                       fclose(fp);\r
-               }\r
-       }\r
-       now_rec_video = false;\r
-}\r
-\r
-void EMU::restart_rec_video()\r
-{\r
-       bool tmp = now_rec_video;\r
-       stop_rec_video();\r
-       if(tmp) start_rec_video(-1);\r
-}\r
-\r
-unsigned __stdcall rec_video_thread(void *lpx)\r
-{\r
-       volatile video_thread_t *p = (video_thread_t *)lpx;\r
-       LONG lBytesWritten;\r
-       int result = RESULT_SUCCESS;\r
-       \r
-       while(p->frames > 0) {\r
-               if(AVIStreamWrite(p->pAVICompressed, p->lAVIFrames++, 1, (LPBYTE)p->lpBmpSource, p->pbmInfoHeader->biSizeImage, AVIIF_KEYFRAME, NULL, &lBytesWritten) == AVIERR_OK) {\r
-                       p->frames--;\r
-                       // if avi file size > (2GB - 16MB), create new avi file\r
-                       if((p->dwAVIFileSize += lBytesWritten) >= 2130706432) {\r
-                               result = RESULT_FULL;\r
-                               break;\r
-                       }\r
-               } else {\r
-                       result = RESULT_ERROR;\r
-                       break;\r
-               }\r
-       }\r
-       p->result = result;\r
-       _endthreadex(0);\r
-       return 0;\r
-}\r
-\r
+/*
+       Skelton for retropc emulator
+
+       Author : Takeda.Toshiya
+       Date   : 2006.08.18 -
+
+       [ win32 screen ]
+*/
+
+#include "emu.h"
+#include "vm/vm.h"
+
+#define RESULT_SUCCESS 1
+#define RESULT_FULL    2
+#define RESULT_ERROR   3
+
+unsigned __stdcall rec_video_thread(void *lpx);
+
+#ifdef USE_CRT_FILTER
+static uint8 r0[2048], g0[2048], b0[2048], t0[2048];
+static uint8 r1[2048], g1[2048], b1[2048];
+#endif
+
+void EMU::initialize_screen()
+{
+       screen_width = SCREEN_WIDTH;
+       screen_height = SCREEN_HEIGHT;
+       screen_width_aspect = SCREEN_WIDTH_ASPECT;
+       screen_height_aspect = SCREEN_HEIGHT_ASPECT;
+       window_width = WINDOW_WIDTH;
+       window_height = WINDOW_HEIGHT;
+       screen_size_changed = true;
+       
+       source_width = source_height = -1;
+       source_width_aspect = source_height_aspect = -1;
+       stretch_pow_x = stretch_pow_y = -1;
+       stretch_screen = false;
+       
+       // create dib sections
+       HDC hdc = GetDC(main_window_handle);
+       create_dib_section(hdc, screen_width, screen_height, &hdcDib, &hBmp, &hOldBmp, &lpBuf, &lpBmp, &lpDib);
+#ifdef USE_SCREEN_ROTATE
+       create_dib_section(hdc, screen_height, screen_width, &hdcDibRotate, &hBmpRotate, &hOldBmpRotate, &lpBufRotate, &lpBmpRotate, &lpDibRotate);
+#endif
+       ReleaseDC(main_window_handle, hdc);
+       
+       hdcDibStretch1 = hdcDibStretch2 = NULL;
+       hBmpStretch1 = hOldBmpStretch1 = hBmpStretch2 = hOldBmpStretch2 = NULL;
+       lpBufStretch1 = lpBufStretch2 = NULL;
+       
+       // initialize d3d9
+       lpd3d9 = NULL;
+       lpd3d9Device = NULL;
+       lpd3d9Surface = NULL;
+       lpd3d9OffscreenSurface = NULL;
+       lpd3d9Buffer = NULL;
+       render_to_d3d9Buffer = false;
+       use_d3d9 = config.use_d3d9;
+       wait_vsync = config.wait_vsync;
+       
+       // initialize video recording
+       now_rec_video = false;
+       hdcDibRec = NULL;
+       pAVIStream = NULL;
+       pAVICompressed = NULL;
+       pAVIFile = NULL;
+       
+       // initialize update flags
+       first_draw_screen = false;
+       first_invalidate = self_invalidate = false;
+       
+#ifdef USE_CRT_FILTER
+       // initialize crtc filter
+       memset(r1, 0, sizeof(r1));
+       memset(g1, 0, sizeof(g1));
+       memset(b1, 0, sizeof(b1));
+#endif
+}
+
+#define release_dib_section(hdcdib, hbmp, holdbmp, lpbuf) { \
+       if(hdcdib != NULL && holdbmp != NULL) { \
+               SelectObject(hdcdib, holdbmp); \
+       } \
+       if(hbmp != NULL) { \
+               DeleteObject(hbmp); \
+               hbmp = NULL; \
+       } \
+       if(lpbuf != NULL) { \
+               GlobalFree(lpbuf); \
+               lpbuf = NULL; \
+       } \
+       if(hdcdib != NULL) { \
+               DeleteDC(hdcdib); \
+               hdcdib = NULL; \
+       } \
+}
+
+#define release_d3d9() { \
+       if(lpd3d9OffscreenSurface != NULL) { \
+               lpd3d9OffscreenSurface->Release(); \
+               lpd3d9OffscreenSurface = NULL; \
+       } \
+       if(lpd3d9Surface != NULL) { \
+               lpd3d9Surface->Release(); \
+               lpd3d9Surface = NULL; \
+       } \
+       if(lpd3d9Device != NULL) { \
+               lpd3d9Device->Release(); \
+               lpd3d9Device = NULL; \
+       } \
+       if(lpd3d9 != NULL) { \
+               lpd3d9->Release(); \
+               lpd3d9 = NULL; \
+       } \
+}
+
+#define release_d3d9_surface() { \
+       if(lpd3d9OffscreenSurface != NULL) { \
+               lpd3d9OffscreenSurface->Release(); \
+               lpd3d9OffscreenSurface = NULL; \
+       } \
+       if(lpd3d9Surface != NULL) { \
+               lpd3d9Surface->Release(); \
+               lpd3d9Surface = NULL; \
+       } \
+}
+
+void EMU::release_screen()
+{
+       // stop video recording
+       stop_rec_video();
+       
+       // release dib sections
+       release_dib_section(hdcDib, hBmp, hOldBmp, lpBuf);
+#ifdef USE_SCREEN_ROTATE
+       release_dib_section(hdcDibRotate, hBmpRotate, hOldBmpRotate, lpBufRotate);
+#endif
+       release_dib_section(hdcDibStretch1, hBmpStretch1, hOldBmpStretch1, lpBufStretch1);
+       release_dib_section(hdcDibStretch2, hBmpStretch2, hOldBmpStretch2, lpBufStretch2);
+       
+       // release d3d9
+       release_d3d9();
+}
+
+void EMU::create_dib_section(HDC hdc, int width, int height, HDC *hdcDib, HBITMAP *hBmp, HBITMAP *hOldBmp, LPBYTE *lpBuf, scrntype **lpBmp, LPBITMAPINFO *lpDib)
+{
+       *hdcDib = CreateCompatibleDC(hdc);
+       *lpBuf = (LPBYTE)GlobalAlloc(GPTR, sizeof(BITMAPINFO));
+       *lpDib = (LPBITMAPINFO)(*lpBuf);
+       memset(&(*lpDib)->bmiHeader, 0, sizeof(BITMAPINFOHEADER));
+       (*lpDib)->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+       (*lpDib)->bmiHeader.biWidth = width;
+       (*lpDib)->bmiHeader.biHeight = height;
+       (*lpDib)->bmiHeader.biPlanes = 1;
+#if defined(_RGB555)
+       (*lpDib)->bmiHeader.biBitCount = 16;
+       (*lpDib)->bmiHeader.biCompression = BI_RGB;
+       (*lpDib)->bmiHeader.biSizeImage = width * height * 2;
+#elif defined(_RGB565)
+       (*lpDib)->bmiHeader.biBitCount = 16;
+       (*lpDib)->bmiHeader.biCompression = BI_BITFIELDS;
+       LPDWORD lpBf = (LPDWORD)*lpDib->bmiColors;
+       lpBf[0] = 0x1f << 11;
+       lpBf[1] = 0x3f << 5;
+       lpBf[2] = 0x1f << 0;
+       (*lpDib)->bmiHeader.biSizeImage = width * height * 2;
+#elif defined(_RGB888)
+       (*lpDib)->bmiHeader.biBitCount = 32;
+       (*lpDib)->bmiHeader.biCompression = BI_RGB;
+       (*lpDib)->bmiHeader.biSizeImage = width * height * 4;
+#endif
+       (*lpDib)->bmiHeader.biXPelsPerMeter = 0;
+       (*lpDib)->bmiHeader.biYPelsPerMeter = 0;
+       (*lpDib)->bmiHeader.biClrUsed = 0;
+       (*lpDib)->bmiHeader.biClrImportant = 0;
+       *hBmp = CreateDIBSection(hdc, *lpDib, DIB_RGB_COLORS, (PVOID*)&(*lpBmp), NULL, 0);
+       *hOldBmp = (HBITMAP)SelectObject(*hdcDib, *hBmp);
+}
+
+int EMU::get_window_width(int mode)
+{
+#ifdef USE_SCREEN_ROTATE
+       if(config.monitor_type) {
+               return window_height + screen_height_aspect * mode;
+       }
+#endif
+       return window_width + screen_width_aspect * mode;
+}
+
+int EMU::get_window_height(int mode)
+{
+#ifdef USE_SCREEN_ROTATE
+       if(config.monitor_type) {
+               return window_width + screen_width_aspect * mode;
+       }
+#endif
+       return window_height + screen_height_aspect * mode;
+}
+
+void EMU::set_display_size(int width, int height, bool window_mode)
+{
+RETRY:
+       bool display_size_changed = false;
+       bool stretch_changed = false;
+       int prev_stretched_width = stretched_width;
+       int prev_stretched_height = stretched_height;
+       
+       if(width != -1 && (display_width != width || display_height != height)) {
+               display_width = width;
+               display_height = height;
+               display_size_changed = stretch_changed = true;
+       }
+       if(use_d3d9 != config.use_d3d9) {
+               if(!(use_d3d9 = config.use_d3d9)) {
+                       release_d3d9();
+               }
+               display_size_changed = stretch_changed = true;
+       }
+       if(wait_vsync != config.wait_vsync) {
+               wait_vsync = config.wait_vsync;
+               display_size_changed = stretch_changed = true;
+       }
+       
+       // virtual machine renders to d3d9 buffer directly???
+       render_to_d3d9Buffer = use_d3d9;
+       
+#ifdef USE_SCREEN_ROTATE
+       if(config.monitor_type) {
+               hdcDibSource = hdcDibRotate;
+               lpBmpSource = lpBmpRotate;
+               lpDibSource = lpDibRotate;
+               pbmInfoHeader = &lpDibRotate->bmiHeader;
+               
+               stretch_changed |= (source_width != screen_height);
+               stretch_changed |= (source_height != screen_width);
+               stretch_changed |= (source_width_aspect != screen_height_aspect);
+               stretch_changed |= (source_height_aspect != screen_width_aspect);
+               
+               source_width = screen_height;
+               source_height = screen_width;
+               source_width_aspect = screen_height_aspect;
+               source_height_aspect = screen_width_aspect;
+               
+               render_to_d3d9Buffer = false;
+       } else {
+#endif
+               hdcDibSource = hdcDib;
+               lpBmpSource = lpBmp;
+               lpDibSource = lpDib;
+               pbmInfoHeader = &lpDib->bmiHeader;
+               
+               stretch_changed |= (source_width != screen_width);
+               stretch_changed |= (source_height != screen_height);
+               stretch_changed |= (source_width_aspect != screen_width_aspect);
+               stretch_changed |= (source_height_aspect != screen_height_aspect);
+               
+               source_width = screen_width;
+               source_height = screen_height;
+               source_width_aspect = screen_width_aspect;
+               source_height_aspect = screen_height_aspect;
+#ifdef USE_SCREEN_ROTATE
+       }
+#endif
+       
+       if(config.stretch_type == 1 && !window_mode) {
+               // fit to full screen (aspect)
+               stretched_width = (display_height * source_width_aspect) / source_height_aspect;
+               stretched_height = display_height;
+               if(stretched_width > display_width) {
+                       stretched_width = display_width;
+                       stretched_height = (display_width * source_height_aspect) / source_width_aspect;
+               }
+       } else if(config.stretch_type == 2 && !window_mode) {
+               // fit to full screen (fill)
+               stretched_width = display_width;
+               stretched_height = display_height;
+       } else {
+               // dot by dot
+               int tmp_pow_x = display_width / source_width_aspect;
+               int tmp_pow_y = display_height / source_height_aspect;
+               int tmp_pow = 1;
+               if(tmp_pow_y >= tmp_pow_x && tmp_pow_x > 1) {
+                       tmp_pow = tmp_pow_x;
+               } else if(tmp_pow_x >= tmp_pow_y && tmp_pow_y > 1) {
+                       tmp_pow = tmp_pow_y;
+               }
+               stretched_width = source_width_aspect * tmp_pow;
+               stretched_height = source_height_aspect * tmp_pow;
+       }
+       screen_dest_x = (display_width - stretched_width) / 2;
+       screen_dest_y = (display_height - stretched_height) / 2;
+       
+       stretch_changed |= (prev_stretched_width != stretched_width);
+       stretch_changed |= (prev_stretched_height != stretched_height);
+       
+       int new_pow_x = 1, new_pow_y = 1;
+       while(stretched_width > source_width * new_pow_x) {
+               new_pow_x++;
+       }
+       while(stretched_height > source_height * new_pow_y) {
+               new_pow_y++;
+       }
+//     if(!use_d3d9 && new_pow_x > 1 && new_pow_y > 1) {
+//             // support high quality stretch only for x1 window size in gdi mode
+//             new_pow_x = new_pow_y = 1;
+//     }
+       if(stretch_pow_x != new_pow_x || stretch_pow_y != new_pow_y) {
+               stretch_pow_x = new_pow_x;
+               stretch_pow_y = new_pow_y;
+               stretch_changed = true;
+       }
+       if(stretch_pow_x != 1 || stretch_pow_y != 1) {
+               render_to_d3d9Buffer = false;
+       }
+       
+       if(stretch_changed) {
+               release_dib_section(hdcDibStretch1, hBmpStretch1, hOldBmpStretch1, lpBufStretch1);
+               release_dib_section(hdcDibStretch2, hBmpStretch2, hOldBmpStretch2, lpBufStretch2);
+               stretch_screen = false;
+               
+               if(stretch_pow_x != 1 || stretch_pow_y != 1) {
+                       HDC hdc = GetDC(main_window_handle);
+                       create_dib_section(hdc, source_width * stretch_pow_x, source_height * stretch_pow_y, &hdcDibStretch1, &hBmpStretch1, &hOldBmpStretch1, &lpBufStretch1, &lpBmpStretch1, &lpDibStretch1);
+                       SetStretchBltMode(hdcDibStretch1, COLORONCOLOR);
+                       if(!use_d3d9) {
+                               create_dib_section(hdc, stretched_width, stretched_height, &hdcDibStretch2, &hBmpStretch2, &hOldBmpStretch2, &lpBufStretch2, &lpBmpStretch2, &lpDibStretch2);
+                               SetStretchBltMode(hdcDibStretch2, HALFTONE);
+                       }
+                       ReleaseDC(main_window_handle, hdc);
+                       stretch_screen = true;
+               }
+               
+               if(use_d3d9 && display_size_changed) {
+                       // release and initialize d3d9
+                       release_d3d9();
+                       
+                       if((lpd3d9 = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) {
+                               MessageBox(main_window_handle, _T("Failed to initialize Direct3D9"), _T(DEVICE_NAME), MB_OK | MB_ICONWARNING);
+                               config.use_d3d9 = false;
+                               goto RETRY;
+                       } else {
+                               // initialize present params
+                               D3DPRESENT_PARAMETERS d3dpp;
+                               ZeroMemory(&d3dpp, sizeof(d3dpp));
+                               d3dpp.BackBufferWidth = display_width;
+                               d3dpp.BackBufferHeight = display_height;
+                               d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;//D3DFMT_UNKNOWN;
+                               d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+                               d3dpp.hDeviceWindow = main_window_handle;
+                               d3dpp.Windowed = TRUE;
+                               d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
+                               d3dpp.PresentationInterval = config.wait_vsync ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
+                               
+                               // create d3d9 device
+                               HRESULT hr = lpd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, main_window_handle, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &lpd3d9Device);
+                               if(hr != D3D_OK) {
+                                       hr = lpd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, main_window_handle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &lpd3d9Device);
+                                       if(hr != D3D_OK) {
+                                               hr = lpd3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, main_window_handle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &lpd3d9Device);
+                                       }
+                               }
+                               if(hr != D3D_OK) {
+                                       MessageBox(main_window_handle, _T("Failed to create a Direct3D9 device"), _T(DEVICE_NAME), MB_OK | MB_ICONWARNING);
+                                       config.use_d3d9 = false;
+                                       goto RETRY;
+                               }
+                       }
+               }
+               if(use_d3d9 && lpd3d9Device != NULL) {
+                       // release and create d3d9 surfaces
+                       release_d3d9_surface();
+                       
+                       HRESULT hr = lpd3d9Device->CreateOffscreenPlainSurface(source_width * stretch_pow_x, source_height * stretch_pow_y, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &lpd3d9Surface, NULL);
+                       if(hr == D3D_OK) {
+                               hr = lpd3d9Device->CreateOffscreenPlainSurface(source_width * stretch_pow_x, source_height * stretch_pow_y, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &lpd3d9OffscreenSurface, NULL);
+                       }
+                       if(hr == D3D_OK) {
+                               lpd3d9Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 0.0, 0);
+                       } else {
+                               MessageBox(main_window_handle, _T("Failed to create a Direct3D9 offscreen surface"), _T(DEVICE_NAME), MB_OK | MB_ICONWARNING);
+                               config.use_d3d9 = false;
+                               goto RETRY;
+                       }
+               }
+               if(stretch_screen) {
+                       render_to_d3d9Buffer = false;
+               }
+       }
+       
+       first_draw_screen = false;
+       first_invalidate = true;
+       screen_size_changed = false;
+       
+#ifdef USE_CRT_FILTER
+       memset(r1, 0, sizeof(r1));
+       memset(g1, 0, sizeof(g1));
+       memset(b1, 0, sizeof(b1));
+#endif
+}
+
+void EMU::change_screen_size(int sw, int sh, int swa, int sha, int ww, int wh)
+{
+       // virtual machine changes the screen size
+       if(screen_width != sw || screen_height != sh) {
+               screen_width = sw;
+               screen_height = sh;
+               screen_width_aspect = (swa != -1) ? swa : sw;
+               screen_height_aspect = (sha != -1) ? sha : sh;
+               window_width = ww;
+               window_height = wh;
+               screen_size_changed = true;
+               
+               // re-create dib sections
+               HDC hdc = GetDC(main_window_handle);
+               release_dib_section(hdcDib, hBmp, hOldBmp, lpBuf);
+               create_dib_section(hdc, screen_width, screen_height, &hdcDib, &hBmp, &hOldBmp, &lpBuf, &lpBmp, &lpDib);
+#ifdef USE_SCREEN_ROTATE
+               release_dib_section(hdcDibRotate, hBmpRotate, hOldBmpRotate, lpBufRotate);
+               create_dib_section(hdc, screen_height, screen_width, &hdcDibRotate, &hBmpRotate, &hOldBmpRotate, &lpBufRotate, &lpBmpRotate, &lpDibRotate);
+#endif
+               ReleaseDC(main_window_handle, hdc);
+               
+               // stop recording
+               if(now_rec_video) {
+                       stop_rec_video();
+                       stop_rec_sound();
+               }
+               
+               // change the window size
+               PostMessage(main_window_handle, WM_RESIZE, 0L, 0L);
+       }
+}
+
+int EMU::draw_screen()
+{
+       // don't draw screen before new screen size is applied to buffers
+       if(screen_size_changed) {
+               return 0;
+       }
+       
+       // check avi file recording timing
+       if(now_rec_video && rec_video_run_frames <= 0) {
+               return 0;
+       }
+       
+       // lock offscreen surface
+       D3DLOCKED_RECT pLockedRect;
+       if(use_d3d9 && lpd3d9OffscreenSurface != NULL && lpd3d9OffscreenSurface->LockRect(&pLockedRect, NULL, 0) == D3D_OK) {
+               lpd3d9Buffer = (scrntype *)pLockedRect.pBits;
+       } else {
+               lpd3d9Buffer = NULL;
+       }
+       
+       // draw screen
+       vm->draw_screen();
+       
+       // screen size was changed in vm->draw_screen()
+       if(screen_size_changed) {
+               // unlock offscreen surface
+               if(use_d3d9 && lpd3d9Buffer != NULL) {
+                       lpd3d9Buffer = NULL;
+                       lpd3d9OffscreenSurface->UnlockRect();
+               }
+               return 0;
+       }
+       
+#ifdef USE_SCREEN_ROTATE
+       // rotate screen
+       if(config.monitor_type) {
+               for(int y = 0; y < screen_height; y++) {
+                       scrntype* src = lpBmp + screen_width * (screen_height - y - 1);
+                       scrntype* out = lpBmpRotate + screen_height * (screen_width - 1) + (screen_height - y - 1);
+                       for(int x = 0; x < screen_width; x++) {
+                               *out = src[x];
+                               out -= screen_height;
+                       }
+               }
+       }
+#endif 
+       
+       // stretch screen
+       if(stretch_screen) {
+               scrntype* src = lpBmpSource + source_width * (source_height - 1);
+               scrntype* out = lpBmpStretch1 + source_width * stretch_pow_x * (source_height * stretch_pow_y - 1);
+               int data_len = source_width * stretch_pow_x;
+#ifdef USE_CRT_FILTER
+               #define _3_8(v) (((((v) * 3) >> 3) * 180) >> 8)
+               #define _5_8(v) (((((v) * 3) >> 3) * 180) >> 8)
+               #define _8_8(v) (((v) * 180) >> 8)
+               
+               if(config.crt_filter && stretch_pow_x == 3 && stretch_pow_y == 3) {
+                       r1[0] = g1[0] = b1[0] = r1[source_width + 1] = g1[source_width + 1] = b1[source_width + 1] = 0;
+                       
+                       if(!screen_skip_line) {
+                               for(int y = 0; y < source_height; y++) {
+                                       for(int x = 1; x <= source_width; x++) {
+                                               uint32 c = src[x - 1];
+                                               t0[x] = (c >> 24) & 0xff;
+                                               r0[x] = (c >> 16) & 0xff;
+                                               g0[x] = (c >>  8) & 0xff;
+                                               b0[x] = (c      ) & 0xff;
+                                               r1[x] = (c >> 19) & 0x1f;
+                                               g1[x] = (c >> 11) & 0x1f;
+                                               b1[x] = (c >>  3) & 0x1f;
+                                       }
+                                       scrntype* out1 = out;
+                                       out -= data_len;
+                                       scrntype* out2 = out;
+                                       out -= data_len;
+                                       scrntype* out3 = out;
+                                       out -= data_len;
+                                       for(int x = 1, xx = 0; x <= source_width; x++, xx += 3) {
+                                               uint32 r = r1[x - 1] + r0[x] + r1[x + 1];
+                                               uint32 g = g1[x - 1] + g0[x] + g1[x + 1];
+                                               uint32 b = b1[x - 1] + b0[x] + b1[x + 1];
+                                               out1[xx    ] = out2[xx    ] = (32 + _8_8(r)) << 16;
+                                               out1[xx + 1] = out2[xx + 1] = (32 + _8_8(g)) << 8;
+                                               out1[xx + 2] = out2[xx + 2] = (32 + _8_8(b));
+                                               if(t0[x]) {
+                                                       out3[xx    ] = (32 + _8_8(r)) << 16;
+                                                       out3[xx + 1] = (32 + _8_8(g)) << 8;
+                                                       out3[xx + 2] = (32 + _8_8(b));
+                                               } else {
+                                                       out3[xx    ] = (32 + _5_8(r)) << 16;
+                                                       out3[xx + 1] = (32 + _5_8(g)) << 8;
+                                                       out3[xx + 2] = (32 + _5_8(b));
+                                               }
+                                       }
+                                       src -= source_width;
+                               }
+                       } else {
+                               for(int y = 0; y < source_height; y += 2) {
+                                       for(int x = 1; x <= source_width; x++) {
+                                               uint32 c = src[x - 1];
+                                               t0[x] = (c >> 24) & 0xff;
+                                               r0[x] = (c >> 16) & 0xff;
+                                               g0[x] = (c >>  8) & 0xff;
+                                               b0[x] = (c      ) & 0xff;
+                                               r1[x] = (c >> 20) & 0x0f;
+                                               g1[x] = (c >> 12) & 0x0f;
+                                               b1[x] = (c >>  4) & 0x0f;
+                                       }
+                                       scrntype* out1 = out;
+                                       out -= data_len;
+                                       scrntype* out2 = out;
+                                       out -= data_len;
+                                       scrntype* out3 = out;
+                                       out -= data_len;
+                                       scrntype* out4 = out;
+                                       out -= data_len;
+                                       scrntype* out5 = out;
+                                       out -= data_len;
+                                       scrntype* out6 = out;
+                                       out -= data_len;
+                                       for(int x = 1, xx = 0; x <= source_width; x++, xx += 3) {
+                                               uint32 r = r1[x - 1] + r0[x] + r1[x + 1];
+                                               uint32 g = g1[x - 1] + g0[x] + g1[x + 1];
+                                               uint32 b = b1[x - 1] + b0[x] + b1[x + 1];
+                                               out1[xx    ] = out2[xx    ] = out3[xx    ] = out4[xx    ] = (32 + _8_8(r)) << 16;
+                                               out1[xx + 1] = out2[xx + 1] = out3[xx + 1] = out4[xx + 1] = (32 + _8_8(g)) << 8;
+                                               out1[xx + 2] = out2[xx + 2] = out3[xx + 2] = out4[xx + 2] = (32 + _8_8(b));
+                                               if(t0[x]) {
+                                                       out5[xx    ] = out6[xx    ] = (32 + _8_8(r)) << 16;
+                                                       out5[xx + 1] = out6[xx + 1] = (32 + _8_8(g)) << 8;
+                                                       out5[xx + 2] = out6[xx + 2] = (32 + _8_8(b));
+                                               } else {
+                                                       out5[xx    ] = out6[xx    ] = (32 + _5_8(r)) << 16;
+                                                       out5[xx + 1] = out6[xx + 1] = (32 + _5_8(g)) << 8;
+                                                       out5[xx + 2] = out6[xx + 2] = (32 + _5_8(b));
+                                               }
+                                       }
+                                       src -= source_width * 2;
+                               }
+                       }
+               } else if(config.crt_filter && stretch_pow_x == 2 && stretch_pow_y == 2) {
+                       if(!screen_skip_line) {
+                               for(int y = 0; y < source_height; y++) {
+                                       for(int x = 1; x <= source_width; x++) {
+                                               uint32 c = src[x - 1];
+                                               t0[x] = (c >> 24) & 0xff;
+                                               r0[x] = (c >> 16) & 0xff;
+                                               g0[x] = (c >>  8) & 0xff;
+                                               b0[x] = (c      ) & 0xff;
+                                               r1[x] = (c >> 19) & 0x1f;
+                                               g1[x] = (c >> 11) & 0x1f;
+                                               b1[x] = (c >>  3) & 0x1f;
+                                       }
+                                       scrntype* out1 = out;
+                                       out -= data_len;
+                                       scrntype* out2 = out;
+                                       out -= data_len;
+                                       for(int x = 1, xx = 0; x <= source_width; x++, xx += 2) {
+                                               uint32 r = r1[x - 1] + r0[x] + r1[x + 1];
+                                               uint32 g = g1[x - 1] + g0[x] + g1[x + 1];
+                                               uint32 b = b1[x - 1] + b0[x] + b1[x + 1];
+                                               out1[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));
+                                               out1[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));
+                                               if(t0[x]) {
+                                                       out2[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));
+                                                       out2[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));
+                                               } else {
+                                                       out2[xx    ] = RGB_COLOR(32 + _3_8(r), 32 + _3_8(g), 32 + _3_8(b));
+                                                       out2[xx + 1] = RGB_COLOR(16 + _3_8(r), 16 + _3_8(g), 16 + _3_8(b));
+                                               }
+                                       }
+                                       src -= source_width;
+                               }
+                       } else {
+                               for(int y = 0; y < source_height; y += 2) {
+                                       for(int x = 1; x <= source_width; x++) {
+                                               uint32 c = src[x - 1];
+                                               t0[x] = (c >> 24) & 0xff;
+                                               r0[x] = (c >> 16) & 0xff;
+                                               g0[x] = (c >>  8) & 0xff;
+                                               b0[x] = (c      ) & 0xff;
+                                               r1[x] = (c >> 19) & 0x1f;
+                                               g1[x] = (c >> 11) & 0x1f;
+                                               b1[x] = (c >>  3) & 0x1f;
+                                       }
+                                       scrntype* out1 = out;
+                                       out -= data_len;
+                                       scrntype* out2 = out;
+                                       out -= data_len;
+                                       scrntype* out3 = out;
+                                       out -= data_len;
+                                       scrntype* out4 = out;
+                                       out -= data_len;
+                                       for(int x = 1, xx = 0; x <= source_width; x++, xx += 2) {
+                                               uint32 r = r1[x - 1] + r0[x] + r1[x + 1];
+                                               uint32 g = g1[x - 1] + g0[x] + g1[x + 1];
+                                               uint32 b = b1[x - 1] + b0[x] + b1[x + 1];
+                                               out1[xx    ] = out2[xx    ] = out3[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));
+                                               out1[xx + 1] = out2[xx + 1] = out3[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));
+                                               if(t0[x]) {
+                                                       out4[xx    ] = RGB_COLOR(32 + _8_8(r), 32 + _8_8(g), 32 + _8_8(b));
+                                                       out4[xx + 1] = RGB_COLOR(16 + _5_8(r), 16 + _5_8(g), 16 + _5_8(b));
+                                               } else {
+                                                       out4[xx    ] = RGB_COLOR(32 + _3_8(r), 32 + _3_8(g), 32 + _3_8(b));
+                                                       out4[xx + 1] = RGB_COLOR(16 + _3_8(r), 16 + _3_8(g), 16 + _3_8(b));
+                                               }
+                                       }
+                                       src -= source_width * 2;
+                               }
+                       }
+               } else
+#endif
+               for(int y = 0; y < source_height; y++) {
+                       if(stretch_pow_x != 1) {
+                               scrntype* out_tmp = out;
+                               for(int x = 0; x < source_width; x++) {
+                                       scrntype c = src[x];
+                                       for(int px = 0; px < stretch_pow_x; px++) {
+                                               out_tmp[px] = c;
+                                       }
+                                       out_tmp += stretch_pow_x;
+                               }
+                       } else {
+                               // faster than memcpy()
+                               for(int x = 0; x < source_width; x++) {
+                                       out[x] = src[x];
+                               }
+                       }
+                       if(stretch_pow_y != 1) {
+                               scrntype* src_tmp = out;
+                               for(int py = 1; py < stretch_pow_y; py++) {
+                                       out -= data_len;
+                                       // about 10% faster than memcpy()
+                                       for(int x = 0; x < data_len; x++) {
+                                               out[x] = src_tmp[x];
+                                       }
+                               }
+                       }
+                       src -= source_width;
+                       out -= data_len;
+               }
+               if(!use_d3d9) {
+                       StretchBlt(hdcDibStretch2, 0, 0, stretched_width, stretched_height, hdcDibStretch1, 0, 0, source_width * stretch_pow_x, source_height * stretch_pow_y, SRCCOPY);
+               }
+       }
+       first_draw_screen = true;
+       
+       // copy bitmap to d3d9 offscreen surface
+       if(use_d3d9 && lpd3d9Buffer != NULL) {
+               if(!(render_to_d3d9Buffer && !now_rec_video)) {
+                       scrntype *src = stretch_screen ? lpBmpStretch1 : lpBmpSource;
+                       src += source_width * stretch_pow_x * (source_height * stretch_pow_y - 1);
+                       scrntype *out = lpd3d9Buffer;
+                       int data_len = source_width * stretch_pow_x;
+                       
+                       for(int y = 0; y < source_height * stretch_pow_y; y++) {
+                               for(int i = 0; i < data_len; i++) {
+                                       out[i] = src[i];
+                               }
+                               src -= data_len;
+                               out += data_len;
+                       }
+               }
+               // unlock offscreen surface
+               lpd3d9Buffer = NULL;
+               lpd3d9OffscreenSurface->UnlockRect();
+       }
+       
+       // invalidate window
+       InvalidateRect(main_window_handle, NULL, first_invalidate);
+       UpdateWindow(main_window_handle);
+       self_invalidate = true;
+       
+       // record avi file
+       if(now_rec_video) {
+               static double frames = 0;
+               static int prev_video_fps = -1;
+#ifdef SUPPORT_VARIABLE_TIMING
+               static double prev_vm_fps = -1;
+               double vm_fps = vm->frame_rate();
+               if(prev_video_fps != rec_video_fps || prev_vm_fps != vm_fps) {
+                       prev_video_fps = rec_video_fps;
+                       prev_vm_fps = vm_fps;
+                       frames = vm_fps / rec_video_fps;
+               }
+#else
+               if(prev_video_fps != rec_video_fps) {
+                       prev_video_fps = rec_video_fps;
+                       frames = FRAMES_PER_SEC / rec_video_fps;
+               }
+#endif
+               int counter = 0;
+               if(use_video_thread) {
+                       while(rec_video_run_frames > 0) {
+                               rec_video_run_frames -= frames;
+                               rec_video_frames += frames;
+                               counter++;
+                       }
+                       if(counter != 0) {
+                               if(hVideoThread != (HANDLE)0) {
+                                       if(video_thread_param.result == 0) {
+                                               WaitForSingleObject(hVideoThread, INFINITE);
+                                       }
+                                       hVideoThread = (HANDLE)0;
+                                       
+                                       if(video_thread_param.result == RESULT_FULL) {
+                                               stop_rec_video();
+                                               if(!start_rec_video(-1)) {
+                                                       return 0;
+                                               }
+                                       } else if(video_thread_param.result == RESULT_ERROR) {
+                                               stop_rec_video();
+                                               return 0;
+                                       }
+                               }
+                               BitBlt(hdcDibRec, 0, 0, source_width, source_height, hdcDibSource, 0, 0, SRCCOPY);
+                               video_thread_param.frames += counter;
+                               video_thread_param.result = 0;
+                               if((hVideoThread = (HANDLE)_beginthreadex(NULL, 0, rec_video_thread, &video_thread_param, 0, NULL)) == (HANDLE)0) {
+                                       stop_rec_video();
+                                       return 0;
+                               }
+                       }
+               } else {
+                       while(rec_video_run_frames > 0) {
+                               LONG lBytesWritten;
+                               if(AVIStreamWrite(pAVICompressed, lAVIFrames++, 1, (LPBYTE)lpBmpSource, pbmInfoHeader->biSizeImage, AVIIF_KEYFRAME, NULL, &lBytesWritten) == AVIERR_OK) {
+                                       // if avi file size > (2GB - 16MB), create new avi file
+                                       if((dwAVIFileSize += lBytesWritten) >= 2130706432) {
+                                               stop_rec_video();
+                                               if(!start_rec_video(-1)) {
+                                                       break;
+                                               }
+                                       }
+                                       rec_video_run_frames -= frames;
+                                       rec_video_frames += frames;
+                                       counter++;
+                               } else {
+                                       stop_rec_video();
+                                       break;
+                               }
+                       }
+               }
+               return counter;
+       } else {
+               return 1;
+       }
+}
+
+scrntype* EMU::screen_buffer(int y)
+{
+       if(use_d3d9 && lpd3d9Buffer != NULL && render_to_d3d9Buffer && !now_rec_video) {
+               return lpd3d9Buffer + screen_width * y;
+       }
+       return lpBmp + screen_width * (screen_height - y - 1);
+}
+
+void EMU::update_screen(HDC hdc)
+{
+#ifdef USE_BITMAP
+       if(first_invalidate || !self_invalidate) {
+               HDC hmdc = CreateCompatibleDC(hdc);
+               HBITMAP hBitmap = LoadBitmap(instance_handle, _T("IDI_BITMAP1"));
+               BITMAP bmp;
+               GetObject(hBitmap, sizeof(BITMAP), &bmp);
+               int w = (int)bmp.bmWidth;
+               int h = (int)bmp.bmHeight;
+               HBITMAP hOldBitmap = (HBITMAP)SelectObject(hmdc, hBitmap);
+               BitBlt(hdc, 0, 0, w, h, hmdc, 0, 0, SRCCOPY);
+               SelectObject(hmdc, hOldBitmap);
+               DeleteObject(hBitmap);
+               DeleteDC(hmdc);
+       }
+#endif
+       if(first_draw_screen) {
+#ifdef USE_LED
+               // 7-seg LEDs
+               for(int i = 0; i < MAX_LEDS; i++) {
+                       int x = leds[i].x;
+                       int y = leds[i].y;
+                       int w = leds[i].width;
+                       int h = leds[i].height;
+                       BitBlt(hdc, x, y, w, h, hdcDib, x, y, SRCCOPY);
+               }
+#else
+#ifdef USE_ACCESS_LAMP
+               // get access lamps status of drives
+               int status = vm->access_lamp() & 7;
+               static int prev_status = 0;
+               bool render_in = (status != 0);
+               bool render_out = (prev_status != status);
+               prev_status = status;
+               
+               COLORREF crColor = RGB((status & 1) ? 255 : 0, (status & 2) ? 255 : 0, (status & 4) ? 255 : 0);
+               int right_bottom_x = screen_dest_x + stretched_width;
+               int right_bottom_y = screen_dest_y + stretched_height;
+#endif
+               // standard screen
+               if(use_d3d9) {
+                       LPDIRECT3DSURFACE9 lpd3d9BackSurface = NULL;
+                       if(lpd3d9Device != NULL && lpd3d9Device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &lpd3d9BackSurface) == D3D_OK && lpd3d9BackSurface != NULL) {
+                               RECT rectSrc = { 0, 0, source_width * stretch_pow_x, source_height * stretch_pow_y };
+                               RECT rectDst = { screen_dest_x, screen_dest_y, screen_dest_x + stretched_width, screen_dest_y + stretched_height };
+                               
+                               lpd3d9Device->UpdateSurface(lpd3d9OffscreenSurface, NULL, lpd3d9Surface, NULL);
+                               lpd3d9Device->StretchRect(lpd3d9Surface, &rectSrc, lpd3d9BackSurface, &rectDst, stretch_screen ? D3DTEXF_LINEAR : D3DTEXF_POINT);
+#ifdef USE_ACCESS_LAMP
+                               // draw access lamps
+                               if(render_in || render_out) {
+                                       HDC hDC = 0;
+                                       for(int y = display_height - 6; y < display_height; y++) {
+                                               for(int x = display_width - 6; x < display_width; x++) {
+                                                       if((x < right_bottom_x && y < right_bottom_y) ? render_in : render_out) {
+                                                               if(hDC == 0 && lpd3d9BackSurface->GetDC(&hDC) != D3D_OK) {
+                                                                       goto quit;
+                                                               }
+                                                               SetPixelV(hDC, x, y, crColor);
+                                                       }
+                                               }
+                                       }
+quit:
+                                       if(hDC != 0) {
+                                               lpd3d9BackSurface->ReleaseDC(hDC);
+                                       }
+                               }
+#endif
+                               lpd3d9BackSurface->Release();
+                               lpd3d9Device->Present(NULL, NULL, NULL, NULL);
+                       }
+               } else {
+                       if(stretch_screen) {
+                               BitBlt(hdc, screen_dest_x, screen_dest_y, stretched_width, stretched_height, hdcDibStretch2, 0, 0, SRCCOPY);
+                       } else if(stretched_width == source_width && stretched_height == source_height) {
+                               BitBlt(hdc, screen_dest_x, screen_dest_y, stretched_width, stretched_height, hdcDibSource, 0, 0, SRCCOPY);
+                       } else {
+                               StretchBlt(hdc, screen_dest_x, screen_dest_y, stretched_width, stretched_height, hdcDibSource, 0, 0, source_width, source_height, SRCCOPY);
+                       }
+#ifdef USE_ACCESS_LAMP
+                       // draw access lamps
+                       if(render_in || render_out) {
+                               for(int y = display_height - 6; y < display_height; y++) {
+                                       for(int x = display_width - 6; x < display_width; x++) {
+                                               if((x < right_bottom_x && y < right_bottom_y) ? render_in : render_out) {
+                                                       SetPixelV(hdc, x, y, crColor);
+                                               }
+                                       }
+                               }
+                       }
+#endif
+               }
+#endif
+               first_invalidate = self_invalidate = false;
+       }
+}
+
+void EMU::capture_screen()
+{
+       if(use_d3d9 && render_to_d3d9Buffer && !now_rec_video) {
+               // virtual machine may render screen to d3d9 buffer directly...
+               vm->draw_screen();
+       }
+       
+       // create file name
+       SYSTEMTIME sTime;
+       GetLocalTime(&sTime);
+       
+       _TCHAR file_name[_MAX_PATH];
+       _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);
+       
+       // create bitmap
+       BITMAPFILEHEADER bmFileHeader = { (WORD)(TEXT('B') | TEXT('M') << 8) };
+       bmFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
+       bmFileHeader.bfSize = bmFileHeader.bfOffBits + pbmInfoHeader->biSizeImage;
+       
+       DWORD dwSize;
+       HANDLE hFile = CreateFile(bios_path(file_name), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+       WriteFile(hFile, &bmFileHeader, sizeof(BITMAPFILEHEADER), &dwSize, NULL);
+       WriteFile(hFile, lpDibSource, sizeof(BITMAPINFOHEADER), &dwSize, NULL);
+       WriteFile(hFile, lpBmpSource, pbmInfoHeader->biSizeImage, &dwSize, NULL);
+       CloseHandle(hFile);
+}
+
+bool EMU::start_rec_video(int fps)
+{
+       if(fps > 0) {
+               rec_video_fps = fps;
+               rec_video_run_frames = rec_video_frames = 0;
+       } else {
+               fps = rec_video_fps;
+       }
+       bool show_dialog = (fps > 0);
+       
+       // create file name
+       SYSTEMTIME sTime;
+       GetLocalTime(&sTime);
+       
+       _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);
+       
+       // initialize vfw
+       AVIFileInit();
+       if(AVIFileOpen(&pAVIFile, bios_path(video_file_name), OF_WRITE | OF_CREATE, NULL) != AVIERR_OK) {
+               return false;
+       }
+       use_video_thread = false;
+       
+       // stream header
+       AVISTREAMINFO strhdr;
+       memset(&strhdr, 0, sizeof(strhdr));
+       strhdr.fccType = streamtypeVIDEO;       // vids
+       strhdr.fccHandler = 0;
+       strhdr.dwScale = 1;
+       strhdr.dwRate = fps;
+       strhdr.dwSuggestedBufferSize = pbmInfoHeader->biSizeImage;
+       SetRect(&strhdr.rcFrame, 0, 0, source_width, source_height);
+       if(AVIFileCreateStream(pAVIFile, &pAVIStream, &strhdr) != AVIERR_OK) {
+               stop_rec_video();
+               return false;
+       }
+       
+       // compression
+       AVICOMPRESSOPTIONS FAR * pOpts[1];
+       pOpts[0] = &opts;
+       if(show_dialog && !AVISaveOptions(main_window_handle, ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE, 1, &pAVIStream, (LPAVICOMPRESSOPTIONS FAR *)&pOpts)) {
+               AVISaveOptionsFree(1, (LPAVICOMPRESSOPTIONS FAR *)&pOpts);
+               stop_rec_video();
+               return false;
+       }
+       if(AVIMakeCompressedStream(&pAVICompressed, pAVIStream, &opts, NULL) != AVIERR_OK) {
+               stop_rec_video();
+               return false;
+       }
+       if(AVIStreamSetFormat(pAVICompressed, 0, &lpDibSource->bmiHeader, lpDibSource->bmiHeader.biSize + lpDibSource->bmiHeader.biClrUsed * sizeof(RGBQUAD)) != AVIERR_OK) {
+               stop_rec_video();
+               return false;
+       }
+       dwAVIFileSize = 0;
+       lAVIFrames = 0;
+       
+       SYSTEM_INFO info;
+       GetSystemInfo(&info);
+       
+       if(info.dwNumberOfProcessors > 1) {
+               use_video_thread = true;
+               hVideoThread = (HANDLE)0;
+               video_thread_param.pAVICompressed = pAVICompressed;
+               video_thread_param.lpBmpSource = lpBmpSource;
+               video_thread_param.pbmInfoHeader = pbmInfoHeader;
+               video_thread_param.dwAVIFileSize = 0;
+               video_thread_param.lAVIFrames = 0;
+               video_thread_param.frames = 0;
+               video_thread_param.result = 0;
+               
+               HDC hdc = GetDC(main_window_handle);
+               create_dib_section(hdc, source_width, source_height, &hdcDibRec, &hBmpRec, &hOldBmpRec, &lpBufRec, &lpBmpRec, &lpDibRec);
+               ReleaseDC(main_window_handle, hdc);
+       }
+       now_rec_video = true;
+       return true;
+}
+
+void EMU::stop_rec_video()
+{
+       // release thread
+       if(use_video_thread) {
+               if(hVideoThread != (HANDLE)0) {
+                       WaitForSingleObject(hVideoThread, INFINITE);
+                       hVideoThread = (HANDLE)0;
+               }
+               if(hdcDibRec) {
+                       release_dib_section(hdcDibRec, hBmpRec, hOldBmpRec, lpBufRec);
+               }
+       }
+       
+       // release vfw
+       if(pAVIStream) {
+               AVIStreamClose(pAVIStream);
+       }
+       if(pAVICompressed) {
+               AVIStreamClose(pAVICompressed);
+       }
+       if(pAVIFile) {
+               AVIFileClose(pAVIFile);
+               AVIFileExit();
+       }
+       pAVIStream = NULL;
+       pAVICompressed = NULL;
+       pAVIFile = NULL;
+       
+       // repair header
+       if(now_rec_video) {
+               FILE* fp = NULL;
+               if(_tfopen_s(&fp, bios_path(video_file_name), _T("r+b")) == 0) {
+                       // copy fccHandler
+                       uint8 buf[4];
+                       fseek(fp, 0xbc, SEEK_SET);
+                       if(ftell(fp) == 0xbc) {
+                               fread(buf, 4, 1, fp);
+                               fseek(fp, 0x70, SEEK_SET);
+                               fwrite(buf, 4, 1, fp);
+                       }
+                       fclose(fp);
+               }
+       }
+       now_rec_video = false;
+}
+
+void EMU::restart_rec_video()
+{
+       bool tmp = now_rec_video;
+       stop_rec_video();
+       if(tmp) start_rec_video(-1);
+}
+
+unsigned __stdcall rec_video_thread(void *lpx)
+{
+       volatile video_thread_t *p = (video_thread_t *)lpx;
+       LONG lBytesWritten;
+       int result = RESULT_SUCCESS;
+       
+       while(p->frames > 0) {
+               if(AVIStreamWrite(p->pAVICompressed, p->lAVIFrames++, 1, (LPBYTE)p->lpBmpSource, p->pbmInfoHeader->biSizeImage, AVIIF_KEYFRAME, NULL, &lBytesWritten) == AVIERR_OK) {
+                       p->frames--;
+                       // if avi file size > (2GB - 16MB), create new avi file
+                       if((p->dwAVIFileSize += lBytesWritten) >= 2130706432) {
+                               result = RESULT_FULL;
+                               break;
+                       }
+               } else {
+                       result = RESULT_ERROR;
+                       break;
+               }
+       }
+       p->result = result;
+       _endthreadex(0);
+       return 0;
+}
+