网页功能: 加入收藏 设为首页 网站搜索  
DirectX - tasy (II) (节选)
发表日期:2006-08-20作者:[转贴] 出处:  

  我们继续上次的话题。

  上一讲中,我们介绍了一下具体的步骤。下面的清单 1.0 包含了所有的功能以及一个展示如何操作显存和键盘的例子。我们简单地将它作为一个演示。

// LISTING 1.0 - DIRECT X 5.0 GAME CONSOLE ////////////////////////////////////

// INCLUDES ///////////////////////////////////////////////////////////////////

#define WIN32_LEAN_AND_MEAN
// make sure certain headers are included correctly

#include <windows.h> 
// include the standard windows stuff
#include <windowsx.h>
// include the 32 bit stuff
#include <mmsystem.h>
// include the multi media stuff
                           
// note you need winmm.lib also
#include <ddraw.h>   
// include direct draw components

#include <stdlib.h>  
// include all the good stuff
#include <stdio.h>
#include <math.h>
#include <float.h>

// DEFINES ////////////////////////////////////////////////////////////////////

#define WINDOW_CLASS_NAME "WINDOW_CLASS"
// this is the name of the window class

// defines for screen parameters


#define SCREEN_WIDTH 640  
// the width of the viewing surface
#define SCREEN_HEIGHT 480 
// the height of the viewing surface
#define SCREEN_BPP 8      
// the bits per pixel
#define MAX_COLORS 256    
// the maximum number of colors

// TYPES //////////////////////////////////////////////////////////////////////

typedef unsigned char UCHAR;

// MACROS /////////////////////////////////////////////////////////////////////

// these query the keyboard in real-time


#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

// PROTOTYPES /////////////////////////////////////////////////////////////////

int DD_Init(HWND hwnd);
int DD_Shutdown(void);
int Set_Pal_Entry(int index, int red, int green, int blue);

void Game_Init(void);
void Game_Main(void);
void Game_Shutdown(void);

// DIRECTDRAW GLOBALS ////////////////////////////////////////////////////////

LPDIRECTDRAW lpdd = NULL;               
// dd object
LPDIRECTDRAWSURFACE lpddsprimary = NULL;
// dd primary surface
LPDIRECTDRAWPALETTE lpddpal = NULL;     
// a pointer to the created dd palette
PALETTEENTRY color_palette[256];        
// holds the shadow palette entries
DDSURFACEDESC ddsd;              
// a direct draw surface description struct
DDSCAPS ddscaps;                 
// a direct draw surface capabilities struct
HRESULT ddrval;                  
// result back from dd calls
HWND main_window_handle = NULL;  
// used to store the window handle
UCHAR *video_buffer = NULL;      
// pointer to video ram


// GAME GLOBALS GO HERE /////////////////////////////////////////////////////

// DIRECT X FUNCTIONS /////////////////////////////////////////////////////////

int DD_Init(HWND hwnd)
{
    // this function is responsible for initializing direct draw, it creates a
    // primary surface

    int index;
// looping index

   
// now that the windows portion is complete, start up direct draw
    if (DirectDrawCreate(NULL,&lpdd,NULL)!=DD_OK)
    {
       
// shutdown any other dd objects and kill window
        DD_Shutdown();
        return(0);
    }
// end if

   
// now set the coop level to exclusive and set for full screen and mode x
    if (lpdd->SetCooperativeLevel(hwnd, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE |
        DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX)!=DD_OK)
    {
       
// shutdown any other dd objects and kill window
        DD_Shutdown();
        return(0);
    }
// end if

   
// now set the display mode
    if (lpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP)!=DD_OK)
    {
       
// shutdown any other dd objects and kill window
        DD_Shutdown();
        return(0);
    }
// end if

   
// Create the primary surface
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

    if
    (lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)!=DD_OK)
    {
       
// shutdown any other dd objects and kill window
        DD_Shutdown();
        return(0);
    }
// end if

   
// create the palette and attach it to the primary surface

   
// clear all the palette entries to RGB 0,0,0
    memset(color_palette,0,256*sizeof(PALETTEENTRY));
   
   
// set all of the flags to the correct value
    for (index=0; index<256; index++)
    {
       
// create the GRAY/RED/GREEN/BLUE palette, 64 shades of each
        if ((index / 64)==0)
        {
            color_palette[index].peRed = index*4;
            color_palette[index].peGreen = index*4;
            color_palette[index].peBlue = index*4;
        }
// end if
        else
        if ((index / 64)==1)
            color_palette[index].peRed = (index%64)*4;
        else
        if ((index / 64)==2)
            color_palette[index].peGreen = (index%64)*4;
        else
        if ((index / 64)==3)
            color_palette[index].peBlue = (index%64)*4;

       
// set the no collapse flag
        color_palette[index].peFlags = PC_NOCOLLAPSE;

    }
// end for index

   
// now create the palette object, note that it is a member of the dd object itself
    if (lpdd->CreatePalette((DDPCAPS_8BIT | DDPCAPS_INITIALIZE),color_palette,&lpddpal,NULL)!=DD_OK)
    {
       
// shutdown any other dd objects and kill window
        DD_Shutdown();
        return(0);
    }
