/*
 * w_gdi3d.c : pseudo-3D graphics display routines (GDI version)
 *
 * Copyright (c) Yukihiko Aoki 1999
 * NetHack may be freely redistributed.  See license for details.
 *
 */

#include "hack.h"

#ifdef NH2K_EXTENDS

#include "win32api.h"
#include "w_main.h"
#include "w_dibtile.h"
#include "effect.h"

/*
 * for storing 3D tile related data
 */
typedef struct tagGDI3D{
    int        disp_mode;                   /* display mode */
    BOOL       view_flg;                    /* */
    POINT      view_point;                  /**/
    RECT       changed_rect;
    SIZE       block_size;
    POINT      cursor;
    POINT      start;
    short      cols;
    short      rows;
    POINT      clip;
    HDRAWDIB   hdd;                         /* DrawDib(Video for Windows) handle */
    TILELIST   *glyph_tile;                 /* compressed bitmap list */
    TILELIST   *option_tile;                /* option bitmaps(cursor only) */
    TILELIST   *effect_tile;                /* animations */
    OFFSCREEN  *buffer;                     /* DIB offscreen buffer for map */
    OFFSCREEN  *glyph_buf;                  /* DIB offscreen buffer for single tile */
    EFFECTITEM effect_item[EFFECT_MAX];     /* effect informations */
    BYTE       draw_flg[ROWNO+1][COLNO*2+2];/* redraw flag */
    short      base[ROWNO][COLNO];          /* floor glyph buffer */
    short      fore[ROWNO][COLNO];          /* foreground glyph buffer */
    short      back[ROWNO][COLNO];          /* background glyph buffer */
}GDI3D;

/*
 * static variables
 */
static GDI3D *canvas = NULL;                /* this variable should be a parameter */

/*
 * local functions
 */
static void NDECL(GDI3D_uninit);
static void NDECL(GDI3D_clear);
static void NDECL(GDI3D_updateGlyph);
static void FDECL(GDI3D_invalidate, (int,int));
static void FDECL(GDI3D_printGlyph, (int,int,int,int));
static void FDECL(GDI3D_setCursor, (POINT));
static void FDECL(GDI3D_setDispMode, (int,int,int));
static void FDECL(GDI3D_draw, (HWND,HDC,BOOL));
static void FDECL(GDI3D_getRect, (RECT*));
static void FDECL(GDI3D_putGlyph, (HDC,RECT*,int));
static void FDECL(GDI3D_setViewPoint, (int,int,int));
static void FDECL(GDI3D_dispEffect, (HWND,HDC,int,int,int,int));
static void FDECL(GDI3D_clip, (int,int));
static HPALETTE NDECL(GDI3D_getPalette);

/*
 * position macro
 */
#define TOP     (0)
#define BOTTOM  (canvas->block_size.cy)
#define LEFT    (0)
#define CENTER  (canvas->block_size.cx)
#define RIGHT   (canvas->block_size.cx * 2)

/***************************************************************************************/
/* initialize
/***************************************************************************************/
BOOL GDI3D_init(WINCONTROL *ctl, void (*callbackProc)(int,int))
{
    RECT rcValid;

    /* allocate memory */
    canvas = NEWMEMORY(sizeof(GDI3D));
    if(!canvas) {
        return FALSE;
    }

    /* video for windows handle opening */
    canvas->hdd = DrawDibOpen();
    str2rect(ctl->valid_rect, &rcValid);
    str2effects(ctl->animation, canvas->effect_item);

    /* load bitmaps */
    canvas->glyph_tile = Tile_load(
        NULL, ctl->glyph, ctl->cx, ctl->cy, &rcValid, callbackProc);
    canvas->option_tile = Tile_load(
        NULL, ctl->option, ctl->cx, ctl->cy, &rcValid, NULL);
    canvas->effect_tile = Tile_load(
        NULL, ctl->effect, ctl->cx, ctl->cy, &rcValid, NULL);
    if(!canvas->glyph_tile) {
        GDI3D_uninit();
        return FALSE;
    }

    /* create offscreen buffer */
    canvas->block_size.cx = ctl->cx / 3;
    canvas->block_size.cy = ctl->cy / 2;
    canvas->buffer = Offscreen_create(
        (canvas->block_size.cx * 2) * COLNO + canvas->block_size.cx * ROWNO,
        canvas->block_size.cy * (ROWNO + 1), 
        canvas->glyph_tile->hpal);
    if(!canvas->buffer) {
        GDI3D_uninit();
        return FALSE;
    }

    /* create sub offscreen buffer */
    canvas->glyph_buf = Offscreen_create(
        ctl->cx, ctl->cy, canvas->glyph_tile->hpal);
    if(!canvas->glyph_buf) {
        GDI3D_uninit();
        return FALSE;
    }

    /* set initial values */
    canvas->cursor.x = -1;
    canvas->cursor.y = -1;
    canvas->view_point.x = -1;
    canvas->view_point.y = -1;

    /* clear offscreen buffer */
    GDI3D_clear();

    return TRUE;
}

