DirectDraw programming Basics

Source: Internet
Author: User
DirectDraw programming BASICS (zz from gameres blog) This article is intended for beginners who have been studying programming for several months: I have read the C ++ tutorial and understand the basic C ++ syntax; have a little VC experience, know how to build a project, understand some basic concepts of Windows programming, such as Windows, message loops, etc. Also, I will check the information if I don't understand it :).
I have read several books about DirectDraw, which are all good. I would like to thank their authors. What is lacking in the United States is that some of these books have a high starting point. Although we can still clearly understand some concepts, there will be a lot of confusion in organizing these documents. Here I want to repeat the concepts in the book and sort out my ideas. Let's get down to the truth.
First of all, let's talk about something that can't be said. I think they should not be mentioned because these things may be too basic and masters often ignore the role of these things on new users. As a newbie, I think it is more urgent to master the framework and organization of the program than to be familiar with several APIs. Now lets begin:
To write a game program, you must familiarize yourself with the process and exercise the ability to organize program files. For beginners, I suggest processing and analyzing programs to be written step by step. I do not recommend that you skip your mind at this time. This is a good habit, and of course it is also helpful for us to grasp the ideas and methods of programming as soon as possible. The following describes a general process and the corresponding program framework.

 

(The frame cannot be displayed ..)

So how can we use the above process to build our general program framework?
We already know something about Windows programming. Maybe you know more about MFC. We do not advocate the use of MFC here. Although it encapsulates many useful models, it is cumbersome for us to compile games. Okay, let's continue. Since Windows API is used, you can create a file winmain. cpp to handle windows programming related window problems. In this way, we should create a window in the file to process basic messages (for example, exit by "ESC") and control program exit. Do the messages in the game window need to be processed here? Of course, the windows in the game are not only Windows windows, but the display part is controlled by DirectDraw. Therefore, we have to call relevant modules in winmain. cpp to process the window. In this case, the entire process is almost covered in winmain. cpp. Good, it controls the entire framework of the program and provides a platform for your program kernel. If the platform is ready, the next step is gamemain. CPP is about to be born. It is mainly used to control all components of the entire game, coordinate all parts of the work, complete game setup initialization, and control the game exit through message loops in the game. Your talent is here to make full use. Generally, a game program has several fixed components: Display, music, and information input. DirectX provides convenient components such as DirectDraw, directsound, directmusic, and directinput. Accordingly, we create mydirectdraw. cpp, mydirectaudio. cpp, and mydirectinput. cpp to control the corresponding functions of each component.
Obviously, these three parts are for the gamemain. cpp service and are called by gamemain. cpp. We can see that
Our program should include the following files and their inclusion relationships:

(The chart cannot be displayed. 555)
 
This table shows how program files are organized. From this perspective, we found that winmain. cpp seems to be an investor who provides a development platform. He only pays attention to the overall process of the project and does not pay attention to details. Gamemain. CPP is like a project owner. He plans the detailed process of the project and controls it. CPP interaction to complete the project and coordinate mydirectdraw down. CPP, mydirectaudio. CPP, mydirectinput. between CPP. Mydirectdraw. cpp, mydirectaudio. cpp, and mydirectinput. cpp are employees who are responsible for their respective work and complete relevant functions for gamemain. cpp.
The organization program should be like this. Of course, the specific problem is analyzed. Let's start to look at the DirectDraw section.
First, install the DirectX SDK and add dxguid to the VC. lib and ddraw. lib. lib, I have been depressed for a while, which is quite harmful.) in this way, the DirectDraw program can be compiled. In dxguid. Lib, all global handles used in DirectX are defined. ddraw. Lib is the function library used by DirectDraw.
The following code can be written. Here, of course, we mainly look at how to write mydirectdraw. cpp.
For this reason, I have selected several source codes for reference research. They will be packaged together with this article.
I am still used to having a bird's eye view on the whole:
In general, there must be at least two parts in mydirectdraw. cpp (do not forget to reference the header file ddraw. h): initialization and termination. First, let's look at initialization. Initialization is nothing more than preparation. The definition of what is needed is created at hand for future use. Let's see how to write the initialization function intmydirectdrawinit (void. First, define a pointer to the DirectDraw object, create a DirectDraw object, query to obtain the latest DirectDraw interface, set the level of collaboration, and set the display mode. Through these steps, we can create a black screen, that is, we have opened up the space we need. Of course, the initialization of the DirectDraw program is not that simple. To operate 2D images, we also need to create the home page, cache page, and off-screen page. In short, everything that needs to be prepared before the operation can be put here as needed. The ending int mydirectdrawshut (void) should release the things we opened. Generally, the home page pointer and DirectDraw interface should be released.
This is generally the case. Go on should be fine-tuned.
First define the pointer: lpdirectdraw lpddraw_temp; indicates the entire Display System
Create object: If (failed (directdrawcreate (null, & lpddraw_temp, null )))
{
MessageBox (null, text ("Direct Draw create error! "),
Text ("wrong! "), Mb_ OK );
Return (0 );
}
A failed macro is used to check whether the creation is successful. This helps us track errors.
Function directdrawcreate (null, & lpddraw_temp, null) is created. The first parameter is the Globally Unique Identifier of the driver. null indicates the current display device; the second parameter is used to accept the address of the created DirectDraw object. Here we use & lpddraw_temp to accept it. The third parameter? Don't ask, just give it null and don't want to get into trouble.
Query the DirectDraw interface: If (failed (lpddraw_temp-> QueryInterface (iid_idirectdraw7,
(Lpvoid *) & lpddraw7 )))
{
MessageBox (null, text ("DirectDraw QueryInterface error! "),
Text ("wrong! "), Mb_ OK );
Return (0 );
}
Use the QueryInterface () method to obtain the new interface. Here idirectdraw7 is used instead of idirectdraw8, And the pointer to idirectdraw7 is placed in lpddraw7. This is a global variable. You can define lpdirectdraw7 lpddraw7 = NULL;
By the way, you should generally know the interface you are using, which is related to the SDK, so this step is not necessary.
Set collaboration level: If (failed (lpddraw7-> setcooperativelevel (main_window_handle,
Ddscl_fullscreen | ddscl_allowmodex |
Ddscl_exclusive | ddscl_allowreboot )))
{
MessageBox (null, text ("DirectDraw setcooperativelevel error! "),
Text ("wrong! "), Mb_ OK );
Return (0 );
}
Determines the relationship between your program and windows. It applies for resources used by windows, such as full screen and exclusive. The first parameter is the handle of the main window, which is the one you created in winmain (). The second parameter has several control flags. The common usage is as follows:
Ddscl_fullscreen: Full Screen mode, which must be used together with ddscl_exclusive
Ddscl_exclusive: exclusive request level, must be used together with ddscl_fullscreen
Ddscl_allowreboot: allows the system to detect CTRL + ALT + DEL key messages (this is useful)
I think these three will be enough, and the rest will be ignored first.
Set the display mode: If (failed (lpddraw7-> setdisplaymode (800,600, 16, 0, 0 )))
{
MessageBox (null, text ("DirectDraw setdisplaymode error! "),
Text ("wrong! "), Mb_ OK );
Return (0 );
}
The display mode to be used in the game may be different from the current display mode of the user. You need to set setdisplaymode () to force the mode set here. The first three parameters of setdisplaymode are easy to understand, fourth, use 0 to indicate the default update rate. The fifth parameter here is 0. Some books say that ddsdm_standvgamode must be used. (You can understand, but you don't know what this 0 means, I guess it means default.
So far, I think we have created the space we need. Later, as we increase our requirements, we will gradually improve the initialization function. Now let's look at the ending function:
Release Interface: If (lpddraw7)
{
Lpddraw7-> release ();
Lpddraw7 = NULL;
}
In the future, you need to release the home page, cache page, and so on. Note that you must release the resources you have applied for. This is a good habit, it should be noted that the first creation must be released, because the later creation may work in the first creation environment.
So far, we have just made the most basic preparations and can't do anything.
Do you want to do something? Let's take a break. Let's say something you have to say:
Let's look at the color. There are several colors, including 256 colors (8 digits), 16 digits, 24 digits, and 32 digits. 256 colors are rarely used. 16 bits are still mainstream, so let's take a look at 16 bits. Generally, 16 bits have two formats: 5.5.5 and 5.6.5, it is generally expressed in RGB notation. Where:
5.5.5 format, the highest bit is Alpha, indicating whether it is transparent, the remaining 15 bits indicate color, red, green, and blue each five bits, this format can represent 32786 colors. Macro
# DEFINE _ rgb16bit555 (R, G, B) (B % 32) + (g % 32) <5) + (R % 32) <10 )) to be converted to the 5.5.5 format.
For the 5.6.5 format, it is clear that red and blue are 5 bits and green are 6 bits, which can represent 65536 colors. Similarly, the macro
# DEFINE _ rgb16bit565 (R, G, B) (B % 32) + (g % 64) <6) + (R % 32) <11 )) to be converted to the 5.6.5 format.
I don't know what's going on with the shift in the middle. Let's just stop reading it. The more you see, the more you will be able to get bored.
What format should I use? Check the machine. Most of them can use 5.6.5. Of course you can check the machine. As for how to check the machine, I will not talk about it. Check the relevant information. What about 24 digits? 8 bits in red, green, and blue, 32 bits? Add an Alpha bit, and the remaining 24 digits. Let's talk about the color.
What do you want? To make some color on the screen, see the source code code1.
Will you find out what we should add to the above? Yes, you should create a page in the initialization function, that is, the directdrawsurface object. What is the difference between it and the DirectDraw object? DirectDraw object. We know that it refers to the entire display system, that is, the system composed of your video card and video screen. Can you directly draw something on the display screen? No. The display on the display screen is displayed through the video memory and memory operations. In contrast to the display screen, there should be a blank rectangle in the memory for you to paint, and then display it on the display screen. The blank sheet of paper is the directdrawsurface object, which represents a continuous linear data zone in the display memory or memory. This data area can be identified and confirmed by DirectDraw Objects representing the display hardware. Generally, there are four types of pages that can be created. We usually use the primary surface and offscreen plain pages to first talk about the home page, which is a piece of video memory, the images on the home page are displayed on the screen, and operations on the home page directly have a problem. If there is more data, the images will be discontinuous. Therefore, the buffer technology can be used, that is, a back buffer (backend buffer) is created. To put it bluntly, a new area is opened in the memory, which corresponds to the area on the home page. In this way, the home page is not directly operated, write the data here first, and then use the form feed to become visible. The Screen Separation page is different. It is the same screen as the home page, but it never appears on the screen and is usually used to store bitmaps, this interface is used to forward the bitmap image bits to the home page or backend buffer. Let's take a look at the positions and functions of these pages at work:

(A chart is not displayed here)
 
In this way, we have a general understanding of the role of the page, so we should create a page during initialization to wait for the page operations. So we should add the following in the initialization function:
Memset (& ddsd, 0, sizeof (ddsd ));
Ddsd. dwsize = sizeof (ddsd );
// Set dwflags to tell DirectDraw which members are available
Ddsd. dwflags = ddsd_caps | ddsd_backbuffercount;
// Define ddscaps. dwcaps and request a home page with background Buffer
Ddsd. ddscaps. dwcaps = ddscaps_primarysurface | ddscaps_complex |
Ddscaps_flip;
// Define the number of backend buffers to 1
Ddsd. dwbackbuffercount = 1;
// Create the Home Page
If (failed (lpddraw7-> createsurface (& ddsd, & lpddprimary, null )))
{
MessageBox (null, text ("DirectDraw create primary surface error! "),
Text ("wrong! "), Mb_ OK );
Return (0 );
}
// Set ddscaps. dwcaps
Ddsd. ddscaps. dwcaps = ddscaps_backbuffer;
// Connect the home page and background Buffer
If (failed (lpddprimary-> getattachedsurface (& ddsd. ddscaps, & lpddback )))
{
MessageBox (null, text ("DirectDraw create back surface error! "),
Text ("wrong! "), Mb_ OK );
Return (0 );
}
Here, we need to define several global variables:
Extern lpdirectsurface7 lpddprimary;
Extern lpdirectsurface7 lpddback;
Extern ddsurfacedesc2 ddsd;
This is a pointer to the home page, a pointer to the background buffer, and a page description structure. Needless to say, you can put these definitions in mydirectdraw. h. Declare the type of the page you want to create by filling in members of the ddsd structure. No screen disconnection page is created here. The homepage and background buffering can be used to complete some relatively simple operations. If the data is not displayed in many images and the data is too complex, you should create an off-screen page.
Correspondingly, in addition to the directdraw7 interface, the backend buffer pointer and Home Page pointer are also released at the end. Remind me that the first creation must be released, or you will be embarrassed to die. How to release these things, look at the code in code1, it is easy to understand.
By the way, let's take a look at how to create an off-screen page and look at the following code:
Ddsurfacedesc2 ddsd;
Lpdirectsurface7 lpddopl; // needless to say
Memset (& ddsd, 0, sizeof (ddsd); // clear the structure content
Ddsd. dwsize = sizeof (ddsd); // set the size
Ddsd. dwflags = ddsd_caps | ddsd_height | ddsd_width;
Ddsd. ddscaps. dwcaps = ddscaps_offscreenplain; // specify the page type.
Dddsd. dwwidth = 600;
Ddsd. dwheight = 800; // set the size of the off-screen page.
If (failed (lpddraw7-> createsurface (& ddsd, & lpddopl, null )))
{
MessageBox (null, text ("DirectDraw create offscreen plain error! "),
Text ("wrong! "), Mb_ OK );
Return (0 );
} // Create an off-screen page
Okay! The off-screen page is created. For more information, because the off-screen page is an independent page and does not belong to any other page, you must specify its size.
Let's talk about the creation of the page. Is there a feeling that everything is ready, just in the air?
Look up, it's Dawn, it's time to go to bed. Let's wake up and then say, let's go and call.
...... N hours later ......
Now, we have nothing to do with Dongfeng.
For a simple drawing, see code1 (hitting on the screen)
I still cannot organize the operations on the bitmap used by the page (drawing these two items) and cannot organize what I understand into the program (sweat! I have not really understood it yet, so I can say it here.) I am also learning how to understand it several times. Maybe I can organize it. So, we can only split and start to copy all the books according to the document I have read. I hope that after copying, you will be able to get a little organized.
From the previous page table, we can see that the operation here is nothing more than loading bitmap, texture, page flip display, and cropping the screen. Let's talk about it step by step. Here we will talk about the case. The module, the code segment, and the previous files are not much associated. Don't scold me, long live.
First, load the bitmap to the off-screen page. You need to use Windows HDC for access and use Windows API with DirectX. Let's look at the code segment:
HDC, hdc1; // declare the HDC object. HDC is used to store bitmap. hdc1 represents the DC of the off-screen page.
Hbitmap bitmap; // declare an hbitmap object
HDC =: createcompatatibledc (null); // create a DC compatible with the current display mode (the parameter is null)
Bitmap = (hbitmap): loadimage(null,”bgroud.bmp ", image_bitmap, 640,480,
Lr_loadfromfile );
// Load bitmap 640*480
: SelectObject (HDC, bitmap); // use the Windows function to set the content in HDC to bitmap.

Now we have loaded the bitmap to the DC. Below we need to paste the bitmap in the DC to the off-screen page.
Lpdirectsurface7 lpddopl; // This definition is not required.
Hresult result; // Why? Look down
Lpddopl-> getsurfacedesc (& ddsd); // The ddsd is the same as the one we previously defined.
Result = lpddopl-> getdc (& hdc1); // use getdc () to retrieve the DC from the screen
If (result! = Dd_ OK)
MessageBox ("failed to get DC in the temporary storage zone"); // check whether the result is successful.
: Bitblt (hdc1, 0, 0, ddsd. dwwidth, ddsd. dwheight, HDC, 0, 0, srccopy );
// This is the Windows function used for textures.
Lpddopl-> releasedc (hdc1); // release the DC from the screen. Be sure to release it.
Now we have pasted the bitmap to the off-screen page. Below we should fill in the bitmap in the DC of the off-screen page to the back buffer, and then display it through a new page. First, let's take a look at the Paster functions BLT and bltfast of DirectDraw. The prototypes of these two functions are described in the DirectX development manual translated by Lao Wang. You can go down on my homepage and check them out. Here I will give a brief introduction:
Hresult BLT (lprect lpdestrect, // The area of the target page. lpdestrect defines the coordinates of the upper left and lower right points.
Lpdirectdrawsurface7 lpddsrcsurface, // Source Page pointer
Lprect lpsrcrect, // area of the Source Page
DWORD dwflags, // control flag. For details, see Lao Wang's manual.
Lpddbltfx) // information structure of graphic transformation. For details, refer
Hresult bltfast (DWORD dwx, // the upper left X coordinate of the target area
DWORD dwy, // y coordinate on the top left of the target area
Lpdirectdrawsurface7 lpddsrcsurface, // Source Page pointer
Lprect lpsrcrect, // area of the Source Page
DWORD dwtrans, // for conversion parameters, see the old Wang Manual

The difference between the two is that BLT has more graphics resizing functions, but bltfast is more efficient, and it is clear how to choose it. Call one of the two functions to map the page from the screen to the back buffer. The Code is as follows:
Lpddback-> bltfast (0, 0, lpddopl, crect (0, 0, 640,480), ddbltfast_wait );
// Lpddback is the background buffer we have previously declared, crect (...) Is a crect class object. If we have declared a crect rect; here we can use & rect instead.
This step is easy.
It seems that there is only one step away from the display. Right, you just need to flip the page (FLIP) and it will be okay.
First look at the paging function:
Hresult flip (lpdirectdrawsurface7 lpdddestsurface, // target page you want to flip
DWORD dwflags) // usually set to ddflip_wait
Note: If the first parameter is null, it indicates that it is redirected to the next page connected to the current page. When a page feed object is a visible page, such as a page feed link on the home page, the flip function for page feed is executed asynchronously with the system CPU. This means that on these visible pages, the flip function is called, which simply tells the display hardware to switch pages, it does not need to be returned after the page change operation is completed on the hardware device. This is because the display hardware (Display) can be changed only once after a vertical refresh is completed. Therefore, the successful call of the flip function does not mean that the page feed has been completed. Before the actual page feed operation is complete, the background cache that will become the Home Page cannot be locked or operated blit. To synchronize the flip function with the system CPU, specify the ddflip_wait flag during the call.
The Code is also simple:
Lpddprimary-> flip (null, ddflip_wait );
Now, we have displayed a designated bgroud.bmp on the screen. This can be used as the background image of your game, such as the huge chart of a submarine game.
It should be noted that, if we want to operate on the page (generally back buffer), it is best to lock the page before the operation, and unlock it after use to prevent interference from other GDI programs. For example:
Lpddback-> lock (null, & ddsd, DDLOCK-WAIT | ddlock_surfacememoryptr,
Null); // lock the background Buffer
Lpddback-> unlock (null); // unlock background Buffer
Add the two statements to the corresponding positions.

What should we do next? Now that we have a background, we should introduce our Genie (the term genie is really cute) and think about how it can make our Genie work. Honestly, at this point, I am about to crash. The following content should belong to a strange part (if I am still familiar with the previous content ). Fortunately, this person is very persistent, so I have to continue to write down my head, please forgive me for not understanding the place, and I hope you will give me some advice.
Make preparations First, eat first, take a break ............
...... N hours again ......
It's really nice to have a meal, please cherish it, friends: Take a deep breath, let's go on
Using DirectDraw for animation, we load different images into the off-screen page, and then regularly paste them into the back buffer. When the pages are displayed, the animation effect is displayed.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.