ResourceBase ResourceManager::find(const Torque::Path &path) { #ifdef TORQUE_DEBUG_RES_MANAGER Con::printf( "ResourceManager::find : [%s]", path.getFullPath().c_str() ); #endif ResourceHeaderMap::Iterator iter = mResourceHeaderMap.find( path.getFullPath() ); if ( iter == mResourceHeaderMap.end() ) return ResourceBase(); ResourceHeaderMap::Pair &pair = *iter; ResourceBase::Header *header = pair.value; return ResourceBase(header); }
void ResourceManager::reloadResource( const Torque::Path &path, bool showMessage ) { if ( showMessage ) Con::warnf( "[ResourceManager::notifiedFileChanged] : File changed [%s]", path.getFullPath().c_str() ); ResourceHeaderMap::Iterator iter = mResourceHeaderMap.find( path.getFullPath() ); if ( iter != mResourceHeaderMap.end() ) { ResourceBase::Header *header = (*iter).value; mResourceHeaderMap.erase( iter ); // Move the resource into the previous resource map. iter = mPrevResourceHeaderMap.findOrInsert( path ); iter->value = header; } // Now notify users of the resource change so they // can release and reload. mChangeSignal.trigger( path ); }
bool MacFileSystemChangeNotifier::internalAddNotification( const Torque::Path& dir ) { // Map the path. Torque::Path fullFSPath = mFS->mapTo( dir ); String osPath = PathToOS( fullFSPath ); // Create event stream. Event* event = new Event; CFStringRef path = CFStringCreateWithCharacters( NULL, osPath.utf16(), osPath.numChars() ); CFArrayRef paths = CFArrayCreate( NULL, ( const void** ) &path, 1, NULL ); FSEventStreamRef stream; CFAbsoluteTime latency = 3.f; FSEventStreamContext context; dMemset( &context, 0, sizeof( context ) ); context.info = event; stream = FSEventStreamCreate( NULL, &fsNotifyCallback, &context, paths, kFSEventStreamEventIdSinceNow, latency, kFSEventStreamCreateFlagNone ); event->mStream = stream; event->mDir = dir; event->mHasChanged = false; mEvents.push_back( event ); // Put it in the run loop and start the stream. FSEventStreamScheduleWithRunLoop( stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); FSEventStreamStart( stream ); CFRelease( path ); CFRelease( paths ); #ifdef DEBUG_SPEW Platform::outputDebugString( "[MacFileSystemChangeNotifier] Added change notification %i to '%s' (full path: %s)", mEvents.size(), dir.getFullPath().c_str(), osPath.c_str() ); #endif return true; }
//----------------------------------------------------------------------------- /// 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(); }
//----------------------------------------------------------------------------- /// Check if an up-to-date cached DTS is available for this DAE file bool ColladaShapeLoader::canLoadCachedDTS(const Torque::Path& path) { // Generate the cached filename Torque::Path cachedPath(path); cachedPath.setExtension("cached.dts"); // Check if a cached DTS newer than this file is available FileTime cachedModifyTime; if (Platform::getFileTimes(cachedPath.getFullPath(), NULL, &cachedModifyTime)) { bool forceLoadDAE = Con::getBoolVariable("$collada::forceLoadDAE", false); FileTime daeModifyTime; if (!Platform::getFileTimes(path.getFullPath(), NULL, &daeModifyTime) || (!forceLoadDAE && (Platform::compareFileTimes(cachedModifyTime, daeModifyTime) >= 0) )) { // DAE not found, or cached DTS is newer return true; } } return false; }
bool MacFileSystemChangeNotifier::internalRemoveNotification( const Torque::Path& dir ) { for( U32 i = 0, num = mEvents.size(); i < num; ++ i ) if( mEvents[ i ]->mDir == dir ) { #ifdef DEBUG_SPEW Platform::outputDebugString( "[MacFileSystemChangeNotifier] Removing change notification %i from '%s'", i + 1, dir.getFullPath().c_str() ); #endif FSEventStreamStop( mEvents[ i ]->mStream ); FSEventStreamInvalidate( mEvents[ i ]->mStream ); FSEventStreamRelease( mEvents[ i ]->mStream ); SAFE_DELETE( mEvents[ i ] ); mEvents.erase( i ); return true; } return false; }
static S32 buildFileList(const char* pattern, bool recurse, bool multiMatch) { static const String sSlash( "/" ); sgFindFilesResults.clear(); String sPattern(Torque::Path::CleanSeparators(pattern)); if(sPattern.isEmpty()) { Con::errorf("findFirstFile() requires a search pattern"); return -1; } if(!Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), sPattern.c_str())) { Con::errorf("findFirstFile() given initial directory cannot be expanded: '%s'", pattern); return -1; } sPattern = String::ToString(sgScriptFilenameBuffer); String::SizeType slashPos = sPattern.find('/', 0, String::Right); // if(slashPos == String::NPos) // { // Con::errorf("findFirstFile() missing search directory or expression: '%s'", sPattern.c_str()); // return -1; // } // Build the initial search path Torque::Path givenPath(Torque::Path::CompressPath(sPattern)); givenPath.setFileName("*"); givenPath.setExtension("*"); if(givenPath.getPath().length() > 0 && givenPath.getPath().find('*', 0, String::Right) == givenPath.getPath().length()-1) { // Deal with legacy searches of the form '*/*.*' String suspectPath = givenPath.getPath(); String::SizeType newLen = suspectPath.length()-1; if(newLen > 0 && suspectPath.find('/', 0, String::Right) == suspectPath.length()-2) { --newLen; } givenPath.setPath(suspectPath.substr(0, newLen)); } Torque::FS::FileSystemRef fs = Torque::FS::GetFileSystem(givenPath); //Torque::Path path = fs->mapTo(givenPath); Torque::Path path = givenPath; // Make sure that we have a root so the correct file system can be determined when using zips if(givenPath.isRelative()) path = Torque::Path::Join(Torque::FS::GetCwd(), '/', givenPath); path.setFileName(String::EmptyString); path.setExtension(String::EmptyString); if(!Torque::FS::IsDirectory(path)) { Con::errorf("findFirstFile() invalid initial search directory: '%s'", path.getFullPath().c_str()); return -1; } // Build the search expression const String expression(slashPos != String::NPos ? sPattern.substr(slashPos+1) : sPattern); if(expression.isEmpty()) { Con::errorf("findFirstFile() requires a search expression: '%s'", sPattern.c_str()); return -1; } S32 results = Torque::FS::FindByPattern(path, expression, recurse, sgFindFilesResults, multiMatch ); if(givenPath.isRelative() && results > 0) { // Strip the CWD out of the returned paths // MakeRelativePath() returns incorrect results (it adds a leading ..) so doing this the dirty way const String cwd = Torque::FS::GetCwd().getFullPath(); for(S32 i = 0;i < sgFindFilesResults.size();++i) { String str = sgFindFilesResults[i]; if(str.compare(cwd, cwd.length(), String::NoCase) == 0) str = str.substr(cwd.length()); sgFindFilesResults[i] = str; } } return results; }
char* GFXGLShader::_handleIncludes( const Torque::Path& path, FileStream *s ) { // TODO: The #line pragma on GLSL takes something called a // "source-string-number" which it then never explains. // // Until i resolve this mystery i disabled this. // //String linePragma = String::ToString( "#line 1 \r\n"); //U32 linePragmaLen = linePragma.length(); U32 shaderLen = s->getStreamSize(); char* buffer = (char*)dMalloc(shaderLen + 1); //dStrncpy( buffer, linePragma.c_str(), linePragmaLen ); s->read(shaderLen, buffer); buffer[shaderLen] = 0; char* p = dStrstr(buffer, "#include"); while(p) { char* q = p; p += 8; if(dIsspace(*p)) { U32 n = 0; while(dIsspace(*p)) ++p; AssertFatal(*p == '"', "Bad #include directive"); ++p; static char includeFile[256]; while(*p != '"') { AssertFatal(*p != 0, "Bad #include directive"); includeFile[n++] = *p++; AssertFatal(n < sizeof(includeFile), "#include directive too long"); } ++p; includeFile[n] = 0; // First try it as a local file. Torque::Path includePath = Torque::Path::Join(path.getPath(), '/', includeFile); includePath = Torque::Path::CompressPath(includePath); FileStream includeStream; if ( !includeStream.open( includePath, Torque::FS::File::Read ) ) { // Try again assuming the path is absolute // and/or relative. includePath = String( includeFile ); includePath = Torque::Path::CompressPath(includePath); if ( !includeStream.open( includePath, Torque::FS::File::Read ) ) { AssertISV(false, avar("failed to open include '%s'.", includePath.getFullPath().c_str())); if ( smLogErrors ) Con::errorf( "GFXGLShader::_handleIncludes - Failed to open include '%s'.", includePath.getFullPath().c_str() ); // Fail... don't return the buffer. dFree(buffer); return NULL; } } char* includedText = _handleIncludes(includePath, &includeStream); // If a sub-include fails... cleanup and return. if ( !includedText ) { dFree(buffer); return NULL; } // TODO: Disabled till this is fixed correctly. // // Count the number of lines in the file // before the include. /* U32 includeLine = 0; { char* nl = dStrstr( buffer, "\n" ); while ( nl ) { includeLine++; nl = dStrstr( nl, "\n" ); if(nl) ++nl; } } */ String manip(buffer); manip.erase(q-buffer, p-q); String sItx(includedText); // TODO: Disabled till this is fixed correctly. // // Add a new line pragma to restore the proper // file and line number after the include. //sItx += String::ToString( "\r\n#line %d \r\n", includeLine ); dFree(includedText); manip.insert(q-buffer, sItx); char* manipBuf = dStrdup(manip.c_str()); p = manipBuf + (p - buffer); dFree(buffer); buffer = manipBuf; } p = dStrstr(p, "#include"); } return buffer; }
bool GFXGLShader::_loadShaderFromStream( GLuint shader, const Torque::Path &path, FileStream *s, const Vector<GFXShaderMacro> ¯os ) { Vector<char*> buffers; Vector<U32> lengths; // The GLSL version declaration must go first! const char *versionDecl = "#version 150\r\n"; buffers.push_back( dStrdup( versionDecl ) ); lengths.push_back( dStrlen( versionDecl ) ); if(GFXGL->mCapabilities.shaderModel5) { const char *extension = "#extension GL_ARB_gpu_shader5 : enable\r\n"; buffers.push_back( dStrdup( extension ) ); lengths.push_back( dStrlen( extension ) ); } const char *newLine = "\r\n"; buffers.push_back( dStrdup( newLine ) ); lengths.push_back( dStrlen( newLine ) ); // Now add all the macros. for( U32 i = 0; i < macros.size(); i++ ) { if(macros[i].name.isEmpty()) // TODO OPENGL continue; String define = String::ToString( "#define %s %s\n", macros[i].name.c_str(), macros[i].value.c_str() ); buffers.push_back( dStrdup( define.c_str() ) ); lengths.push_back( define.length() ); } // Now finally add the shader source. U32 shaderLen = s->getStreamSize(); char *buffer = _handleIncludes(path, s); if ( !buffer ) return false; buffers.push_back(buffer); lengths.push_back(shaderLen); glShaderSource(shader, buffers.size(), (const GLchar**)const_cast<const char**>(buffers.address()), NULL); #if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX) FileStream stream; if ( !stream.open( path.getFullPath()+"_DEBUG", Torque::FS::File::Write ) ) { AssertISV(false, avar("GFXGLShader::initShader - failed to write debug shader '%s'.", path.getFullPath().c_str())); } for(int i = 0; i < buffers.size(); ++i) stream.writeText(buffers[i]); #endif // Cleanup the shader source buffer. for ( U32 i=0; i < buffers.size(); i++ ) dFree( buffers[i] ); glCompileShader(shader); return true; }
bool GFXD3D9Shader::_compileShader( const Torque::Path &filePath, const String& target, const D3DXMACRO *defines, GenericConstBufferLayout* bufferLayoutF, GenericConstBufferLayout* bufferLayoutI, Vector<GFXShaderConstDesc> &samplerDescriptions ) { PROFILE_SCOPE( GFXD3D9Shader_CompileShader ); HRESULT res = D3DERR_INVALIDCALL; LPD3DXBUFFER code = NULL; LPD3DXBUFFER errorBuff = NULL; #ifdef TORQUE_DEBUG U32 flags = D3DXSHADER_DEBUG; #else U32 flags = 0; #endif #ifdef TORQUE_OS_XENON flags |= D3DXSHADER_PREFER_FLOW_CONTROL; #endif #ifdef D3DXSHADER_USE_LEGACY_D3DX9_31_DLL if( D3DX_SDK_VERSION >= 32 ) { // will need to use old compiler for 1_1 shaders - check for pixel // or vertex shader with appropriate version. if ((target.compare("vs1", 3) == 0) || (target.compare("vs_1", 4) == 0)) flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL; if ((target.compare("ps1", 3) == 0) || (target.compare("ps_1", 4) == 0)) flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL; } #endif #if !defined(TORQUE_OS_XENON) && (D3DX_SDK_VERSION <= 40) #error This version of the DirectX SDK is too old. Please install a newer version of the DirectX SDK: http://msdn.microsoft.com/en-us/directx/default.aspx #endif ID3DXConstantTable* table = NULL; static String sHLSLStr( "hlsl" ); static String sOBJStr( "obj" ); // Is it an HLSL shader? if ( filePath.getExtension().equal(sHLSLStr, String::NoCase) ) { FrameAllocatorMarker fam; char *buffer = NULL; // Set this so that the D3DXInclude::Open will have this // information for relative paths. smD3DXInclude->setPath( filePath.getRootAndPath() ); FileStream s; if ( !s.open( filePath, Torque::FS::File::Read ) ) { AssertISV(false, avar("GFXD3D9Shader::initShader - failed to open shader '%s'.", filePath.getFullPath().c_str())); if ( smLogErrors ) Con::errorf( "GFXD3D9Shader::_compileShader - Failed to open shader file '%s'.", filePath.getFullPath().c_str() ); return false; } // Convert the path which might have virtualized // mount paths to a real file system path. Torque::Path realPath; if ( !FS::GetFSPath( filePath, realPath ) ) realPath = filePath; // Add a #line pragma so that error and warning messages // returned by the HLSL compiler report the right file. String linePragma = String::ToString( "#line 1 \"%s\"\r\n", realPath.getFullPath().c_str() ); U32 linePragmaLen = linePragma.length(); U32 bufSize = s.getStreamSize(); buffer = (char *)fam.alloc( bufSize + linePragmaLen + 1 ); dStrncpy( buffer, linePragma.c_str(), linePragmaLen ); s.read( bufSize, buffer + linePragmaLen ); buffer[bufSize+linePragmaLen] = 0; res = GFXD3DX.D3DXCompileShader( buffer, bufSize + linePragmaLen, defines, smD3DXInclude, "main", target, flags, &code, &errorBuff, &table ); } // Is it a precompiled obj shader? else if ( filePath.getExtension().equal( sOBJStr, String::NoCase ) ) { FileStream s; if(!s.open(filePath, Torque::FS::File::Read)) { AssertISV(false, avar("GFXD3D9Shader::initShader - failed to open shader '%s'.", filePath.getFullPath().c_str())); if ( smLogErrors ) Con::errorf( "GFXD3D9Shader::_compileShader - Failed to open shader file '%s'.", filePath.getFullPath().c_str() ); return false; } res = GFXD3DX.D3DXCreateBuffer(s.getStreamSize(), &code); AssertISV(res == D3D_OK, "Unable to create buffer!"); s.read(s.getStreamSize(), code->GetBufferPointer()); if (res == D3D_OK) { DWORD* data = (DWORD*) code->GetBufferPointer(); res = GFXD3DX.D3DXGetShaderConstantTable(data, &table); } } else { if ( smLogErrors ) Con::errorf( "GFXD3D9Shader::_compileShader - Unsupported shader file type '%s'.", filePath.getFullPath().c_str() ); return false; } if ( res != D3D_OK && smLogErrors ) Con::errorf( "GFXD3D9Shader::_compileShader - Error compiling shader: %s: %s (%x)", DXGetErrorStringA(res), DXGetErrorDescriptionA(res), res ); if ( errorBuff ) { // remove \n at end of buffer U8 *buffPtr = (U8*) errorBuff->GetBufferPointer(); U32 len = dStrlen( (const char*) buffPtr ); buffPtr[len-1] = '\0'; if( res != D3D_OK ) { if ( smLogErrors ) Con::errorf( " %s", (const char*) errorBuff->GetBufferPointer() ); } else { if ( smLogWarnings ) Con::warnf( "%s", (const char*) errorBuff->GetBufferPointer() ); } } else if ( code == NULL && smLogErrors ) Con::errorf( "GFXD3D9Shader::_compileShader - no compiled code produced; possibly missing file '%s'.", filePath.getFullPath().c_str() ); // Create the proper shader if we have code if( code != NULL ) { #ifndef TORQUE_SHIPPING LPD3DXBUFFER disassem = NULL; D3DXDisassembleShader( (DWORD*)code->GetBufferPointer(), false, NULL, &disassem ); mDissasembly = (const char*)disassem->GetBufferPointer(); SAFE_RELEASE( disassem ); if ( gDisassembleAllShaders ) { String filename = filePath.getFullPath(); filename.replace( ".hlsl", "_dis.txt" ); FileStream *fstream = FileStream::createAndOpen( filename, Torque::FS::File::Write ); if ( fstream ) { fstream->write( mDissasembly ); fstream->close(); delete fstream; } } #endif if (target.compare("ps_", 3) == 0) res = mD3D9Device->CreatePixelShader( (DWORD*)code->GetBufferPointer(), &mPixShader ); else res = mD3D9Device->CreateVertexShader( (DWORD*)code->GetBufferPointer(), &mVertShader ); if (res == S_OK) _getShaderConstants(table, bufferLayoutF, bufferLayoutI, samplerDescriptions); #ifdef TORQUE_ENABLE_CSF_GENERATION // Ok, we've got a valid shader and constants, let's write them all out. if ( !_saveCompiledOutput(filePath, code, bufferLayoutF, bufferLayoutI) && smLogErrors ) Con::errorf( "GFXD3D9Shader::_compileShader - Unable to save shader compile output for: %s", filePath.getFullPath().c_str() ); #endif SAFE_RELEASE(table); if ( res != S_OK && smLogErrors ) Con::errorf( "GFXD3D9Shader::_compileShader - Unable to create shader for '%s'.", filePath.getFullPath().c_str() ); } bool result = code != NULL && res == S_OK; SAFE_RELEASE( code ); SAFE_RELEASE( errorBuff ); return result; }
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 ); }