/***************************************************************************************/
/* uninitialize
/***************************************************************************************/
void GDI3D_uninit(void)
{
    if(canvas) {
        if(canvas->glyph_tile) {
            Tile_free(canvas->glyph_tile);
        }
        if(canvas->option_tile) {
            Tile_free(canvas->option_tile);
        }
        if(canvas->effect_tile) {
            Tile_free(canvas->effect_tile);
        }
        if(canvas->buffer) {
            Offscreen_free(canvas->buffer);
        }
        if(canvas->glyph_buf) {
            Offscreen_free(canvas->glyph_buf);
        }
        if(canvas->hdd) {
            DrawDibClose(canvas->hdd);
        }
        DELMEMORY(canvas);
        canvas = NULL;
    }
}

/***************************************************************************************/
/* set function pointers
/***************************************************************************************/
void GDI3D_func(DISPPROC *procs)
{
    procs->uninit       = GDI3D_uninit;
    procs->clear        = GDI3D_clear;
    procs->printGlyph   = GDI3D_printGlyph;
    procs->updateGlyph  = GDI3D_updateGlyph;
    procs->setCursor    = GDI3D_setCursor;
    procs->setDispMode  = GDI3D_setDispMode;
    procs->draw         = GDI3D_draw;
    procs->getRect      = GDI3D_getRect;
    procs->putGlyph     = GDI3D_putGlyph;
    procs->getPalette   = GDI3D_getPalette;
    procs->setViewPoint = GDI3D_setViewPoint;
    procs->dispEffect   = GDI3D_dispEffect;
    procs->clip         = GDI3D_clip;
}

/*-------------------------------------------------------------------------------------
 * set redraw flag on
 *-------------------------------------------------------------------------------------*/
static void _invalidate(int row, int col)
{
    if(canvas && row >=0 && col >= 0) {
        /* set redraw flags */
        canvas->draw_flg[row][col * 2]         = FLAG_ON;
        canvas->draw_flg[row][col * 2 + 1]     = FLAG_ON;
        canvas->draw_flg[row][col * 2 + 2]     = FLAG_ON;
        canvas->draw_flg[row + 1][col * 2 + 1] = FLAG_ON;
        canvas->draw_flg[row + 1][col * 2 + 2] = FLAG_ON;
        canvas->draw_flg[row + 1][col * 2 + 3] = FLAG_ON;

        canvas->changed_rect.left   = min(col * 2, canvas->changed_rect.left);
        canvas->changed_rect.top    = min(row, canvas->changed_rect.top);
        canvas->changed_rect.right  = max(col * 2 + 3, canvas->changed_rect.right);
        canvas->changed_rect.bottom = max(row + 1, canvas->changed_rect.bottom);
    }
}

/*-------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void GDI3D_clip(int x, int y)
{
    if(canvas) {
        canvas->clip.x = x;
        canvas->clip.y = y;
    }
}

/*-------------------------------------------------------------------------------------
 * clear glyphs and offscreen buffer
 *-------------------------------------------------------------------------------------*/
static void GDI3D_clear(void)
{
    int y, x;

    if(canvas) {
        for(y = 0; y < ROWNO; y++) {
            for(x = 0; x < COLNO; x++) {
                canvas->fore[y][x] = INVALID_GLYPH;
                canvas->back[y][x] = INVALID_GLYPH;
                canvas->base[y][x] = INVALID_GLYPH;
            }
        }
        Offscreen_clear(canvas->buffer);
    }
}

