Sign in to follow this  

Pixels & Locked DirectDraw Surfaces

This topic is 4688 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm having problem with drawing pixels to my DirectDraw surfaces. I mean to create a scrolling star field and to do this I need to lock the back buffer surface and draw each star as a pixel. The locking and unlocking of the surface goes well from what I see. But when I set the color to the correct memory location I get an error. I'm using 16-Bit colored surface and the problem I'm getting is that the application stalls and not all the stars are drawn. My hypothesis that either the memory location is incorrect or the color assignment is. I use the fallowing formula to find the proper memory location
video_buffer[ X + ( Y + surface_pitch ) ] = color

I've had problems figuring out how to achieve the correct colors. Would any of you know of any FOURCC macro that converts an RGB color to a 16-Bit equivalent? If the color format is 16-Bit then the bit count of the RGB components (taken from the DirectX SDK) should be R:5, G;6, B:5 or A:1/X:1, R:5, G:5, B:5. I figured I should just treat each color conversion and the later format R:5, G;, B:5. That way I know I'm safe. How do I convert the RGB color to a 16-Bit color?

Share this post


Link to post
Share on other sites
video_buffer[ X + ( Y + surface_pitch ) ] = color is wrong
it should be "Y * surface_pitch" (note the multiply instead of addition).

Maybe that'll help out..

You don't specify what your quantities are in that code though.

Q: What size is the video_buffer pointer? byte*? short* ? int*??
Q: What size is the color variable? Ideally it should match whatever the answer to the first question is [smile].

Quote:
Would any of you know of any FOURCC macro that converts an RGB color to a 16-Bit equivalent?

I do remember seeing some somewhere - not sure if they were standard (as in, part of the SDK headers) or part of the associated sample framework. Check your version of the SDK for any #defines... D3DCOLOR_ARGB() and D3DCOLOR_XRGB() definitely exist - they're not what you want, but if you search the files for them they might lead you to what you want.

Alternatively, they aren't too difficult to work out with some bit shifting..

#define MAKE_INTO_565RGB( r, g, b ) ( ((r) >> 3) | ((g) >> 2) | ((b) >> 3) )

is off the top of my head (not entirely sure it works!), assumes r,g,b are all 8 bit quantities though.

hth
Jack

Share this post


Link to post
Share on other sites
Actually, I met to put Y * surface_pitch. Oops, sorry my bad!

As I stated before, I'm using 16-Bit color format; so that would be a short or WORD. I assume that I could convert your macro to RGB_16BIT(R,G,B)(((R)>>5)|((G)>>6)|((B)>>5)) for 16-Bit color conversions.

I also cast the lpSurface memory pointer to a USHORT* variable. I use the star's position as an index using the above formula into the variable and assign the various star colors.

There are three layers to the star field. Each layer represents a depth in the star field and the colors of those stars are set to mimic the distance; in a more comic book since. The farthest layer (1) is a dark lavender, the middle layer (2) is a medium gray and the last layer (1) is a bright white with a small yellow tint. Pretty cool huh?

Any ways, these star layers slowly scroll across the screen with a separate speed. It's common since that stars farther away will seem to move more slowly then closer stars, so each layer is scrolled by the same speed as there index. For example layer 1 (the farthest away) is scrolled at a speed of 1. Simple right?

Well all of this would look cool if I could only get the pixels to show up on the screen. Plus, to actually move them and not have the application stalling or locking things up (as it has done for me).

Share this post


Link to post
Share on other sites
This is part of the code that is at the start of my drawing loop

DDSURFACEDESC2 DDsd ;
DDBLTFX DDfx ;
USHORT* pVidMem = NULL ;
SPRITEITOR Itor ;
HRESULT hRet ;

memset( &DDfx, 0, sizeof( DDBLTFX ) ) ;
DDfx.dwSize = sizeof( DDBLTFX ) ;
DDfx.dwFillColor = 0L ;

g_lpDDSBack->Blt( NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &DDfx ) ;

if ( FAILED( hRet = g_lpDDSBack->Lock( NULL, &DDsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL ) ) )
{
return ( hRet ) ;
}
else
{
pVidMem = ( USHORT* )DDsd.lpSurface ;

for ( int I = 0 ; I < STARFIELD_SIZE ; I++ )
{
switch ( g_vStarField[ I ].nSpeed )
{
case 0 :
g_vStarField[ I ].nX += 1 ;
break ;

case 1 :
g_vStarField[ I ].nX += 2 ;
break ;

case 2 :
g_vStarField[ I ].nX += 2 ;
break ;
}

if ( g_vStarField[ I ].nX > DDsd.lPitch )
{
g_vStarField[ I ].nX = 0 ;
g_vStarField[ I ].nY = rand( ) % 480 ;
g_vStarField[ I ].nSpeed = rand( ) % 3 ;
}

switch ( g_vStarField[ I ].nSpeed )
{
case 0 :
pVidMem[ g_vStarField[ I ].nX + ( g_vStarField[ I ].nY * DDsd.lPitch >> 1 ) ] =
RGB16( 80, 80, 100 ) ;
break ;

case 1 :
pVidMem[ g_vStarField[ I ].nX + ( g_vStarField[ I ].nY * DDsd.lPitch >> 1 ) ] =
RGB16( 140, 140, 140 ) ;
break ;

case 2 :
pVidMem[ g_vStarField[ I ].nX + ( g_vStarField[ I ].nY * DDsd.lPitch >> 1 ) ] =
RGB16( 255, 255, 240 ) ;
break ;
}
}

g_lpDDSBack->Unlock( NULL ) ;
}



As of now, I can see my window in fullscreen and that application stalls. I can still exit but all it does is stall. What is the problem here?

Share this post


Link to post
Share on other sites
1) the surface pitch is in bytes - so remember to divide by 2 if your "video_buffer" pointer is declared as something like WORD*, unsigned short*, u16* etc.


2) "video_buffer[ X + ( Y + surface_pitch ) ] = color" - you should be multiplying Y by the pitch, not adding it!!!


3) As you know, there are multiple layouts for a 16bit surface - typically 1555 and 565 in x,R,G,B order (where x is "unused" for DirectDraw - it can be alpha for textures in Direct3D). This does mean you're unlikely to get a single macro which handles all cases.


4) Take a look at the bit masks in the DDPIXELFORMAT structure for your surface - these will describe which bits of the pixel are used for which component (you'll need to know your binary). For example:

a. if dwRBitMask (the mask for RED) is 0xF800, then in binary that's: 1111 1000 0000 0000

b. "1111 1000 0000 0000" has 5 'on' bits, and they're at positions 11 to 15 in the word (assuming least significant bit starts at 0)

c. take another: dwGBitMask (the mask for GREEN) = 0x07E0 = 0000 0111 1110 0000

d. dwGBitMask has 6 'on' bits, from bit 5 up to bit 10


5) So say you want to set the green portion of a pixel to a value of 200 (assuming the colour values you want to set range from 0-255):

a. from a range of 0-255 uses 8 bits - from counting the bits in the green mask we know we only have 6 to store it in - the range it uses needs to be scaled down

b. in binary, 200 is: 11001000, and as you can see, it takes 8 bits

c. the easiest way to scale that down to 6 bits is with a bit shift - we'll lose the bits we shift off, but what happens to those bits is beyond the scope of this explanation (Google for "error diffusion" and "dithering"), and certainly not necessary for a starfield.

d. just like with decimal, the further to the left you get in a binary number, the more significant or important the value becomes - so to scale down, shift the number to the right:

green = green >> numbits

e. numbits = 8-6 : i.e. we have a number that's 8 bits long and we want it to fit into 6 bits so 8-6 is how many bits we need to get rid of.

f. 1100 1000 >> 2 == 0011 0010

g. if you look at that as a 16-bit number it's: 0000 0000 0011 0010

h. then look at the mask for green: 0000 0111 1110 0000

i. the number of used bits are correct, but the position of those bits is wrong - we can reposition them with another shift. We need the lowest bit of our green to start at bit 5

j. so shift left by 5: green = green << 5

k. if all you want is levels of green, then that's all you need to do to set a 16 bit pixel based on its mask - however you usually want more colour...

l. first repeat the above process for each colour component R, G, and B using each of the masks in the DDPIXELFORMAT so you end up with 3 variables: red, green, and blue

m. finally bitwise-OR the three variables together:

pixel = red|green|blue;

n. and that's it - an RGB pixel from separate R, G and B components.


There are optimisations you can make - there are alternatives to shifting - there are things you can do with the bits you lost off the shifting etc...

...I've also left the task of counting the number of bits in each mask and finding which position the lowest bit in each mask as well as the actual code as an exercise to the reader [you'll benefit from doing it yourself] :o)

Share this post


Link to post
Share on other sites
Well, I'm not even able to plot a pixel even with 0xFFFF. So the problem is not just in colors. I've tried lots of alternatives to figuring this problem out. But I'm going to switch to 8-Bit Palettized. That is what I originally wanted because its fast 2D graphics and they still look good if you use the right palette. Besides that, I can create easy effects with palette rotation. Thanks anyways.

Share this post


Link to post
Share on other sites

This topic is 4688 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this