khanat-opennel-code/code/nel/tools/3d/plugin_max/nel_mesh_lib/export_material.cpp

1434 lines
48 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
#include "export_nel.h"
#include "../tile_utility/tile_utility.h"
#include "nel/3d/texture_file.h"
#include "nel/3d/texture_multi_file.h"
#include "nel/3d/texture_cube.h"
#include "nel/3d/tangent_space_build.h"
#include "nel/3d/meshvp_per_pixel_light.h"
#include <vector>
#include <string>
using namespace NLMISC;
using namespace NL3D;
using namespace std;
// Name of animatable values
#define BMTEX_CROP_APPLY "apply"
#define BMTEX_CROP_U_NAME "clipu"
#define BMTEX_CROP_V_NAME "clipv"
#define BMTEX_CROP_W_NAME "clipw"
#define BMTEX_CROP_H_NAME "cliph"
#define MAT_SLOTS 4
#define SHADER_NORMAL 1
#define SHADER_BUMP 2
#define SHADER_USER_COLOR 3
#define SHADER_LIGHTMAP 4
#define SHADER_SPECULAR 5
#define SHADER_WATER 6
#define SHADER_PER_PIXEL_LIGHTING 7
#define SHADER_PER_PIXEL_LIGHTING_NO_SPEC 8
#define NEL_BITMAP_TEXTURE_CLASS_ID_A 0x5a8003f9
#define NEL_BITMAP_TEXTURE_CLASS_ID_B 0x43e0955
/** Test wether the given max material is a water material. A water object should only have one material, and must have planar, convex geometry.
* Morevover, the mapping should only have scale and offsets, no rotation
*/
bool CExportNel::hasWaterMaterial(INode& node, TimeValue time)
{
// Get primary material pointer of the node
Mtl* pNodeMat = node.GetMtl();
// If NULL, no material at all at this node
if (pNodeMat == NULL) return false;
if (pNodeMat->NumSubMtls() != 0) return 0; // subMaterials not supported for water
int bWater = 0; // false
CExportNel::getValueByNameUsingParamBlock2 (*pNodeMat, "bWater", (ParamType2)TYPE_BOOL, &bWater, time);
return bWater != 0;
}
///===================================================================================================
bool CExportNel::hasMaterialWithShaderForVP(INode &node, TimeValue time, NL3D::CMaterial::TShader &shader)
{
// Get primary material pointer of the node
Mtl* pNodeMat = node.GetMtl();
// If NULL, no material at all at this node
if (pNodeMat == NULL) return false;
return CExportNel::needVP(*pNodeMat, time, shader);
}
///===================================================================================================
bool CExportNel::needVP(Mtl &mat, TimeValue time, NL3D::CMaterial::TShader &shader)
{
if (mat.NumSubMtls() != 0) // look at sub materials
{
for (uint k = 0; k < (uint) mat.NumSubMtls(); ++k)
{
if (CExportNel::needVP(*(mat.GetSubMtl(k)), time, shader)) return true;
}
return false;
}
int shaderType = 0; // false
CExportNel::getValueByNameUsingParamBlock2 (mat, "iShaderType", (ParamType2)TYPE_INT, &shaderType, time);
switch (shaderType)
{
case 7: // per pixel lighting (shader 7) need a specific VP
shader = CMaterial::PerPixelLighting;
return true;
break;
case 8: // per pixel lighting, no specular
shader = CMaterial::PerPixelLightingNoSpec;
return true;
break;
default:
return false;
break;
}
}
///===================================================================================================
/// Build a per-pixel vertex program
static NL3D::CMeshVPPerPixelLight *BuildPerPixelLightingVP(NL3D::CMesh::CMeshBuild *mb, bool wantSpecular)
{
// We need at least one texture set to be able to build the tangent space information.
// In this version, we support only one texture coordinate for the input. If there are more the result is undefined.
NL3D::CMesh::CMeshBuild otherMb;
if (NL3D::BuildTangentSpace(otherMb, *mb)) // build succesful ?
{
*mb = otherMb;
CMeshVPPerPixelLight *vp = new CMeshVPPerPixelLight;
vp->SpecularLighting = wantSpecular;
return vp;
}
else
{
return NULL;
}
return NULL;
}
///===================================================================================================
IMeshVertexProgram *CExportNel::buildMeshMaterialShaderVP(NL3D::CMaterial::TShader shader, NL3D::CMesh::CMeshBuild *mb)
{
nlassert(shader < CMaterial::shaderCount);
switch (shader)
{
case CMaterial::PerPixelLighting:
return BuildPerPixelLightingVP(mb, true /* with specular */);
break;
case CMaterial::PerPixelLightingNoSpec:
return BuildPerPixelLightingVP(mb, false /* no spec */);
break;
default: return NULL; // no need for a vp
}
}
// Build an array of NeL material corresponding with max material at this node. Return the number of material exported.
// Fill an array to remap the 3ds vertexMap channels for each materials. maxBaseBuild.RemapChannel.size() must be == to materials.size().
// maxBaseBuild.RemapChannel[mat].size() is the final count of NeL vertexMap channels used for the material nb mat.
// For each NeL channel of a material, copy the 3ds channel maxBaseBuild.RemapChannel[nelChannel]._IndexInMaxMaterial using the transformation matrix
// maxBaseBuild.RemapChannel[nelChannel]._UVMatrix.
// maxBaseBuild.NeedVertexColor will be true if at least one material need vertex color. Forced to true if lightmaps are used.
// maxBaseBuild.AlphaVertex[mat] will be true if the material use per vertex alpha.
// maxBaseBuild.AlphaVertexChannel[mat] will be the channel to use to get the alpha if the material use per vertex alpha.
// This method append the node material to the vector passed.
void CExportNel::buildMaterials (std::vector<NL3D::CMaterial>& materials, CMaxMeshBaseBuild& maxBaseBuild, INode& node,
TimeValue time)
{
// Material count
maxBaseBuild.FirstMaterial=materials.size();
int nMaterialCount=0;
// Get primary material pointer of the node
Mtl* pNodeMat=node.GetMtl();
// If NULL, no material at all at this node
if (pNodeMat!=NULL)
{
// Number of sub material at in this material
nMaterialCount=pNodeMat->NumSubMtls();
// If it is a multisub object, export all its sub materials
if (nMaterialCount>0)
{
// Resize the destination array
materials.resize (materials.size()+nMaterialCount);
// Resize the vertMap remap table
maxBaseBuild.MaterialInfo.resize (nMaterialCount);
// Export all the sub materials
for (int nSub=0; nSub<nMaterialCount; nSub++)
{
// Get a pointer on the sub material
Mtl* pSub=pNodeMat->GetSubMtl(nSub);
// Should not be NULL
nlassert (pSub);
// Export it
buildAMaterial (materials[maxBaseBuild.FirstMaterial+nSub], maxBaseBuild.MaterialInfo[nSub], *pSub, time);
// Need vertex color ?
maxBaseBuild.NeedVertexColor |= maxBaseBuild.MaterialInfo[nSub].AlphaVertex | maxBaseBuild.MaterialInfo[nSub].ColorVertex;
}
}
// Else export only this material, so, count is 1
else
{
// Only one material
nMaterialCount=1;
// Resize the destination array
materials.resize (materials.size()+1);
// Resize the vertMap remap table
maxBaseBuild.MaterialInfo.resize (1);
// Export the main material
buildAMaterial (materials[maxBaseBuild.FirstMaterial], maxBaseBuild.MaterialInfo[0], *pNodeMat, time);
// Need vertex color ?
maxBaseBuild.NeedVertexColor |= maxBaseBuild.MaterialInfo[0].AlphaVertex | maxBaseBuild.MaterialInfo[0].ColorVertex;
}
}
// Normalize UVRouting
uint i;
for (i=0; i<maxBaseBuild.MaterialInfo.size (); i++)
{
uint j;
for (j=0; j<MAX_MAX_TEXTURE; j++)
{
uint8 routing = maxBaseBuild.MaterialInfo[i].UVRouting[j];
if (maxBaseBuild.UVRouting[j] == 0xff)
{
maxBaseBuild.UVRouting[j] = routing;
}
else
{
if (routing != 0xff )
{
if (routing != maxBaseBuild.UVRouting[j])
{
// Active the channel because someone need it
maxBaseBuild.UVRouting[j] = j;
}
}
}
}
}
// If no material exported
if (nMaterialCount==0)
{
// Insert at least a material
materials.resize (materials.size()+1);
nMaterialCount=1;
// Resize the vertMap remap table
maxBaseBuild.MaterialInfo.resize (1);
// Init the first material
materials[maxBaseBuild.FirstMaterial].initLighted();
// Default mat
materials[maxBaseBuild.FirstMaterial].setLighting(true, CRGBA::Black, CRGBA::White, CRGBA::White, CRGBA::Black);
// Export the main material
maxBaseBuild.MaterialInfo[0].MaterialName = "Default";
}
// Return the count of material
maxBaseBuild.NumMaterials=nMaterialCount;
}
// Build a NeL material corresponding with a max material.
void CExportNel::buildAMaterial (NL3D::CMaterial& material, CMaxMaterialInfo& materialInfo, Mtl& mtl, TimeValue time)
{
// It is a NeL material ?
if (isClassIdCompatible (mtl, Class_ID(NEL_MTL_A,NEL_MTL_B)))
{
// Get the shader value now
int iShaderType = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "iShaderType", (ParamType2)TYPE_INT, &iShaderType, time);
// Carefule with options
if ((iShaderType == SHADER_LIGHTMAP) && (!_Options.bExportLighting))
iShaderType = SHADER_NORMAL;
// Water or lightmap ??
bool isWaterOrLightmap= iShaderType==SHADER_WATER || iShaderType==SHADER_LIGHTMAP;
bool isLightmap= iShaderType==SHADER_LIGHTMAP;
// *** Init lighted or unlighted ?
// Get unlighted flag
int bUnlighted = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bUnlighted", (ParamType2)TYPE_BOOL, &bUnlighted, 0);
// force unlighted in case of lightmap.
if(isLightmap)
bUnlighted= 1;
// Init the material
if( bUnlighted )
material.initUnlit ();
else
material.initLighted ();
// *** Choose a shader
switch (iShaderType)
{
case SHADER_NORMAL:
case SHADER_BUMP:
case SHADER_USER_COLOR:
case SHADER_LIGHTMAP:
case SHADER_SPECULAR:
case SHADER_PER_PIXEL_LIGHTING:
case SHADER_PER_PIXEL_LIGHTING_NO_SPEC:
material.setShader ((CMaterial::TShader)(iShaderType-1));
break;
case SHADER_WATER:
material.setShader (CMaterial::Normal);
break;
default:
nlassert(0);
break;
}
// Stain glass window flag
int bStainGlass = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bStainedGlassWindow", (ParamType2)TYPE_BOOL, &bStainGlass, time);
material.setStainedGlassWindow (bStainGlass!=0);
// *** Alpha
// Alpha blend ?
int bAlphaBlend = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bAlphaBlend", (ParamType2)TYPE_BOOL, &bAlphaBlend, time);
// Set the blend
material.setBlend (bAlphaBlend!=0);
// Blend function
int blendFunc = 1;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "iBlendSrcFunc", (ParamType2)TYPE_INT, &blendFunc, time);
material.setSrcBlend ((CMaterial::TBlend)(blendFunc-1));
CExportNel::getValueByNameUsingParamBlock2 (mtl, "iBlendDestFunc", (ParamType2)TYPE_INT, &blendFunc, time);
material.setDstBlend ((CMaterial::TBlend)(blendFunc-1));
// if water or lightMap, force std blend.
if(isWaterOrLightmap)
material.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
// Set the alpha test flag
int bAlphaTest = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bAlphaTest", (ParamType2)TYPE_BOOL, &bAlphaTest, time);
material.setAlphaTest (bAlphaTest != 0);
// Vertex alpha
int bAlphaVertex = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bAlphaVertex", (ParamType2)TYPE_BOOL, &bAlphaVertex, time);
// if water or lightMap, disable alphaVertex
if(isWaterOrLightmap)
bAlphaVertex= 0;
// Active vertex alpha if in alpha test or alpha blend mode
materialInfo.AlphaVertex = (bAlphaBlend || bAlphaTest) && (bAlphaVertex != 0);
// Get channel to use for alpha vertex
materialInfo.AlphaVertexChannel = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "iAlphaVertexChannel", (ParamType2)TYPE_INT, &materialInfo.AlphaVertexChannel, time);
// *** Zbuffer
// ZBias
float zBias = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "fZBias", (ParamType2)TYPE_FLOAT, &zBias, time);
material.setZBias ( zBias );
// Alpha blend ?
if (bAlphaBlend)
{
// Force z write ?
int bForceZWrite = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bForceZWrite", (ParamType2)TYPE_BOOL, &bForceZWrite, time);
material.setZWrite( bForceZWrite != 0 );
}
else
{
// Force no z write ?
int bForceNoZWrite = 0; // false
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bForceNoZWrite", (ParamType2)TYPE_BOOL, &bForceNoZWrite, time);
material.setZWrite( bForceNoZWrite == 0 );
}
// *** Colors
// * Vertex color ?
int bColorVertex = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bColorVertex", (ParamType2)TYPE_BOOL, &bColorVertex, time);
material.setLightedVertexColor (material.isLighted() && (bColorVertex != 0));
// Ok, color vertex
materialInfo.ColorVertex = bColorVertex != 0;
// * Diffuse
// Get from max
Point3 maxDiffuse;
CRGBA nelDiffuse;
CExportNel::getValueByNameUsingParamBlock2(mtl, "cDiffuse", (ParamType2)TYPE_RGBA, &maxDiffuse, time)
|| CExportNel::getValueByNameUsingParamBlock2(mtl, "diffuse", (ParamType2)TYPE_RGBA, &maxDiffuse, time);
// Convert to NeL color
convertColor (nelDiffuse, maxDiffuse);
// Set the opacity
float fOp = 0.0f;
CExportNel::getValueByNameUsingParamBlock2(mtl, "pOpacity", (ParamType2)TYPE_PCNT_FRAC, &fOp, time)
|| CExportNel::getValueByNameUsingParamBlock2(mtl, "opacity", (ParamType2)TYPE_PCNT_FRAC, &fOp, time);
// Add alpha to the value
float fA=(fOp*255.f+0.5f);
clamp (fA, 0.f, 255.f);
nelDiffuse.A=(uint8)fA;
// Set le NeL diffuse color material
if (bUnlighted)
{
material.setColor (nelDiffuse);
// For the lightmap
material.setDiffuse (nelDiffuse);
}
else
{
material.setDiffuse (nelDiffuse);
material.setOpacity (nelDiffuse.A);
}
// * Self illum color
CRGBA nelEmissive;
int bSelfIllumColorOn;
Point3 maxSelfIllum;
float fTemp;
CExportNel::getValueByNameUsingParamBlock2(mtl, "bUseSelfIllumColor", (ParamType2)TYPE_BOOL, &bSelfIllumColorOn, time)
|| CExportNel::getValueByNameUsingParamBlock2(mtl, "useSelfIllumColor", (ParamType2)TYPE_BOOL, &bSelfIllumColorOn, time);
if( bSelfIllumColorOn )
{
CExportNel::getValueByNameUsingParamBlock2(mtl, "cSelfIllumColor", (ParamType2)TYPE_RGBA, &maxSelfIllum, time)
|| CExportNel::getValueByNameUsingParamBlock2(mtl, "selfIllumColor", (ParamType2)TYPE_RGBA, &maxSelfIllum, time);
}
else
{
CExportNel::getValueByNameUsingParamBlock2(mtl, "pSelfIllumAmount", (ParamType2)TYPE_PCNT_FRAC, &fTemp, time)
|| CExportNel::getValueByNameUsingParamBlock2(mtl, "selfIllumAmount", (ParamType2)TYPE_PCNT_FRAC, &fTemp, time);
maxSelfIllum = maxDiffuse * fTemp;
}
convertColor( nelEmissive, maxSelfIllum );
material.setEmissive (nelEmissive);
// * Ambient
CRGBA nelAmbient;
Point3 maxAmbient;
CExportNel::getValueByNameUsingParamBlock2(mtl, "cAmbient", (ParamType2)TYPE_RGBA, &maxAmbient, time)
|| CExportNel::getValueByNameUsingParamBlock2(mtl, "ambient", (ParamType2)TYPE_RGBA, &maxAmbient, time);
convertColor (nelAmbient, maxAmbient);
material.setAmbient (nelAmbient);
// * Specular
CRGBA nelSpecular;
Point3 maxSpecular;
CExportNel::getValueByNameUsingParamBlock2(mtl, "cSpecular", (ParamType2)TYPE_RGBA, &maxSpecular, time)
|| CExportNel::getValueByNameUsingParamBlock2(mtl, "specular", (ParamType2)TYPE_RGBA, &maxSpecular, time);
convertColor (nelSpecular, maxSpecular);
// Get specular level
float shininess;
CExportNel::getValueByNameUsingParamBlock2(mtl, "pSpecularLevel", (ParamType2)TYPE_PCNT_FRAC, &shininess, time)
|| CExportNel::getValueByNameUsingParamBlock2(mtl, "specularLevel", (ParamType2)TYPE_PCNT_FRAC, &shininess, time);
clamp(shininess, 0.f, 1.f);
CRGBAF fColor = nelSpecular;
fColor *= shininess;
nelSpecular = fColor;
material.setSpecular (nelSpecular);
// * Get specular shininess
CExportNel::getValueByNameUsingParamBlock2 (mtl, "pGlossiness", (ParamType2)TYPE_PCNT_FRAC, &shininess, time)
|| CExportNel::getValueByNameUsingParamBlock2 (mtl, "glossiness", (ParamType2)TYPE_PCNT_FRAC, &shininess, time);
shininess=(float)pow(2.0, shininess * 10.0) * 4.f;
material.setShininess (shininess);
// * Usercolor
if (iShaderType == SHADER_USER_COLOR)
{
CRGBA nelUserColor;
Point3 maxUserColor;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "cUserColor", (ParamType2)TYPE_RGBA, &maxUserColor, time);
convertColor (nelUserColor, maxUserColor);
material.setUserColor (nelUserColor);
}
// * Double sided flag
int bDoubleSided;
CExportNel::getValueByNameUsingParamBlock2(mtl, "bTwoSided", (ParamType2)TYPE_BOOL, &bDoubleSided, time)
|| CExportNel::getValueByNameUsingParamBlock2(mtl, "twoSided", (ParamType2)TYPE_BOOL, &bDoubleSided, time);
material.setDoubleSided ( bDoubleSided!=0 );
// *** Textures
/// test wether texture matrix animation should be exported
int bExportTexMatAnim = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bExportTextureMatrix", (ParamType2)TYPE_BOOL, &bExportTexMatAnim, 0);
materialInfo.TextureMatrixEnabled = (bExportTexMatAnim != 0);
// Reset info
materialInfo.RemapChannel.clear ();
// For each textures
uint i;
for (i=0; i<IDRV_MAT_MAXTEXTURES; i++)
{
// Lightmap, only one texture
if ((iShaderType==SHADER_USER_COLOR) && (i>0)) break;
if ((iShaderType==SHADER_LIGHTMAP) && (i>0)) break;
if ((iShaderType==SHADER_SPECULAR) && (i>1)) break;
// Get the enable flag name
char enableSlotName[100];
smprintf (enableSlotName, 100, "bEnableSlot_%d", i+1);
// Get the enable flag
int bEnableSlot = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, enableSlotName, (ParamType2)TYPE_BOOL, &bEnableSlot, time);
if (bEnableSlot)
{
// Get the texture arg name
char textureName[100];
smprintf (textureName, 100, "tTexture_%d", i+1);
// Get the texture pointer
Texmap *pTexmap = NULL;
CExportNel::getValueByNameUsingParamBlock2 (mtl, textureName, (ParamType2)TYPE_TEXMAP, &pTexmap, time);
if (pTexmap)
{
// Pointer on the diffuse texture
static ITexture* pTexture=NULL;
// Ok export the texture in NeL format
CMaterialDesc materialDesc;
pTexture=buildATexture (*pTexmap, materialDesc, time, (i==1) && (iShaderType==SHADER_SPECULAR) );
// Get the gen texture coord flag
char texGenName[100];
smprintf (texGenName, 100, "bTexGen_%d", i+1);
int bTexGen = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, texGenName, (ParamType2)TYPE_BOOL, &bTexGen, time);
// If specular shader, set uv channel to reflexion
if ( ((i==1) && (iShaderType==SHADER_SPECULAR)) || bTexGen )
{
materialDesc._IndexInMaxMaterial = UVGEN_REFLEXION;
}
materialInfo.RemapChannel.push_back (materialDesc);
// Add flags if mapping coodinates are used..
if (materialDesc._IndexInMaxMaterial>=0)
{
uint j;
for (j=0; j<i; j++)
{
// Same UV channel ?
if (materialInfo.RemapChannel[j]._IndexInMaxMaterial == materialDesc._IndexInMaxMaterial)
break;
}
// Channel routing
materialInfo.UVRouting[i] = (j == i) ? i : j;
}
// Add the texture if it exist
material.setTexture (i, pTexture);
// Envmap gen ?
material.setTexCoordGen (i, materialDesc._IndexInMaxMaterial<0);
/// texture matrix animation ?
if (bExportTexMatAnim != 0)
{
/// and activate flag
material.enableUserTexMat(i);
/// setup the uv matrix
CMatrix uvMat;
CExportNel::uvMatrix2NelUVMatrix(materialDesc.getUVMatrix(), uvMat);
material.setUserTexMat(i, uvMat);
}
}
}
}
// Export mapping channel 2 if lightmap asked.
if ( iShaderType==SHADER_LIGHTMAP ) // lightmap enabled ?
{
// Get the lightmap UV channel
int iLightMapChannel = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "iLightMapChannel", (ParamType2)TYPE_INT, &iLightMapChannel, time);
// Resize it
uint size = materialInfo.RemapChannel.size();
materialInfo.RemapChannel.resize( size + 1 );
// Copy information from channel 0
if (materialInfo.RemapChannel.size () > 1)
materialInfo.RemapChannel[size] = materialInfo.RemapChannel[0];
// Source lightmap mapping channel
materialInfo.RemapChannel[size]._IndexInMaxMaterial = iLightMapChannel;
// Backup old mapping channel
materialInfo.RemapChannel[size]._IndexInMaxMaterialAlternative = materialInfo.RemapChannel[0]._IndexInMaxMaterial;
}
// For each slot
uint stage;
for (stage=0; stage<std::min ((uint)MAT_SLOTS, (uint)IDRV_MAT_MAXTEXTURES); stage++)
{
// Make a post fixe
char postfixC[10];
smprintf (postfixC, 10, "_%d", stage+1);
string postfix = postfixC;
// Shader normal ?
if (iShaderType==SHADER_NORMAL)
{
// RGB, get the values
int opRGB = 0;
int opRGBBlend = 0;
int opRGBArg0 = 0;
int opRGBArg1 = 0;
int opRGBArg2 = 0;
int opRGBArg0Operand = 0;
int opRGBArg1Operand = 0;
int opRGBArg2Operand = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iRgbOperation"+postfix).c_str(), (ParamType2)TYPE_INT, &opRGB, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iRgbBlendSource"+postfix).c_str(), (ParamType2)TYPE_INT, &opRGBBlend, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iRgbArg0"+postfix).c_str(), (ParamType2)TYPE_INT, &opRGBArg0, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iRgbArg1"+postfix).c_str(), (ParamType2)TYPE_INT, &opRGBArg1, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iRgbArg2"+postfix).c_str(), (ParamType2)TYPE_INT, &opRGBArg2, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iRgbArg0Operand"+postfix).c_str(), (ParamType2)TYPE_INT, &opRGBArg0Operand, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iRgbArg1Operand"+postfix).c_str(), (ParamType2)TYPE_INT, &opRGBArg1Operand, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iRgbArg2Operand"+postfix).c_str(), (ParamType2)TYPE_INT, &opRGBArg2Operand, time);
// Setup the value
if (opRGB<5)
material.texEnvOpRGB (stage, (CMaterial::TTexOperator)(opRGB-1));
else
{
if (opRGB == 6)
{
material.texEnvOpRGB (stage, CMaterial::Mad);
}
else
{
material.texEnvOpRGB (stage, (CMaterial::TTexOperator)(opRGBBlend+3));
}
}
material.texEnvArg0RGB (stage, (CMaterial::TTexSource)(opRGBArg0-1), (CMaterial::TTexOperand)(opRGBArg0Operand-1));
if (opRGBArg1 == 4)
{
material.texEnvArg1RGB (stage, CMaterial::Texture, (CMaterial::TTexOperand)(opRGBArg1Operand-1));
}
else
{
material.texEnvArg1RGB (stage, (CMaterial::TTexSource)(opRGBArg1), (CMaterial::TTexOperand)(opRGBArg1Operand-1));
}
if (opRGBArg2 == 4)
{
material.texEnvArg2RGB (stage, CMaterial::Texture, (CMaterial::TTexOperand)(opRGBArg2Operand-1));
}
else
{
material.texEnvArg2RGB (stage, (CMaterial::TTexSource)(opRGBArg2), (CMaterial::TTexOperand)(opRGBArg2Operand-1));
}
// Alpha, get the values
int opAlpha = 0;
int opAlphaBlend = 0;
int opAlphaArg0 = 0;
int opAlphaArg1 = 0;
int opAlphaArg2 = 0;
int opAlphaArg0Operand = 0;
int opAlphaArg1Operand = 0;
int opAlphaArg2Operand = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iAlphaOperation"+postfix).c_str(), (ParamType2)TYPE_INT, &opAlpha, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iAlphaBlendSource"+postfix).c_str(), (ParamType2)TYPE_INT, &opAlphaBlend, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iAlphaArg0"+postfix).c_str(), (ParamType2)TYPE_INT, &opAlphaArg0, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iAlphaArg1"+postfix).c_str(), (ParamType2)TYPE_INT, &opAlphaArg1, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iAlphaArg2"+postfix).c_str(), (ParamType2)TYPE_INT, &opAlphaArg2, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iAlphaArg0Operand"+postfix).c_str(), (ParamType2)TYPE_INT, &opAlphaArg0Operand, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iAlphaArg1Operand"+postfix).c_str(), (ParamType2)TYPE_INT, &opAlphaArg1Operand, time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iAlphaArg2Operand"+postfix).c_str(), (ParamType2)TYPE_INT, &opAlphaArg2Operand, time);
// Setup the value
if (opAlpha<5)
material.texEnvOpAlpha (stage, (CMaterial::TTexOperator)(opAlpha-1));
else
{
if (opAlpha == 6)
{
material.texEnvOpAlpha(stage, CMaterial::Mad);
}
else
{
material.texEnvOpAlpha (stage, (CMaterial::TTexOperator)(opAlphaBlend+3));
}
}
material.texEnvArg0Alpha (stage, (CMaterial::TTexSource)(opAlphaArg0-1), (CMaterial::TTexOperand)(opAlphaArg0Operand-1));
if (opAlphaArg1 == 4)
{
material.texEnvArg1Alpha (stage, CMaterial::Texture, (CMaterial::TTexOperand)(opAlphaArg1Operand-1));
}
else
{
material.texEnvArg1Alpha (stage, (CMaterial::TTexSource)(opAlphaArg1), (CMaterial::TTexOperand)(opAlphaArg1Operand-1));
}
if (opAlphaArg2 == 4)
{
material.texEnvArg2Alpha (stage, CMaterial::Texture, (CMaterial::TTexOperand)(opAlphaArg2Operand-1));
}
else
{
material.texEnvArg2Alpha (stage, (CMaterial::TTexSource)(opAlphaArg2), (CMaterial::TTexOperand)(opAlphaArg2Operand-1));
}
// Constant color
Point3 constantColor;
CRGBA nelConstantColor;
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("cConstant"+postfix).c_str(), (ParamType2)TYPE_RGBA, &constantColor, time);
// Convert to NeL color
convertColor (nelConstantColor, constantColor);
// Constant alpha
int constantAlpha = 255;
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iConstantAlpha"+postfix).c_str(), (ParamType2)TYPE_INT, &constantAlpha, time);
nelConstantColor.A = (uint8)constantAlpha;
// Setup the constant color
material.texConstantColor(stage, nelConstantColor);
// Texenv mode
int texEnvMode = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, ("iTextureShader"+postfix).c_str(), (ParamType2)TYPE_INT, &texEnvMode, time);
if (texEnvMode>1)
{
// Enable and setup it
material.enableTexAddrMode ();
material.setTexAddressingMode (stage, (CMaterial::TTexAddressingMode)(texEnvMode-2));
}
}
}
// Set material name
TSTR name=mtl.GetName();
materialInfo.MaterialName = (const char*)name;
}
else
{
// Not a nel material, try to get something near...
// Init the material lighted
material.initLighted ();
// *** ***************
// *** Export Textures
// *** ***************
/// TODO: Only one texture for the time. Add multitexture support, and shaders support.
// Look for a diffuse texmap
vector<bool> mapEnables;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "mapEnables", (ParamType2)TYPE_BOOL_TAB, &mapEnables, time, false);
Texmap *pDifTexmap = NULL;
Texmap *pOpaTexmap = NULL;
Texmap *pSpeTexmap = NULL;
if (mapEnables[ID_DI])
pDifTexmap = mtl.GetSubTexmap (ID_DI);
if (mapEnables[ID_OP])
pOpaTexmap = mtl.GetSubTexmap (ID_OP);
if (mapEnables[ID_SP])
pSpeTexmap = mtl.GetSubTexmap (ID_SP);
// Is there a lightmap handling wanted
int bLightMap = 0; // false
int bAlphaTest = 1; // true
int bForceZWrite = 0; // false
int bForceNoZWrite = 0; // false
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bForceZWrite", (ParamType2)TYPE_BOOL, &bForceZWrite, time, false);
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bForceNoZWrite", (ParamType2)TYPE_BOOL, &bForceNoZWrite, time, false);
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bAlphaTest", (ParamType2)TYPE_BOOL, &bAlphaTest, time, false);
if( pSpeTexmap != NULL )
{
material.setShader (CMaterial::Specular);
}
else
{
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bLightMap", (ParamType2)TYPE_BOOL, &bLightMap, time, false);
if (bLightMap)
{
material.setShader (CMaterial::LightMap);
}
else
{
material.setShader (CMaterial::Normal);
}
}
int bStainedGlassWindow = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bStainedGlassWindow", (ParamType2)TYPE_BOOL, &bStainedGlassWindow, time, false);
material.setStainedGlassWindow( bStainedGlassWindow!=0 );
material.setAlphaTest(false);
// By default set blend to false
material.setBlend (false);
// Diffuse texmap is present ?
if (pDifTexmap)
{
// Pointer on the diffuse texture
static ITexture* pTexture=NULL;
// Is it a simple file ?
if (isClassIdCompatible(*pDifTexmap, Class_ID (BMTEX_CLASS_ID, 0))
|| isClassIdCompatible(*pDifTexmap, Class_ID (NEL_BITMAP_TEXTURE_CLASS_ID_A, NEL_BITMAP_TEXTURE_CLASS_ID_B))
)
{
// List of channels used by this texture
CMaterialDesc _3dsTexChannel;
// Ok export the texture in NeL format
pTexture=buildATexture (*pDifTexmap, _3dsTexChannel, time);
// For this shader, only need a texture channel.
materialInfo.RemapChannel.resize (1);
// Need an explicit channel, not generated
if ( _3dsTexChannel._IndexInMaxMaterial < 0 )
{
materialInfo.RemapChannel[0]._IndexInMaxMaterial=UVGEN_MISSING;
materialInfo.RemapChannel[0]._UVMatrix.IdentityMatrix();
}
// Else copy it
else
materialInfo.RemapChannel[0]=_3dsTexChannel;
// Add the texture if it exist
material.setTexture(0, pTexture);
// Active blend if texture in opacity
if( pOpaTexmap!=NULL )
{
if( bAlphaTest )
{ // If Alpha Test enabled no blend required just check if we are forced to NOT write in the ZBuffer
material.setAlphaTest(true);
if( bForceNoZWrite )
material.setZWrite( false );
else
material.setZWrite( true );
}
else
{ // No Alpha Test so we have to blend and check if we are forced to write in the ZBuffer
material.setBlend( true );
if( bForceZWrite )
material.setZWrite( true );
else
material.setZWrite( false );
}
}
// Add flags if mapping coodinates are used..
if (_3dsTexChannel._IndexInMaxMaterial>=0)
{
// Channel routing
materialInfo.UVRouting[0] = 0;
}
// Export mapping channel 2 if lightmap asked.
if ( bLightMap ) // lightmap enabled ?
{
materialInfo.RemapChannel.resize( 2 );
// Copy information from channel 0
materialInfo.RemapChannel[1] = materialInfo.RemapChannel[0];
materialInfo.RemapChannel[1]._IndexInMaxMaterial = 2;
materialInfo.RemapChannel[1]._IndexInMaxMaterialAlternative = materialInfo.RemapChannel[0]._IndexInMaxMaterial;
// Add flags if mapping coodinates are used..
materialInfo.UVRouting[1] |= 1;
}
}
}
if (pSpeTexmap)
{
// Pointer to the specular reflection texture
CTextureCube* pTextureCube = NULL;
if (isClassIdCompatible(*pSpeTexmap, Class_ID(ACUBIC_CLASS_ID, 0)))
{
pTextureCube = buildTextureCubeFromReflectRefract(*pSpeTexmap, time);
}
else if (isClassIdCompatible(*pSpeTexmap, Class_ID(COMPOSITE_CLASS_ID, 0)))
{
pTextureCube = buildTextureCubeFromComposite(*pSpeTexmap, time);
}
else if (isClassIdCompatible(*pSpeTexmap, Class_ID(BMTEX_CLASS_ID, 0)))
{
pTextureCube = buildTextureCubeFromTexture(*pSpeTexmap, time);
}
// Add the texture if it exist
material.setTexture(1, pTextureCube);
}
// Blend mode
int opacityType = 0; // 0-filter 1-substractive 2-additive
CExportNel::getValueByNameUsingParamBlock2 (mtl, "opacityType", (ParamType2)TYPE_INT, &opacityType, time, false);
if( opacityType == 0 ) // Filter
material.setBlendFunc (CMaterial::srcalpha, CMaterial::invsrcalpha);
else
material.setBlendFunc (CMaterial::srcalpha, CMaterial::one);
// Z function by default. TODO.
material.setZFunc (CMaterial::lessequal);
// Z bias by default. TODO.
material.setZBias (0.f);
// Is the mtl a std material ?
// The class Id can be the StdMat one, or StdMat2
// It can be the superClassId if the mtl is derived from StdMat or StdMat2.
if (
isClassIdCompatible (mtl, Class_ID(DMTL_CLASS_ID, 0)) ||
isClassIdCompatible (mtl, Class_ID(DMTL2_CLASS_ID, 0))
)
{
// Get a pointer on a stdmat
//StdMat2* stdmat=(StdMat2*)&mtl;
// *****************************************
// *** Colors, self illumination and opacity
// *****************************************
// Get the diffuse color of the max material
//Color color=stdmat->GetDiffuse (time);
Point3 maxDiffuse;
CRGBA nelDiffuse;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "diffuse", (ParamType2)TYPE_RGBA, &maxDiffuse, time, false);
// Convert to NeL color
convertColor (nelDiffuse, maxDiffuse);
// Get the opacity value from the material
// float fOp=stdmat->GetOpacity (time);
float fOp = 0.0f;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "opacity", (ParamType2)TYPE_PCNT_FRAC, &fOp, time, false);
// Add alpha to the value
float fA=(fOp*255.f+0.5f);
clamp (fA, 0.f, 255.f);
nelDiffuse.A=(uint8)fA;
// Set le NeL diffuse color material
material.setColor (nelDiffuse);
// Set the blend mode on if opacity is not 1.f
if( fOp < 0.99f )
{
if( bAlphaTest )
{ // If Alpha Test enabled no blend required just check if we are forced to NOT write in the ZBuffer
material.setAlphaTest(true);
if( bForceNoZWrite )
material.setZWrite( false );
else
material.setZWrite( true );
}
else
{ // No Alpha Test so we have to blend and check if we are forced to write in the ZBuffer
material.setBlend( true );
if( bForceZWrite )
material.setZWrite( true );
else
material.setZWrite( false );
}
}
// Get colors of 3dsmax material
CRGBA nelEmissive;
CRGBA nelAmbient;
CRGBA nelSpecular;
//if (stdmat->GetSelfIllumColorOn())
// convertColor (emissiveColor, stdmat->GetSelfIllumColor (time));
//else
// convertColor (emissiveColor, stdmat->GetDiffuse (time)*stdmat->GetSelfIllum (time));
int bSelfIllumColorOn;
Point3 maxSelfIllum;
float fTemp;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "useSelfIllumColor", (ParamType2)TYPE_BOOL, &bSelfIllumColorOn, time, false);
if( bSelfIllumColorOn )
{
CExportNel::getValueByNameUsingParamBlock2 (mtl, "selfIllumColor", (ParamType2)TYPE_RGBA, &maxSelfIllum, time, false);
}
else
{
CExportNel::getValueByNameUsingParamBlock2 (mtl, "selfIllumAmount", (ParamType2)TYPE_PCNT_FRAC, &fTemp, time, false);
maxSelfIllum = maxDiffuse * fTemp;
}
convertColor( nelEmissive, maxSelfIllum );
Point3 maxAmbient;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "ambient", (ParamType2)TYPE_RGBA, &maxAmbient, time, false);
convertColor (nelAmbient, maxAmbient);
Point3 maxSpecular;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "specular", (ParamType2)TYPE_RGBA, &maxSpecular, time, false);
convertColor (nelSpecular, maxSpecular);
// Specular level
float shininess; //=stdmat->GetShinStr(time);
CExportNel::getValueByNameUsingParamBlock2 (mtl, "specularLevel", (ParamType2)TYPE_PCNT_FRAC, &shininess, time, false);
CRGBAF fColor = nelSpecular;
fColor *= shininess;
nelSpecular = fColor;
// Shininess
CExportNel::getValueByNameUsingParamBlock2 (mtl, "glossiness", (ParamType2)TYPE_PCNT_FRAC, &shininess, time, false);
//shininess=stdmat->GetShader()->GetGlossiness(time);
shininess=(float)pow(2.0, shininess * 10.0) * 4.f;
// Light parameters
material.setLighting (true, nelEmissive, nelAmbient, nelDiffuse, nelSpecular, shininess);
// Double sided
int bDoubleSided;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "twoSided", (ParamType2)TYPE_BOOL, &bDoubleSided, time, false);
//material.setDoubleSided (stdmat->GetTwoSided()!=FALSE);
material.setDoubleSided ( bDoubleSided!=0 );
}
if( ! bLightMap )
{
int bUnlighted = 0; // false
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bUnlighted", (ParamType2)TYPE_BOOL, &bUnlighted, 0, false);
if( bUnlighted )
{
material.setLighting( false );
}
}
// Use alpha vertex ?
int bAlphaVertex = 0; // false
// Get the scripted value
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bAlphaVertex", (ParamType2)TYPE_BOOL, &bAlphaVertex, time, false);
// Find ?
if ( bAlphaVertex )
{
// Ok, alpha vertex
materialInfo.AlphaVertex = true;
if( bAlphaTest )
{
// If Alpha Test enabled no blend required just check if we are forced to NOT write in the ZBuffer
material.setAlphaTest(true);
if( bForceNoZWrite )
material.setZWrite( false );
else
material.setZWrite( true );
}
else
{ // No Alpha Test so we have to blend and check if we are forced to write in the ZBuffer
material.setBlend( true );
if( bForceZWrite )
material.setZWrite( true );
else
material.setZWrite( false );
}
// Get the channel for alpha vertex
materialInfo.AlphaVertexChannel = 0;
CExportNel::getValueByNameUsingParamBlock2 (mtl, "iAlphaVertexChannel", (ParamType2)TYPE_INT, &materialInfo.AlphaVertexChannel, time, false);
}
// Use color vertex ?
int bColorVertex = 0; // false
// Get the scripted value
CExportNel::getValueByNameUsingParamBlock2 (mtl, "bColorVertex", (ParamType2)TYPE_BOOL, &bColorVertex, time, false);
// Find ?
if ( bColorVertex )
{
// Ok, color vertex
materialInfo.ColorVertex = true;
// Active vertex color in lighted mode
material.setLightedVertexColor (material.isLighted());
}
// Set material name
TSTR name=mtl.GetName();
materialInfo.MaterialName = (const char*)name;
}
}
// Get 3ds channels uv used by a texmap and make a good index channel
int CExportNel::getVertMapChannel (Texmap& texmap, Matrix3& channelMatrix, TimeValue time)
{
// *** Get the channel matrix
// Set to identity because deafult implementation of texmapGetUVTransform make nothing
channelMatrix.IdentityMatrix();
// Get UV channel matrix
texmap.GetUVTransform(channelMatrix);
// Return the map channel
return texmap.GetMapChannel();
}
// get the absolute or relative path from a texture filename
static std::string ConvertTexFileName(const char *src, bool _AbsolutePath)
{
// File name, maxlen 256 under windows
char sFileName[512];
strcpy (sFileName, src);
// Let absolute path ?
if (!_AbsolutePath)
{
// Decompose bitmap file name
char sName[256];
char sExt[256];
_splitpath (sFileName, NULL, NULL, sName, sExt);
// Make the final path
_makepath (sFileName, NULL, NULL, sName, sExt);
}
return std::string(sFileName);
}
// Build a NeL texture corresponding with a max Texmap.
// Fill an array with the 3ds vertexMap used by this texture.
// Texture file uses only 1 channel.
ITexture* CExportNel::buildATexture (Texmap& texmap, CMaterialDesc &remap3dsTexChannel, TimeValue time, bool forceCubic)
{
/// TODO: support other texmap than Bitmap
// By default, not build
ITexture* pTexture=NULL;
// Is it a bitmap texture file ?
if (isClassIdCompatible(texmap, Class_ID (BMTEX_CLASS_ID,0))
|| isClassIdCompatible(texmap, Class_ID(NEL_BITMAP_TEXTURE_CLASS_ID_A, NEL_BITMAP_TEXTURE_CLASS_ID_B))
)
{
// Cast the pointer
BitmapTex* pBitmap=(BitmapTex*)&texmap;
// Get the apply crop value
int bApply;
bool bRes=getValueByNameUsingParamBlock2 (texmap, BMTEX_CROP_APPLY, (ParamType2)TYPE_BOOL, &bApply, time);
nlassert (bRes);
// If a crop is applyed
if (bApply)
{
// Get the crop value U
bRes=getValueByNameUsingParamBlock2 (texmap, BMTEX_CROP_U_NAME, (ParamType2)TYPE_FLOAT, &(remap3dsTexChannel._CropU), time);
nlassert (bRes);
// Get the crop value V
bRes=getValueByNameUsingParamBlock2 (texmap, BMTEX_CROP_V_NAME, (ParamType2)TYPE_FLOAT, &(remap3dsTexChannel._CropV), time);
nlassert (bRes);
// Get the crop value W
bRes=getValueByNameUsingParamBlock2 (texmap, BMTEX_CROP_W_NAME, (ParamType2)TYPE_FLOAT, &(remap3dsTexChannel._CropW), time);
nlassert (bRes);
// Get the crop value H
bRes=getValueByNameUsingParamBlock2 (texmap, BMTEX_CROP_H_NAME, (ParamType2)TYPE_FLOAT, &(remap3dsTexChannel._CropH), time);
nlassert (bRes);
}
// 1) build a texture that can either be a file texture or a multifile texture
ITexture *srcTex;
const uint numNelTextureSlots = 8;
static const char *fileNamesTab[] = { "bitmap1FileName",
"bitmap2FileName",
"bitmap3FileName",
"bitmap4FileName",
"bitmap5FileName",
"bitmap6FileName",
"bitmap7FileName",
"bitmap8FileName"
};
if (isClassIdCompatible(texmap, Class_ID(NEL_BITMAP_TEXTURE_CLASS_ID_A, NEL_BITMAP_TEXTURE_CLASS_ID_B))) // is it a set of textures ?
{
uint k;
std::string fileName[numNelTextureSlots];
for (k = 0; k < numNelTextureSlots; ++k) // copy each texture of the set
{
nlassert(k < sizeof(fileNamesTab) / sizeof(const char *));
/// get the file name from the parameter block
bRes=getValueByNameUsingParamBlock2 (texmap, fileNamesTab[k], (ParamType2)TYPE_STRING, &fileName[k], time);
nlassert (bRes);
}
uint numUsedSlots = 0;
uint l;
for (l = 0; l < numNelTextureSlots; ++l)
{
if (!fileName[l].empty()) numUsedSlots = l + 1;
}
// if only the first slot is used we create a CTextureFile...
if (l == 1 && !fileName[0].empty())
{
srcTex = new CTextureFile;
static_cast<CTextureFile *>(srcTex)->setFileName (ConvertTexFileName(fileName[0].c_str(), _AbsolutePath));
}
else
{
srcTex = new CTextureMultiFile(numUsedSlots);
for (k = 0; k < numUsedSlots; ++k) // copy each texture of the set
{
if (!fileName[k].empty())
{
/// set the name of the texture after converting it
static_cast<CTextureMultiFile *>(srcTex)->setFileName(k, ConvertTexFileName(fileName[k].c_str(), _AbsolutePath).c_str());
}
}
}
}
else // standard texture
{
srcTex = new CTextureFile;
static_cast<CTextureFile *>(srcTex)->setFileName (ConvertTexFileName(pBitmap->GetMapName(), _AbsolutePath));
}
// 2) Use this texture 'as it', or duplicate it to create the faces of a cube map
// Force cubic
if (forceCubic)
{
// Cube side
const static CTextureCube::TFace tfNewOrder[6] = { CTextureCube::positive_z, CTextureCube::negative_z,
CTextureCube::negative_x, CTextureCube::positive_x,
CTextureCube::positive_y, CTextureCube::negative_y };
// Alloc a cube texture
CTextureCube* pTextureCube = new CTextureCube;
for (uint side=0; side<6; side++)
{
// Set a copy of the source texture in the cube
if (dynamic_cast<CTextureMultiFile *>(srcTex))
{
pTextureCube->setTexture (tfNewOrder[side], new CTextureMultiFile(*static_cast<CTextureMultiFile *>(srcTex)));
}
else
{
pTextureCube->setTexture (tfNewOrder[side], new CTextureFile(*static_cast<CTextureFile *>(srcTex)));
}
}
// Ok, good texture
pTexture=pTextureCube;
delete srcTex;
srcTex = NULL;
}
else
{
/// just use the source texture
pTexture = srcTex;
}
}
else if (isClassIdCompatible(texmap, Class_ID(ACUBIC_CLASS_ID, 0)))
{
pTexture = buildTextureCubeFromReflectRefract(texmap, time);
}
else if (isClassIdCompatible(texmap, Class_ID(COMPOSITE_CLASS_ID, 0)))
{
pTexture = buildTextureCubeFromComposite(texmap, time);
}
// Get the UVs channel and the channel matrix
Matrix3 channelMatrix;
int nChannel=getVertMapChannel (texmap, channelMatrix, time);
// Add the UVs channel
remap3dsTexChannel._IndexInMaxMaterial=nChannel;
remap3dsTexChannel._UVMatrix=channelMatrix;
// check for tiling
if (pTexture != NULL) // avoid possible crash
{
if (!(texmap.GetTextureTiling() & U_WRAP)) pTexture->setWrapS(ITexture::Clamp);
if (!(texmap.GetTextureTiling() & V_WRAP)) pTexture->setWrapT(ITexture::Clamp);
}
// Return the texture pointer
return pTexture;
}
/// Build a NeL texture cube from a Reflect/refract map containing 6 textures.
NL3D::CTextureCube *CExportNel::buildTextureCubeFromReflectRefract(Texmap &texmap, TimeValue time)
{
if (isClassIdCompatible(texmap, Class_ID(ACUBIC_CLASS_ID, 0)))
{
// texture cube
CTextureCube *pTextureCube = new CTextureCube();
// set settings
pTextureCube->setWrapS(ITexture::Clamp);
pTextureCube->setWrapT(ITexture::Clamp);
pTextureCube->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff);
// face order
const static CTextureCube::TFace tfNewOrder[6] =
{ CTextureCube::positive_z, CTextureCube::negative_z, // up dn
CTextureCube::negative_x, CTextureCube::positive_x, // lf rt
// CTextureCube::positive_y, CTextureCube::negative_y };
CTextureCube::negative_y, CTextureCube::positive_y }; // fr bk
// vector of bitmap names
vector<string> names;
CExportNel::getValueByNameUsingParamBlock2(texmap, "bitmapName", (ParamType2)TYPE_STRING_TAB, &names, time);
uint nNbSubMap = std::min<uint>((uint)names.size(), 6);
for (uint i = 0; i < nNbSubMap; ++i)
{
// Create a texture file
CTextureFile *pT = new CTextureFile();
// Set the file name
pT->setFileName(ConvertTexFileName(names[i].c_str(), _AbsolutePath));
// Set the texture
pTextureCube->setTexture(tfNewOrder[i], pT);
}
// return the texture cube
return pTextureCube;
}
else return NULL;
}
/// Build a NeL texture cube from a Composite map containing 6 textures (note: no re-ordering is done, because it didn't reorder composite cube in previous version either).
NL3D::CTextureCube *CExportNel::buildTextureCubeFromComposite(Texmap &texmap, TimeValue time)
{
if (isClassIdCompatible(texmap, Class_ID(COMPOSITE_CLASS_ID, 0)))
{
// texture cube
CTextureCube *pTextureCube = new CTextureCube();
// set settings
pTextureCube->setWrapS(ITexture::Clamp);
pTextureCube->setWrapT(ITexture::Clamp);
pTextureCube->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff);
// get number of maps
uint nNbSubMap = std::min<uint>((uint)texmap.NumSubTexmaps(), 6);
for (uint i = 0; i < nNbSubMap; ++i)
{
std::vector<CMaterialDesc> _3dsTexChannel;
Texmap *pSubMap = texmap.GetSubTexmap(i);
if (pSubMap != NULL && isClassIdCompatible(*pSubMap, Class_ID(BMTEX_CLASS_ID, 0)))
{
CMaterialDesc _3dsTexChannel;
ITexture *pTexture = buildATexture(*pSubMap, _3dsTexChannel, time);
pTextureCube->setTexture((CTextureCube::TFace)i, pTexture);
}
}
// return the texture cube
return pTextureCube;
}
else return NULL;
}
/// Build a NeL texture cube from a single texture.
NL3D::CTextureCube *CExportNel::buildTextureCubeFromTexture(Texmap &texmap, TimeValue time)
{
if (isClassIdCompatible(texmap, Class_ID(BMTEX_CLASS_ID, 0)))
{
// texture cube
CTextureCube *pTextureCube = new CTextureCube();
// set settings
pTextureCube->setWrapS(ITexture::Clamp);
pTextureCube->setWrapT(ITexture::Clamp);
pTextureCube->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff);
// List of channels used by this texture
CMaterialDesc _3dsTexChannel;
// Ok export the texture in NeL format
ITexture *pTexture = buildATexture(texmap, _3dsTexChannel, time);
pTextureCube->setTexture(CTextureCube::positive_x, pTexture);
return pTextureCube;
}
else return NULL;
}
#pragma optimize("", on)