📄 ddcompo.cpp
字号:
/////////////
// DDCompo.cpp : v0043
// Written by : Liu Gang
// Compiler : Microsoft Visual C++ 4.0 & DirectX
// Library : DDraw.Lib
// Copyright (C) : 1996 WayAhead Corporation
// v0020 : Nov.12.1996
// v0030 : Dec.11.1996, upgrade to DirectDraw 2.0 or higher
// v0031 : Jan.22.1997, fix one reported bug, and change something in SetRange()
// v0040 : Feb.13.1997, changed some cursor functions, deleted surface m_lpSpriteBuffer
// v0041 : Mar.5.1997, add member m_bShow and function Show()
// v0042 : Mar.22.1997, add some global functions for cursor
// Fixed a bug when cursor is animating, add Erase() to CDDCursor
// v0043 : Apr.9.1997, changed the name of one of cursor's member m_bCreated to m_bCreatedC
/////////////
// implementation file
// DirectDraw components
// mouse cursor, framerate, etc
// 此文件与DDAPI结合比较紧密,使用了一些DDAPI的全局变量
#include "stdafx.h"
#include "Assert.h" // ErrorMessage(), Assert()
#include "DDCompo.h"
#include "mmsystem.h"
#include "L_Allbmp.h"
//////////////////////////////
// globals
//////////////////////////////
// mouse cursor
class CDDCursor *DDC_pCursor = NULL; // current mouse cursor pointer
// MMX Cheater
extern MAIN_bMMX;
/////////
/////////
// frame rate
class CDDSurface DDC_sFrameRate;
#ifdef _DEBUG
BOOL DDC_bShowFrameRate=TRUE;
#else
BOOL DDC_bShowFrameRate=FALSE;
#endif
DWORD DDC_dwFrameCount;
DWORD DDC_dwFrameTime;
DWORD DDC_dwFrames;
// display functions
#ifdef _CURSOR_OLD_VERSION_
// sprite的显示范围
RECT DDC_rcSpriteRange={0,0,SCREEN_WIDTH, SCREEN_HEIGHT};
// max size of each sprite
// sprite的矩形乘2或新旧位置的总矩形不能大于此值,用于优化显示
SIZE DDC_szSpriteMax={320, 200};
#endif // _CURSOR_OLD_VERSION_
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// frame rate
/////////////////////////
// load frame rate file
// filename : bitmap file to display framerate
// return value : TRUE if succeeded
BOOL DDC_LoadFrameRate( LPCTSTR filename )
{
DDC_dwFrameTime = timeGetTime();
// no color key, in system memory
if( !DDC_sFrameRate.LoadBitmap( filename, FALSE, FALSE ) )
return FALSE;
return TRUE;
}
// set if should show frame rate
// bShow : TRUE for show frame rate
void DDC_ShowFrameRate( BOOL bShow/* = TRUE */)
{
DDC_bShowFrameRate = bShow;
DDC_dwFrameCount = 0;
DDC_dwFrameTime = timeGetTime();
// update screen
RECT rect;
SetRect( &rect, 0, 0, 96, 16 );
DDC_UpdateScreen( &rect );
}
// show display frame rate
void DDC_DisplayFrameRate( void )
{
DWORD time2;
static DWORD dwFramesLast;
if( !DDC_bShowFrameRate ) return;
DDC_dwFrameCount++;
time2 = timeGetTime() - DDC_dwFrameTime;
dwFramesLast = DDC_dwFrames;
if( time2 > 1000 )
{
DDC_dwFrames = (DDC_dwFrameCount*1000)/time2;
DDC_dwFrameTime = timeGetTime();
DDC_dwFrameCount = 0;
}
if( DDC_dwFrames >999999 ) DDC_dwFrames = 999999;
// drawing
if( dwFramesLast == DDC_dwFrames ) return;
/*
//--- MMX Cheater --- Liu Gang
if( !MAIN_bMMX )
{
if( DDC_dwFrames < 5 ) DDC_dwFrames -= 1;
else if( DDC_dwFrames < 10 ) DDC_dwFrames -= 2;
else if( DDC_dwFrames < 20 ) DDC_dwFrames -= 4;
else if( DDC_dwFrames < 30 ) DDC_dwFrames -= 6;
else if( DDC_dwFrames < 40 ) DDC_dwFrames -= 8;
if( DDC_dwFrames <= 0 ) DDC_dwFrames = 1;
}
//--- MMX Cheater ---
*/
DWORD dwFrames = DDC_dwFrames;
// update to front buffer
for ( int i=0; i< 6; i++ )
{
int num = dwFrames%10;
RECT rect;
POINT ptDest;
rect.top = 0;
rect.bottom = 16;
rect.left = 16*num;
rect.right = rect.left + 16;
ptDest.x = 16*5-16*i, ptDest.y = 0;
DDC_sFrameRate.BltToFront( ptDest, &rect );
dwFrames = dwFrames/10;
}
}
// get frame rate
int DDC_GetFrameRate()
{
return DDC_dwFrames;
}
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// cursor
// constructor
CDDCursor::CDDCursor()
{
m_bCreatedC = FALSE;
m_bShow = TRUE;
#ifdef _CURSOR_OLD_VERSION_
m_lpSpriteBuffer = NULL; // Sprite buffer
#endif // _CURSOR_OLD_VERSION_
m_lpMixBuffer = NULL; // mix buffer
m_szSize.cx = 0, m_szSize.cy = 0;
GetCursorPos( &m_ptPos );
m_rcRange.left = 0,
m_rcRange.top = 0,
m_rcRange.right = SCREEN_WIDTH,
m_rcRange.bottom = SCREEN_HEIGHT;
m_nState = DDC_CURSOR_STATE_NORMAL;
m_nStateLast = DDC_CURSOR_STATE_NORMAL;
m_nFrame = 0;
m_nFrameLast = 0;
m_nSpeed = 5;
for( int i=0; i<DDC_CURSOR_STATE_MAX; i++ )
{
m_ptHotspot[i].x = 15,
m_ptHotspot[i].y = 15;
}
for( int j=0; j<DDC_CURSOR_STATE_MAX; j++ )
m_nFrameCount[j] = 1;
}
// destructor
CDDCursor::~CDDCursor()
{
Release();
}
// load cursor
// create cursor
// filename : cursor bitmap filename
// nCol : cursor state, 横向排列在位图中,大小一样, cannot be zero
// nRow : cursor frame, 纵向排列在位图中,动画鼠标的每一帧, cannot be zero
// return value : TRUE if succeeded
BOOL CDDCursor::Load( LPCTSTR filename, int nCol/*=1*/, int pnRow[]/*=NULL*/, POINT pptHotspot[]/*=NULL*/ )
{
// load bitmap from file
// has color key, auto
if( GetSurface() )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+7, "cannot load cursor twice!" );
return FALSE;
}
// has color key, in system memory
if( !LoadBitmap( filename, TRUE, FALSE ) )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+0, "Cannot open cursor bitmap file! ", filename );
return FALSE;
}
// set members
// set size of cursor
m_szSize = GetSize();
// set frame counters, rows per column
int nRowMax=1;
if( pnRow )
{
for( int i=0; i<nCol; i++ )
{
m_nFrameCount[i] = pnRow[i];
if( nRowMax < m_nFrameCount[i] )
nRowMax = m_nFrameCount[i];
}
}
// set hotspots of cursor in each state
if( pptHotspot )
{
for( int i=0; i<nCol; i++ )
{
m_ptHotspot[i] = pptHotspot[i];
}
}
if( nCol == 0 )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+1, "Column cannot be zero!" );
return FALSE;
}
if( nRowMax == 0 )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+2, "Any row cannot be zero!" );
return FALSE;
}
m_szSize.cy /= nCol;
m_szSize.cx /= nRowMax;
// create mix buffer
BOOL retrn;
if( m_lpMixBuffer )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+4, "cannot load cursor mix buffer twice!" );
return FALSE;
}
m_lpMixBuffer = new CDDSurface;
// no color key, in system memory
retrn = m_lpMixBuffer->Create( m_szSize.cx*2, m_szSize.cy*2, FALSE, FALSE );
if( !retrn )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+3, "Cannot create mix buffer for cursor!" );
return FALSE;
}
#ifdef _CURSOR_OLD_VERSION_
// create sprite buffer
if( m_lpSpriteBuffer )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+5, "Cannot create cursor sprite buffer twice!" );
return FALSE;
}
m_lpSpriteBuffer = new CDDSurface;
// no color key, in system memory
retrn = m_lpSpriteBuffer->Create( DDC_szSpriteMax.cx, DDC_szSpriteMax.cy, FALSE, FALSE );
if( !retrn )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+6, "Cannot create sprite buffer for cursor!" );
return FALSE;
}
#endif // _CURSOR_OLD_VERSION_
m_bCreatedC = TRUE;
return TRUE;
}
// load cursor
// create cursor
// filename : cursor bitmap compact file
// nIndex : index number in compact file
// nCol : cursor state, 横向排列在位图中,大小一样, cannot be zero
// nRow : cursor frame, 纵向排列在位图中,动画鼠标的每一帧, cannot be zero
// return value : TRUE if succeeded
BOOL CDDCursor::LoadEx( LPSTR filename, LPSTR fileIndex, int nIndex, int nCol/*=1*/, int pnRow[]/*=NULL*/, POINT pptHotspot[]/*=NULL*/ )
{
// load bitmap from file
// has color key, auto
if( GetSurface() )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+7, "cannot load cursor twice!" );
return FALSE;
}
class CPicture_imageall picture;
picture.image_open_compress(filename);
picture.image_open_index(fileIndex);
picture.LoadBitmap( this, nIndex );
picture.image_close_index();
picture.image_close_compress();
SetColorKeyRGB( RGB(0,0,0) );
// set members
// set size of cursor
m_szSize = GetSize();
// set frame counters, rows per column
int nRowMax=1;
if( pnRow )
{
for( int i=0; i<nCol; i++ )
{
m_nFrameCount[i] = pnRow[i];
if( nRowMax < m_nFrameCount[i] )
nRowMax = m_nFrameCount[i];
}
}
// set hotspots of cursor in each state
if( pptHotspot )
{
for( int i=0; i<nCol; i++ )
{
m_ptHotspot[i] = pptHotspot[i];
}
}
if( nCol == 0 )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+1, "Column cannot be zero!" );
return FALSE;
}
if( nRowMax == 0 )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+2, "Any row cannot be zero!" );
return FALSE;
}
m_szSize.cy /= nCol;
m_szSize.cx /= nRowMax;
// create mix buffer
BOOL retrn;
if( m_lpMixBuffer )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+4, "cannot load cursor mix buffer twice!" );
return FALSE;
}
m_lpMixBuffer = new CDDSurface;
// no color key, in system memory
retrn = m_lpMixBuffer->Create( m_szSize.cx*2, m_szSize.cy*2, FALSE, FALSE );
if( !retrn )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+3, "Cannot create mix buffer for cursor!" );
return FALSE;
}
#ifdef _CURSOR_OLD_VERSION_
// create sprite buffer
if( m_lpSpriteBuffer )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+5, "Cannot create cursor sprite buffer twice!" );
return FALSE;
}
m_lpSpriteBuffer = new CDDSurface;
// no color key, in system memory
retrn = m_lpSpriteBuffer->Create( DDC_szSpriteMax.cx, DDC_szSpriteMax.cy, FALSE, FALSE );
if( !retrn )
{
ErrorMessage( hwndGame, DDC_ERROR_ID+6, "Cannot create sprite buffer for cursor!" );
return FALSE;
}
#endif // _CURSOR_OLD_VERSION_
m_bCreatedC = TRUE;
return TRUE;
}
// release cursor
void CDDCursor::Release()
{
CDDSurface::Release();
#ifdef _CURSOR_OLD_VERSION_
if( m_lpSpriteBuffer )
{
m_lpSpriteBuffer->Release();
delete m_lpSpriteBuffer;
m_lpSpriteBuffer = NULL;
}
#endif // _CURSOR_OLD_VERSION_
if( m_lpMixBuffer )
{
m_lpMixBuffer->Release();
delete m_lpMixBuffer;
m_lpMixBuffer = NULL;
}
m_bCreatedC = FALSE;
}
// set cursor moving range
// this may effects other cursor's range
// rcRange : new range for mouse moving in
// return value : old range for mouse moving in
// Warning : A bug report here:
// Cannot erase old cursor if change range in run time
// but this be fixed on Jan.22.1997
RECT CDDCursor::SetRange( CONST RECT *lprcRange )
{
RECT rcRangeOld;
rcRangeOld.left = m_rcRange.left,
rcRangeOld.top = m_rcRange.top,
rcRangeOld.right = m_rcRange.right,
rcRangeOld.bottom = m_rcRange.bottom;
// erase cursor in old position
if( m_bCreatedC )
DD_UpdateScreen( &GetRect() );
m_rcRange.left = lprcRange->left,
m_rcRange.top = lprcRange->top,
m_rcRange.right = lprcRange->right,
m_rcRange.bottom = lprcRange->bottom;
// set cursor moving range
ClipCursor( &m_rcRange );
// redraw it right now
if( m_bCreatedC )
Draw( TRUE );
return rcRangeOld;
}
// change cursor to next frame when display
void CDDCursor::Animate()
{
Assert( m_bCreatedC );
static int nTimer=0;
nTimer ++;
if( nTimer >= m_nSpeed )
{
nTimer = 0;
m_nFrameLast = m_nFrame;
m_nFrame = ( m_nFrame+1 )%m_nFrameCount[m_nState];
}
Draw( TRUE );
}
// set cursor state
// nState : new state
// return value : old state
int CDDCursor::SetState( int nState )
{
if( m_bCreatedC )
{
Erase(); // erase old
}
m_nStateLast = m_nState;
m_nState = nState;
// reset frame
m_nFrameLast = m_nFrame; m_nFrame = 0;
if( m_bCreatedC )
{
// Draw( TRUE ); // draw new
}
return m_nStateLast;
}
// set cursor frame
// nFrame : new frame
// return value : old frame
int CDDCursor::SetFrame( int nFrame )
{
m_nFrameLast = m_nFrame;
m_nFrame = nFrame;
if( m_bCreatedC )
Draw( TRUE );
return m_nFrameLast;
}
// set animate speed
// nSpeed : new speed
// return value : old speed
int CDDCursor::SetSpeed( int nSpeed )
{
int nSpeedLast = m_nSpeed;
m_nSpeed = nSpeed;
return nSpeedLast;
}
// get cursor rectangle
RECT CDDCursor::GetRect()
{
RECT rcDest;
rcDest.left = m_ptPos.x - m_ptHotspot[m_nState].x;
rcDest.top = m_ptPos.y - m_ptHotspot[m_nState].y;
rcDest.right = rcDest.left + m_szSize.cx;
rcDest.bottom = rcDest.top + m_szSize.cy;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -