Torque3D Documentation / _generateds / materialList.cpp

materialList.cpp

Engine/source/materials/materialList.cpp

More...

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