/*-------------------------------------------------------------------------------------
 * set glyph to destinated position
 *-------------------------------------------------------------------------------------*/
static void GDI3D_printGlyph(int col, int row, int back, int fore)
{
    short floor, prev;

    if(canvas) {
        /* set new glyph */
        canvas->fore[row][col] =
            (fore == cmap_to_glyph(S_stone)) ? INVALID_GLYPH : Glyph_toTile(fore);

        Glyph_separateBack(back, &floor, &prev);
        canvas->base[row][col] = floor;
        canvas->back[row][col] = prev;

        /* clear offscreen */
        Offscreen_blackness(
            canvas->buffer,
            (col * (canvas->block_size.cx * 2)) + (canvas->block_size.cx * (ROWNO - row)),
            row * canvas->block_size.cy,
            canvas->block_size.cx * 3,
            canvas->block_size.cy * 2);

        _invalidate(row,col);
    }
}

/*-------------------------------------------------------------------------------------
 * Check whether need background mesh
 *-------------------------------------------------------------------------------------*/
static BOOL _needMesh(int row, int col, int posx, int posy)
{
    BOOL need = FALSE;

    if(posx == LEFT && posy == TOP) {
        need = (row > 0 && col > 0 && (canvas->fore[row - 1][col - 1] != INVALID_GLYPH));
    }else if(posy == TOP && (posx == CENTER || posx == RIGHT)) {
        need = (row > 0 && (canvas->fore[row - 1][col] != INVALID_GLYPH));
    }

    return need;
}

/*-------------------------------------------------------------------------------------
 * put background glyph to destinate position
 *-------------------------------------------------------------------------------------*/
static void _putBk(int row, int col, int ptx, int pty, int posx, int posy)
{
    int idx;

    if(row >= 0 && col >= 0 && row < ROWNO && col < COLNO) {
        idx = canvas->base[row][col];

        /* draw floor */
        if(idx != INVALID_GLYPH) {
            Offscreen_blt(canvas->buffer,
                ptx, pty, canvas->block_size.cx, canvas->block_size.cy,
                &canvas->glyph_tile->tiles[idx], posx, posy, BLTMODE_MASK);
        }
    }
}

/*-------------------------------------------------------------------------------------
 * put glyph to destinate position
 *-------------------------------------------------------------------------------------*/
static void _putAt(int row, int col, int ptx, int pty, int posx, int posy)
{
    int fgidx, bgidx;

    if(row >= 0 && col >= 0 && row < ROWNO && col < COLNO) {
        fgidx = canvas->fore[row][col];
        bgidx = canvas->back[row][col];

        /* draw background */
        if(bgidx != INVALID_GLYPH) {
            Offscreen_blt(canvas->buffer,
                ptx, pty, canvas->block_size.cx, canvas->block_size.cy,
                &canvas->glyph_tile->tiles[bgidx], posx, posy,
                _needMesh(row,col,posx,posy) ? BLTMODE_MESH : BLTMODE_MASK);
        }

        /* draw cursor */
        if(col == canvas->cursor.x && row == canvas->cursor.y) {
            Offscreen_blt(canvas->buffer,
                ptx, pty, canvas->block_size.cx, canvas->block_size.cy,
                &canvas->option_tile->tiles[0], posx, posy, BLTMODE_MASK);
        }

        /* draw foreground */
        if(fgidx != INVALID_GLYPH) {
            Offscreen_blt(canvas->buffer,
                ptx, pty, canvas->block_size.cx, canvas->block_size.cy,
                &canvas->glyph_tile->tiles[fgidx], posx, posy, BLTMODE_MASK);
        }
    }
}

/*-------------------------------------------------------------------------------------
 * update entire offscreen buffer
 *-------------------------------------------------------------------------------------*/
