materialList.cpp
Engine/source/materials/materialList.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames 26// Copyright (C) 2015 Faust Logic, Inc. 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 28 29#include "platform/platform.h" 30#include "materials/materialList.h" 31 32#include "materials/matInstance.h" 33#include "materials/materialManager.h" 34#include "materials/materialFeatureTypes.h" 35#include "materials/processedMaterial.h" 36#include "core/volume.h" 37#include "console/simSet.h" 38 39#include "scene/reflectionManager.h" 40#include "renderInstance/renderDeferredMgr.h" 41#include "lighting/advanced/advancedLightManager.h" 42#include "lighting/advanced/advancedLightBinManager.h" 43 44 45MaterialList::MaterialList() 46{ 47 VECTOR_SET_ASSOCIATION(mMatInstList); 48 VECTOR_SET_ASSOCIATION(mMaterialNames); 49} 50 51MaterialList::MaterialList(const MaterialList* pCopy) 52{ 53 VECTOR_SET_ASSOCIATION(mMatInstList); 54 VECTOR_SET_ASSOCIATION(mMaterialNames); 55 56 mMaterialNames.setSize(pCopy->mMaterialNames.size()); 57 S32 i; 58 for (i = 0; i < mMaterialNames.size(); i++) 59 { 60 mMaterialNames[i] = pCopy->mMaterialNames[i]; 61 } 62 63 clearMatInstList(); 64 mMatInstList.setSize(pCopy->size()); 65 for( i = 0; i < mMatInstList.size(); i++ ) 66 { 67 if( i < pCopy->mMatInstList.size() && pCopy->mMatInstList[i] ) 68 { 69 mMatInstList[i] = pCopy->mMatInstList[i]->getMaterial()->createMatInstance(); 70 } 71 else 72 { 73 mMatInstList[i] = NULL; 74 } 75 } 76} 77 78 79 80MaterialList::MaterialList(U32 materialCount, const char **materialNames) 81{ 82 VECTOR_SET_ASSOCIATION(mMaterialNames); 83 84 set(materialCount, materialNames); 85} 86 87 88//-------------------------------------- 89void MaterialList::set(U32 materialCount, const char **materialNames) 90{ 91 free(); 92 mMaterialNames.setSize(materialCount); 93 clearMatInstList(); 94 mMatInstList.setSize(materialCount); 95 for(U32 i = 0; i < materialCount; i++) 96 { 97 mMaterialNames[i] = materialNames[i]; 98 mMatInstList[i] = NULL; 99 } 100} 101 102 103//-------------------------------------- 104MaterialList::~MaterialList() 105{ 106 free(); 107} 108 109//-------------------------------------- 110void MaterialList::setMaterialName(U32 index, const String& name) 111{ 112 if (index < mMaterialNames.size()) 113 mMaterialNames[index] = name; 114} 115 116//-------------------------------------- 117GFXTextureObject *MaterialList::getDiffuseTexture(U32 index) 118{ 119 AssertFatal(index < (U32) mMatInstList.size(), "MaterialList::getDiffuseTex: index lookup out of range."); 120 121 MatInstance *matInst = dynamic_cast<MatInstance*>(mMatInstList[index]); 122 if (matInst && matInst->getProcessedMaterial()) 123 return matInst->getProcessedMaterial()->getStageTexture(0, MFT_DiffuseMap); 124 else 125 return NULL; 126} 127 128//-------------------------------------- 129void MaterialList::free() 130{ 131 clearMatInstList(); 132 mMatInstList.clear(); 133 mMaterialNames.clear(); 134} 135 136/* 137//-------------------------------------- 138U32 MaterialList::push_back(GFXTexHandle textureHandle, const String &filename) 139{ 140 mMaterialNames.push_back(filename); 141 mMatInstList.push_back(NULL); 142 143 // return the index 144 return mMaterialNames.size()-1; 145} 146*/ 147 148//-------------------------------------- 149U32 MaterialList::push_back(const String &filename, Material* material) 150{ 151 mMaterialNames.push_back(filename); 152 mMatInstList.push_back(material ? material->createMatInstance() : NULL); 153 154 // return the index 155 return mMaterialNames.size()-1; 156} 157 158//-------------------------------------- 159bool MaterialList::read(Stream &stream) 160{ 161 free(); 162 163 // check the stream version 164 U8 version; 165 if ( stream.read(&version) && version != BINARY_FILE_VERSION) 166 return readText(stream,version); 167 168 // how many materials? 169 U32 count; 170 if ( !stream.read(&count) ) 171 return false; 172 173 // pre-size the vectors for efficiency 174 mMaterialNames.reserve(count); 175 176 // read in the materials 177 for (U32 i=0; i<count; i++) 178 { 179 // Load the bitmap name 180 char buffer[256]; 181 stream.readString(buffer); 182 if( !buffer[0] ) 183 { 184 AssertWarn(0, "MaterialList::read: error reading stream"); 185 return false; 186 } 187 188 // Material paths are a legacy of Tribes tools, 189 // strip them off... 190 char *name = &buffer[dStrlen(buffer)]; 191 while (name != buffer && name[-1] != '/' && name[-1] != '\\') 192 name--; 193 194 // Add it to the list 195 mMaterialNames.push_back(name); 196 mMatInstList.push_back(NULL); 197 } 198 199 return (stream.getStatus() == Stream::Ok); 200} 201 202//-------------------------------------- 203bool MaterialList::write(Stream &stream) 204{ 205 stream.write((U8)BINARY_FILE_VERSION); // version 206 stream.write((U32)mMaterialNames.size()); // material count 207 208 for(S32 i=0; i < mMaterialNames.size(); i++) // material names 209 stream.writeString(mMaterialNames[i]); 210 211 return (stream.getStatus() == Stream::Ok); 212} 213 214//-------------------------------------- 215bool MaterialList::readText(Stream &stream, U8 firstByte) 216{ 217 free(); 218 219 if (!firstByte) 220 return (stream.getStatus() == Stream::Ok || stream.getStatus() == Stream::EOS); 221 222 char buf[1024]; 223 buf[0] = firstByte; 224 U32 offset = 1; 225 226 for(;;) 227 { 228 stream.readLine((U8*)(buf+offset), sizeof(buf)-offset); 229 if(!buf[0]) 230 break; 231 offset = 0; 232 233 // Material paths are a legacy of Tribes tools, 234 // strip them off... 235 char *name = &buf[dStrlen(buf)]; 236 while (name != buf && name[-1] != '/' && name[-1] != '\\') 237 name--; 238 239 // Add it to the list 240 mMaterialNames.push_back(name); 241 mMatInstList.push_back(NULL); 242 } 243 244 return (stream.getStatus() == Stream::Ok || stream.getStatus() == Stream::EOS); 245} 246 247bool MaterialList::readText(Stream &stream) 248{ 249 U8 firstByte; 250 stream.read(&firstByte); 251 return readText(stream,firstByte); 252} 253 254//-------------------------------------- 255bool MaterialList::writeText(Stream &stream) 256{ 257 for(S32 i=0; i < mMaterialNames.size(); i++) 258 stream.writeLine((U8*)(mMaterialNames[i].c_str())); 259 stream.writeLine((U8*)""); 260 261 return (stream.getStatus() == Stream::Ok); 262} 263 264//-------------------------------------------------------------------------- 265// Clear all materials in the mMatInstList member variable 266//-------------------------------------------------------------------------- 267void MaterialList::clearMatInstList() 268{ 269 // clear out old materials. any non null element of the list should be pointing at deletable memory, 270 // although multiple indexes may be pointing at the same memory so we have to be careful (see 271 // comment in loop body) 272 for (U32 i=0; i<mMatInstList.size(); i++) 273 { 274 if (mMatInstList[i]) 275 { 276 BaseMatInstance* current = mMatInstList[i]; 277 278 // ok, since ts material lists can remap difference indexes to the same object 279 // we need to make sure that we don't delete the same memory twice. walk the 280 // rest of the list and null out any pointers that match the one we deleted. 281 for (U32 j=0; j<mMatInstList.size(); j++) 282 if (mMatInstList[j] == current) 283 mMatInstList[j] = NULL; 284 285 mMatInstList[i] = NULL; 286 delete current; 287 } 288 } 289} 290 291//-------------------------------------------------------------------------- 292// Map materials - map materials to the textures in the list 293//-------------------------------------------------------------------------- 294void MaterialList::mapMaterials() 295{ 296 mMatInstList.setSize( mMaterialNames.size() ); 297 298 for( U32 i=0; i<mMaterialNames.size(); i++ ) 299 mapMaterial( i ); 300} 301 302/// Map the material name at the given index to a material instance. 303/// 304/// @note The material instance that is created will <em>not be initialized.</em> 305 306void MaterialList::mapMaterial( U32 i ) 307{ 308 AssertFatal( i < size(), "MaterialList::mapMaterialList - index out of bounds" ); 309 310 if( mMatInstList[i] != NULL ) 311 return; 312 313 // lookup a material property entry 314 const String &matName = getMaterialName(i); 315 316 // JMQ: this code assumes that all materials have names. 317 if( matName.isEmpty() ) 318 { 319 mMatInstList[i] = NULL; 320 return; 321 } 322 323 String materialName; 324 // Skip past a leading '#' marker. 325 if (matName.compare("#", 1) == 0) 326 materialName = MATMGR->getMapEntry(matName.substr(1, matName.length()-1)); 327 else 328 materialName = MATMGR->getMapEntry(matName); 329 330 // IF we didn't find it, then look for a PolyStatic generated Material 331 // [a little cheesy, but we need to allow for user override of generated Materials] 332 if ( materialName.isEmpty() ) 333 materialName = MATMGR->getMapEntry( String::ToString( "polyMat_%s", matName.c_str() ) ); 334 335 if ( materialName.isNotEmpty() ) 336 { 337 Material * mat = MATMGR->getMaterialDefinitionByName( materialName ); 338 mMatInstList[i] = mat ? mat->createMatInstance() : MATMGR->createWarningMatInstance(); 339 } 340 else 341 { 342 if ( Con::getBoolVariable( "$Materials::createMissing", true ) ) 343 { 344 // No Material found, create new "default" material with just a diffuseMap 345 346 // First see if there is a valid diffuse texture 347 GFXTexHandle texHandle; 348 if (mLookupPath.isEmpty()) 349 { 350 texHandle.set( mMaterialNames[i], &GFXStaticTextureSRGBProfile, avar("%s() - handle (line %d)", __FUNCTION__, __LINE__) ); 351 } 352 else 353 { 354 // Should we strip off the extension of the path here before trying 355 // to load the texture? 356 String fullPath = String::ToString( "%s/%s", mLookupPath.c_str(), mMaterialNames[i].c_str() ); 357 texHandle.set( fullPath, &GFXStaticTextureSRGBProfile, avar("%s() - handle (line %d)", __FUNCTION__, __LINE__) ); 358 } 359 360 if ( texHandle.isValid() ) 361 { 362 String newMatName = Sim::getUniqueName( "DefaultMaterial" ); 363 Material *newMat = MATMGR->allocateAndRegister( newMatName, mMaterialNames[i] ); 364 365 // Flag this as an autogenerated Material 366 newMat->mAutoGenerated = true; 367 368 // Overwrite diffuseMap in new material 369 newMat->mDiffuseMapFilename[0] = texHandle->mTextureLookupName; 370 371 // Set up some defaults for transparent textures 372 if (texHandle->mHasTransparency) 373 { 374 newMat->mTranslucent = true; 375 newMat->mTranslucentBlendOp = Material::LerpAlpha; 376 newMat->mTranslucentZWrite = true; 377 newMat->mAlphaRef = 20; 378 } 379 380 // create a MatInstance for the new material 381 mMatInstList[i] = newMat->createMatInstance(); 382 383 #ifndef TORQUE_SHIPPING 384 Con::warnf( "[MaterialList::mapMaterials] Creating missing material for texture: %s", texHandle->mTextureLookupName.c_str() ); 385 #endif 386 } 387 else 388 { 389 Con::errorf( "[MaterialList::mapMaterials] Unable to find material for texture: %s", mMaterialNames[i].c_str() ); 390 mMatInstList[i] = MATMGR->createWarningMatInstance(); 391 } 392 } 393 else 394 { 395 mMatInstList[i] = MATMGR->createWarningMatInstance(); 396 } 397 } 398} 399 400void MaterialList::initMatInstances( const FeatureSet &features, 401 const GFXVertexFormat *vertexFormat ) 402{ 403 for( U32 i=0; i < mMatInstList.size(); i++ ) 404 { 405 BaseMatInstance *matInst = mMatInstList[i]; 406 if ( !matInst ) 407 continue; 408 409 if ( !matInst->init( features, vertexFormat ) ) 410 { 411 Con::errorf( "MaterialList::initMatInstances - failed to initialize material instance for '%s'", 412 matInst->getMaterial()->getName() ); 413 414 // Fall back to warning material. 415 416 SAFE_DELETE( matInst ); 417 matInst = MATMGR->createMatInstance( "WarningMaterial" ); 418 matInst->init( MATMGR->getDefaultFeatures(), vertexFormat ); 419 mMatInstList[ i ] = matInst; 420 } 421 else 422 { 423 AdvancedLightManager* lightMgr = dynamic_cast<AdvancedLightManager*>(LIGHTMGR); 424 if (lightMgr) 425 { 426 REFLECTMGR->getReflectionMaterial(matInst); 427 428 // Hunt for the pre-pass manager/target 429 lightMgr->getDeferredRenderBin()->getDeferredMaterial(matInst); 430 } 431 } 432 } 433 434} 435 436void MaterialList::setMaterialInst( BaseMatInstance *matInst, U32 texIndex ) 437{ 438 AssertFatal( texIndex < mMatInstList.size(), "MaterialList::setMaterialInst - index out of bounds" ); 439 mMatInstList[texIndex] = matInst; 440} 441