#include "driver.h"

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <ddraw.h>
#include <math.h>

#include "osdepend.h"
#include "win32.h"
#include "resource.h"
#include "misc.h"
#include "tsv.h"
#include "ticker.h"
#include "DirectDraw.h"
#include "png.h"
#include "artwork.h"
#include "blit.h"
#include "video.h"
#include "sound.h"
#include "Joystick.h"
#include "osd_pal.h"

#ifdef SAI
#include "2xsaiwin.h"
#endif

#ifdef KAILLERA
#include "KailleraChat.h"
#endif /* KAILLERA */

/***************************************************************************
    Macros
 ***************************************************************************/

#define FLAG_NONE          0
#define FLAG_INITIALIZING  1
#define FLAG_MINIMIZED     2
#define FLAG_LOSTFORCUS    4
#define FLAG_MENUOPEN      8

#define FRAMESKIP_LEVELS  12
#define INTENSITY_LEVELS 256
#define FRAMES_TO_SKIP    20

#define MAKECOL(r, g, b)   (((r & 0xFF) >> (8 - Red.m_nSize))   << Red.m_nShift   | \
                            ((g & 0xFF) >> (8 - Green.m_nSize)) << Green.m_nShift | \
                            ((b & 0xFF) >> (8 - Blue.m_nSize))  << Blue.m_nShift)

#define MAKECOL15(r, g, b) (((r & 0xF8) << 7) | ((g & 0xF8) << 2) | ((b & 0xF8) >> 3))

#define MAKECOL32(r, g, b) (((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF))

#define GETC(col, pi)      (((col & (pi)->m_dwMask) >> (pi)->m_nShift)) << (8 - (pi)->m_nSize)

/***************************************************************************
    Internal structures and variables
 ***************************************************************************/

struct tPixelInfo
{
    int     m_nShift;
    int     m_nSize;
    DWORD   m_dwMask;
};

struct tCurrentSettings
{
    int     width;
    int     height;
    int     depth;
    int     fps;
    int     attributes;
    int     orientation;
    options_type osd_options;
};

static const int           safety = 16;


static unsigned char       color_map[INTENSITY_LEVELS];
static double              gamma;
static int                 brightness;
static int                 showfps;
static int                 showfpstemp;
static char                fpsbuf[32];
static char                vupbuf[32];
static int                 throttle;
static int                 autoframeskip;
static int                 frameskip;
static int                 frameskip_counter;
static int                 frameskipadjust;
static int                 boost = 0;
static int                 frameskip_bak;
static int                 autoframeskip_bak;
static int                 throttle_bak;
static double              speed;
static int                 warming_up;
static TICKER              prev_measure;
static TICKER              this_frame_base;
static TICKER              prev;
static int                 vups;
static int                 vfcount;
static int                 frames_displayed;
static TICKER              start_time;
static TICKER              end_time;
static double              video_fps;

static int                 snapno = 0;

static tRect               game_rect;
static RECT                rectPrimary;
static RECT                rectBack;

static BOOL                is_window;
static BOOL                disable_mmx;
static BOOL                disable_mmx2;

static int                 adjusted_width;
static int                 adjusted_height;
static int                 resized_width;
static int                 resized_height;
static int                 window_status;

static BOOL                hdouble;
static BOOL                vdouble;

static LONG                lScanLineStart;
static LONG                lScanLineMax;

/* options */
static int                 display_index;
static int                 switch_resolution;
static int                 screen_width;
static int                 screen_height;
static int                 refresh_rate;
static int                 game_depth;
static int                 screen_depth;
static BOOL                adjust_aspect;
static BOOL                double_size;
#ifdef SAI
static BOOL			double_filter;
#endif
#ifdef NFILTER
static BOOL                nfilter;
#endif
#ifdef FSSTRETCH
static BOOL			   fat_mode;
#endif
static BOOL                hscanlines;
static BOOL                vscanlines;
static int                 scanline_brightness;
static BOOL                use_back_buffer;
static BOOL                use_stretch;
static int                 stretch_scale;
static BOOL                triple_buffer;
static DWORD               flip_mode;
static BOOL                video_sync;
static BOOL                use_sleep;
static BOOL                force_system_memory;
static BOOL                emulation_mode;

/* palette / color */
static BOOL                dirtypalette;
static BOOL                dirty_background;
static PALETTEENTRY*       palette_entries;
static PALETTEENTRY*       adjusted_palette;
UINT32*                    palette_lookup;
static UINT8*              palette_is_dirty;
static UINT32              nTotalColors;
UINT32                     nColors;
int                        iTrans;
int                        iTransOpt;
static int                 iTransRate;
static int                 bytes_per_pixel;
static struct tPixelInfo   Red;
static struct tPixelInfo   Green;
static struct tPixelInfo   Blue;

/* DirectDraw */
static IDirectDraw2*       pDDraw;
static IDirectDrawSurface* pDDSFlip;
static IDirectDrawSurface* pDDSPrimary;
static IDirectDrawSurface* pDDSBack;
#ifdef SAI
static IDirectDrawSurface* pDDScale;
#endif
static IDirectDrawClipper* pDDClipper;
#ifdef SAI
static DDSURFACEDESC primary_desc;
static DDSURFACEDESC blit_desc;
static DDSURFACEDESC Sxsai_desc;
#endif

/* bitmap */
static struct mame_bitmap*  pMAMEBitmap;
static BYTE*               pBitmapOffset;
static int                 nBitmapPitch;
#ifndef SAI
static BYTE*               pSurfaceBits;
static int                 nSurfacePitch;
#endif

/* menu */
static HMENU               hMenu;
static HMENU               hPopup[4];

static bliter_func         bliter;

struct tCurrentSettings    video_settings;

const UINT8 colortable[MAX_COLORTABLE][3] =
{
	{ 0x00, 0x00, 0x00 },	// FONT_COLOR_BLANK
	{ 0xff, 0xff, 0xff },	// FONT_COLOR_NORMAL
	{ 0xff, 0xff, 0xff },	// FONT_COLOR_BLANK_INVERSE
	{ 0x00, 0x00, 0x00 },	// FONT_COLOR_NORMAL_INVERSE
	{ 0xff, 0xff, 0x00 },	// FONT_COLOR_NORMAL2
	{ 0xff, 0xee, 0x00 },	// FONT_COLOR_SPECIAL
	{ 0xff, 0xff, 0xff },	// FONT_COLOR_WHITE
	{ 0xff, 0x00, 0x00 },	// BUTTON_COLOR_RED
	{ 0xff, 0xee, 0x00 },	// BUTTON_COLOR_YELLOW
	{ 0x00, 0xff, 0x33 },	// BUTTON_COLOR_GREEN
	{ 0x00, 0xaa, 0xff },	// BUTTON_COLOR_BLUE
	{ 0xaa, 0x00, 0xff },	// BUTTON_COLOR_PURPLE
	{ 0xff, 0x00, 0xaa },	// BUTTON_COLOR_PINK
	{ 0x00, 0xff, 0xcc },	// BUTTON_COLOR_AQUA
	{ 0x00, 0x00, 0x5a },	// SYSTEM_COLOR_BACKGROUND
	{ 0xc0, 0xc0, 0xc0 },	// SYSTEM_COLOR_FRAMEMEDIUM
	{ 0xe0, 0xe0, 0xe0 },	// SYSTEM_COLOR_FRAMELIGHT
	{ 0x80, 0x80, 0x80 },	// SYSTEM_COLOR_FRAMEDARK
	{ 0x64, 0xa0, 0xe8 },	// OSDBAR_COLOR_FRAMEMEDIUM
	{ 0xa0, 0xc8, 0xf0 },	// OSDBAR_COLOR_FRAMELIGHT
	{ 0x90, 0xc0, 0xf0 },	// OSDBAR_COLOR_FRAMEDARK
	{ 0x3c, 0x78, 0xf0 },   // OSDBAR_COLOR_DEFAULTBAR
	{ 0x3c, 0x78, 0xf0 },	// CURSOR_COLOR
};

#ifdef KAILLERA
extern int kPlay;
#endif

/***************************************************************************
    Function prototypes
 ***************************************************************************/

INLINE void               MapColor(unsigned char* pRed, unsigned char* pGreen, unsigned char* pBlue);
static void               AdjustColorMap(void);

static void               SetPen(int pen, unsigned char red, unsigned char green, unsigned char blue);
static void               SetPaletteColors(void);
static void               AdjustPalette(void);

static int                AdjustVisibleRect(int min_x, int min_y, int max_x, int max_y);
static void               GetPixelInfo(DWORD dwMask, struct tPixelInfo* pPixelInfo);

static void               SelectDisplayMode(int width, int height, int depth);
static BOOL               FindDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwDepth);
static BOOL               FindBestDisplayMode(DWORD  dwWidthIn,   DWORD  dwHeightIn, DWORD dwDepth,
                                              DWORD* pdwWidthOut, DWORD* pdwHeightOut);
static void               DrawSurface(int flag);
static void               ClearSurface(IDirectDrawSurface *pddSurface);
static BOOL               LockSurface(IDirectDrawSurface *pddSurface);
INLINE BOOL               UnlockSurface(IDirectDrawSurface *pddSurface);
static BOOL               RestoreSurface(void);

static void               ReleaseDDrawObjects(void);
static void               ReleasePalettes(void);

static BOOL               WaitVBlank(void);
static void               CalcVBlank(void);

static void               OnActivateApp(HWND hWnd, BOOL fActivate, DWORD dwThreadId);
static void               OnSysCommand(HWND hWnd, UINT cmd, int x, int y);
static void               OnSize(HWND hWnd,UINT state,int cx,int cy);
static BOOL               OnSetCursor(HWND hWnd, HWND hWndCursor, UINT codeHitTest, UINT msg);

static int                video_init2(options_type *osd_options);
static void               ChangeDisplayMode(int switch_mode);
static void               set_bitmap(struct mame_bitmap *bitmap, int depth);
static void               ApplyMenuItems(void);

/***************************************************************************
    External OSD function definitions
 ***************************************************************************/

/*
    put here anything you need to do when the program is started. Return 0 if
    initialization was successful, nonzero otherwise.
*/

int win32_video_init(options_type *osd_options)
{
    /* Reset the Snapshot number */
    snapno = 0;

    video_settings.width = 0;
    memset(&video_settings, 0, sizeof(struct tCurrentSettings));
    memcpy(&video_settings.osd_options, osd_options, sizeof(options_type));

    gamma              = max(0, osd_options->gamma_correct);
    brightness         = max(0, osd_options->brightness);
    showfps            = FALSE;
    showfpstemp        = 0;
    throttle           = 1;
    autoframeskip      = osd_options->autoframeskip ? 1 : 0;
    frameskip          = osd_options->frameskip ? 1 : 0;
    frameskip          = autoframeskip ? 0 : frameskip;
    frameskip_counter  = 0;
    frameskipadjust    = 0;
    speed              = 100.0;
    vups               = 0;
    vfcount            = 0;
    warming_up         = 1;
    prev_measure       = ticker();
    this_frame_base    = prev_measure;
    prev               = prev_measure;
    frames_displayed   = 0;
    start_time         = prev_measure;
    end_time           = prev_measure;
    video_fps          = Machine->drv->frames_per_second;

    display_index      = osd_options->monitor;
    disable_mmx        = osd_options->disable_mmx;
    disable_mmx2       = osd_options->disable_mmx2;

    dirtypalette       = 0;
    dirty_background   = FALSE;
    bytes_per_pixel    = 2;

    window_status      = FLAG_INITIALIZING;

    palette_entries    = NULL;
    adjusted_palette   = NULL;
    palette_lookup     = NULL;
    palette_is_dirty   = NULL;
    nTotalColors       = 0;
    nColors            = 0;
    iTrans             = 0;
    iTransOpt          = 0;
    iTransRate         = 0;

    hMenu              = GetSystemMenu(MAME32App.m_hWnd, FALSE);
    hPopup[0]          = CreatePopupMenu();
    hPopup[1]          = CreatePopupMenu();
    hPopup[2]          = CreatePopupMenu();
    hPopup[3]          = CreatePopupMenu();

#ifdef JAPANESE
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_FULLSCREEN, "フルスクリーン\x95\x5c示(&F)\tAlt+Enter");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_ASPECT, "アスペクト比調整(&A)");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_DOUBLE, "\x83\x5cフトウェア2倍拡大(&D)");
#ifdef SAI
    AppendMenu(hMenu, MF_STRING, IDM_DOUBLEF, "2x Scale(&S)");