static void GDI3D_updateGlyph(void)
{
    int x,y;
    int ptx, pty;

    if(!canvas) {
        return;
    }

    for(y = canvas->changed_rect.top; y <= canvas->changed_rect.bottom; y++) {
        for(x = canvas->changed_rect.left; x <= canvas->changed_rect.right; x++) {
            ptx = ((ROWNO - y) * canvas->block_size.cx) + (x * canvas->block_size.cx);
            pty = y * canvas->block_size.cy;
            if(canvas->draw_flg[y][x] == FLAG_OFF) {
                continue;
            }
            if((x % 2) == 0) {
                _putBk(y - 1, x / 2 - 1, ptx, pty, CENTER, BOTTOM);
                _putBk(y,     x / 2 - 1, ptx, pty, RIGHT,  TOP);
                _putBk(y,     x / 2,     ptx, pty, LEFT,   TOP);
                _putAt(y - 1, x / 2 - 1, ptx, pty, CENTER, BOTTOM);
                _putAt(y,     x / 2 - 1, ptx, pty, RIGHT,  TOP);
                _putAt(y,     x / 2,     ptx, pty, LEFT,   TOP);
            }else {
                _putBk(y - 1, x / 2 - 1, ptx, pty, RIGHT,  BOTTOM);
                _putBk(y - 1, x / 2,     ptx, pty, LEFT,   BOTTOM);
                _putBk(y,     x / 2,     ptx, pty, CENTER, TOP);
                _putAt(y - 1, x / 2 - 1, ptx, pty, RIGHT,  BOTTOM);
                _putAt(y - 1, x / 2,     ptx, pty, LEFT,   BOTTOM);
                _putAt(y,     x / 2,     ptx, pty, CENTER, TOP);
            }
            canvas->draw_flg[y][x] = FLAG_OFF;
        }
    }
    canvas->changed_rect.left   = (COLNO * 2 + 2);
    canvas->changed_rect.top    = (ROWNO + 1);
    canvas->changed_rect.right  = 0;
    canvas->changed_rect.bottom = 0;
}

/*-------------------------------------------------------------------------------------
 * set cursor position
 *-------------------------------------------------------------------------------------*/
static void GDI3D_setCursor(POINT cursor)
{
    if(canvas && (canvas->cursor.x != cursor.x || canvas->cursor.y != cursor.y)) {

        /* invalidate current cursor pposition */
        _invalidate(canvas->cursor.y, canvas->cursor.x);

        /* clear offscreen */
        if(canvas->cursor.x >= 0 && canvas->cursor.y >= 0) {
            Offscreen_blackness(
                canvas->buffer,
                (canvas->cursor.x * (canvas->block_size.cx * 2))
                    + (canvas->block_size.cx * (ROWNO - canvas->cursor.y)),
                canvas->cursor.y * canvas->block_size.cy,
                canvas->block_size.cx * 3,
                canvas->block_size.cy * 2);
        }

        /* invalidate new cursor position */
        _invalidate(cursor.y, cursor.x);
        canvas->cursor = cursor;
    }
}

/*-------------------------------------------------------------------------------------
 * set display mode
 *-------------------------------------------------------------------------------------*/
static void GDI3D_setDispMode(int mode, int width, int height)
{
    if(canvas) {
        canvas->disp_mode = mode;
    }
}

/*-------------------------------------------------------------------------------------
 * print offscreen buffer to window surface
 *-------------------------------------------------------------------------------------*/
