DDraw笔记-创建表面

创建表面

创建DDraw对象和设置协作级别请看《一个简单的DDraw应用程序

设置模式

SetDisplayMode为设置视频模式的函数

 
  
HRESULT SetDisplayMode(
DWORD dwWidth,      // 屏幕宽
DWORD dwHeight, // 屏幕高
DWORD dwBPP, // 每个像素的位数, 8,16,24, 等.
DWORD dwRefreshRate, // 刷新频率,0为默认
DWORD dwFlags); // 标记字,一般为 0 即可

视频模式

Width

Height

BPP

Mode X

320

200

8

*

320

240

8

*

320

400

8

*

512

512

8,16,24,32

 

640

480

8,16,24,32

 

800

600

8,16,24,32

 

1024

768

8,16,24,32

 

1280

1024

8,16,24,32

 

设置模式源代码下载

色彩深度

现在用色彩深度多数为8、16、24、32

当选择8位的色彩深度的时候,我们需要一个调色板。

2011052114031547.png

调色板数据结构

先了解调色板数据结构:

 
  
typedef struct tagPALETTEENTRY
{
  BYTE peRed;
// red component 8-bits
  BYTE peGreen; // green component 8-bits
  BYTE peBlue; // blue component 8-bits
  BYTE peFlags; // 把这个标记设置为 PC_NOCOLLAPSE
} PALETTEENTRY;

要创建一个调色板只要定义下面这样的数组。

PALETTEENTRY palette[256];

然后填充这个数组,注意的是把peFlags设置为PC_NOCOLLAPSE,因为我们不想Win32/DirectX优化我们的调色板。

 
  
PALETTEENTRY palette[ 256 ]; // 调色板

// 初始化调色板数组

for ( int color = 1 ; color < 255 ; color ++ )

{
// 随机填充RGB值
palette[color].peRed = rand() % 256 ;
palette[color].peGreen
= rand() % 256 ;
palette[color].peBlue
= rand() % 256 ;
palette[color].peFlags
= PC_NOCOLLAPSE; // 不优化调色板
}


// 把0项填充为黑色
palette[ 0 ].peRed = 0 ;
palette[
0 ].peGreen = 0 ;
palette[
0 ].peBlue = 0 ;
palette[
0 ].peFlags = PC_NOCOLLAPSE;


// 把255项填充为白色
palette[ 255 ].peRed = 255 ;
palette[
255 ].peGreen = 255 ;
palette[
255 ].peBlue = 255 ;
palette[
255 ].peFlags = PC_NOCOLLAPSE;

创建调色板对象

 
 
 
  
HRESULT CreatePalette(
DWORD dwFlags,       
// 控制标记,见下面
LPPALETTEENTRY lpColorTable,          // 调色板数据指针,见上面
LPDIRECTDRAWPALETTE FAR * lplpDDPalette,    // 返回的调色板接口指针
IUnknown FAR * pUnkOuter);    // 传NULL即可
 

CreatePalette()控制标记 

描述

DDPCAPS_1BIT

1位色彩。色彩表包含2项

DDPCAPS_2BIT

2位色彩。色彩表包含4项

DDPCAPS_4BIT

4位色彩。色彩表包含16项

DDPCAPS_8BIT

8位色彩。色彩表包含256项.最常用

DDPCAPS_8BITENTRIES

用于一个称为索引调色板的高级我改,适用于1、2和4位调色板,在此我们只要设置为否

DDPCAPS_ALPHA

表示想关的PALETTEENTRY结构peFlags成员将被翻译成一个控制透明的8位alpha值。用这个标记创建 的调色板只配置能到一个用DDSCAPS_TEXTURE性能标记创建的D3D纹理表面

DDPCAPS_ALLOW256

表示这个调色板可以定义所有256个项。正常情况下,0项和255项分别相应地接收黑和白,并且在某些系统如NT上你在任何情况下都不能写这些项。然而,大多数情况下你不需要这个标记,因为为0项通常都是黑并且大多数调色板在255项为白的时候也能工作。

DDPCAPS_INITIALIZE

用lpDDColorArray传递的色彩数组中的色彩初始化调色板。使得调色板数据能被传递并下载到硬件调色板

DDPCAPS_PRIMARYSURFACE

这个调色板配置到主显示表面。改变调色板的色表会立即影响显示,除非DDPSETPAL_VSYNC是特定的值并受去拷的

