// // DirectDraw class // #include "DebugOut.h" #include "DirectDraw.h" #include "COM.h" CDirectDraw DirectDraw; #define COMUSE TRUE #define DYNDLL FALSE CDirectDraw::BLTFUNC CDirectDraw::NormalBltTable[] = { &CDirectDraw::Render8bpp_Normal, &CDirectDraw::Render16bpp_Normal, &CDirectDraw::Render24bpp_Normal, &CDirectDraw::Render32bpp_Normal, }; CDirectDraw::BLTFUNC CDirectDraw::ScanlineBltTable[] = { &CDirectDraw::Render8bpp_Scanline, &CDirectDraw::Render16bpp_Scanline, &CDirectDraw::Render24bpp_Scanline, &CDirectDraw::Render32bpp_Scanline, }; CDirectDraw::BLTFUNC CDirectDraw::DoubleBltTable[] = { &CDirectDraw::Render8bpp_Double, &CDirectDraw::Render16bpp_Double, &CDirectDraw::Render24bpp_Double, &CDirectDraw::Render32bpp_Double, }; CDirectDraw::BLTFUNC CDirectDraw::DoubleScanlineBltTable[] = { &CDirectDraw::Render8bpp_DoubleScanline, &CDirectDraw::Render16bpp_DoubleScanline, &CDirectDraw::Render24bpp_DoubleScanline, &CDirectDraw::Render32bpp_DoubleScanline, }; CDirectDraw::BLTFUNC CDirectDraw::nx2xSaIBltTable[] = { &CDirectDraw::Render8bpp_Double, &CDirectDraw::nx_2xSaI_16bpp, &CDirectDraw::Render24bpp_Double, &CDirectDraw::nx_2xSaI_32bpp, }; CDirectDraw::BLTFUNC CDirectDraw::nxSuper2xSaIBltTable[] = { &CDirectDraw::Render8bpp_Double, &CDirectDraw::nx_Super2xSaI_16bpp, &CDirectDraw::Render24bpp_Double, &CDirectDraw::nx_Super2xSaI_32bpp, }; CDirectDraw::BLTFUNC CDirectDraw::nxSuperEagleBltTable[] = { &CDirectDraw::Render8bpp_Double, &CDirectDraw::nx_SuperEagle_16bpp, &CDirectDraw::Render24bpp_Double, &CDirectDraw::nx_SuperEagle_32bpp, }; CDirectDraw::BLTFUNC CDirectDraw::nxScale2xBltTable[] = { &CDirectDraw::Render8bpp_Double, &CDirectDraw::nx_Scale2x_16bpp, &CDirectDraw::Render24bpp_Double, &CDirectDraw::nx_Scale2x_32bpp, }; CDirectDraw::BLTFUNC CDirectDraw::nxHq2xBltTable[] = { &CDirectDraw::Render8bpp_Double, &CDirectDraw::nx_hq2x_16bpp, &CDirectDraw::Render24bpp_Double, &CDirectDraw::nx_hq2x_32bpp, }; CDirectDraw::BLTFUNC CDirectDraw::nxLq2xBltTable[] = { &CDirectDraw::Render8bpp_Double, &CDirectDraw::nx_lq2x_16bpp, &CDirectDraw::Render24bpp_Double, &CDirectDraw::nx_lq2x_32bpp, }; ////////////////////////////////////////////////////////////////////// // デフォルトパレット ////////////////////////////////////////////////////////////////////// CDirectDraw::PALBUF CDirectDraw::m_PalDefault[] = { 0x7F, 0x7F, 0x7F, 0x20, 0x00, 0xB0, 0x28, 0x00, 0xB8, 0x60, 0x10, 0xA0, 0x98, 0x20, 0x78, 0xB0, 0x10, 0x30, 0xA0, 0x30, 0x00, 0x78, 0x40, 0x00, 0x48, 0x58, 0x00, 0x38, 0x68, 0x00, 0x38, 0x6C, 0x00, 0x30, 0x60, 0x40, 0x30, 0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0xBC, 0xBC, 0x40, 0x60, 0xF8, 0x40, 0x40, 0xFF, 0x90, 0x40, 0xF0, 0xD8, 0x40, 0xC0, 0xD8, 0x40, 0x60, 0xE0, 0x50, 0x00, 0xC0, 0x70, 0x00, 0x88, 0x88, 0x00, 0x50, 0xA0, 0x00, 0x48, 0xA8, 0x10, 0x48, 0xA0, 0x68, 0x40, 0x90, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x60, 0xA0, 0xFF, 0x50, 0x80, 0xFF, 0xA0, 0x70, 0xFF, 0xF0, 0x60, 0xFF, 0xFF, 0x60, 0xB0, 0xFF, 0x78, 0x30, 0xFF, 0xA0, 0x00, 0xE8, 0xD0, 0x20, 0x98, 0xE8, 0x00, 0x70, 0xF0, 0x40, 0x70, 0xE0, 0x90, 0x60, 0xD0, 0xE0, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x90, 0xD0, 0xFF, 0xA0, 0xB8, 0xFF, 0xC0, 0xB0, 0xFF, 0xE0, 0xB0, 0xFF, 0xFF, 0xB8, 0xE8, 0xFF, 0xC8, 0xB8, 0xFF, 0xD8, 0xA0, 0xFF, 0xF0, 0x90, 0xC8, 0xF0, 0x80, 0xA0, 0xF0, 0xA0, 0xA0, 0xFF, 0xC8, 0xA0, 0xFF, 0xF0, 0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; ////////////////////////////////////////////////////////////////////// // キャラクタ ////////////////////////////////////////////////////////////////////// static BYTE lzSight[] = { #include "lzSight.h" }; static BYTE lzAscii[] = { #include "lzAscii.h" }; static BYTE lzTVlayer[] = { #include "lzTVlayer.h" }; // メモリから1バイト取ってくる static __inline INT mgetc( LPBYTE& inbuf, INT& bufsize ) { if( bufsize <= 0 ) return -1; bufsize--; return (INT)*inbuf++; } // // LZSS解凍ルーチン // #define N 4096 #define F 18 static void LZdecode( BYTE *inbuf, BYTE *outbuf, INT length ) { INT i, j, k, r, c; WORD flags; BYTE text[N+F-1]; INT outsize = 0; for( i = 0; i < N - F; i++ ) text[i] = 0; r = N - F; flags = 0; for(;;) { if( ((flags >>= 1) & 256) == 0 ) { if( (c = mgetc( inbuf, length )) < 0 ) break; flags = c | 0xff00; } if( flags & 1 ) { if( (c = mgetc( inbuf, length )) < 0 ) break; *outbuf++ = c; text[r++] = c; r &= (N-1); outsize++; } else { if( (i = mgetc( inbuf, length )) < 0 ) break; if( (j = mgetc( inbuf, length )) < 0 ) break; i |= ((j & 0xf0)<<4); j = (j & 0x0f)+2; for( k = 0; k <= j; k++ ) { c = text[(i+k) & (N-1)]; *outbuf++ = c; text[r++] = c; r &= (N-1); outsize++; } } } } ////////////////////////////////////////////////////////////////////// // 構築/消滅 ////////////////////////////////////////////////////////////////////// CDirectDraw::CDirectDraw() { // General m_hWnd = NULL; m_bUseHEL = FALSE; m_bSystemMemory = FALSE; m_bScreenMode = FALSE; m_bGDI = FALSE; m_bAspect = FALSE; m_bAllLine = FALSE; m_bMaxZoom = FALSE; m_bDoubleSize = FALSE; m_bTVFrameMode = FALSE; m_bScanlineMode = FALSE; m_nScanlineColor = 75; m_bZapper = FALSE; m_bZapperDraw = FALSE; m_ZapperPosX = m_ZapperPosY = -1; m_bWindowVSync = FALSE; m_bChangeMode = FALSE; m_bDraw = FALSE; m_bNoRestore = FALSE; // DirectDraw m_hDDraw = NULL; m_lpDD = NULL; m_lpDDPrimary = NULL; m_lpDDBack = NULL; m_lpDDRender = NULL; m_lpDDAscii = NULL; m_lpDDZapper = NULL; m_lpDDTV = NULL; m_lpDDClipper = NULL; m_lpDDClipper2 = NULL; m_lpDDPalette = NULL; m_lpRender = NULL; m_lpRenderDelta = NULL; m_bDeltaUpdate = FALSE; m_hPalette = NULL; m_DisplayModeNum = 0; m_bForceWrite = FALSE; // Filter m_nBltFilter = 0; // デフォルト解像度 m_dwDisplayWidth = 640; m_dwDisplayHeight = 480; m_dwDisplayDepth = 16; m_dwDisplayRate = 0; // リフレッシュレート指定無し // LineColormode ::memset( m_LineColormode, 0, sizeof(m_LineColormode) ); // パレット m_nPaletteMode = 0; m_bMonoMode = FALSE; ::memcpy( m_PaletteBuf, m_PalDefault, sizeof(m_PaletteBuf) ); ZEROMEMORY( m_cpPalette, sizeof(m_cpPalette) ); ZEROMEMORY( m_mpPalette, sizeof(m_mpPalette) ); ZEROMEMORY( m_cnPalette, sizeof(m_cnPalette) ); ZEROMEMORY( m_csPalette, sizeof(m_csPalette) ); ZEROMEMORY( m_mnPalette, sizeof(m_mnPalette) ); ZEROMEMORY( m_msPalette, sizeof(m_msPalette) ); // その他 m_bDiskAccessLamp = FALSE; ZEROMEMORY( m_szInfo, sizeof(m_szInfo) ); ZEROMEMORY( m_szMess, sizeof(m_szMess) ); // MMX detect { m_bMMX = FALSE; DWORD flag1, flag2; __asm { pushfd pop eax mov flag1, eax xor eax, 0x00200000 push eax popfd pushfd pop eax mov flag2, eax } if( flag1 != flag2 ) { DWORD flag; __asm { mov eax, 1 cpuid mov flag, edx } if( flag & 0x00800000 ) { m_bMMX = TRUE; } } } // TEST // m_nBltFilter = BLTFILTER_2XSAI; // m_nBltFilter = BLTFILTER_SUPER2XSAI; // m_nBltFilter = BLTFILTER_SUPEREAGLE; // m_nBltFilter = BLTFILTER_SCALE2X; #if COMUSE COM::AddRef(); #endif } CDirectDraw::~CDirectDraw() { ReleaseDDraw(); #if COMUSE COM::Release(); #endif } ////////////////////////////////////////////////////////////////////// // メンバ関数 ////////////////////////////////////////////////////////////////////// // コールバック関数 HRESULT WINAPI CDirectDraw::EnumModesCallback( LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext ) { // Thisポインタを受け取る CDirectDraw* pDD = (CDirectDraw*)lpContext; // 256x240以下の解像度は除外(ex. 320x200) if( lpDDSurfaceDesc->dwWidth < 256 || lpDDSurfaceDesc->dwHeight < 240 ) return DDENUMRET_OK; // 8,16,24,32bit以外は除外(4bitがあるね^^;) if( !(lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount == 8 || lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount == 16 || lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount == 24 || lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount == 32) ) return DDENUMRET_OK; // スクエアサイズの解像度以外は除外(ex. 640x400) (1280x1024は選択可能に) // if( lpDDSurfaceDesc->dwWidth*3 != lpDDSurfaceDesc->dwHeight*4 && !(lpDDSurfaceDesc->dwWidth == 1280 && lpDDSurfaceDesc->dwHeight == 1024) ) // return DDENUMRET_OK; // サイズ/ビット深度/リフレッシュレート/ピクセルフォーマットのコピー DISPLAYMODE mode; mode.dwWidth = lpDDSurfaceDesc->dwWidth; mode.dwHeight = lpDDSurfaceDesc->dwHeight; mode.dwDepth = lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount; mode.dwRate = lpDDSurfaceDesc->dwRefreshRate; pDD->m_DisplayModes.push_back( mode ); // 列挙数が超えた場合はキャンセル if( ++pDD->m_DisplayModeNum > CDirectDraw::DD_DISPLAYMODEMAX-1 ) { // DEBUGOUT( "CDirectDraw:Maximum display modes over.\n" ); return DDENUMRET_CANCEL; } return DDENUMRET_OK; } // DirectDrawの初期化 BOOL CDirectDraw::InitialDDraw( HWND hWnd ) { try { // DirectDrawオブジェクトの作成 #if !DYNDLL #if !COMUSE if( !m_bUseHEL ) { if( DirectDrawCreateEx(NULL, (LPVOID*)&m_lpDD, IID_IDirectDraw7, NULL) != DD_OK ) { m_lpDD = NULL; throw "CDirectDraw:DirectDrawCreateEx failed."; } } else { if( DirectDrawCreateEx((LPGUID)DDCREATE_EMULATIONONLY, (LPVOID*)&m_lpDD, IID_IDirectDraw7, NULL) != DD_OK ) { m_lpDD = NULL; throw "CDirectDraw:DirectDrawCreateEx failed."; } } #else // COM的利用(ライブラリをリンクするだけで起動が遅くなるので...) // COM::AddRef(); // CLSID_DirectDrawでは無くCLSID_DirectDraw7を使わないと駄目 if( ::CoCreateInstance( CLSID_DirectDraw7, NULL, CLSCTX_ALL, IID_IDirectDraw7, (LPVOID*)&m_lpDD ) != S_OK ) { m_lpDD = NULL; throw "CDirectDraw:DirectX 7.0 or greater is required."; // throw "CDirectDraw:CoCreateInstance failed."; } if( !m_bUseHEL ) { if( m_lpDD->Initialize( NULL ) != DD_OK ) throw "CDirectDraw:IDirectDraw7->Initialize failed."; } else { if( m_lpDD->Initialize( (LPGUID)DDCREATE_EMULATIONONLY ) != DD_OK ) // HEL throw "CDirectDraw:IDirectDraw7->Initialize failed."; } #endif #else // DLLを動的ロードして利用 if( !(m_hDDraw = ::LoadLibrary( "DDRAW.DLL" )) ) { throw "CDirectDraw:DirectX 7.0 or greater is required."; } typedef HRESULT(WINAPI * DIRECTDRAWCREATEEX)( GUID*, VOID**, REFIID, IUnknown* ); DIRECTDRAWCREATEEX DirectDrawCreateEx = (DIRECTDRAWCREATEEX)GetProcAddress( m_hDDraw, "DirectDrawCreateEx" ); if( !DirectDrawCreateEx ) { ::FreeLibrary( m_hDDraw ); m_hDDraw = NULL; throw "CDirectDraw:DirectX 7.0 or greater is required."; } if( !m_bUseHEL ) { if( DirectDrawCreateEx(NULL, (LPVOID*)&m_lpDD, IID_IDirectDraw7, NULL) != DD_OK ) { m_lpDD = NULL; throw "CDirectDraw:DirectX 7.0 or greater is required."; } } else { if( DirectDrawCreateEx((LPGUID)DDCREATE_EMULATIONONLY, (LPVOID*)&m_lpDD, IID_IDirectDraw7, NULL) != DD_OK ) { m_lpDD = NULL; throw "CDirectDraw:DirectX 7.0 or greater is required."; } } #endif // モニタ解像度の調査 DDSURFACEDESC2 ddsd; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); if( m_lpDD->GetDisplayMode( &ddsd ) != DD_OK ) throw "CDirectDraw:GetDisplayMode failed."; if( ddsd.ddpfPixelFormat.dwRGBBitCount < 8 ) throw "CDirectDraw:Unsupported display mode."; // 利用可能なディスプレイモードの取得 m_DisplayModeNum = 0; if( m_lpDD->EnumDisplayModes(DDEDM_REFRESHRATES, NULL, (LPVOID)this, (LPDDENUMMODESCALLBACK2)EnumModesCallback) != DD_OK ) throw "CDirectDraw:EnumDisplayModes failed."; if( !m_DisplayModeNum ) throw "CDirectDraw:No display modes available."; m_hWnd = hWnd; // デフォルトパレット設定 memcpy( m_PaletteBuf, m_PalDefault, sizeof(m_PalDefault) ); // Render screen if( !m_lpRender ) { if( !(m_lpRender = (LPBYTE)malloc( RENDER_WIDTH*RENDER_HEIGHT )) ) throw "CDirectDraw::Out of memory."; } ::memset( m_lpRender, 0x3F, RENDER_WIDTH*RENDER_HEIGHT ); // Render delta screen if( !m_lpRenderDelta ) { if( !(m_lpRenderDelta = (LPBYTE)malloc( DELTA_WIDTH*DELTA_HEIGHT*sizeof(DWORD) )) ) throw "CDirectDraw::Out of memory."; } ::memset( m_lpRenderDelta, 0xFF, DELTA_WIDTH*DELTA_HEIGHT*sizeof(DWORD) ); m_bDeltaUpdate = FALSE; // LineColormode ::memset( m_LineColormode, 0, sizeof(m_LineColormode) ); } catch( char *str ) { m_DisplayModeNum = 0; RELEASE( m_lpDD ); ::MessageBox( hWnd, str, "ERROR", MB_ICONERROR|MB_OK ); return FALSE; } return TRUE; } // DirectDrawの開放 void CDirectDraw::ReleaseDDraw() { ReleaseSurface(); if( m_lpDD ) { RELEASE( m_lpDD ); } #if COMUSE // COM::Release(); #endif #if DYNDLL if( m_hDDraw ) { m_hDDraw = NULL; ::FreeLibrary( m_hDDraw ); } #endif FREE( m_lpRenderDelta ); FREE( m_lpRender ); // m_hWnd = NULL; } // サーフェスの初期化 BOOL CDirectDraw::InitialSurface( BOOL bScreenMode ) { INT i; DDSURFACEDESC2 ddsd; DDSCAPS2 ddscaps; DDBLTFX ddbltfx; try { if( !m_lpDD ) throw "CDirectDraw:DirectDraw object uninitialized."; m_bGDI = FALSE; m_bScreenMode = bScreenMode; m_bMessage = FALSE; if( !m_bScreenMode ) { // ウインドウ // 協調モード if( m_lpDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL ) != DD_OK ) throw "CDirectDraw:SetCooperativeLevel failed."; // プライマリサーフェス ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; if( m_lpDD->CreateSurface( &ddsd, &m_lpDDPrimary, NULL ) != DD_OK ) throw "CDirectDraw:CreateSurface failed."; // クリッパーの作成 if( m_lpDD->CreateClipper( 0, &m_lpDDClipper, NULL ) != DD_OK ) throw "CDirectDraw:CreateClipper failed."; m_lpDDClipper->SetHWnd( 0, m_hWnd ); m_lpDDPrimary->SetClipper( m_lpDDClipper ); RELEASE( m_lpDDClipper ); } else { // フルスクリーン // 排他モード if( m_lpDD->SetCooperativeLevel( m_hWnd, DDSCL_ALLOWREBOOT|DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN ) != DD_OK ) throw "CDirectDraw:SetCooperativeLevel error"; // 画面解像度の設定 if( m_lpDD->SetDisplayMode( m_dwDisplayWidth, m_dwDisplayHeight, m_dwDisplayDepth, m_dwDisplayRate, DDSDM_STANDARDVGAMODE ) != DD_OK ) { // 失敗したらリフレッシュレート指定を無くしてもう一度やってみる if( m_lpDD->SetDisplayMode( m_dwDisplayWidth, m_dwDisplayHeight, m_dwDisplayDepth, 0, DDSDM_STANDARDVGAMODE ) != DD_OK ) { throw "CDirectDraw:SetDisplayMode failed."; } else { m_dwDisplayRate = 0; } } // プライマリサーフェスとバックサーフェスの作成 ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; if( m_lpDD->CreateSurface(&ddsd, &m_lpDDPrimary, NULL) != DD_OK ) throw "CDirectDraw:CreateSurface failed."; ZEROMEMORY( &ddscaps, sizeof(DDSCAPS2) ); ddscaps.dwCaps = DDSCAPS_BACKBUFFER; if( m_lpDDPrimary->GetAttachedSurface(&ddscaps, &m_lpDDBack) != DD_OK ) throw "CDirectDraw:GetAttachedSurface failed."; } // offscreen surface m_bForceWrite = FALSE; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; if( !m_bSystemMemory ) { ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; } else { ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; m_bForceWrite = TRUE; // 多段レンダリングしない } ddsd.dwWidth = SCREEN_WIDTH*2; ddsd.dwHeight = SCREEN_HEIGHT*2; if( m_lpDD->CreateSurface(&ddsd, &m_lpDDRender, NULL) != DD_OK ) { // システムメモリにも取れないってか.... if( ddsd.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) throw "CDirectDraw:CreateSurface failed."; // ビデオメモリに取れない時,しょうがないのでシステムメモリに取る ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; if( m_lpDD->CreateSurface(&ddsd, &m_lpDDRender, NULL) != DD_OK ) throw "CDirectDraw:CreateSurface failed."; m_bForceWrite = TRUE; // 多段レンダリングしない } if( !m_bSystemMemory ) { ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; } else { ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; } if( m_lpDD->CreateSurface(&ddsd, &m_lpDDRender2, NULL) != DD_OK ) { // システムメモリにも取れないってか.... if( ddsd.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) throw "CDirectDraw:CreateSurface failed."; // ビデオメモリに取れない時,しょうがないのでシステムメモリに取る ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; if( m_lpDD->CreateSurface(&ddsd, &m_lpDDRender2, NULL) != DD_OK ) throw "CDirectDraw:CreateSurface failed."; } typedef struct tagDDRGNDATA { RGNDATAHEADER rdh; RECT rect[8]; } DDRGNDATA; DDRGNDATA rgn; rgn.rdh.dwSize = sizeof(RGNDATAHEADER); rgn.rdh.iType = RDH_RECTANGLES; rgn.rdh.nCount = 1; rgn.rdh.nRgnSize = sizeof(RECT); rgn.rdh.rcBound.left = 0; rgn.rdh.rcBound.top = 0; rgn.rdh.rcBound.right = ddsd.dwWidth; rgn.rdh.rcBound.bottom = ddsd.dwHeight; rgn.rect[0].left = 0; rgn.rect[0].top = 0; rgn.rect[0].right = ddsd.dwWidth; rgn.rect[0].bottom = ddsd.dwHeight; // Rendering surface clipper if( m_lpDD->CreateClipper( 0, &m_lpDDClipper2, NULL ) != DD_OK ) throw "CDirectDraw:CreateClipper failed."; m_lpDDClipper2->SetClipList( (LPRGNDATA)&rgn, 0 ); m_lpDDRender->SetClipper( m_lpDDClipper2 ); // Ascii surface(6x6x64character) ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; // ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; ddsd.dwWidth = 6*8; ddsd.dwHeight = 6*8; if( m_lpDD->CreateSurface(&ddsd, &m_lpDDAscii, NULL) != DD_OK ) throw "CDirectDraw:CreateSurface failed."; // Color key DDCOLORKEY ddck; ZEROMEMORY( &ddck, sizeof(DDCOLORKEY) ); ddck.dwColorSpaceLowValue = 0; ddck.dwColorSpaceHighValue = 0; m_lpDDAscii->SetColorKey( DDCKEY_SRCBLT, &ddck ); // Zapper surface ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; // ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; ddsd.dwWidth = 16; ddsd.dwHeight = 16; if( m_lpDD->CreateSurface(&ddsd, &m_lpDDZapper, NULL) != DD_OK ) throw "CDirectDraw:CreateSurface failed."; // Color key ZEROMEMORY( &ddck, sizeof(DDCOLORKEY) ); ddck.dwColorSpaceLowValue = 0; ddck.dwColorSpaceHighValue = 0; m_lpDDZapper->SetColorKey( DDCKEY_SRCBLT, &ddck ); // TV ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; if( !m_bSystemMemory ) { ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; } else { ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; } ddsd.dwWidth = 512; ddsd.dwHeight = 480; if( m_lpDD->CreateSurface(&ddsd, &m_lpDDTV, NULL) != DD_OK ) { // システムメモリにも取れないってか.... if( ddsd.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY ) throw "CDirectDraw:CreateSurface failed."; // ビデオメモリに取れない時,しょうがないのでシステムメモリに取る ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; if( m_lpDD->CreateSurface(&ddsd, &m_lpDDTV, NULL) != DD_OK ) throw "CDirectDraw:CreateSurface failed."; } // Color key ZEROMEMORY( &ddck, sizeof(DDCOLORKEY) ); ddck.dwColorSpaceLowValue = 0; ddck.dwColorSpaceHighValue = 0; m_lpDDTV->SetColorKey( DDCKEY_SRCBLT, &ddck ); // DirectDraw/GDI Palette ZEROMEMORY( &m_logPalette, sizeof(m_logPalette) ); m_logPalette.palVersion = 0x0300; m_logPalette.palNumEntries = 256; HDC hdc = ::GetDC( NULL ); GetSystemPaletteEntries( hdc, 0, 256, m_logPalette.pe ); ReleaseDC( NULL, hdc ); for( i = 0; i < 10; i++ ) { m_logPalette.pe[i ].peFlags = PC_EXPLICIT; m_logPalette.pe[i+246].peFlags = PC_EXPLICIT; } for( i = 10; i < 246; i++ ) { m_logPalette.pe[i].peRed = 0; m_logPalette.pe[i].peGreen = 0; m_logPalette.pe[i].peBlue = 0; if( i >= 0x10 && i < 0x20 ) { m_logPalette.pe[i].peRed = (i-0x10)*0x10; m_logPalette.pe[i].peGreen = (i-0x10)*0x10; m_logPalette.pe[i].peBlue = (i-0x10)*0x10; m_logPalette.pe[i].peFlags = PC_RESERVED; } else if( i >= 0x40 && i < 0xC0 ) { m_logPalette.pe[i].peFlags = PC_RESERVED; } else { m_logPalette.pe[i].peFlags = PC_NOCOLLAPSE; } } // Surface clear ddbltfx.dwSize = sizeof(DDBLTFX); ddbltfx.dwFillColor = 0; if( m_lpDDBack ) { m_lpDDBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL|DDBLT_WAIT, &ddbltfx); } m_lpDDRender->Blt(NULL, NULL, NULL, DDBLT_COLORFILL|DDBLT_WAIT, &ddbltfx); m_lpDDRender2->Blt(NULL, NULL, NULL, DDBLT_COLORFILL|DDBLT_WAIT, &ddbltfx); // Palette object DDSURFACEDESC2 ddsd; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); m_lpDDPrimary->GetSurfaceDesc(&ddsd); if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 ) { if( !m_bScreenMode ) { if( (m_hPalette = CreatePalette( (LOGPALETTE *)&m_logPalette )) == NULL ) throw "CDirectDraw:CreatePalette failed."; } else { if( m_lpDD->CreatePalette( DDPCAPS_8BIT, m_logPalette.pe, &m_lpDDPalette, NULL ) != DD_OK ) throw "CDirectDraw:CreatePalette error"; if( m_lpDDPrimary->SetPalette( m_lpDDPalette ) != DD_OK ) throw "CDirectDraw:SetPalette failed."; } } // Palette calculate CalcPaletteTable(); // Palette Realize RealizePalette(); m_bPaletteUpdate = TRUE; // Character setup SetLZSSChar( lzAscii, m_lpDDAscii ); SetLZSSChar( lzSight, m_lpDDZapper ); SetLZSSChar( lzTVlayer, m_lpDDTV ); // 再描画の為 m_bDeltaUpdate = TRUE; } catch( char *str ) { ReleaseSurface(); // DEBUGOUT( "%s\n", str ); ::MessageBox( m_hWnd, str, "ERROR", MB_ICONERROR|MB_OK ); return FALSE; } // DEBUGOUT( "CDirectDraw:InitialSurface complete.\n" ); return TRUE; } // サーフェスの開放 BOOL CDirectDraw::ReleaseSurface( void ) { if( !m_lpDD ) return FALSE; GDIDELETE( m_hPalette ); RELEASE( m_lpDDPalette ); RELEASE( m_lpDDClipper2 ); RELEASE( m_lpDDClipper ); RELEASE( m_lpDDTV ); RELEASE( m_lpDDZapper ); RELEASE( m_lpDDAscii ); RELEASE( m_lpDDRender2 ); RELEASE( m_lpDDRender ); RELEASE( m_lpDDBack ); RELEASE( m_lpDDPrimary ); return TRUE; } // サーフェスのリストアサブ BOOL CDirectDraw::RestoreSurfaceSub( LPDIRECTDRAWSURFACE7 lpSurface ) { if( lpSurface ) { if( lpSurface->IsLost() == DDERR_SURFACELOST ) { // ロストしていたらリストアする // DEBUGOUT( "CDirectDraw:Restore surface...." ); if( lpSurface->Restore() == DD_OK ) { // DEBUGOUT( "Ok.\n" ); } else { // DEBUGOUT( "Failed.\n" ); } return FALSE; } } return TRUE; } // サーフェスのリストア BOOL CDirectDraw::RestoreSurface() { if( !m_lpDD ) return FALSE; if( m_bNoRestore ) return FALSE; BOOL bRet = TRUE; // ロストしてたら内容は失われているので描画をキャンセルしてね if( !RestoreSurfaceSub( m_lpDDRender ) ) { bRet = FALSE; } if( !RestoreSurfaceSub( m_lpDDRender2 ) ) { bRet = FALSE; } if( !RestoreSurfaceSub( m_lpDDBack ) ) { bRet = FALSE; } if( !RestoreSurfaceSub( m_lpDDPrimary ) ) { bRet = FALSE; } if( !RestoreSurfaceSub( m_lpDDAscii ) ) { SetLZSSChar( lzAscii, m_lpDDAscii ); bRet = FALSE; } if( !RestoreSurfaceSub( m_lpDDZapper ) ) { SetLZSSChar( lzSight, m_lpDDZapper ); bRet = FALSE; } if( !RestoreSurfaceSub( m_lpDDTV ) ) { SetLZSSChar( lzTVlayer, m_lpDDTV ); bRet = FALSE; } if( !bRet ) { // 再描画の為 m_bDeltaUpdate = TRUE; } return bRet; } // // ディスプレイモード変更開始 // BOOL CDirectDraw::BeginDisplayChange() { if( !m_lpDD ) return FALSE; // 既に変更中やないか if( m_bChangeMode ) return FALSE; // 変更中じゃ m_bChangeMode = TRUE; if( m_bScreenMode ) { m_lpDD->RestoreDisplayMode(); } // サーフェスの開放 ReleaseSurface(); // 協調モード m_lpDD->SetCooperativeLevel( NULL, DDSCL_NORMAL ); return TRUE; } // // ディスプレイモード変更終了とサーフェスの再構築 // BOOL CDirectDraw::EndDisplayChange() { if( !m_lpDD || !m_bChangeMode ) return FALSE; // Rebuild surface if( !InitialSurface( m_bScreenMode ) ) { m_bChangeMode = FALSE; return FALSE; } // Wait ::Sleep( 250 ); // Change mode complete m_bChangeMode = FALSE; return TRUE; } // // WM_DISPLAYCHANGEハンドラから呼ばれる // BOOL CDirectDraw::OnChangeDisplayMode() { // 自分自身で変更している時はキャンセル if( m_bChangeMode ) return TRUE; // DirectDrawオブジェクトが無ければ意味無し if( !m_lpDD ) return FALSE; // DEBUGOUT( "CDirectDraw:OnChangeDisplayMode\n" ); // 協調モードのチェック HRESULT hr = m_lpDD->TestCooperativeLevel(); if( !m_bScreenMode ) { // ウインドウ if( hr == DDERR_EXCLUSIVEMODEALREADYSET ) { // 他に排他モード野郎がおるのでおしまい // DEBUGOUT( "CDirectDraw:DDERR_EXCLUSIVEMODEALREADYSET\n" ); // リストアしちゃいやん m_bNoRestore = TRUE; return TRUE; } else if( hr == DDERR_WRONGMODE || hr == DD_OK ) { // 普通のディスプレイモードの変更(何故かWindowメッセージだとDD_OKな時がある) // DEBUGOUT( "CDirectDraw:DDERR_WRONGMODE\n" ); // リストアしてええよ m_bNoRestore = FALSE; // サーフェスの開放 ReleaseSurface(); // サーフェスの初期化 BOOL bRet = InitialSurface( m_bScreenMode ); if( bRet ) { // DEBUGOUT( "CDirectDraw:InitialSurface ok.\n" ); } else { // DEBUGOUT( "CDirectDraw:InitialSurface failed.\n" ); } return bRet; } else if( hr == DDERR_INVALIDOBJECT ) { // DEBUGOUT( "CDirectDraw:DDERR_INVALIDOBJECT\n" ); return FALSE; } else if( hr == DDERR_NOEXCLUSIVEMODE ) { // DEBUGOUT( "CDirectDraw:DDERR_NOEXCLUSIVEMODE\n" ); } else { // DEBUGOUT( "CDirectDraw:Unknown error. hr=%08Xた\n", hr ); } // 良く分からんのでとりあえずサーフェスをリストア m_bNoRestore = FALSE; RestoreSurface(); return TRUE; } else { // フルスクリーン if( hr == DDERR_NOEXCLUSIVEMODE ) { // フルスクリーンモードから抜けた時 // DEBUGOUT( "CDirectDraw:DDERR_NOEXCLUSIVEMODE\n" ); return TRUE; } if( hr == DD_OK ) { // リストアしろって事か... // サーフェスをリストア RestoreSurface(); return TRUE; } // 不明な原因 return FALSE; } return TRUE; } void CDirectDraw::SetDisplayMode( DWORD dwWidth, DWORD dwHeight, DWORD dwDepth, DWORD dwRate ) { m_dwDisplayWidth = dwWidth; m_dwDisplayHeight = dwHeight; m_dwDisplayDepth = dwDepth; m_dwDisplayRate = dwRate; } void CDirectDraw::GetDisplayMode( DWORD& dwWidth, DWORD& dwHeight, DWORD& dwDepth, DWORD& dwRate ) { dwWidth = m_dwDisplayWidth; dwHeight = m_dwDisplayHeight; dwDepth = m_dwDisplayDepth; dwRate = m_dwDisplayRate; } BOOL CDirectDraw::GetDisplayMode( INT no, DWORD& dwWidth, DWORD& dwHeight, DWORD& dwDepth, DWORD& dwRate ) { if( m_DisplayModes.size() < no ) return FALSE; dwWidth = m_DisplayModes[no].dwWidth; dwHeight = m_DisplayModes[no].dwHeight; dwDepth = m_DisplayModes[no].dwDepth; dwRate = m_DisplayModes[no].dwRate; return TRUE; } INT CDirectDraw::GetMatchDisplayMode( DWORD dwWidth, DWORD dwHeight, DWORD dwDepth, DWORD dwRate ) { for( int i = 0; i < m_DisplayModes.size(); i++ ) { if( m_DisplayModes[i].dwWidth == dwWidth || m_DisplayModes[i].dwHeight == dwHeight || m_DisplayModes[i].dwDepth == dwDepth || m_DisplayModes[i].dwRate == dwRate ) return i; } return -1; } BOOL CDirectDraw::IsNowDisplayMode( DWORD dwWidth, DWORD dwHeight, DWORD dwDepth, DWORD dwRate ) { if( m_dwDisplayWidth == dwWidth && m_dwDisplayHeight == dwHeight && m_dwDisplayDepth == dwDepth && m_dwDisplayRate == dwRate ) return TRUE; return FALSE; } // ビット位置の取得 void CDirectDraw::GetBitMask( DWORD val, int& shift, int& bits ) { shift = 0; while( !(val & (1<0) ) { bits--; } bits = bits - shift; } static float PalConvTbl[][3] = { 1.00f, 1.00f, 1.00f, 1.00f, 0.80f, 0.73f, 0.73f, 1.00f, 0.70f, 0.76f, 0.78f, 0.58f, 0.86f, 0.80f, 1.00f, 0.83f, 0.68f, 0.85f, 0.67f, 0.77f, 0.83f, 0.68f, 0.68f, 0.68f, // 1.00f, 1.00f, 1.00f, }; // パレットテーブルの計算 BOOL CDirectDraw::CalcPaletteTable() { INT i, j; if( !m_lpDD || !m_lpDDPrimary ) return FALSE; DDSURFACEDESC2 ddsd; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); ddsd.dwFlags = DDSD_PIXELFORMAT; if( m_lpDDPrimary->GetSurfaceDesc(&ddsd) != DD_OK ) throw "CDirectDraw:GetSurfaceDesc error"; INT Rbit, Gbit, Bbit; INT Rsft, Gsft, Bsft; if( ddsd.ddpfPixelFormat.dwRGBBitCount != 8 ) { GetBitMask( ddsd.ddpfPixelFormat.dwRBitMask, Rsft, Rbit ); GetBitMask( ddsd.ddpfPixelFormat.dwGBitMask, Gsft, Gbit ); GetBitMask( ddsd.ddpfPixelFormat.dwBBitMask, Bsft, Bbit ); } for( j = 0; j < 8; j++ ) { for( i = 0; i < 64; i++ ) { DWORD Rn, Gn, Bn; DWORD Rs, Gs, Bs; // Normal Rn = (DWORD)(PalConvTbl[j][0]*m_PaletteBuf[i].r); Gn = (DWORD)(PalConvTbl[j][1]*m_PaletteBuf[i].g); Bn = (DWORD)(PalConvTbl[j][2]*m_PaletteBuf[i].b); // Scanline Rs = (DWORD)(PalConvTbl[j][0]*m_PaletteBuf[i].r*m_nScanlineColor/100.0f); Gs = (DWORD)(PalConvTbl[j][1]*m_PaletteBuf[i].g*m_nScanlineColor/100.0f); Bs = (DWORD)(PalConvTbl[j][2]*m_PaletteBuf[i].b*m_nScanlineColor/100.0f); m_cpPalette[j][i+0x00].rgbRed = (BYTE)Rn; m_cpPalette[j][i+0x00].rgbGreen = (BYTE)Gn; m_cpPalette[j][i+0x00].rgbBlue = (BYTE)Bn; m_cpPalette[j][i+0x40].rgbRed = (BYTE)Rs; m_cpPalette[j][i+0x40].rgbGreen = (BYTE)Gs; m_cpPalette[j][i+0x40].rgbBlue = (BYTE)Bs; m_cnPalette[j][i] = ((Rn>>(8-Rbit))<>(8-Gbit))<>(8-Bbit))<>(8-Rbit))<>(8-Gbit))<>(8-Bbit))< Bsft ) { // RGB555->RGB888の時 m_cfPalette[j][i] = ((Rn>>(8-5))<<10)|((Gn>>(8-5))<<5)|((Bn>>(8-5))<<0); } else { // BGR555->BGR888の時 m_cfPalette[j][i] = ((Rn>>(8-5))<<0)|((Gn>>(8-5))<<5)|((Bn>>(8-5))<<10); } // Monochrome Rn = (DWORD)(m_PaletteBuf[i&0x30].r); Gn = (DWORD)(m_PaletteBuf[i&0x30].g); Bn = (DWORD)(m_PaletteBuf[i&0x30].b); Rn = Gn = Bn = (DWORD)(0.299f * Rn + 0.587f * Gn + 0.114f * Bn); Rn = (DWORD)(PalConvTbl[j][0]*Rn); Gn = (DWORD)(PalConvTbl[j][1]*Gn); Bn = (DWORD)(PalConvTbl[j][2]*Bn); if( Rn > 0xFF ) Rs = 0xFF; if( Gn > 0xFF ) Gs = 0xFF; if( Bn > 0xFF ) Bs = 0xFF; // Scanline Rs = (DWORD)(m_PaletteBuf[i&0x30].r*m_nScanlineColor/100.0f); Gs = (DWORD)(m_PaletteBuf[i&0x30].g*m_nScanlineColor/100.0f); Bs = (DWORD)(m_PaletteBuf[i&0x30].b*m_nScanlineColor/100.0f); Rs = Gs = Bs = (DWORD)(0.299f * Rs + 0.587f * Gs + 0.114f * Bs); Rs = (DWORD)(PalConvTbl[j][0]*Rs); Gs = (DWORD)(PalConvTbl[j][1]*Gs); Bs = (DWORD)(PalConvTbl[j][2]*Bs); if( Rs > 0xFF ) Rs = 0xFF; if( Gs > 0xFF ) Gs = 0xFF; if( Bs > 0xFF ) Bs = 0xFF; m_mpPalette[j][i+0x00].rgbRed = (BYTE)Rn; m_mpPalette[j][i+0x00].rgbGreen = (BYTE)Gn; m_mpPalette[j][i+0x00].rgbBlue = (BYTE)Bn; m_mpPalette[j][i+0x40].rgbRed = (BYTE)Rs; m_mpPalette[j][i+0x40].rgbGreen = (BYTE)Gs; m_mpPalette[j][i+0x40].rgbBlue = (BYTE)Bs; m_mnPalette[j][i] = ((Rn>>(8-Rbit))<>(8-Gbit))<>(8-Bbit))<>(8-Rbit))<>(8-Gbit))<>(8-Bbit))< Bsft ) { // RGB555->RGB888の時 m_mfPalette[j][i] = ((Rn>>(8-5))<<10)|((Gn>>(8-5))<<5)|((Bn>>(8-5))<<0); } else { // BGR555->BGR888の時 m_mfPalette[j][i] = ((Rn>>(8-5))<<0)|((Gn>>(8-5))<<5)|((Bn>>(8-5))<<10); } } } // 再描画の為 m_bDeltaUpdate = TRUE; return TRUE; } // パレットテーブルの設定 void CDirectDraw::SetPaletteTable( LPBYTE pal ) { if( pal ) memcpy( m_PaletteBuf, pal, sizeof(m_PaletteBuf) ); else memcpy( m_PaletteBuf, m_PalDefault, sizeof(m_PaletteBuf) ); CalcPaletteTable(); m_bPaletteUpdate = TRUE; } // パレットテーブルの設定 void CDirectDraw::SetPaletteTable( RGBQUAD* rgb ) { for( INT i = 0; i < 64; i++ ) { m_PaletteBuf[i].r = rgb[i].rgbRed; m_PaletteBuf[i].g = rgb[i].rgbGreen; m_PaletteBuf[i].b = rgb[i].rgbBlue; } CalcPaletteTable(); m_bPaletteUpdate = TRUE; } // パレットテーブルの取得 void CDirectDraw::GetPaletteTable( RGBQUAD* rgb ) { for( INT i = 0; i < 64; i++ ) { rgb[i].rgbRed = m_PaletteBuf[i].r; rgb[i].rgbGreen = m_PaletteBuf[i].g; rgb[i].rgbBlue = m_PaletteBuf[i].b; rgb[i].rgbReserved = 0; } } // パレットファイルの更新 void CDirectDraw::SetPaletteFile( LPCTSTR fname ) { // パレットファイルの更新 if( strlen( fname ) > 0 ) { FILE *fp; if( (fp = ::fopen( fname, "rb" )) ) { BYTE palbuf[192]; // サイズ分読み込み if( ::fread( palbuf, 192, 1, fp ) == 1 ) { // パレットの変更と計算 SetPaletteTable( palbuf ); } else { // 読みきれなかった時はデフォルト SetPaletteTable( (LPBYTE)NULL ); } FCLOSE(fp); } else { // 開けなかった時はデフォルト SetPaletteTable( (LPBYTE)NULL ); } } else { // 名前が無い時はデフォルト SetPaletteTable( (LPBYTE)NULL ); } } // フルスクリーンモードでのGDIウインドウ表示設定 BOOL CDirectDraw::SetFullScreenGDI( BOOL bMode ) { // 念の為チェック if( !m_lpDD || !m_lpDDPrimary ) return FALSE; if( m_bScreenMode ) { if( !m_bGDI ) { if( bMode ) { RELEASE( m_lpDDClipper ); // 一応 if( m_lpDD->CreateClipper(0, &m_lpDDClipper, NULL) == DD_OK ) { m_lpDDClipper->SetHWnd( 0, m_hWnd ); m_lpDDPrimary->SetClipper( m_lpDDClipper ); if( m_lpDD->FlipToGDISurface() == DD_OK ) { m_bGDI = TRUE; } else { RELEASE( m_lpDDClipper ); return FALSE; } } } } else { if( !bMode ) { RELEASE( m_lpDDClipper ); m_bGDI = FALSE; } } } return TRUE; } void CDirectDraw::RealizePalette() { if( !m_lpDD || !m_lpDDPrimary ) return; if( !m_bScreenMode ) { DDSURFACEDESC2 ddsd; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); m_lpDDPrimary->GetSurfaceDesc(&ddsd); if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 ) { HDC hdc; hdc = ::GetDC( m_hWnd ); ::SelectPalette( hdc, m_hPalette, FALSE ); ::RealizePalette( hdc ); ::ReleaseDC( m_hWnd, hdc ); m_bPaletteUpdate = TRUE; } } } // 描画(Windowsメッセージ用) void CDirectDraw::OnScreenDraw() { if( !m_bScreenMode ) { // Window mode Blt(); Flip(); } else { // Fullscreen mode if( m_bGDI ) { Blt(); Flip(); } } } void CDirectDraw::SetPaletteMode( INT nMode, BOOL bMono ) { if( (m_nPaletteMode != nMode) || (m_bMonoMode != bMono) ) { m_bPaletteUpdate = TRUE; } m_nPaletteMode = nMode; m_bMonoMode = bMono; } // 表示中のパレットテーブルの取得 void CDirectDraw::GetPaletteData( RGBQUAD* rgb ) { if( !m_bMonoMode ) { for( INT i = 0; i < 64; i++ ) { rgb[i ] = m_cpPalette[m_nPaletteMode][i]; rgb[i+0x40] = m_mpPalette[m_nPaletteMode][i]; } } else { for( INT i = 0; i < 64; i++ ) { rgb[i ] = m_mpPalette[m_nPaletteMode][i]; rgb[i+0x40] = m_mpPalette[m_nPaletteMode][i]; } } } void CDirectDraw::GetPaletteData2( RGBQUAD* rgb ) { for( INT j = 0; j < 8; j++ ) { for( INT i = 0; i < 64; i++ ) { rgb[j*256+i ] = m_cpPalette[j][i]; rgb[j*256+i+0x40] = m_mpPalette[j][i]; } } } void CDirectDraw::Blt() { INT i; DDSURFACEDESC2 ddsd; if( !m_lpDD || !m_lpDDPrimary ) return; // ScreenMode changing? if( m_bChangeMode ) return; // Surface lost check & restore if( !RestoreSurface() ) return; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); if( m_lpDDPrimary->GetSurfaceDesc(&ddsd) != DD_OK ) return; // Palette copy if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 ) { static BYTE linecolor = 0; if( m_LineColormode[1] != linecolor ) { linecolor = m_LineColormode[1]; m_bPaletteUpdate = TRUE; } if( !(m_LineColormode[1]&0x80) ) { for( i = 0; i < 128; i++ ) { m_logPalette.pe[i+0x40].peRed = m_cpPalette[m_nPaletteMode][i].rgbRed; m_logPalette.pe[i+0x40].peGreen = m_cpPalette[m_nPaletteMode][i].rgbGreen; m_logPalette.pe[i+0x40].peBlue = m_cpPalette[m_nPaletteMode][i].rgbBlue; } } else { for( i = 0; i < 128; i++ ) { m_logPalette.pe[i+0x40].peRed = m_mpPalette[m_nPaletteMode][i].rgbRed; m_logPalette.pe[i+0x40].peGreen = m_mpPalette[m_nPaletteMode][i].rgbGreen; m_logPalette.pe[i+0x40].peBlue = m_mpPalette[m_nPaletteMode][i].rgbBlue; } } if( !m_bScreenMode ) { ::AnimatePalette( m_hPalette, 0, 256, m_logPalette.pe ); } } // Size calculate BOOL bDoubleWidth = FALSE; BOOL bDoubleHeight = FALSE; RECT rcW; rcW.left = 0; rcW.top = 0; rcW.right = SCREEN_WIDTH; rcW.bottom = SCREEN_HEIGHT; if( m_bDoubleSize || (m_nBltFilter && IsMMX()) ) { rcW.right *= 2; rcW.bottom *= 2; bDoubleWidth = TRUE; bDoubleHeight = TRUE; } else if( m_bScanlineMode ) { rcW.bottom *= 2; bDoubleHeight = TRUE; } // Render function BLTFUNC* bltfunc; if( !m_nBltFilter || !IsMMX() ) { if( !m_bDoubleSize ) { if( !m_bScanlineMode ) { bltfunc = NormalBltTable; } else { bltfunc = ScanlineBltTable; } } else { if( !m_bScanlineMode ) { bltfunc = DoubleBltTable; } else { bltfunc = DoubleScanlineBltTable; } } } else { switch( m_nBltFilter ) { case BLTFILTER_2XSAI: bltfunc = nx2xSaIBltTable; break; case BLTFILTER_SUPER2XSAI: bltfunc = nxSuper2xSaIBltTable; break; case BLTFILTER_SUPEREAGLE: bltfunc = nxSuperEagleBltTable; break; case BLTFILTER_SCALE2X: bltfunc = nxScale2xBltTable; break; case BLTFILTER_HQ2X: bltfunc = nxHq2xBltTable; break; case BLTFILTER_LQ2X: bltfunc = nxLq2xBltTable; break; default: break; } } BOOL bFilter = FALSE; LPBYTE lpRdr = m_lpRender+8; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); if( m_bForceWrite ) { // 多段レンダリング無し if( m_lpDDRender->Lock( NULL, &ddsd, 0, NULL ) == DD_OK ) { switch( ddsd.ddpfPixelFormat.dwRGBBitCount ) { case 8: (this->*bltfunc[0])( lpRdr, &m_lpRenderDelta[DELTA_WIDTH*2*sizeof(DWORD)], ddsd, TRUE ); break; case 16: (this->*bltfunc[1])( lpRdr, &m_lpRenderDelta[DELTA_WIDTH*2*sizeof(DWORD)], ddsd, TRUE ); break; case 24: (this->*bltfunc[2])( lpRdr, &m_lpRenderDelta[DELTA_WIDTH*2*sizeof(DWORD)], ddsd, TRUE ); break; case 32: (this->*bltfunc[3])( lpRdr, &m_lpRenderDelta[DELTA_WIDTH*2*sizeof(DWORD)], ddsd, TRUE ); break; default: break; } m_lpDDRender->Unlock( NULL ); m_bDeltaUpdate = FALSE; } } else { if( m_lpDDRender2->Lock( NULL, &ddsd, 0, NULL ) == DD_OK ) { switch( ddsd.ddpfPixelFormat.dwRGBBitCount ) { case 8: (this->*bltfunc[0])( lpRdr, &m_lpRenderDelta[DELTA_WIDTH*2*sizeof(DWORD)], ddsd, m_bDeltaUpdate ); break; case 16: (this->*bltfunc[1])( lpRdr, &m_lpRenderDelta[DELTA_WIDTH*2*sizeof(DWORD)], ddsd, m_bDeltaUpdate ); break; case 24: (this->*bltfunc[2])( lpRdr, &m_lpRenderDelta[DELTA_WIDTH*2*sizeof(DWORD)], ddsd, m_bDeltaUpdate ); break; case 32: (this->*bltfunc[3])( lpRdr, &m_lpRenderDelta[DELTA_WIDTH*2*sizeof(DWORD)], ddsd, m_bDeltaUpdate ); break; default: break; } m_lpDDRender2->Unlock( NULL ); m_bDeltaUpdate = FALSE; m_lpDDRender->Blt( &rcW, m_lpDDRender2, &rcW, 0, NULL ); } } // TV枠 if( m_bTVFrameMode ) { m_lpDDRender->Blt( &rcW, m_lpDDTV, NULL, DDBLT_KEYSRC, NULL ); } // Infomation string if( strlen(m_szInfo) > 0 ) { INT x, y, o; x = bDoubleWidth ? 16 : 8; o = m_bAllLine ? 0 : 8; y = bDoubleHeight ? 8+o*2 : 4+o; RenderString( x, y, m_szInfo ); } // Message string if( m_bMessage ) { if( timeGetTime()-m_dwMessageTime > 1500 ) { m_bMessage = FALSE; } if( strlen(m_szMess) > 0 ) { INT x, y, o; x = bDoubleWidth ? 16 : 8; o = m_bAllLine ? 8 : 0; y = bDoubleHeight ? (SCREEN_HEIGHT*2-36+o*2) : (SCREEN_HEIGHT-18+o); RenderString( x, y, m_szMess ); } } // DiskAccessLamp if( m_bDiskAccessLamp ) { INT x, y, o; x = bDoubleWidth ? SCREEN_WIDTH*2-20 : SCREEN_WIDTH-10; o = m_bAllLine ? 0 : 8; y = bDoubleHeight ? 8+o*2 : 4+o; RenderString( x, y, "\\" ); } if( m_bZapper && m_bZapperDraw ) { if( m_ZapperPosX >= 0 && m_ZapperPosX < SCREEN_WIDTH && m_ZapperPosY >= 0 && m_ZapperPosY < SCREEN_HEIGHT ) { RECT rcS, rcZ; SetRect( &rcZ, 0, 0, 16, 16 ); if( !bDoubleWidth ) { rcS.left = m_ZapperPosX-(rcZ.right-rcZ.left)/2; rcS.right = m_ZapperPosX+(rcZ.right-rcZ.left)/2; } else { rcS.left = m_ZapperPosX*2-(rcZ.right-rcZ.left); rcS.right = m_ZapperPosX*2+(rcZ.right-rcZ.left); } if( !bDoubleHeight ) { rcS.top = m_ZapperPosY-(rcZ.bottom-rcZ.top)/2; rcS.bottom = m_ZapperPosY+(rcZ.bottom-rcZ.top)/2; } else { rcS.top = m_ZapperPosY*2-(rcZ.bottom-rcZ.top); rcS.bottom = m_ZapperPosY*2+(rcZ.bottom-rcZ.top); } m_lpDDRender->Blt( &rcS, m_lpDDZapper, &rcZ, DDBLT_KEYSRC, NULL ); } } } void CDirectDraw::Flip() { if( !m_lpDD || !m_lpDDPrimary ) return; // ScreenMode changing? if( m_bChangeMode ) return; // Surface lost check & restore if( !RestoreSurface() ) return; DDSURFACEDESC2 ddsd; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); m_lpDDPrimary->GetSurfaceDesc(&ddsd); // Size calculate BOOL bDoubleWidth = FALSE; BOOL bDoubleHeight = FALSE; if( m_bDoubleSize || (m_nBltFilter && IsMMX()) ) { bDoubleWidth = TRUE; bDoubleHeight = TRUE; } else if( m_bScanlineMode ) { bDoubleHeight = TRUE; } RECT rcS, rcC; if( !bDoubleWidth ) { rcS.left = 0; rcS.right = SCREEN_WIDTH; } else { rcS.left = 0; rcS.right = SCREEN_WIDTH*2; } if( !m_bAllLine ) { rcS.top = 8; rcS.bottom = SCREEN_HEIGHT-8; } else { rcS.top = 0; rcS.bottom = SCREEN_HEIGHT; } if( bDoubleHeight ) { rcS.top *= 2; rcS.bottom *= 2; } if( !m_bScreenMode ) { // Window mode ::GetClientRect( m_hWnd, &rcC ); ::ClientToScreen( m_hWnd, (POINT*)&rcC.left ); ::ClientToScreen( m_hWnd, (POINT*)&rcC.right ); if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 ) { HDC hdc; if( m_lpDDPrimary->GetDC( &hdc ) == DD_OK ) { ::SelectPalette( hdc, m_hPalette, FALSE ); ::RealizePalette( hdc ); m_lpDDPrimary->ReleaseDC( hdc ); } } } else { // Fullscreen mode if( !m_bMaxZoom ) { DDBLTFX ddbltfx; ddbltfx.dwSize = sizeof(DDBLTFX); ddbltfx.dwFillColor = 0; m_lpDDBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL|DDBLT_WAIT, &ddbltfx); // Position offset caluclate LONG swidth, sheight; LONG dwidth, dheight; LONG hmul, vmul; if( !m_bAspect ) swidth = SCREEN_WIDTH; else swidth = 320; if( !m_bAllLine ) sheight = SCREEN_HEIGHT-16; else sheight = SCREEN_HEIGHT; dwidth = (LONG)ddsd.dwWidth; dheight = (LONG)ddsd.dwHeight; hmul = dwidth / swidth; vmul = dheight / sheight; if( vmul < hmul ) hmul = vmul; else vmul = hmul; rcC.left = (dwidth -swidth *hmul)/2; rcC.top = (dheight-sheight*vmul)/2; rcC.right = rcC.left+swidth *hmul; rcC.bottom = rcC.top +sheight*vmul; } else { // Maximum zoom rcC.left = 0; rcC.top = 0; rcC.right = (LONG)ddsd.dwWidth; rcC.bottom = (LONG)ddsd.dwHeight; } } if( !m_bScreenMode ) { // Window mode if( m_bWindowVSync ) { HRESULT hr; while( TRUE ) { hr = m_lpDD->WaitForVerticalBlank( DDWAITVB_BLOCKBEGIN, NULL ); if( hr == DD_OK ) break; if( hr == DDERR_SURFACELOST ) { break; } if( hr != DDERR_WASSTILLDRAWING ) { break; } } // m_lpDDPrimary->Blt( NULL, m_lpDDBack, NULL, DDBLT_WAIT, NULL ); } m_lpDDPrimary->Blt( &rcC, m_lpDDRender, &rcS, DDBLT_WAIT, NULL ); if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 ) { if( m_bPaletteUpdate ) { m_bPaletteUpdate = FALSE; ::AnimatePalette( m_hPalette, 0, 256, m_logPalette.pe ); } } } else { // Fullscreen mode m_lpDDBack->Blt( &rcC, m_lpDDRender, &rcS, DDBLT_WAIT, NULL ); if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 ) { if( m_bPaletteUpdate ) { m_bPaletteUpdate = FALSE; m_lpDDPalette->SetEntries( 0, 0, 256, m_logPalette.pe ); } } if( m_bFlip ) { if( !m_bGDI ) { HRESULT hr; while( TRUE ) { hr = m_lpDDPrimary->Flip( NULL, DDFLIP_WAIT ); if( hr == DD_OK ) break; if( hr == DDERR_SURFACELOST ) { break; } if( hr != DDERR_WASSTILLDRAWING ) { break; } } } else { HRESULT hr; while( TRUE ) { hr = m_lpDD->WaitForVerticalBlank( DDWAITVB_BLOCKBEGIN, NULL ); if( hr == DD_OK ) break; if( hr == DDERR_SURFACELOST ) { break; } if( hr != DDERR_WASSTILLDRAWING ) { break; } } m_lpDDPrimary->Blt( NULL, m_lpDDBack, NULL, DDBLT_WAIT, NULL ); } } else { m_lpDDPrimary->Blt( NULL, m_lpDDBack, NULL, DDBLT_WAIT, NULL ); } } } BYTE CDirectDraw::GetZapperHit() { if( m_bZapper ) { if( m_ZapperPosX >= 0 && m_ZapperPosX < SCREEN_WIDTH && m_ZapperPosY >= 0 && m_ZapperPosY < SCREEN_HEIGHT ) { BYTE c = m_lpRender[8+m_ZapperPosX+RENDER_WIDTH*m_ZapperPosY]; DWORD Yn = (DWORD)(0.299f * m_cpPalette[0][c].rgbRed + 0.587f * m_cpPalette[0][c].rgbGreen + 0.114f * m_cpPalette[0][c].rgbBlue); if( Yn > 0xFF ) Yn = 0xFF; return (BYTE)Yn; } } return 0x00; } void CDirectDraw::GetZapperPos( LONG& x, LONG& y ) { x = y = -1; if( !m_lpDD || !m_lpDDPrimary ) return; // ScreenMode changing? if( m_bChangeMode ) return; if( !m_bZapper ) return; RECT rcS, rcC; // Size calculate rcS.left = 0; rcS.right = SCREEN_WIDTH; if( !m_bAllLine ) { rcS.top = 8; rcS.bottom = SCREEN_HEIGHT-8; } else { rcS.top = 0; rcS.bottom = SCREEN_HEIGHT; } if( m_bScanlineMode ) { rcS.top *= 2; rcS.bottom *= 2; } if( !m_bScreenMode ) { // Window mode ::GetClientRect( m_hWnd, &rcC ); ::ClientToScreen( m_hWnd, (POINT*)&rcC.left ); ::ClientToScreen( m_hWnd, (POINT*)&rcC.right ); } else { // Fullscreen mode DDSURFACEDESC2 ddsd; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); if( m_lpDDPrimary->GetSurfaceDesc(&ddsd) != DD_OK ) return; if( !m_bMaxZoom ) { // Position offset caluclate LONG swidth, sheight; LONG dwidth, dheight; LONG hmul, vmul; if( !m_bAspect ) swidth = SCREEN_WIDTH; else swidth = 320; if( !m_bAllLine ) sheight = SCREEN_HEIGHT-16; else sheight = SCREEN_HEIGHT; dwidth = (LONG)ddsd.dwWidth; dheight = (LONG)ddsd.dwHeight; hmul = dwidth / swidth; vmul = dheight / sheight; if( vmul < hmul ) hmul = vmul; else vmul = hmul; rcC.left = (dwidth -swidth *hmul)/2; rcC.top = (dheight-sheight*vmul)/2; rcC.right = rcC.left+swidth *hmul; rcC.bottom = rcC.top +sheight*vmul; } else { // Maximum zoom rcC.left = 0; rcC.top = 0; rcC.right = (LONG)ddsd.dwWidth; rcC.bottom = (LONG)ddsd.dwHeight; } } POINT mp; FLOAT hz, vz; ::GetCursorPos( &mp ); if( mp.x >= rcC.left && mp.x < rcC.right && mp.y >= rcC.top && mp.y < rcC.bottom ) { hz = (FLOAT)(rcS.right-rcS.left)/(rcC.right-rcC.left); vz = (FLOAT)(rcS.bottom-rcS.top)/(rcC.bottom-rcC.top); x = (LONG)((mp.x-rcC.left)*hz)+rcS.left; if( !m_bScanlineMode ) { y = (LONG)((mp.y-rcC.top) *vz)+rcS.top; } else { y = (LONG)(((mp.y-rcC.top) *vz)+rcS.top)/2; } if( x > SCREEN_WIDTH-1 ) x = SCREEN_WIDTH-1; if( y > SCREEN_HEIGHT-1 ) y = SCREEN_HEIGHT-1; } else { x = y = -1; } m_ZapperPosX = x; m_ZapperPosY = y; } void CDirectDraw::SetZapperPos( LONG x, LONG y ) { m_ZapperPosX = x; m_ZapperPosY = y; } // Infomation string void CDirectDraw::SetInfoString( LPCSTR str ) { if( str ) { if( strlen(str) > INFOSTR_SIZE ) { memcpy( m_szInfo, str, INFOSTR_SIZE ); m_szInfo[INFOSTR_SIZE] = '\0'; } else { strcpy( m_szInfo, str ); } } else { m_szInfo[0] = '\0'; } } // Message string void CDirectDraw::SetMessageString( LPCSTR str ) { if( str ) { if( strlen(str) > INFOSTR_SIZE ) { memcpy( m_szMess, str, INFOSTR_SIZE ); m_szMess[INFOSTR_SIZE] = '\0'; } else { strcpy( m_szMess, str ); } m_bMessage = TRUE; m_dwMessageTime = ::timeGetTime(); } else { m_bMessage = FALSE; m_szMess[0] = '\0'; } } void CDirectDraw::RenderString( INT x, INT y, LPCSTR str ) { if( !m_lpDD || !m_lpDDPrimary ) return; // ScreenMode changing? if( m_bChangeMode ) return; if( !str ) return; // Size calculate BOOL bDoubleWidth = FALSE; BOOL bDoubleHeight = FALSE; if( m_bDoubleSize || (m_nBltFilter && IsMMX()) ) { bDoubleWidth = TRUE; bDoubleHeight = TRUE; } else if( m_bScanlineMode ) { bDoubleHeight = TRUE; } RECT rcS, rcW; INT ch; INT xadd; rcW.left = x; rcW.top = y; if( !bDoubleWidth ) { rcW.right = x+6; xadd = 6; } else { rcW.right = x+12; xadd = 12; } if( !bDoubleHeight ) { rcW.bottom = y+6; } else { rcW.bottom = y+12; } while( *str ) { ch = toupper(*str)-0x20; rcS.left = (ch%8)*6; rcS.right = rcS.left+6; rcS.top = (ch/8)*6; rcS.bottom = rcS.top+6; m_lpDDRender->Blt( &rcW, m_lpDDAscii, &rcS, DDBLT_KEYSRC, NULL ); rcW.left += xadd; rcW.right += xadd; str++; } } // LZSS BMPからサーフェスへのコピー void CDirectDraw::SetLZSSChar( LPBYTE lpLZ, LPDIRECTDRAWSURFACE7 lpDDSurface ) { LPBYTE lpBuf = NULL; LPBITMAPINFOHEADER pbi; LPBYTE lpPix; HDC hDC; if( !(lpBuf = (LPBYTE)malloc( *((LONG*)lpLZ) )) ) throw "Out of memory."; LZdecode( &lpLZ[8], lpBuf, *((LONG*)&lpLZ[4]) ); pbi = (LPBITMAPINFOHEADER)lpBuf; if( pbi->biBitCount < 16 ) lpPix = ((LPBYTE)pbi)+pbi->biSize+(1<biBitCount)*sizeof(RGBQUAD); else lpPix = (LPBYTE)pbi+pbi->biSize; DDSURFACEDESC2 ddsd; ZEROMEMORY( &ddsd, sizeof(DDSURFACEDESC2) ); ddsd.dwSize = sizeof(DDSURFACEDESC2); lpDDSurface->GetSurfaceDesc(&ddsd); // BMPは高さがマイナスな事があるので.... LONG height = pbi->biHeight; if( height < 0 ) height = -height; if( lpDDSurface->GetDC( &hDC ) == DD_OK ) { StretchDIBits( hDC, 0, 0, ddsd.dwWidth, ddsd.dwHeight, 0, 0, pbi->biWidth, height, lpPix, (LPBITMAPINFO)lpBuf, DIB_RGB_COLORS, SRCCOPY ); lpDDSurface->ReleaseDC( hDC ); } FREE( lpBuf ); } BYTE CDirectDraw::GetPixel( INT x, INT y ) { if( x >= 0 && x < SCREEN_WIDTH && y >= 0 && y < SCREEN_HEIGHT ) { BYTE c = m_lpRender[8+(x)+RENDER_WIDTH*y]; return c; } return 0x00; } #include "Render.h"