Drawing lines and ellipses with DirectDraw

This is a discussion on Drawing lines and ellipses with DirectDraw within the Game Programming forums, part of the General Programming Boards category; Hey everyone, this is my problem: I want to draw a line and an ellipse, but DirectDraw has no built-in ...

  1. #1
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879

    Question Drawing lines and ellipses with DirectDraw

    Hey everyone, this is my problem: I want to draw a line and an ellipse, but DirectDraw has no built-in features to do so, except for in VB. Searching through my book and my brain, I came up with only two solutions: manually calculate the position of each pixel, then lock the surface and plot them; or make a call to GetDC, and use GDI to draw the line. The latter is from my unreliable book, and uses the reputedly slow GDI. However, I have no idea if the manual calculate/plot approach would be any faster. Which method should I try?
    Last edited by Hunter2; 01-04-2003 at 03:37 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  2. #2
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Using GDI can be slow, true. However, locking the surfaces is pretty slow also and SetPixel is RIDICULOUSLY slow. So, unless you want to write your own SetPixel ( SetPixelV slightly faster.. ) I suggest just using GDI. If you're curious though you can write your own line drawing algorithm. Look up Bresenham on google and you can use his algorithm. There are similar algorithms for elipses, circles, triangles, polygons etc. Many use DDA style algorithms. If this is not you cup of tea then you can use GDI.

    Alternatively, you may use a bitmap as the elipse depending on what you are doing and manipulate it accordingly. Just a thought.

  3. #3
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    However, locking the surfaces is pretty slow also and SetPixel is RIDICULOUSLY slow.
    I'm assuming you mean the GDI SetPixel, since I can't seem to find one in the DX docs... But if that's the case, wouldn't that defeat the purpose of avoiding GDI?

    So, unless you want to write your own SetPixel
    I was sort of thinking of that, actually, by locking the surface and setting the pixels directly. But then, locking the surface is "pretty slow"... Would it still be faster though?

    If you're curious though you can write your own line drawing algorithm.
    That could be interesting; I could even try adding special effects I guess, like gradient lines

    In conclusion: For the moment, I guess I'll use GDI to draw my lines, although if it's worthwhile I'll probably look into making my own line/ellipse things later. Thanks MrWizard!


    **EDIT**
    About using a bitmap for an ellipse, I thought about that... but then wouldn't it take a lot of memory and take even longer to make the blit? (i.e. has to set a lot more pixels)
    Last edited by Hunter2; 01-03-2003 at 12:18 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  4. #4
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    I would say just use GDI and unless you REALLY see a performance hit don't worry about it. You should be ok just using that. One of the times I lock surfaces is to check collisions. I can't think of too many others where you need to lock the surfaces. I'd say just use GDI you should be fine.

  5. #5
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Ok, thanks alot!
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  6. #6
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Hey, guys (or maybe just MrWizard ), new question! I trying to make a SetPixel or my own - this is my idea so far:
    PHP Code:
    //the surface is already locked
    //pixels contains the data, and is an unsigned char*
    //ddsd is my DDSURFACEDESC2 filled in with the data

    bool setPixel(DWORD xDWORD yDWORD colour)
    {
         if((
    y) > numPixels)
              return 
    false;
         
         
    unsigned charptr pixels;

         
    int bytes_per_pixel ddsd.ddpfPixelFormat.dwRGBBitCount >> 3;

         
    ptr += ((+ (ddsd.lPitch >> bytes_per_pixel)) * bytes_per_pixel);

         if(
    ddsd.ddpfPixelFormat.dwRGBBitCount == 8)
              *
    ptr = (unsigned char)colour;
         else if(
    ddsd.ddpfPixelFormat.dwRGBBitCount == 16)
              *(
    unsigned short*)ptr = (unsigned short)colour;
         else if(
    ddsd.ddpfPixelFormat.dwRGBBitCount == 32)
              *(
    DWORD*)ptr = (DWORD)colour;

         return 
    true;

    Would this code work? Or if it would, would it be too slow or unreliable or something? (I heard that multiplication is a really bad thing to have in graphics code)

    **EDIT**
    Another idea I had, was instead of the ifs, using a typedef when I lock the surface (i.e. do the if's then instead of now, then "typedef the_type (unsigned char)" or "typedef the_type (unsigned short)"). Would it work if I tried re-typedefing a type?

    **EDIT2**
    sorry, with all my editing the code, it's getting really jumbled right now...
    Last edited by Hunter2; 01-04-2003 at 02:14 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  7. #7
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Tell ya what. I'm leaving to go back to Seattle early Sunday. When I get home I'll post my code for setting and getting pixels. I think its pretty similar but may have slight differences. Talk to you more about it later.

    EDIT:

    Check your PM's Hunter2,
    Last edited by MrWizard; 01-05-2003 at 05:47 PM.

  8. #8
    Registered User
    Join Date
    Jan 2003
    Posts
    3

    My linedraw

    It's for DirectX8 and it only works for 32bit color.
    But maybe you can use it. But you have to remove or replace some of the variables with your own (such as m_iScreenWidth and my specific buffer names).

    Oh yeah and it uses goto...HAHA..

    PHP Code:
    void LineDraw(int x1int y1int x2int y2int rint gint b)
    {
        
    LPDIRECT3DSURFACE8 pBackBuffer;
        
    D3DLOCKED_RECT D3DLockedRect;
        
    HRESULT hr;
        
    int *pSurfaceData;
        
    int *p;
        
    int        Color32 0x0000000//ARGB

        
    if (m_iBitsPerPixel == 32)
        {
            
    Color32 |= b;
            
    Color32 |= (<<8);
            
    Color32 |= (<<16);
        }
        else
            return;

        
    int        xy;
        
    int        dxdy;
        
    int        incxincy;
        
    int        balance;

        if ( (
    x1<0) || (x1<=m_iScreenWidth) || (y1<0) || (y1>=m_iScreenHeight) || (x2 >= m_iScreenWidth) || (x2 0) || (y2<0) || (y2 >= m_iScreenHeight) )
            goto 
    LINEDRAWWITHCHECK;


        
    //lock backbuffer
        
    m_pd3dDevice->GetBackBuffer(0D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
        
    hr pBackBuffer->LockRect(&D3DLockedRectNULLD3DLOCK_NO_DIRTY_UPDATE);
        if (
    hr != D3D_OK)
        {
            
    pLog->Log("Gfx::LineDraw - unable to lock backbuffer");
            return;
        }

        
    pSurfaceData = (int*)D3DLockedRect.pBits;

        
        if (
    x2 >= x1)
        {
            
    dx x2 x1;
            
    incx 1;
        }
        else
        {
            
    dx x1 x2;
            
    incx = -1;
        }

        if (
    y2 >= y1)
        {
            
    dy y2 y1;
            
    incy 1;
        }
        else
        {
            
    dy y1 y2;
            
    incy = -1;
        }

        
    x1;
        
    y1;

        if (
    dx >= dy)
        {
            
    dy <<= 1;
            
    balance dy dx;
            
    dx <<= 1;

            while (
    != x2)
            {
                
    //plotpixel
                
    pSurfaceData;
                
    += (* (D3DLockedRect.Pitch/4)) + x;
                *
    Color32;

                if (
    balance >= 0)
                {
                    
    += incy;
                    
    balance -= dx;
                }
                
    balance += dy;
                
    += incx;
            } 

            
    //plotpixel
            
    pSurfaceData;
            
    += (* (D3DLockedRect.Pitch/4)) + x;
            *
    Color32;
            
        }
        else
        {

            
    dx <<= 1;
            
    balance dx dy;
            
    dy <<= 1;

            while (
    != y2)
            {
                
    //plotpixel
                
    pSurfaceData;
                
    += (* (D3DLockedRect.Pitch/4)) + x;
                *
    Color32;

                if (
    balance >= 0)
                {
                    
    += incx;
                    
    balance -= dy;
                }
                
    balance += dx;
                
    += incy;
            } 

            
    //plotpixel
            
    pSurfaceData;
            
    += (* (D3DLockedRect.Pitch/4)) + x;
            *
    Color32;

        }

        
    //unlock backbuffer
        
    hr pBackBuffer->UnlockRect();
        if (
    hr != D3D_OK)
        {
            
    pLog->Log("Gfx::Unable to unlock backbuffer. ");
        }
        return;

    LINEDRAWWITHCHECK:

        
    //lock backbuffer
        
    m_pd3dDevice->GetBackBuffer(0D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
        
    hr pBackBuffer->LockRect(&D3DLockedRectNULLD3DLOCK_NO_DIRTY_UPDATE);
        if (
    hr != D3D_OK)
            return;
        
    pSurfaceData = (int*)D3DLockedRect.pBits;
        
        if (
    x2 >= x1)
        {
            
    dx x2 x1;
            
    incx 1;
        }
        else
        {
            
    dx x1 x2;
            
    incx = -1;
        }

        if (
    y2 >= y1)
        {
            
    dy y2 y1;
            
    incy 1;
        }
        else
        {
            
    dy y1 y2;
            
    incy = -1;
        }

        
    x1;
        
    y1;

        if (
    dx >= dy)
        {
            
    dy <<= 1;
            
    balance dy dx;
            
    dx <<= 1;

            while (
    != x2)
            {
                
    //plotpixel
                
    if ( (>=0) && (<m_iScreenWidth) && (>=0) && (m_iScreenHeight) )
                {
                    
    pSurfaceData;
                    
    += (* (D3DLockedRect.Pitch/4)) + x;
                    *
    Color32;
                }

                if (
    balance >= 0)
                {
                    
    += incy;
                    
    balance -= dx;
                }
                
    balance += dy;
                
    += incx;
            } 
            
    //plotpixel
            
    if ( (>=0) && (<m_iScreenWidth) && (>=0) && (m_iScreenHeight) )
            {
                
    pSurfaceData;
                
    += (* (D3DLockedRect.Pitch/4)) + x;
                *
    Color32;
            }
            
        }
        else
        {
            
    dx <<= 1;
            
    balance dx dy;
            
    dy <<= 1;

            while (
    != y2)
            {
                
    //plotpixel
                
    if ( (>=0) && (<m_iScreenWidth) && (>=0) && (m_iScreenHeight) )
                {
                    
    pSurfaceData;
                    
    += (* (D3DLockedRect.Pitch/4)) + x;
                    *
    Color32;
                }

                if (
    balance >= 0)
                {
                    
    += incx;
                    
    balance -= dy;
                }
                
    balance += dx;
                
    += incy;
            } 

            
    //plotpixel
            
    if ( (>=0) && (<m_iScreenWidth) && (>=0) && (m_iScreenHeight) )
            {
                
    pSurfaceData;
                
    += (* (D3DLockedRect.Pitch/4)) + x;
                *
    Color32;
            }

        }

        
    //unlock backbuffer
        
    hr pBackBuffer->UnlockRect();
        if (
    hr != D3D_OK)
            
    pLog->Log("Gfx::LineDraw() - Unable to unlock backbuffer.");


  9. #9
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Unless you're making a REALLY graphics-intensive game, the GDI is fine.
    It's actually not that slow.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  10. #10
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Ok, thanks everyone.

    P.S.
    I really needed the SetPixel(), since that's doing all the background-drawing (i.e. drawing stars), and in the GDI version the star-drawing took something like the 4th longest time to do.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

Popular pages Recent additions subscribe to a feed

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21