Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a DirectX10 texture (ID3D10Texture2D) that I load from disk with the following code:

CComPtr<ID3D10Device>   spD3D; // Initialized correctly elsewhere

hr = D3DX10CreateTextureFromFile( 
        spD3D.p, 
        wsFilename.c_str(), 
        NULL, NULL, 
        &spTextureResource, 
        NULL 
    );

if( FAILED(hr) || ! spTextureResource.p )
    return false;

spTextureResource->QueryInterface <ID3D10Texture2D> ( &m_spTexture );
if( ! m_spTexture.p )
    return false;

The texture loads fine, I can blit this onscreen.

Later, I want to use that texture as an atlas. To do so, the first thing I want to do is to call ID3D10Texture2D::Map() in order to get at the texels and parse them (to determine where my tiles are).

The following call fails with E_INVALIDARG:

D3D10_MAPPED_TEXTURE2D mapped;
HRESULT hr = spTexture->Map( 0, D3D10_MAP_READ, 0, &mapped );

So I'm thinking that this fails because the texture can't be read from by the CPU. So in order to get a texture that is CPU readable, I tried setting the D3DX10_IMAGE_LOAD_INFO structure to include D3D10_CPU_ACCESS_READ. This fails on D3DX10CreateShaderResourceViewFromFile() with E_INVALIDARG.

So I guess I've given up trying to load in a texture and be able to read its data from on the CPU.

So I thought, what about making a texture with the following D3D10_TEXTURE2D_DESC flags:

    D3D10_TEXTURE2D_DESC    desc;
    ZeroMemory(&desc, sizeof(D3D10_TEXTURE2D_DESC));
    desc.CPUAccessFlags     = D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE;
    desc.Usage              = D3D10_USAGE_DYNAMIC;
    desc.BindFlags          = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;

Step 2 of my plan is to use CopyResource or CopyResourceSubregion to copy data from the disk file into my dynamic texture, so I can use the dynamic texture as a source to read texel data from.

Will this approach work? Am I barking up the wrong tree and missing an obvious simpler route?

I'm worried that CopyResource won't work either, since the original texture was loaded from disk without the D3D10_CPU_ACCESS_READ flag.

God, I've got to write this for OpenGL too, I hope it's easier with GL!

My plan is to parse this texture and determine where my tiles are, so I can use the texture as an atlas for generating sprites.

share|improve this question
1  
I made a splatmap terrain shader with atlas maps, I abandoned it because of filtering problems (bleeding, especially with mip maps). Good luck though, I'd love to see someone break the 2-4-8-16 texture limit for 'normal' shaders! –  Valmond Dec 6 '11 at 19:39
add comment

1 Answer 1

up vote 1 down vote accepted

In order to read texel information from a texture, we need a texture with Usage = D3D10_USAGE_STAGING.

This allows the D3D10_CPU_ACCESS_READ flag to be set.

I loaded this texture a second time (as a temporary, or "staging" resource, so that I could read the texel information).

So to get read access to a texture, we must fill in this IMAGE_LOAD_INFO structure, which is passed to the D3DX10CreateTextureFromFile() call.

    CComPtr<ID3D10Device>       spD3D       = RenderMgr::I()->D3DDev();
    CComPtr<ID3D10Texture2D>    spTexture;      
    CComPtr<ID3D10Resource>     spResource;


    D3DX10_IMAGE_LOAD_INFO  loadInfo;
    loadInfo.Width          = D3DX10_FROM_FILE;
    loadInfo.Height         = D3DX10_FROM_FILE;
    loadInfo.Depth          = D3DX10_FROM_FILE;
    loadInfo.FirstMipLevel  = 0;
    loadInfo.MipLevels      = D3DX10_FROM_FILE;
    loadInfo.Usage          = D3D10_USAGE_STAGING;
    loadInfo.BindFlags      = 0;
    loadInfo.CpuAccessFlags = D3D10_CPU_ACCESS_WRITE | D3D10_CPU_ACCESS_READ;
    loadInfo.MiscFlags      = 0;
    loadInfo.Format         = m_pTexAtlas->Desc().Format;
    loadInfo.Filter         = D3DX10_FILTER_NONE;
    loadInfo.MipFilter      = D3DX10_FILTER_NONE;
    loadInfo.pSrcInfo       = 0;                

    hr = D3DX10CreateTextureFromFile(
        spD3D,
        wsTexture.c_str(),
        &loadInfo,
        NULL,
        &spResource,
        NULL
    );

    if( ! SUCCEEDED(hr) )
        return false;

    spResource->QueryInterface <ID3D10Texture2D> (&spTexture);
    if( ! spTexture )
    {
        spResource.Release();
        return false;
    }

    spTexture->GetDesc( &desc );

    ZeroMemory(&mapped, sizeof(D3D10_MAPPED_TEXTURE2D));

    hr = spTexture->Map( D3D10CalcSubresource(0, 0, 1), D3D10_MAP_READ, 0, &mapped );
    if( ! SUCCEEDED(hr) )
        return false;

Okay, so now the Map() call succeeds. I hope it helps someone out there !!! I wasted an entire day on this. I wish there was better documentation for dealing with textures. I was working from Luna, which like many sources, only deals with textures as they can be mapped to models :S

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.