#endif
    AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hPopup[0], "水平スキャンライン");
    AppendMenu(hPopup[0], MF_STRING, IDM_NOHSCANLINE, "無効");
    AppendMenu(hPopup[0], MF_STRING, IDM_HSCANLINE0, "0%");
    AppendMenu(hPopup[0], MF_STRING, IDM_HSCANLINE25, "25%");
    AppendMenu(hPopup[0], MF_STRING, IDM_HSCANLINE50, "50%");
    AppendMenu(hPopup[0], MF_STRING, IDM_HSCANLINE75, "75%");
    AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hPopup[1], "垂直スキャンライン");
    AppendMenu(hPopup[1], MF_STRING, IDM_NOVSCANLINE, "無効");
    AppendMenu(hPopup[1], MF_STRING, IDM_VSCANLINE0, "0%");
    AppendMenu(hPopup[1], MF_STRING, IDM_VSCANLINE25, "25%");
    AppendMenu(hPopup[1], MF_STRING, IDM_VSCANLINE50, "50%");
    AppendMenu(hPopup[1], MF_STRING, IDM_VSCANLINE75, "75%");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hPopup[2], "ハードウェアストレッチ");
    AppendMenu(hPopup[2], MF_STRING, IDM_NOSTRETCH, "無効");
    AppendMenu(hPopup[2], MF_STRING, IDM_HWSTRETCH2X, "2倍");
    AppendMenu(hPopup[2], MF_STRING, IDM_HWSTRETCH3X, "3倍");
    AppendMenu(hPopup[2], MF_STRING, IDM_HWSTRETCH4X, "4倍");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hPopup[3], "トリプルバッファ");
    AppendMenu(hPopup[3], MF_STRING, IDM_TBUFFER_OFF, "無効");
    AppendMenu(hPopup[3], MF_STRING, IDM_TBUFFER_WAIT, "VSyncを待つ");
    AppendMenu(hPopup[3], MF_STRING, IDM_TBUFFER_NOWAIT, "VSyncを待たない");
#ifdef FSSTRETCH
    AppendMenu(hMenu, MF_STRING, IDM_FAT_MODE, "画面全体に拡大(&F)");
#endif
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_VSYNC, "VSyncを待つ(&W)");
    AppendMenu(hMenu, MF_STRING, IDM_SLEEP, "Sleepを使用(&L)");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_USE_SYSMEM, "システムメモリを使用(&M)");
    AppendMenu(hMenu, MF_STRING, IDM_DDEMULATION, "DirectDraw HELを使用(&E)");
#else
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_FULLSCREEN, "&Full Screen\tAlt+Enter");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_ASPECT, "&Adjust Aspect Ratio");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_DOUBLE, "Software &Double");
#ifdef SAI
    AppendMenu(hMenu, MF_STRING, IDM_DOUBLEF, "&2x Scale");
#endif
    AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hPopup[0], "&Horizontal Scan Lines");
    AppendMenu(hPopup[0], MF_STRING, IDM_NOHSCANLINE, "Disable");
    AppendMenu(hPopup[0], MF_STRING, IDM_HSCANLINE0, "0%");
    AppendMenu(hPopup[0], MF_STRING, IDM_HSCANLINE25, "25%");
    AppendMenu(hPopup[0], MF_STRING, IDM_HSCANLINE50, "50%");
    AppendMenu(hPopup[0], MF_STRING, IDM_HSCANLINE75, "75%");
    AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hPopup[1], "&Vertical Scan Lines");
    AppendMenu(hPopup[1], MF_STRING, IDM_NOVSCANLINE, "Disable");
    AppendMenu(hPopup[1], MF_STRING, IDM_VSCANLINE0, "0%");
    AppendMenu(hPopup[1], MF_STRING, IDM_VSCANLINE25, "25%");
    AppendMenu(hPopup[1], MF_STRING, IDM_VSCANLINE50, "50%");
    AppendMenu(hPopup[1], MF_STRING, IDM_VSCANLINE75, "75%");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hPopup[2], "Hardware &Stretch");
    AppendMenu(hPopup[2], MF_STRING, IDM_NOSTRETCH, "Disable");
    AppendMenu(hPopup[2], MF_STRING, IDM_HWSTRETCH2X, "x2");
    AppendMenu(hPopup[2], MF_STRING, IDM_HWSTRETCH3X, "x3");
    AppendMenu(hPopup[2], MF_STRING, IDM_HWSTRETCH4X, "x4");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hPopup[3], "&Triple Buffer");
    AppendMenu(hPopup[3], MF_STRING, IDM_TBUFFER_OFF, "Disable");
    AppendMenu(hPopup[3], MF_STRING, IDM_TBUFFER_WAIT, "Wait VSync");
    AppendMenu(hPopup[3], MF_STRING, IDM_TBUFFER_NOWAIT, "No Wait");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_VSYNC, "&Wait VSync");
    AppendMenu(hMenu, MF_STRING, IDM_SLEEP, "Use S&leep");
    AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hMenu, MF_STRING, IDM_USE_SYSMEM, "Use System &Memory");
    AppendMenu(hMenu, MF_STRING, IDM_DDEMULATION, "Use DirectDraw H&EL");
#endif

    memset(&Red,   0, sizeof(struct tPixelInfo));
    memset(&Green, 0, sizeof(struct tPixelInfo));
    memset(&Blue,  0, sizeof(struct tPixelInfo));

    memset(fpsbuf, 0, 32);
    memset(vupbuf, 0, 32);

    AdjustColorMap();

    return video_init2(osd_options);
}


static int video_init2(options_type *osd_options)
{
    game_rect.m_Top      = 0;
    game_rect.m_Left     = 0;
    game_rect.m_Width    = 0;
    game_rect.m_Height   = 0;

    rectPrimary.left     = 0;
    rectPrimary.top      = 0;
    rectPrimary.right    = 0;
    rectPrimary.bottom   = 0;

    rectBack.left        = 0;
    rectBack.top         = 0;
    rectBack.right       = 0;
    rectBack.bottom      = 0;

    is_window            = osd_options->window_mode;
    switch_resolution    = (osd_options->switchres || is_window);
    resized_width        = 0;
    resized_height       = 0;
    screen_width         = osd_options->width;
    screen_height        = osd_options->height;
    refresh_rate         = osd_options->refreshrate;
    adjusted_width       = 0;
    adjusted_height      = 0;

    lScanLineMax         = 0;

    game_depth           = 0;
    screen_depth         = 0;

    pDDraw               = NULL;
    pDDSFlip             = NULL;
    pDDSPrimary          = NULL;
    pDDSBack             = NULL;
#ifdef SAI
    pDDScale             = NULL;
#endif
    pDDClipper           = NULL;

    bliter               = NULL;

    pMAMEBitmap          = NULL;
    pBitmapOffset        = NULL;
    nBitmapPitch         = 0;
#ifndef SAI
    pSurfaceBits         = NULL;
    nSurfacePitch        = 0;
#endif

    hdouble              = FALSE;
    vdouble              = FALSE;

    adjust_aspect        = osd_options->adjust_aspect;
#ifdef FSSTRETCH
   fat_mode           = osd_options->fat_mode;
#endif
    double_size          = osd_options->double_size;
#ifdef NFILTER
    nfilter              = osd_options->nfilter;
#endif
#ifdef SAI
    double_filter        = osd_options->double_filter;
#endif
    hscanlines           = osd_options->hscanlines;
    vscanlines           = osd_options->vscanlines;
    scanline_brightness  = osd_options->sl_brightness;
    use_stretch          = osd_options->hw_stretch;
    stretch_scale        = osd_options->scale;
    force_system_memory  = osd_options->use_sysmem;
    emulation_mode       = osd_options->use_hel;
    use_back_buffer      = TRUE;
    iTransOpt            = osd_options->transparency;
    iTransRate           = osd_options->transparency_rate;

#ifdef NFILTER
    if(nfilter)
    {
        use_stretch    = TRUE;
        stretch_scale  = 4;
    }
#endif
    if (is_window)
    {
        screen_depth     = 0;
        triple_buffer    = FALSE;
        video_sync       = osd_options->wait_vsync;
        use_sleep        = osd_options->use_sleep;
    }
    else
    {
        screen_depth     = osd_options->screen_depth;
        triple_buffer    = osd_options->use_triplebuf;
        video_sync       = FALSE;
        use_sleep        = FALSE;
    }

    if (hscanlines)
        vscanlines = FALSE;

    if (triple_buffer)
    {
        if (osd_options->tbvsync)
            flip_mode = DDFLIP_WAIT;
        else
            flip_mode = DDFLIP_NOVSYNC;
    }

    if (!use_stretch)
        stretch_scale = 1;

    return 0;
}


/*
    put here cleanup routines to be executed when the program is terminated.
*/
void win32_video_exit(void)
{
    int i;

    osd_close_display();

    if (hMenu)
    {
        GetSystemMenu(MAME32App.m_hWnd, TRUE);
        hMenu = NULL;
    }
    for (i = 0; i < 4; i++)
    {
        if (hPopup[i])
        {
            DestroyMenu(hPopup[i]);
            hPopup[i] = NULL;
        }
    }

#ifdef BUILD_CONSOLE
   if (frames_displayed > FRAMES_TO_SKIP)
       fprintf(stdout, "Average FPS: %f\n",
                       (double)TICKS_PER_SEC / (end_time - start_time) * (frames_displayed - FRAMES_TO_SKIP));
#else
   if (frames_displayed > FRAMES_TO_SKIP)
       logerror("Average FPS: %f\n",
                (double)TICKS_PER_SEC / (end_time - start_time) * (frames_displayed - FRAMES_TO_SKIP));
#endif
}

int osd_create_display(int width, int height, int depth, int fps, int attributes, int orientation)
{
    DDSURFACEDESC  ddSurfaceDesc;
    DDPIXELFORMAT  ddPixelFormat;
    HRESULT        hResult;

    if (video_settings.width == 0)
    {
        video_settings.depth       = depth;
        video_settings.fps         = fps;
        video_settings.attributes  = attributes;
        video_settings.orientation = orientation;
    }

    game_depth = depth;
    if (depth == 15) depth = 16;

    if (emulation_mode)
        DirectDraw_CreateEmulationMode();
    else
        DirectDraw_CreateByIndex(display_index);

    pDDraw = dd;
    if (pDDraw == NULL)
    {
#ifdef JAPANESE
        ErrorMsg("DirectDrawオブジェクトが作成されていません");
#else
        ErrorMsg("No DirectDraw object has been created");
#endif
        return 0;
    }

    if (AdjustVisibleRect(0, 0, width - 1, height - 1))
        goto error;

    ShowWindow(MAME32App.m_hWnd, SW_HIDE);
    SetWindowText(MAME32App.m_hWnd, GetDescriptionByName(Machine->gamedrv->name));

    if (is_window)
    {
        tRect WindowRect;

        SetWindowLong(MAME32App.m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_BORDER);
#ifdef NFILTER
        WindowRect.m_Width  = screen_width + (2 * GetSystemMetrics(SM_CXFIXEDFRAME));
        WindowRect.m_Height = screen_height + (2 * GetSystemMetrics(SM_CYFIXEDFRAME)) + GetSystemMetrics(SM_CYCAPTION);
#else
        WindowRect.m_Width  = screen_width + (2 * GetSystemMetrics(SM_CXFRAME));
        WindowRect.m_Height = screen_height + (2 * GetSystemMetrics(SM_CYFRAME)) + GetSystemMetrics(SM_CYCAPTION);
#endif
        WindowRect.m_Left = (GetSystemMetrics(SM_CXFULLSCREEN) - WindowRect.m_Width)  / 2;
        WindowRect.m_Top  = ((GetSystemMetrics(SM_CYFULLSCREEN) + GetSystemMetrics(SM_CYCAPTION)) - WindowRect.m_Height) / 2;

        SetWindowPos(MAME32App.m_hWnd,
                     HWND_NOTOPMOST,
                     WindowRect.m_Left,
                     WindowRect.m_Top,
                     WindowRect.m_Width,
                     WindowRect.m_Height,
                     SWP_NOZORDER);
    }
    else
    {
        SetWindowLong(MAME32App.m_hWnd, GWL_STYLE, WS_POPUP);

        SetWindowPos(MAME32App.m_hWnd,
                     HWND_TOPMOST,
                     0, 0,
                     GetSystemMetrics(SM_CXSCREEN) / 4,
                     GetSystemMetrics(SM_CYSCREEN) / 4,
                     0);
    }

    hResult = IDirectDraw2_SetCooperativeLevel(pDDraw, MAME32App.m_hWnd,
                                               (is_window) ? DDSCL_NORMAL : DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
    if (FAILED(hResult))
    {
#ifdef JAPANESE
        ErrorMsg("IDirectDraw2.SetCooperativeLevel でエラーが発生しました");
#else
        ErrorMsg("IDirectDraw2.SetCooperativeLevel failed.");
#endif
        goto error;
    }

    if (is_window)
    {
        ddSurfaceDesc.dwSize = sizeof(ddSurfaceDesc);
        hResult = IDirectDraw2_GetDisplayMode(pDDraw, &ddSurfaceDesc);
        if (hResult != DD_OK)
        {
#ifdef JAPANESE
            ErrorMsg("IDirectDraw2.GetDisplayMode でエラーが発生しました");
#else
            ErrorMsg("IDirectDraw2.GetDisplayMode failed.");
#endif
            goto error;
        }

        if ((ddSurfaceDesc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) ||
            (ddSurfaceDesc.ddpfPixelFormat.dwRBitMask == 0 &&
             ddSurfaceDesc.ddpfPixelFormat.dwGBitMask == 0 &&
             ddSurfaceDesc.ddpfPixelFormat.dwBBitMask == 0))
        {
            bytes_per_pixel = 1;
        }
        else
        {
            bytes_per_pixel = ddSurfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8;
        }
    }
    else
    {
        int frame_rate;
        int tmp_depth;

        if (refresh_rate != 0)
        {
            if (screen_depth != 0)
                tmp_depth = screen_depth;
            else
                tmp_depth = depth;

try_set_display_mode1:
            hResult = IDirectDraw2_SetDisplayMode(pDDraw,
                                                  screen_width,
                                                  screen_height,
                                                  tmp_depth, refresh_rate, 0);
            if (FAILED(hResult))
            {
                if (screen_depth != 0)
                {
                    tmp_depth = depth;
                    goto try_set_display_mode1;
                }
            }
            else
                goto found;
        }

        // most monitors can't go this low
        if (fps < 50.0)
            fps *= 2.0;

        if (screen_depth != 0)
            tmp_depth = screen_depth;
        else
            tmp_depth = depth;

        frame_rate = (int)fps;

//      if (triple_buffer == FALSE)
//          frame_rate = 0; // old behavior--monitor default when not triple buffering

try_set_display_mode2:
        hResult = IDirectDraw2_SetDisplayMode(pDDraw,
                                              screen_width,
                                              screen_height,
                                              tmp_depth, frame_rate, 0);
        if (FAILED(hResult))
        {
            if (frame_rate == 0)
            {
                if (screen_depth != 0)
                {
                    tmp_depth = depth;
                    if (triple_buffer == TRUE)
                        frame_rate = (int)fps;
                    goto try_set_display_mode2;
                }
                else
                {
#ifdef JAPANESE
                    ErrorMsg("IDirectDraw2.SetDisplayModeでエラーが発生しました\n"
                             "DirectDrawは要求された画面モード %dx%d (%d bpp) をサポートしていません",
#else
                    ErrorMsg("IDirectDraw2.SetDisplayMode failed.\n"
                             "DirectDraw does not support the requested mode %dx%d (%d bpp)",
#endif
                             screen_width, screen_height, tmp_depth);
                    goto error;
                }
            }

            frame_rate = 0; // tried to get the correct rate, now try anything
            goto try_set_display_mode2;
        }

found:
        if (tmp_depth == 15) tmp_depth = 16;
        bytes_per_pixel = tmp_depth / 8;
    }

    if (triple_buffer)
    {
        /* Create the primary surface with 2 back buffers. */
#ifdef SAI
        memset(&primary_desc, 0, sizeof(primary_desc));
        primary_desc.dwSize         = sizeof(primary_desc);
        primary_desc.dwFlags        = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
        primary_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
                                       DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;
        primary_desc.dwBackBufferCount = 2;

        hResult = IDirectDraw2_CreateSurface(pDDraw, &primary_desc, &pDDSFlip, NULL);
#else
        memset(&ddSurfaceDesc, 0, sizeof(ddSurfaceDesc));
        ddSurfaceDesc.dwSize         = sizeof(ddSurfaceDesc);
        ddSurfaceDesc.dwFlags        = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
        ddSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
                                       DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;
        ddSurfaceDesc.dwBackBufferCount = 1;

        hResult = IDirectDraw2_CreateSurface(pDDraw, &ddSurfaceDesc, &pDDSFlip, NULL);
#endif
        if (FAILED(hResult))
        {
#ifdef JAPANESE
            ErrorMsg("IDirectDraw2.CreateSurfaceでエラーが発生しました");
#else
            ErrorMsg("IDirectDraw2.CreateSurface failed.");
#endif
            goto error;
        }

        /* If the surface can't be locked, clean up and use the backbuffer scheme. */
        if (LockSurface(pDDSFlip) && UnlockSurface(pDDSFlip))
        {
           DDSCAPS ddscaps;

           memset(&ddscaps, 0, sizeof(ddscaps));
           ddscaps.dwCaps = DDSCAPS_BACKBUFFER;

           hResult = IDirectDrawSurface2_GetAttachedSurface(pDDSFlip, &ddscaps, &pDDSPrimary);
           if (FAILED(hResult))
           {
#ifdef JAPANESE
               ErrorMsg("IDirectDrawSurface2.GetAttachedSurfaceでエラーが発生しました");
#else
               ErrorMsg("IDirectDrawSurface2.GetAttachedSurface failed.");
#endif
               goto error;
           }
        }
        else
        {
            IDirectDraw_Release(pDDSFlip);
            triple_buffer   = FALSE;
            use_back_buffer = TRUE;
        }
    }

    if (pDDSFlip == NULL)
    {
        /* Create the primary surface with no back buffers. */
#ifdef SAI
        memset(&primary_desc, 0, sizeof(primary_desc));
        primary_desc.dwSize         = sizeof(primary_desc);
        primary_desc.dwFlags        = DDSD_CAPS;
        primary_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

        hResult = IDirectDraw2_CreateSurface(pDDraw, &primary_desc, &pDDSPrimary, NULL);
#else
        memset(&ddSurfaceDesc, 0, sizeof(ddSurfaceDesc));
        ddSurfaceDesc.dwSize         = sizeof(ddSurfaceDesc);
        ddSurfaceDesc.dwFlags        = DDSD_CAPS;
        ddSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

        hResult = IDirectDraw2_CreateSurface(pDDraw, &ddSurfaceDesc, &pDDSPrimary, NULL);
#endif
        if (FAILED(hResult))
        {
#ifdef JAPANESE
            ErrorMsg("IDirectDraw2.CreateSurfaceでエラーが発生しました");
#else
            ErrorMsg("IDirectDraw2.CreateSurface failed.");
#endif
            goto error;
        }
    }

    if (use_back_buffer)
    {
        /* Create a separate back buffer to blit with */
#ifdef SAI
        memset(&blit_desc, 0, sizeof(blit_desc));
        blit_desc.dwSize   = sizeof(blit_desc);
        blit_desc.dwFlags  = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
        blit_desc.dwWidth  = adjusted_width + 32;
        blit_desc.dwHeight = adjusted_height;
        if (force_system_memory)
            blit_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
        else
            blit_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;

        hResult = IDirectDraw2_CreateSurface(pDDraw, &blit_desc, &pDDSBack, NULL);
        if (FAILED(hResult))
        {
            if (!force_system_memory)
            {
                blit_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
                hResult = IDirectDraw2_CreateSurface(pDDraw, &blit_desc, &pDDSBack, NULL);
            }
#else
        memset(&ddSurfaceDesc, 0, sizeof(ddSurfaceDesc));
        ddSurfaceDesc.dwSize   = sizeof(ddSurfaceDesc);
        ddSurfaceDesc.dwFlags  = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
        ddSurfaceDesc.dwWidth  = adjusted_width + 32;
        ddSurfaceDesc.dwHeight = adjusted_height;
        if (force_system_memory)
            ddSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
        else
            ddSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;

        hResult = IDirectDraw2_CreateSurface(pDDraw, &ddSurfaceDesc, &pDDSBack, NULL);
        if (FAILED(hResult))
        {
            if (!force_system_memory)
            {
                ddSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
                hResult = IDirectDraw2_CreateSurface(pDDraw, &ddSurfaceDesc, &pDDSBack, NULL);
            }
#endif

            if (FAILED(hResult))
            {
#ifdef JAPANESE
                ErrorMsg("IDirectDraw2.CreateSurface(back buffer)でエラーが発生しました");
#else
                ErrorMsg("IDirectDraw2.CreateSurface(back buffer) failed.");
#endif
                goto error;
            }
        }
    }
    else
    {
        pDDSBack = pDDSPrimary;
    }

#ifdef SAI
    if (double_filter)
    {
        memset(&Sxsai_desc, 0, sizeof(Sxsai_desc));
        Sxsai_desc.dwSize   = sizeof(Sxsai_desc);
        Sxsai_desc.dwFlags  = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
        Sxsai_desc.dwWidth  = (adjusted_width + 32) * 2;
        Sxsai_desc.dwHeight = adjusted_height * 2;
        Sxsai_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;

        hResult = IDirectDraw2_CreateSurface(pDDraw, &Sxsai_desc, &pDDScale, NULL);
        if (FAILED(hResult))
        {
            Sxsai_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
            hResult = IDirectDraw2_CreateSurface(pDDraw, &Sxsai_desc, &pDDScale, NULL);

            if (FAILED(hResult))
            {
#ifdef JAPANESE
                ErrorMsg("IDirectDraw2.CreateSurface(scale buffer)でエラーが発生しました");
#else
                ErrorMsg("IDirectDraw2.CreateSurface(scale buffer) failed.");
#endif
                goto error;
            }
        }
    }
    else
    {
        pDDScale = pDDSPrimary;
    }
#endif

    memset(&ddPixelFormat, 0, sizeof(DDPIXELFORMAT));
    ddPixelFormat.dwSize  = sizeof(DDPIXELFORMAT);
    ddPixelFormat.dwFlags = DDPF_RGB;

    hResult = IDirectDrawSurface2_GetPixelFormat(pDDSPrimary, &ddPixelFormat);
    if (FAILED(hResult))
    {
#ifdef JAPANESE
        ErrorMsg("IDirectDrawSurface2.GetPixelFormatでエラーが発生しました");
#else
        ErrorMsg("IDirectDrawSurface2.GetPixelFormat failed.");
#endif
        return 1;
    }

    GetPixelInfo(ddPixelFormat.dwRBitMask, &Red);
    GetPixelInfo(ddPixelFormat.dwGBitMask, &Green);
    GetPixelInfo(ddPixelFormat.dwBBitMask, &Blue);

    if (is_window)
    {
        hResult = IDirectDraw2_CreateClipper(pDDraw, 0, &pDDClipper, NULL);
        if (FAILED(hResult))
        {
#ifdef JAPANESE
            ErrorMsg("IDirectDraw2.CreateClipper でエラーが発生しました");
#else
            ErrorMsg("IDirectDraw2.CreateClipper failed.");
#endif
            goto error;
        }

        hResult = IDirectDrawClipper_SetHWnd(pDDClipper, 0, MAME32App.m_hWnd);
        if (FAILED(hResult))
        {
#ifdef JAPANESE
            ErrorMsg("IDirectDrawClipper.SetHWnd でエラーが発生しました");
#else
            ErrorMsg("IDirectDrawClipper.SetHWnd failed.");
#endif
            goto error;
        }

        hResult = IDirectDrawSurface2_SetClipper(pDDSPrimary, pDDClipper);
        if (FAILED(hResult))
        {
#ifdef JAPANESE
            ErrorMsg("IDirectDrawSurface2.SetClipper でエラーが発生しました");
#else
            ErrorMsg("IDirectDrawSurface2.SetClipper failed.");
#endif
            goto error;
        }
    }

    ShowWindow(MAME32App.m_hWnd, SW_SHOW);

    SetAbsoluteForegroundWindow(MAME32App.m_hWnd);

    return 0;

error:
    osd_close_display();
    return 1;
}


void osd_close_display(void)
{
    ReleaseDDrawObjects();
    ReleasePalettes();

    window_status = FLAG_INITIALIZING;
}


void osd_set_visible_area(int min_x, int max_x, int min_y, int max_y)
{
    if (min_x > max_x || min_y > max_y)
        return;

    AdjustVisibleRect(min_x, min_y, max_x, max_y);

    set_ui_visarea(game_rect.m_Left,
                   game_rect.m_Top,
                   game_rect.m_Left + game_rect.m_Width  - 1,
                   game_rect.m_Top  + game_rect.m_Height - 1);
}


void osd_set_debugger_focus(int debugger_has_focus)
{
}


static int SetBliter(void)
{
    int dest_bpp;

    if (bytes_per_pixel == 2)
        dest_bpp = Red.m_nSize + Green.m_nSize + Blue.m_nSize;
    else
        dest_bpp = bytes_per_pixel * 8;

    bliter = select_bliter(game_depth,
                           dest_bpp,
                           double_size,
                           use_stretch,
#ifdef NFILTER
                           nfilter,
#endif
                           hdouble,
                           vdouble,
                           hscanlines,
                           vscanlines,
                           scanline_brightness,
                           disable_mmx,
                           disable_mmx2);
    if (bliter == NULL)
        return 1;

    nTotalColors += MAX_COLORTABLE;

    memset(palette_is_dirty, 1, nTotalColors);

    SetPaletteColors();

    nTotalColors -= MAX_COLORTABLE;

    osd_refresh_display();

    if (pDDSFlip)    ClearSurface(pDDSFlip);
    if (pDDSPrimary) ClearSurface(pDDSPrimary);
    if (pDDSBack)    ClearSurface(pDDSBack);
#ifdef SAI
    if (pDDScale)    ClearSurface(pDDScale);
#endif

    if (video_sync) CalcVBlank();

    if (hMenu) ApplyMenuItems();

    UpdateWindow(MAME32App.m_hWnd);

    window_status &= ~FLAG_INITIALIZING;

    MAME32App.m_bIsInitialized = TRUE;

    return 0;
}


int osd_allocate_colors(unsigned int totalcolors,
                        const UINT8 *palette, UINT32 *rgb_components,
                        const UINT8 *debug_palette, UINT32 *debug_pens)
{
    int i, r, g, b;

    nTotalColors = (totalcolors > 32768) ? totalcolors : 32768;
    nColors = totalcolors;
    iTrans = 1;
    if(nTotalColors < nColors * 2) {
        nColors = nTotalColors;
        iTrans = 0;
    }

    palette_lookup   = (UINT32 *)malloc((nTotalColors + MAX_COLORTABLE) * sizeof(UINT32));
    palette_is_dirty = malloc(nTotalColors + MAX_COLORTABLE);
    palette_entries  = (PALETTEENTRY *)malloc((nTotalColors + MAX_COLORTABLE) * sizeof(PALETTEENTRY));
    adjusted_palette = (PALETTEENTRY *)malloc((nTotalColors + MAX_COLORTABLE) * sizeof(PALETTEENTRY));
    if (palette_lookup == NULL || palette_is_dirty == NULL
    ||  palette_entries == NULL || adjusted_palette == NULL)
        return 1;

    memset(palette_lookup,   0, (nTotalColors + MAX_COLORTABLE) * sizeof(UINT32));
    memset(palette_is_dirty, 0, nTotalColors + MAX_COLORTABLE);
    memset(palette_entries,  0, (nTotalColors + MAX_COLORTABLE) * sizeof(PALETTEENTRY));
    memset(adjusted_palette, 0, (nTotalColors + MAX_COLORTABLE) * sizeof(PALETTEENTRY));

    /* direct render */
    if (rgb_components)
    {
        int r1, g1, b1;

        i = 0;
        for (r1 = 0; r1 < 32; r1++)
        {
            for (g1 = 0; g1 < 32; g1++)
            {
                for (b1 = 0; b1 < 32; b1++)
                {
                    r = (r1 << 3) | (r1 >> 2);
                    g = (g1 << 3) | (g1 >> 2);
                    b = (b1 << 3) | (b1 >> 2);

                    SetPen(MAKECOL15(r, g, b), r, g, b);
                }
            }
        }

        if (game_depth == 32)
        {
            for (i = 0; i < totalcolors; i++)
            {
                r = palette[3 * i + 0];
                g = palette[3 * i + 1];
                b = palette[3 * i + 2];
                *rgb_components++ = MAKECOL32(r, g, b);
            }

            for(i = 0; i < MAX_COLORTABLE; i++) {
                r = (int) colortable[i][0];
                g = (int) colortable[i][1];
                b = (int) colortable[i][2];
                Machine->uifont->colortable[i] = MAKECOL32(r, g, b);
            }

            return SetBliter();
        }
        else
        {
            rgb_components[0] = 0x7c00;
            rgb_components[1] = 0x03e0;
            rgb_components[2] = 0x001f;

            for(i = 0; i < MAX_COLORTABLE; i++) {
                r = (int) colortable[i][0];
                g = (int) colortable[i][1];
                b = (int) colortable[i][2];
                Machine->uifont->colortable[i] = MAKECOL15(r, g, b);
            }

            return SetBliter();
        }
    }
    else
    {
        for (i = 0; i < totalcolors; i++)
        {
            r = palette[3 * i + 0];
            g = palette[3 * i + 1];
            b = palette[3 * i + 2];

            SetPen(i, r, g, b);
        }
    }

    if(nTotalColors + MAX_COLORTABLE < 65535) {
        for(i = 0; i < MAX_COLORTABLE; i++) {
            r = (int) colortable[i][0];
            g = (int) colortable[i][1];
            b = (int) colortable[i][2];
            SetPen(i + nTotalColors, r & 0xff, g & 0xff, b & 0xff);
            Machine->uifont->colortable[i] = i + nTotalColors;
        }
    } else {
        for(i = 0; i < MAX_COLORTABLE; i++) {
            Machine->uifont->colortable[i] = 65535;
        }
        Machine->uifont->colortable[0] = 0;
        Machine->uifont->colortable[3] = 0;
    }

    return SetBliter();
}


void osd_modify_pen(int pen, unsigned char red, unsigned char green, unsigned char blue)
{
    if (palette_entries[pen].peRed   == red
    &&  palette_entries[pen].peGreen == green
    &&  palette_entries[pen].peBlue  == blue)
        return;

    SetPen(pen, red, green, blue);
    dirtypalette = TRUE;
}


//void osd_mark_dirty(int x1, int y1, int x2, int y2)
//{
//}


int osd_skip_this_frame(void)
{
    static const int skiptable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS] =
    {
        { 0,0,0,0,0,0,0,0,0,0,0,0 },
        { 0,0,0,0,0,0,0,0,0,0,0,1 },
        { 0,0,0,0,0,1,0,0,0,0,0,1 },
        { 0,0,0,1,0,0,0,1,0,0,0,1 },
        { 0,0,1,0,0,1,0,0,1,0,0,1 },
        { 0,1,0,0,1,0,1,0,0,1,0,1 },
        { 0,1,0,1,0,1,0,1,0,1,0,1 },
        { 0,1,0,1,1,0,1,0,1,1,0,1 },
        { 0,1,1,0,1,1,0,1,1,0,1,1 },
        { 0,1,1,1,0,1,1,1,0,1,1,1 },
        { 0,1,1,1,1,1,0,1,1,1,1,1 },
        { 0,1,1,1,1,1,1,1,1,1,1,1 }
    };

    return skiptable[frameskip][frameskip_counter];
}


void osd_update_video_and_audio(struct mame_bitmap *game_bitmap, struct mame_bitmap *debug_bitmap)
{
    static const int waittable[FRAMESKIP_LEVELS][FRAMESKIP_LEVELS] =
    {
        { 1,1,1,1,1,1,1,1,1,1,1,1 },
        { 2,1,1,1,1,1,1,1,1,1,1,0 },
        { 2,1,1,1,1,0,2,1,1,1,1,0 },
        { 2,1,1,0,2,1,1,0,2,1,1,0 },
        { 2,1,0,2,1,0,2,1,0,2,1,0 },
        { 2,0,2,1,0,2,0,2,1,0,2,0 },
        { 2,0,2,0,2,0,2,0,2,0,2,0 },
        { 2,0,2,0,0,3,0,2,0,0,3,0 },
        { 3,0,0,3,0,0,3,0,0,3,0,0 },
        { 4,0,0,0,4,0,0,0,4,0,0,0 },
        { 6,0,0,0,0,0,6,0,0,0,0,0 },
        {12,0,0,0,0,0,0,0,0,0,0,0 }
    };
    TICKER curr;

    if (warming_up)
    {
        /* first time through, initialize timer */
        prev_measure = ticker() - FRAMESKIP_LEVELS * TICKS_PER_SEC / video_fps;
        warming_up = 0;
    }

    if (frameskip_counter == 0)
        this_frame_base = prev_measure + FRAMESKIP_LEVELS * TICKS_PER_SEC / video_fps;

    if (osd_skip_this_frame() == 0)
    {
        int draw_flag = 0;

        if (game_bitmap != pMAMEBitmap)
            set_bitmap(game_bitmap, (game_depth == 15) ? 16 : game_depth);

        if (is_window)
        {
            POINT p;
            RECT  rect;
            BOOL  bResized = FALSE;

            if (resized_width || resized_height)
            {
                screen_width  = resized_width;
                screen_height = resized_height;

                resized_width  = 0;
                resized_height = 0;

                bResized = TRUE;
            }

            p.x = 0;
            p.y = 0;
            ClientToScreen(MAME32App.m_hWnd, &p);
            rect.left   = p.x;
            rect.top    = p.y;
            rect.right  = p.x + screen_width;
            rect.bottom = p.y + screen_height;

            if (p.x != rectPrimary.left || p.y != rectPrimary.top || bResized)
                rectPrimary = rect;
        }

        if (triple_buffer)
            ClearSurface(pDDSPrimary);

        if (dirtypalette)
        {
            SetPaletteColors();
            dirtypalette = 0;
        }

        if (showfps || showfpstemp)
        {
            ui_text(game_bitmap, fpsbuf, Machine->uiwidth - strlen(fpsbuf) * Machine->uifontwidth, 0);

            if ((Machine->drv->video_attributes & VIDEO_TYPE_VECTOR) || (partial_update_count > 1))
                ui_text(game_bitmap, vupbuf, Machine->uiwidth - strlen(vupbuf) * Machine->uifontwidth, Machine->uifontheight);
	}

        if (triple_buffer && use_back_buffer)
            DrawSurface(draw_flag++);

        if (triple_buffer || use_back_buffer)
            DrawSurface(draw_flag++);

        if (showfpstemp)
        {
            showfpstemp--;
            if (showfps == 0 && showfpstemp == 0)
                schedule_full_refresh();
        }

        if (input_ui_pressed(IPT_UI_SHOW_FPS))
        {
            if (showfpstemp)
            {
                showfpstemp = 0;
                schedule_full_refresh();
            }
            else
            {
                showfps ^= 1;
                if (showfps == 0)
                    schedule_full_refresh();
            }
        }

        curr = ticker();

        /* now wait until it's time to update the screen */
        if (throttle)
        {
            /* wait only if the audio update hasn't synced us already */
            TICKER target = this_frame_base +
                            frameskip_counter * TICKS_PER_SEC / video_fps;

            if (curr - target < 0)
            {
                profiler_mark(PROFILER_IDLE);
                if (use_sleep)
                {
                    int sleep_time;

                    curr = ticker();
                    sleep_time = (int)((double)(target - curr) / ((double)TICKS_PER_SEC / 1000.0)) - 1;
                    if (sleep_time > 1)
                        Sleep(sleep_time);
                }
                do
                {
                    curr = ticker();
                }
                while (curr - target < 0);
                profiler_mark(PROFILER_END);
            }
        }

        /* for the FPS average calculation */
        if (++frames_displayed == FRAMES_TO_SKIP)
            start_time = curr;
        else
            end_time = curr;

        if (frameskip_counter == 0)
        {
            speed = (double)TICKS_PER_SEC / (video_fps * (double)(curr - prev_measure) / (double)(100 * FRAMESKIP_LEVELS));

            prev_measure = curr;
        }

        prev = curr;

        vfcount += waittable[frameskip][frameskip_counter];
        if (vfcount >= video_fps)
        {
            extern int vector_updates; /* avgdvg_go()'s per Mame frame, should be 1 */

            vfcount = 0;
            vups = vector_updates;
            vector_updates = 0;
        }

        if (showfps || showfpstemp)
        {
            double fps;

            fps   = (video_fps * (double)(FRAMESKIP_LEVELS - frameskip) * speed) / (double)(100 * FRAMESKIP_LEVELS);
            sprintf(fpsbuf, "%s%2d%4.0f%%%6.1f/%.1f fps", autoframeskip ? "auto" : "fskp", frameskip, speed, fps, video_fps);

            if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR)
                sprintf(vupbuf, " %d vector updates", vups);
            else if (partial_update_count > 1)
                sprintf(vupbuf, " %d partial updates", partial_update_count);
        }

        if (dirty_background)
        {
            ClearSurface(pDDSPrimary);
            dirty_background = FALSE;
        }

        if (video_sync)
        {
            if (throttle)
            {
                lScanLineStart = GetSystemMetrics(SM_CYSCREEN);
                if (rectPrimary.bottom < lScanLineStart)
                    lScanLineStart = rectPrimary.bottom;

                profiler_mark(PROFILER_IDLE);
                while (WaitVBlank() == FALSE);
                profiler_mark(PROFILER_END);
            }
        }

        DrawSurface(draw_flag);

        if (throttle && autoframeskip &&  frameskip_counter == 0)
        {
            /* adjust speed to video refresh rate if vsync is on */
            int adjspeed = (int)(speed + 0.5);

            if (adjspeed >= 100)
            {
                frameskipadjust++;
                if (frameskipadjust >= 3)
                {
                    frameskipadjust = 0;
                    if (frameskip > 0) frameskip--;
                }
            }
            else
            {
                if (adjspeed < 80)
                    frameskipadjust -= (90 - adjspeed) / 5;
                else
                {
                    /* don't push frameskip too far if we are close to 100% speed */
                    if (frameskip < 8)
                        frameskipadjust--;
                }

                while (frameskipadjust <= -2)
                {
                    frameskipadjust += 2;
                    if (frameskip < FRAMESKIP_LEVELS - 1) frameskip++;
                }
            }
        }
    }

    win32_sound_calc_samples();

#ifdef KAILLERA
    if (!kPlay)
    {
#endif /* KAILLERA */

    if (input_ui_pressed(IPT_UI_FRAMESKIP_INC))
    {
        if (autoframeskip)
        {
            autoframeskip = 0;
            frameskip = 0;
        }
        else
        {
            if (frameskip == FRAMESKIP_LEVELS - 1)
            {
                frameskip = 0;
                autoframeskip = 1;
            }
            else
                frameskip++;
        }

        if (showfps == 0)
            showfpstemp = 2 * Machine->drv->frames_per_second;

        /* reset the frame counter every time the frameskip key is pressed, so */
        /* we'll measure the average FPS on a consistent status. */
        frames_displayed = 0;
    }

    if (input_ui_pressed(IPT_UI_FRAMESKIP_DEC))
    {
        if (autoframeskip)
        {
            autoframeskip = 0;
            frameskip = FRAMESKIP_LEVELS - 1;
        }
        else
        {
            if (frameskip == 0)
                autoframeskip = 1;
            else
                frameskip--;
        }

        if (showfps == FALSE)
            showfpstemp = 2 * Machine->drv->frames_per_second;

        /* reset the frame counter every time the frameskip key is pressed, so */
        /* we'll measure the average FPS on a consistent status. */
        frames_displayed = 0;
    }

    if (input_ui_pressed(IPT_UI_THROTTLE))
    {
        throttle ^= 1;

        /* reset the frame counter every time the throttle key is pressed, so */
        /* we'll measure the average FPS on a consistent status. */
        frames_displayed = 0;
    }

#ifdef KAILLERA
    }
#endif /* KAILLERA */

    frameskip_counter = (frameskip_counter + 1) % FRAMESKIP_LEVELS;

    MAME32App.m_pJoystick->poll_joysticks();
    MAME32App.HandleAutoPause();
    MAME32App.ProcessMessages();

    if ((code_pressed(KEYCODE_LALT) || code_pressed(KEYCODE_RALT))
    &&  (code_pressed(KEYCODE_ENTER) || code_pressed(KEYCODE_ENTER_PAD)))
        ChangeDisplayMode(1);

		if(!boost && input_ui_pressed(IPT_UI_BOOST) )
		{
			boost = 1;
			frameskip_bak = frameskip;
			autoframeskip_bak = autoframeskip;
			throttle_bak = throttle;
		}

		if(boost && input_ui_pressed(IPT_UI_BOOST) )
		{
			boost = 0;
			frameskip = frameskip_bak;
			autoframeskip = autoframeskip_bak;
			throttle = throttle_bak;
		}

		if(boost)
		{
			frameskip = FRAMESKIP_LEVELS - 1;
			autoframeskip = 0;
			throttle = 0;
		}

}


void osd_set_gamma(float _gamma)
{
    if (_gamma < 0.2) _gamma = 0.2;
    if (_gamma > 3.0) _gamma = 3.0;

    gamma = _gamma;

    AdjustColorMap();
    AdjustPalette();
}


float osd_get_gamma(void)
{
    return (float)gamma;
}


void osd_set_brightness(int _brightness)
{
    brightness = _brightness;

    AdjustColorMap();
    AdjustPalette();
}


int osd_get_brightness(void)
{
    return brightness;
}


void osd_save_snapshot(struct mame_bitmap *bitmap)
{
    char sFileName[MAX_PATH];
    int  nResult;
    void *pFile;

    /* first of all try with "gamename.png" */
    sprintf(sFileName, "%.8s", Machine->gamedrv->name);

    /* Avoid overwriting of existing files */
    nResult = osd_faccess(sFileName, OSD_FILETYPE_SCREENSHOT);
    if (nResult)
    {
        /* Create a unique PNG file */
        do
        {
            /* otherwise use "nameNNNN" */
            sprintf(sFileName, "%.4s%04d", Machine->gamedrv->name, snapno++);

            nResult = osd_faccess(sFileName, OSD_FILETYPE_SCREENSHOT);
        }
        while (nResult != 0);
    }

    pFile = osd_fopen(sFileName, "", OSD_FILETYPE_SCREENSHOT, TRUE);
    if (pFile)
    {
        save_screen_snapshot_as(pFile, bitmap);
        osd_fclose(pFile);
    }
}


void osd_pause(int paused)
{
    static float orig_brt;

    if (paused && MAME32App.m_bMamePaused == FALSE)
    {
        MAME32App.m_bMamePaused = TRUE;

        orig_brt = osd_get_brightness();
#ifdef MAME32JP
    if (options.blackout) // BLACKOUT
#endif /* MAME32JP */
        osd_set_brightness(orig_brt * 0.65);
    }
    else
    {
        MAME32App.m_bMamePaused = FALSE;
#ifdef MAME32JP
    if (options.blackout) // BLACKOUT
#endif /* MAME32JP */
        osd_set_brightness(orig_brt);
    }

    osd_refresh_display();
}


void osd_refresh_display(void)
{
    if (is_window)
        InvalidateRect(MAME32App.m_hWnd, NULL, FALSE);
    else
        dirty_background = TRUE;
}


BOOL DirectDraw_OnMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
    if (is_window)
    {
        switch (Msg)
        {
            PEEK_MESSAGE(hWnd, WM_ACTIVATEAPP,  OnActivateApp);
            HANDLE_MESSAGE(hWnd, WM_SYSCOMMAND, OnSysCommand);
            HANDLE_MESSAGE(hWnd, WM_SIZE,       OnSize);
        }
    }
    else
    {
        switch (Msg)
        {
            PEEK_MESSAGE(hWnd, WM_ACTIVATEAPP,  OnActivateApp);
            HANDLE_MESSAGE(hWnd, WM_SYSCOMMAND, OnSysCommand);
            HANDLE_MESSAGE(hWnd, WM_SETCURSOR,  OnSetCursor);
        }
    }
    return FALSE;
}

