"From scratch" .ter file generation
by Stephen Zepp · in Torque Game Engine · 10/30/2004 (5:18 pm) · 16 replies
For testing purposes, I have the need to generate two completely square .ter files that are basically flat, each with a single texture that covers the entire heightmap.
The problem comes in where I have to do this via code (editor is not available due to massive code changes, not to mention client/server is the only way this version of our repo executes)--I have a basic console function created by Bryan Turner as part of the Terrain Manager, but unfortunately I can't figure out how to get it to assign a texture properly, while maintaining proper directory paths to my data/terrains dir.
Here is the console function I am using:
This executes fine, except for when file->save is executed:
(con't next post).
The problem comes in where I have to do this via code (editor is not available due to massive code changes, not to mention client/server is the only way this version of our repo executes)--I have a basic console function created by Bryan Turner as part of the Terrain Manager, but unfortunately I can't figure out how to get it to assign a texture properly, while maintaining proper directory paths to my data/terrains dir.
Here is the console function I am using:
ConsoleFunction(makeTestTerrain, void, 2, 10, "(string fileName, ...) - makes a test terrain file - arguments after the fileName are the names of the initial terrain materials.")
{
TerrainFile *file = new TerrainFile;
S32 nMaterialTypes;
argc -= 2;
Con::printf("console function makeTestTerrain called, filename %s", argv[1]);
// Load materials
if (argc > 1)
{
nMaterialTypes = argc;
for (S32 i=0; i<TerrainManager::MaterialGroups && i < argc; i++)
{
char material[256];
char *ext;
dStrcpy(material, argv[i+2]);
ext = dStrrchr(material, '.');
if (ext)
*ext = 0;
file->mMaterialFileName[i] = StringTable->insert(material);
}
}
else
{
nMaterialTypes = 1;
file->mMaterialFileName[0] = StringTable->insert("Default");
}
// create circular cone in the middle of the map:
S32 i, j;
for(i = 0; i < TerrainManager::BlockSize; i++)
{
for(j = 0; j < TerrainManager::BlockSize; j++)
{
S32 x = i & 0x7f;
S32 y = j & 0x7f;
F32 dist = mSqrt((64 - x) * (64 - x) + (64 - y) * (64 - y));
dist /= 64.0f;
if(dist > 1)
dist = 1;
U32 offset = i + (j << TerrainManager::BlockShift);
file->mHeightMap[offset] = (U16)((1 - dist) * (1 - dist) * 20000);
file->mBaseMaterialMap[offset] = 0;
}
}
//
char filename[256];
dStrcpy(filename,argv[1]);
char* ext = dStrrchr(filename, '.');
if (!ext || dStricmp(ext, ".ter") != 0)
dStrcat(filename, ".ter");
Con::printf("Saved the test terrain as %s", filename);
file->save(filename);
delete file;
}This executes fine, except for when file->save is executed:
(con't next post).
#2
10/30/2004 (5:22 pm)
FYI, once I can get a decent amount of the current patch of Terrain Manager build 19 against 1_3_0 debugged, along with support files and examples, I plan on handing it back to David D. for review, and hopefully release to the community. Unfortunately, I can't seem to get past this stumbling block and I need these files for debugging and troubleshooting.
#3
11/03/2004 (3:35 pm)
No one see anything with the code, or have generated .ter files from scratch? I'm assuming that I'm simply missing something that's already in the code, but needs to be applied to the TerrainBlock prior to a save...
#4
11/03/2004 (10:38 pm)
I found the easiest thing to do was to completely rewrite the terrain code... :(
#5
I'm pretty sure I'm just missing some prep step (like buildPropertyMap or something that I don't fully understand the functionality of yet) in creating the .ter files from code, but just not sure which it is yet.
Right now I'm trying to turn our dedicated server-client setup back into a "standalone capable" version, which should let me edit these .ter files.
@Ben: I assume you're talking about with TSE? Very much looking forward to seeing that implementation when the milestone hits, you're completely correct, fully new implementation would be much cleaner and effective, but also quite a bit more difficult to make backwards compatible with TGE (I think).
11/04/2004 (3:43 am)
Heh..well, we're trying to get the Terrain Manager code patched against TGE 1.3, and I'm pretty much there--it works, it pages. However, the .ter files I have can only get one texture assigned to them, and that texture path is currently hard coded to the ./ of your executable (which obviously isn't good).I'm pretty sure I'm just missing some prep step (like buildPropertyMap or something that I don't fully understand the functionality of yet) in creating the .ter files from code, but just not sure which it is yet.
Right now I'm trying to turn our dedicated server-client setup back into a "standalone capable" version, which should let me edit these .ter files.
@Ben: I assume you're talking about with TSE? Very much looking forward to seeing that implementation when the milestone hits, you're completely correct, fully new implementation would be much cleaner and effective, but also quite a bit more difficult to make backwards compatible with TGE (I think).
#6
I notice you're not writing out any opacity data for your materials?
11/04/2004 (12:18 pm)
Yes, it's true.I notice you're not writing out any opacity data for your materials?
#7
I've got an extremely basic tile set (all the same .ter, in a 4x4 grid) working, and you can cross borders, but the files are -exactly- the same, therefore I don't have the visual change across boundary. My goal was to have a checkerboard pattern, but as I've described above, I had no luck actually assigning different materials to the file--just the default.png in the working directory of the mission file itself had any luck. Quite honestly, I can't even duplicate which iteration of "random changes to see what happens" cycles I had that even got that far.
Since the texture/material paths seem to be hard coded into the .ter file, I haven't even been able to generate a flat terrain in TorqueDemo and then move it to my directory structure--the ./demo/ dir path is hardcoded into those .ter files as well.
I'm pretty sure I'm missing something really simple---either I simply don't know what path to type in to assign a texture to my console method generated test .ter files, or I am missing a basic ".ter file reconstruction" action needed before I can save the test .ter's off.
I've learned a ton regarding how terrains are handled in TGE while implementing this patch, but I'm still a clueless newbie when it comes down to it!
11/04/2004 (12:26 pm)
Right now I'm simply trying to get bare bones terrains in place for troubleshooting purposes. My goal is to be able to visually see borders between two terrain tiles, so I can have a visual feel for various boundary problems.I've got an extremely basic tile set (all the same .ter, in a 4x4 grid) working, and you can cross borders, but the files are -exactly- the same, therefore I don't have the visual change across boundary. My goal was to have a checkerboard pattern, but as I've described above, I had no luck actually assigning different materials to the file--just the default.png in the working directory of the mission file itself had any luck. Quite honestly, I can't even duplicate which iteration of "random changes to see what happens" cycles I had that even got that far.
Since the texture/material paths seem to be hard coded into the .ter file, I haven't even been able to generate a flat terrain in TorqueDemo and then move it to my directory structure--the ./demo/ dir path is hardcoded into those .ter files as well.
I'm pretty sure I'm missing something really simple---either I simply don't know what path to type in to assign a texture to my console method generated test .ter files, or I am missing a basic ".ter file reconstruction" action needed before I can save the test .ter's off.
I've learned a ton regarding how terrains are handled in TGE while implementing this patch, but I'm still a clueless newbie when it comes down to it!
#8
11/04/2004 (2:02 pm)
Ben, are you planning to port the TSE terrain paging system back to TGE? If so, I reckon I'll ditch the terrain manager altogether...
#9
Anyway, I'd love to analyze your code and help you out, but I fear I haven't the time to do it... I would suggest making sure you understand each thing it writes out... none of it is really complex, just the context that makes it so. You can also always write your own stuff out, or use the terrain editor to assign new materials, right?
11/04/2004 (3:42 pm)
It's not inconceivable that that might happen but if it did it wouldn't happen for probably a year, at the soonest. If you want to get any sort of real project done, I strongly suggest doing your own solution. :)Anyway, I'd love to analyze your code and help you out, but I fear I haven't the time to do it... I would suggest making sure you understand each thing it writes out... none of it is really complex, just the context that makes it so. You can also always write your own stuff out, or use the terrain editor to assign new materials, right?
#10
11/04/2004 (3:56 pm)
In a nutshell the question is "how (and more deeply, why) do materialAlphaMaps get generated?". It appears they are directly related to both the height of a location and the terrain texture applied to it, but the underlying save terrain code (stock, mostly at least) won't let you save a .ter file without alpha maps...I just don't know how they get generated ;)
#11
11/04/2004 (5:29 pm)
Material alpha maps tell you how much of each material is present at each sample point. The terrain blender is responsible for taking those inputs and blending them together to produce a final texture which is rendered. So it's basically saying... this spot is 75% rock, 25% grass, or similar things. It's generated by the terrain editor, either by using some generation rules (which might take height into account) or simply by the user painting information onto the terrain.
#12
11/05/2004 (3:26 am)
@Ben: helps a lot, thanks! Is this done by buildPropertyMap(), or is that a separate functionality?
#13
11/05/2004 (9:07 am)
Ahh... The alpha maps are just values, and those values are manipulated by the terrain editor. There's no internal book-keeping done on them in the terrain class, if that's what you're asking... I guess I'm a little unclear what you're getting at.
#14
The very basic "generate terrain" console method I'm using doesn't ever do whatever it takes to calculate and assign values, and the stock save terrain method assertfails if you don't have them generated and placed in the array.
Thanks for the help!
11/05/2004 (9:15 am)
You've given me enough to go on, when I can get to it this weekend I'll trace through the editor load sequence (from load to save), and try to figure out where those values are generated and assigned.The very basic "generate terrain" console method I'm using doesn't ever do whatever it takes to calculate and assign values, and the stock save terrain method assertfails if you don't have them generated and placed in the array.
Thanks for the help!
#15
11/05/2004 (10:59 am)
I'd suggest assigning all 1's (all 255's) to the first alpha map, and 0's to the rest, as a test. The size of the map is the same as the size of the heightfield.
#16
In the console function makeTestTerrain:
03/09/2005 (2:10 am)
I know this is a bit late but here is how I fixed that memory crash with the alpha maps.In the console function makeTestTerrain:
// start of file
// Load materials
if (argc > 1)
{
nMaterialTypes = argc;
for (S32 i=0; i<TerrainBlock::MaterialGroups && i < argc; i++)
{
char material[256];
char *ext;
dStrcpy(material, argv[i+2]);
ext = dStrrchr(material, '.');
if (ext)
*ext = 0;
file->mMaterialFileName[i] = StringTable->insert(material);
file->mMaterialAlphaMap[i] = new U8[TerrainBlock::BlockSize * TerrainBlock::BlockSize];
dMemset(file->mMaterialAlphaMap[i], i + 1 / 1 , TerrainBlock::BlockSize * TerrainBlock::BlockSize);
}
}
else
{
nMaterialTypes = 1;
file->mMaterialFileName[0] = NULL; //StringTable->insert("Default");
}
// rest of file
Torque 3D Owner Stephen Zepp
bool TerrainFile::save(const char *filename) { FileStream writeFile; if (!ResourceManager->openFileForWrite(writeFile, filename)) { Con::printf("Failed to open File For Write, filename %s", filename); return false; } // write the VERSION and HeightField writeFile.write((U8)FILE_VERSION); for (S32 i=0; i < (TerrainManager::BlockSize * TerrainManager::BlockSize); i++) writeFile.write(mHeightMap[i]); // write the material group map, after merging the flags... Material * materialMap = (Material*)mMaterialMap; for (S32 j=0; j < (TerrainManager::BlockSize * TerrainManager::BlockSize); j++) { U8 val = mBaseMaterialMap[j]; val |= materialMap[j].flags & Material::PersistMask; writeFile.write(val); } // write the MaterialList Info S32 k; for(k=0; k < TerrainManager::MaterialGroups; k++) { // DS: always write the materials out since they're shared. // ok, only write out the material string if there is a non-zero // alpha material: /*if(mMaterialFileName[k] && mMaterialFileName[k][0]) { S32 n; for(n = 0; n < TerrainManager::BlockSize * TerrainManager::BlockSize; n++) if(mMaterialAlphaMap[k][n]) break; if(n == TerrainManager::BlockSize * TerrainManager::BlockSize) mMaterialFileName[k] = 0; }*/ writeFile.writeString(mMaterialFileName[k]); } for(k=0; k < TerrainManager::MaterialGroups; k++) { if(mMaterialFileName[k] && mMaterialFileName[k][0]) { AssertFatal(mMaterialAlphaMap[k] != NULL, "Error, must have a material map here!"); writeFile.write(TerrainManager::BlockSize * TerrainManager::BlockSize, mMaterialAlphaMap[k]); } } if(mTextureScript) { U32 len = dStrlen(mTextureScript); writeFile.write(len); writeFile.write(len, mTextureScript); } else writeFile.write(U32(0)); if(mHeightfieldScript) { U32 len = dStrlen(mHeightfieldScript); writeFile.write(len); writeFile.write(len, mHeightfieldScript); } else writeFile.write(U32(0)); return (writeFile.getStatus() == FileStream::Ok); }It asserts every single time on the AssertFatal(mMaterialAlphaMap[k] != NULL, "Error, must have a material map here!"); line if I call the terrain with any derivation of a path to the terrain .png file I want to use, such as:
makeTestTerrain("./scorched", "./game/data/terrains/highplains/scorched");
or any derivation thereof.
As far as I can tell, there are two possible problems:
1) I'm completely off on the path I need to assign a terrain texture.
2) There is something that needs to be done regarding alphaMaps (buildMaterialsMap possibly?)
Of course, there could be a wide variety of things that I'm missing completely--does anyone have any thoughts or spot any problems?