Not logged in, Join Here! or Log In Below:  
 
News Articles Search    
 

 Home / General Programming / Flipping a texture in DirectX Account Manager
 
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.
 
IndigoStallion

April 20, 2005, 10:05 PM

Does anyone know how to flip a texture vertically in directX?

I'm loading it like this:

  1. LPDIRECT3DTEXTURE8* m_pMeshTextures;
  2.  
  3.         if( FAILED( D3DXCreateTextureFromFileInMemory( pDevice, buffer, info.uncompressed_size, m_pMeshTextures ) ) )
  4.         {
  5.                 free( buffer );
  6.                 throw "Could not create texture from file in memory";
  7.         }
  8.  
  9.  

 
Endurion

April 21, 2005, 01:21 AM

Can't do that with D3DX functions. You may need to lock the textures surface and do the mirroring yourself, simply mirror the image file or apply the texture coordinates mirrored.

 
theAntiELVIS

April 21, 2005, 01:27 AM

Yeah - you can lock the surface and manipulate it via the ->Bits property. If you only need to flip it as it is applied to geometry you can just play with the u/v coords. If you want to manipulate it directly you can create a new blank texture and read/write the bits straight across, then save the new one.

Just remember to take the pitch of a texture row into account.

 
IndigoStallion

April 21, 2005, 08:37 AM

Thanks, I'll try that. Psuedo code would help...

What do you mean by the "pitch of a texture row"?

 
IndigoStallion

April 21, 2005, 07:23 PM

OK. Here is the code I'm trying to use.... but it always gives me an access violation. Any idea why?

  1.  
  2.         D3DLOCKED_RECT MasterLockedSurface;
  3.         D3DLOCKED_RECT SlaveLockedSurface;
  4.         unsigned char *MPixels;
  5.         unsigned char *SPixels;
  6.  
  7. //      for(int TexLevel = 0; TexLevel <= MasterInfo.Depth; TexLevel++)
  8. //      {
  9.                 TempTexture->LockRect(0, &MasterLockedSurface, NULL, 0);
  10.                 SlaveTexture->LockRect(0, &SlaveLockedSurface, NULL, D3DLOCK_DISCARD );
  11.                 MPixels = (unsigned char*)MasterLockedSurface.pBits;
  12.                 SPixels = (unsigned char*)SlaveLockedSurface.pBits;
  13.                 for(int y = 1; y <= MasterInfo.Height - 1; y++)
  14.                 {
  15.                         for(int x = 1; x <= MasterLockedSurface.Pitch - 1; x++)
  16.                         {
  17.                                 *(DWORD*)SPixels[y * MasterLockedSurface.Pitch + (x << 2)] = *(DWORD*)MPixels[y * MasterLockedSurface.Pitch + (x << 2)];
  18.                         }
  19.                 }
  20. //      }
  21.         SlaveTexture->UnlockRect(0);
  22.         TempTexture->UnlockRect(0);
  23.  

 
juhnu

April 21, 2005, 09:16 PM

1. you should use the correct, slave surface's pitch when calculating the offset to access the pixels in the slave surface.