BOOL throttled(void)
{
    return throttle;
}


/***************************************************************************
    Internal functions
 ***************************************************************************/

static void set_bitmap(struct mame_bitmap *bitmap, int depth)
{
    pBitmapOffset = &((UINT8 *)bitmap->line[game_rect.m_Top])[game_rect.m_Left * depth / 8];
    nBitmapPitch = (UINT8 *)bitmap->line[1] - (UINT8 *)bitmap->line[0];
    pMAMEBitmap  = bitmap;
}


static void ChangeDisplayMode(int switch_mode)
{
    int width       = video_settings.width;
    int height      = video_settings.height;
    int depth       = video_settings.depth;
    int fps         = video_settings.fps;
    int attributes  = video_settings.attributes;
    int orientation = video_settings.orientation;

    window_status |= FLAG_INITIALIZING;

    osd_sound_enable(0);

    ReleaseDDrawObjects();

    if (switch_mode)
        video_settings.osd_options.window_mode = video_settings.osd_options.window_mode ? FALSE : TRUE;

    video_init2(&video_settings.osd_options);

    video_settings.width = 0;

    if (osd_create_display(width, height, depth, fps, attributes, orientation))
        goto error;

    set_visible_area(Machine->visible_area.min_x,
                     Machine->visible_area.max_x,
                     Machine->visible_area.min_y,
                     Machine->visible_area.max_y);

    osd_sound_enable(1);

    if (SetBliter())
        goto error;

    window_status &= ~FLAG_INITIALIZING;
    return;

error:
    SendMessage(MAME32App.m_hWnd, WM_CLOSE, 0, 0);
}


