X-File embedded template references not recognized by GetChildren()

Started by
5 comments, last by darkzorb 9 years, 4 months ago

Hey Everyone,

I'm trying to debug some code I have which reads in .X files. The problem I'm having is depending on the structure format of my .X files, sometimes the embedded template references are not read.

I have a particular template with the following format:

Frame Root {

FrameTransformMatrix {...}

Material material1 {...}

Frame ChildFrame {

FrameTransformMatrix {...}

Mesh {

MeshNormals {...}

MeshMaterialList {...

{material1}

}

}

}

}

And for some reason when I perform a getChildren when I am parsing the MeshMaterialList template, 0 children are found. It seems material1 is not recognized even though I define it before the ChildFrame.

What I noticed is that when I take the material out of the Root frame, all of a sudden DirectX recognizes the previously defined template. So my new template would take the following form:

Material material1 {...}

Frame Root {

FrameTransformMatrix {...}

Frame ChildFrame {

FrameTransformMatrix {...}

Mesh {

MeshNormals {...}

MeshMaterialList {...

{material1}

}

}

}

}

Anyone have any idea why DirectX would not recognize the material1 template in the first format?

To clarify what I'm trying to do, I recently updated some old 32-bit code which read X-Files using the old IDirectXFile interface to use the 64-bit compatible ID3DX interface. So I'm still registering templates and creating enumeration objects in the same way. My old .X files mostly get read in correctly except for those in the format listed above. I would manually change the .X files, but I'd rather retain the robustness of the type of .X files that the code can read in if at all possible.

I saw that the new ID3DXFile interface has a new RegisterEnumTemplates method which wasn't in the old IDirectXFile API. Not sure what it is, so I tried using it to register templates, but it didn't seem to do anything, or maybe I'm just not using it correctly.

Not sure if my post makes any sense. I'm still a bit new to DirectX, so forgive me if I'm lacking clarity in any of my explanation of the problem. Any suggestions/hints on this matter would be greatly appreciated. Thanks!

Advertisement

First, it helps if you post the actual text you're using. You don't show where you use the keyword "template." What you've posted isn't valid templating.

In any case, templates define structures in terms of a structure name, curly brackets, and contents described with known keywords.

I.e.,

template MyStuff { WORD someWord; STRING someString; ... }