2. for(int x = 1; x

  1. for(int x = 0; x < MasterInfo.Width; ++x)


3. for(int y = 1; y
  1. for(int y = 0; y < MasterInfo.Height; ++y)


4. you should check the returned buffers for possible NULL values and/or Lock() error values.

5. you should verify the dimensions and format of the textures are same, and having 32-bit texels.

6. ....



juhani

 
IndigoStallion

April 21, 2005, 10:49 PM

Thanks for the suggestions.

I'm still getting an acces violation on this line though:

  1. *(DWORD*)SPixels[y * MasterLockedSurface.Pitch + (x << 2)] = *(DWORD*)MPixels[y * MasterLockedSurface.Width + (x << 2)];


Here is the more refined code:

  1.  
  2.         D3DXIMAGE_INFO MasterInfo;
  3.         LPDIRECT3DTEXTURE8 TempTexture = NULL;
  4.  
  5.         // use D3DX utility library to load our texture now.
  6.         if( FAILED( D3DXCreateTextureFromFileInMemoryEx(pDevice, //Our D3D Device
  7.                                   buffer,                       //Filename of our texture
  8.                                                                   info.uncompressed_size,
  9.                                   D3DX_DEFAULT,         //Width:D3DX_DEFAULT = Take from file
  10.                                   D3DX_DEFAULT,         //Height:D3DX_DEFAULT = Take from file
  11.                                   1,                            //MipLevels
  12.                                   0,                            //Usage, Is this to be used as a Render Target? 0 == No
  13.                                   D3DFMT_A8R8G8B8,      //32-bit with Alpha, everything should support this
  14.                                   D3DPOOL_MANAGED,      //Pool, let D3D Manage our memory
  15.                                   D3DX_DEFAULT,         //Filter:Default filtering
  16.                                   D3DX_DEFAULT,         //MipFilter, used for filtering mipmaps
  17.                                   NULL,                         //ColourKey
  18.                                   &MasterInfo,          //SourceInfo, returns extra info if we want it (we don't)
  19.                                   NULL,                         //Palette:We're not using one
  20.                                   &TempTexture) ))      // Our texture goes here.
  21.         {
  22.                 free( buffer );
  23.                 throw "Could not create texture from file in memory EX";
  24.         }
  25.         if(TempTexture == NULL) throw "Error Loading Texture, NULL Returned";
  26.  
  27.         LPDIRECT3DTEXTURE8 SlaveTexture = NULL;
  28.         if(FAILED(pDevice->CreateTexture( MasterInfo.Width, MasterInfo.Height, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &SlaveTexture )))
  29.         {
  30.                 throw "Error Creating Blank Texture";
  31.         }
  32.         if(SlaveTexture == NULL) throw "Error Creating Blank Texture, NULL Returned";
  33.  
  34.         D3DLOCKED_RECT MasterLockedSurface;
  35.         D3DLOCKED_RECT SlaveLockedSurface;
  36.         unsigned char *MPixels;
  37.         unsigned char *SPixels;
  38.  
  39.         if(FAILED(TempTexture->LockRect(0, &MasterLockedSurface, NULL, 0))) throw "Error Locking Master Surface";
  40.         if(FAILED(SlaveTexture->LockRect(0, &SlaveLockedSurface, NULL, D3DLOCK_DISCARD ))) throw "Error Locking Master Surface";
  41.                 MPixels = (unsigned char*)MasterLockedSurface.pBits;
  42.                 SPixels = (unsigned char*)SlaveLockedSurface.pBits;
  43.                 for(int y = 0; y <= MasterInfo.Height; y++)
  44.                 {
  45.                         for(int x = 0; x <= MasterInfo.Width; x++)
  46.                         {
  47.                                 *(DWORD*)SPixels[y * MasterLockedSurface.Width + (x << 2)] = *(DWORD*)MPixels[y * MasterLockedSurface.Width + (x << 2)];
  48.                         }
  49.                 }
  50.         SlaveTexture->UnlockRect(0);
  51.         TempTexture->UnlockRect(0);
  52.  
  53.         free( buffer );
  54.  
  55.         return SlaveTexture;
  56.  

 
fman256

April 21, 2005, 11:24 PM

it should be:
*(DWORD*)(SPixels+...)=*(DWORD*)(NPixels+...)
not
*(DWORD*)SPixels[...]=*(DWORD*)MPixels[...]

your code is converting an unsigned char to a DWORD*, instead of unsigned char* to DWORD*.




 
fman256

April 21, 2005, 11:38 PM

Also the fors should be:

for(int y = 0; y < MasterInfo.Height; y++)

and

for(int x = 0; x < MasterInfo.Width; x++)

 
Corre

April 22, 2005, 12:37 AM

please don't be offended by this, but you might want to consider working through some C++ textbook or something... It is really useful to have a good grip on the fundamentals of the language, saves you a lot of time in situations like this.

 
Moe

April 22, 2005, 11:11 AM

If you want to write/change the colour values of a texture, then you must declare the usage of the texture correctly.

This wonít do the trick because you do not specify the usage flag.

  1.  
  2. D3DXCreateTextureFromFileInMemoryEx( pDevice,  buffer,
  3.            D3DX_DEFAULT, D3DX_DEFAULT, 1,
  4.            0,   //Usage, Is this to be used as a Render Target? 0 == No
  5.            D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
  6.            D3DX_DEFAULT,        D3DX_DEFAULT,
  7.            NULL, &MasterInfo, NULL, &TempTexture);
  8.  

I have left your comment only at the mentioned point. I know referring to the dx samples this might look correct, but you should always use the actual flag you need. Refer to the docu to be sure witch one. I think itís D3DUSAGE_DYNAMIC if you want to access and change the colour values of the texture.

Maybe there are more mistakes in your code. I have not checked it properly. But this should solve the access violation.

Hope it helped.

 
Steven Hansen

April 22, 2005, 11:54 AM

Argh. The easiest way to flip a texture (and the most efficient besides) is *not* locking it down. Why would you ever lock a texture down to do something that D3D provides fast functionality for?

Steps:
1. Create another texture of desired size with D3DUSAGE_RENDERTARGET flag.
2. Set the top surface of that texture as the render target.
3. Set desired filtering (point or linear) if stretching.
4. Put the source texture into the pipeline as texture 0.
5. Either use a vertex buffer or system memory vertices, and then call DrawPrimitive/DrawPrimitiveUP. Choose texture coordinates that invert the y values (or v values for those that use (u, v)).
6. Restore old render target.

And there it is. Inverted texture. You will probably want to perform the same process for the other mip-levels if those matter to you.

That said, it makes me wonder why you need to invert a texture at all. With a single source texture, you can draw any orientation by manipulation of the texture coordinates of your target geometry. If you feel you need a texture to be stored in a particular orientation (upside down, rightside up, mirrored vertically, etc) you should carefully examine whether texture coordinate manipulation might not avoid that hassle.

 
IndigoStallion

April 22, 2005, 05:56 PM

OK. I got the function working, and I thought I would post the final code in case someone else needs it. I needed to flip the texture because the company that originally made the models used the flipping as a form of copy protection, and this is still easier than changing 300+ models.

Thanks for all of your help.

  1.  
  2.  
  3. LPDIRECT3DTEXTURE8 AStarZip::CreateFlippedTextureFromFileInZip( LPDIRECT3DDEVICE8 pDevice, LPCSTR szZip, LPCSTR szFile)
  4. {
  5.         // open ZIP
  6.         unzFile zip = unzOpen( szZip );
  7.  
  8.         if( !zip )
  9.                 throw "Could Find PAK File";
  10.        
  11.         // locate the file and open it
  12.         unzLocateFile( zip, szFile, 1 );
  13.        
  14.         if( unzOpenCurrentFile( zip ) != UNZ_OK )
  15.                 throw "Error Opening PAK File";
  16.        
  17.         // find current file info (we are looking for uncompressed file size)
  18.         unz_file_info info;
  19.         unzGetCurrentFileInfo( zip, &info, NULL, 0, NULL, 0, NULL, 0 );
  20.        
  21.         // create a buffer big enough to hold uncompressed file in memory
  22.         void *buffer = malloc( info.uncompressed_size );
  23.  
  24.         if( !buffer )
  25.         {
  26.                 unzCloseCurrentFile( zip );
  27.                 unzClose( zip );
  28.  
  29.                 throw "Out Of Memory";
  30.         }
  31.        
  32.         // load into memory
  33.         unzReadCurrentFile( zip, buffer, info.uncompressed_size );
  34.        
  35.         unzCloseCurrentFile( zip );
  36.         unzClose( zip );
  37.  
  38.         D3DXIMAGE_INFO MasterInfo;
  39.         LPDIRECT3DTEXTURE8 MasterTexture = NULL;
  40.  
  41.         // use D3DX utility library to load our texture now.
  42.         if( FAILED( D3DXCreateTextureFromFileInMemoryEx(pDevice, //Our D3D Device
  43.                                   buffer,                       //Filename of our texture
  44.                                                                   info.uncompressed_size,
  45.                                   D3DX_DEFAULT,         //Width:D3DX_DEFAULT = Take from file
  46.                                   D3DX_DEFAULT,         //Height:D3DX_DEFAULT = Take from file
  47.                                   1,                            //MipLevels
  48.                                   0,                            //Usage, Is this to be used as a Render Target? 0 == No
  49.                                   D3DFMT_A8R8G8B8,      //32-bit with Alpha, everything should support this
  50.                                   D3DPOOL_MANAGED,      //Pool, let D3D Manage our memory
  51.                                   D3DX_DEFAULT,         //Filter:Default filtering
  52.                                   D3DX_DEFAULT,         //MipFilter, used for filtering mipmaps
  53.                                   NULL,                         //ColourKey
  54.                                   &MasterInfo,          //SourceInfo, returns extra info on the texture.
  55.                                   NULL,                         //Palette: We're not using one
  56.                                   &MasterTexture) ))    // Our texture goes here.
  57.         {
  58.                 free( buffer );
  59.                 throw "Could not create texture from file in memory EX";
  60.         }
  61.         if(MasterTexture == NULL) throw "Error Loading Texture, NULL Returned";
  62.  
  63.         LPDIRECT3DTEXTURE8 SlaveTexture = NULL;
  64.         if(FAILED(pDevice->CreateTexture( MasterInfo.Width, MasterInfo.Height, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &SlaveTexture )))
  65.         {
  66.                 throw "Error Creating Blank Texture";
  67.         }
  68.         if(SlaveTexture == NULL) throw "Error Creating Blank Texture, NULL Returned";
  69.  
  70.         D3DLOCKED_RECT MasterLockedSurface;
  71.         D3DLOCKED_RECT SlaveLockedSurface;
  72.         unsigned char *MPixels, *SPixels;
  73.         long ArrayOffset, InvertedArrayOffset;
  74.  
  75.         if(FAILED(MasterTexture->LockRect(0, &MasterLockedSurface, NULL, 0))) throw "Error Locking Master Surface";
  76.         if(FAILED(SlaveTexture->LockRect(0, &SlaveLockedSurface, NULL, D3DLOCK_DISCARD ))) throw "Error Locking Slave Surface";
  77.                 MPixels = (unsigned char*)MasterLockedSurface.pBits;
  78.                 SPixels = (unsigned char*)SlaveLockedSurface.pBits;
  79.                 for(int y = 0; y < MasterInfo.Height; y++)
  80.                 {
  81.                         for(int x = 0; x < MasterLockedSurface.Pitch; x++)
  82.                         {              
  83.                                 ArrayOffset = ((MasterInfo.Height - 1) - y) * MasterLockedSurface.Pitch + (x << 2);
  84.                                 InvertedArrayOffset = y * MasterLockedSurface.Pitch + (x << 2);
  85.                                 *(DWORD*)(SPixels + InvertedArrayOffset)=*(DWORD*)(MPixels + ArrayOffset);
  86.                         }
  87.                 }
  88.         SlaveTexture->UnlockRect(0);
  89.         MasterTexture->UnlockRect(0);
  90.  
  91.         free( buffer );
  92.  
  93.         return SlaveTexture;
  94. }
  95.  
  96.  

 
Steven Hansen

April 22, 2005, 06:16 PM

Ugh.

Firstly, if you are performing this logic to bypass copy protection - *Shame on You!!!* After you start releasing your own software, I'm sure you will want people to actually buy your stuff.

Secondly, you are still flipping in system memory - video memory flipping would be much faster.

Third - you're using DirectX 8? What is your motivation there?

 
IndigoStallion

April 22, 2005, 09:41 PM

As for the copy protection, I have permission to use the models. It's written permission too... So i'm safe there. I want to learn at least the basics of DirectX 8 first, mainly because all of the books I have use it. Although video memory might be faster, it is only called once at at start time, and it only has to process about 100 textures, so I'm not overly concerned about the speed. Besides, the 'loading' scrollbar needs to display something ;)

If you have a reference as to where I can find an example/information on flipping in video memory, I'd apreciate it if you would post a link.

Again, thanks for everybody's help.

 
juhnu

April 24, 2005, 12:21 AM

With the dx9 you could use IDirect3DDevice9::StretchRect(). Not sure if that is available on dx8. Might very well be it's not.


juhani

 
juhnu

April 24, 2005, 12:33 AM

the flags are just hints for the drivers, they do not limit the usage of the texture. It is possible to lock all textures, otherwise all the textures would contain random noise, wouldn't they? Also, it's not necessarily true that the dynamic usage flag would automatically be the best choice even for textures that are 'dynamic' by their actual usage. One should also check the caps that the dynamic textures are actually supported by the device.



juhani

 
theAntiELVIS

April 24, 2005, 03:25 PM

Also realize the above technique may result in a new texture that is visually different from the original due to filtering. If that's okay then this is the way to do it. If not then you want to lock the surface and do a 1:1 read/write to a new texture.

 
This thread contains 18 messages.
 
 
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.