static void ReleaseDDrawObjects(void)
{
    if (pDDraw)
    {
#ifdef SAI
        if (pDDScale)    ClearSurface(pDDScale);
#endif
        if (pDDSBack)    ClearSurface(pDDSBack);
        if (pDDSPrimary) ClearSurface(pDDSPrimary);
        if (pDDSFlip)    ClearSurface(pDDSFlip);

        if (pDDClipper)
        {
            IDirectDrawClipper_Release(pDDClipper);
            pDDClipper = NULL;
        }

#ifdef SAI
        if (pDDScale)
        {
            IDirectDrawSurface2_Release(pDDScale);
            if (pDDScale == pDDSPrimary)
                pDDSPrimary = NULL;
            pDDScale = NULL;
        }
#endif

        if (pDDSBack)
        {
            IDirectDrawSurface2_Release(pDDSBack);
            if (pDDSBack == pDDSPrimary)
                pDDSPrimary = NULL;
            pDDSBack = NULL;
        }

        if (pDDSFlip)
        {
            IDirectDrawSurface2_Release(pDDSFlip);
            pDDSFlip = NULL;
            pDDSPrimary = NULL;
        }

        if (pDDSPrimary)
        {
            IDirectDrawSurface2_Release(pDDSPrimary);
            pDDSPrimary = NULL;
        }

        if (is_window == FALSE)
        {
            while (1)
            {
                if (IDirectDraw2_SetCooperativeLevel(pDDraw, MAME32App.m_hWnd, DDSCL_NORMAL) == DD_OK)
                    break;
                Sleep(100);
            }
            while (1)
            {
                if (IDirectDraw2_RestoreDisplayMode(pDDraw) == DD_OK)
                    break;
                Sleep(100);
            }
        }

        pDDraw = NULL;

        InvalidateRect(NULL, NULL, FALSE);
    }
}


static void ReleasePalettes(void)
{
    if (adjusted_palette)
    {
        free(adjusted_palette);
        adjusted_palette = NULL;
    }

    if (palette_entries)
    {
        free(palette_entries);
        palette_entries = NULL;
    }

    if (palette_is_dirty)
    {
        free(palette_is_dirty);
        palette_is_dirty = NULL;
    }

    if (palette_lookup)
    {
        free(palette_lookup);
        palette_lookup = NULL;
    }
}

INLINE void MapColor(unsigned char *red, unsigned char *green, unsigned char *blue)
{
    *red   = color_map[*red];
    *green = color_map[*green];
    *blue  = color_map[*blue];
}

static void AdjustColorMap(void)
{
    int i;

    for (i = 0; i < INTENSITY_LEVELS; i++)
    {
        color_map[i] = (unsigned char)((INTENSITY_LEVELS - 1.0)
                        * (brightness / 100.0)
                        * pow(((double)i / (INTENSITY_LEVELS - 1.0)), 1.0 / gamma));
    }
}

/*===========================================================================
    palette functions
 ==========================================================================*/

static void SetPen(int pen, unsigned char red, unsigned char green, unsigned char blue)
{
    palette_entries[pen].peRed   = red;
    palette_entries[pen].peGreen = green;
    palette_entries[pen].peBlue  = blue;
    palette_entries[pen].peFlags = PC_NOCOLLAPSE;

    memcpy(&adjusted_palette[pen], &palette_entries[pen], sizeof(PALETTEENTRY));
    if (pen < nTotalColors)
    {
        MapColor(&adjusted_palette[pen].peRed,
                 &adjusted_palette[pen].peGreen,
                 &adjusted_palette[pen].peBlue);

        palette_is_dirty[pen] = 1;
    }
}


