A better way to load many textures

Started by
3 comments, last by yewbie 12 years, 9 months ago
For awhile now I have been just parsing a whole directory of image files each being its own 64x64 texture..
But now I would like to put all of my texture into a single image, load it as a surface, parse through that and have individual textures loaded out of that surface...

Now I have a little test application I have been trying to do this on and I can't seem to figure it out.

I have made a offscreenplain surface, I load my image using LoadSurfaceFromFileEx, the part I cannot find any information on (or I cannot get to work) is loading a RECT from said surface into a texture.

I have been trying to use GetSurfaceLevel on my texture to return the textures surface, then using StretchRect() to copy data from one surface to the texture surface but it always turns up with no data...

I can post some sample code of what I was doing if you want (I would have to rewrite it since it was a scratch pad I have tried many different ways)

Am I going about this the wrong way?
Advertisement
I know a programmer who had this problem once. He told me that after pondering it for a while, he realized that he could get around his problem by calling the textures dynamically rather than statically. This way, when the function StretchRect() links the data to the parser, there will be no overflow errors, and the program should execute correctly. If you are still having a problem after trying this, please post your code.

D3DSURFACE_DESC surface;
LPDIRECT3DSURFACE9 TexSurface;
LPDIRECT3DTEXTURE9 Texture;
LPDIRECT3DSURFACE9 Surface;

string filename = "texture.png";
D3DXIMAGE_INFO info;
HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);
if(result != D3D_OK) return;


//Create surface
HRESULT hr22 = d3ddev -> CreateOffscreenPlainSurface(
info.Width, //Width of the surface
info.Height, //height of the surface
D3DFMT_X8R8G8B8, //Surface format
D3DPOOL_DEFAULT, //Memory pool to use
&Surface, //Pointer to the surface
NULL); //Reserved (always NULL)
if(result != D3D_OK) return;


//Load surface from file into newly created surface
HRESULT hr0 = D3DXLoadSurfaceFromFile(
Surface, //Destination surface
NULL, //Destination palette
NULL, //Destination rectangle
filename.c_str(), //Source filename
NULL, //Source rectangle
D3DX_DEFAULT, //Controls how image is filtered
D3DCOLOR_XRGB(0, 0, 0), //For transparency (0 for none)
NULL); //Source image info (usually NULL)



HRESULT hr1 = D3DXCreateTexture(d3ddev, 64,64,1, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &Texture);
HRESULT hr2 = Texture->GetSurfaceLevel(0, &TexSurface);
//TexSurface should contain our blank surface

HRESULT hr3 = d3ddev->StretchRect(Surface, NULL, TexSurface, NULL, D3DTEXF_NONE); //copy from one surface to our texture surface



Every HRESULT turns up fine until I get to hr3 my stretch rect, it returns HRESULT "-2005530516"
which is D3DERR_INVALIDCALL
Interesting update here, it looks like the source surface when doing UpdateSurface HAS to be D3DPOOL_SYSTEMMEM
Its the only way this works!

Found in the remarks section of UpdateSurface on the MSDN
http://msdn.microsof...v=vs.85%29.aspx

edit: I guess what I need to do is load the surface into system memory, parse it out into my various textures then release that surface and it should be fine.
I am interested in some feedback from the rest of the community I have written this class to parse / store textures in directx, I would like to know if anyone had any input on it.
And please don't rip on me for calling it "texturemanager" lol =p
Also I will be added accessor functions, and for my application I will never need to release them (Until the program is closed)

Also I had another question, since its a class doesn't directx play nice with classes?
And release its own resources when the default destructor is called?
(even though its a bad practice) ?

Also if anyone notices anything really bad about my coding practices I would also appreciate that feedback, I tested this on a 5120x5120 image, worked great.

Edit: Also posting in case some poor soul was also looking to do this.

TextureLoader.h
#ifndef TEXTURECLASS

#define TEXTURECLASS

/*------------------------------------------------------------------------------------------------- */
/* this class Holds all of texture information */
/* Declared as a new class for each type, tile, npc, etc */
/*-------------------------------------------------------------------------------------------------*/
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <Windows.h>

#include <d3d9.h>
#include <d3dx9.h>

using namespace std;

class TEXTURE
{
public:
LPDIRECT3DTEXTURE9 Texture;
int Width;
int Height;
};

class TEXTUREMANAGER
{
public:
void LoadTextureSheet(string FileName, IDirect3DDevice9* D3d, int TileWidth, int TileHeight); //load a texture sheet
vector <TEXTURE> TextureList; //This is our texture list
int NumberOfTextures;
private:
LPDIRECT3DSURFACE9 TempSurface; //this is our scratch surface when we are loading a textureset
LPDIRECT3DSURFACE9 TexSurface; //this is our scratch surface when we are loading a textureset
};
#endif


TextureLoader.cpp
#include "TextureLoader.h"


void TEXTUREMANAGER::LoadTextureSheet(string FileName, IDirect3DDevice9* D3d, int TileWidth, int TileHeight)
{
NumberOfTextures = 0;
D3DXIMAGE_INFO info;
HRESULT result = D3DXGetImageInfoFromFile(FileName.c_str(), &info);
if(result != D3D_OK) return;

//Create TextureSheet surface
result = D3d->CreateOffscreenPlainSurface(
info.Width, //Width of the surface
info.Height, //height of the surface
D3DFMT_X8R8G8B8, //Surface format
D3DPOOL_SYSTEMMEM, //Memory pool to use
&TempSurface, //Pointer to the surface
NULL); //Reserved (always NULL)
if(result != D3D_OK) return;

result = D3d->CreateOffscreenPlainSurface(info.Width, info.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &TexSurface, NULL);
if(result != D3D_OK) return;

//Load surface from file into newly created surface
result = D3DXLoadSurfaceFromFile(
TempSurface, //Destination surface
NULL, //Destination palette
NULL, //Destination rectangle
FileName.c_str(), //Source filename
NULL, //Source rectangle
D3DX_DEFAULT, //Controls how image is filtered
D3DCOLOR_XRGB(0, 0, 0), //For transparency (0 for none)
NULL); //Source image info (usually NULL)
if(result != D3D_OK) return;

int TilesWide = info.Width / TileWidth;
int TilesHigh = info.Height / TileHeight;


for(int a=0;a<TilesWide;a++)
{
for(int b=0;b<TilesHigh;b++)
{
TEXTURE NewTexture;
NewTexture.Height = TileHeight;
NewTexture.Width = TileWidth;

result = D3DXCreateTexture(D3d,TileWidth,TileHeight,1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &NewTexture.Texture);
if(result != D3D_OK) return;

result = NewTexture.Texture->GetSurfaceLevel(0, &TexSurface); //get surface of texture
if(result != D3D_OK) return;

RECT Source;
SetRect(&Source, a*TileWidth,b*TileHeight, (a*TileWidth)+TileWidth,(b*TileHeight)+TileHeight);
RECT Dest;
SetRect(&Dest, 0,0,TileWidth,TileHeight);
result = D3d->UpdateSurface(TempSurface, &Source, TexSurface, NULL);

//NewTexture should contain our texture
TextureList.push_back(NewTexture);
NumberOfTextures++;
}
}
}
Another interesting thing:

When calling
GetSurfaceLevel()

I have to do the following afterwards or I get a memory leak if I reload my surfaces, interesting.
TexSurface->Release();
D3d->Release();

This topic is closed to new replies.

Advertisement