diff options
Diffstat (limited to 'dmagick/internal/Windows.d')
| -rw-r--r-- | dmagick/internal/Windows.d | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/dmagick/internal/Windows.d b/dmagick/internal/Windows.d new file mode 100644 index 0000000..1358253 --- /dev/null +++ b/dmagick/internal/Windows.d @@ -0,0 +1,207 @@ +/** + * Copyright: Mike Wey 2011 + * License: zlib (See accompanying LICENSE file) + * Authors: Mike Wey + */ + +module dmagick.internal.Windows; + +import core.sys.windows.windows; + +import dmagick.Image; +import dmagick.Exception; +import dmagick.Geometry; + +Window[HWND] windows; + +class Window +{ + Image image; + size_t height; + size_t width; + + WNDCLASS wndclass; + HINSTANCE hInstance; + HWND hwnd; + MSG msg; + + this(Image image) + { + this.image = image; + + height = image.rows; + width = image.columns; + + hInstance = cast(HINSTANCE) GetModuleHandleA(null); + + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = &WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIconA(null, IDI_APPLICATION); + wndclass.hCursor = LoadCursorA(null, IDC_ARROW); + wndclass.hbrBackground = null; + wndclass.lpszMenuName = "DMagick"; + wndclass.lpszClassName = "DMagick"; + + if (!RegisterClassA(&wndclass)) + throw new DMagickException("This program requires Windows NT!"); + + RECT rect = RECT(0,0, width,height); + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, false); + + hwnd = CreateWindowA("DMagick", "DMagick", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, + null, null, hInstance, null); + + windows[hwnd] = this; + } + + void display() + { + ShowWindow(hwnd, SW_SHOWNORMAL); + UpdateWindow(hwnd); + + while (GetMessageA(&msg, null, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + } + + extern(Windows) static LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) + { + static int cxClient, cyClient, cxSource, cySource; + int x, y; + HDC hdc; + PAINTSTRUCT ps; + + static HDC hdcMem; + static HBITMAP hbmMem; + static HANDLE hOld; + RECT rect; + + switch (message) + { + case WM_SIZE: + cxClient = LOWORD(lParam); + cyClient = HIWORD(lParam); + return 0; + + case WM_ERASEBKGND: // don't redraw bg + return 1; + + case WM_PAINT: + { + // Get DC for window + hdc = BeginPaint(hwnd, &ps); + + // Create an off-screen DC for double-buffering + hdcMem = CreateCompatibleDC(hdc); + hbmMem = CreateCompatibleBitmap(hdc, cxClient, cyClient); + hOld = SelectObject(hdcMem, hbmMem); + + // Draw into hdcMem + GetClientRect(hwnd, &rect); + FillRect(hdcMem, &rect, GetStockObject(BLACK_BRUSH)); + + windows[hwnd].DrawAlphaBlend(hwnd, hdcMem); + + // Transfer the off-screen DC to the screen + BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY); + + // Free-up the off-screen DC + SelectObject(hdcMem, hOld); + DeleteObject(hbmMem); + DeleteDC (hdcMem); + + EndPaint(hwnd, &ps); + return 0; + } + + case WM_DESTROY: + windows[hwnd] = null; + PostQuitMessage(0); + return 0; + + default: + } + + return DefWindowProcA(hwnd, message, wParam, lParam); + } + + void DrawAlphaBlend(HWND hWnd, HDC hdcwnd) + { + HDC hdc; // handle of the DC we will create + HBITMAP hbitmap; // bitmap handle + BITMAPINFO bmi; // bitmap header + VOID* pvBits; // pointer to DIB section + ULONG ulWindowWidth, ulWindowHeight; // window width/height + RECT rt; // used for getting window dimensions + + // get window dimensions + GetClientRect(hWnd, &rt); + + // calculate window width/height + ulWindowWidth = rt.right - rt.left; + ulWindowHeight = rt.bottom - rt.top; + + // make sure we have at least some window size + if (ulWindowWidth < 1 || ulWindowHeight < 1) + return; + + // create a DC for our bitmap -- the source DC for GdiAlphaBlend + hdc = CreateCompatibleDC(hdcwnd); + + // setup bitmap info + bmi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; // must be inverted so Y axis is at top + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; // four 8-bit components + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = width * height * 4; + + // create our DIB section and select the bitmap into the dc + hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, null, 0x0); + SelectObject(hdc, hbitmap); + + auto area = Geometry(width, height, 0, 0); + enum channels = "BGRA"; // win32 uses BGR(A) + byte[] arr = (cast(byte*)pvBits)[0 .. (area.width * area.height) * channels.length]; + image.exportPixels(area, arr, channels); + + //TODO: Rezize image. + BitBlt(hdcwnd, 0, 0, width, height, hdc, 0, 0, SRCCOPY); + + DeleteObject(hbitmap); + DeleteDC(hdc); + } +} + +pragma(lib, "gdi32.lib"); + +const AC_SRC_OVER = 0x00; +const AC_SRC_ALPHA = 0x01; +const GWLP_USERDATA = -21; + +enum DWORD BI_RGB = 0; +enum UINT DIB_RGB_COLORS = 0; + +struct BLENDFUNCTION +{ + BYTE BlendOp; + BYTE BlendFlags; + BYTE SourceConstantAlpha; + BYTE AlphaFormat; +} + +struct AlphaBlendType +{ + static normal = BLENDFUNCTION(AC_SRC_OVER, 0, 255, AC_SRC_ALPHA); +} + +extern(Windows) BOOL BitBlt(HDC, int, int, int, int, HDC, int, int, DWORD); +extern(Windows) HBITMAP CreateCompatibleBitmap(HDC, int, int); +extern(Windows) HBITMAP CreateDIBSection(HDC, const(BITMAPINFO)*, UINT, void**, HANDLE, DWORD);
\ No newline at end of file |