static void SetPaletteColors(void)
{
    int i;

    if (bytes_per_pixel == 2)
    {
        for (i = 0; i < nTotalColors; i++)
        {
            if (palette_is_dirty[i])
            {
                palette_is_dirty[i] = 0;
                palette_lookup[i] = MAKECOL(adjusted_palette[i].peRed,
                                            adjusted_palette[i].peGreen,
                                            adjusted_palette[i].peBlue) * 0x00010001;
                if(i + nColors < nTotalColors - MAX_COLORTABLE) {
                    palette_lookup[i + nColors] = MAKECOL(adjusted_palette[i].peRed * iTransRate / 100,
                                                          adjusted_palette[i].peGreen * iTransRate / 100,
                                                          adjusted_palette[i].peBlue * iTransRate / 100) * 0x00010001;
                }
            }
        }
    }
    else
    {
        for (i = 0; i < nTotalColors; i++)
        {
            if (palette_is_dirty[i])
            {
                palette_is_dirty[i] = 0;
                palette_lookup[i] = MAKECOL(adjusted_palette[i].peRed,
                                            adjusted_palette[i].peGreen,
                                            adjusted_palette[i].peBlue);
                if(i + nColors < nTotalColors) {
                    palette_lookup[i + nColors] = MAKECOL(adjusted_palette[i].peRed * iTransRate / 100,
                                                          adjusted_palette[i].peGreen * iTransRate / 100,
                                                          adjusted_palette[i].peBlue * iTransRate / 100);
                }
            }
        }
    }
}


static void AdjustPalette(void)
{
    int i;

    memcpy(adjusted_palette, palette_entries, nTotalColors * sizeof(PALETTEENTRY));

    for (i = 0; i < nTotalColors; i++)
    {
        MapColor(&adjusted_palette[i].peRed,
                 &adjusted_palette[i].peGreen,
                 &adjusted_palette[i].peBlue);

        palette_is_dirty[i] = 1;
    }

    dirtypalette = TRUE;
}


/*===========================================================================
    Display settings
 ==========================================================================*/

static int AdjustVisibleRect(int min_x, int min_y, int max_x, int max_y)
{
    int width;
    int height;
    int attributes;
    int orientation;
    int depth;

    width  = (max_x - min_x) + 1;
    height = (max_y - min_y) + 1;

    if (!(window_status & FLAG_INITIALIZING))
    {
        if (width  != game_rect.m_Width
        ||  height != game_rect.m_Height)
        {
            video_settings.width  = width;
            video_settings.height = height;
            ChangeDisplayMode(0);
            return 0;
        }
    }

    game_rect.m_Left   = min_x;
    game_rect.m_Top    = min_y;
    game_rect.m_Width  = width;
    game_rect.m_Height = height;

    attributes  = video_settings.attributes;
    orientation = video_settings.orientation;
    depth       = screen_depth ? screen_depth : video_settings.depth;

    if (video_settings.width == 0)
    {
        video_settings.width  = width;
        video_settings.height = height;
    }

    if (attributes & VIDEO_TYPE_VECTOR)
        adjust_aspect = FALSE;

    if ((attributes & VIDEO_PIXEL_ASPECT_RATIO_MASK) == VIDEO_PIXEL_ASPECT_RATIO_1_2)
    {
        double_size = FALSE;
#ifdef NFILTER
        nfilter = FALSE;
#endif

        if (orientation & ORIENTATION_SWAP_XY)
        {
            vdouble    = FALSE;
            hdouble    = TRUE;
            hscanlines = FALSE;
        }
        else
        {
            vdouble    = TRUE;
            hdouble    = FALSE;
            vscanlines = FALSE;
        }
    }
    else if ((attributes & VIDEO_PIXEL_ASPECT_RATIO_MASK) == VIDEO_PIXEL_ASPECT_RATIO_2_1)
    {
        double_size = FALSE;
#ifdef NFILTER
        nfilter = FALSE;
#endif

        if (orientation & ORIENTATION_SWAP_XY)
        {
            vdouble    = TRUE;
            hdouble    = FALSE;
            vscanlines = FALSE;
        }
        else
        {
            vdouble    = FALSE;
            hdouble    = TRUE;
            hscanlines = FALSE;
        }
    }
    else if (!double_size)
    {
        hscanlines = FALSE;
        vscanlines = FALSE;
    }


    if (adjust_aspect && switch_resolution)
    {
        int game_x, game_y;
        int screen_x, screen_y;
        int org_width, org_height;
        int xnum, ynum;
        float screen_aspect;
        float game_aspect;
        float aspect_adjust;

        org_width  = width;
        org_height = height;

        if (attributes & VIDEO_ASPECT_RATIO_MASK)
        {
            xnum = VIDEO_ASPECT_RATIO_NUM(attributes) / 4;
            ynum = VIDEO_ASPECT_RATIO_DEN(attributes) / 3;
        }
        else if ((attributes & VIDEO_DUAL_MONITOR) ||
                 (attributes & VIDEO_PIXEL_ASPECT_RATIO_MASK) == VIDEO_PIXEL_ASPECT_RATIO_1_2)
        {
            xnum = 2;
            ynum = 1;
        }
        else if ((attributes & VIDEO_PIXEL_ASPECT_RATIO_MASK) == VIDEO_PIXEL_ASPECT_RATIO_2_1)
        {
            xnum = 1;
            ynum = 2;
        }
        else
        {
            xnum = 1;
            ynum = 1;
        }

        if (is_window)
        {
            screen_x = GetSystemMetrics(SM_CXSCREEN);
            screen_y = GetSystemMetrics(SM_CYSCREEN);
        }
        else
        {
            screen_x = 4;
            screen_y = 3;
        }

        if (orientation & ORIENTATION_SWAP_XY)
        {
            int temp = xnum;
            xnum = ynum;
            ynum = temp;
        }

        game_x = width  / xnum;
        game_y = height / ynum;

        if (orientation & ORIENTATION_SWAP_XY)
        {
            screen_aspect = (float)screen_x / (float)screen_y;
            game_aspect   = (float)game_y / (float)game_x;
            aspect_adjust = game_aspect / screen_aspect;
            if (aspect_adjust < 1.0)
            {
                int tmp = width;

                width *= aspect_adjust;
                aspect_adjust = (float)tmp / (float)width;
                height *= aspect_adjust;
                width = tmp;
            }
            else
                width *= aspect_adjust;
            width = (width + 7) & ~7;
        }
        else
        {
            screen_aspect = (float)screen_x / (float)screen_y;
            game_aspect   = (float)game_x / (float)game_y;
            aspect_adjust = game_aspect / screen_aspect;
            if (aspect_adjust < 1.0)
            {
                int tmp = height;

                height *= aspect_adjust;
                aspect_adjust = (float)tmp / (float)height;
                width  *= aspect_adjust;
                height = tmp;
            }
            else
                height *= aspect_adjust;
            width = (width + 7) & ~7;
        }

        if (width != org_width || height != org_height)
            use_back_buffer = TRUE;
    }

    if (is_window)
    {
        int nDesktopWidth, nDesktopHeight;

        nDesktopWidth   = GetSystemMetrics(SM_CXFULLSCREEN) - 2 * GetSystemMetrics(SM_CXFRAME);
        nDesktopHeight  = GetSystemMetrics(SM_CYFULLSCREEN) - 2 * GetSystemMetrics(SM_CYFRAME);

#ifdef SAI
        adjusted_width  = width  * (double_size ? 2 : 1) * (double_filter ? 2 : 1) * (hdouble ? 2 : 1);
        adjusted_height = height * (double_size ? 2 : 1) * (double_filter ? 2 : 1) * (vdouble ? 2 : 1);

        screen_width  = width  * stretch_scale * (double_size ? 2 : 1) * (double_filter ? 2 : 1) * (hdouble ? 2 : 1);
        screen_height = height * stretch_scale * (double_size ? 2 : 1) * (double_filter ? 2 : 1) * (vdouble ? 2 : 1);
#else
        adjusted_width  = width  * (double_size ? 2 : 1) * (hdouble ? 2 : 1);
        adjusted_height = height * (double_size ? 2 : 1) * (vdouble ? 2 : 1);

        screen_width  = width  * stretch_scale * (double_size ? 2 : 1) * (hdouble ? 2 : 1);
        screen_height = height * stretch_scale * (double_size ? 2 : 1) * (vdouble ? 2 : 1);
#endif
#ifdef NFILTER
        nDesktopWidth   = GetSystemMetrics(SM_CXFULLSCREEN) - 2 * GetSystemMetrics(SM_CXFIXEDFRAME);
        nDesktopHeight  = GetSystemMetrics(SM_CYFULLSCREEN) - 2 * GetSystemMetrics(SM_CYFIXEDFRAME);

        if(nfilter) {
                adjusted_width  = width  * 2;
                adjusted_height = height * 2;
        }
        else {
                adjusted_width  = width  * (double_size ? 2 : 1) * (hdouble ? 2 : 1);
                adjusted_height = height * (double_size ? 2 : 1) * (vdouble ? 2 : 1);
        }

        if(nfilter) {
                screen_width  = width  * stretch_scale * 2;
                screen_height = height * stretch_scale * 2;
        }
        else {
                screen_width  = width  * stretch_scale * (double_size ? 2 : 1) * (hdouble ? 2 : 1);
                screen_height = height * stretch_scale * (double_size ? 2 : 1) * (vdouble ? 2 : 1);
        }
#endif

        if (screen_width > nDesktopWidth || screen_height > nDesktopHeight)
        {
            double dx, dy;

            use_stretch = TRUE;

            dx = (double)nDesktopWidth / (double)screen_width;
            dy = (double)nDesktopHeight / (double)screen_height;

            if (dx > dy)
            {
                screen_width  = (int)((double)screen_width * dy);
                screen_height = nDesktopHeight;
            }
            else
            {
                screen_width  = nDesktopWidth;
                screen_height = (int)((double)screen_height * dy);
            }
        }
    }
    else
    {
        int left, top;

#ifdef SAI
        adjusted_width  = width  * stretch_scale * (double_size ? 2 : 1) * (double_filter ? 2 : 1) * (hdouble ? 2 : 1);
        adjusted_height = height * stretch_scale * (double_size ? 2 : 1) * (double_filter ? 2 : 1) * (vdouble ? 2 : 1);
#else
        adjusted_width  = width  * stretch_scale * (double_size ? 2 : 1) * (hdouble ? 2 : 1);
        adjusted_height = height * stretch_scale * (double_size ? 2 : 1) * (vdouble ? 2 : 1);
#endif
#ifdef NFILTER
        if(nfilter) {
                adjusted_width  = width  * stretch_scale * 2;
                adjusted_height = height * stretch_scale * 2;
        }
        else {
                adjusted_width  = width  * stretch_scale * (double_size ? 2 : 1) * (hdouble ? 2 : 1);
                adjusted_height = height * stretch_scale * (double_size ? 2 : 1) * (vdouble ? 2 : 1);
        }
#endif

        if (switch_resolution)
        {
            SelectDisplayMode(adjusted_width, adjusted_height, depth);
        }
        else
        {
            if (FindDisplayMode(screen_width, screen_height, depth) == FALSE)
            {
#ifdef JAPANESE
                ErrorMsg("DirectDrawは要求された画面モード %dx%d (%d bpp) をサポートしていません",
#else
                ErrorMsg("DirectDraw does not support the requested mode %dx%d (%d bpp)",
#endif
                         screen_width, screen_height, depth);
                return 1;
            }
        }

#ifdef SAI
        adjusted_width  = width  * stretch_scale * (double_size ? 2 : 1) * (double_filter ? 2 : 1) * (hdouble ? 2 : 1);
        adjusted_height = height * stretch_scale * (double_size ? 2 : 1) * (double_filter ? 2 : 1) * (vdouble ? 2 : 1);
#else
        adjusted_width  = width  * stretch_scale * (double_size ? 2 : 1) * (hdouble ? 2 : 1);
        adjusted_height = height * stretch_scale * (double_size ? 2 : 1) * (vdouble ? 2 : 1);
#endif
#ifdef NFILTER
        if(nfilter) {
                adjusted_width  = width  * stretch_scale * 2;
                adjusted_height = height * stretch_scale * 2;
        }
        else {
                adjusted_width  = width  * stretch_scale * (double_size ? 2 : 1) * (hdouble ? 2 : 1);
                adjusted_height = height * stretch_scale * (double_size ? 2 : 1) * (vdouble ? 2 : 1);
        }
#endif
        if (adjusted_width  > screen_width ||  adjusted_height > screen_height)
        {
            double dx, dy;

            use_stretch = TRUE;
            use_back_buffer = TRUE;

            dx = (double)screen_width / (double)adjusted_width;
            dy = (double)screen_height / (double)adjusted_height;

            if (dx > dy)
            {
                adjusted_width  = (int)((double)adjusted_width * dy);
                adjusted_height = screen_height;
            }
            else
            {
                adjusted_width  = screen_width;
                adjusted_height = (int)((double)adjusted_height * dy);
            }
        }
        else if (stretch_scale == 1 && !adjust_aspect)
            use_back_buffer = FALSE;

        left = (screen_width - adjusted_width) / 2;
        top  = (screen_height - adjusted_height) / 2;

#ifdef FSSTRETCH
	  if (!fat_mode) {
	        rectPrimary.left   = left;
      	  rectPrimary.top    = top;
	        rectPrimary.right  = left + adjusted_width;
      	  rectPrimary.bottom = top  + adjusted_height;
	  } else {
	        rectPrimary.left   = 0;
      	  rectPrimary.top    = 0;
	        rectPrimary.right  = screen_width;
      	  rectPrimary.bottom = screen_height;
	  }
#else
        rectPrimary.left   = left;
        rectPrimary.top    = top;
        rectPrimary.right  = left + adjusted_width;
        rectPrimary.bottom = top  + adjusted_height;
#endif
    }

    rectBack.left   = 0;
    rectBack.top    = 0;
    rectBack.right  = game_rect.m_Width;
    rectBack.bottom = game_rect.m_Height;

#ifdef NFILTER
    if (double_size || nfilter)
#else
    if (double_size)
#endif
    {
        rectBack.right  *= 2;
        rectBack.bottom *= 2;
    }
    if (hdouble)
        rectBack.right  *= 2;
    if (vdouble)
        rectBack.bottom *= 2;

    if (Machine->scrbitmap)
        set_bitmap(Machine->scrbitmap, (game_depth == 15) ? 16 : game_depth);

    return 0;
}

static void GetPixelInfo(DWORD dwMask, struct tPixelInfo* pPixelInfo)
{
    int nShift = 0;
    int nCount = 0;
    int i;

    pPixelInfo->m_dwMask = dwMask;

    while ((dwMask & 1) == 0 && nShift < sizeof(DWORD) * 8)
    {
        nShift++;
        dwMask >>= 1;
    }
    pPixelInfo->m_nShift = nShift;

    for (i = 0; i < sizeof(DWORD) * 8; i++)
    {
        if (dwMask & (1 << i))
            nCount++;
    }
    pPixelInfo->m_nSize = nCount;
}


/*===========================================================================
    Functions for full screen mode
 ==========================================================================*/

/*
    FindBestDisplayMode will search through the available display modes
    and select the mode which is just large enough for the input dimentions.
    If no display modes are large enough, the largest mode available is returned.
*/
static BOOL FindBestDisplayMode(DWORD  dwWidthIn,   DWORD  dwHeightIn, DWORD dwDepth,
                                DWORD* pdwWidthOut, DWORD* pdwHeightOut)
{
    struct tDisplayModes*   pDisplayModes;
    int     i;
    BOOL    bFound = FALSE;
    DWORD   dwBestWidth  = 10000;
    DWORD   dwBestHeight = 10000;
    DWORD   dwBiggestWidth  = 0;
    DWORD   dwBiggestHeight = 0;

    if (dwDepth == 15)
        dwDepth = 16;

    pDisplayModes = DirectDraw_GetDisplayModes();

retray:
    for (i = 0; i < pDisplayModes->m_nNumModes; i++)
    {
        if (dwDepth != pDisplayModes->m_Modes[i].m_dwBPP)
            continue;

        /* Find a mode big enough for input size. */
        if (dwWidthIn  <= pDisplayModes->m_Modes[i].m_dwWidth
        &&  dwHeightIn <= pDisplayModes->m_Modes[i].m_dwHeight)
        {
            /* Get the smallest display size. */
            if (pDisplayModes->m_Modes[i].m_dwWidth  < dwBestWidth
            ||  pDisplayModes->m_Modes[i].m_dwHeight < dwBestHeight)
            {
                dwBestWidth  = pDisplayModes->m_Modes[i].m_dwWidth;
                dwBestHeight = pDisplayModes->m_Modes[i].m_dwHeight;
                bFound = TRUE;
            }
        }

        /*
            Keep track of the biggest size in case
            we can't find a mode that works.
        */
        if (dwBiggestWidth  < pDisplayModes->m_Modes[i].m_dwWidth
        ||  dwBiggestHeight < pDisplayModes->m_Modes[i].m_dwHeight)
        {
            dwBiggestWidth  = pDisplayModes->m_Modes[i].m_dwWidth;
            dwBiggestHeight = pDisplayModes->m_Modes[i].m_dwHeight;
        }
    }

    if (bFound)
    {
        *pdwWidthOut  = dwBestWidth;
        *pdwHeightOut = dwBestHeight;
    }
    else
    {
        if (dwDepth == 32)
        {
            bFound = FALSE;
            dwBestWidth  = 10000;
            dwBestHeight = 10000;
            dwBiggestWidth  = 0;
            dwBiggestHeight = 0;
            dwDepth = 24;
            goto retray;
        }
        *pdwWidthOut  = dwBiggestWidth;
        *pdwHeightOut = dwBiggestHeight;
    }

    bytes_per_pixel = dwDepth / 8;

#if 0 //VERBOSE
    logerror("FindBestDisplayMode: dwWidthIn=%i dwHeightIn=%i dwDepth=%i *pdwWidthOut=%i *pdwHeightOut=%i\n", dwWidthIn, dwHeightIn, dwDepth, *pdwWidthOut, *pdwHeightOut);
#endif

    return bFound;
}

static BOOL FindDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwDepth)
{
    int     i;
    BOOL    bModeFound = FALSE;
    struct tDisplayModes*   pDisplayModes;

    pDisplayModes = DirectDraw_GetDisplayModes();

    if (dwDepth == 15)
        dwDepth = 16;

retray:
    for (i = 0; i < pDisplayModes->m_nNumModes; i++)
    {
        if (pDisplayModes->m_Modes[i].m_dwWidth  == dwWidth
        &&  pDisplayModes->m_Modes[i].m_dwHeight == dwHeight
        &&  pDisplayModes->m_Modes[i].m_dwBPP    == dwDepth)
        {
            bModeFound = TRUE;
            break;
        }
    }

    if (dwDepth == 32)
    {
        dwDepth = 24;
        goto retray;
    }

    bytes_per_pixel = dwDepth / 8;

    return bModeFound;
}

/*
    This function tries to find the best display mode.
*/
static void SelectDisplayMode(int width, int height, int depth)
{
    if (switch_resolution)
    {
        /* vector games use 640x480 as default */
        if (Machine->drv->video_attributes & VIDEO_TYPE_VECTOR)
        {
#ifdef NFILTER
            if(nfilter) {
                  screen_width  = 640 * 2 * stretch_scale;
                  screen_height = 480 * 2 * stretch_scale;
            }
            else {
                  screen_width  = 640 * (double_size ? 2 : 1) * stretch_scale;
                  screen_height = 480 * (double_size ? 2 : 1) * stretch_scale;
            }
#else
            screen_width  = 640 * (double_size ? 2 : 1) * stretch_scale;
            screen_height = 480 * (double_size ? 2 : 1) * stretch_scale;
#endif
        }
        else
        {
#ifdef NFILTER
            if ((double_size || nfilter) && !use_stretch)
#else
            if (double_size && !use_stretch)
#endif
            {
                BOOL bResult = FindBestDisplayMode(width, height, depth,
                                                   (DWORD *)&screen_width,
                                                   (DWORD *)&screen_height);
#ifdef NFILTER
                if (bResult == FALSE) {
                    double_size = FALSE;
                    nfilter = FALSE;
                }
#else
                if (bResult == FALSE)
                    double_size = FALSE;
#endif
            }

#ifdef NFILTER
            if ((!double_size && !nfilter) || use_stretch)
#else
            if (!double_size || use_stretch)
#endif
            {
                FindBestDisplayMode(width, height, depth,
                                    (DWORD *)&screen_width,
                                    (DWORD *)&screen_height);
            }
        }
    }
}


/*===========================================================================
    DirectDraw functions
 ==========================================================================*/

static void DrawSurface(int flag)
{
    HRESULT hResult;

    profiler_mark(PROFILER_BLIT);

    switch (flag)
    {
    case 0: /* draw direct */
#ifdef SAI
		if(double_filter) {
			hResult = IDirectDrawSurface2_Lock(pDDSBack, NULL, &blit_desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
			if (hResult == DDERR_SURFACELOST) IDirectDrawSurface2_Restore(pDDSBack);

			hResult = IDirectDrawSurface2_Lock(pDDScale, NULL, &Sxsai_desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
			if (hResult == DDERR_SURFACELOST) IDirectDrawSurface2_Restore(pDDScale);

			Scale2x(pBitmapOffset, nBitmapPitch, 0, Sxsai_desc.lpSurface, Sxsai_desc.lPitch,
					game_rect.m_Width, game_rect.m_Height, 0);
	            bliter(Sxsai_desc.lpSurface, blit_desc.lpSurface, Sxsai_desc.lPitch, blit_desc.lPitch, 
					game_rect.m_Width*2, game_rect.m_Height*2);
			UnlockSurface(pDDScale);
	            UnlockSurface(pDDSBack);
		}
		else {
			hResult = IDirectDrawSurface2_Lock(pDDSBack, NULL, &blit_desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
			if (hResult == DDERR_SURFACELOST) IDirectDrawSurface2_Restore(pDDSBack);

	            bliter(pBitmapOffset, blit_desc.lpSurface, nBitmapPitch, blit_desc.lPitch, 
					game_rect.m_Width, game_rect.m_Height);
	            UnlockSurface(pDDSBack);
		}
#else
        if (LockSurface(pDDSBack))
        {
            bliter(pBitmapOffset, pSurfaceBits, nBitmapPitch, nSurfacePitch, game_rect.m_Width, game_rect.m_Height);
            UnlockSurface(pDDSBack);
        }
#endif
        break;

    case 1: /* triple buffer or use back buffer */
        if (use_back_buffer)
        {
            hResult = IDirectDrawSurface2_Blt(pDDSPrimary,
                                              &rectPrimary,
                                              pDDSBack,
                                              &rectBack,
                                              DDBLT_WAIT,
                                              NULL);

            if (hResult == DDERR_SURFACELOST)
                IDirectDrawSurface2_Restore(pDDSPrimary);
        }
        else
        {
            hResult = IDirectDrawSurface2_Flip(pDDSFlip, NULL, flip_mode);

            if (hResult == DDERR_SURFACELOST)
                IDirectDrawSurface2_Restore(pDDSFlip);
        }
        break;

    case 2: /* triple buffer + hardware stretch */
        hResult = IDirectDrawSurface2_Flip(pDDSFlip, NULL, flip_mode);
        if (hResult == DDERR_SURFACELOST)
            IDirectDrawSurface2_Restore(pDDSFlip);
        break;
    }

    profiler_mark(PROFILER_END);
}


static void ClearSurface(IDirectDrawSurface *pddSurface)
{
    HRESULT hResult;
    DDBLTFX ddBltFX;

    memset(&ddBltFX, 0, sizeof(DDBLTFX));
    ddBltFX.dwSize = sizeof(DDBLTFX);

    hResult = IDirectDrawSurface2_Blt(pddSurface,
                                      NULL,
                                      NULL,
                                      NULL,
                                      DDBLT_WAIT | DDBLT_COLORFILL,
                                      &ddBltFX);

    if (hResult == DDERR_SURFACELOST)
        IDirectDrawSurface2_Restore(pddSurface);
}


static BOOL LockSurface(IDirectDrawSurface *pddSurface)
{
#ifndef SAI
    DDSURFACEDESC  ddSurfaceDesc;
#endif
    HRESULT        hResult;

#ifdef SAI
    blit_desc.dwSize = sizeof(blit_desc);

    hResult = IDirectDrawSurface2_Lock(pddSurface, NULL, &blit_desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
#else
    ddSurfaceDesc.dwSize = sizeof(ddSurfaceDesc);

    hResult = IDirectDrawSurface2_Lock(pddSurface, NULL, &ddSurfaceDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
#endif

    if (hResult == DDERR_SURFACELOST)
    {
        IDirectDrawSurface2_Restore(pddSurface);
        return FALSE;
    }

#ifndef SAI
    pSurfaceBits  = ddSurfaceDesc.lpSurface;
    nSurfacePitch = ddSurfaceDesc.lPitch;

    if (pddSurface == pDDSPrimary)
        pSurfaceBits += nSurfacePitch * rectPrimary.top + bytes_per_pixel * rectPrimary.left;
#endif

    return TRUE;
}


INLINE BOOL UnlockSurface(IDirectDrawSurface *pddSurface)
{
    return (IDirectDrawSurface2_Unlock(pddSurface, NULL) == DD_OK);
}


static BOOL RestoreSurface(void)
{
    HRESULT             hResult;
    LPDIRECTDRAWSURFACE pddSurface;

    pddSurface = pDDSFlip ? pDDSFlip : pDDSPrimary;

    hResult = IDirectDrawSurface2_IsLost(pddSurface);
    if (hResult == DDERR_SURFACELOST)
    {
        hResult = IDirectDrawSurface2_Restore(pddSurface);
        if (hResult != DD_OK)
            return FALSE;
    }

    hResult = IDirectDrawSurface2_IsLost(pDDSBack);
    if (hResult == DDERR_SURFACELOST)
    {
        hResult = IDirectDrawSurface2_Restore(pDDSBack);
        if (hResult != DD_OK)
            return FALSE;
    }

#ifdef SAI
    hResult = IDirectDrawSurface2_IsLost(pDDScale);
    if (hResult == DDERR_SURFACELOST)
    {
        hResult = IDirectDrawSurface2_Restore(pDDScale);
        if (hResult != DD_OK)
            return FALSE;
    }
#endif

    return TRUE;
}


static BOOL WaitVBlank(void)
{
    DWORD dwScanLine;
    BOOL  bResult;

    IDirectDraw2_GetVerticalBlankStatus(pDDraw, &bResult);
    if (bResult)
        return TRUE;

    IDirectDraw2_GetScanLine(pDDraw, &dwScanLine);
    if (dwScanLine >= lScanLineStart)
       return TRUE;
    else
       return FALSE;
}


static void CalcVBlank(void)
{
    HRESULT hResult;
    DWORD   dwScanLineMax;
    DWORD   dwTemp;

    hResult = IDirectDraw2_GetScanLine(pDDraw, &dwTemp);
    if (hResult == DD_OK)
    {
        dwScanLineMax = dwTemp;

        while (1)
        {
            IDirectDraw2_GetScanLine(pDDraw, &dwTemp);
            if (dwScanLineMax <= dwTemp)
                break;

            dwScanLineMax = dwTemp;
        }
        return;
    }

    video_sync = FALSE;
}


/*===========================================================================
    Windows message
 ==========================================================================*/

static void OnActivateApp(HWND hWnd, BOOL fActivate, DWORD dwThreadId)
{
    if (window_status & FLAG_INITIALIZING)
        return;

    if (fActivate && MAME32App.m_hWnd == hWnd)
    {
        if (RestoreSurface())
            SetAbsoluteForegroundWindow(hWnd);
        window_status &= ~FLAG_LOSTFORCUS;
    }
    else if (!fActivate)
    {
        window_status |= FLAG_LOSTFORCUS;
    }
}


static void OnSize(HWND hWnd, UINT state, int cx, int cy)
{
    if (window_status & FLAG_INITIALIZING)
        return;

    resized_width  = cx;
    resized_height = cy;

    if ((window_status & FLAG_MINIMIZED) && state == SIZE_RESTORED)
    {
        int draw_flag = 0;

        RestoreSurface();
        window_status &= ~FLAG_MINIMIZED;

        if (triple_buffer && use_back_buffer)
            DrawSurface(draw_flag++);

        if (triple_buffer || use_back_buffer)
            DrawSurface(draw_flag++);

        DrawSurface(draw_flag);
    }
    else if (!(window_status & FLAG_MINIMIZED) && state == SIZE_MINIMIZED)
    {
        window_status |= FLAG_MINIMIZED;
    }
}


static BOOL OnSetCursor(HWND hWnd, HWND hWndCursor, UINT codeHitTest, UINT msg)
{
    SetCursor(NULL);

    return TRUE;
}


static void OnSysCommand(HWND hWnd, UINT CmdID, int x, int y)
{
    options_type *o = &video_settings.osd_options;
    int change_display_mode = 0;
    int menu_update = 0;

    switch (CmdID)
    {
    case IDM_FULLSCREEN:
        change_display_mode = 2;
        break;

    case IDM_DOUBLE:
#ifdef SAI
	if(!double_filter) {
        o->double_size   = !o->double_size;
        change_display_mode = 1;
	}
#else
        o->double_size   = !o->double_size;
        change_display_mode = 1;
#endif
        break;

    case IDM_NOHSCANLINE:
    case IDM_NOVSCANLINE:
        o->hscanlines = FALSE;
        o->vscanlines = FALSE;
        change_display_mode = 1;
        break;

    case IDM_HSCANLINE0:
    case IDM_HSCANLINE25:
    case IDM_HSCANLINE50:
    case IDM_HSCANLINE75:
#ifdef SAI
	if(!double_filter) {
        o->hscanlines    = TRUE;
        o->vscanlines    = FALSE;
        o->double_size   = TRUE;
        o->sl_brightness = (CmdID - IDM_HSCANLINE0) * 25;
        change_display_mode = 1;
	}
#else
        o->hscanlines    = TRUE;
        o->vscanlines    = FALSE;
        o->double_size   = TRUE;
        o->sl_brightness = (CmdID - IDM_HSCANLINE0) * 25;
        change_display_mode = 1;
#endif
        break;

    case IDM_VSCANLINE0:
    case IDM_VSCANLINE25:
    case IDM_VSCANLINE50:
    case IDM_VSCANLINE75:
#ifdef SAI
	if(!double_filter) {
        o->hscanlines  = FALSE;
        o->vscanlines  = TRUE;
        o->double_size = TRUE;
        o->sl_brightness = (CmdID - IDM_VSCANLINE0) * 25;
        change_display_mode = 1;
	}
#else
        o->hscanlines  = FALSE;
        o->vscanlines  = TRUE;
        o->double_size = TRUE;
        o->sl_brightness = (CmdID - IDM_VSCANLINE0) * 25;
        change_display_mode = 1;
#endif
        break;

    case IDM_NOSTRETCH:
        o->hw_stretch    = FALSE;
#ifdef FSSTRETCH
        o->fat_mode      = FALSE;
#endif
        o->scale         = 1;
        change_display_mode = 1;
        break;

    case IDM_HWSTRETCH2X:
    case IDM_HWSTRETCH3X:
    case IDM_HWSTRETCH4X:
        o->hw_stretch    = TRUE;
        o->scale         = (CmdID - IDM_HWSTRETCH2X) + 2;
        change_display_mode = 1;
        break;

    case IDM_ASPECT:
        o->adjust_aspect = !adjust_aspect;
        change_display_mode = 1;
        break;

#ifdef FSSTRETCH
    case IDM_FAT_MODE:
        o->fat_mode = !fat_mode;
        o->hw_stretch       = TRUE;
        o->scale            = 2;
        change_display_mode = 1;
        break;
#endif

    case IDM_TBUFFER_OFF:
        o->use_triplebuf = FALSE;
        change_display_mode = 1;
        break;

    case IDM_TBUFFER_WAIT:
        o->use_triplebuf = TRUE;
        o->tbvsync       = TRUE;
        menu_update = 1;
        break;

    case IDM_TBUFFER_NOWAIT:
        o->use_triplebuf = TRUE;
        o->tbvsync       = FALSE;
        menu_update = 1;
        break;

    case IDM_VSYNC:
        o->wait_vsync = !o->wait_vsync;
        video_sync    = !video_sync;
        menu_update = 1;
        break;

    case IDM_SLEEP:
        o->use_sleep = !o->use_sleep;
        menu_update = 1;
        break;

    case IDM_USE_SYSMEM:
        o->use_sysmem = !force_system_memory;
        change_display_mode = 1;
        break;

    case IDM_DDEMULATION:
        o->use_hel= !emulation_mode;
        change_display_mode = 1;
        break;

#ifdef SAI
    case IDM_DOUBLEF:
        o->double_filter   = !o->double_filter;
        change_display_mode = 1;
        break;
#endif
    }

    if (change_display_mode)
        ChangeDisplayMode(change_display_mode - 1);
    else if (menu_update)
        ApplyMenuItems();
}


static void ApplyMenuItems(void)
{
    options_type *o = &video_settings.osd_options;

    if (video_settings.attributes & VIDEO_TYPE_VECTOR)
        EnableMenuItem(hMenu, IDM_ASPECT, MF_GRAYED);

    if (hdouble)
    {
        EnableMenuItem(hPopup[0], IDM_NOHSCANLINE, MF_GRAYED);
        EnableMenuItem(hPopup[0], IDM_HSCANLINE0,  MF_GRAYED);
        EnableMenuItem(hPopup[0], IDM_HSCANLINE25, MF_GRAYED);
        EnableMenuItem(hPopup[0], IDM_HSCANLINE50, MF_GRAYED);
        EnableMenuItem(hPopup[0], IDM_HSCANLINE75, MF_GRAYED);
    }
    else if (vdouble)
    {
        EnableMenuItem(hPopup[1], IDM_NOVSCANLINE, MF_GRAYED);
        EnableMenuItem(hPopup[1], IDM_VSCANLINE0,  MF_GRAYED);
        EnableMenuItem(hPopup[1], IDM_VSCANLINE25, MF_GRAYED);
        EnableMenuItem(hPopup[1], IDM_VSCANLINE50, MF_GRAYED);
        EnableMenuItem(hPopup[1], IDM_VSCANLINE75, MF_GRAYED);
    }

    CheckMenuItem(hMenu,     IDM_DOUBLE,        (double_size || hdouble || vdouble) ? MF_CHECKED : MF_UNCHECKED);
#ifdef SAI
    CheckMenuItem(hMenu,     IDM_DOUBLEF,       (double_filter || hdouble || vdouble) ? MF_CHECKED : MF_UNCHECKED);
#endif
    CheckMenuItem(hMenu,     IDM_ASPECT,        adjust_aspect ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[0], IDM_NOHSCANLINE,   hscanlines ? MF_UNCHECKED : MF_CHECKED);
    CheckMenuItem(hPopup[0], IDM_HSCANLINE0,    (hscanlines && scanline_brightness == 0)  ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[0], IDM_HSCANLINE25,   (hscanlines && scanline_brightness == 25) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[0], IDM_HSCANLINE50,   (hscanlines && scanline_brightness == 50) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[0], IDM_HSCANLINE75,   (hscanlines && scanline_brightness == 75) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[1], IDM_NOVSCANLINE,   vscanlines  ? MF_UNCHECKED : MF_CHECKED);
    CheckMenuItem(hPopup[1], IDM_VSCANLINE0,    (vscanlines && scanline_brightness == 0)  ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[1], IDM_VSCANLINE25,   (vscanlines && scanline_brightness == 25) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[1], IDM_VSCANLINE50,   (vscanlines && scanline_brightness == 50) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[1], IDM_VSCANLINE75,   (vscanlines && scanline_brightness == 75) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[2], IDM_NOSTRETCH,     (stretch_scale == 1) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[2], IDM_HWSTRETCH2X,   (stretch_scale == 2 && use_stretch) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[2], IDM_HWSTRETCH3X,   (stretch_scale == 3 && use_stretch) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[2], IDM_HWSTRETCH4X,   (stretch_scale == 4 && use_stretch) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[3], IDM_TBUFFER_OFF,    o->use_triplebuf ? MF_UNCHECKED : MF_CHECKED);
    CheckMenuItem(hPopup[3], IDM_TBUFFER_WAIT,   (o->use_triplebuf && o->tbvsync) ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hPopup[3], IDM_TBUFFER_NOWAIT, (o->use_triplebuf && !o->tbvsync) ? MF_CHECKED : MF_UNCHECKED);
#ifdef FSSTRETCH
    CheckMenuItem(hMenu,     IDM_FAT_MODE,      fat_mode ? MF_CHECKED : MF_UNCHECKED);
#endif
    CheckMenuItem(hMenu,     IDM_VSYNC,          o->wait_vsync ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hMenu,     IDM_SLEEP,          o->use_sleep ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hMenu,     IDM_USE_SYSMEM,     force_system_memory ? MF_CHECKED : MF_UNCHECKED);
    CheckMenuItem(hMenu,     IDM_DDEMULATION,    emulation_mode ? MF_CHECKED : MF_UNCHECKED);
}