// end if

   
// now attach the palette to the primary surface
    lpddsprimary->SetPalette(lpddpal);

   
// return success if we got this far
    return(1);

}
// end DD_Init

///////////////////////////////////////////////////////////////////////////////

int DD_Shutdown(void)
{
    // this function tests for dd components that have been created and releases
    // them back to the operating system

   
// test if the dd object exists
    if (lpdd)
    {
       
// test if there is a primary surface
        if(lpddsprimary)
        {
           
// release the memory and set pointer to NULL
            lpddsprimary->Release();
            lpddsprimary = NULL;
        }
// end if

       
// now release the dd object itself
        lpdd->Release();
        lpdd = NULL;

       
// return success
        return(1);

    }
// end if
    else
        return(0);

}
// end DD_Shutdown

//////////////////////////////////////////////////////////////////////////////

int Set_Pal_Entry(int index, int red, int green, int blue)
{
   
// this function sets a palette entry with the sent color

    PALETTEENTRY color;
// used to build up color

   
// set RGB value in structure
    color.peRed = (BYTE)red;
    color.peGreen = (BYTE)green;
    color.peBlue = (BYTE)blue;
    color.peFlags = PC_NOCOLLAPSE;

   
// set the color palette entry
    lpddpal->SetEntries(0,index,1,&color);

   
// make copy in shadow palette
    memcpy(&color_palette[index],
        &color,
        sizeof(PALETTEENTRY));

   
// return success
    return(1);

}
// end Set_Pal_Entry

// WINDOWS CALLBACK FUNCTION //////////////////////////////////////////////////

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
   
// this is the main message handler of the system

    HDC hdc;
// handle to graphics context
    PAINTSTRUCT ps;
// used to hold the paint info

   
// what is the message?

    switch(msg)
    {
    case WM_CREATE:
        {
           
// do windows inits here
            return(0);
        } break;

    case WM_PAINT:
        {
           
// this message occurs when your window needs repainting
            hdc = BeginPaint(hwnd,&ps);
            EndPaint(hwnd,&ps);

            return(0);
        } break;

    case WM_DESTROY:
        {
           
// this message is sent when your window is destroyed
            PostQuitMessage(0);
            return(0);
        } break;

    default:break;

    }
// end switch

   
// let windows process any messages that we didn't take care of
    return (DefWindowProc(hwnd, msg, wparam, lparam));

}
// end WinProc

// WINMAIN ////////////////////////////////////////////////////////////////////

int WINAPI WinMain( HINSTANCE hinstance,
                    HINSTANCE hprevinstance,
                    LPSTR lpcmdline,
                    int ncmdshow)
{
    WNDCLASSEX winclass; 
// this holds the windows class info
    HWND hwnd;           
// this holds the handle of our new window
    MSG msg;             
// this holds a generic message

   
// first fill in the window class stucture

    winclass.cbSize = sizeof(WNDCLASSEX);
    winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
    winclass.lpfnWndProc = WindowProc;
    winclass.cbClsExtra = 0;
    winclass.cbWndExtra = 0;
    winclass.hInstance = hinstance;
    winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    winclass.lpszMenuName = NULL;
    winclass.lpszClassName = WINDOW_CLASS_NAME;

   
// register the window class
    if (!RegisterClassEx(&winclass))
        return(0);

   
// create the window
    if (!(hwnd = CreateWindowEx(WS_EX_TOPMOST,
            WINDOW_CLASS_NAME,     
// class
            "You can't See This!", 
// title
            WS_VISIBLE | WS_POPUP,
            0,0,
// x,y
            GetSystemMetrics(SM_CXSCREEN),
            GetSystemMetrics(SM_CYSCREEN),
            NULL,          
// parent
            NULL,          
// menu
            hinstance,     
// instance
            NULL)))        
// creation parms
        return(0);

   
// hide the mouse cursor
    ShowCursor(0);

   
// save the window handle
    main_window_handle = hwnd;

   
// initialize direct draw
    if (!DD_Init(hwnd))
    {
        DestroyWindow(hwnd);
        return(0);
    }
// end if

   
// initialize game
    Game_Init();

   
// enter main event loop
    while(1)
    {
        if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
        {
           
// test if this is a quit
            if (msg.message == WM_QUIT)
                break;

           
// translate any accelerator keys
            TranslateMessage(&msg);

           
// send the message to the window proc
            DispatchMessage(&msg);
        }
// end if
        else
        {
           
// do asynchronous processing here

           
// acquire pointer to video ram, note it is always linear
            memset(&ddsd,0,sizeof(ddsd));
            ddsd.dwSize = sizeof(ddsd);
            lpddsprimary->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR,NULL);
            video_buffer = (UCHAR *)ddsd.lpSurface;

           
// call main logic module
            Game_Main();

           
// release pointer to video ram
            lpddsprimary->Unlock(ddsd.lpSurface);

        }
// end else

    }
// end while

   
// shut down direct draw
    DD_Shutdown();

   
// shutdown game
    Game_Shutdown();

   
// return to Windows
    return(msg.wParam);

}
// end WinMain

