diff --git a/panda/src/gobj/textureStage.cxx b/panda/src/gobj/textureStage.cxx index 26a00fc6c7..cd29b04040 100644 --- a/panda/src/gobj/textureStage.cxx +++ b/panda/src/gobj/textureStage.cxx @@ -15,6 +15,7 @@ #include "internalName.h" #include "bamReader.h" #include "bamWriter.h" +#include "indent.h" using std::ostream; @@ -221,15 +222,28 @@ compare_to(const TextureStage &other) const { */ void TextureStage:: write(ostream &out) const { - out << "TextureStage " << get_name() << ", sort = " << get_sort() << ", priority = " << get_priority() << "\n" - << " texcoords = " << get_texcoord_name()->get_name() - << ", mode = " << get_mode() << ", color = " << get_color() - << ", scale = " << get_rgb_scale() << ", " << get_alpha_scale() - << ", saved_result = " << get_saved_result() - << ", tex_view_offset = " << get_tex_view_offset() << "\n"; + write(out, 0); +} + +/** + * Writes the details of this stage + */ +void TextureStage:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) + << "TextureStage " << get_name() << ", sort = " << get_sort() + << ", priority = " << get_priority() << "\n"; + + indent(out, indent_level) + << " texcoords = " << get_texcoord_name()->get_name() + << ", mode = " << get_mode() << ", color = " << get_color() + << ", scale = " << get_rgb_scale() << ", " << get_alpha_scale() + << ", saved_result = " << get_saved_result() + << ", tex_view_offset = " << get_tex_view_offset() << "\n"; if (get_mode() == M_combine) { - out << " RGB combine mode = " << get_combine_rgb_mode() << "\n"; + indent(out, indent_level) + << " RGB combine mode = " << get_combine_rgb_mode() << "\n"; if (get_num_combine_rgb_operands() >= 1) { out << " 0: " << get_combine_rgb_source0() << ", " << get_combine_rgb_operand0() << "\n"; @@ -242,7 +256,8 @@ write(ostream &out) const { out << " 2: " << get_combine_rgb_source2() << ", " << get_combine_rgb_operand2() << "\n"; } - out << " alpha combine mode = " << get_combine_alpha_mode() << "\n"; + indent(out, indent_level) + << " alpha combine mode = " << get_combine_alpha_mode() << "\n"; if (get_num_combine_alpha_operands() >= 1) { out << " 0: " << get_combine_alpha_source0() << ", " << get_combine_alpha_operand0() << "\n"; diff --git a/panda/src/gobj/textureStage.h b/panda/src/gobj/textureStage.h index a1a9ccb6dd..ebbd1ab1a2 100644 --- a/panda/src/gobj/textureStage.h +++ b/panda/src/gobj/textureStage.h @@ -182,6 +182,7 @@ PUBLISHED: int compare_to(const TextureStage &other) const; void write(std::ostream &out) const; + void write(std::ostream &out, int indent_level) const; void output(std::ostream &out) const; INLINE static TextureStage *get_default(); diff --git a/pandatool/src/assimp/assimpLoader.cxx b/pandatool/src/assimp/assimpLoader.cxx index 4a106d4497..0f3158f2db 100644 --- a/pandatool/src/assimp/assimpLoader.cxx +++ b/pandatool/src/assimp/assimpLoader.cxx @@ -21,9 +21,11 @@ #include "geomTriangles.h" #include "pnmFileTypeRegistry.h" #include "pnmImage.h" +#include "alphaTestAttrib.h" #include "materialAttrib.h" #include "textureAttrib.h" #include "cullFaceAttrib.h" +#include "transparencyAttrib.h" #include "ambientLight.h" #include "directionalLight.h" #include "spotlight.h" @@ -35,12 +37,48 @@ #include "animBundleNode.h" #include "animChannelMatrixXfmTable.h" #include "pvector.h" +#include "cmath.h" +#include "deg_2_rad.h" +#include "string_utils.h" #include "pandaIOSystem.h" #include "pandaLogger.h" #include +#ifndef AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR +#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0 +#endif + +#ifndef AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR +#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0 +#endif + +#ifndef AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR +#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0 +#endif + +#ifndef AI_MATKEY_GLTF_ALPHAMODE +#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0 +#endif + +#ifndef AI_MATKEY_GLTF_ALPHACUTOFF +#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0 +#endif + +// Older versions of Assimp used these glTF-specific keys instead. +#ifndef AI_MATKEY_BASE_COLOR +#define AI_MATKEY_BASE_COLOR AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR +#endif + +#ifndef AI_MATKEY_METALLIC_FACTOR +#define AI_MATKEY_METALLIC_FACTOR AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR +#endif + +#ifndef AI_MATKEY_ROUGHNESS_FACTOR +#define AI_MATKEY_ROUGHNESS_FACTOR AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR +#endif + using std::ostringstream; using std::stringstream; using std::string; @@ -265,7 +303,8 @@ load_texture(size_t index) { } else { if (assimp_cat.is_debug()) { assimp_cat.debug() - << "Reading embedded raw texture with size " << tex.mWidth << "x" << tex.mHeight << "\n"; + << "Reading embedded raw texture with size " + << tex.mWidth << "x" << tex.mHeight << "\n"; } ptex->setup_2d_texture(tex.mWidth, tex.mHeight, Texture::T_unsigned_byte, Texture::F_rgba); @@ -292,16 +331,18 @@ load_texture(size_t index) { * Converts an aiMaterial into a RenderState. */ void AssimpLoader:: -load_texture_stage(const aiMaterial &mat, const aiTextureType &ttype, CPT(TextureAttrib) &tattr) { +load_texture_stage(const aiMaterial &mat, const aiTextureType &ttype, + TextureStage::Mode mode, CPT(TextureAttrib) &tattr, + CPT(TexMatrixAttrib) &tmattr) { aiString path; aiTextureMapping mapping; unsigned int uvindex; float blend; aiTextureOp op; - aiTextureMapMode mapmode; + aiTextureMapMode mapmode[3]; for (size_t i = 0; i < mat.GetTextureCount(ttype); ++i) { - mat.GetTexture(ttype, i, &path, &mapping, nullptr, &blend, &op, &mapmode); + mat.GetTexture(ttype, i, &path, &mapping, nullptr, &blend, &op, mapmode); if (AI_SUCCESS != mat.Get(AI_MATKEY_UVWSRC(ttype, i), uvindex)) { // If there's no texture coordinate set for this texture, assume that @@ -310,13 +351,23 @@ load_texture_stage(const aiMaterial &mat, const aiTextureType &ttype, CPT(Textur uvindex = i; } - stringstream str; - str << uvindex; - PT(TextureStage) stage = new TextureStage(str.str()); - if (uvindex > 0) { - stage->set_texcoord_name(InternalName::get_texcoord_name(str.str())); + if (ttype == aiTextureType_DIFFUSE && i == 1) { + // The glTF 2 importer duplicates this slot in older versions of Assimp. + // Since glTF doesn't support multiple diffuse textures anyway, we check + // for this old glTF-specific key, and if present, ignore this texture. + aiColor4D col; + if (AI_SUCCESS == mat.Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR, col)) { + return; + } } - PT(Texture) ptex = nullptr; + + std::string uvindex_str = format_string(uvindex); + PT(TextureStage) stage = new TextureStage(uvindex_str); + stage->set_mode(mode); + if (uvindex > 0) { + stage->set_texcoord_name(InternalName::get_texcoord_name(uvindex_str)); + } + PT(Texture) ptex; // I'm not sure if this is the right way to handle it, as I couldn't find // much information on embedded textures. @@ -355,7 +406,84 @@ load_texture_stage(const aiMaterial &mat, const aiTextureType &ttype, CPT(Textur } if (ptex != nullptr) { + // Apply the mapping modes. + switch (mapmode[0]) { + case aiTextureMapMode_Wrap: + ptex->set_wrap_u(SamplerState::WM_repeat); + break; + case aiTextureMapMode_Clamp: + ptex->set_wrap_u(SamplerState::WM_clamp); + break; + case aiTextureMapMode_Decal: + ptex->set_wrap_u(SamplerState::WM_border_color); + ptex->set_border_color(LColor(0, 0, 0, 0)); + break; + case aiTextureMapMode_Mirror: + ptex->set_wrap_u(SamplerState::WM_mirror); + break; + default: + break; + } + switch (mapmode[1]) { + case aiTextureMapMode_Wrap: + ptex->set_wrap_v(SamplerState::WM_repeat); + break; + case aiTextureMapMode_Clamp: + ptex->set_wrap_v(SamplerState::WM_clamp); + break; + case aiTextureMapMode_Decal: + ptex->set_wrap_v(SamplerState::WM_border_color); + ptex->set_border_color(LColor(0, 0, 0, 0)); + break; + case aiTextureMapMode_Mirror: + ptex->set_wrap_v(SamplerState::WM_mirror); + break; + default: + break; + } + switch (mapmode[2]) { + case aiTextureMapMode_Wrap: + ptex->set_wrap_w(SamplerState::WM_repeat); + break; + case aiTextureMapMode_Clamp: + ptex->set_wrap_w(SamplerState::WM_clamp); + break; + case aiTextureMapMode_Decal: + ptex->set_wrap_w(SamplerState::WM_border_color); + ptex->set_border_color(LColor(0, 0, 0, 0)); + break; + case aiTextureMapMode_Mirror: + ptex->set_wrap_w(SamplerState::WM_mirror); + break; + default: + break; + } + tattr = DCAST(TextureAttrib, tattr->add_on_stage(stage, ptex)); + + // Is there a texture transform? + aiUVTransform transform; + if (AI_SUCCESS == mat.Get(AI_MATKEY_UVTRANSFORM(ttype, i), transform)) { + // Reconstruct the original origin from the glTF file. + PN_stdfloat rcos, rsin; + csincos(-transform.mRotation, &rsin, &rcos); + transform.mTranslation.x -= (0.5 * transform.mScaling.x) * (-rcos + rsin + 1); + transform.mTranslation.y -= ((0.5 * transform.mScaling.y) * (rsin + rcos - 1)) + 1 - transform.mScaling.y; + + LMatrix3 matrix = + LMatrix3::translate_mat(0, -1) * + LMatrix3::scale_mat(transform.mScaling.x, transform.mScaling.y) * + LMatrix3::rotate_mat(rad_2_deg(-transform.mRotation)) * + LMatrix3::translate_mat(transform.mTranslation.x, 1 + transform.mTranslation.y); + + CPT(TransformState) cstate = + TransformState::make_mat3(matrix); + + CPT(RenderAttrib) new_attr = (tmattr == nullptr) + ? TexMatrixAttrib::make(stage, std::move(cstate)) + : tmattr->add_stage(stage, std::move(cstate)); + tmattr = DCAST(TexMatrixAttrib, std::move(new_attr)); + } } } } @@ -369,7 +497,7 @@ load_material(size_t index) { CPT(RenderState) state = RenderState::make_empty(); - aiColor3D col; + aiColor4D col; bool have; int ival; PN_stdfloat fval; @@ -379,7 +507,11 @@ load_material(size_t index) { // First do the material attribute. PT(Material) pmat = new Material; have = false; - if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_DIFFUSE, col)) { + if (AI_SUCCESS == mat.Get(AI_MATKEY_BASE_COLOR, col)) { + pmat->set_base_color(LColor(col.r, col.g, col.b, col.a)); + have = true; + } + else if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_DIFFUSE, col)) { pmat->set_diffuse(LColor(col.r, col.g, col.b, 1)); have = true; } @@ -391,6 +523,13 @@ load_material(size_t index) { } have = true; } + //else { + // if (AI_SUCCESS == mat.Get(AI_MATKEY_SHININESS_STRENGTH, fval)) { + // pmat->set_specular(LColor(fval, fval, fval, 1)); + // } else { + // pmat->set_specular(LColor(1, 1, 1, 1)); + // } + //} if (AI_SUCCESS == mat.Get(AI_MATKEY_COLOR_AMBIENT, col)) { pmat->set_specular(LColor(col.r, col.g, col.b, 1)); have = true; @@ -406,6 +545,22 @@ load_material(size_t index) { pmat->set_shininess(fval); have = true; } + if (AI_SUCCESS == mat.Get(AI_MATKEY_METALLIC_FACTOR, fval)) { + pmat->set_metallic(fval); + have = true; + } + if (AI_SUCCESS == mat.Get(AI_MATKEY_ROUGHNESS_FACTOR, fval)) { + pmat->set_roughness(fval); + have = true; + } + if (AI_SUCCESS == mat.Get(AI_MATKEY_REFRACTI, fval)) { + pmat->set_refractive_index(fval); + have = true; + } + else if (pmat->has_metallic()) { + // Default refractive index to 1.5 for PBR models + pmat->set_refractive_index(1.5); + } if (have) { state = state->add_attrib(MaterialAttrib::make(pmat)); } @@ -429,15 +584,44 @@ load_material(size_t index) { } } + // Alpha mode. + aiString alpha_mode; + if (AI_SUCCESS == mat.Get(AI_MATKEY_GLTF_ALPHAMODE, alpha_mode)) { + if (strcmp(alpha_mode.C_Str(), "MASK") == 0) { + PN_stdfloat cutoff = 0.5; + mat.Get(AI_MATKEY_GLTF_ALPHACUTOFF, cutoff); + state = state->add_attrib(AlphaTestAttrib::make(AlphaTestAttrib::M_greater_equal, cutoff)); + } + else if (strcmp(alpha_mode.C_Str(), "BLEND") == 0) { + state = state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha)); + } + } + // And let's not forget the textures! CPT(TextureAttrib) tattr = DCAST(TextureAttrib, TextureAttrib::make()); - load_texture_stage(mat, aiTextureType_DIFFUSE, tattr); - load_texture_stage(mat, aiTextureType_LIGHTMAP, tattr); + CPT(TexMatrixAttrib) tmattr; + load_texture_stage(mat, aiTextureType_DIFFUSE, TextureStage::M_modulate, tattr, tmattr); + + // Check for an ORM map, from the glTF/OBJ importer. glTF also puts it in the + // LIGHTMAP slot, despite only having the lightmap in the red channel, so we + // have to ignore it. + if (mat.GetTextureCount(aiTextureType_UNKNOWN) > 0) { + load_texture_stage(mat, aiTextureType_UNKNOWN, TextureStage::M_selector, tattr, tmattr); + } else { + load_texture_stage(mat, aiTextureType_LIGHTMAP, TextureStage::M_modulate, tattr, tmattr); + } + + load_texture_stage(mat, aiTextureType_NORMALS, TextureStage::M_normal, tattr, tmattr); + load_texture_stage(mat, aiTextureType_EMISSIVE, TextureStage::M_emission, tattr, tmattr); + load_texture_stage(mat, aiTextureType_HEIGHT, TextureStage::M_height, tattr, tmattr); if (tattr->get_num_on_stages() > 0) { state = state->add_attrib(tattr); } + if (tmattr != nullptr) { + state = state->add_attrib(tmattr); + } - _mat_states[index] = state; + _mat_states[index] = std::move(state); } /** @@ -634,6 +818,10 @@ load_mesh(size_t index) { aformat->add_column(InternalName::get_texcoord_name(out.str()), 3, Geom::NT_stdfloat, Geom::C_texcoord); } } + if (mesh.HasTangentsAndBitangents()) { + aformat->add_column(InternalName::get_tangent(), 3, Geom::NT_stdfloat, Geom::C_vector); + aformat->add_column(InternalName::get_binormal(), 3, Geom::NT_stdfloat, Geom::C_vector); + } PT(GeomVertexArrayFormat) tb_aformat = new GeomVertexArrayFormat; tb_aformat->add_column(InternalName::make("transform_blend"), 1, Geom::NT_uint16, Geom::C_index); @@ -737,7 +925,7 @@ load_mesh(size_t index) { GeomVertexWriter vertex (vdata, InternalName::get_vertex()); for (size_t i = 0; i < mesh.mNumVertices; ++i) { const aiVector3D &vec = mesh.mVertices[i]; - vertex.add_data3(vec.x, vec.y, vec.z); + vertex.set_data3(vec.x, vec.y, vec.z); } // Now the normals, if any. @@ -745,7 +933,7 @@ load_mesh(size_t index) { GeomVertexWriter normal (vdata, InternalName::get_normal()); for (size_t i = 0; i < mesh.mNumVertices; ++i) { const aiVector3D &vec = mesh.mNormals[i]; - normal.add_data3(vec.x, vec.y, vec.z); + normal.set_data3(vec.x, vec.y, vec.z); } } @@ -754,7 +942,7 @@ load_mesh(size_t index) { GeomVertexWriter color (vdata, InternalName::get_color()); for (size_t i = 0; i < mesh.mNumVertices; ++i) { const aiColor4D &col = mesh.mColors[0][i]; - color.add_data4(col.r, col.g, col.b, col.a); + color.set_data4(col.r, col.g, col.b, col.a); } } @@ -764,7 +952,7 @@ load_mesh(size_t index) { GeomVertexWriter texcoord0 (vdata, InternalName::get_texcoord()); for (size_t i = 0; i < mesh.mNumVertices; ++i) { const aiVector3D &vec = mesh.mTextureCoords[0][i]; - texcoord0.add_data3(vec.x, vec.y, vec.z); + texcoord0.set_data3(vec.x, vec.y, vec.z); } for (unsigned int u = 1; u < num_uvs; ++u) { ostringstream out; @@ -772,11 +960,23 @@ load_mesh(size_t index) { GeomVertexWriter texcoord (vdata, InternalName::get_texcoord_name(out.str())); for (size_t i = 0; i < mesh.mNumVertices; ++i) { const aiVector3D &vec = mesh.mTextureCoords[u][i]; - texcoord.add_data3(vec.x, vec.y, vec.z); + texcoord.set_data3(vec.x, vec.y, vec.z); } } } + // Now the tangents and bitangents, if any. + if (mesh.HasTangentsAndBitangents()) { + GeomVertexWriter tangent (vdata, InternalName::get_tangent()); + GeomVertexWriter binormal (vdata, InternalName::get_binormal()); + for (size_t i = 0; i < mesh.mNumVertices; ++i) { + const aiVector3D &tvec = mesh.mTangents[i]; + const aiVector3D &bvec = mesh.mBitangents[i]; + tangent.set_data3(tvec.x, tvec.y, tvec.z); + binormal.set_data3(bvec.x, bvec.y, bvec.z); + } + } + // Now the transform blend table if (character) { GeomVertexWriter transform_blend (vdata, InternalName::get_transform_blend()); @@ -787,7 +987,7 @@ load_mesh(size_t index) { for (size_t j = 0; j < bone_weights[i].size(); ++j) { tblend.add_transform(bone_weights[i][j].joint_vertex_xform, bone_weights[i][j].weight); } - transform_blend.add_data1i(tbtable->add_blend(tblend)); + transform_blend.set_data1i(tbtable->add_blend(tblend)); } tbtable->set_rows(SparseArray::lower_on(vdata->get_num_rows())); @@ -868,10 +1068,16 @@ load_node(const aiNode &node, PandaNode *parent, bool under_joint) { bool prune = false; if (node.mNumMeshes == 0) { - pnode = new PandaNode(name); + if (parent == _root && assimp_collapse_dummy_root_node && !under_joint && + (name.empty() || name[0] == '$' || name == "RootNode" || name == "ROOT" || name == "Root" || (name.size() > 2 && name[0] == '<' && name[name.size() - 1] == '>') || name == _root->get_name())) { + // Collapse root node. + pnode = _root; + } else { + pnode = new PandaNode(name); - // Possibly prune this if this is a joint or under a joint. - prune = under_joint; + // Possibly prune this if this is a joint or under a joint. + prune = under_joint; + } } else if (node.mNumMeshes == 1) { size_t meshIndex = node.mMeshes[0]; @@ -933,7 +1139,47 @@ load_node(const aiNode &node, PandaNode *parent, bool under_joint) { } } - parent->add_child(pnode); + if (parent != pnode) { + parent->add_child(pnode); + } + + if (node.mMetaData != nullptr) { + for (unsigned i = 0; i < node.mMetaData->mNumProperties; ++i) { + const aiMetadataEntry &entry = node.mMetaData->mValues[i]; + std::string value; + switch (entry.mType) { + //case AI_BOOL: + // value = (*static_cast(entry.mData)) ? "1" : ""; + // break; + case (aiMetadataType)1: // AI_INT32 + value = format_string(*static_cast(entry.mData)); + break; + case AI_UINT64: + value = format_string(*static_cast(entry.mData)); + break; + case AI_FLOAT: + value = format_string(*static_cast(entry.mData)); + break; + case AI_AISTRING: + { + const aiString *str = static_cast(entry.mData); + value = std::string(str->data, str->length); + } + break; + default: + // Special case because AI_DOUBLE was added in Assimp 4.0 with the same + // value as AI_AISTRING. Defined as if so that we don't get a duplicate + // case error with moder ncompilers. + if (entry.mType == (aiMetadataType)4) { + value = format_string(*static_cast(entry.mData)); + break; + } + continue; + } + const aiString &key = node.mMetaData->mKeys[i]; + pnode->set_tag(std::string(key.data, key.length), std::move(value)); + } + } // Load in the transformation matrix. const aiMatrix4x4 &t = node.mTransformation; diff --git a/pandatool/src/assimp/assimpLoader.h b/pandatool/src/assimp/assimpLoader.h index 807dc219fa..906a9b5fa9 100644 --- a/pandatool/src/assimp/assimpLoader.h +++ b/pandatool/src/assimp/assimpLoader.h @@ -18,6 +18,7 @@ #include "filename.h" #include "modelRoot.h" #include "texture.h" +#include "textureStage.h" #include "pmap.h" #include @@ -71,7 +72,9 @@ private: const aiNode *find_node(const aiNode &root, const aiString &name); void load_texture(size_t index); - void load_texture_stage(const aiMaterial &mat, const aiTextureType &ttype, CPT(TextureAttrib) &tattr); + void load_texture_stage(const aiMaterial &mat, const aiTextureType &ttype, + TextureStage::Mode mode, CPT(TextureAttrib) &tattr, + CPT(TexMatrixAttrib) &tmattr); void load_material(size_t index); void create_joint(Character *character, CharacterJointBundle *bundle, PartGroup *parent, const aiNode &node); void create_anim_channel(const aiAnimation &anim, AnimBundle *bundle, AnimGroup *parent, const aiNode &node); diff --git a/pandatool/src/assimp/config_assimp.cxx b/pandatool/src/assimp/config_assimp.cxx index 2b84d2c63b..060b480d3a 100644 --- a/pandatool/src/assimp/config_assimp.cxx +++ b/pandatool/src/assimp/config_assimp.cxx @@ -52,7 +52,7 @@ ConfigVariableBool assimp_fix_infacing_normals ConfigVariableBool assimp_optimize_meshes ("assimp-optimize-meshes", true, - PRC_DESC("Removes the number of draw calls by unifying geometry with the same " + PRC_DESC("Reduces the number of draw calls by unifying geometry with the same " "materials. Especially effective in conjunction with " "assimp-optimize-graph and assimp-remove-redundant-materials.")); @@ -86,6 +86,13 @@ ConfigVariableDouble assimp_smooth_normal_angle "normals. Note that you may need to clear the model-cache after " "changing this.")); +ConfigVariableBool assimp_collapse_dummy_root_node +("assimp-collapse-dummy-root-node", false, + PRC_DESC("If set to true, collapses the root node that Assimp creates, if it " + "appears to be a synthetic dummy root node and contains no meshes. " + "This variable is new as of Panda3D 1.10.13 and will become true by " + "default as of Panda3D 1.11.0.")); + /** * Initializes the library. This must be called at least once before any of * the functions or classes in this library can be used. Normally it will be diff --git a/pandatool/src/assimp/config_assimp.h b/pandatool/src/assimp/config_assimp.h index e17e2caae6..f999a60030 100644 --- a/pandatool/src/assimp/config_assimp.h +++ b/pandatool/src/assimp/config_assimp.h @@ -33,6 +33,7 @@ extern ConfigVariableBool assimp_optimize_graph; extern ConfigVariableBool assimp_flip_winding_order; extern ConfigVariableBool assimp_gen_normals; extern ConfigVariableDouble assimp_smooth_normal_angle; +extern ConfigVariableBool assimp_collapse_dummy_root_node; extern EXPCL_ASSIMP void init_libassimp(); diff --git a/pandatool/src/assimp/pandaIOStream.cxx b/pandatool/src/assimp/pandaIOStream.cxx index ad610d608f..e8d4dc8657 100644 --- a/pandatool/src/assimp/pandaIOStream.cxx +++ b/pandatool/src/assimp/pandaIOStream.cxx @@ -27,10 +27,11 @@ PandaIOStream(std::istream &stream) : _istream(stream) { */ size_t PandaIOStream:: FileSize() const { + _istream.clear(); std::streampos cur = _istream.tellg(); _istream.seekg(0, ios::end); std::streampos end = _istream.tellg(); - _istream.seekg(cur, ios::beg); + _istream.seekg(cur); return end; } @@ -47,8 +48,14 @@ Flush() { */ size_t PandaIOStream:: Read(void *buffer, size_t size, size_t count) { - _istream.read((char*) buffer, size * count); - return _istream.gcount(); + _istream.read((char *)buffer, size * count); + + if (_istream.eof()) { + // Gracefully handle EOF. + _istream.clear(ios::eofbit); + } + + return _istream.gcount() / size; } /** diff --git a/pandatool/src/ptloader/config_ptloader.cxx b/pandatool/src/ptloader/config_ptloader.cxx index 5c02a7a146..a9c4b54dd4 100644 --- a/pandatool/src/ptloader/config_ptloader.cxx +++ b/pandatool/src/ptloader/config_ptloader.cxx @@ -80,10 +80,11 @@ init_libptloader() { LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr(); init_liblwo(); + init_libflt(); + FltToEggConverter *flt = new FltToEggConverter; reg->register_type(new LoaderFileTypePandatool(flt)); - init_libflt(); LwoToEggConverter *lwo = new LwoToEggConverter; reg->register_type(new LoaderFileTypePandatool(lwo));