static void GDI3D_draw(HWND hwnd, HDC hdc, BOOL redraw_only)
{
    HDC      dcMem = NULL;
    HBITMAP  oldBmp;
    HPALETTE oldPal;
    RECT     rc, *lprc;
    int      startx, starty;
    int      width, height;

    if(!canvas) {
        return;
    }

    /* get window rectangle */
    lprc = &rc;
    GetClientRect(hwnd, lprc);
    oldPal = SelectPalette(hdc, canvas->glyph_tile->hpal, FALSE);

    if(canvas->disp_mode == D_ENTIRE) {
        startx = 0;
        starty = 0;
        width = canvas->buffer->info->biWidth;
        height = canvas->buffer->info->biHeight;

    } else if(canvas->view_flg) {

        width  = (rc.right - rc.left);
        height = (rc.bottom - rc.top);
        startx = canvas->buffer->info->biWidth * canvas->view_point.x / 100 - width / 2;
        startx = (startx > (canvas->buffer->info->biWidth - width))
            ? (canvas->buffer->info->biWidth - width) : startx;
        startx = (startx < 0) ? 0 : startx;
        starty = canvas->buffer->info->biHeight * canvas->view_point.y / 100 - height / 2;
        starty = (starty > (canvas->buffer->info->biHeight - height))
            ? (canvas->buffer->info->biHeight - height) : starty;
        starty = (starty < 0) ? 0 : starty;

    } else {
        /* set horisontal start position */
        startx = (canvas->clip.x * canvas->block_size.cx * 2
            + (ROWNO - canvas->clip.y) * canvas->block_size.cx) - RCWIDTH(lprc) / 2;
        startx = (startx > (canvas->buffer->info->biWidth - RCWIDTH(lprc)))
            ? (canvas->buffer->info->biWidth - RCWIDTH(lprc)) : startx;
        startx = (startx < 0) ? 0 : startx;
        /* set vertival start position */
        starty = (canvas->clip.y * canvas->block_size.cy) - RCHEIGHT(lprc) / 2;
        starty = (starty > (canvas->buffer->info->biHeight - RCHEIGHT(lprc)))
            ? (canvas->buffer->info->biHeight - RCHEIGHT(lprc)) : starty;
        starty = (starty < 0) ? 0 : starty;
    }
    canvas->start.x = startx;
    canvas->start.y = starty;

    /* now drawing offscreen bitmap to surface */
    if(canvas->disp_mode == D_DEFAULT) {
        /* blt same size as bitmap, faster */
        dcMem = CreateCompatibleDC(hdc);
        oldBmp = SelectObject(dcMem, canvas->buffer->hbmp);
        BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
            dcMem, startx, starty, SRCCOPY);
        SelectObject(dcMem, oldBmp);
        DeleteDC(dcMem);

    } else if(!canvas->hdd) {
        /* if can't use DrawDib routine, use StretchBlt, but it will very slow */
        dcMem = CreateCompatibleDC(hdc);
        oldBmp = SelectObject(dcMem, canvas->buffer->hbmp);
        StretchBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
            dcMem, startx, starty, width, height, SRCCOPY);
        SelectObject(dcMem, oldBmp);
        DeleteDC(dcMem);

    } else {
        /* stretch blt by using DrawDib */
        DrawDibDraw(canvas->hdd, hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
            canvas->buffer->info, canvas->buffer->bits, startx, starty, width, height, 0);
    }
    SelectPalette(hdc, oldPal, FALSE);
}

/*-------------------------------------------------------------------------------------
 * calculate rectangle size best match for current display mode
 *-------------------------------------------------------------------------------------*/
static void GDI3D_getRect(RECT *rc)
{
    int width;
    int height;

    /* except full screen mode */
    if(canvas && canvas->disp_mode != D_ENTIRE) {

        canvas->cols = min(RCWIDTH(rc) / (canvas->block_size.cx * 2), COLNO);
        canvas->rows = min(RCHEIGHT(rc) / canvas->block_size.cy, ROWNO);

        width  = (canvas->block_size.cx * 2) * canvas->cols;
        if(width < RCWIDTH(rc)) {
            rc->left += (RCWIDTH(rc) - width) / 2;
            rc->right = rc->left + width;
        }

        height = canvas->block_size.cy * canvas->rows;
        if(height < RCHEIGHT(rc)) {
            rc->top += (RCHEIGHT(rc) - height) / 2;
            rc->bottom = rc->top + height;
        }
    }
}

/*-------------------------------------------------------------------------------------
 * print single glyph to destineted rectangle
 *-------------------------------------------------------------------------------------*/
