04.03 - Pixel Manipulation

Started by
47 comments, last by Teej 22 years, 4 months ago
Biere et punk,
Ok ya that's what I thought

Piotyr,
I ran into the same problem as you, but i found a solution that worked for me.

The problem seems to be in the order of the for loops. Try switching them around so the x variable is the outer for loop and the y variable is the inner one.

eg.
for (x = 0; x < SCREEN_WIDTH; x++){   for (y = 0; y < SCREEN_HEIGHT; y++)       buffer[x + y*lPitch] = color;}  


The pixels will now be drawn in vertical lines on the screen instead of horizontally. I'm not sure why it would cause a problem the other way, maybe someone can shed some light on the topic?

Edited by - Dionysis on May 9, 2001 12:49:14 AM
Advertisement
Hello everyone... Just browsing through here because i LOVE the idea, teej wish this was around when i first met DDraw!

thought i might throw in some code for determining the pixels in 16bit mode.

during initialization, call:

ZeroMemory(&ddPF, sizeof(ddPF));
ddPF.dwSize = sizeof(ddPF);

// get the information from the back surface
ddret = lpSurface->GetPixelFormat(&ddPF);
if (ddret != DD_OK)
return FALSE;

// now we interpret the return values
if (ddPF.dwFlags & DDPF_RGB) {
switch (ddPF.dwRGBBitCount) {
case 16: {
DWORD dwRBM = ddPF.dwRBitMask;
DWORD dwGBM = ddPF.dwGBitMask;
DWORD dwBBM = ddPF.dwBBitMask;
// calculate shift left amount
for (iRSHL=0; (dwRBM&1)!=1; iRSHL++) dwRBM>>=1;
for (iGSHL=0; (dwGBM&1)!=1; iGSHL++) dwGBM>>=1;
for (iBSHL=0; (dwBBM&1)!=1; iBSHL++) dwBBM>>=1;
// calculate shift right amount
for (iRSHR=8; (dwRBM&1)==1; iRSHR--) dwRBM>>=1;
for (iGSHR=8; (dwGBM&1)==1; iGSHR--) dwGBM>>=1;
for (iBSHR=8; (dwBBM&1)==1; iBSHR--) dwBBM>>=1;
// calculate the mask to use for merging colors
// merge means taking the average of two pixels, giving a 'translucent' effect
dwMergeMask = 0xFFFFFFFF;
if (iRSHL>0)
dwMergeMask ^= 1<<(iRSHL+15) | 1<<(iRSHL-1);
if (iGSHL>0)
dwMergeMask ^= 1<<(iGSHL+15) | 1<<(iGSHL-1);
if (iBSHL>0)
dwMergeMask ^= 1<<(iBSHL+15) | 1<<(iBSHL-1);
dwMergeMask ^= 1<<31 | 1<<15;
break;
}



(that was a quick cut and paste, so there is probably braces missing)

then, when you want to write the pixel, use:

  buffer[offset]= (red >>iRSHR<<iRSHL) | (green >>iGSHR<<iGSHL) | (blue >>iBSHR<<iBSHL);  


this way, red green and blue are values from 0 to 255 and it will always work, whether 5-5-5 or 5-6-5 or whatever format.

erm... i don't want to intrude on what teej is telling you so just ignore the dwMergeMask for the moment

Edited by - zenic on May 10, 2001 1:27:49 AM
Hey Teej

First of all I would like to say you are doing a great job. Secondly I think I have found an error in your document. You say that the pitch is the number of extra bytes use by the screen card, but in fact it is the total of the width plus extra bytes used by the screen card. The source code it correct, but in your article under "Using the Memory Pitch" you have the formula "buffer[ y * (SCREEN_WIDTH + lPitch) + x] = color;" which is wrong. It should be buffer[y*lPitch + x] = colour;

I hope this helps.

Edited by - White Knight on May 10, 2001 6:28:51 AM
First time I''ve visited here and this whole thing looks like a really good idea. But I have a query if anyone can help.

I''ve locked two surfaces (one off screen and one a back buffer for the primary surface) running in 32 bit colour and i''m trying to copy data between them. (I''m not bliting ''cos I''m performing a few operations of the data). My basic code is:

//Lock surfaces
lpDDSOffScreen->Lock(pSourceRECT, &DDSDSource, DDLOCK_WAIT | DDLOCK_READONLY, NULL);
lpDDSBackBuffer->Lock(pDestRECT, &DDSDDest, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
//Devide pitches by 4 to adjust for double words
DDSDSource.lPitch/=4;
DDSDDest.lPitch/=4;
//Extract pointers to surface areas
pDWORDSource=(DWORD *)DDSDSource.lSurface;
pDWORDDest=(DWORD *)DDSDDest.lpSurface;
//Loop through surface area
for(int nCountY=0; nCountYbottom-pSourceRECT->top; nCountY++)
{
for(int nCountX; nCountXright-pSourceRECT->left; nCountX++)
{
//Move data (Obviously I do more than this in reality or I''d just use a blit)
*(pDWORDDest+nCountX)=*(pDWORDSource+nCountX);
}
//Move to next rows in surfaces
pDWORDSource+=DDSDSource.lPitch;
pDWORDDest+=DDSDDest.lPitch;
}
//Unlock surface
lpDDSBackBuffer->Unlock(pDestRECT);
lpDDSOffScreen->UnLock(pSourceRECT);

If I do the same thing with words or bytes it works fine, just not with double words. (Adjusting the devision on lPitch to match.) And it is definately using 32bit colour. (I''ve check all the values in my DDSURFACEDESC structers.)

Can anyone please help me?
Sorry, I forgot to mention what went wrong just above (it is early morning at the moment here y''know). Anyway I get a sort of blue hue to everything.

Thats everything (I''m sure of it)
First, teej great thing you are doing here .

And then, a cool program that all of you can try out.
First pick a random point on the screens. Then start drawing a square of which the center is at the specific point. The width of the square increases with every entrance in the Game_Main function. When the square reaches one of the edges of the screen, start over again with a new randomly choosen point.

How I did it:

  int Game_Main(){  DWORD *buffer;  long lPitch;  static POINT p;         // the random center of the square  static WORD color;      // square color  static int squarewidth; // the half of the width of the square  // the code below will fill our entire surface with one color  DDBLTFX ddbltfx;  ZeroMemory(&ddbltfx, sizeof(ddbltfx));  ddbltfx.dwSize = sizeof(ddbltfx);  // fill with black  ddbltfx.dwFillColor = 0;  G.lpDDSBack->Blt(NULL,NULL,NULL,                   DDBLT_COLORFILL | DDBLT_WAIT,                   &ddbltfx);    // check if we are touching one of the edges  if (p.y-squarewidth <= 0 ||      p.y+squarewidth >= SCREEN_HEIGHT ||      p.x-squarewidth <= 0 ||      p.x+squarewidth >= SCREEN_WIDTH)  {    p.x = rand()%SCREEN_WIDTH;    p.y = rand()%SCREEN_HEIGHT;    color = RGB16(rand()%32,rand()%64,rand()%32));    squarewidth = 0;  }  else  {    DDSURFACEDESC2 ddsd;    ZeroMemory(&ddsd, sizeof(ddsd));    ddsd.dwSize = sizeof(ddsd);    // lock surface    G.plDDSBack->Lock(NULL, &ddsd,                      DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,                      NULL);    buffer = (WORD *)ddsd.lpSurface;    lPitch = ddsd.lPitch >> 1;    // put the square onto the surface    int x, y;    for (y=p.y-squarewidth; y<p.y+squarewidth; y++)    {      for (x=p.x-squarewidth; x<p.x+squarewidth; x++)      {        buffer[y*lPitch+x] = color;      }    }    // unlock the surface again    G.lpDDSBack->Unlock(NULL);  }  // enlarge the square  squarewidth++;  // flip backbuffer to primary  G.lpDDSPrimary->Flip(NULL, 0);}  



Well, this should work. There can be some errors in it, because I don''t have the code with me.
ErrorX: Who knows where the tutorial will end. There''s much to learn and practice on in the world of 2D games, and then there''s 3D...

Dionysis: Will get back to you with a better explaination shortly (busy at the moment).

White Knight: Thanks for spotting the error...I was typing madly when I wrote it, and lost track there. I''ve fixed the article.

Anon: Will try your code this evening...


Teej
Anon: I''ve tried the code...very nice, indeed!

For anyone who wants to try it, I''ve added it to this post and corrected any subtle typos that Anon made (recognizing the fact that he typed it from memory so there''s bound to be some little thing off here and there):

  void Game_Main(){    WORD *buffer;    long lPitch;    static POINT p;         // the random center of the square      static WORD color;      // square color      static int squarewidth; // the half of the width of the square          // the code below will fill our entire surface with one color      DDBLTFX ddbltfx;    ZeroMemory(&ddbltfx, sizeof(ddbltfx));    ddbltfx.dwSize = sizeof(ddbltfx);    // fill with black      ddbltfx.dwFillColor = 0;      G.lpDDSBack->Blt(NULL,NULL,NULL,                     DDBLT_COLORFILL | DDBLT_WAIT,                     &ddbltfx);        // check if we are touching one of the edges      if (p.y-squarewidth <= 0 ||        p.y+squarewidth >= SCREEN_HEIGHT ||        p.x-squarewidth <= 0 ||        p.x+squarewidth >= SCREEN_WIDTH)    {            p.x = rand()%SCREEN_WIDTH;        p.y = rand()%SCREEN_HEIGHT;        color = RGB16(rand()%32,rand()%64,rand()%32);        squarewidth = 0;    }    else    {        DDSURFACEDESC2 ddsd;        ZeroMemory(&ddsd, sizeof(ddsd));        ddsd.dwSize = sizeof(ddsd);        // lock surface        G.lpDDSBack->Lock(NULL, &ddsd,                          DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,                          NULL);        buffer = (WORD *)ddsd.lpSurface;        lPitch = ddsd.lPitch >> 1;        // put the square onto the surface         int x, y;        for (y=p.y-squarewidth; y<p.y+squarewidth; y++)        {            for (x=p.x-squarewidth; x<p.x+squarewidth; x++)            {                buffer[y*lPitch+x] = color;            }        }        // unlock the surface again        G.lpDDSBack->Unlock(NULL);    }    // enlarge the square    squarewidth++;    // flip backbuffer to primary    G.lpDDSPrimary->Flip(NULL, 0);}  


Anyone else?

Teej

PS: Anon, get yourself registered with GameDev.net so we know who you are!
Weyhey, were back up! Geez this site is cool, I spent 6 hours last night getting from the start to this point and am anxoius to carry on. I''ve been brushing up on trig and stuff and playing with DirectX coz I''m terminally impatiant

Thanx Teej.

Sad day today, mourning the loss of Douglas Adams........
For you fractal lovers, check this out:
    #define NUM_POINTS 3int pointsX[NUM_POINTS] = {SCREEN_WIDTH / 2, 50, SCREEN_WIDTH - 50};int pointsY[NUM_POINTS] = {50, SCREEN_HEIGHT - 50, SCREEN_HEIGHT - 50};int myX = rand() % SCREEN_WIDTH;int myY = rand() % SCREEN_HEIGHT;int i = 0;//////////////////////////////////////////////////////////////////////////////// Game_Main//// This function is called once per frame.//void Game_Main(){	   int pick = rand() % NUM_POINTS;	   myX = (myX + pointsX[pick]) / 2;	   myY = (myY + pointsY[pick]) / 2;	   if(i > 1000)	   {		   DDSURFACEDESC2 ddsd;		   WORD *buffer; 		   long lPitch;  		   // Prepare a DDSURFACEDESC2 structure for Lock() 		   ZeroMemory(&ddsd, sizeof(ddsd));		   ddsd.dwSize = sizeof(ddsd);		   // Lock the backbuffer surface		   G.lpDDSPrimary->Lock(NULL, &ddsd,			   DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);  		   // Get the surface pointer and the memory pitch (in WORDs)		   buffer = (WORD *)ddsd.lpSurface;		   lPitch = ddsd.lPitch / 2;		   // (bytes / 2 = WORDs)		   // Draw onto the display 		   buffer[myY*lPitch + myX] = RGB16(0,3,25);		  		   // Unlock the surface 		   G.lpDDSPrimary->Unlock(NULL); 	   }	   else		i++;}  


Edited by - FragLegs on May 12, 2001 9:00:05 PM

Edited by - FragLegs on May 12, 2001 9:01:32 PM

This topic is closed to new replies.

Advertisement