// HERE ARE OUR GAME CONSOLE FUNCTIONS ///////////////////////////////////////////////////////

void Game_Init(void)
{
   
// do any initialization here
}
// end Game_Init

/////////////////////////////////////////////////////////////////////////////////////////////

void Game_Shutdown(void)
{
   
// cleanup and release all resources here
}
// end Game_Shutdown

/////////////////////////////////////////////////////////////////////////////////////////////

void Game_Main(void)
{
    // process your game logic and draw next frame
    // this function must exit each frame and return back to windows
    // also this function is responsible for controlling the frame rate
    // therefore, if you want the game to run at 30fps, then the function should
    // take 1/30th of a second before returning

    static int px = SCREEN_WIDTH/2, 
// position of player
    py = SCREEN_HEIGHT/2,
    color = 0;                      
// color of blob 0..3, gray, red, green, blue

    // on entry video_buffer is valid

    // get input, note how keyboard is accessed with constants
    //"VK_"
    // these are defined in "winuser.h" are basically the
    //scan codes
    // for letters just use capital ASCII codes


    if (KEY_DOWN(VK_ESCAPE))
        PostMessage(main_window_handle,WM_CLOSE,0,0); // this is how you exit you game

   
// which way is player moving
    if (KEY_DOWN(VK_RIGHT))
        if (++px>SCREEN_WIDTH-8) px=8;

    if (KEY_DOWN(VK_LEFT))
        if (--px<8) px=SCREEN_WIDTH-8;

    if (KEY_DOWN(VK_UP))
        if (--py<8) py=SCREEN_HEIGHT-8;

    if (KEY_DOWN(VK_DOWN))
        if (++py>SCREEN_HEIGHT-8) py=8;

   
// adjust color, notice
    if (KEY_DOWN('C'))
    {
        if (++color>=4)
        color=0;
        Sleep(100);
    }
// end if

   
// draw graphics
    for (int pixels=0; pixels<32; pixels++)
    video_buffer[(px-4+rand()%8)+(py-4+rand()%8)*SCREEN_WIDTH] = (color*64)+rand()%64;

   
// sync time (optional)

   
// use sleep to slow system down to 70ish fps
    Sleep(14);
// note that Sleep is extremly inaccurate, IRL you would use something more robust

   
// return and let windows have some time

}
// end Game_Main

  要编译这个程序并且运行它,你需要在工程中包括库文件 DDRAW.LIB ,和头文件 DDRAW.H 。他们通过设置搜索路径存在于你的 IDE 中或者是直接加到工程中去。你的目标程序,应该是一个标准的 Windows 程序。在建立了程序后,运行它,你应该可以看到一个炽热的水滴,并且可以通过方向键来移动它,<C> 键可以更改色彩,按 <ESC> 可以退出程序。现在你拥有了开始体验 DirectX 基础的所有东西了。你可以通过常量 SCREEN_WIDTH 和 SCREEN_HEIGHT 来尝试双缓冲、不同分辨率,甚至是调色板颜色变换。

  现在,只剩下一个可能引起的问题了。如果你的显卡不能简单地为 DirectX 创建一个线形的显存模式的话,你必须直接仔细得操作显卡了。举个简单的例子,如果你创建了一个 640 象素每行,即在 640x480x256 色模式中,操作下一行的显存的话,你必须加上 640,或者是一般地操作一个象素点,你可以这样写:

    
video_buffer[x + y*640] = pixel;

  无论如何,如果你的显卡无法支持线形内存的话,那么,你必须去修改一下,以便能直接真正地操作显存的“线形内存跨度”。这个值会比象素值大。举个例子,它在 640 个象素每行的模式中甚至可能是 1024 个象素的值。这个线形跨度能够通过锁定一个 DirectDraw 表面的描述来访问,像这样:

    
// 我们可以这样锁定
    
lpddsprimary->Lock(NULL,&ddsd,DDLOCK_SURFACEMEMORYPTR,NULL);
    video_buffer = (UCHAR *)ddsd.lpSurface;

    
// 这里就是我们可以用于操作的值

    
int lpitch = ddsd.lPitch;

  那么,我们可以通过下面的方法来直接操作显存了:

    
video_buffer[x + y*lpitch] = pixel;

  因此,最安全的方法是去经常使用我们修改后得到的值。但是,这个方法牺牲了极大的性能。因此,你可能会去测试他们是否会是一个相等的值,然后使用一个不同的基于此原理的渲染函数。

[本文例子的源代码下载]

我来说两句】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 DirectX - tasy (II) (节选)
本类热点文章
  在DirectX 8 中进行2D渲染
  DirectDraw打造极速图形引擎(一)
  用窗口模式运行游戏
  DirectDraw编程基础
  Windows的位图alpha混合技术
  再谈GDI模式作图
  终极优化你的游戏——使用脏矩形技术
  D3D8里面的2D图形编程
  全屏模式
  对2D游戏引擎设计的一些思考
  DirectX8中的二维图形高级技巧
  使用标准GDI实现游戏品质的动画系统
最新分类信息我要发布 
最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放  
Copyright ©2003-2024 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00436