DDPCAPS_VSYNC

强制调色板更新并只能在垂直的空白期执行。最小色彩异常和闪烁。不过还示获完全支持。

 
上面搞那么多控制标记,但一般是下面组合。
DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE
如果不考虑设置色彩项0和255可以忽略DDPCAPS_ALLOW256
如果CreatePalette()调用中没有传递调色板,可以忽略DDPCAPS_INITIALIZE
 
 
 
  
// 创建调色板对象
if (FAILED(lpdd -> CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE, palette, & lpddpal, NULL)))
{
return ( 0 );
}
 

创建显示表面

有两种显示表面:主显示表面从显示表面
主显示表面:直接对应于被视频卡光栅化的实际显存,且任何时候都是可见的。在任何DDraw程序里我们只能有一个主显示表面,它直接指向图像并常驻VRAM。
从显示表面:它可以是任意大小,可以驻留在VRAM或是系统内存,可以有任意多个。
 
 
创建一个表面只要再个步骤:
1.填充一个DDSURFACEDESC2数据结构,来描述创建的显示表面。
2.调用IDirectDraw7::CreateSurface()来创建显示表面。
 
 
  
/*
* DDSURFACEDESC2
*/
typedef
struct _DDSURFACEDESC2
{
DWORD dwSize;
// size of the DDSURFACEDESC structure
DWORD dwFlags; // determines what fields are valid
DWORD dwHeight; // height of surface to be created
DWORD dwWidth; // width of input surface
union
{
LONG lPitch;
// distance to start of next line (return value only)
DWORD dwLinearSize; // Formless late-allocated optimized surface size
} DUMMYUNIONNAMEN( 1 );
union
{
DWORD dwBackBufferCount;
// number of back buffers requested
DWORD dwDepth; // the depth if this is a volume texture
} DUMMYUNIONNAMEN( 5 );
union
{
DWORD dwMipMapCount;
// number of mip-map levels requestde
// dwZBufferBitDepth removed, use ddpfPixelFormat one instead
DWORD dwRefreshRate; // refresh rate (used when display mode is described)
DWORD dwSrcVBHandle; // The source used in VB::Optimize
} DUMMYUNIONNAMEN( 2 );
DWORD dwAlphaBitDepth;
// depth of alpha buffer requested
DWORD dwReserved; // reserved
LPVOID lpSurface; // pointer to the associated surface memory
union
{
DDCOLORKEY ddckCKDestOverlay;
// color key for destination overlay use
DWORD dwEmptyFaceColor; // Physical color for empty cubemap faces
} DUMMYUNIONNAMEN( 3 );
DDCOLORKEY ddckCKDestBlt;
// color key for destination blt use
DDCOLORKEY ddckCKSrcOverlay; // color key for source overlay use
DDCOLORKEY ddckCKSrcBlt; // color key for source blt use
union
{
DDPIXELFORMAT ddpfPixelFormat;
// pixel format description of the surface
DWORD dwFVF; // vertex format description of vertex buffers
} DUMMYUNIONNAMEN( 4 );
DDSCAPS2 ddsCaps;
// direct draw surface capabilities
DWORD dwTextureStage; // stage in multitexture cascade
} DDSURFACEDESC2;
 
这个结构值成员比较多。我们只要了解粗体部分即可。
dwSize:本结构自身的大小。
dwFlags:指示DDraw会把有次数拨款哪个域中或从哪个域查询数据。见下表。

DDSURFACEDESC2结构中dwFlags域的可选标志 

Value

Description

DDSD_ALPHABITDEPTH

表明dwAlphaBitDepth 成员有效.

DDSD_BACKBUFFERCOUNT

表明dwBackBufferCount 成员有效.

DDSD_CAPS

表明ddsCaps 成员有效.

DDSD_CKDESTBLT

表明ddckCKDestBlt 成员有效.

DDSD_CKDESTOVERLAY

表明ddckCKDestOverlay 成员有效.

DDSD_CKSRCBLT

表明ddckCKSrcBlt 成员有效.

DDSD_CKSRCOVERLAY

表明ddckCKSrcOverlay 成员有效.

DDSD_HEIGHT

表明dwHeight 成员有效.

DDSD_LINEARSIZE

表明dwLinearSize 成员有效.

DDSD_LPSURFACE

表明lpSurface 成员有效.

DDSD_MIPMAPCOUNT

