?? gamedev_net - the simple directmedia layer from a win32 perspective, part 2 sdl video.htm
字號:
<B>#include <stdlib.h>
#include <memory.h>
</B>
enum {
SCREENWIDTH = 512,
SCREENHEIGHT = 384,
SCREENBPP = 0,
SCREENFLAGS = SDL_ANYFORMAT
} ;
<B>void SetPixel ( SDL_Surface* pSurface , int x , int y , SDL_Color color ) ;
SDL_Color GetPixel ( SDL_Surface* pSurface , int x , int y ) ;
</B>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
if ( SDL_PollEvent ( &event ) )
{
//an event was found
if ( event.type == SDL_QUIT ) break ;
}
<B> //pick a random color
SDL_Color color ;
color.r = rand ( ) % 256 ;
color.g = rand ( ) % 256 ;
color.b = rand ( ) % 256 ;
//lock the surface
SDL_LockSurface ( pSurface ) ;
//plot pixel at random location
SetPixel ( pSurface , rand ( ) % SCREENWIDTH , rand ( ) % SCREENHEIGHT , color ) ;
//unlock surface
SDL_UnlockSurface ( pSurface ) ;
//update surface
SDL_UpdateRect ( pSurface , 0 , 0 , 0 , 0 ) ;
</B> }//end of message pump
//done
return ( 0 ) ;
}
<B>void SetPixel ( SDL_Surface* pSurface , int x , int y , SDL_Color color )
{
//convert color
Uint32 col = SDL_MapRGB ( pSurface->format , color.r , color.g , color.b ) ;
//determine position
char* pPosition = ( char* ) pSurface->pixels ;
//offset by y
pPosition += ( pSurface->pitch * y ) ;
//offset by x
pPosition += ( pSurface->format->BytesPerPixel * x ) ;
//copy pixel data
memcpy ( pPosition , &col , pSurface->format->BytesPerPixel ) ;
}
SDL_Color GetPixel ( SDL_Surface* pSurface , int x , int y )
{
SDL_Color color ;
Uint32 col = 0 ;
//determine position
char* pPosition = ( char* ) pSurface->pixels ;
//offset by y
pPosition += ( pSurface->pitch * y ) ;
//offset by x
pPosition += ( pSurface->format->BytesPerPixel * x ) ;
memcpy ( &col , pPosition , pSurface->format->BytesPerPixel ) ;
//convert color
SDL_GetRGB ( col , pSurface->format , &color.r , &color.g , &color.b ) ;
return ( color ) ;
}
</B></PRE></BLOCKQUOTE>
<P>Again, the code in bold is the code that has been added to the basic shell
application. This example starts placing dots of random colors onto the window.
When it runs, it looks somewhat like figure 2.</P>
<P class=maintext-2 align=center><IMG height=409
src="GameDev_net - The Simple DirectMedia Layer from a WIN32 Perspective, Part 2 SDL Video_files/02-02.jpg"
width=518> <BR><B>Figure 2: Random Pixels Demo</B></P>
<P>Once you can plot a pixel, you can do just about anything, including drawing
lines, circles, rectangular frames, and so on. Doing all of that stuff is
naturally beyond the scope of this article. I get you as far as plotting
pixels.</P>
<H2>Blitting</H2>
<P>The primary use of SDL_Surfaces is not to fill rectangles nor to plot pixels.
The main task is to copy rectangular sections from one surface to another, much
like GDI's BitBlt function and DirectDraw's Blt or BltFast function. The
function for doing that is SDL_BlitSurface.</P>
<BLOCKQUOTE><PRE class=code>int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);
</PRE></BLOCKQUOTE>
<P>This function takes four parameters, the source surface, a source rectangle,
a destination surface, and a destination rectangle. It returns 0 if everything
is OK, and -1 if there was a problem. If the pointers to either rectangle are
NULL, then the entire surface is assumed to be the source or destination area.
Naturally, you need two surfaces in order to perform a blit, although you can
use the same for both source and destination, at least in theory. The
documentation warns that you should not call SDL_BlitSurface on a surface that
is locked. So, time (already) for another quick example: the Amazing Bouncing
Ball Demo of Death(tm)!</P>
<P>Start yourself a new project, name it SDLBouncingBall or something just as
clever, and place the following code into main.cpp. Also, make a small bitmap
that is 32x32 pixels in size, draw a circle in it, and save it as ball.bmp.</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 ) ;
<B> //load bitmap
SDL_Surface* pBitmap = SDL_LoadBMP ( "ball.bmp" ) ;
//source and destination rectangles
SDL_Rect rcSrc , rcDst ;
rcSrc.w = pBitmap->w ;
rcSrc.h = pBitmap->h ;
rcSrc.x = 0 ;
rcSrc.y = 0 ;
rcDst = rcSrc ;
//movement rate
int dx = 2 , dy = 2 ;
</B> //declare event variable
SDL_Event event ;
//message pump
for ( ; ; )
{
//look for an event
if ( SDL_PollEvent ( &event ) )
{
//an event was found
if ( event.type == SDL_QUIT ) break ;
}
<B> //clear the screen
SDL_FillRect ( pSurface , NULL , 0 ) ;
//place the ball
SDL_BlitSurface ( pBitmap , &rcSrc , pSurface , &rcDst ) ;
//move the ball
rcDst.x += dx ;
rcDst.y += dy ;
//check for bounces
if ( rcDst.x == 0 || rcDst.x == SCREENWIDTH - rcDst.w ) dx = -dx ;
if ( rcDst.y == 0 || rcDst.y == SCREENHEIGHT - rcDst.h ) dy = -dy ;
//update the screen
SDL_UpdateRect ( pSurface , 0 , 0 , 0 , 0 ) ;
</B> }//end of message pump
//done
return ( 0 ) ;
}
</PRE></BLOCKQUOTE>
<P>And if you run the application, you'll see whatever image you made for your
ball bounce slowly around the window. Its not a particularly mind-boggling
example, but it does adequately demonstrate SDL_BlitSurface. Plus it's
hypnotic.... you are getting sleepy... sleeeeeepy....</P>
<P>Anyway. That's the simple blit demo. As we go along, this stuff just keeps
getting easier. Figure 3 shows what this program looks like.</P>
<P class=maintext-2 align=center><IMG height=409
src="GameDev_net - The Simple DirectMedia Layer from a WIN32 Perspective, Part 2 SDL Video_files/02-03.jpg"
width=518> <BR><B>Figure 3: Bouncing Ball Demo</B></P>
<P>Just a quick note before we move on. When using the SDL_BlitSurface function,
the contents of the SDL_Rect pointed to by dstrect can change if the destination
rectangle is clipped, so often it is a good idea to make a copy of the
destination rectangle prior to blitting, unless you absolutely know that the
destination rectangle lies entirely withing the destination surface.</P>
<H2>Color Keys</H2>
<P>And now we come to the issue of transparency. In GDI, in order to make
transparency work, you either need to use bitmasks, or else use the
TransparentBlt function, which doesn't work on all versions of Windows. In
DirectDraw, you have to set up a DDCOLORKEY for a surface that uses one, and you
have to pass particular flags when using the Blt or BltFast function.</P>
<P>In SDL, setting up a transparent color is really easy. Unlike DirectDraw, you
can only have one (1) transparent color for an SDL surface (of course, it's not
like DirectDraw had widespread support for transparent color spaces, but I
digress). In any case, a single color is usually enough for transparency anyway.
Once a color key has been set for a surface, it is used whenever that surface is
the source surface in a blit operation (which is nice, because then you don't
have to remember which surfaces have color keys).</P>
<P>The function for setting the color key of a surface is called
SDL_SetColorKey.</P>
<BLOCKQUOTE><PRE class=code>int SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key);
</PRE></BLOCKQUOTE>
<P>This function takes three parameters: a pointer to a surface, a flag, and a
key (the color, in the surfaces native pixel format). It returns an int, 0 if
successful, and -1 if there is an error.</P>
<P>If flag contiains SDL_SRCCOLORKEY, then the value in key becomes the new
transparent color key. If flag contains 0, any color key is cleared. You can
retrieve the color key from the surface's pixel format, e.g.
pSurface->format->colorkey.</P>
<P>Remember that key is in the native pixel format of the surface, and so if
working with SDL_Color variables, you'll need to convert it with SDL_MapRGB.</P>
<P>No example for color keys, as their use is fairly obvious.</P>
<H2>Clipping Rectangles</H2>
<P>As a final topic, I'm going to show you how to set up a clipping rectangle
for a surface. A clipping rectangle is the equivalent of an HRGN selected into
an HDC in GDI, or an IDirectDrawClipper object attached to an IDirectDrawSurface
object with SetClipper. Compared to their GDI or DirectDraw counterparts, the
SDL clipping rectangle is not nearly as powerful or flexible. You can only have
a single clipping rectangle at a time. For most purposes, that's enough. For
times when it is not, you'll just have to get creative.</P>
<P>A clipping rectangle is just that: a rectangular area ( as described by an
SDL_Rect variable) to which all destination blits are confined. Pixel plotting
is unaffected by the clipping rectangle, as it directly accesses the pixel data
of the surface. To set up a clipping rectangle for a surface, the function is
SDL_SetClipRect.</P>
<BLOCKQUOTE><PRE class=code>void SDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect);
</PRE></BLOCKQUOTE>
<P>This function returns no value. It takes two parameters, a pointer to a
surface (for which you are setting the clipping rectangle), and a pointer to an
SDL_Rect structure (which contains the new clipping rectangle). If you pass NULL
for rect, you will set the clipping area to the size of the entire surface.</P>
<P>To examine the contents of the clipping rectangle, you can either look at the
clip_rect member of the SDL_Surface structure, or you can use SDL_GetClipRect,
which has the same parameter list as SDL_SetClipRect, except that the current
clipping rectangle is instead read into the variable pointed to by rect.</P>
<P>No example for clipping rectangles, as their use is fairly obvious.</P>
<H1>Summary</H1>
<P>We haven't totally exhausted the video system of SDL yet. There is still
quite a bit more, but you've now been exposed to the basics. The functions shown
in this article will be the ones most oft-used, although there are certainly
some interesting aspects of some of the other functions, and later in the
series, we shall return once again to the video subsystem. For now, this shall
suffice.</P>
<P>Next Time: Events</P>
<P>Ernest S. Pazera</P>
<P><A href="mailto:ernestpazera@hotmail.com">ernestpazera@hotmail.com</A></P>
<P>Sources: SDL Documentation</P>
<P align=center><B><A
href="http://www.gamedev.net/community/forums/topic.asp?key=featart&uid=1603&forum_id=35&Topic_Title=The+Simple+DirectMedia+Layer+from+a+WIN32+Perspective%2C+Part+2%3A+SDL+Video">Discuss
this article in the forums</A></B></P>
<P><BR><SPAN class=maintext-2>Date this article was posted to GameDev.net:
<B>12/17/2001</B> <BR>(Note that this date does not necessarily correspond to
the date the article was written)</SPAN>
<P align=center>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -