Sign in to follow this  
Vaine0

Need help with GetRenderTargetData()

Recommended Posts

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this