123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- /*
- Open Asset Import Library (assimp)
- ----------------------------------------------------------------------
- Copyright (c) 2006-2025, assimp team
- All rights reserved.
- Redistribution and use of this software in source and binary forms,
- with or without modification, are permitted provided that the
- following conditions are met:
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
- * Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- ----------------------------------------------------------------------
- */
- #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
- #include "OgreImporter.h"
- #include <assimp/StringUtils.h>
- #include <assimp/TinyFormatter.h>
- #include <assimp/fast_atof.h>
- #include <assimp/material.h>
- #include <assimp/scene.h>
- #include <assimp/DefaultLogger.hpp>
- #include <memory>
- #include <sstream>
- #include <vector>
- using namespace std;
- namespace Assimp {
- namespace Ogre {
- static const string partComment = "//";
- static const string partBlockStart = "{";
- static const string partBlockEnd = "}";
- void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh) {
- std::vector<aiMaterial *> materials;
- // Create materials that can be found and parsed via the IOSystem.
- for (size_t i = 0, len = mesh->NumSubMeshes(); i < len; ++i) {
- SubMesh *submesh = mesh->GetSubMesh(i);
- if (submesh && !submesh->materialRef.empty()) {
- aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);
- if (material) {
- submesh->materialIndex = static_cast<int>(materials.size());
- materials.push_back(material);
- }
- }
- }
- AssignMaterials(pScene, materials);
- }
- void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh) {
- std::vector<aiMaterial *> materials;
- // Create materials that can be found and parsed via the IOSystem.
- for (size_t i = 0, len = mesh->NumSubMeshes(); i < len; ++i) {
- SubMeshXml *submesh = mesh->GetSubMesh(static_cast<uint16_t>(i));
- if (submesh && !submesh->materialRef.empty()) {
- aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);
- if (material) {
- submesh->materialIndex = static_cast<int>(materials.size());
- materials.push_back(material);
- }
- }
- }
- AssignMaterials(pScene, materials);
- }
- void OgreImporter::AssignMaterials(aiScene *pScene, std::vector<aiMaterial *> &materials) {
- pScene->mNumMaterials = static_cast<unsigned int>(materials.size());
- if (pScene->mNumMaterials > 0) {
- pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
- for (size_t i = 0; i < pScene->mNumMaterials; ++i) {
- pScene->mMaterials[i] = materials[i];
- }
- }
- }
- aiMaterial *OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string &materialName) {
- if (materialName.empty()) {
- return nullptr;
- }
- // Full reference and examples of Ogre Material Script
- // can be found from http://www.ogre3d.org/docs/manual/manual_14.html
- /*and here is another one:
- import * from abstract_base_passes_depth.material
- import * from abstract_base.material
- import * from mat_shadow_caster.material
- import * from mat_character_singlepass.material
- material hero/hair/caster : mat_shadow_caster_skin_areject
- {
- set $diffuse_map "hero_hair_alpha_c.dds"
- }
- material hero/hair_alpha : mat_char_cns_singlepass_areject_4weights
- {
- set $diffuse_map "hero_hair_alpha_c.dds"
- set $specular_map "hero_hair_alpha_s.dds"
- set $normal_map "hero_hair_alpha_n.dds"
- set $light_map "black_lightmap.dds"
- set $shadow_caster_material "hero/hair/caster"
- }
- */
- stringstream ss;
- // Scope for scopre_ptr auto release
- {
- /* There are three .material options in priority order:
- 1) File with the material name (materialName)
- 2) File with the mesh files base name (pFile)
- 3) Optional user defined material library file (m_userDefinedMaterialLibFile) */
- std::vector<string> potentialFiles;
- potentialFiles.push_back(materialName + ".material");
- potentialFiles.push_back(pFile.substr(0, pFile.rfind(".mesh")) + ".material");
- if (!m_userDefinedMaterialLibFile.empty())
- potentialFiles.push_back(m_userDefinedMaterialLibFile);
- IOStream *materialFile = nullptr;
- for (size_t i = 0; i < potentialFiles.size(); ++i) {
- materialFile = pIOHandler->Open(potentialFiles[i]);
- if (materialFile) {
- break;
- }
- ASSIMP_LOG_VERBOSE_DEBUG("Source file for material '", materialName, "' ", potentialFiles[i], " does not exist");
- }
- if (!materialFile) {
- ASSIMP_LOG_ERROR("Failed to find source file for material '", materialName, "'");
- return nullptr;
- }
- std::unique_ptr<IOStream> stream(materialFile);
- if (stream->FileSize() == 0) {
- ASSIMP_LOG_WARN("Source file for material '", materialName, "' is empty (size is 0 bytes)");
- return nullptr;
- }
- // Read bytes
- vector<char> data(stream->FileSize());
- stream->Read(&data[0], stream->FileSize(), 1);
- // Convert to UTF-8 and terminate the string for ss
- BaseImporter::ConvertToUTF8(data);
- data.push_back('\0');
- ss << &data[0];
- }
- ASSIMP_LOG_VERBOSE_DEBUG("Reading material '", materialName, "'");
- aiMaterial *material = new aiMaterial();
- m_textures.clear();
- aiString matName(materialName);
- material->AddProperty(&matName, AI_MATKEY_NAME);
- // The stringstream will push words from a line until newline.
- // It will also trim whitespace from line start and between words.
- string linePart;
- ss >> linePart;
- const string partMaterial = "material";
- const string partTechnique = "technique";
- while (!ss.eof()) {
- // Skip commented lines
- if (linePart == partComment) {
- NextAfterNewLine(ss, linePart);
- continue;
- }
- if (linePart != partMaterial) {
- ss >> linePart;
- continue;
- }
- ss >> linePart;
- if (linePart != materialName) {
- ss >> linePart;
- continue;
- }
- NextAfterNewLine(ss, linePart);
- if (linePart != partBlockStart) {
- ASSIMP_LOG_ERROR("Invalid material: block start missing near index ", ss.tellg());
- return material;
- }
- ASSIMP_LOG_VERBOSE_DEBUG("material '", materialName, "'");
- while (linePart != partBlockEnd) {
- // Proceed to the first technique
- ss >> linePart;
- if (linePart == partTechnique) {
- std::string techniqueName = SkipLine(ss);
- ReadTechnique(ai_trim(techniqueName), ss, material);
- }
- // Read information from a custom material
- /** @todo This "set $x y" does not seem to be a official Ogre material system feature.
- Materials can inherit other materials and override texture units by using the (unique)
- parent texture unit name in your cloned material.
- This is not yet supported and below code is probably some hack from the original
- author of this Ogre importer. Should be removed? */
- if (linePart == "set") {
- ss >> linePart;
- if (linePart == "$specular") //todo load this values:
- {
- } else if (linePart == "$diffuse") {
- } else if (linePart == "$ambient") {
- } else if (linePart == "$colormap") {
- ss >> linePart;
- aiString cm(linePart);
- material->AddProperty(&cm, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
- } else if (linePart == "$normalmap") {
- ss >> linePart;
- aiString nm(linePart);
- material->AddProperty(&nm, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
- } else if (linePart == "$shininess_strength") {
- ss >> linePart;
- float Shininess = fast_atof(linePart.c_str());
- material->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS_STRENGTH);
- } else if (linePart == "$shininess_exponent") {
- ss >> linePart;
- float Shininess = fast_atof(linePart.c_str());
- material->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS);
- }
- //Properties from Venetica:
- else if (linePart == "$diffuse_map") {
- ss >> linePart;
- if (linePart[0] == '"') // "file" -> file
- linePart = linePart.substr(1, linePart.size() - 2);
- aiString ts(linePart);
- material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
- } else if (linePart == "$specular_map") {
- ss >> linePart;
- if (linePart[0] == '"') // "file" -> file
- linePart = linePart.substr(1, linePart.size() - 2);
- aiString ts(linePart);
- material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_SHININESS, 0));
- } else if (linePart == "$normal_map") {
- ss >> linePart;
- if (linePart[0] == '"') // "file" -> file
- linePart = linePart.substr(1, linePart.size() - 2);
- aiString ts(linePart);
- material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
- } else if (linePart == "$light_map") {
- ss >> linePart;
- if (linePart[0] == '"') {
- linePart = linePart.substr(1, linePart.size() - 2);
- }
- aiString ts(linePart);
- material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, 0));
- }
- }
- }
- ss >> linePart;
- }
- return material;
- }
- bool OgreImporter::ReadTechnique(const std::string &techniqueName, stringstream &ss, aiMaterial *material) {
- string linePart;
- ss >> linePart;
- if (linePart != partBlockStart) {
- ASSIMP_LOG_ERROR("Invalid material: Technique block start missing near index ", ss.tellg());
- return false;
- }
- ASSIMP_LOG_VERBOSE_DEBUG(" technique '", techniqueName, "'");
- const string partPass = "pass";
- while (linePart != partBlockEnd) {
- ss >> linePart;
- // Skip commented lines
- if (linePart == partComment) {
- SkipLine(ss);
- continue;
- }
- /// @todo Techniques have other attributes than just passes.
- if (linePart == partPass) {
- string passName = SkipLine(ss);
- ReadPass(ai_trim(passName), ss, material);
- }
- }
- return true;
- }
- bool OgreImporter::ReadPass(const std::string &passName, stringstream &ss, aiMaterial *material) {
- string linePart;
- ss >> linePart;
- if (linePart != partBlockStart) {
- ASSIMP_LOG_ERROR("Invalid material: Pass block start missing near index ", ss.tellg());
- return false;
- }
- ASSIMP_LOG_VERBOSE_DEBUG(" pass '", passName, "'");
- const string partAmbient = "ambient";
- const string partDiffuse = "diffuse";
- const string partSpecular = "specular";
- const string partEmissive = "emissive";
- const string partTextureUnit = "texture_unit";
- while (linePart != partBlockEnd) {
- ss >> linePart;
- // Skip commented lines
- if (linePart == partComment) {
- SkipLine(ss);
- continue;
- }
- // Colors
- /// @todo Support alpha via aiColor4D.
- if (linePart == partAmbient || linePart == partDiffuse || linePart == partSpecular || linePart == partEmissive) {
- float r, g, b;
- ss >> r >> g >> b;
- const aiColor3D color(r, g, b);
- ASSIMP_LOG_VERBOSE_DEBUG(" ", linePart, " ", r, " ", g, " ", b);
- if (linePart == partAmbient) {
- material->AddProperty(&color, 1, AI_MATKEY_COLOR_AMBIENT);
- } else if (linePart == partDiffuse) {
- material->AddProperty(&color, 1, AI_MATKEY_COLOR_DIFFUSE);
- } else if (linePart == partSpecular) {
- material->AddProperty(&color, 1, AI_MATKEY_COLOR_SPECULAR);
- } else if (linePart == partEmissive) {
- material->AddProperty(&color, 1, AI_MATKEY_COLOR_EMISSIVE);
- }
- } else if (linePart == partTextureUnit) {
- string textureUnitName = SkipLine(ss);
- ReadTextureUnit(ai_trim(textureUnitName), ss, material);
- }
- }
- return true;
- }
- bool OgreImporter::ReadTextureUnit(const std::string &textureUnitName, stringstream &ss, aiMaterial *material) {
- string linePart;
- ss >> linePart;
- if (linePart != partBlockStart) {
- ASSIMP_LOG_ERROR("Invalid material: Texture unit block start missing near index ", ss.tellg());
- return false;
- }
- ASSIMP_LOG_VERBOSE_DEBUG(" texture_unit '", textureUnitName, "'");
- const string partTexture = "texture";
- const string partTextCoordSet = "tex_coord_set";
- const string partColorOp = "colour_op";
- aiTextureType textureType = aiTextureType_NONE;
- std::string textureRef;
- int uvCoord = 0;
- while (linePart != partBlockEnd) {
- ss >> linePart;
- // Skip commented lines
- if (linePart == partComment) {
- SkipLine(ss);
- continue;
- }
- if (linePart == partTexture) {
- ss >> linePart;
- textureRef = linePart;
- // User defined Assimp config property to detect texture type from filename.
- if (m_detectTextureTypeFromFilename) {
- size_t posSuffix = textureRef.find_last_of('.');
- size_t posUnderscore = textureRef.find_last_of('_');
- if (posSuffix != string::npos && posUnderscore != string::npos && posSuffix > posUnderscore) {
- string identifier = ai_tolower(textureRef.substr(posUnderscore, posSuffix - posUnderscore));
- ASSIMP_LOG_VERBOSE_DEBUG("Detecting texture type from filename postfix '", identifier, "'");
- if (identifier == "_n" || identifier == "_nrm" || identifier == "_nrml" || identifier == "_normal" || identifier == "_normals" || identifier == "_normalmap") {
- textureType = aiTextureType_NORMALS;
- } else if (identifier == "_s" || identifier == "_spec" || identifier == "_specular" || identifier == "_specularmap") {
- textureType = aiTextureType_SPECULAR;
- } else if (identifier == "_l" || identifier == "_light" || identifier == "_lightmap" || identifier == "_occ" || identifier == "_occlusion") {
- textureType = aiTextureType_LIGHTMAP;
- } else if (identifier == "_disp" || identifier == "_displacement") {
- textureType = aiTextureType_DISPLACEMENT;
- } else {
- textureType = aiTextureType_DIFFUSE;
- }
- } else {
- textureType = aiTextureType_DIFFUSE;
- }
- }
- // Detect from texture unit name. This cannot be too broad as
- // authors might give names like "LightSaber" or "NormalNinja".
- else {
- string unitNameLower = ai_tolower(textureUnitName);
- if (unitNameLower.find("normalmap") != string::npos) {
- textureType = aiTextureType_NORMALS;
- } else if (unitNameLower.find("specularmap") != string::npos) {
- textureType = aiTextureType_SPECULAR;
- } else if (unitNameLower.find("lightmap") != string::npos) {
- textureType = aiTextureType_LIGHTMAP;
- } else if (unitNameLower.find("displacementmap") != string::npos) {
- textureType = aiTextureType_DISPLACEMENT;
- } else {
- textureType = aiTextureType_DIFFUSE;
- }
- }
- } else if (linePart == partTextCoordSet) {
- ss >> uvCoord;
- }
- /// @todo Implement
- else if (linePart == partColorOp) {
- /*
- ss >> linePart;
- if("replace"==linePart)//I don't think, assimp has something for this...
- {
- }
- else if("modulate"==linePart)
- {
- //TODO: set value
- //material->AddProperty(aiTextureOp_Multiply)
- }
- */
- }
- }
- if (textureRef.empty()) {
- ASSIMP_LOG_WARN("Texture reference is empty, ignoring texture_unit.");
- return false;
- }
- if (textureType == aiTextureType_NONE) {
- ASSIMP_LOG_WARN("Failed to detect texture type for '", textureRef, "', ignoring texture_unit.");
- return false;
- }
- unsigned int textureTypeIndex = m_textures[textureType];
- m_textures[textureType]++;
- ASSIMP_LOG_VERBOSE_DEBUG(" texture '", textureRef, "' type ", textureType,
- " index ", textureTypeIndex, " UV ", uvCoord);
- aiString assimpTextureRef(textureRef);
- material->AddProperty(&assimpTextureRef, AI_MATKEY_TEXTURE(textureType, textureTypeIndex));
- material->AddProperty(&uvCoord, 1, AI_MATKEY_UVWSRC(textureType, textureTypeIndex));
- return true;
- }
- } // namespace Ogre
- } // namespace Assimp
- #endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
|