Sign in to follow this  

Saving a texture to memory

This topic is 3591 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hi guys using c++ and directX i want to be able to save an array of textures to memory and then be able to load them when ever i need them , the textures will be screenshots taken by a web camera on the PC/ windows. what is the best way to do this , so far i hhave come up with this: -
typedef struct TexStruct
{
	LPD3DXBUFFER ImageBuffer;
}TexStruct;

TexStruct TexArray[11];

void SaveScreenShotToMem(LPDIRECT3DTEXTURE9 Texture)
{
        /* test to fill up the an array of textures */
	for (int i = 0; i < 11; i++)
	{
              if(TexArray[i].ImageBuffer == NULL)
		D3DXSaveTextureToFileInMemory(TexArray[i].ImageBuffer, D3DXIFF_PNG, Texture, NULL);
	}
}


but this does not seem to work is there any other way? or should i say what is the correct way [Edited by - Prog101 on February 15, 2008 5:52:59 PM]

Share this post


Link to post
Share on other sites
Uh, textures are "in memory" already. An LPDIRECT3DTEXTURE9 is a pointer. The pointed-at thing is in memory, not on disk - that's what pointers are. You can't point to the disk.

Also, saying "does not seem to work" is spectacularly unhelpful. What happened when you tried it? Under what conditions did you try it (i.e. where are you getting the LPDIRECT3DTEXTURE9s that you pass to the function, and how are you trying to verify what it does)?

Share this post


Link to post
Share on other sites
I know that the textures are already in memory in that LPDIRECT3DTEXTURE9 is a pointer. What i want to do is when i save the game data , i also save the texture in raw data, not create a image file type i.e. png. the texture that is passed is valid as it renders to the screen now i just want to create an array that holds the raw data so i can then load the raw data when i need to as a texture and display it.

the errror i get is that the buffer that i save the texture to is invalid, what am i doing wrong, if anyone can help?

Share this post


Link to post
Share on other sites
And what do the debug runtimes tell you?

What happens if you create the buffer first, using D3DXCreateBuffer? I'm not sure if the buffer needs created by you, or if D3DXSaveTextureToFileInMemory creates it (Although by taking a pointer to a pointer to a buffer, it implies that the function creates the buffer for you)

If you just want to save the raw texture data, just LockRect() the texture (For each mip level if you want, or just the top mip level and then regenerate them when you load - And your textures should be in the managed pool anyway, so LockRect() will work fine) and read the data from there.

Share this post


Link to post
Share on other sites
Quote:

What i want to do is when i save the game data , i also save the texture in raw data, not create a image file

Why? D3DX can both write and read PNG files -- and all the files that you can write with the save function, there. It's likely going to be easier, and cheaper (in terms of space) to save it in an image format and read it back from that format, rather than save raw uncompressed pixels.

Share this post


Link to post
Share on other sites
Hi Evil steve thanks for your reply is it possible if you could gve me a quick example of what you mean and what aray data tye i would save the raw information in?

Share this post


Link to post
Share on other sites
Quote:
Original post by Prog101
Hi Evil steve thanks for your reply is it possible if you could gve me a quick example of what you mean and what aray data tye i would save the raw information in?
Untested, off the top of my head:

bool SaveScreenShotToMem(LPDIRECT3DTEXTURE9 pTexture)
{
// Get the surface description for the texture, to determine size
D3DSURFACE_DESC desc;
hResult = pTexture->GetLevelDesc(0, &desc);
if(FAILED(hResult))
return false; // Can't GetLevelDescfor some reason. See debug output (With debug runtimes) for reason

// Lock the first mip-level of the texture to get access to it's bits
D3DLOCKED_RECT rect;
HRESULT hResult = pTexture->LockRect(0, &rect, NULL, D3DLOCK_READONLY);
if(FAILED(hResult))
return false; // Can't LockRect for some reason. See debug output (With debug runtimes) for reason

// Allocate output buffer - Assumes 32-bit (4 bytes per pixel) textures. You
// Can determine the bpp from desc.Format if needed
BYTE* pData = new BYTE[desc.Width * desc.Height * 4];

// Read data from locked rect
for(UINT y=0; y<desc.Height; ++y)
{
// Get a pointer to this "row" of pixels
BYTE* pBits = (BYTE*)rect.pBits + y*rect.Pitch;
memcpy(pData, pBits, desc.Width*4); // Again, assume 32-bit
}

// Unlock the texture
pTexture->UnlockRect(0);

// Do whatever with pData - it now contains the texture data

// Cleanup and return success
delete[] pData;
return true;
}





