Sign in to follow this  
danharibo

Texture manager is fail

Recommended Posts

I tried to write a texture manager that stopped textures being loaded more than once, but I've hit a slight snag. The textures don't load at all, they get returned as NULL even though if the file doesn't exist, a "missing.dds" texture gets set. here is the code that loads the textures:
LPDIRECT3DTEXTURE9 RenderSystem::getTexture(std::string filename)
{
	std::ofstream outF("error.txt",std::ios_base::app);
	std::vector<std::pair<std::string,LPDIRECT3DTEXTURE9>>::iterator texIt;
	
	for(texIt = mTextures.begin(); texIt != mTextures.end(); texIt++)
	{
		outF << (*texIt).first << " : "<< filename << "\n";
		if((*texIt).first == filename)
		{
			return (*texIt).second;
		}
	}
	
	outF << filename.c_str() << "\n";

	
	//Texture isn't loaded yet, try to load it..
	LPDIRECT3DTEXTURE9 nNewTx=0;
	
	std::ifstream mFile(filename.c_str());
	
	if(mFile.is_open())
	{
		mFile.close();
		D3DXCreateTextureFromFile(d3ddev,filename.c_str(),&nNewTx);
		outF << "RenderManager: Texture Found!" << "\n";
		mTextures.push_back(std::pair<std::string,LPDIRECT3DTEXTURE9>(filename,nNewTx));	
	}
	else
	{
		D3DXCreateTextureFromFile(d3ddev,"missing.dds",&nNewTx);
		outF << "OSHI-" << "\n";
		mFile.close();
	}
	outF.close();
	return nNewTx;
}
this of course, outputs to a file:
Quote:
sprite.dds RenderManager: Texture Found! sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds sprite.dds : sprite.dds
Now, even though it "finds" the texture, the instance of the texture that is returned is NULL, and instead of being greeted by some sprites (which is what happens when i load the file per sprite) I just get a blank screen :(

Share this post


Link to post
Share on other sites
Are you sure that it loads "missing.dds" successfully? You never check the return value of D3DXCreateTextureFromFile().

Step over the code with the debugger to see exactly what's going on.

BTW, there is no need to call close() on the files; their destructors will take care of that.

Share this post


Link to post
Share on other sites
Ok, after checking the Result of the call, It doesn't load the texture. but it doesn't return any of the errors here: http://msdn2.microsoft.com/en-us/library/bb172801(VS.85).aspx either. What :(

Share this post


Link to post
Share on other sites
How are you checking for errors? The correct way is to use the FAILED and SUCCEEDED macros. Example:

if ( FAILED(D3DXCreateTextureFromFile(...)) ) { ... }


Doing something like this:

if ( D3DXCreateTextureFromFile(...) != D3D_OK ) { ... }


is wrong (don't remember why though).

Share this post


Link to post
Share on other sites
Ok, Now i'm doing this..

if(mFile.is_open())
{
mFile.close();

HRESULT hr;
hr = D3DXCreateTextureFromFile(d3ddev,filename.c_str(),&nNewTx);
if(FAILED(hr))
{
char buf[2048];
sprintf(buf, "Error: %s error description: %s\n",DXGetErrorString(hr),DXGetErrorDescription(hr));
outF << buf << "\n";

return NULL;
}
outF << "RenderManager: Texture Found!" << "\n";
mTextures.push_back(std::pair<std::string,LPDIRECT3DTEXTURE9>(filename,nNewTx));
}
else
{
HRESULT hr;
hr = D3DXCreateTextureFromFile(d3ddev,"missing.dds",&nNewTx);
if(FAILED(hr))
{
char buf[2048];
sprintf(buf, "Error: %s error description: %s\n",DXGetErrorString(hr),DXGetErrorDescription(hr));
outF << buf << "\n";

return NULL;
}
}


and I'm getting this:
Quote:
sprite.dds
Error: D3DERR_INVALIDCALL error description: Invalid call




[Edited by - danharibo on April 24, 2008 2:10:32 PM]

Share this post


Link to post
Share on other sites
First, don't post the same line a 100 times. Posting it once and saying it repeats is enough. Please edit your two posts and fix this.

Second, like MJP said, use the Debug Runtimes and see if you get any errors.

Third, that error might mean that it is unable to locate the texture. Make sure you are using the correct path.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
First, don't post the same line a 100 times. Posting it once and saying it repeats is enough. Please edit your two posts and fix this.

Second, like MJP said, use the Debug Runtimes and see if you get any errors.

Third, that error might mean that it is unable to locate the texture. Make sure you are using the correct path.


Ok, Sorry :x

I'm running the debug runtimes, and I'm getting this now:
Quote:
D3DX: pTexture pointer is invalid


And It can locate the file, as when I load the texture per Sprite, it works.

Share this post


Link to post
Share on other sites
Do you get the same behavior if you use a different filetype? "sprite.png" for example? Is there a particular reason you're storing your textures in a vector of pairs? Wouldn't a key-value container be better?

Just reviewing my own texture pool code, the only time D3DXCreateTextureFromFileEx fails on me is when it cant find the texture in the folder it's looking in.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
if ( D3DXCreateTextureFromFile(...) != D3D_OK ) { ... }

is wrong (don't remember why though).
Because a "failed" return value is a value with the high bit set, there's 2 billion possible "success" values, and 2 billion possible "failure" values. Checking against D3D_OK is only checking one of the 2 billion possible values. It's less of an issue with D3D, since I think it almost always returns D3D_OK, but there are some calls that can return e.g. S_FALSE, which is a success code, but isn't the same as D3D_OK (It usually means that the call succeeded, but there's something that might cause problems - E.g. SetTexture(0, NULL) might return S_FALSE because it succeeded, but the texture passed was NULL (Hypothetically)).


Quote:
Original post by danharibo
I'm running the debug runtimes, and I'm getting this now:
Quote:
D3DX: pTexture pointer is invalid


And It can locate the file, as when I load the texture per Sprite, it works.
Where is that error coming from? What function (The line before or after it in the debug output will tell you)?

Also, I wouldn't bother checking if the file exists, why not just set the missing.dds file if the original file can't be loaded?
And what Gage64 said - a std::map would be much better suited for this, that's exactly what it's for after all...

Share this post


Link to post
Share on other sites
Ok, this is what the code looks like now:
LPDIRECT3DTEXTURE9 RenderSystem::getTexture(std::string filename)
{
std::ofstream outF("error.txt",std::ios_base::app);
std::map<std::string,LPDIRECT3DTEXTURE9>::iterator texIt;

for(texIt = mTextures.begin(); texIt != mTextures.end(); texIt++)
{
outF << "Texture " << filename << " Is in Library" << "\n";
if((*texIt).first == filename)
{
return (*texIt).second;
}
}


outF << "Texture " << filename << " Is Not in Library, Adding it" << "\n";

//Texture isn't loaded yet, try to load it..
LPDIRECT3DTEXTURE9 nNewTx=0;

HRESULT hr;
hr = D3DXCreateTextureFromFileA(d3ddev,filename.c_str(),&nNewTx);
if(FAILED(hr))
{
char buf[2048];
sprintf(buf, "Error: %s error description: %s\n",DXGetErrorString(hr),DXGetErrorDescription(hr));
outF << buf << "\n";
outF.close();
if(mTextures.find("err") != mTextures.end())
return mTextures.find("err")->second;
return NULL;
}

mTextures.insert(std::pair<std::string,LPDIRECT3DTEXTURE9>(filename,nNewTx));
return nNewTx;
}

The output in error.txt is still the same though:
Quote:
Texture sprite.dds Is Not in Library, Adding it
Error: D3DERR_INVALIDCALL error description: Invalid call

Texture sprite.dds Is Not in Library, Adding it
Error: D3DERR_INVALIDCALL error description: Invalid call


Share this post


Link to post
Share on other sites
I'm not sure, but I think that if D3DXCreateTextureFromFile can't find the file, it returns D3DXERR_INVALIDDATA rather than D3DERR_INVALIDCALL. But don't quote me on that.

In any case, it probably means that D3DXCreateTextureFromFile, or your d3ddev variable is NULL.

Share this post


Link to post
Share on other sites
Ok, I'm having some trouble again here, when adding the default texture to the map (or "err"), according to this loop it's in the map:
	if(KEY_DOWN(VK_DELETE))
{
//Print out all Textures:
std::map<std::string,LPDIRECT3DTEXTURE9>::iterator texIter;
for(texIter = mTextures.begin(); texIter != mTextures.end(); texIter++)
{
std::ofstream outF("TextureList.txt");
outF << texIter->first << "\n";
outF.close();
}
}


and the contents of "TextureList.txt" is simply "err", as it should be.

and according to this, it is loaded successfully.
	LPDIRECT3DTEXTURE9 errTex;
HRESULT hr = D3DXCreateTextureFromFileA(d3ddev,"err.dds",&errTex);
if(FAILED(hr))
{
char buf[2048];
sprintf(buf, "Error Loading err.dds: %s error description: %s\n",DXGetErrorString(hr),DXGetErrorDescription(hr));
std::ofstream outF("error.txt");
outF << buf << "\n";
outF.close();
}
mTextures.insert(std::pair<std::string,LPDIRECT3DTEXTURE9>("err",errTex));

There is no such error in the log so it must have loaded correctly.

Now, When I return the "err.dds" in getTexture, it doesn't return..
...	HRESULT hr;
hr = D3DXCreateTextureFromFileA(d3ddev,filename.c_str(),&nNewTx);
if(FAILED(hr))
{
char buf[2048];
sprintf(buf, "Failed to add %s to Cache: %s error description: %s\n",filename.c_str(),DXGetErrorString(hr),DXGetErrorDescription(hr));
outF << buf << "\n";
if(mTextures.find("err") != mTextures.end())
{
outF << "Returning Default Texture" << std::endl;
outF.close();
return mTextures.find("err")->second;
}
return NULL;
}
...

Which is odd, since it's loaded and in the map, yet "find" doesn't return anything :|

Share this post


Link to post
Share on other sites
Upon seeing the word "singleton" my sense of public service compels me to post this...

Quote:
Original post by Promit
I was originally going to write something myself. I decided it wasn't necessary; Washu, jpetrie, and others did most of the actual work already. This list will be updated whenever I feel like it. The ones I like are in bold.

Washu's Journal
Why are you infected with Singletonitis?
Singletonitis, Part 2
Singletonitis, Part 3
Threads
Singletons and Memory Management
When to use and not to use singletons
Rate my engine!
learning singletons
Sharing data between game states
Good/Generic C++ Programming
Singleton managers
Singleton versus Monostate Pattern
The One: A Singleton Discussion (companion to article)
A Singleton Texture Manager for OpenGL (companion to article)
Articles
A Singleton Texture Manager for OpenGL
The One: A Singleton Discussion
Using Managers
The Singleton Class Cluster
External Links
Singleton Pattern (wikipedia)
Singleton Pattern (c2 wiki)
Singleton Considered Stupid
Use your singletons wisely
Why Singletons are Evil
Singletonitis

Share this post


Link to post
Share on other sites
Quote:
Original post by MJP
Upon seeing the word "singleton" my sense of public service compels me to post this...



I'm sure a render manager (that is in charge of inserting new sprites into the rendering loop) would be a good class to have singleton'd

Share this post


Link to post
Share on other sites
Quote:
Original post by danharibo
Quote:
Original post by MJP
Upon seeing the word "singleton" my sense of public service compels me to post this...



I'm sure a render manager (that is in charge of inserting new sprites into the rendering loop) would be a good class to have singleton'd


Nope.

Share this post


Link to post
Share on other sites
Quote:
Original post by danharibo
I'm sure a render manager (that is in charge of inserting new sprites into the rendering loop) would be a good class to have singleton'd

No reason to require one and only one instance.
No reason to access it globally.

Ergo:

No reason for it to be a singleton. [smile]

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