Need help with GetRenderTargetData()

Started by
0 comments, last by ET3D 15 years, 5 months ago
Hey, I'm trying to render my scene to a texture. Here's the function I wrote to try to figure this out:

int	DXRenderer::DrawToTexture(Window* window, ITexture& texture)
{
	m_done = false;

	HRESULT hRes = 0;

	Camera* camera = window->GetCamera();

	LPDIRECT3DTEXTURE9 dxTexture;
	LPDIRECT3DSURFACE9 dxSurface;
	m_d3dDevice->CreateTexture(texture.GetWidth(), texture.GetHeight(),  0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &dxTexture, NULL);
	dxTexture->GetSurfaceLevel(0, &dxSurface);
	m_d3dDevice->SetRenderTarget(0, dxSurface);


	if(window == GetActiveWindow())
		m_d3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,0x99999999,1.0,0);
	else
		m_d3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,0x88888888,1.0,0);
	
	Matrix4 m = ~camera->GetCoordinateSystem();
	m_d3dDevice->SetTransform(D3DTS_VIEW, (D3DXMATRIX*)&m);
	D3DXMATRIX matProjection; 
	D3DXMatrixPerspectiveFovLH(	&matProjection, 45.0f * (PI/180.0f), 
								(float)window->GetWidth() / (float)window->GetHeight(), 
								camera->GetNearPlaneDistance(), camera->GetFarPlaneDistance());
	m_d3dDevice->SetTransform(D3DTS_PROJECTION, &matProjection);

	D3DLIGHT9 d3dLight; 
	ZeroMemory(&d3dLight, sizeof(d3dLight));
	d3dLight.Type = D3DLIGHT_POINT;
	d3dLight.Diffuse.r  = 1.0f;
	d3dLight.Diffuse.g  = 1.0f;
	d3dLight.Diffuse.b  = 1.0f;
	d3dLight.Ambient.r  = 1.0f;
	d3dLight.Ambient.g  = 1.0f;
	d3dLight.Ambient.b  = 1.0f;
	d3dLight.Specular.r = 1.0f;
	d3dLight.Specular.g = 1.0f;
	d3dLight.Specular.b = 1.0f;
	d3dLight.Position.x = camera->GetPosition().x;
	d3dLight.Position.y = camera->GetPosition().y;
	d3dLight.Position.z = camera->GetPosition().z;
	d3dLight.Attenuation0 = 0.5f; 
	d3dLight.Range        = 1000.0f;
	hRes = m_d3dDevice->SetLight(0, &d3dLight);
	DX_ERROR(hRes);

	if(m_threadSafe)
	{
		m_d3dDevice->BeginScene();
		{	
			// Draw all objects.
			RenderStack* renderStack = GetRenderStack();
			IRenderableObj* obj = renderStack->Peek(true);
			while(obj)
			{

				if(m_texMan.Contains(obj->GetTextureName()))
				{
					hRes = m_d3dDevice->SetTexture(0, m_texMan.Get(obj->GetTextureName()));
					DX_ERROR(hRes);
				}
				else
					m_d3dDevice->SetTexture(0, NULL);
			
				Matrix4 transform = obj->GetTransform();
				m_d3dDevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)&transform );

				if(strcmp(obj->GetType(), "Triangle") == 0)
					DrawTriangle((TriangleRenderObj*)obj);
				else if(strcmp(obj->GetType(), "MeshSet") == 0)
					DrawMesh((MeshRenderObj*)obj);
				else if(strcmp(obj->GetType(), "Line") == 0)
					DrawLine((LineRenderObj*)obj);

				obj = renderStack->Peek();
			}
		}
		m_d3dDevice->EndScene();
	}

	LPDIRECT3DTEXTURE9 dxDestTexture;
	LPDIRECT3DSURFACE9 dxDestSurface;
	m_d3dDevice->CreateTexture(texture.GetWidth(), texture.GetHeight(),  0, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &dxDestTexture, NULL);
	dxDestTexture->GetSurfaceLevel(0, &dxDestSurface);
	m_d3dDevice->GetRenderTargetData(dxSurface, dxDestSurface);
	D3DLOCKED_RECT rect;
	dxDestTexture->LockRect(0, &rect, NULL, 0);
	for(unsigned i = 0; i < texture.GetHeight(); i++)
		memcpy(texture.GetData() + (i*texture.GetWidth()), (char*)rect.pBits + (i * rect.Pitch), texture.GetWidth() * texture.GetByteType());
	dxDestTexture->UnlockRect(0);
	
	D3DXSaveSurfaceToFile(L"D:\\wtf.bmp",D3DXIFF_BMP,dxDestSurface,NULL,NULL);

	dxTexture->Release();
	dxSurface->Release();
	dxDestTexture->Release();
	dxDestSurface->Release();
	
	m_done = true;

    return 1;
}


The problem is that calling

D3DXSaveSurfaceToFile(L"D:\\wtf.bmp",D3DXIFF_BMP,dxDestSurface,NULL,NULL); 



produces correct results.

for(unsigned i = 0; i < texture.GetHeight(); i++)
		memcpy(texture.GetData() + (i*texture.GetWidth()), (char*)rect.pBits + (i * rect.Pitch), texture.GetWidth() * texture.GetByteType());



Does not seem to copy the same image into memory though. Here's what was output to D:\\wtf.bmp: and I'm rendering the texture data on the quad, in the image. And the only last bit of information is how I'm creating my texture to be displayed. I know this is bad, but I'm creating it once per frame. So, DrawToTexture() is called, the source I'm posting below is called, and then my main render loop is called, with the updated texture applied to the quad.

case ITexture::Ax8Rx8Gx8Bx8:
		szType = sizeof(char);
		hRes = m_d3dDevice->CreateTexture(texture->GetWidth(), texture->GetHeight(), 0, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &d3dTexture, NULL);
		break;
	}

If anyone knows why this image isn't coming out correctly on the quad, please let me know... Thanks, David
Advertisement
Looks to me like you're missing "* texture.GetByteType()" in the first parameter of memcpy.

My tip for debugging: when you have problems, revert to simpler code. In this case, use loops instead of memcpy, so that you can go over the loop and check that all your indices are correct.

This topic is closed to new replies.

Advertisement