• 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位的色彩深度的时候,我们需要一个调色板。

    调色板数据结构

    先了解调色板数据结构:

    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

     
    
  • 相关阅读:
    CodeForces 500C New Year Book Reading
    CodeForces 460B Little Dima and Equation 枚举
    CodeForces 451B Sort the Array
    【jquery】jQuery实现轮播图
    【IDEA】IDEA技巧记录
    【eclipse】日常使用eclipse记录
    【SSM】spring配置文件中读取配置文件的三种方式
    【Git】IDEA克隆和提交项目于码云
    semantic UI—表单验证
    【spring Data Jpa】JPA生成数据库表
  • 原文地址:https://www.cnblogs.com/fangyukuan/p/2052728.html
Copyright © 2020-2023  润新知