However, as jpetrie said, PNG or some other compressed format would be better for space (Although slightly slower).

Share this post


Link to post
Share on other sites
that seems to work fine i had to play with it because it is in C, but how do i get the bpp fom the D3DFORMAT of the texture instead of hardcoding the 32 bit?


bool SaveTexToMem(IDirect3DTexture9 *pTexture, BYTE* pData)
{
// Get the surface description for the texture, to determine size
D3DSURFACE_DESC desc;
D3DLOCKED_RECT rect;
UINT i;
HRESULT hResult;

hResult = IDirect3DTexture9_GetLevelDesc(pTexture, 0, &desc);
if(FAILED(hResult))
{
DebugMessage("SaveTexToMem:: Can't GetLevelDesc");
return FALSE;
}

// Lock the first mip-level of the texture to get access to it's bits
hResult = IDirect3DTexture9_LockRect(pTexture,0,&rect, NULL, D3DLOCK_READONLY);
if(FAILED(hResult))
{
DebugMessage("SaveTexToMem:: Can't LockRect");
return FALSE;
}

// Allocate output buffer - Assumes 32-bit (4 bytes per pixel) textures.
pData = (BYTE *)malloc(desc.Width * desc.Height * 4 * sizeof(BYTE),MF_NONE);

// Read data from locked rect
for(i = 0; i < desc.Height; ++i)
{
// Get a pointer to this "row" of pixels
BYTE* pBits = (BYTE*)rect.pBits + i*rect.Pitch;
memcpy(pData, pBits, desc.Width*4); // Again, assume 32-bit
}

// Unlock the texture
IDirect3DTexture9_UnlockRect(pTexture,0);

return TRUE;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Prog101
that seems to work fine i had to play with it because it is in C, but how do i get the bpp fom the D3DFORMAT of the texture instead of hardcoding the 32 bit?

*** Source Snippet Removed ***
There may well be a better way to do this, but from my engine code:

PFormatInfo.h:

//============================================================================
// PFormatInfo.h - Get information about a D3DFORMAT
//============================================================================

#ifndef __PFORMATINFO_H__
#define __PFORMATINFO_H__

#include <d3d9.h>

struct PPixelFormat
{
unsigned nBpp;

unsigned nABits;
unsigned nAMask;
unsigned nAShift;

unsigned nRBits;
unsigned nRMask;
unsigned nRShift;

unsigned nGBits;
unsigned nGMask;
unsigned nGShift;

unsigned nBBits;
unsigned nBMask;
unsigned nBShift;
};

bool GetPixelFormat(D3DFORMAT d3dFmt, PPixelFormat& fmt);

#endif // __PFORMATINFO_H__




PFormatInfo.cpp:

//============================================================================
// PFormatInfo.cpp - Get information about a D3DFORMAT
//============================================================================

#include "PFormatInfo.h"

//============================================================================

bool GetPixelFormat(D3DFORMAT d3dFmt, PPixelFormat& fmt)
{
switch(d3dFmt)
{
case D3DFMT_R8G8B8:
fmt.nBpp = 24;
fmt.nABits = 0;
fmt.nAMask = 0;
fmt.nAShift = 0;
fmt.nRBits = 8;
fmt.nRMask = 0x00ff0000;
fmt.nRShift = 16;
fmt.nGBits = 8;
fmt.nGMask = 0x0000ff00;
fmt.nGShift = 8;
fmt.nBBits = 8;
fmt.nBMask = 0x000000ff;
fmt.nBShift = 0;
break;

case D3DFMT_A8R8G8B8:
fmt.nBpp = 32;
fmt.nABits = 8;
fmt.nAMask = 0xff000000;
fmt.nAShift = 24;
fmt.nRBits = 8;
fmt.nRMask = 0x00ff0000;
fmt.nRShift = 16;
fmt.nGBits = 8;
fmt.nGMask = 0x0000ff00;
fmt.nGShift = 8;
fmt.nBBits = 8;
fmt.nBMask = 0x000000ff;
fmt.nBShift = 0;
break;

case D3DFMT_X8R8G8B8:
fmt.nBpp = 32;
fmt.nABits = 0;
fmt.nAMask = 0;
fmt.nAShift = 0;
fmt.nRBits = 8;
fmt.nRMask = 0x00ff0000;
fmt.nRShift = 16;
fmt.nGBits = 8;
fmt.nGMask = 0x0000ff00;
fmt.nGShift = 8;
fmt.nBBits = 8;
fmt.nBMask = 0x000000ff;
fmt.nBShift = 0;
break;

case D3DFMT_R5G6B5:
fmt.nBpp = 16;
fmt.nABits = 0;
fmt.nAMask = 0;
fmt.nAShift = 0;
fmt.nRBits = 5;
fmt.nRMask = 0x0000f800;
fmt.nRShift = 11;
fmt.nGBits = 6;
fmt.nGMask = 0x000007e0;
fmt.nGShift = 5;
fmt.nBBits = 5;
fmt.nBMask = 0x0000001f;
fmt.nBShift = 0;
break;

case D3DFMT_X1R5G5B5:
fmt.nBpp = 16;
fmt.nABits = 0;
fmt.nAMask = 0;
fmt.nAShift = 0;
fmt.nRBits = 5;
fmt.nRMask = 0x00007c00;
fmt.nRShift = 10;
fmt.nGBits = 5;
fmt.nGMask = 0x000003e0;
fmt.nGShift = 5;
fmt.nBBits = 5;
fmt.nBMask = 0x0000001f;
fmt.nBShift = 0;
break;

case D3DFMT_A1R5G5B5:
fmt.nBpp = 16;
fmt.nABits = 1;
fmt.nAMask = 0x00008000;
fmt.nAShift = 15;
fmt.nRBits = 5;
fmt.nRMask = 0x00007c00;
fmt.nRShift = 10;
fmt.nGBits = 5;
fmt.nGMask = 0x000003e0;
fmt.nGShift = 5;
fmt.nBBits = 5;
fmt.nBMask = 0x0000001f;
fmt.nBShift = 0;
break;

case D3DFMT_A4R4G4B4:
fmt.nBpp = 16;
fmt.nABits = 4;
fmt.nAMask = 0x0000f000;
fmt.nAShift = 12;
fmt.nRBits = 4;
fmt.nRMask = 0x00000f00;
fmt.nRShift = 8;
fmt.nGBits = 4;
fmt.nGMask = 0x000000f0;
fmt.nGShift = 4;
fmt.nBBits = 4;
fmt.nBMask = 0x0000000f;
fmt.nBShift = 0;
break;

case D3DFMT_R3G3B2:
fmt.nBpp = 8;
fmt.nABits = 0;
fmt.nAMask = 0;
fmt.nAShift = 0;
fmt.nRBits = 3;
fmt.nRMask = 0x000000e0;
fmt.nRShift = 5;
fmt.nGBits = 3;
fmt.nGMask = 0x0000001c;
fmt.nGShift = 2;
fmt.nBBits = 2;
fmt.nBMask = 0x00000003;
fmt.nBShift = 0;
break;

case D3DFMT_A8:
fmt.nBpp = 8;
fmt.nABits = 8;
fmt.nAMask = 0x000000ff;
fmt.nAShift = 0;
fmt.nRBits = 0;
fmt.nRMask = 0;
fmt.nRShift = 0;
fmt.nGBits = 0;
fmt.nGMask = 0;
fmt.nGShift = 0;
fmt.nBBits = 0;
fmt.nBMask = 0;
fmt.nBShift = 0;
break;

case D3DFMT_A8R3G3B2:
fmt.nBpp = 16;
fmt.nABits = 8;
fmt.nAMask = 0x0000ff00;
fmt.nAShift = 0;
fmt.nRBits = 3;
fmt.nRMask = 0x000000e0;
fmt.nRShift = 5;
fmt.nGBits = 3;
fmt.nGMask = 0x0000001c;
fmt.nGShift = 2;
fmt.nBBits = 2;
fmt.nBMask = 0x00000003;
fmt.nBShift = 0;
break;

case D3DFMT_X4R4G4B4:
fmt.nBpp = 16;
fmt.nABits = 0;
fmt.nAMask = 0;
fmt.nAShift = 0;
fmt.nRBits = 4;
fmt.nRMask = 0x00000f00;
fmt.nRShift = 8;
fmt.nGBits = 4;
fmt.nGMask = 0x000000f0;
fmt.nGShift = 4;
fmt.nBBits = 4;
fmt.nBMask = 0x0000000f;
fmt.nBShift = 0;
break;

case D3DFMT_A2B10G10R10:
fmt.nBpp = 32;
fmt.nABits = 2;
fmt.nAMask = 0xc0000000;
fmt.nAShift = 30;
fmt.nRBits = 10;
fmt.nRMask = 0x000003ff;
fmt.nRShift = 0;
fmt.nGBits = 10;
fmt.nGMask = 0x000ffc00;
fmt.nGShift = 10;
fmt.nBBits = 10;
fmt.nBMask = 0x3ff00000;
fmt.nBShift = 20;
break;

case D3DFMT_A8B8G8R8:
fmt.nBpp = 32;
fmt.nABits = 8;
fmt.nAMask = 0xff000000;
fmt.nAShift = 24;
fmt.nRBits = 8;
fmt.nRMask = 0x000000ff;
fmt.nRShift = 0;
fmt.nGBits = 8;
fmt.nGMask = 0x0000ff00;
fmt.nGShift = 8;
fmt.nBBits = 8;
fmt.nBMask = 0x00ff0000;
fmt.nBShift = 16;
break;

case D3DFMT_X8B8G8R8:
fmt.nBpp = 32;
fmt.nABits = 0;
fmt.nAMask = 0;
fmt.nAShift = 0;
fmt.nRBits = 8;
fmt.nRMask = 0x000000ff;
fmt.nRShift = 0;
fmt.nGBits = 8;
fmt.nGMask = 0x0000ff00;
fmt.nGShift = 8;
fmt.nBBits = 8;
fmt.nBMask = 0x00ff0000;
fmt.nBShift = 16;
break;

case D3DFMT_G16R16:
fmt.nBpp = 32;
fmt.nABits = 0;
fmt.nAMask = 0;
fmt.nAShift = 0;
fmt.nRBits = 16;
fmt.nRMask = 0x0000ffff;
fmt.nRShift = 0;
fmt.nGBits = 16;
fmt.nGMask = 0xffff0000;
fmt.nGShift = 16;
fmt.nBBits = 0;
fmt.nBMask = 0;
fmt.nBShift = 0;
break;

case D3DFMT_A2R10G10B10:
fmt.nBpp = 32;
fmt.nABits = 2;
fmt.nAMask = 0xc0000000;
fmt.nAShift = 30;
fmt.nRBits = 10;
fmt.nRMask = 0x3ff00000;
fmt.nRShift = 20;
fmt.nGBits = 10;
fmt.nGMask = 0x000ffc00;
fmt.nGShift = 10;
fmt.nBBits = 10;
fmt.nBMask = 0x000003ff;
fmt.nBShift = 0;
break;

default:
memset(&fmt, 0, sizeof(fmt));
return false;
}

return true;
}

//============================================================================



Hard coded and messy, yes. But there's only a finite number of D3DFORMATs. DirectDraw had "Pixel format" structs to do this sort of stuff, but I don't know if something similar exists in D3D.

EDIT: Example usage too:

int GetBytesPerPixelFromFormat(D3DFORMAT d3dFmt)
{
PPixelFormat fmt;
if(!GetPixelFormat(d3dFmt, fmt))
return 0; // Unhandled format

return fmt.nBpp/8;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve

// Read data from locked rect
for(UINT y=0; y<desc.Height; ++y)
{
// Get a pointer to this "row" of pixels
BYTE* pBits = (BYTE*)rect.pBits + y*rect.Pitch;
memcpy(pData, pBits, desc.Width*4); // Again, assume 32-bit
}



It's not safe to use memcpy with pointers that alias/may overlap. Use memmove.

Share this post


Link to post
Share on other sites
Quote:
Original post by truthsayer
Quote:
Original post by Evil Steve

// Read data from locked rect
for(UINT y=0; y<desc.Height; ++y)
{
// Get a pointer to this "row" of pixels
BYTE* pBits = (BYTE*)rect.pBits + y*rect.Pitch;
memcpy(pData, pBits, desc.Width*4); // Again, assume 32-bit
}



It's not safe to use memcpy with pointers that alias/may overlap. Use memmove.
Why would pData and pBits overlap? pData is allocated from the application and pBits is allocated by D3D from the texture lock. They're both likely to be in system memory, but unless the heap is broke, there's no chance they'll overlap.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
Quote:
Original post by truthsayer
Quote:
Original post by Evil Steve

// Read data from locked rect
for(UINT y=0; y<desc.Height; ++y)
{
// Get a pointer to this "row" of pixels
BYTE* pBits = (BYTE*)rect.pBits + y*rect.Pitch;
memcpy(pData, pBits, desc.Width*4); // Again, assume 32-bit
}



It's not safe to use memcpy with pointers that alias/may overlap. Use memmove.
Why would pData and pBits overlap? pData is allocated from the application and pBits is allocated by D3D from the texture lock. They're both likely to be in system memory, but unless the heap is broke, there's no chance they'll overlap.


I didn't say they did, was just giving some general but not very well known advice.

Share this post


Link to post
Share on other sites

This topic is 3591 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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