123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- /*
- ---------------------------------------------------------------------------
- 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.
- ---------------------------------------------------------------------------
- */
- /** @file IRRShared.cpp
- * @brief Shared utilities for the IRR and IRRMESH loaders
- */
- // This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
- #if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
- #include "IRRShared.h"
- #include <assimp/ParsingUtils.h>
- #include <assimp/fast_atof.h>
- #include <assimp/material.h>
- #include <assimp/DefaultLogger.hpp>
- using namespace Assimp;
- // Transformation matrix to convert from Assimp to IRR space
- const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4(
- 1.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f);
- // ------------------------------------------------------------------------------------------------
- // read a property in hexadecimal format (i.e. ffffffff)
- void IrrlichtBase::ReadHexProperty(HexProperty &out, pugi::xml_node& hexnode) {
- for (pugi::xml_attribute attrib : hexnode.attributes()) {
- if (!ASSIMP_stricmp(attrib.name(), "name")) {
- out.name = std::string(attrib.value());
- } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
- // parse the hexadecimal value
- out.value = strtoul16(attrib.value());
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- // read a decimal property
- void IrrlichtBase::ReadIntProperty(IntProperty &out, pugi::xml_node& intnode) {
- for (pugi::xml_attribute attrib : intnode.attributes()) {
- if (!ASSIMP_stricmp(attrib.name(), "name")) {
- out.name = std::string(attrib.value());
- } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
- // parse the int value
- out.value = strtol10(attrib.value());
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- // read a string property
- void IrrlichtBase::ReadStringProperty(StringProperty &out, pugi::xml_node& stringnode) {
- for (pugi::xml_attribute attrib : stringnode.attributes()) {
- if (!ASSIMP_stricmp(attrib.name(), "name")) {
- out.name = std::string(attrib.value());
- } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
- // simple copy the string
- out.value = std::string(attrib.value());
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- // read a boolean property
- void IrrlichtBase::ReadBoolProperty(BoolProperty &out, pugi::xml_node& boolnode) {
- for (pugi::xml_attribute attrib : boolnode.attributes()) {
- if (!ASSIMP_stricmp(attrib.name(), "name")) {
- out.name = std::string(attrib.value());
- } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
- // true or false, case insensitive
- out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- // read a float property
- void IrrlichtBase::ReadFloatProperty(FloatProperty &out, pugi::xml_node &floatnode) {
- for (pugi::xml_attribute attrib : floatnode.attributes()) {
- if (!ASSIMP_stricmp(attrib.name(), "name")) {
- out.name = std::string(attrib.value());
- } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
- // just parse the float
- out.value = fast_atof(attrib.value());
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- // read a vector property
- void IrrlichtBase::ReadVectorProperty(VectorProperty &out, pugi::xml_node& vectornode) {
- for (pugi::xml_attribute attrib : vectornode.attributes()) {
- if (!ASSIMP_stricmp(attrib.name(), "name")) {
- out.name = std::string(attrib.value());
- } else if (!ASSIMP_stricmp(attrib.name(), "value")) {
- // three floats, separated with commas
- const char *ptr = attrib.value();
- size_t len = std::strlen(ptr);
- const char *end = ptr + len;
- SkipSpaces(&ptr, end);
- ptr = fast_atoreal_move<float>(ptr, (float &)out.value.x);
- SkipSpaces(&ptr, end);
- if (',' != *ptr) {
- ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
- } else {
- SkipSpaces(ptr + 1, &ptr, end);
- }
- ptr = fast_atoreal_move<float>(ptr, (float &)out.value.y);
- SkipSpaces(&ptr, end);
- if (',' != *ptr) {
- ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
- } else {
- SkipSpaces(ptr + 1, &ptr, end);
- }
- ptr = fast_atoreal_move<float>(ptr, (float &)out.value.z);
- }
- }
- }
- // ------------------------------------------------------------------------------------------------
- // Convert a string to a proper aiMappingMode
- int ConvertMappingMode(const std::string &mode) {
- if (mode == "texture_clamp_repeat") {
- return aiTextureMapMode_Wrap;
- } else if (mode == "texture_clamp_mirror") {
- return aiTextureMapMode_Mirror;
- }
- return aiTextureMapMode_Clamp;
- }
- // ------------------------------------------------------------------------------------------------
- // Parse a material from the XML file
- aiMaterial *IrrlichtBase::ParseMaterial(pugi::xml_node& materialNode, unsigned int &matFlags) {
- aiMaterial *mat = new aiMaterial();
- aiColor4D clr;
- aiString s;
- matFlags = 0; // zero output flags
- int cnt = 0; // number of used texture channels
- unsigned int nd = 0;
- for (pugi::xml_node child : materialNode.children()) {
- if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
- HexProperty prop;
- ReadHexProperty(prop, child);
- if (prop.name == "Diffuse") {
- ColorFromARGBPacked(prop.value, clr);
- mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
- } else if (prop.name == "Ambient") {
- ColorFromARGBPacked(prop.value, clr);
- mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
- } else if (prop.name == "Specular") {
- ColorFromARGBPacked(prop.value, clr);
- mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
- }
- // NOTE: The 'emissive' property causes problems. It is
- // often != 0, even if there is obviously no light
- // emitted by the described surface. In fact I think
- // IRRLICHT ignores this property, too.
- #if 0
- else if (prop.name == "Emissive") {
- ColorFromARGBPacked(prop.value,clr);
- mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
- }
- #endif
- } else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
- FloatProperty prop;
- ReadFloatProperty(prop, child);
- if (prop.name == "Shininess") {
- mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
- }
- } else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
- BoolProperty prop;
- ReadBoolProperty(prop, child);
- if (prop.name == "Wireframe") {
- int val = (prop.value ? true : false);
- mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
- } else if (prop.name == "GouraudShading") {
- int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
- mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
- } else if (prop.name == "BackfaceCulling") {
- int val = (!prop.value);
- mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
- }
- } else if (!ASSIMP_stricmp(child.name(), "texture") ||
- !ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
- StringProperty prop;
- ReadStringProperty(prop, child);
- if (prop.value.length()) {
- // material type (shader)
- if (prop.name == "Type") {
- if (prop.value == "solid") {
- // default material ...
- } else if (prop.value == "trans_vertex_alpha") {
- matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
- } else if (prop.value == "lightmap") {
- matFlags = AI_IRRMESH_MAT_lightmap;
- } else if (prop.value == "solid_2layer") {
- matFlags = AI_IRRMESH_MAT_solid_2layer;
- } else if (prop.value == "lightmap_m2") {
- matFlags = AI_IRRMESH_MAT_lightmap_m2;
- } else if (prop.value == "lightmap_m4") {
- matFlags = AI_IRRMESH_MAT_lightmap_m4;
- } else if (prop.value == "lightmap_light") {
- matFlags = AI_IRRMESH_MAT_lightmap_light;
- } else if (prop.value == "lightmap_light_m2") {
- matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
- } else if (prop.value == "lightmap_light_m4") {
- matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
- } else if (prop.value == "lightmap_add") {
- matFlags = AI_IRRMESH_MAT_lightmap_add;
- } else if (prop.value == "normalmap_solid" ||
- prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
- matFlags = AI_IRRMESH_MAT_normalmap_solid;
- } else if (prop.value == "normalmap_trans_vertex_alpha" ||
- prop.value == "parallaxmap_trans_vertex_alpha") {
- matFlags = AI_IRRMESH_MAT_normalmap_tva;
- } else if (prop.value == "normalmap_trans_add" ||
- prop.value == "parallaxmap_trans_add") {
- matFlags = AI_IRRMESH_MAT_normalmap_ta;
- } else {
- ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: ", prop.value);
- }
- }
- // Up to 4 texture channels are supported
- if (prop.name == "Texture1") {
- // Always accept the primary texture channel
- ++cnt;
- s.Set(prop.value);
- mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
- } else if (prop.name == "Texture2" && cnt == 1) {
- // 2-layer material lightmapped?
- if (matFlags & AI_IRRMESH_MAT_lightmap) {
- ++cnt;
- s.Set(prop.value);
- mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
- // set the corresponding material flag
- matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
- } else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
- ++cnt;
- s.Set(prop.value);
- mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
- // set the corresponding material flag
- matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
- } else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
- ++cnt;
- s.Set(prop.value);
- mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
- ++nd;
- // set the corresponding material flag
- matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
- } else {
- ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
- }
- } else if (prop.name == "Texture3" && cnt == 2) {
- // Irrlicht does not seem to use these channels.
- ++cnt;
- s.Set(prop.value);
- mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
- } else if (prop.name == "Texture4" && cnt == 3) {
- // Irrlicht does not seem to use these channels.
- ++cnt;
- s.Set(prop.value);
- mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
- }
- // Texture mapping options
- if (prop.name == "TextureWrap1" && cnt >= 1) {
- int map = ConvertMappingMode(prop.value);
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
- } else if (prop.name == "TextureWrap2" && cnt >= 2) {
- int map = ConvertMappingMode(prop.value);
- if (matFlags & AI_IRRMESH_MAT_lightmap) {
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
- } else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
- } else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
- }
- } else if (prop.name == "TextureWrap3" && cnt >= 3) {
- int map = ConvertMappingMode(prop.value);
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
- } else if (prop.name == "TextureWrap4" && cnt >= 4) {
- int map = ConvertMappingMode(prop.value);
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
- mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
- }
- }
- }
- // break;
- /*case EXN_ELEMENT_END:
- // Assume there are no further nested nodes in <material> elements
- if ( !ASSIMP_stricmp(reader->getNodeName(),"material") ||
- !ASSIMP_stricmp(reader->getNodeName(),"attributes"))
- {
- // Now process lightmapping flags
- // We should have at least one textur to do that ..
- if (cnt && matFlags & AI_IRRMESH_MAT_lightmap)
- {
- float f = 1.f;
- unsigned int unmasked = matFlags&~AI_IRRMESH_MAT_lightmap;
- // Additive lightmap?
- int op = (unmasked & AI_IRRMESH_MAT_lightmap_add
- ? aiTextureOp_Add : aiTextureOp_Multiply);
- // Handle Irrlicht's lightmapping scaling factor
- if (unmasked & AI_IRRMESH_MAT_lightmap_m2 ||
- unmasked & AI_IRRMESH_MAT_lightmap_light_m2)
- {
- f = 2.f;
- }
- else if (unmasked & AI_IRRMESH_MAT_lightmap_m4 ||
- unmasked & AI_IRRMESH_MAT_lightmap_light_m4)
- {
- f = 4.f;
- }
- mat->AddProperty( &f, 1, AI_MATKEY_TEXBLEND_LIGHTMAP(0));
- mat->AddProperty( &op,1, AI_MATKEY_TEXOP_LIGHTMAP(0));
- }
- return mat;
- }
- default:
- // GCC complains here ...
- break;
- }
- }*/
- }
- //ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
- return mat;
- }
- #endif // !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
|