Thread: LPDIRECTDRAWSURFACE7->Lock()

  1. #1
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145

    LPDIRECTDRAWSURFACE7->Lock()

    I'm having a question about this method. I'm working on a game and are using it to lock my background and then alter it pizel by pixel. I'm doing a fade-to-black and a fade-from-black.

    However, I've experienced that it is extremely slow to do this. Of course, modifying 640x480 pixels one by one may not be recommended, but this is rediciously slow (~2-3 fps) especially considering I'm using a P4 2.4GHz 1Gb RAM.

    I made some tests and it seems the lag only occurs when reading the data from the surface (to alter it):

    This simply sets the data to some value and it runs smoothly:
    Code:
    if(!FAILED(SecondarySurface->Lock(NULL, &SurfaceDesc, DDLOCK_WAIT, NULL)))
    {
       //Get a pointer to the surface
       SurfacePointer = (DWORD*)SurfaceDesc.lpSurface;
    
       for(Y = 0; Y < SCREENHEIGHT; Y++)
       {
          for(X = 0; X < SCREENWIDTH; X++)
          {
             (*SurfacePointer) = rand() % 0xFFFFFF;
             SurfacePointer++;
          }
       }
    
       //Unlock the surface
       SecondarySurface->Unlock(NULL);
    }
    This however is extremely laggy (I used the RGB macros before, but tried making my own too since I thought it was the macros that were so slow):
    Code:
    if(!FAILED(SecondarySurface->Lock(NULL, &SurfaceDesc, DDLOCK_WAIT, NULL)))
    {
       //Get a pointer to the surface
       SurfacePointer = (DWORD*)SurfaceDesc.lpSurface;
    
       for(Y = 0; Y < SCREENHEIGHT; Y++)
       {
          for(X = 0; X < SCREENWIDTH; X++)
          {
             TempColour = (*SurfacePointer);
    
             TempR = (BYTE)((INT)((TempColour & 0xFF0000) >> 16) * FadePercentage / 100);
             TempG = (BYTE)((INT)((TempColour & 0x00FF00) >> 8) * FadePercentage / 100);
             TempB = (BYTE)((INT)(TempColour & 0x0000FF) * FadePercentage / 100);
             (*SurfacePointer) = (TempR << 16) | (TempG << 8) | TempB;
    
             SurfacePointer++;
          }
       }
    
       //Unlock the surface
       SecondarySurface->Unlock(NULL);
    }
    I thought it might be too much calculations on each pixel, so I tried just this:
    Code:
    TempColour = (*SurfacePointer);
    (*SurfacePointer) = TempColour + 10;
    But that lags like h*ll too.

    It seems like the problem is the reading from the surface, but how can fix this? Help plz?

    EDIT:
    I'm using Visual C/C++ on WinXP
    Last edited by Magos; 03-18-2003 at 10:46 AM.
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  2. #2
    Used Registerer jdinger's Avatar
    Join Date
    Feb 2002
    Posts
    1,065
    Magos,
    A much faster way to perform a fade with DirectDraw is to use GammaRamps. It's really simple too.

    Here's the code from my engine (used DirectX 7):

    //the header file "Fade.h"
    Code:
    #pragma once
    
    //Types.h is a header file that I declare my typedefs, etc. in
    //for instance the "ul" in the CFade class is a typdef for an
    //unsigned long: typedef unsigned long ul;
    //and the lpdds7 is a typedef for an LPDIRECTDRAWSURFACE7:
    //typedef LPDIRECTDRAWSURFACE7 lpdds7;
    #include "Types.h"
    
    class CFade
    {
    private:
    	LPDIRECTDRAWGAMMACONTROL m_GammaControl;
    	DDGAMMARAMP m_GammaRamp;
    	DDGAMMARAMP m_OldGammaRamp;
    	DDGAMMARAMP m_TempRamp;
    	ul m_Timer;
    	bool m_Complete;
    	int m_TempI;
    public:
    	CFade();
    	~CFade();
    	void Init(const lpdds7 sf);
    	void Fade();
    };

    //the *.cpp file "Fade.cpp"
    Code:
    #include "Fade.h"
    
    CFade::CFade()
    {
    	m_GammaControl=0;
    	m_Timer=0;
    	m_Complete=false;
    }
    
    CFade::~CFade() 
    {
    	if(m_GammaControl)
    	{
    		m_GammaControl->SetGammaRamp(0,&m_OldGammaRamp);
    	}
    }
    
    void CFade::Init(const lpdds7 sf)
    {
    	sf->QueryInterface(IID_IDirectDrawGammaControl,(void **)&m_GammaControl);
    	m_GammaControl->GetGammaRamp(0,&m_OldGammaRamp);
    	m_GammaControl->GetGammaRamp(0,&m_GammaRamp);
    	m_Timer=timeGetTime();
    	for(int i=0;i<256;i++)
    	{
    		if(m_GammaRamp.red[i]>32) m_TempRamp.red[i]=m_GammaRamp.red[i]/32;
    		m_GammaRamp.red[i]=0;
    		if(m_GammaRamp.green[i]>32) m_TempRamp.green[i]=m_GammaRamp.green[i]/32;
    		m_GammaRamp.green[i]=0;
    		if(m_GammaRamp.blue[i]>32) m_TempRamp.blue[i]=m_GammaRamp.blue[i]/32;
    		m_GammaRamp.blue[i]=0;		
    	}
    	m_GammaControl->SetGammaRamp(0,&m_GammaRamp);
    	m_TempI=0;
    }
    
    void CFade::Fade()
    {
    	if(!m_Complete)
    	{
    		if((timeGetTime()-m_Timer)>500)
    		{
    			for(int i=0;i<256;i++)
    			{
    				m_GammaRamp.red[i]=m_TempRamp.red[i]*m_TempI;
    				m_GammaRamp.green[i]=m_TempRamp.green[i]*m_TempI;
    				m_GammaRamp.blue[i]=m_TempRamp.blue[i]*m_TempI;
    			}
    			m_GammaControl->SetGammaRamp(0,&m_GammaRamp);
    			m_TempI++;
    			m_Timer=timeGetTime();
    		}
    		if(m_TempI==32) m_Complete=true;
    	}
    }
    Then to initialize it you pass your primary surface as the parameter to Init() and put a call to Fade() inside your main loop.

    Sorry I didn't comment it :( Basically you get access to a Gamma Control with the call to the primary surface's QueryInterface member function. Then save the current gamma setting, use the current settings to get a temp setting which is a certain value less than the original (in my case I divide by 32). Then set the gamma settings to 0 (all black). To fade in you cycle through using a timer and you increment your gamma settings until it equals the original (in my case I add 32).

    It could be a lot cleaner (bit shifting is one optimization off the top of my head) and a bit more robust (fade out, etc). But this was a quick one I threw together. Feel free to add/change it however you need if you decide to use it.

  3. #3
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Thanks for the reply.

    I was under the impression that gammaramps faded the whole screen rather than specific parts of it (ie a surface). Is this true?
    I only want to fade the background while the rest of the screen (player, enemies, objects etc...) still is visible.
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  4. #4
    Used Registerer jdinger's Avatar
    Join Date
    Feb 2002
    Posts
    1,065
    Yes that is true. Sorry I didn't notice that you were just trying to fade a particular surface. I have limited exeperience with using Lock()/Unlock() mainly because I always understoond it to be really slow.

    I'll do some research tonight and see what I can come up with.

  5. #5
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    ya, it is slow .

    Anyway, I found a way that seems to work now. I copied the visul data from the background into a buffer. This way I can read from there instead from the surface directly, and since the background doesn't change during the fade I only need one read cycle per fade (2 actually, one for the fade-in and one for the fade-out).
    It runs pretty smooth now, though it will need testing on some slower machines later.

    Thanks anyway!
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  6. #6
    Used Registerer jdinger's Avatar
    Join Date
    Feb 2002
    Posts
    1,065
    Cool. Glad to hear that you found a workaround.

Popular pages Recent additions subscribe to a feed