表明dwMipMapCount 成员有效.

DDSD_PITCH

表明lPitch 成员有效.

DDSD_PIXELFORMAT

表明ddpfPixelFormat 成员有效.

DDSD_REFRESHRATE

表明dwRefreshRate 成员有效.

DDSD_TEXTURESTAGE

表明dwTextureStage 成员有效.

DDSD_WIDTH

表明dwWidth 成员有效.

 
dwHeight: 显示表面以像素计的宽度。
dwWidth:显示表面以像素计的高度。
lPitch:水平内存间距。它是该显式模式中每行上的字节数。注意:视VRAM的布局而定,lPitch可以是是任何值。因此当你倾向于逐行方总一个DDraw显示表面内存时,必须用lPitch来移到下一行,而不是用每像素字节数乘宽度。
dwBackBufferCount:后备缓冲或连锁于主显示表面的从属离屏切换缓冲的数目。
lpSurface:用于获取指向所创建的显示表面所驻留的实际内存的指针。
ddckCKDestBlt:目标色彩键。
ddckCKSrcBlt:源色彩键。
ddsCaps:返回所请求的显示表面的一些未在别处定义的属性。它也是一个结构体
 
 
 
  
typedef struct _DDSCAPS2
{
DWORD dwCaps;
// 见下表
DWORD dwCaps2; // 给3D内容伤脑筋
DWORD dwCaps3; // 保留值,不使用
DWORD dwCaps4; // 保留值,不使用
} DDSCAPS2, FAR* LPDDSCAPS2;
 

DDraw显示表面的功能控制设置

描述

DDSCAPS_BACKBUFFER

表示该显示表面的是一个平面翻转结构的后备缓冲

DDSCAPS_COMPLEX

表示正在描述一个复杂的显示表面,该表面拥有一个主表面缓冲和一或多个后备缓冲以生成翻转链

DDSCAPS_FLIP

表示该显示表面是一个平台翻转结构的一部分。当这个功能标记传递给CreateSurface方法时,将会创建 一个前端缓冲和一或多个后备缓冲

DDSCAPS_LOCALVIDMEM

表示该显示表面存在于真下的本地显存,而不是非本地显存中。如果指定该标记,DDSCAPS_VIDEOMEMORY也要指定。

DDSCAPS_MODEX

表示该显示表面是一个320*320或320*240ModelX显示平面

DDSCAPS_NONLOCALVIDMEM

表示该显示表面存在于非本地显存而非真正的本地显存中,如果批定了该标志DDSCAPS_VIDEOMEMORY不能要指定。

DDSCAPS_OFFSCREENPLAIN

表示该显示表面将一个离屏表面,不是一个特殊的表面,如覆盖、纹理、z-缓冲、前端缓冲、后端缓冲或是alpha缓冲平面。通常用于图元精灵(Sprite)

DDSCAPS_OWNDC

表示该显示表面uqf会长期有一个设备上下文关联

DDSCAPS_PRIMARYSURFACE

表示该显示表面是主显示表面,代表其时用户可见的内容

DDSCAPS_STANDARDVGAMODE

表示该表面是一个标准的VGA平面,而且不是一个ModelX平面些标记不能与DDSCAPS_MODEX标记同时使用

DDSCAPS_SYSTEMMEMORY

表示该显示表面内存从系统内存分配

DDSCAPS_VIDEOMEMORY

表示该显示表面存在于显存中

  
 
  
// 初始化ddsd

memset(
& ddsd, 0 , sizeof (ddsd));

ddsd.dwSize
= sizeof (ddsd);



ddsd.dwFlags
= DDSD_CAPS;

ddsd.ddsCaps.dwCaps
= DDSCAPS_PRIMARYSURFACE; // 创建主显示表面标志



// 创建主显示表面

if (FAILED(lpdd -> CreateSurface( & ddsd, & lpddsprimary, NULL)))

{

return ( 0 );

}

关联调色板

 
 
 
  
// 把调色板和主显示表面关联起来
if (FAILED(lpddsprimary -> SetPalette(lpddpal)))
{
return ( 0 );
}
 

加解锁