Within MyStuff, WORD and STRING are recogninzed. In your first template (assuming it's a template), you have: MesMaterialList { { some-word } }

The parser doesn't know how you intend the inner structure { some-word } to be interpreted. It's an unnamed, undefined structure.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Hey Buckeyes,

First of all, thanks for the response. Appreciate you reading over my post and trying to help. Forgive me if some of my assumptions are incorrect as I work through your post, as I'm still new to DirectX.


First, it helps if you post the actual text you're using. You don't show where you use the keyword "template." What you've posted isn't valid templating.

I register the D3DRM_XTEMPLATES found in rmxftmpl.h. That way I don't need all of the template front matter in every single .X file. Plus I only use predefined templates, so D3DRM_XTEMPLATES is more than enough. Below is the contents of my .X file in it's original non-working format. As I originally stated, when I move the material out of the Root frame, so that it is the first template in the file, all of a sudden the material1 reference found in the MeshMaterialList is recognized by the GetChildren() call when parsing MeshMaterialList. See code example at end of post for clarification of this move.


Frame Root {
  FrameTransformMatrix {
     1.000000, 0.000000, 0.000000, 0.000000,
     0.000000,-0.000000, 1.000000, 0.000000,
     0.000000, 1.000000, 0.000000, 0.000000,
     0.000000, 0.000000, 0.000000, 1.000000;;
  }

  Material material1 {
    0.000000;0.000000;0.000000;0.000000;;
    0.000000;0.000000;0.000000;0.000000;;
    0.000000;0.000000;0.000000;;

    TextureFilename {
     "material1.bmp";
    }
  }

  Frame Cube {
    FrameTransformMatrix {
       1.750000, 0.000000, 0.000000, 0.000000,
       0.000000, 0.583333, 0.000000, 0.000000,
       0.000000, 0.000000,16.291666, 0.000000,
      -0.010820, 0.000000, 0.000000, 1.000000;;
    }

    Mesh {
      8;
      -0.304800;-0.304800;-0.304800;,
      -0.304800; 0.304800;-0.304800;,
       0.304800; 0.304800;-0.304800;,
       0.304800;-0.304800;-0.304800;,
      -0.304800;-0.304800; 0.304800;,
      -0.304800; 0.304800; 0.304800;,
       0.304800; 0.304800; 0.304800;,
       0.304800;-0.304800; 0.304800;;
      6;
      4;0,1,5,4;,
      4;1,2,6,5;,
      4;2,3,7,6;,
      4;3,0,4,7;,
      4;3,2,1,0;,
      4;4,5,6,7;;

      MeshNormals {
        6;
        -1.000000; 0.000000; 0.000000;,
         0.000000; 1.000000;-0.000000;,
         1.000000; 0.000000;-0.000000;,
         0.000000;-1.000000; 0.000000;,
        -0.000000; 0.000000;-1.000000;,
        -0.000000; 0.000000; 1.000000;;
        6;
        4;0,0,0,0;,
        4;1,1,1,1;,
        4;2,2,2,2;,
        4;3,3,3,3;,
        4;4,4,4,4;,
        4;5,5,5,5;;
      }

      MeshMaterialList {
        1;
        6;
        0,
        0,
        0,
        0,
        0,
        0;;
        {material1}
      }
    }
  }
}

?


In any case, templates define structures in terms of a structure name, curly brackets, and contents described with known keywords.

I.e.,

template MyStuff { WORD someWord; STRING someString; ... }

Within MyStuff, WORD and STRING are recogninzed. In your first template (assuming it's a template), you have: MesMaterialList { { some-word } }

The parser doesn't know how you intend the inner structure { some-word } to be interpreted. It's an unnamed, undefined structure.

As far as I know the MeshMaterialList template for X-Files hasn't changed from IDirectXFile to ID3DX. I looked at the template format found on the Microsoft website and it still seems to look the same. Not sure why it would parse correctly in the past with GetNextObject(), but returns zero children with GetChildren(). But maybe I'm just not understanding your explanation correctly.

http://msdn.microsoft.com/en-us/library/windows/desktop/bb147192(v=vs.85).aspx

Moreover, if the format of MeshMaterialList is incorrect, then it goes back to my original question of, why does it parse correctly when I move material1 outside of the Root frame. If {material1} is undefined when written in this way, then shouldn't GetChildren() similarly not recognize the reference when parsing the X-File with material1 outside of the Root frame?

For clarification, this is the adjustment to the X-File that causes the material1 reference to be recognized by GetChildren(). Again, I would make the edit to my X-Files, but the problem is, I have a bunch of X-Files that use the above format, and I rather not manually edit all of them. Much rather have a more robust parser if at all possible.


Material material1 {
  0.000000;0.000000;0.000000;0.000000;;
  0.000000;0.000000;0.000000;0.000000;;
  0.000000;0.000000;0.000000;;

  TextureFilename {
   "material1.bmp";
  }
}

Frame Root {
  FrameTransformMatrix {
     1.000000, 0.000000, 0.000000, 0.000000,
     0.000000,-0.000000, 1.000000, 0.000000,
     0.000000, 1.000000, 0.000000, 0.000000,
     0.000000, 0.000000, 0.000000, 1.000000;;
  }

  Frame Cube {
    FrameTransformMatrix {
       1.750000, 0.000000, 0.000000, 0.000000,
       0.000000, 0.583333, 0.000000, 0.000000,
       0.000000, 0.000000,16.291666, 0.000000,
      -0.010820, 0.000000, 0.000000, 1.000000;;
    }

    Mesh {
      8;
      -0.304800;-0.304800;-0.304800;,
      -0.304800; 0.304800;-0.304800;,
       0.304800; 0.304800;-0.304800;,
       0.304800;-0.304800;-0.304800;,
      -0.304800;-0.304800; 0.304800;,
      -0.304800; 0.304800; 0.304800;,
       0.304800; 0.304800; 0.304800;,
       0.304800;-0.304800; 0.304800;;
      6;
      4;0,1,5,4;,
      4;1,2,6,5;,
      4;2,3,7,6;,
      4;3,0,4,7;,
      4;3,2,1,0;,
      4;4,5,6,7;;

      MeshNormals {
        6;
        -1.000000; 0.000000; 0.000000;,
         0.000000; 1.000000;-0.000000;,
         1.000000; 0.000000;-0.000000;,
         0.000000;-1.000000; 0.000000;,
        -0.000000; 0.000000;-1.000000;,
        -0.000000; 0.000000; 1.000000;;
        6;
        4;0,0,0,0;,
        4;1,1,1,1;,
        4;2,2,2,2;,
        4;3,3,3,3;,
        4;4,4,4,4;,
        4;5,5,5,5;;
      }

      MeshMaterialList {
        1;
        6;
        0,
        0,
        0,
        0,
        0,
        0;;
        {material1}
      }
    }
  }
}

I missed the mention of GetChildren() in the topic title. You don't mention how or why you're reading the X file, but that and your second post indicates you're using ID3DXFile. See comments below. I've never used that method for loading X-files and can't help you directly with that.


I saw that the new ID3DXFile interface has a new RegisterEnumTemplates method

First, there really isn't anything "new" about D3DX9. Actually, the entire D3DX API is deprecated.

Second, can you explain further what you mean "some code I have which reads in .X files"? The purpose for "reading" individual objects from an X file isn't clear. That is, if your intent is to load/create a mesh from the file, why not use D3DXLoadMeshFromX? That process recognizes all the predefined templates and you don't have to mess with registering templates, etc., as you've indicated you do, in fact, use only the predefined templates.

EDIT: If you have a lot of files using materials in the way shown in your first file post, that would require you to edit the files to place material data in the MeshMaterialList, as that's what the MeshMaterialList template expects.

Third, is there a reason you want to define data variables, rather than simply placing the data itself in the MeshMaterialList structure? EDIT: reading your post again, perhaps it's because you have existing files in the format shown.

That is, instead of:


MeshMaterialList {
  1;
  6;
  0,
  0,
  0,
  0,
  0,
  0;;
  {material1}
}

why not:


MeshMaterialList {
  1;
  6;
  0,
  0,
  0,
  0,
  0,
  0;;
  Material material1 {
    0.000000;0.000000;0.000000;0.000000;;
    0.000000;0.000000;0.000000;0.000000;;
    0.000000;0.000000;0.000000;;
    TextureFilename { "material1.bmp"; }
  }
}

The latter is the common method of specifying data to meet the template specification.

With regard the original X file data that you posted, with only "{ material1 }" in the MeshMaterialList structure, I suspect it's not recognized as a material because it's not defined in that context. It's expecting data (not variable names) within the MeshMaterialList structure. That is, you have a structure Material (that happens to have the name "material1") as a child of the root frame. I am guessing, but I suspect the parser interprets the child structure of the Root Frame named "material1" as just child data of the frame. It appears you're trying to use "material1" as a variable name, the data to be inserted whereever the parser finds the word "material1." I'm not sure the parser is that smart. It's built to use templates to arrange data found in the X file into defined structures. EDIT: It appears your "old" file loading method may have taken the place of the parser with regard to using "variables" in that way.

With regard to defining "material1" as a variable outside the mesh hierarchy, I suspect GetChildren() finds it because in that position in the file, it's a valid data structure. Just out of curiosity, in the second file you posted above, does the MeshMaterialList, in fact, actually contain the data from material1? What is the actual data content of the MeshMaterialList?


As far as I know the MeshMaterialList template for X-Files hasn't changed from IDirectXFile to ID3DX.

It's very likely the template hasn't changed. That template, as defined, expects Material structures (not variable names) with data defining the various materials to use for the Mesh to which the MeshMaterialList is a child. That is, the template specifies, to follow the face indices:


[Material <3D82AB4D-62DA-11CF-AB39-0020AF71E433>]

and the template for Material is specified elsewhere. As you have, in your X file:

{ { material1 }}

I'm guessing that doesn't meet the specification.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.


I missed the mention of GetChildren() in the topic title. You don't mention how or why you're reading the X file, but that and your second post indicates you're using ID3DXFile. See comments below. I've never used that method for loading X-files and can't help you directly with that.

You actually didn't miss the mention of GetChildren(). I added that to the title after your initial response because I felt that my thread title was a bit vague before. Sorry about the confusion.


First, there really isn't anything "new" about D3DX9. Actually, the entire D3DX API is deprecated.

Yeah, I would like to get rid of the interface altogether at some point, but I'm really just not all that ambitious right now to go that route as I would not only have to rewrite a lot of code but would also need to redo the 100s of models I have. It's definitely something I'll consider in the future though. For now, I'm just trying to port the program which in the past only worked on 32-bit Windows to now also run on a 64-bit Windows client. The 32-bit program had used the even older IDirectXFile interface, which lacks compatibility with 64-bit. This is why I switched over to ID3DXFile, since it does have 64-bit compatibility. Unfortunately, ID3DXFile no longer supports the GetNextObject() method which had parsed all the mesh files correctly, and now uses the GetChildren() method to scan for templates.


Second, can you explain further what you mean "some code I have which reads in .X files"? The purpose for "reading" individual objects from an X file isn't clear. That is, if your intent is to load/create a mesh from the file, why not use D3DXLoadMeshFromX? That process recognizes all the predefined templates and you don't have to mess with registering templates, etc., as you've indicated you do, in fact, use only the predefined templates.

EDIT: If you have a lot of files using materials in the way shown in your first file post, that would require you to edit the files to place material data in the MeshMaterialList, as that's what the MeshMaterialList template expects.

To be honest, I'm not really sure why the original developer designed the architecture of the program in this way. What the program currently does is, it reads in data from .X model files into a structure which can be later read by OpenGL to display the graphics. Honestly, it would have made more sense to use all DirectX or do the graphics part with OpenGL but without the X-file API, but unfortunately that's not how the previous developer did things, and I really don't have the time at this current point in time to redo everything from the grounds up sad.png .


Third, is there a reason you want to define data variables, rather than simply placing the data itself in the MeshMaterialList structure? EDIT: reading your post again, perhaps it's because you have existing files in the format shown.

Yes, you are correct! I do have a lot of existing files in that format, which is why I'm hoping that I don't need to go and modify every single X-File I have that isn't being parsed correctly.


With regard the original X file data that you posted, with only "{ material1 }" in the MeshMaterialList structure, I suspect it's not recognized as a material because it's not defined in that context. It's expecting data (not variable names) within the MeshMaterialList structure. That is, you have a structure Material (that happens to have the name "material1") as a child of the root frame. I am guessing, but I suspect the parser interprets the child structure of the Root Frame named "material1" as just child data of the frame. It appears you're trying to use "material1" as a variable name, the data to be inserted whereever the parser finds the word "material1." I'm not sure the parser is that smart. It's built to use templates to arrange data found in the X file into defined structures. EDIT: It appears your "old" file loading method may have taken the place of the parser with regard to using "variables" in that way.

Hmm, as far as I know, the previous developer did not have any special parsing code to recognize "variables" and replace them with material data, it seemed the GetNextObject() method inherently has the capability to recognize these references and replace them with the associated named template.


With regard to defining "material1" as a variable outside the mesh hierarchy, I suspect GetChildren() finds it because in that position in the file, it's a valid data structure. Just out of curiosity, in the second file you posted above, does the MeshMaterialList, in fact, actually contain the data from material1? What is the actual data content of the MeshMaterialList?

I hope I'm understanding your question correctly, but correct me if I'm not. What I have posted above is exactly what is in the file, I did not alter it in any way. In the file {material1} is not replaced with the actual contents of the material. It merely has "{material1}" as the text, and uses it as an embedded template reference, which should be picked up by the ID3DX interface GetChild() method to automatically replace the reference with a previous declaration of the template with that name.


It's very likely the template hasn't changed. That template, as defined, expects Material structures (not variable names) with data defining the various materials to use for the Mesh to which the MeshMaterialList is a child. That is, the template specifies, to follow the face indices:
[Material <3D82AB4D-62DA-11CF-AB39-0020AF71E433>]
and the template for Material is specified elsewhere. As you have, in your X file:

{ { material1 }}

I'm guessing that doesn't meet the specification.

From what I've read, X-Files has supported these embedded template references for a while. The page linked below has some examples where they have materials defined, and then inserts a reference by the material name.

http://paulbourke.net/dataformats/directx/


From what I've read, X-Files has supported these embedded template references for a while. The page linked below has some examples where they have materials defined, and then inserts a reference by the material name.

Thanks for the link. Learn something new every day. Perhaps an important distinction: template reference vs. reference to an instance. In the link you provided, the author provides examples of object instances, very similar to using typedef in C.


Template mytemp {
array DWORD myvar[3];
}
Then an instance of this would look like:
mytemp aTemp {
1, 2, 3;
}


In a later example, he shows instantiations of the Material template: RedMaterial and GreenMaterial, with later use of the instances in the MeshMaterialList. That pattern appears to match what you discovered by moving your instance of Material material1 from Frame Root.

FYI, I played around with a couple X files of my own, editing them and opening them with both MView (Microsoft's old mesh viewer) and my own app, both of which use D3DXLoadMeshFromX and D3DXLoadMeshHierarchyFromX. For those X files, I moved instances of Material from MeshMaterialList outside of the Frame hierarchy as you did, and replaced those instances in MeshMaterialList with { <instanceName> }, the files loaded and displayed correctly, as you found. However, moving the Material instance instead to Frame Root (your other example) resulted in a load error. I suspect that the difference between those two, as mentioned above, is that instancing the Material outside the Frame hierarchy creates a "global" reference which, when MeshMaterialList{ ... { material1 } ... } is parsed, can be found and processed. When an instance is defined within a Frame (or other structure), that instance is not global and the parser doesn't know what to do with { material1 }, as material1 as a reference isn't defined.

As a guess, the same underlying process for the D3DXLoadMesh functions and GetChildren() is probably used. That, unfortunately, implies that you're stuck with 1) modifying all offending X files, or 2) writing your own parser.

I have, in fact, coded my own (very ugly and limited) X file parser for use in my D3D11 apps - it was a lengthy process and, it sounds as if, at this point, editing your X files is the more efficient choice. Besides, once the files are edited, if you then move on to the D3DXLoadMesh functions, you're ready to go.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.


FYI, I played around with a couple X files of my own, editing them and opening them with both MView (Microsoft's old mesh viewer) and my own app, both of which use D3DXLoadMeshFromX and D3DXLoadMeshHierarchyFromX. For those X files, I moved instances of Material from MeshMaterialList outside of the Frame hierarchy as you did, and replaced those instances in MeshMaterialList with { }, the files loaded and displayed correctly, as you found. However, moving the Material instance instead to Frame Root (your other example) resulted in a load error. I suspect that the difference between those two, as mentioned above, is that instancing the Material outside the Frame hierarchy creates a "global" reference which, when MeshMaterialList{ ... { material1 } ... } is parsed, can be found and processed. When an instance is defined within a Frame (or other structure), that instance is not global and the parser doesn't know what to do with { material1 }, as material1 as a reference isn't defined.

Hey Buckeye,

Thanks for testing material template inside and outside of the frame hierarchy with your own code. If not even D3DXLoadMeshFromX/D3DXLoadMeshHierarchyFromX loads the X-File correctly when inside the frame hierarchy, that's enough evidence for me to assume the format for my X-Files are not written as they were intended. I will go ahead and take your suggestion of modifying all the offending X files. Thanks for the help!

This topic is closed to new replies.

Advertisement