From 23a4423c025c42fc5131e090afe0df11112443df Mon Sep 17 00:00:00 2001 From: Mike Wey Date: Fri, 30 Dec 2011 18:39:25 +0100 Subject: Add the windows display functionality. --- dmagick/Image.d | 35 +------- dmagick/internal/Windows.d | 207 +++++++++++++++++++++++++++++++++++++++++++++ examples/draw.d | 2 +- windows.mak | 4 +- 4 files changed, 215 insertions(+), 33 deletions(-) create mode 100644 dmagick/internal/Windows.d diff --git a/dmagick/Image.d b/dmagick/Image.d index a556fa0..6f1a8e4 100644 --- a/dmagick/Image.d +++ b/dmagick/Image.d @@ -25,6 +25,8 @@ import dmagick.ImageView; import dmagick.Options; import dmagick.Utils; +version(Windows) import dmagick.internal.Windows; + //Import all translated c headers. import dmagick.c.MagickCore; @@ -1180,37 +1182,8 @@ class Image { version(Windows) { - WNDCLASS wndclass; - HINSTANCE hInstance = cast(HINSTANCE) GetModuleHandle(null); - HWND hwnd; - MSG msg; - - wndclass.style = CS_HREDRAW | CS_VREDRAW; - wndclass.lpfnWndProc = &WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = hInstance; - wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclass.hbrBackground = null; - wndclass.lpszMenuName = "DMagick"w; - wndclass.lpszClassName = "DMagick"w; - - if (!RegisterClass(&wndclass)) - throw new DMagickException("This program requires Windows NT!"); - - hwnd = CreateWindow(cn, toStringz(title), WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, width, height, - null, null, hInstance, null); - - ShowWindow(hwnd, SW_SHOWNORMAL); - UpdateWindow(hwnd); - - while (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } + Window win = new Window(this); + win.display(); } else { 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 diff --git a/examples/draw.d b/examples/draw.d index deed525..0aced61 100644 --- a/examples/draw.d +++ b/examples/draw.d @@ -64,7 +64,7 @@ void main() dc.fill(cylinderTop); dc.roundRectangle(progressXmax - (2 * wc), progressYmin, progressXmax, progressYmax, wc, hc); - dc.font("Helvetica"); + dc.font("Arial"); dc.fontSize(fontsize); dc.stroke(textShadow); dc.fill(textColor); diff --git a/windows.mak b/windows.mak index ebf57c1..5b0edeb 100644 --- a/windows.mak +++ b/windows.mak @@ -108,7 +108,9 @@ SOURCE= \ dmagick\c\type.d \ dmagick\c\utility.d \ dmagick\c\xmlTree.d \ - dmagick\c\xwindow.d + dmagick\c\xwindow.d \ + \ + dmagick\internal\Windows.d \ ################## DOCS #################################### -- cgit v1.2.3