要访问任何显示表面—主显示表面、从显示表面等。必须 对内存加锁和解锁。没有任何保证 说VRAM会留在同样的地方。它可能是虚拟的,但对它上锁,它就会在锁住期间保持同样的地址空间以便控制。 
 
  
HRESULT Lock(
LPRECT lpDestRect,   
// 要上锁的Rect,整个表面上锁传
NULLLPDDSURFACEDESC2 lpDDSurfaceDesc, // 传递一个空的LPDDSURFACEDESC2DWORD
dwFlags,          // 标志见下表HANDLE
hEvent);          // 传 NULL
  

Lock()方法的控制标记

描述

DDLOCK_READONLY

表示被锁的显示表面的是只读的

DDLOCK_SURFACEMEMORYPTR

表示将要返回一个指向特定RECT顶部的有效的内存指针,如果没有指定矩形,将会返回一个指向显示表面顶部的指针

DDLOCK_WAIT

如果由于正在进行一个块传输操作而不能获得一个锁,该 方法会重试直到得到锁或是有另外的错误发生,如DDERR_SURFACEBUSY

DDLOCK_WRITEONLY

表示被锁的显示表面是可写的

 
 
 
  
// 把显示表面锁住
if (FAILED(lpddsprimary -> Lock(
NULL,
// 想要上锁的区域的RECT
& ddsd, // DDSURFACEDESC2的地址,给空即可
DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, // 告诉Lock想做什么
NULL))) // 事件,高为NULL

{
return ( 0 );
}

   

使用IDirectDrawSurface7::Unlock()方法解锁

声明如下:

 
  
HRESULT Unlock(LPRECT lpRect); // lpRect为在lock函数中第一个参数的Rect

 

 
 

下面是完整例子

完整例子源代码下载

 
  
// -------------------------------------------------------------------------
// 文件名 : 6_3.cpp
// 创建者 : 方煜宽
// 邮箱 : fangyukuan@gmail.com
// 创建时间 : 2010-12-5 23:54
// 功能描述 : 创建主显示表面、
// 创建调色板、
// 关联显示表面和调色板、
// 锁住显示表面、绘制、解锁
// -------------------------------------------------------------------------
#define INITGUID

#include
< windows.h >
#include
< ddraw.h >


LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

HWND main_window_handle
= NULL; // 全局的windows窗口句柄
LPDIRECTDRAW7 lpdd = NULL; // ddraw 接口指针
DDSURFACEDESC2 ddsd; // ddraw 显示表面 描述结构
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL; // ddraw 主显示表面
LPDIRECTDRAWSURFACE7 lpddsback = NULL; // ddraw 从显示表面

LPDIRECTDRAWPALETTE lpddpal
= NULL; // 调色板接口指针
PALETTEENTRY palette[ 256 ]; // 调色板
PALETTEENTRY save_palette[ 256 ]; // 调色板

#define SCREEN_WIDTH 640 // 屏幕宽
#define SCREEN_HEIGHT 480 // 屏幕高
#define SCREEN_BPP 8 // 深度

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
 
  
int Game_Init( void * parms = NULL, int num_parms = 0 )
{
// 创建组件并返回IDirectDraw7接口指针
if (FAILED(DirectDrawCreateEx(NULL, ( void ** ) & lpdd, IID_IDirectDraw7, NULL)))
return 0 ;

// 设置协作级别
lpdd -> SetCooperativeLevel(main_window_handle,
DDSCL_FULLSCREEN
| DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT);

// 设置模式
if (FAILED(lpdd -> SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0 , 0 )))
{
return 0 ;
}

// 初始化 ddsd
memset( & ddsd, 0 , sizeof (ddsd));
ddsd.dwSize
= sizeof (ddsd);

ddsd.dwFlags
= DDSD_CAPS;
ddsd.ddsCaps.dwCaps
= DDSCAPS_PRIMARYSURFACE; // 创建主显示表面标志

// 创建主显示表面
if (FAILED(lpdd -> CreateSurface( & ddsd, & lpddsprimary, NULL)))
{
return 0 ;
}

// 初始化 调色板 数组
for ( int color = 1 ; color < 255 ; color ++ )
{
// 随机填充RGB值
palette[color].peRed = rand() % 256 ;
palette[color].peGreen
= rand() % 256 ;
palette[color].peBlue
= rand() % 256 ;

palette[color].peFlags
= PC_NOCOLLAPSE; // 不优化调色板
}

// 把0项填充为黑色
palette[ 0 ].peRed = 0 ;
palette[
0 ].peGreen = 0 ;
palette[
0 ].peBlue = 0 ;
palette[
0 ].peFlags = PC_NOCOLLAPSE;

// 把255项填充为白色
palette[ 255 ].peRed = 255 ;
palette[
255 ].peGreen = 255 ;
palette[
255 ].peBlue = 255 ;
palette[
255 ].peFlags = PC_NOCOLLAPSE;

// 创建调色板对象
if (FAILED(lpdd -> CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE,
palette,
& lpddpal, NULL)))
{
return 0 ;
}

// 把 调色板 和 主显示表面 关联起来
if (FAILED(lpddsprimary -> SetPalette(lpddpal)))
{
return 0 ;
}

return 1 ;
}
 
  
int Game_Shutdown( void * parms = NULL, int num_parms = 0 )
{
// first the palette
if (lpddpal)
{
lpddpal
-> Release();
lpddpal
= NULL;
}

// now the primary surface
if (lpddsprimary)
{
lpddsprimary
-> Release();
lpddsprimary
= NULL;
}

// now blow away the IDirectDraw4 interface
if (lpdd)
{
lpdd
-> Release();
lpdd
= NULL;
}

return 1 ;

}
 
 
 
  
int Game_Main( void * parms = NULL, int num_parms = 0 )
{
if (KEYDOWN(VK_ESCAPE))
SendMessage(main_window_handle, WM_CLOSE,
0 , 0 );


memset(
& ddsd, 0 , sizeof (ddsd));
ddsd.dwSize
= sizeof (ddsd);

// 把 显示表面 锁住
if (FAILED(lpddsprimary -> Lock(
NULL,
// 想要上锁的区域的RECT
& ddsd, // DDSURFACEDESC2的地址,给空即可
DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, // 告诉Lock想做什么
NULL))) // 事件,高为NULL
{
return ( 0 );
}

// now ddsd.lPitch is valid and so is ddsd.lpSurface

// make a couple aliases to make code cleaner, so we don't
// have to cast
int mempitch = ( int )ddsd.lPitch;
UCHAR
* video_buffer = (UCHAR * )ddsd.lpSurface;

// 随机 颜色 绘制到随机 像素点
for ( int index = 0 ; index < 1000 ; index ++ )
{
// select random position and color for 640x480x8
UCHAR color = rand() % 256 ;
int x = rand() % 640 ;
int y = rand() % 480 ;

video_buffer[x
+ y * mempitch] = color;
}

// 解锁显示表面(需要将原本 lock中使用的RECT传递给Unlock,如果事个显示表面传NULL
if (FAILED(lpddsprimary -> Unlock(NULL)))
return ( 0 );

Sleep(
30 );

return ( 1 );
}
 
 
 
  
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
HWND hwnd;
MSG msg;
TCHAR lpszClassName[]
= TEXT( " kuan " );

WNDCLASS wc;
wc.style
= CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc
= WndProc;
wc.cbClsExtra
= 0 ;
wc.cbWndExtra
= 0 ;
wc.hInstance
= hInstance;
wc.hIcon
= ::LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor
= ::LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground
= (HBRUSH)::GetStockObject(BLACK_BRUSH);
wc.lpszMenuName
= NULL;
wc.lpszClassName
= lpszClassName;

RegisterClass(
& wc);

hwnd
= CreateWindow(lpszClassName,
TEXT(
" fangyukuan " ),
WS_POPUP
| WS_VISIBLE,
0 , 0 ,SCREEN_WIDTH,SCREEN_HEIGHT,
NULL,
NULL,
hInstance,
NULL);
main_window_handle
= hwnd;

Game_Init();
while (TRUE)
{
if (::PeekMessage( & msg, NULL, 0 , 0 , PM_REMOVE))
{
if (msg.message == WM_QUIT)
break ;

::TranslateMessage(
& msg);
::DispatchMessage(
& msg);
}
Game_Main();

}
Game_Shutdown();

return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
{
::MessageBeep(
0 );
}
break ;
case WM_DESTROY:
::PostQuitMessage(
0 );
break ;
default :
return ::DefWindowProc(hwnd,message,wParam,lParam);
}
return 0 ;
}
运行效果如下:
 
 

方煜宽  2011.05.21

转载请保留下面链接

http://www.cnblogs.com/fangyukuan/archive/2011/05/21/2052728.html

 


转载于:https://www.cnblogs.com/fangyukuan/archive/2011/05/21/2052728.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值