chiark / gitweb /
New front end functions to save and restore a region of the puzzle
authorSimon Tatham <anakin@pobox.com>
Wed, 22 Jun 2005 08:30:31 +0000 (08:30 +0000)
committerSimon Tatham <anakin@pobox.com>
Wed, 22 Jun 2005 08:30:31 +0000 (08:30 +0000)
bitmap. Can be used to implement sprite-like animations: for
example, useful for games that wish to implement a user interface
which involves dragging an object around the playing area.

[originally from svn r5987]

gtk.c
osx.m
puzzles.h
windows.c

diff --git a/gtk.c b/gtk.c
index 5f016ad6082605382f4dee0fb380f4d2c2503c03..e3bffa5f4b875be8392222304472e66faed41a42 100644 (file)
--- a/gtk.c
+++ b/gtk.c
@@ -334,6 +334,57 @@ void draw_polygon(frontend *fe, int *coords, int npoints,
     sfree(points);
 }
 
+struct blitter {
+    GdkPixmap *pixmap;
+    int w, h, x, y;
+};
+
+blitter *blitter_new(int w, int h)
+{
+    /*
+     * We can't create the pixmap right now, because fe->window
+     * might not yet exist. So we just cache w and h and create it
+     * during the firs call to blitter_save.
+     */
+    blitter *bl = snew(blitter);
+    bl->pixmap = NULL;
+    bl->w = w;
+    bl->h = h;
+    return bl;
+}
+
+void blitter_free(blitter *bl)
+{
+    if (bl->pixmap)
+        gdk_pixmap_unref(bl->pixmap);
+    sfree(bl);
+}
+
+void blitter_save(frontend *fe, blitter *bl, int x, int y)
+{
+    if (!bl->pixmap)
+        bl->pixmap = gdk_pixmap_new(fe->area->window, bl->w, bl->h, -1);
+    bl->x = x;
+    bl->y = y;
+    gdk_draw_pixmap(bl->pixmap,
+                    fe->area->style->fg_gc[GTK_WIDGET_STATE(fe->area)],
+                    fe->pixmap,
+                    x, y, 0, 0, bl->w, bl->h);
+}
+
+void blitter_load(frontend *fe, blitter *bl, int x, int y)
+{
+    assert(bl->pixmap);
+    if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) {
+        x = bl->x;
+        y = bl->y;
+    }
+    gdk_draw_pixmap(fe->pixmap,
+                    fe->area->style->fg_gc[GTK_WIDGET_STATE(fe->area)],
+                    bl->pixmap,
+                    0, 0, x, y, bl->w, bl->h);
+}
+
 void draw_update(frontend *fe, int x, int y, int w, int h)
 {
     if (fe->bbox_l > x  ) fe->bbox_l = x  ;
diff --git a/osx.m b/osx.m
index 7b6789d5a94c6a79bbc7b7913461ba9fac175e31..74bd1b28b6d0d25bb9c62f686e74aaba0331961c 100644 (file)
--- a/osx.m
+++ b/osx.m
@@ -1232,6 +1232,48 @@ void draw_text(frontend *fe, int x, int y, int fonttype, int fontsize,
 
     [string drawAtPoint:point withAttributes:attr];
 }
+struct blitter {
+    int w, h;
+    int x, y;
+    NSImage *img;
+};
+blitter *blitter_new(int w, int h)
+{
+    blitter *bl = snew(blitter);
+    bl->x = bl->y = -1;
+    bl->w = w;
+    bl->h = h;
+    bl->img = [[NSImage alloc] initWithSize:NSMakeSize(w, h)];
+    [bl->img setFlipped:YES];
+    return bl;
+}
+void blitter_free(blitter *bl)
+{
+    [bl->img release];
+    sfree(bl);
+}
+void blitter_save(frontend *fe, blitter *bl, int x, int y)
+{
+    [fe->image unlockFocus];
+    [bl->img lockFocus];
+    [fe->image drawInRect:NSMakeRect(0, 0, bl->w, bl->h)
+       fromRect:NSMakeRect(x, y, bl->w, bl->h)
+       operation:NSCompositeCopy fraction:1.0];
+    [bl->img unlockFocus];
+    [fe->image lockFocus];
+    bl->x = x;
+    bl->y = y;
+}
+void blitter_load(frontend *fe, blitter *bl, int x, int y)
+{
+    if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) {
+        x = bl->x;
+        y = bl->y;
+    }
+    [bl->img drawInRect:NSMakeRect(x, y, bl->w, bl->h)
+       fromRect:NSMakeRect(0, 0, bl->w, bl->h)
+       operation:NSCompositeCopy fraction:1.0];
+}
 void draw_update(frontend *fe, int x, int y, int w, int h)
 {
     [fe->view setNeedsDisplayInRect:NSMakeRect(x,y,w,h)];
index 0dbc7f883cd3bc928f23df91598f45dc28122997..987bd9b7b62eff749811d81ef805a3f8604a16d8 100644 (file)
--- a/puzzles.h
+++ b/puzzles.h
@@ -74,6 +74,7 @@ typedef struct game_aux_info game_aux_info;
 typedef struct game_ui game_ui;
 typedef struct game_drawstate game_drawstate;
 typedef struct game game;
+typedef struct blitter blitter;
 
 #define ALIGN_VNORMAL 0x000
 #define ALIGN_VCENTRE 0x100
@@ -146,6 +147,16 @@ void activate_timer(frontend *fe);
 void status_bar(frontend *fe, char *text);
 void get_random_seed(void **randseed, int *randseedsize);
 
+blitter *blitter_new(int w, int h);
+void blitter_free(blitter *bl);
+/* save puts the portion of the current display with top-left corner
+ * (x,y) to the blitter. load puts it back again to the specified
+ * coords, or else wherever it was saved from
+ * (if x = y = BLITTER_FROMSAVED). */
+void blitter_save(frontend *fe, blitter *bl, int x, int y);
+#define BLITTER_FROMSAVED (-1)
+void blitter_load(frontend *fe, blitter *bl, int x, int y);
+
 /*
  * midend.c
  */
index b93847d427fe33216597f7cc9e72db2963d1d37e..c05dd6e7384f911270f39279364e5fca73c4255b 100644 (file)
--- a/windows.c
+++ b/windows.c
@@ -90,6 +90,12 @@ struct cfg_aux {
     int ctlid;
 };
 
+struct blitter {
+    HBITMAP bitmap;
+    frontend *fe;
+    int x, y, w, h;
+};
+
 struct frontend {
     midend_data *me;
     HWND hwnd, statusbar, cfgbox;
@@ -149,6 +155,82 @@ void status_bar(frontend *fe, char *text)
     }
 }
 
+blitter *blitter_new(int w, int h)
+{
+    blitter *bl = snew(blitter);
+
+    memset(bl, 0, sizeof(blitter));
+    bl->w = w;
+    bl->h = h;
+    bl->bitmap = 0;
+
+    return bl;
+}
+
+void blitter_free(blitter *bl)
+{
+    if (bl->bitmap) DeleteObject(bl->bitmap);
+    sfree(bl);
+}
+
+static void blitter_mkbitmap(frontend *fe, blitter *bl)
+{
+    HDC hdc = GetDC(fe->hwnd);
+    bl->bitmap = CreateCompatibleBitmap(hdc, bl->w, bl->h);
+    ReleaseDC(fe->hwnd, hdc);
+}
+
+/* BitBlt(dstDC, dstX, dstY, dstW, dstH, srcDC, srcX, srcY, dType) */
+
+void blitter_save(frontend *fe, blitter *bl, int x, int y)
+{
+    HDC hdc_win, hdc_blit;
+    HBITMAP prev_blit;
+
+    if (!bl->bitmap) blitter_mkbitmap(fe, bl);
+
+    bl->x = x; bl->y = y;
+
+    hdc_win = GetDC(fe->hwnd);
+    hdc_blit = CreateCompatibleDC(hdc_win);
+    if (!hdc_blit) fatal("hdc_blit failed: 0x%x", GetLastError());
+
+    prev_blit = SelectObject(hdc_blit, bl->bitmap);
+    if (prev_blit == NULL || prev_blit == HGDI_ERROR)
+        fatal("SelectObject for hdc_main failed: 0x%x", GetLastError());
+
+    if (!BitBlt(hdc_blit, 0, 0, bl->w, bl->h,
+                fe->hdc_bm, x, y, SRCCOPY))
+        fatal("BitBlt failed: 0x%x", GetLastError());
+
+    SelectObject(hdc_blit, prev_blit);
+    DeleteDC(hdc_blit);
+    ReleaseDC(fe->hwnd, hdc_win);
+}
+
+void blitter_load(frontend *fe, blitter *bl, int x, int y)
+{
+    HDC hdc_win, hdc_blit;
+    HBITMAP prev_blit;
+
+    assert(bl->bitmap); /* we should always have saved before loading */
+
+    if (x == BLITTER_FROMSAVED) x = bl->x;
+    if (y == BLITTER_FROMSAVED) y = bl->y;
+
+    hdc_win = GetDC(fe->hwnd);
+    hdc_blit = CreateCompatibleDC(hdc_win);
+
+    prev_blit = SelectObject(hdc_blit, bl->bitmap);
+
+    BitBlt(fe->hdc_bm, x, y, bl->w, bl->h,
+           hdc_blit, 0, 0, SRCCOPY);
+
+    SelectObject(hdc_blit, prev_blit);
+    DeleteDC(hdc_blit);
+    ReleaseDC(fe->hwnd, hdc_win);
+}
+
 void frontend_default_colour(frontend *fe, float *output)
 {
     DWORD c = GetSysColor(COLOR_MENU); /* ick */