?? gamedev_net - the simple directmedia layer from a win32 perspective, part 2 sdl video.htm
字號:
<TD>The surface will be used as a destination for OpenGL rendering.</TD></TR>
<TR>
<TD>SDL_RESIZABLE*</TD>
<TD>(Windowed mode only) the window is resizable.</TD></TR>
<TR>
<TD>SDL_HWACCEL</TD>
<TD>The surface will use hardware accelerated blitting.</TD></TR>
<TR>
<TD>SDL_SRCCOLORKEY</TD>
<TD>The surface has a color key.</TD></TR>
<TR>
<TD>SDL_RLEACCEL</TD>
<TD>The surface is used for run-length-encoded blits.</TD></TR>
<TR>
<TD>SDL_SRCALPHA</TD>
<TD>The surface has an alpha component.</TD></TR>
<TR>
<TD>SDL_PREALLOC</TD>
<TD>The surface came to be from a pre-allocated array of pixel
data.</TD></TR></TBODY></TABLE>
<P>*only the display surface may have these flags</P>
<P>The format member is a pointer to an SDL_PixelFormat structure that describes
the pixel format for this surface.</P>
<P>The w and h members describe the width and height of the surface.</P>
<P>The pitch contains the number of bytes per scan line for the surface. Video
cards being what they are, this value is often not the same as the BytesPerPixel
times the width.</P>
<P>The pixels is a pointer to pixel data for the surface. It is used to read or
write pixels to and from the surface.</P>
<P>The clip_rect member is an SDL_Rect that describes the clipping area of the
surface. Any writing outside of this area will not be shown.</P>
<P>And finally, refcount is a reference count. When a surface is created, it is
set to one. You can increment it manually. It is decremented whenever the
surface is freed. Once it reaches 0, the surface is deleted from memory. This
member is sort of like using AddRef for COM objects.</P>
<P>IMPORTANT NOTE: with the exception of refcount and the data pointed to by
pixels, these members should not by modified by you directly. There are
functions for dealing with and changing most of them.</P>
<H2>SDL_VideoInfo</H2>
<P>The last structure we're going to look at is SDL_VideoInfo. As you might
expect, it contains information about the video display on the machine it is
running on. Here's what it looks like:</P>
<BLOCKQUOTE><PRE class=code>typedef struct{
Uint32 hw_available:1;
Uint32 wm_available:1;
Uint32 blit_hw:1;
Uint32 blit_hw_CC:1;
Uint32 blit_hw_A:1;
Uint32 blit_sw:1;
Uint32 blit_sw_CC:1;
Uint32 blit_sw_A:1;
Uint32 blit_fill:1;
Uint32 video_mem;
SDL_PixelFormat *vfmt;
} SDL_VideoInfo;
</PRE></BLOCKQUOTE>
<P>The closest equivalent in DirectDraw is the DDCAPS structure. SDL_VideoInfo,
however, is much easier to read. Most of the members are single bits, and a
value of 0 means that the feature in question is not supported, and 1 means that
the feature is supported.</P>
<P>The hw_available indicates that you may create hardware surfaces, which
naturally will be faster than software surface.</P>
<P>The wm_available indicates that a window manager is available. In WIN32, one
is, but for other platforms, one might not be. The window manager is another
subsystem of SDL that deals with some pretty basic settings for a window (if you
are using windowed mode versus fullscreen).</P>
<P>The blit_hw, blit_hw_CC, and blit_hw_A all deal with the availability of
hardware acceleration for blits between surface stored in hardware. The blit_hw
bit specifies that generic hardware to hardware blits are accelerated,
blit_hw_CC specifies that hardware to hardware colorkeyed blits are accelerated,
and blit_hw_A specifies that hardware to hardware alpha blits are
accelerated.</P>
<P>The blit_sw, blit_sw_CC, and blit_sw_A are much the same as the blit_hw
members, except that they specify the capabilities for software to hardware
blits instead.</P>
<P>The blit_fill member specifies that color fill operations are
accelerated.</P>
<P>The video_mem contains, in kilobytes, the amount of video RAM for the
system.</P>
<P>The vfmt member is a pointer to an SDL_PixelFormat. Depending on when you
call it, it will contain either the "best" video format (the one with the most
capabilities), or the current video format (depending on if you have already set
up your display surface or not).</P>
<H1>Video Information (TGO-02-B)</H1>
<P>The beautiful thing about SDL is that you don't have to gather any
information about the video subsystem before using it if you don't want to. SDL
will emulate anything you want. Of course, emulation is slower, but it
guarantees that your application will run on any platform that has an SDL
implementation.</P>
<P>However, if you do want information about the video system, there are a few
functions that you can use. The first of these is SDL_GetVideoInfo.</P>
<BLOCKQUOTE><PRE class=code>SDL_VideoInfo *SDL_GetVideoInfo(void);
</PRE></BLOCKQUOTE>
<P>This function returns a pointer to an SDL_VideoInfo structure. It takes no
parameters. DO NOT FREE THE POINTER RETURNED FROM THIS FUNCTION!</P>
<P>In order to be effective, you have to call SDL_GetVideoInfo after you have
initialized the SDL video subsystem. Typically, initialization of SDL is the
first line in the program. The line looks like this:</P>
<BLOCKQUOTE><PRE class=code>SDL_Init ( SDL_INIT_VIDEO ) ;
</PRE></BLOCKQUOTE>
<P>This single line sets up the video system and the even system (which is
another topic altogether). After this call, you can call SDL_GetVideoInfo, and
get information about the best pixel format to use for your system, provided you
call it before you call SDL_SetVideoMode. Calling SDL_GetVideoInfo after this
call, you will get the information about the current display mode.</P>
<P>Another thing you can look at, if you really want to, is the name of the
video driver (it probably won't help you much, but its something to look at, I
guess). You can retrieve it with the SDL_VideoDriverName function.</P>
<BLOCKQUOTE><PRE class=code>char *SDL_VideoDriverName(char *namebuf, int maxlen);
</PRE></BLOCKQUOTE>
<P>This function takes two parameters, a pointer to a string (namebuf), and an
int specifying the maximum length of the string to copy (including the
null-terminator). The value returned is the namebuf pointer if this function is
successful, and NULL if it fails. It will only fail if you haven't initialized
the video subsystem. The name of the video driver isn't particularly useful, but
you might want it for some sort of log file for diagnostic purposes.</P>
<P>This next call is useful if you are targeting full screen applications. The
function is called SDL_ListModes, and it looks like the following.</P>
<BLOCKQUOTE><PRE class=code>SDL_Rect **SDL_ListModes(SDL_PixelFormat *format, Uint32 flags);
</PRE></BLOCKQUOTE>
<P>This function takes a pointer to an SDL_PixelFormat (or NULL to simply use
the value retrieved by SDL_GetVideoInfo ( )->vfmt), and a combination of
flags ( the same flags that are value for SDL_Surfaces). It spits out an array
of SDL_Rect pointers that describe the various video modes that have the
specified format and support the flag specified. If, for example, you need a
hardware surface with double buffering, you would call SDL_ListModes in the
following manner.</P>
<BLOCKQUOTE><PRE class=code>SDL_Rect** pModeRects = SDL_ListModes ( NULL , SDL_HWSURFACE | SDL_DOUBLEBUF ) ;
</PRE></BLOCKQUOTE>
<P>Some special notes about SDL_ListModes. First, it is a NULL terminated list
of SDL_Rect* variables. Second, if all video modes accept the flag, this
function will return -1 rather than a pointer. Third, if no video modes accept
the flag, this function will return NULL. So, this function might be a little
cumbersome to use.</P>
<P>A different, more directly useful function, SDL_VideoModeOK.</P>
<BLOCKQUOTE><PRE class=code>int SDL_VideoModeOK(int width, int height, int bpp, Uint32 flags);
</PRE></BLOCKQUOTE>
<P>This function takes the width, height, bits per pixel, and flags for a
potential display surface, and determines if the match up of these values is
acceptable for the display hardware. Even if they are not, you can still use the
same parameters to create your display surface, and SDL will emulate for
you.</P>
<P>If this function returns 0, then no bpp value will work for the flags
specified. If the return value is non-zero, then it represents the nearest bpp
that will accept the flags specified. It is best to pick one of the standard
mode sizes (640x480, 800x600, 1024x768) when picking mode sizes if you are doing
a full screen application. If you aren't, and the video hardware don't support
that particular mode, SDL will again emulate it, by placing it on the next
larger supported size, and limiting output to a rectangle in the middle of the
screen. So, if you went for a 512x384 mode (which is supported on quite a bit of
hardware), and the video hardware didn't support it, SDL will throw you into a
640x480 mode, and place all output in the middle 512x384.</P>
<P>But enough of examining video capabilities... on to creating surfaces!</P>
<H1>Creating and Destroying Surfaces (TGO-02-C)</H1>
<P>Surfaces are the most important part of using SDL's video subsystem. Without
them, there'd be nothing to see, and how good is an application you can't see?
(Apologies to ZForm, LLC, whose clients can't read this article anyway--they
make software for the blind).</P>
<P>The first surface you should create in any SDL based application is the
display surface. You can create it with the SDL_SetVideoMode function.</P>
<BLOCKQUOTE><PRE class=code>SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags);
</PRE></BLOCKQUOTE>
<P>This function takes a width, height, bits per pixel, and flags, and spits out
a pointer to an SDL_Surface. This pointer is to the display surface/primary
surface. If you are doing a full-screen application, you will probably want to
check out the modes with SDL_ListModes and/or SDL_VideoModeOK, but if you don't
that's OK.</P>
<P>If you aren't doing a full-screen application, then you should specify 0 for
bpp, and have SDL_ANYFORMAT as part of your flags. This makes SDL use the
current format of the display, which makes life easier for you. In windowed
mode, you can use whatever width and height you like. In WIN32, this will give
you a window that has a client area of the size you requested.</P>
<P>After calling SDL_SetVideoMode, don't call SDL_FreeSurface on this pointer.
SDL cleans up the display surface during SDL_Quit, so you don't have to worry
about it.</P>
<P>In fact, you don't even have to store this pointer anywhere if you don't want
to. You can use SDL_GetVideoSurface (it takes no parameters) to retrieve a
pointer to the display surface.</P>
<P>Of course, you'll need more than simply a display surface to make your game,
unless you plan on making a game with nothing but pixel plotting and filling
rectangles. You'll need other surfaces as well.</P>
<P>To create a blank surface of a particular size and format, you call
SDL_CreateRGBSurface.</P>
<BLOCKQUOTE><PRE class=code>SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth,
Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
</PRE></BLOCKQUOTE>
<P>To this function, you supply a size (height, width, depth--bpp), and masks
for red, green, blue, and alpha, along with some flags, and this function gives
you a pointer to a newly created surface that matches your specifications.
Typically, you will want to use the same depth and masks as for the display
surface, but even if you don't, SDL will be able to copy from one to the other,
but it'll be a little slower. The only valid flags for SDL_CreateRGBSurface are
SDL_HWSURFACE , SDL_SWSURFACE , SDL_SRCCOLORKEY, and SDL_SRCALPHA. </P>
<P>If this function fails, it returns NULL.</P>
<P>Another function for creating surfaces is SDL_CreateRGBSurfaceFrom. This
function is much the same as SDL_CreateRGBSurface.</P>
<BLOCKQUOTE><PRE class=code>SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch,
Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
</PRE></BLOCKQUOTE>
<P>The notable differences are the lack of a flags parameter (the surface exists
in system RAM), and the addition of the pixels parameter and the pitch
parameter. The pixels parameter is a pointer to pixel data to use for this
surface, and pitch is how many bytes exist in each scan line, which does not
have to be width times depth. The other parameters are the same as for
SDL_CreateRGBSurface. If this function fails, it returns NULL.</P>
<P>Something to keep in mind if you are using SDL_CreateRGBSurfaceFrom: the
pixels parameter should not be freed until you have freed the surface, since the
pixel data you supply to this function is the actual pixel data used by the
surface. It does not make a copy.</P>
<P>The final function for creating a surface is SDL_LoadBMP. This is a damn
handy function. It loads in a standard windows .bmp file onto a surface, and
returns the new surface.</P>
<BLOCKQUOTE><PRE class=code>SDL_Surface *SDL_LoadBMP(const char *file);
</PRE></BLOCKQUOTE>
<P>This function takes a single parameter, a pointer to a string containing the
name of the file you wish to load. It returns the newly created surface, or NULL
if there is an error.</P>
<P>The SDL_LoadBMP function is a godsend. If you've worked with either
DirectDraw or GDI, you know how much of a pain it can be to get a stupid bitmap
loaded. In SDL, its only a single function call! If that's not reason enough to
move to SDL... I don't know what is.</P>
<P>There are two more really cool functions that you can use to create surfaces,
but they are used more for pixel format conversion rather than creating
something in their own right. They take an already existing surface and create a
new surface, with the same contents, but a different pixel format.</P>
<P>The first of these is SDL_ConvertSurface.</P>
<BLOCKQUOTE><PRE class=code>SDL_Surface *SDL_ConvertSurface(SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags ) ;
</PRE></BLOCKQUOTE>
<P>The parameters are fairly straightforward. You give this function a pointer
to a surface that you need converted, a pointer to the format you want it
converted to, and a combinatin of flags ( these flag are the same as those used
in other surface creation functions). This function creates a surface in the
requested format, with the requested flags (if possible), and gives you back a
pointer to a new surface. If this function fails, it'll give you NULL.</P>
<P>The second of these is SDL_DisplayFormat.</P>
<BLOCKQUOTE><PRE class=code>SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface);
</PRE></BLOCKQUOTE>
<P>This function takes a surface, and converts it to the display format, so that
you can make better use of hardware acceleration, if it exists. It returns a
pointer to the newly converted surface, or NULL if it fails.</P>
<P>Typically, after calling SDL_ConvertSurface or SDL_DisplayFormat to convert a
surface, you will want to destroy the old, pre-converted, surface.</P>
<P>Speaking of destroying surfaces, doing so is also quite easy. You simply call
SDL_FreeSurface.</P>
<BLOCKQUOTE><PRE class=code>void SDL_FreeSurface(SDL_Surface *surface);
</PRE></BLOCKQUOTE>
<P>This function takes a pointer to a surface, and returns no values. The
surface's refcount member is decremented, and if the refcount reaches 0, then
the surface is deleted.</P>
<H1>Using SDL Video (TGO-02-D)</H1>
<P>To start with, recall the example we ended with last time (or at least
something very close):</P>
<BLOCKQUOTE><PRE class=code>#include "SDL.h"
enum {
SCREENWIDTH = 512,
SCREENHEIGHT = 384,
SCREENBPP = 0,
SCREENFLAGS = SDL_ANYFORMAT
} ;
int main( int argc, char* argv[] )
{
//initialize systems
SDL_Init ( SDL_INIT_VIDEO ) ;
//set our at exit function
atexit ( SDL_Quit ) ;
//create a window
SDL_Surface* pSurface = SDL_SetVideoMode ( SCREENWIDTH , SCREENHEIGHT ,
SCREENBPP , SCREENFLAGS ) ;
//declare event variable
SDL_Event event ;
//message pump
for ( ; ; )
{
//look for an event
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -