Relative Texture Paths in .x files

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
distributist
Posts: 4
Joined: Wed Apr 07, 2010 9:02 pm

Relative Texture Paths in .x files

Post by distributist »

I've been working on a program someone else wrote, doing some general clean-up. One of the things I have done is upgrade it from Irrlicht 0.14 to 1.7.1, with an interim stop at 1.3.

In the move from 1.3 to 1.7.1, I've encountered a problem with textures in .x files (exported from Maya a long time ago) not loading. I've tried several things, but with no luck (well, putting the texture in the same folder as the .x file works, but that breaks the nice clean organisation that we have). In searching the forums I've seen references to "relative path issues" but haven't found a clear indication of exactly what these are, or what the changes were.

Can anyone provide some clarification on what changed and what I need to do? From what I can see, relative paths should be recognised as they were before.

Thanks,
Hugh
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Well, we usually only add more paths that are tested. Maybe you can provide the output shown on the console?
distributist
Posts: 4
Joined: Wed Apr 07, 2010 9:02 pm

Post by distributist »

Sure. Since relative paths worked before, I figured I must be missing something obvious.

The code loads the file like so:

std::string File = Path + "Objects/Horses/horse_and_jockey.x";
IAnimatedMesh *HorseModel = smgr->getMesh(File.c_str());

The layout is
-Objects
-Horses
>horse_andjockey.x
-Textures
-Whip
>whip.jpg

The .x file has contents such as:

MeshMaterialList {
[Lots of lines of numbers cut]
Material {
1.000000;1.000000;1.000000;1.000000;;
0.000000;
0.000000;0.000000;0.000000;;
0.000000;0.000000;0.000000;;

TextureFilename {
"../../Textures/Whip/whip.jpg";
}
}
}

The error message is simple: "Could not open file of texture: whip.jpg" I've tracked this down to CNullDriver::getTexture.

Thanks,
Hugh
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Ok, I'll have to check whether the relative path additions are working correctly. Sometimes, broken paths are generated due to a missing slash or so. I'll move this to the bug forum so we can track this issue.
distributist
Posts: 4
Joined: Wed Apr 07, 2010 9:02 pm

Post by distributist »

I've been stepping through the Irrlicht code, and, though I don't yet understand what should be happening, I think I see what is going wrong.

In the example below:
  • The mesh is loaded from: "C:\Projects\OurProject\OurProgram\Objects\Horses"
  • The texture is relative to this, in "C:\Projects\OurProject\OurProgram\Textures\Reins", or "../../Textures/Reins/strap.jpg" as it is stored in the .x file.
Irrlicht 1.7.1 - CXMeshFileLoader::parseDataObjectMaterial - lines 1515-1529

Code: Select all

if (!parseDataObjectTextureFilename(TextureFileName))
  return false;
This first part works fine, returning our relative path as defined in the .x file: "../../Textures/Reins/strap.jpg"

Code: Select all

// original name
if (FileSystem->existFile(TextureFileName))
   material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(TextureFileName));
existFile can't find the relative path, so it jumps to the else:

Code: Select all

// mesh path
else
  {
  TextureFileName=FilePath + FileSystem->getFileBasename(TextureFileName);
  if (FileSystem->existFile(TextureFileName))
    material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(TextureFileName));
Here FilePath is the full path we loaded the .x file from: C:/Projects/OurProject/OurProgram/Objects/Horses//" (There's a "//" on the end, but that isn't the problem, at least not yet). The code then separates the file name from the relative path, giving us this, which is wrong: "C:/Projects/OurProject/OurProgram/Objects/Horses//strap.jpg" (This explains why the texture is found if I put it in the same directory).

existFile again can't find the file, so it jumps to:

Code: Select all

// working directory
else
  material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(FileSystem->getFileBasename(TextureFileName)));
And this line tries to load it from whatever the working directory is (it ends up generating the same path as the block above: "C:/Projects/OurProject/OurProgram/Objects/Horses//strap.jpg").

If someone could help me understand where the relative paths are supposed to be handled, I'd be happy to see if I can figure out how to handle this. I'm a little reluctant to try to patch something I don't yet understand well.

Thanks,
Hugh
sio2
Competition winner
Posts: 1003
Joined: Thu Sep 21, 2006 5:33 pm
Location: UK

Post by sio2 »

distributist wrote:In the example below:
  • The mesh is loaded from: "C:\Projects\OurProject\OurProgram\Objects\Horses"
  • The texture is relative to this, in "C:\Projects\OurProject\OurProgram\Textures\Reins", or "../../Textures/Reins/strap.jpg" as it is stored in the .x file.
Have you tried doing

Code: Select all

changeWorkingDirectoryTo("C:\Projects\OurProject\OurProgram\Objects\Horses");
before trying to load the mesh?
distributist
Posts: 4
Joined: Wed Apr 07, 2010 9:02 pm

Post by distributist »

sio2 wrote:Have you tried doing

Code: Select all

changeWorkingDirectoryTo("C:\Projects\OurProject\OurProgram\Objects\Horses");
before trying to load the mesh?
Sorry for the delay in replying. I had to deal with some other issues and just got back to this. Yes, this solves the problem.

The original code doesn't use changeWorkingDirectory anywhere. Earlier versions of Irrlicht's loader must have automatically used the animation file's path as the default, whereas later versions (somewhere after 1.3) must have used the file system object's working directory as the default.

While this is a change, I'm not sure it's a bug. The earlier behaviour was convenient, but I can certainly see how you could make the decision to implement it either way.

Thanks again for everyone's help with this.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

I just digged into that problem for a while. I couldn't really find out if this had ever been different - at least not in the loader. But maybe I missed that as there had been a lot of changes. Anyway that does not matter so much - I get what you are asking for here and it's for example working that way for .obj files.

And well, I suppose the real problem we are having is that each loader does code the way to find texture itself and so we hunt those problems rather often. I think the solution is to add one tool-function which takes the mesh-filename (or at least the folder-name part of it), the user defined texture-path (some filetypes allow setting that) and figures out the best name to use from that. And that function should include relative paths starting from the mesh. Afterwards we can just use that function for all meshloaders - or at least I hope so.

Btw - I also found the reason for the double slashes (//), but that didn't cause the problems here.

Not sure when I will find time to fix this, I suppose it's rather something for 1.8 as there are still a few more urgent bugs I have to work at. But thanks for reporting, I try to get to it, it's something that has bothered me already a few times ;-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply