colladaAppMaterial.cpp
Engine/source/ts/collada/colladaAppMaterial.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#include "platform/platform.h" 25 26#include "ts/loader/tsShapeLoader.h" 27#include "ts/collada/colladaAppMaterial.h" 28#include "ts/collada/colladaUtils.h" 29#include "ts/tsMaterialList.h" 30#include "materials/materialManager.h" 31 32using namespace ColladaUtils; 33 34#ifndef TORQUE_ASSIMP 35 36String AppMaterial::cleanString(const String& str) 37{ 38 String cleanStr(str); 39 40 // Replace invalid characters with underscores 41 const String badChars(" -,.+=*/"); 42 for (String::SizeType i = 0; i < badChars.length(); i++) 43 cleanStr.replace(badChars[i], '_'); 44 45 // Prefix with an underscore if string starts with a number 46 if ((cleanStr[0] >= '0') && (cleanStr[0] <= '9')) 47 cleanStr.insert(0, '_'); 48 49 return cleanStr; 50} 51 52#endif // !TORQUE_ASSIMP 53 54//------------------------------------------------------------------------------ 55 56ColladaAppMaterial::ColladaAppMaterial(const char* matName) 57: mat(0), 58 effect(0), 59 effectExt(0) 60{ 61 name = matName; 62 63 // Set some defaults 64 flags |= TSMaterialList::S_Wrap; 65 flags |= TSMaterialList::T_Wrap; 66 67 diffuseColor = LinearColorF::ONE; 68 69 roughness = 0.0f; 70 metalness = 0.0f; 71 doubleSided = false; 72} 73 74ColladaAppMaterial::ColladaAppMaterial(const domMaterial *pMat) 75: mat(pMat), 76 diffuseColor(LinearColorF::ONE), 77 roughness(0.0f), 78 metalness(0.0f), 79 doubleSided(false) 80{ 81 // Get the effect element for this material 82 effect = daeSafeCast<domEffect>(mat->getInstance_effect()->getUrl().getElement()); 83 effectExt = new ColladaExtension_effect(effect); 84 85 // Get the <profile_COMMON>, <diffuse> and <specular> elements 86 const domProfile_COMMON* commonProfile = ColladaUtils::findEffectCommonProfile(effect); 87 const domCommon_color_or_texture_type_complexType* domDiffuse = findEffectDiffuse(effect); 88 89 // Wrap flags 90 if (effectExt->wrapU) 91 flags |= TSMaterialList::S_Wrap; 92 if (effectExt->wrapV) 93 flags |= TSMaterialList::T_Wrap; 94 95 // Set material attributes 96 if (commonProfile) { 97 98 F32 transparency = 0.0f; 99 if (commonProfile->getTechnique()->getConstant()) { 100 const domProfile_COMMON::domTechnique::domConstant* constant = commonProfile->getTechnique()->getConstant(); 101 diffuseColor.set(1.0f, 1.0f, 1.0f, 1.0f); 102 resolveFloat(constant->getReflectivity(), &metalness); 103 resolveTransparency(constant, &transparency); 104 } 105 else if (commonProfile->getTechnique()->getLambert()) { 106 const domProfile_COMMON::domTechnique::domLambert* lambert = commonProfile->getTechnique()->getLambert(); 107 resolveColor(lambert->getDiffuse(), &diffuseColor); 108 resolveFloat(lambert->getReflectivity(), &metalness); 109 resolveTransparency(lambert, &transparency); 110 } 111 else if (commonProfile->getTechnique()->getPhong()) { 112 const domProfile_COMMON::domTechnique::domPhong* phong = commonProfile->getTechnique()->getPhong(); 113 resolveColor(phong->getDiffuse(), &diffuseColor); 114 resolveFloat(phong->getShininess(), &roughness); 115 resolveTransparency(phong, &transparency); 116 } 117 else if (commonProfile->getTechnique()->getBlinn()) { 118 const domProfile_COMMON::domTechnique::domBlinn* blinn = commonProfile->getTechnique()->getBlinn(); 119 resolveColor(blinn->getDiffuse(), &diffuseColor); 120 resolveFloat(blinn->getShininess(), &roughness); 121 resolveTransparency(blinn, &transparency); 122 } 123 124 // Normalize specularPower (1-128). Values > 1 are assumed to be 125 // already normalized. 126 if (roughness <= 1.0f) 127 roughness *= 128; 128 roughness = mClampF(roughness, 1.0f, 128.0f); 129 130 // Set translucency 131 if (transparency != 0.0f) { 132 flags |= TSMaterialList::Translucent; 133 if (transparency > 1.0f) { 134 flags |= TSMaterialList::Additive; 135 diffuseColor.alpha = transparency - 1.0f; 136 } 137 else if (transparency < 0.0f) { 138 flags |= TSMaterialList::Subtractive; 139 diffuseColor.alpha = -transparency; 140 } 141 else { 142 diffuseColor.alpha = transparency; 143 } 144 } 145 else 146 diffuseColor.alpha = 1.0f; 147 } 148 149 // Double-sided flag 150 doubleSided = effectExt->double_sided; 151 152 // Get the paths for the various textures => Collada indirection at its finest! 153 // <texture>.<newparam>.<sampler2D>.<source>.<newparam>.<surface>.<init_from>.<image>.<init_from> 154 diffuseMap = getSamplerImagePath(effect, getTextureSampler(effect, domDiffuse)); 155 normalMap = getSamplerImagePath(effect, effectExt->bumpSampler); 156 157 // Set the material name 158 name = ColladaUtils::getOptions().matNamePrefix; 159 if ( ColladaUtils::getOptions().useDiffuseNames ) 160 { 161 Torque::Path diffusePath( diffuseMap ); 162 name += diffusePath.getFileName(); 163 } 164 else 165 { 166 name += _GetNameOrId(mat); 167 } 168} 169 170void ColladaAppMaterial::resolveFloat(const domCommon_float_or_param_type* value, F32* dst) 171{ 172 if (value && value->getFloat()) { 173 *dst = value->getFloat()->getValue(); 174 } 175} 176 177void ColladaAppMaterial::resolveColor(const domCommon_color_or_texture_type* value, LinearColorF* dst) 178{ 179 if (value && value->getColor()) { 180 dst->red = value->getColor()->getValue()[0]; 181 dst->green = value->getColor()->getValue()[1]; 182 dst->blue = value->getColor()->getValue()[2]; 183 dst->alpha = value->getColor()->getValue()[3]; 184 } 185} 186 187// Generate a new Material object 188Material *ColladaAppMaterial::createMaterial(const Torque::Path& path) const 189{ 190 // The filename and material name are used as TorqueScript identifiers, so 191 // clean them up first 192 String cleanFile = cleanString(TSShapeLoader::getShapePath().getFileName()); 193 String cleanName = cleanString(getName()); 194 195 // Prefix the material name with the filename (if not done already by TSShapeConstructor prefix) 196 if (!cleanName.startsWith(cleanFile)) 197 cleanName = cleanFile + "_" + cleanName; 198 199 // Determine the blend operation for this material 200 Material::BlendOp blendOp = (flags & TSMaterialList::Translucent) ? Material::LerpAlpha : Material::None; 201 if (flags & TSMaterialList::Additive) 202 blendOp = Material::Add; 203 else if (flags & TSMaterialList::Subtractive) 204 blendOp = Material::Sub; 205 206 // Create the Material definition 207 const String oldScriptFile = Con::getVariable("$Con::File"); 208 Con::setVariable("$Con::File", path.getFullPath()); // modify current script path so texture lookups are correct 209 Material *newMat = MATMGR->allocateAndRegister( cleanName, getName() ); 210 Con::setVariable("$Con::File", oldScriptFile); // restore script path 211 212 newMat->mDiffuseMapFilename[0] = diffuseMap; 213 newMat->mNormalMapFilename[0] = normalMap; 214 215 newMat->mDiffuse[0] = diffuseColor; 216 newMat->mRoughness[0] = roughness; 217 newMat->mMetalness[0] = metalness; 218 219 newMat->mDoubleSided = doubleSided; 220 newMat->mTranslucent = (bool)(flags & TSMaterialList::Translucent); 221 newMat->mTranslucentBlendOp = blendOp; 222 223 return newMat; 224} 225