//----------------------------------------------------------------------------- /// Copy a texture from a KMZ to a cache. Note that the texture filename is modified void copySketchupTexture(const Torque::Path &path, String &textureFilename) { if (textureFilename.isEmpty()) return; Torque::Path texturePath(textureFilename); texturePath.setExtension(findTextureExtension(texturePath)); String cachedTexFilename = String::ToString("%s_%s.cached", TSShapeLoader::getShapePath().getFileName().c_str(), texturePath.getFileName().c_str()); Torque::Path cachedTexPath; cachedTexPath.setRoot(path.getRoot()); cachedTexPath.setPath(path.getPath()); cachedTexPath.setFileName(cachedTexFilename); cachedTexPath.setExtension(texturePath.getExtension()); FileStream *source; FileStream *dest; if ((source = FileStream::createAndOpen(texturePath.getFullPath(), Torque::FS::File::Read)) == NULL) return; if ((dest = FileStream::createAndOpen(cachedTexPath.getFullPath(), Torque::FS::File::Write)) == NULL) { delete source; return; } dest->copyFrom(source); delete dest; delete source; // Update the filename in the material cachedTexPath.setExtension(""); textureFilename = cachedTexPath.getFullPath(); }
void TerrainFile::_loadLegacy( FileStream &stream ) { // Some legacy constants. enum { MaterialGroups = 8, BlockSquareWidth = 256, }; const U32 sampleCount = BlockSquareWidth * BlockSquareWidth; mSize = BlockSquareWidth; // Load the heightmap. mHeightMap.setSize( sampleCount ); for ( U32 i=0; i < mHeightMap.size(); i++ ) stream.read( &mHeightMap[i] ); // Prior to version 7 we stored this weird material struct. const U32 MATERIAL_GROUP_MASK = 0x7; struct Material { enum Flags { Plain = 0, Rotate = 1, FlipX = 2, FlipXRotate = 3, FlipY = 4, FlipYRotate = 5, FlipXY = 6, FlipXYRotate = 7, RotateMask = 7, Empty = 8, Modified = BIT(7), // must not clobber TerrainFile::MATERIAL_GROUP_MASK bits! PersistMask = BIT(7) }; U8 flags; U8 index; }; // Temp locals for loading before we convert to the new // version 7+ format. U8 baseMaterialMap[sampleCount] = { 0 }; U8 *materialAlphaMap[MaterialGroups] = { 0 }; Material materialMap[BlockSquareWidth * BlockSquareWidth]; // read the material group map and flags... dMemset(materialMap, 0, sizeof(materialMap)); AssertFatal(!(Material::PersistMask & MATERIAL_GROUP_MASK), "Doh! We have flag clobberage..."); for (S32 j=0; j < sampleCount; j++) { U8 val; stream.read(&val); // baseMaterialMap[j] = val & MATERIAL_GROUP_MASK; materialMap[j].flags = val & Material::PersistMask; } // Load the material names. Vector<String> materials; for ( U32 i=0; i < MaterialGroups; i++ ) { String matName; stream.read( &matName ); if ( matName.isEmpty() ) continue; if ( mFileVersion > 3 && mFileVersion < 6 ) { // Between version 3 and 5 we store the texture file names // relative to the terrain file. We restore the full path // here so that we can create a TerrainMaterial from it. materials.push_back( Torque::Path::CompressPath( mFilePath.getRoot() + mFilePath.getPath() + '/' + matName ) ); } else materials.push_back( matName ); } if ( mFileVersion <= 3 ) { GFXTexHandle terrainMat; Torque::Path matRelPath; // Try to automatically fix up our material file names for (U32 i = 0; i < materials.size(); i++) { if ( materials[i].isEmpty() ) continue; terrainMat.set( materials[i], &GFXDefaultPersistentProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ) ); if ( terrainMat ) continue; matRelPath = materials[i]; String path = matRelPath.getPath(); String::SizeType n = path.find( '/', 0, String::NoCase ); if ( n != String::NPos ) { matRelPath.setPath( String(Con::getVariable( "$defaultGame" )) + path.substr( n, path.length() - n ) ); terrainMat.set( matRelPath, &GFXDefaultPersistentProfile, avar( "%s() - (line %d)", __FUNCTION__, __LINE__ ) ); if ( terrainMat ) { materials[i] = matRelPath.getFullPath(); mNeedsResaving = true; } } } // for (U32 i = 0; i < TerrainBlock::MaterialGroups; i++) } // if ( mFileVersion <= 3 ) if ( mFileVersion == 1 ) { for( S32 j = 0; j < sampleCount; j++ ) { if ( materialAlphaMap[baseMaterialMap[j]] == NULL ) { materialAlphaMap[baseMaterialMap[j]] = new U8[sampleCount]; dMemset(materialAlphaMap[baseMaterialMap[j]], 0, sampleCount); } materialAlphaMap[baseMaterialMap[j]][j] = 255; } } else { for( S32 k=0; k < materials.size(); k++ ) { AssertFatal(materialAlphaMap[k] == NULL, "Bad assumption. There should be no alpha map at this point..."); materialAlphaMap[k] = new U8[sampleCount]; stream.read(sampleCount, materialAlphaMap[k]); } } // Throw away the old texture and heightfield scripts. if ( mFileVersion >= 3 ) { U32 len; stream.read(&len); char *textureScript = (char *)dMalloc(len + 1); stream.read(len, textureScript); dFree( textureScript ); stream.read(&len); char *heightfieldScript = (char *)dMalloc(len + 1); stream.read(len, heightfieldScript); dFree( heightfieldScript ); } // Load and throw away the old edge terrain paths. if ( mFileVersion >= 5 ) { stream.readSTString(true); stream.readSTString(true); } U32 layerCount = materials.size() - 1; // Ok... time to convert all this mess to the layer index map! for ( U32 i=0; i < sampleCount; i++ ) { // Find the greatest layer. U32 layer = 0; U32 lastValue = 0; for ( U32 k=0; k < MaterialGroups; k++ ) { if ( materialAlphaMap[k] && materialAlphaMap[k][i] > lastValue ) { layer = k; lastValue = materialAlphaMap[k][i]; } } // Set the layer index. mLayerMap[i] = getMin( layer, layerCount ); } // Cleanup. for ( U32 i=0; i < MaterialGroups; i++ ) delete [] materialAlphaMap[i]; // Force resaving on these old file versions. //mNeedsResaving = false; // Resolve the TerrainMaterial objects from the names. _resolveMaterials( materials ); }