Fix game:addSpawnShapesByZone
[ryzomcore.git] / nel / tools / 3d / mesh_utils / assimp_material.cpp
blob11b070c230518b8ccc1ee79f107eae94b7a23431
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2015 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2016 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 // Author: Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
22 #include <nel/misc/types_nl.h>
23 #include "assimp_shape.h"
25 #include <assimp/postprocess.h>
26 #include <assimp/scene.h>
27 #include <assimp/Importer.hpp>
29 #define NL_NODE_INTERNAL_TYPE aiNode
30 #define NL_SCENE_INTERNAL_TYPE aiScene
31 #include "scene_context.h"
33 #include <nel/misc/debug.h>
34 #include <nel/misc/path.h>
35 #include <nel/pipeline/tool_logger.h>
37 #include <nel/3d/mesh.h>
38 #include <nel/3d/texture_file.h>
40 using namespace std;
41 using namespace NLMISC;
42 using namespace NL3D;
44 // http://assimp.sourceforge.net/lib_html/materials.html
46 inline CRGBA convColor(const aiColor3D &ac, uint8 a = 255)
48 return CRGBA(ac.r * 255.99f, ac.g * 255.99f, ac.b * 255.99f);
51 inline CRGBA convColor(const aiColor4D &ac)
53 return CRGBA(ac.r * 255.99f, ac.g * 255.99f, ac.b * 255.99f, ac.a * 255.99f);
56 void assimpMaterial(NL3D::CMaterial &mat, CMeshUtilsContext &context, const aiMaterial *am)
58 aiString amname;
59 if (am->Get(AI_MATKEY_NAME, amname) != aiReturn_SUCCESS)
60 amname = "";
62 mat.initLighted();
63 mat.setShader(CMaterial::Normal);
65 int i;
66 float f;
67 aiColor3D c3;
68 aiColor4D c4;
70 if (am->Get(AI_MATKEY_TWOSIDED, i) == aiReturn_SUCCESS)
71 mat.setDoubleSided(i != 0);
73 if (am->Get(AI_MATKEY_BLEND_FUNC, i) == aiReturn_SUCCESS) switch ((aiBlendMode)i)
75 case aiBlendMode_Default:
76 mat.setSrcBlend(CMaterial::srcalpha);
77 mat.setDstBlend(CMaterial::invsrcalpha);
78 break;
79 case aiBlendMode_Additive:
80 mat.setSrcBlend(CMaterial::one);
81 mat.setDstBlend(CMaterial::one);
82 break;
85 // Colors follow GL convention
86 // "While the ambient, diffuse, specular and emission
87 // "material parameters all have alpha components, only the diffuse"
88 // "alpha component is used in the lighting computation."
89 if (am->Get(AI_MATKEY_COLOR_DIFFUSE, c3) == aiReturn_SUCCESS)
90 mat.setDiffuse(convColor(c3));
92 if (am->Get(AI_MATKEY_OPACITY, f) == aiReturn_SUCCESS)
93 mat.setOpacity(f * 255.99f);
95 if (am->Get(AI_MATKEY_COLOR_AMBIENT, c3) == aiReturn_SUCCESS)
96 mat.setAmbient(convColor(c3));
98 if (am->Get(AI_MATKEY_SHININESS, f) == aiReturn_SUCCESS)
99 mat.setShininess(f); // (float)pow(2.0, f * 10.0) * 4.f;
101 if (am->Get(AI_MATKEY_COLOR_SPECULAR, c3) == aiReturn_SUCCESS)
102 mat.setSpecular(convColor(c3));
104 if (am->Get(AI_MATKEY_SHININESS_STRENGTH, f) == aiReturn_SUCCESS)
105 mat.setSpecular(CRGBAF(mat.getSpecular()) * f);
106 else
107 mat.setSpecular(NLMISC::CRGBA::Black);
109 if (am->Get(AI_MATKEY_COLOR_EMISSIVE, c3) == aiReturn_SUCCESS)
110 mat.setEmissive(convColor(c3));
112 // Textures
113 unsigned int texCount = am->GetTextureCount(aiTextureType_DIFFUSE);
114 if (texCount > IDRV_MAT_MAXTEXTURES)
116 tlwarning(context.ToolLogger, context.Settings.SourceFilePath.c_str(),
117 "Material '%s' has more than %i textures (%i textures found)", amname.C_Str(), IDRV_MAT_MAXTEXTURES, texCount);
118 texCount = IDRV_MAT_MAXTEXTURES;
121 for (unsigned int ti = 0; ti < texCount; ++ti)
123 aiString path;
124 aiTextureMapping mapping;
125 unsigned int uvindex;
126 float blend; // Partially supported
127 aiTextureOp op;
128 aiTextureMapMode mapmode;
129 if (am->GetTexture(aiTextureType_DIFFUSE, ti, &path, &mapping, &uvindex, &blend, &op, &mapmode) != aiReturn_SUCCESS)
131 tlerror(context.ToolLogger, context.Settings.SourceFilePath.c_str(),
132 "Failed to get texture %i in material '%s'", ti, amname.C_Str());
133 break;
136 std::string fileName = CFile::getFilename(CPath::standardizePath(path.C_Str(), false));
137 std::string knownPath = CPath::lookup(fileName, false, false, false);
138 if (knownPath.empty())
140 tlwarning(context.ToolLogger, context.Settings.SourceFilePath.c_str(),
141 "Texture '%s' referenced in material '%s' but not found in the database search paths", fileName.c_str(), amname.C_Str());
144 // NeL supports bitmap and cubemap, but we import only basic bitmap here. Cubemap can be inserted from the mesh editor tool
145 // NeL also has fancy multi-bitmap thing to switch between summer and winter and so on. Same story
146 CSmartPtr<CTextureFile> tex = new CTextureFile();
147 tex->setFileName(fileName);
148 tex->setWrapS(mapmode == aiTextureMapMode_Clamp ? ITexture::Clamp : ITexture::Repeat);
149 tex->setWrapT(mapmode == aiTextureMapMode_Clamp ? ITexture::Clamp : ITexture::Repeat);
150 mat.setTexture(ti, tex);
152 // TODO uvindex for uv routing (probably necessary during shape import - if so also need to also ask the uv channel in the editor and store in meta)
154 // TODO aiTextureMapping texcoordgen if useful to import
156 mat.texEnvArg0Alpha(ti, CMaterial::Texture, CMaterial::SrcAlpha);
157 mat.texEnvArg0RGB(ti, CMaterial::Texture, CMaterial::SrcColor);
158 mat.texEnvArg1Alpha(ti, ti == 0 ? CMaterial::Diffuse : CMaterial::Previous, CMaterial::SrcAlpha);
159 mat.texEnvArg1RGB(ti, ti == 0 ? CMaterial::Diffuse : CMaterial::Previous, CMaterial::SrcColor);
160 switch (op)
162 case aiTextureOp_Multiply:
163 default:
164 mat.texEnvOpAlpha(ti, CMaterial::Modulate);
165 mat.texEnvOpRGB(ti, CMaterial::Modulate);
166 break;
167 case aiTextureOp_Add:
168 mat.texEnvOpAlpha(ti, CMaterial::Add);
169 mat.texEnvOpRGB(ti, CMaterial::Add);
170 break;
171 case aiTextureOp_Subtract:
172 mat.texEnvArg0Alpha(ti, CMaterial::Texture, CMaterial::InvSrcAlpha);
173 mat.texEnvArg0RGB(ti, CMaterial::Texture, CMaterial::InvSrcColor);
174 mat.texEnvOpAlpha(ti, CMaterial::Add);
175 mat.texEnvOpRGB(ti, CMaterial::Add);
176 break;
177 case aiTextureOp_SignedAdd:
178 mat.texEnvOpAlpha(ti, CMaterial::AddSigned);
179 mat.texEnvOpRGB(ti, CMaterial::AddSigned);
180 break;
185 CSmartPtr<CMaterial> assimpMaterial(CMeshUtilsContext &context, const aiMaterial *am)
187 CSmartPtr<CMaterial> matp = new CMaterial();
188 CMaterial &mat = *matp;
189 assimpMaterial(mat, context, am);
190 return matp;
193 void assimpMaterials(CMeshUtilsContext &context)
195 set<CSString> materialNames;
197 const aiScene *scene = context.InternalScene;
198 for (unsigned int mi = 0; mi < scene->mNumMaterials; ++mi)
200 const aiMaterial *am = scene->mMaterials[mi];
202 for (unsigned int pi = 0; pi < am->mNumProperties; ++pi) // DEBUG
203 { // DEBUG
204 const aiMaterialProperty *amp = am->mProperties[pi];
205 printf("%s\n", amp->mKey.C_Str());
206 } // DEBUG
208 aiString amname;
209 if (am->Get(AI_MATKEY_NAME, amname) != aiReturn_SUCCESS)
211 tlerror(context.ToolLogger, context.Settings.SourceFilePath.c_str(),
212 "Material has no name");
213 continue;
216 if (materialNames.find(amname.C_Str()) != materialNames.end())
218 tlerror(context.ToolLogger, context.Settings.SourceFilePath.c_str(),
219 "Material name '%s' used more than once", amname.C_Str());
220 continue;
223 if (context.SceneMeta.Materials.find(amname.C_Str())
224 == context.SceneMeta.Materials.end())
226 materialNames.insert(amname.C_Str());
227 context.SceneMeta.Materials[amname.C_Str()] = assimpMaterial(context, am);
232 /* end of file */