PageRenderTime 39ms CodeModel.GetById 2ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/win32_cairo_doublebuffer.d

http://github.com/AndrejMitrovic/cairoDSamples
D | 331 lines | 223 code | 60 blank | 48 comment | 9 complexity | 89869bf7d7e30653a519a1df2ee29cc5 MD5 | raw file
  1module win32_cairo_doublebuffer;
  2
  3/+
  4 +           Copyright Andrej Mitrovic 2011.
  5 +  Distributed under the Boost Software License, Version 1.0.
  6 +     (See accompanying file LICENSE_1_0.txt or copy at
  7 +           http://www.boost.org/LICENSE_1_0.txt)
  8 +/
  9
 10/+
 11 + Demonstrates the usage of a double-buffer using Cairo and win32.
 12 + Also shows how to avoid re-blitting an area by simply using the
 13 + ps.rcPaint bounding rectangle field, and removing redrawing of
 14 + the entire window when it is resized.
 15 +
 16 + For more info on double-buffering and avoiding screen flicker, see:
 17 + http://wiki.osdev.org/Double_Buffering
 18 + http://www.catch22.net/tuts/flicker
 19 +/
 20
 21import core.runtime;
 22import std.process;
 23import std.stdio;
 24import std.utf;
 25
 26pragma(lib, "gdi32.lib");
 27import win32.windef;
 28import win32.winuser;
 29import win32.wingdi;
 30
 31string appName     = "CairoWindow";
 32string description = "A simple win32 window with Cairo drawing";
 33HINSTANCE hinst;
 34
 35import cairo.cairo;
 36import cairo.win32;
 37
 38alias cairo.cairo.RGB RGB;  // conflicts with win32.wingdi.RGB
 39
 40extern (Windows)
 41int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
 42{
 43    int result;
 44    void exceptionHandler(Throwable e) { throw e; }
 45
 46    try
 47    {
 48        Runtime.initialize(&exceptionHandler);
 49        result = myWinMain(hInstance, hPrevInstance, lpCmdLine, iCmdShow);
 50        Runtime.terminate(&exceptionHandler);
 51    }
 52    catch (Throwable o)
 53    {
 54        MessageBox(null, o.toString().toUTF16z, "Error", MB_OK | MB_ICONEXCLAMATION);
 55        result = 0;
 56    }
 57
 58    return result;
 59}
 60
 61int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow)
 62{
 63    hinst = hInstance;
 64    HACCEL hAccel;
 65    HWND hwnd;
 66    MSG  msg;
 67    WNDCLASS wndclass;
 68
 69    // commented out so we do not redraw the entire screen on resize
 70    //~ wndclass.style         = CS_HREDRAW | CS_VREDRAW;
 71    wndclass.style         = WS_CLIPCHILDREN;
 72    wndclass.lpfnWndProc   = &WndProc;
 73    wndclass.cbClsExtra    = 0;
 74    wndclass.cbWndExtra    = 0;
 75    wndclass.hInstance     = hInstance;
 76    wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
 77    wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
 78    wndclass.hbrBackground = null;
 79    wndclass.lpszMenuName  = appName.toUTF16z;
 80    wndclass.lpszClassName = appName.toUTF16z;
 81
 82    if (!RegisterClass(&wndclass))
 83    {
 84        MessageBox(NULL, "This program requires Windows NT!", appName.toUTF16z, MB_ICONERROR);
 85        return 0;
 86    }
 87
 88    hwnd = CreateWindow(appName.toUTF16z,              // window class name
 89                        description.toUTF16z,          // window caption
 90                        WS_OVERLAPPEDWINDOW,           // window style
 91                        CW_USEDEFAULT,                 // initial x position
 92                        CW_USEDEFAULT,                 // initial y position
 93                        CW_USEDEFAULT,                 // initial x size
 94                        CW_USEDEFAULT,                 // initial y size
 95                        NULL,                          // parent window handle
 96                        NULL,                          // window menu handle
 97                        hInstance,                     // program instance handle
 98                        NULL);                         // creation parameters
 99
100    ShowWindow(hwnd, iCmdShow);
101    UpdateWindow(hwnd);
102
103    while (GetMessage(&msg, NULL, 0, 0))
104    {
105        TranslateMessage(&msg);
106        DispatchMessage(&msg);
107    }
108
109    return msg.wParam;
110}
111
112void roundedRectangle(Context ctx, int x, int y, int w, int h, int radius_x = 5, int radius_y = 5)
113{
114    enum ARC_TO_BEZIER = 0.55228475;
115
116    if (radius_x > w - radius_x)
117        radius_x = w / 2;
118
119    if (radius_y > h - radius_y)
120        radius_y = h / 2;
121
122    // approximate (quite close) the arc using a bezier curve
123    auto c1 = ARC_TO_BEZIER * radius_x;
124    auto c2 = ARC_TO_BEZIER * radius_y;
125
126    ctx.newPath();
127    ctx.moveTo(x + radius_x, y);
128    ctx.relLineTo(w - 2 * radius_x, 0.0);
129    ctx.relCurveTo(c1, 0.0, radius_x, c2, radius_x, radius_y);
130    ctx.relLineTo(0, h - 2 * radius_y);
131    ctx.relCurveTo(0.0, c2, c1 - radius_x, radius_y, -radius_x, radius_y);
132    ctx.relLineTo(-w + 2 * radius_x, 0);
133    ctx.relCurveTo(-c1, 0, -radius_x, -c2, -radius_x, -radius_y);
134    ctx.relLineTo(0, -h + 2 * radius_y);
135    ctx.relCurveTo(0.0, -c2, radius_x - c1, -radius_y, radius_x, -radius_y);
136    ctx.closePath();
137}
138
139extern (Windows)
140LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
141{
142    switch (message)
143    {
144        case WM_CREATE:
145        {
146            window = new Window(hwnd);
147            return 0;
148        }
149
150        default:
151    }
152
153    if (window)
154        return window.process(hwnd, message, wParam, lParam);
155    else
156        return DefWindowProc(hwnd, message, wParam, lParam);
157}
158
159Window window;
160
161struct PaintBuffer
162{
163    int width, height;
164
165    this(HDC localHdc, int cxClient, int cyClient)
166    {
167        width  = cxClient;
168        height = cyClient;
169
170        hBuffer    = CreateCompatibleDC(localHdc);
171        hBitmap    = CreateCompatibleBitmap(localHdc, cxClient, cyClient);
172        hOldBitmap = SelectObject(hBuffer, hBitmap);
173
174        surf = new Win32Surface(hBuffer);
175        ctx = Context(surf);
176        initialized = true;
177    }
178
179    ~this()
180    {
181        if (initialized)  // struct dtors are still buggy sometimes
182        {
183            ctx.dispose();
184            surf.finish();
185            surf.dispose();
186
187            SelectObject(hBuffer, hOldBitmap);
188            DeleteObject(hBitmap);
189            DeleteDC(hBuffer);
190            initialized = false;
191        }
192    }
193
194    bool initialized;
195    HDC hBuffer;
196    HBITMAP hBitmap;
197    HBITMAP hOldBitmap;
198    Context ctx;
199    Surface surf;
200}
201
202class Window
203{
204    int width, height;
205    HWND hwnd;
206    PAINTSTRUCT ps;
207    PaintBuffer paintBuffer;
208    bool needsRedraw;
209
210    this(HWND hwnd)
211    {
212        this.hwnd = hwnd;
213
214        auto hDesk = GetDesktopWindow();
215        RECT rc;
216        GetClientRect(hDesk, &rc);
217
218        auto localHdc = GetDC(hwnd);
219        paintBuffer = PaintBuffer(localHdc, rc.right, rc.bottom);
220        needsRedraw = true;
221    }
222
223    LRESULT process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
224    {
225        switch (message)
226        {
227            case WM_DESTROY:
228                PostQuitMessage(0);
229                return 0;
230
231            case WM_PAINT:
232                OnPaint(hwnd, message, wParam, lParam);
233                return 0;
234
235            case WM_ERASEBKGND:
236                return 1;
237
238            case WM_SIZE:
239            {
240                width  = LOWORD(lParam);
241                height = HIWORD(lParam);
242                return 0;
243            }
244
245            default:
246        }
247
248        return DefWindowProc(hwnd, message, wParam, lParam);
249    }
250
251    void OnPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
252    {
253        static int blitCount;
254        auto hdc = BeginPaint(hwnd, &ps);
255        auto ctx = paintBuffer.ctx;
256        auto hBuffer = paintBuffer.hBuffer;
257
258        auto boundRect = ps.rcPaint;
259
260        with (boundRect)
261        {
262            system("cls");
263            writefln("left: %.3s, top: %.3s, bottom: %.3s, right: %.3s", left, top, bottom, right);
264        }
265
266        if (needsRedraw)  // cairo needs to redraw
267        {
268            draw(ctx);
269            needsRedraw = false;
270        }
271
272        writefln("blit: %.3s", ++blitCount);
273        with (boundRect)  // blit only required areas
274        {
275            BitBlt(hdc, left, top, right, bottom, hBuffer, left, top, SRCCOPY);
276        }
277
278        EndPaint(hwnd, &ps);
279    }
280
281    void draw(Context ctx)
282    {
283        ctx.setSourceRGB(1, 1, 1);
284        ctx.paint();
285        
286        ctx.rectangle(0, 0, 120, 90);
287        ctx.setSourceRGBA(0.7, 0, 0, 0.8);
288        ctx.fill();
289        
290        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_CLEAR);
291        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_SOURCE);
292        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_OVER);
293        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_IN);
294        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_OUT);
295        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_ATOP);
296        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_DEST);
297        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_DEST_OVER);
298        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_DEST_IN);
299        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_DEST_OUT);
300        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_DEST_ATOP);
301        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_DEST_XOR);
302        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_DEST_ADD);
303        //~ ctx.setOperator(Operator.CAIRO_OPERATOR_DEST_SATURATE);
304        
305        //~ // blue
306        ctx.rectangle(40, 30, 120, 90);
307        ctx.setSourceRGBA(0, 0, 0.9, 0.4);
308        ctx.fill();        
309        
310        //~ auto color = RGB(0.9, 0.9, 0.9);
311        //~ ctx.setSourceRGB(color);
312
313        //~ ctx.translate(100, 100);
314
315        //~ ctx.rectangle(0, 0, 200, 200);
316        //~ ctx.strokePreserve();
317        //~ ctx.clip();
318
319        //~ ctx.rectangle(0, 50, 100, 100);
320        //~ ctx.fill();
321
322
323        //~ ctx.setSourceRGB(color);
324        //~ roundedRectangle(ctx, 50, 50, 250, 250, 10, 10);
325        //~ ctx.fillPreserve();
326
327        //~ color = RGB(0.9, 0.9, 0.9);
328        //~ ctx.setSourceRGB(color);
329        //~ ctx.stroke();
330    }
331}