Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

How to convert from one color space to another with DX9

Posted on 2011-10-30
5
Medium Priority
?
1,057 Views
Last Modified: 2012-05-12
Hi I need to convert a bitmap which is currently in D3DFMT_R8G8B8 I need to convert to D3DFMT_X8R8G8B8 is there a simple way of doing this in DX9 so I can use it in a CreateOffscreenPlainSurface.
0
Comment
Question by:nchannon
  • 3
  • 2
5 Comments
 
LVL 12

Expert Comment

by:satsumo
ID: 37054187
Can you explain what the objective for this is?  Why can't you use R8G8B8 with an OffscreenPlainSurface?  What are you trying to do with it?  Which pool are you using?
0
 

Author Comment

by:nchannon
ID: 37064305
Hi I needed to copy a R8G8B8 (RGB24) bmp image to a OffscreenPlainSurface but my hardware only supported X8R8G8B8 and a few others but I have found the solution, I have posted it here if anyone else has the same problem.

What im trying to do is move away from DirectDraw as i need to port my application to win7 and win7 complains when using DD.

PS mypool im using to create the offscreensurface is D3DPOOL_DEFAULT.

If you can help me out with another problem I award these point to you saves setting up another help question and as you seem to be the only one answering DX questions I see no point.
As im porting from DD to DX9 I have run into another problem