static void GDI3D_putGlyph(HDC hdc, RECT *rc, int glyph)
{
    int      cx, cy;
    HDC      dcmem;
    HBITMAP  oldbmp;
    RECT     rcDraw;
    TILEDATA *data;

    if(canvas && canvas->glyph_buf) {

        data = &canvas->glyph_tile->tiles[Glyph_toTile(glyph)];
        cx = canvas->block_size.cx;
        cy = canvas->block_size.cy;

        /* draw glyph to offscreen buffer */
        Offscreen_clear(canvas->glyph_buf);
        Offscreen_blt(canvas->glyph_buf, 
            0, 0, canvas->block_size.cx * 3, canvas->block_size.cy * 2,
            data, 0, 0, BLTMODE_MASK);

        rcDraw.left    = 0;
        rcDraw.top     = 0;
        rcDraw.right   = canvas->glyph_buf->info->biWidth;
        rcDraw.bottom  = canvas->glyph_buf->info->biHeight;
        if(data->size == 0) {
            CopyRect(&rcDraw, &canvas->glyph_tile->defrc);
        }

        if(!canvas->hdd) {
            /* if can't use DrawDib routine, use StretchBlt, but it will very slow */
            dcmem = CreateCompatibleDC(hdc);
            oldbmp = SelectObject(dcmem, canvas->glyph_buf->hbmp);
            StretchBlt(hdc, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top,
                dcmem, 8, 16, 32, 32, SRCCOPY);
            SelectObject(dcmem, oldbmp);
            DeleteDC(dcmem);

        } else {
            /* stretch blt by using DrawDib */
            DrawDibDraw(canvas->hdd, hdc,
                rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top,
                canvas->glyph_buf->info, canvas->glyph_buf->bits,
                rcDraw.left, rcDraw.top, rcDraw.right - rcDraw.left, rcDraw.bottom - rcDraw.top, 0);
        }
    }
}

/*-------------------------------------------------------------------------------------
 * 
 *-------------------------------------------------------------------------------------*/
static void GDI3D_setViewPoint(int flag, int x, int y)
{
    if(flag == VIEWPOINT_SET) {
        canvas->view_flg = TRUE;
        canvas->view_point.x = x;
        canvas->view_point.y = y;
    }else {
        canvas->view_flg = FALSE;
    }
}

#ifdef DISPLAY_EFFECT
/*-------------------------------------------------------------------------------------
 * Special effects
 *-------------------------------------------------------------------------------------*/
static void GDI3D_dispEffect(HWND hwnd, HDC hdc, int col, int row, int type, int delay)
{
    int i, idx;
    COLORREF c;
    HDC dcMem;
    HBITMAP oldBmp;
    HPALETTE oldPal;
    int x, y, dx, dy;
    
    if(!canvas) {
        return;
    }

    x = col * canvas->block_size.cx * 2 + (ROWNO - row) * canvas->block_size.cx;
    y = row * canvas->block_size.cy;
    dx = x - canvas->start.x;
    dy = y - canvas->start.y;

    idx = canvas->effect_item[type].start;
    oldPal = SelectPalette(hdc, canvas->glyph_tile->hpal, FALSE);
    for(i = idx; i < (idx + canvas->effect_item[type].count); i++) {
        Offscreen_copy(canvas->glyph_buf,
            0, 0, canvas->effect_tile->width,canvas->effect_tile->height,
            canvas->buffer,
            x, y, canvas->effect_tile->width,canvas->effect_tile->height);
        Offscreen_blt(canvas->glyph_buf,
            0, 0, canvas->effect_tile->width,canvas->effect_tile->height,
            &canvas->effect_tile->tiles[i], 0, 0, BLTMODE_MASK);
        dcMem = CreateCompatibleDC(hdc);
        oldBmp = SelectObject(dcMem, canvas->glyph_buf->hbmp);
        BitBlt(hdc, dx, dy, canvas->effect_tile->width, canvas->effect_tile->height,
            dcMem, 0, 0, SRCCOPY);
        SelectObject(dcMem, oldBmp);
        DeleteDC(dcMem);
        Sleep(delay);
/*
        DrawDibDraw(
            canvas->hdd,
            hdc, dx, dy, canvas->effect_tile->width, canvas->effect_tile->height,
            canvas->glyph_buf->info, canvas->glyph_buf->bits,
            0, 0, canvas->effect_tile->width, canvas->effect_tile->height, 0);
*/
    }
    SelectPalette(hdc, oldPal, FALSE);

    /* Restore window */
    GDI3D_draw(hwnd, hdc, FALSE);
}
#endif /* DISPLAY_EFFECT */

/*-------------------------------------------------------------------------------------
 * return palette currently using
 *-------------------------------------------------------------------------------------*/
static HPALETTE GDI3D_getPalette(void)
{
    if(canvas) {
        return canvas->glyph_tile->hpal;
    }

    return NULL;
}

static HBITMAP GDI3D_getBitmap(void)
{
    if(canvas) {
        return (canvas->buffer->hbmp);
    }
    
    return NULL;
}

#endif /* NH2K_EXTENDS */