HRESULT CMainDX::BltFast(LPDIRECT3DSURFACE9 Dest,LPDIRECT3DSURFACE9 Src, int x, int y, RECT srcRect)
{
	if (g_pd3dDevice == NULL) return DT_NOT_INITIALIZED;
	if (Src == NULL) return DT_NOT_INITIALIZED;
	if (Dest == NULL) return DT_ERROR;

	// Clipping
	if (srcRect.left < 0) srcRect.left = 0;
	if (srcRect.left > (int)(m_Width)) srcRect.left = (m_Width);
	if (srcRect.top < 0) srcRect.top = 0;
	if (srcRect.top > (int)(m_Height)) srcRect.top = (m_Height);

	if (srcRect.right < srcRect.left) srcRect.right = srcRect.left;
	if (srcRect.right > (int)(m_Width)) srcRect.right = (m_Width);
	if (srcRect.bottom < srcRect.top) srcRect.bottom = srcRect.top;
	if (srcRect.bottom > (int)(m_Height)) srcRect.bottom = (m_Height);

	UINT nHeight = srcRect.bottom-srcRect.top;
	UINT nWidth = srcRect.right-srcRect.left;

	D3DSURFACE_DESC sdesc;
	Dest->GetDesc(&sdesc);

	// Clipping
	if (x < 0)
	{	
		nWidth += x;
		x = 0;
	}
    if (x+nWidth > sdesc.Width)
	{
		nWidth = sdesc.Width-x;
	}
	if (y < 0)
	{
		nHeight += y;
		y = 0;
	}
	if (y+nHeight > sdesc.Height)
	{
		nHeight = sdesc.Height-y;
	}

	// Return if we don't have anything to blit
	if ((nHeight <= 0) || (nWidth <= 0)) return DT_OK;

	RECT destRect; destRect.left=x; destRect.top=y; destRect.right=x+nWidth; destRect.bottom=y+nHeight;

	// Get source and destination pixelformats
	// Optimization: Remove this and do it somewhere else where you can do it once since it makes things slower.
	DT_PIXELFMT spFmt, dpFmt;
	int ret = m_PixelFormat.GetDTPixelFormat(m_Format, &spFmt);
	if (ret != DT_OK) return ret;
	ret = m_PixelFormat.GetDTPixelFormat(sdesc.Format, &dpFmt);
	if (ret != DT_OK) return ret;

	D3DLOCKED_RECT slRect;
	D3DLOCKED_RECT dlRect;

	if (Src->LockRect(&slRect, &srcRect, D3DLOCK_READONLY) == D3D_OK)
	{
		if (Dest->LockRect(&dlRect, &destRect, 0) == D3D_OK)
		{
			BYTE* Source = (BYTE*)slRect.pBits;
			BYTE* Dest = (BYTE*)dlRect.pBits;

			for (UINT y1=0; y1<nHeight; y1++)
			{
				BYTE* Source2 = (BYTE*)Source;
				BYTE* Dest2 = (BYTE*)Dest;

				// If the surface formats would be the same, and we just want to do a SRCCOPY blit, we could just do the following to make it fast:
				//*(WORD*)Dest2 = *(WORD*)Source2;

				// But the following code illustrates breaking up a pixel from the source surface in ARGB components,
				// and then reassembling them on the destination surface, after color conversion if needed. With this 
				// code you can add blending effects such as translucency, multiply, overlay etc.
				// In an application with realtime animation, like a game, however you would not want to work with 
				// many different surface formats, because color conversion makes the blit slower. The best 
				// thing to do would be to use one surface format that best suites your needs.
				
				for (UINT x1=0; x1<nWidth; x1++)
				{
					if (spFmt.BitsPerPixel == 16)
					{
						WORD Sp = *(WORD*)Source2;
											
						DWORD alpha = ((Sp & spFmt.ABMask) >> spFmt.AShift);
						DWORD red = ((Sp & spFmt.RBMask) >> spFmt.RShift);
						DWORD green = ((Sp & spFmt.GBMask) >> spFmt.GShift);
						DWORD blue = ((Sp & spFmt.BBMask) >> spFmt.BShift);

						// Color conversion
						if (spFmt.Format != dpFmt.Format)
						{
							alpha = (DWORD) ((float)((float)alpha/(float)spFmt.AMaxVal) * (float)dpFmt.AMaxVal);
							red = (DWORD) ((float)((float)red/(float)spFmt.RMaxVal) * (float)dpFmt.RMaxVal);
							green = (DWORD) ((float)((float)green/(float)spFmt.GMaxVal) * (float)dpFmt.GMaxVal);
							blue = (DWORD) ((float)((float)blue/(float)spFmt.BMaxVal) * (float)dpFmt.BMaxVal);
						}

						if (dpFmt.BitsPerPixel == 16)
						{
  							WORD* Dp = (WORD*)Dest2;
							*Dp = (WORD) ((((alpha) << dpFmt.AShift) & dpFmt.ABMask) |
										(((red) << dpFmt.RShift) & dpFmt.RBMask) |
										(((green) << dpFmt.GShift) & dpFmt.GBMask) |
										(((blue) << dpFmt.BShift) & dpFmt.BBMask));
						}
						else if (dpFmt.BitsPerPixel > 16)
						{
  							DWORD* Dp = (DWORD*)Dest2;
							*Dp = (DWORD) ((((alpha) << dpFmt.AShift) & dpFmt.ABMask) |
										(((red) << dpFmt.RShift) & dpFmt.RBMask) |
										(((green) << dpFmt.GShift) & dpFmt.GBMask) |
										(((blue) << dpFmt.BShift) & dpFmt.BBMask));
						}
					}
					else if (spFmt.BitsPerPixel > 16)
					{
						DWORD Sp = *(DWORD*)Source2;
											
						DWORD alpha = ((Sp & spFmt.ABMask) >> spFmt.AShift);
						DWORD red = ((Sp & spFmt.RBMask) >> spFmt.RShift);
						DWORD green = ((Sp & spFmt.GBMask) >> spFmt.GShift);
						DWORD blue = ((Sp & spFmt.BBMask) >> spFmt.BShift);

						// Color conversion
						if (spFmt.Format != dpFmt.Format)
						{
							alpha = (DWORD) ((float)((float)alpha/(float)spFmt.AMaxVal) * (float)dpFmt.AMaxVal);
							red = (DWORD) ((float)((float)red/(float)spFmt.RMaxVal) * (float)dpFmt.RMaxVal);
							green = (DWORD) ((float)((float)green/(float)spFmt.GMaxVal) * (float)dpFmt.GMaxVal);
							blue = (DWORD) ((float)((float)blue/(float)spFmt.BMaxVal) * (float)dpFmt.BMaxVal);
						}
					
						if (dpFmt.BitsPerPixel == 16)
						{
  							WORD* Dp = (WORD*)Dest2;
							*Dp = (WORD) ((((alpha) << dpFmt.AShift) & dpFmt.ABMask) |
										(((red) << dpFmt.RShift) & dpFmt.RBMask) |
										(((green) << dpFmt.GShift) & dpFmt.GBMask) |
										(((blue) << dpFmt.BShift) & dpFmt.BBMask));
						}
						else if (dpFmt.BitsPerPixel > 16)
						{
  							DWORD* Dp = (DWORD*)Dest2;
							*Dp = (DWORD) ((((alpha) << dpFmt.AShift) & dpFmt.ABMask) |
										(((red) << dpFmt.RShift) & dpFmt.RBMask) |
										(((green) << dpFmt.GShift) & dpFmt.GBMask) |
										(((blue) << dpFmt.BShift) & dpFmt.BBMask));
						}
					}

					Dest2+=dpFmt.BitsPerPixel/8;
					Source2+=spFmt.BitsPerPixel/8;
				}

				Dest+=dlRect.Pitch;
				Source+=slRect.Pitch;
			}
		}
		else
		{
			Src->UnlockRect();

			return DT_ERROR;
		}

		Dest->UnlockRect();
	}
	else return DT_ERROR;

	Src->UnlockRect();

	return DT_OK;
}

Open in new window

0
 

Author Comment

by:nchannon
ID: 37064363
Ok my problem is in the code below what I have done is basically copyied the code that worked fine in DD but its not working to good in DX9.

Im tring to use GDI still yes I know its old but works to draw lines which create in this sample code a 2 x 2 matrix it also need to be transparant except for the 4 matrix square lines may app is fully 2D as well there is no 3D rendering.

My problem here is hr=g_ScreenMatrixSurface->GetDC(&hDC);
fails with is error measage

HRESULT: 0x8876086c (2289436780)
Name: D3DERR_INVALIDCALL
Description: Invalid call
Severity code: Failed
Facility Code: FACILITY_D3D (2166)
Error Code: 0x086c (2156)

I don't know why this is failing as GetDC worked fine in DD when settting up the CPen

thanks
HRESULT CMainDX::CreateMatrixView()
{
	HDC hDC;

	HRESULT hr;
	RECT rect,rc;
	rect.right = m_RectOverlaySrc.right;
	rect.bottom = m_RectOverlaySrc.bottom;
	rect.top = 0;
	rect.left = 0;
	
	if (g_pd3dDevice->CreateOffscreenPlainSurface(m_RectOverlayDest.right, m_RectOverlayDest.bottom, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &g_ScreenMatrixSurface, NULL) != D3D_OK)
	         {
		     g_ScreenMatrixSurface->Release();
		     return DT_ERROR;
	        }

	

	D3DLOCKED_RECT slRect;
	hr=g_ScreenMatrixSurface->LockRect(&slRect, &m_RectMainWindowDest, D3DLOCK_READONLY);
	hr=g_ScreenMatrixSurface->GetDC(&hDC);
	::SelectObject(hDC,  m_hGridLinesPen);
	m_SplitInfo.scSplitConf = *(views[1]);

    double gridX = (double)(rect.right-rect.left)/m_SplitInfo.scSplitConf.szBoundSize.cx;
	double gridY = (double)(rect.bottom-rect.top)/m_SplitInfo.scSplitConf.szBoundSize.cy;
	for(int j=0;j<(signed)m_SplitInfo.scSplitConf.uNumRects;j++){
			 rc = m_SplitInfo.scSplitConf.rcRect[j];
		  //## Top Line ##//
		::MoveToEx(hDC, rc.left*gridX-0,	rc.top*gridY-0, NULL);
		::LineTo(hDC,	rc.right*gridX-1,	rc.top*gridY-0);
		//## Right Line ##//
		::MoveToEx(hDC, rc.right*gridX-1,   rc.top*gridY-0, NULL);
		::LineTo(hDC,	rc.right*gridX-1,	rc.bottom*gridY-0);
		//## Left Line ##//
		::MoveToEx(hDC, rc.left*gridX-0,	rc.top*gridY-0, NULL);
		::LineTo(hDC,	rc.left*gridX-0,	rc.bottom*gridY-0);
		//## Bottom Line ##//
		::MoveToEx(hDC, rc.left*gridX-0,	rc.bottom*gridY-0, NULL);
		::LineTo(hDC,	rc.right*gridX-1,	rc.bottom*gridY-0);

		
	}

	g_ScreenMatrixSurface->ReleaseDC(hDC);
	g_ScreenMatrixSurface->UnlockRect();
	hr= D3DXSaveSurfaceToFile(_T("backbuf.bmp"), D3DXIFF_BMP, g_ScreenMatrixSurface, NULL, NULL);


	return S_OK;
}

Open in new window

0
 
LVL 12

Accepted Solution

by:
satsumo earned 2000 total points
ID: 37066208
Hello nchannon,

I do seem to be the only DX person answering on EE.

I think the problem is that you're locking the surface before calling GetDC.  Perhaps that was necessary in DirectDraw, but it will not work in DX9.  Locking the surface is for your program to access its memory, while it is locked neither DX or GDI cannot use it.

I do the same sort of thing in my code, mixing GDI and DX.  GDI may be old but its very reliable between versions of Windows, things like GDI+ or WPF are not.  There are sometimes problems with rendering order between GDI and DX.  Both have a rendering queue, you can run into problems where they flush the queue at the wrong time.  I think GDI flushes when you release the DC.
0
 

Author Comment

by:nchannon
ID: 37073220
Ok by removing LockRect GDI works
hr=g_ScreenMatrixSurface->GetDC(&hDC);

Thanks
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

578 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question