From 6ade6f08ce14ea8a0413d3e3195ec29d5903fba5 Mon Sep 17 00:00:00 2001 From: Areloch Date: Thu, 19 Mar 2020 09:47:38 -0500 Subject: [PATCH] Updated Assimp Added initial behavior for ImageAssets to hold a list of GFX resources of different texture profiles to avoid mem leaks with incorrect-typed usages Added function to ImageAsset to get best-fit asset, allowing for fallbacks if the requested assetID is not found Added function to ShapeAsset to get best-fit asset, allowing for fallbacks if the requested assetID is not found Disabled fields for dynamic and static shadowmap refresh rates Moved noShape model to core/rendering/shapes to place it in a more logical module position Added an include to avoid undefined type compile error and removed unneeded semicolon from zone code Added call to reload probe textures when a reloadTextures call is made Adjusted default directional light shadowmap settings to not be as extreme Added utility function to probe manager to allow any class to request a 'best fit' list of probes that would affect a given location, allowing other classes such as fog or particles to utilize IBL. Also updated probeManager's forward rendering to utilize same function to reduce code duplication. Shifted shape loader code to utilize assimp for loader consistency and testing Changed render bin used for SSAO postfx so it runs at the right time Made Core_Rendering module scan for assets Updated loose file references to a number of assets to follow proper formatting Refactored asset import code to follow a more consistent object heirarchy structure on importing assets, allowing more reliable cross-referencing between inbound items Updated asset import logic for materials/images so that they properly utilize ImageType. Images correctly save out the assigned image type, materials reference the images' type to know what map slot they should be used in. Importer logic also updated to better find-and-add associated images based on type. Cleaned up a bunch of old, outdated code in the asset importer Added initial handling for in-place importing of files without needing to process them through the UI. Added ability to edit module script from RMB context menu if torsion path is set Updated list field code for variable inspector to utilize correct ownerObject field --- Engine/lib/assimp/code/3DS/3DSConverter.cpp | 2 +- Engine/lib/assimp/code/3DS/3DSExporter.cpp | 2 +- Engine/lib/assimp/code/3DS/3DSExporter.h | 2 +- Engine/lib/assimp/code/3DS/3DSHelper.h | 2 +- Engine/lib/assimp/code/3DS/3DSLoader.cpp | 2 +- Engine/lib/assimp/code/3DS/3DSLoader.h | 2 +- Engine/lib/assimp/code/3MF/3MFXmlTags.h | 2 +- Engine/lib/assimp/code/3MF/D3MFExporter.cpp | 2 +- Engine/lib/assimp/code/3MF/D3MFExporter.h | 2 +- Engine/lib/assimp/code/3MF/D3MFImporter.cpp | 2 +- Engine/lib/assimp/code/3MF/D3MFImporter.h | 2 +- Engine/lib/assimp/code/3MF/D3MFOpcPackage.cpp | 2 +- Engine/lib/assimp/code/3MF/D3MFOpcPackage.h | 2 +- Engine/lib/assimp/code/AC/ACLoader.cpp | 2 +- Engine/lib/assimp/code/AC/ACLoader.h | 2 +- Engine/lib/assimp/code/AMF/AMFImporter.cpp | 2 +- Engine/lib/assimp/code/AMF/AMFImporter.hpp | 2 +- .../assimp/code/AMF/AMFImporter_Geometry.cpp | 2 +- .../lib/assimp/code/AMF/AMFImporter_Macro.hpp | 2 +- .../assimp/code/AMF/AMFImporter_Material.cpp | 2 +- .../lib/assimp/code/AMF/AMFImporter_Node.hpp | 2 +- .../code/AMF/AMFImporter_Postprocess.cpp | 2 +- Engine/lib/assimp/code/ASE/ASELoader.cpp | 2 +- Engine/lib/assimp/code/ASE/ASELoader.h | 2 +- Engine/lib/assimp/code/ASE/ASEParser.cpp | 2 +- Engine/lib/assimp/code/ASE/ASEParser.h | 2 +- .../lib/assimp/code/Assbin/AssbinExporter.cpp | 797 +--- .../lib/assimp/code/Assbin/AssbinExporter.h | 2 +- .../assimp/code/Assbin/AssbinFileWriter.cpp | 858 +++++ .../lib/assimp/code/Assbin/AssbinFileWriter.h | 66 + .../lib/assimp/code/Assbin/AssbinLoader.cpp | 4 +- Engine/lib/assimp/code/Assbin/AssbinLoader.h | 2 +- Engine/lib/assimp/code/Assjson/cencode.c | 10 +- .../lib/assimp/code/Assxml/AssxmlExporter.cpp | 603 +-- .../lib/assimp/code/Assxml/AssxmlExporter.h | 2 +- .../assimp/code/Assxml/AssxmlFileWriter.cpp | 664 ++++ .../lib/assimp/code/Assxml/AssxmlFileWriter.h | 65 + Engine/lib/assimp/code/B3D/B3DImporter.cpp | 185 +- Engine/lib/assimp/code/B3D/B3DImporter.h | 2 +- Engine/lib/assimp/code/BVH/BVHLoader.cpp | 2 +- Engine/lib/assimp/code/BVH/BVHLoader.h | 2 +- .../lib/assimp/code/Blender/BlenderBMesh.cpp | 2 +- Engine/lib/assimp/code/Blender/BlenderBMesh.h | 2 +- Engine/lib/assimp/code/Blender/BlenderDNA.cpp | 2 +- Engine/lib/assimp/code/Blender/BlenderDNA.h | 2 +- Engine/lib/assimp/code/Blender/BlenderDNA.inl | 2 +- .../assimp/code/Blender/BlenderIntermediate.h | 2 +- .../lib/assimp/code/Blender/BlenderLoader.cpp | 2 +- .../lib/assimp/code/Blender/BlenderLoader.h | 2 +- .../assimp/code/Blender/BlenderModifier.cpp | 2 +- .../lib/assimp/code/Blender/BlenderModifier.h | 2 +- .../lib/assimp/code/Blender/BlenderScene.cpp | 2 +- Engine/lib/assimp/code/Blender/BlenderScene.h | 2 +- .../lib/assimp/code/Blender/BlenderSceneGen.h | 2 +- .../code/Blender/BlenderTessellator.cpp | 2 +- .../assimp/code/Blender/BlenderTessellator.h | 2 +- Engine/lib/assimp/code/C4D/C4DImporter.cpp | 2 +- Engine/lib/assimp/code/C4D/C4DImporter.h | 2 +- Engine/lib/assimp/code/CApi/AssimpCExport.cpp | 2 +- .../assimp/code/CApi/CInterfaceIOWrapper.cpp | 2 +- .../assimp/code/CApi/CInterfaceIOWrapper.h | 2 +- Engine/lib/assimp/code/CMakeLists.txt | 339 +- Engine/lib/assimp/code/COB/COBLoader.cpp | 4 +- Engine/lib/assimp/code/COB/COBLoader.h | 2 +- Engine/lib/assimp/code/COB/COBScene.h | 2 +- Engine/lib/assimp/code/CSM/CSMLoader.cpp | 4 +- Engine/lib/assimp/code/CSM/CSMLoader.h | 2 +- .../assimp/code/Collada/ColladaExporter.cpp | 7 +- .../lib/assimp/code/Collada/ColladaExporter.h | 2 +- .../lib/assimp/code/Collada/ColladaHelper.cpp | 107 + .../lib/assimp/code/Collada/ColladaHelper.h | 40 +- .../lib/assimp/code/Collada/ColladaLoader.cpp | 28 +- .../lib/assimp/code/Collada/ColladaLoader.h | 2 +- .../lib/assimp/code/Collada/ColladaParser.cpp | 150 +- .../lib/assimp/code/Collada/ColladaParser.h | 7 +- Engine/lib/assimp/code/Common/Assimp.cpp | 2 +- .../lib/assimp/code/Common/BaseImporter.cpp | 9 +- Engine/lib/assimp/code/Common/BaseProcess.cpp | 41 +- Engine/lib/assimp/code/Common/BaseProcess.h | 131 +- Engine/lib/assimp/code/Common/Bitmap.cpp | 2 +- .../lib/assimp/code/Common/CreateAnimMesh.cpp | 2 +- .../assimp/code/Common/DefaultIOStream.cpp | 2 +- .../assimp/code/Common/DefaultIOSystem.cpp | 2 +- .../lib/assimp/code/Common/DefaultLogger.cpp | 6 +- .../code/Common/DefaultProgressHandler.h | 2 +- Engine/lib/assimp/code/Common/Exporter.cpp | 9 +- Engine/lib/assimp/code/Common/FileLogStream.h | 2 +- .../lib/assimp/code/Common/FileSystemFilter.h | 2 +- Engine/lib/assimp/code/Common/Importer.cpp | 292 +- Engine/lib/assimp/code/Common/Importer.h | 2 +- .../assimp/code/Common/ImporterRegistry.cpp | 2 +- Engine/lib/assimp/code/Common/PolyTools.h | 2 +- .../assimp/code/Common/PostStepRegistry.cpp | 4 +- .../lib/assimp/code/Common/RemoveComments.cpp | 2 +- .../lib/assimp/code/Common/SGSpatialSort.cpp | 2 +- .../lib/assimp/code/Common/SceneCombiner.cpp | 3 +- .../assimp/code/Common/ScenePreprocessor.cpp | 11 +- .../assimp/code/Common/ScenePreprocessor.h | 2 +- Engine/lib/assimp/code/Common/ScenePrivate.h | 2 +- .../code/Common/SkeletonMeshBuilder.cpp | 2 +- Engine/lib/assimp/code/Common/SpatialSort.cpp | 2 +- .../lib/assimp/code/Common/StandardShapes.cpp | 2 +- .../assimp/code/Common/StdOStreamLogStream.h | 2 +- Engine/lib/assimp/code/Common/Subdivision.cpp | 2 +- .../assimp/code/Common/TargetAnimation.cpp | 2 +- .../lib/assimp/code/Common/TargetAnimation.h | 2 +- Engine/lib/assimp/code/Common/Version.cpp | 10 +- .../code/Common/VertexTriangleAdjacency.cpp | 6 +- .../code/Common/VertexTriangleAdjacency.h | 2 +- .../assimp/code/Common/Win32DebugLogStream.h | 2 +- .../assimp/code/Common/ZipArchiveIOSystem.cpp | 4 +- Engine/lib/assimp/code/Common/assbin_chunks.h | 2 +- Engine/lib/assimp/code/Common/material.cpp | 97 + Engine/lib/assimp/code/Common/scene.cpp | 2 +- Engine/lib/assimp/code/Common/simd.cpp | 2 +- Engine/lib/assimp/code/Common/simd.h | 2 +- Engine/lib/assimp/code/DXF/DXFHelper.h | 2 +- Engine/lib/assimp/code/DXF/DXFLoader.cpp | 2 +- Engine/lib/assimp/code/DXF/DXFLoader.h | 2 +- Engine/lib/assimp/code/FBX/FBXAnimation.cpp | 2 +- .../assimp/code/FBX/FBXBinaryTokenizer.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXCommon.h | 2 +- Engine/lib/assimp/code/FBX/FBXCompileConfig.h | 2 +- Engine/lib/assimp/code/FBX/FBXConverter.cpp | 37 +- Engine/lib/assimp/code/FBX/FBXConverter.h | 4 +- Engine/lib/assimp/code/FBX/FBXDeformer.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXDocument.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXDocument.h | 2 +- .../lib/assimp/code/FBX/FBXDocumentUtil.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXDocumentUtil.h | 2 +- Engine/lib/assimp/code/FBX/FBXExportNode.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXExportNode.h | 2 +- .../lib/assimp/code/FBX/FBXExportProperty.cpp | 2 +- .../lib/assimp/code/FBX/FBXExportProperty.h | 2 +- Engine/lib/assimp/code/FBX/FBXExporter.cpp | 7 +- Engine/lib/assimp/code/FBX/FBXExporter.h | 2 +- .../lib/assimp/code/FBX/FBXImportSettings.h | 2 +- Engine/lib/assimp/code/FBX/FBXImporter.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXImporter.h | 2 +- Engine/lib/assimp/code/FBX/FBXMaterial.cpp | 2 +- .../lib/assimp/code/FBX/FBXMeshGeometry.cpp | 33 +- Engine/lib/assimp/code/FBX/FBXMeshGeometry.h | 2 +- Engine/lib/assimp/code/FBX/FBXModel.cpp | 2 +- .../lib/assimp/code/FBX/FBXNodeAttribute.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXParser.cpp | 10 +- Engine/lib/assimp/code/FBX/FBXParser.h | 2 +- Engine/lib/assimp/code/FBX/FBXProperties.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXProperties.h | 2 +- Engine/lib/assimp/code/FBX/FBXTokenizer.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXTokenizer.h | 2 +- Engine/lib/assimp/code/FBX/FBXUtil.cpp | 2 +- Engine/lib/assimp/code/FBX/FBXUtil.h | 2 +- Engine/lib/assimp/code/HMP/HMPFileData.h | 2 +- Engine/lib/assimp/code/HMP/HMPLoader.cpp | 2 +- Engine/lib/assimp/code/HMP/HMPLoader.h | 2 +- Engine/lib/assimp/code/HMP/HalfLifeFileData.h | 2 +- .../assimp/code/Importer/IFC/IFCBoolean.cpp | 2 +- .../lib/assimp/code/Importer/IFC/IFCCurve.cpp | 6 +- .../assimp/code/Importer/IFC/IFCGeometry.cpp | 7 +- .../assimp/code/Importer/IFC/IFCLoader.cpp | 2 +- .../lib/assimp/code/Importer/IFC/IFCLoader.h | 2 +- .../assimp/code/Importer/IFC/IFCMaterial.cpp | 2 +- .../assimp/code/Importer/IFC/IFCOpenings.cpp | 2 +- .../assimp/code/Importer/IFC/IFCProfile.cpp | 2 +- .../code/Importer/IFC/IFCReaderGen1_2x3.cpp | 2 +- .../code/Importer/IFC/IFCReaderGen2_2x3.cpp | 2 +- .../code/Importer/IFC/IFCReaderGen_2x3.h | 2 +- .../code/Importer/IFC/IFCReaderGen_4.cpp | 2 +- .../assimp/code/Importer/IFC/IFCReaderGen_4.h | 2 +- .../lib/assimp/code/Importer/IFC/IFCUtil.cpp | 2 +- Engine/lib/assimp/code/Importer/IFC/IFCUtil.h | 2 +- .../Importer/STEPParser/STEPFileEncoding.cpp | 2 +- .../Importer/STEPParser/STEPFileEncoding.h | 2 +- .../Importer/STEPParser/STEPFileReader.cpp | 2 +- .../code/Importer/STEPParser/STEPFileReader.h | 2 +- .../code/Importer/StepFile/StepFileGen1.cpp | 2 +- .../code/Importer/StepFile/StepFileGen2.cpp | 2 +- .../code/Importer/StepFile/StepFileGen3.cpp | 2 +- .../Importer/StepFile/StepFileImporter.cpp | 2 +- .../code/Importer/StepFile/StepFileImporter.h | 2 +- .../code/Importer/StepFile/StepReaderGen.h | 2 +- Engine/lib/assimp/code/Irr/IRRLoader.cpp | 2 +- Engine/lib/assimp/code/Irr/IRRLoader.h | 2 +- Engine/lib/assimp/code/Irr/IRRMeshLoader.cpp | 2 +- Engine/lib/assimp/code/Irr/IRRMeshLoader.h | 2 +- Engine/lib/assimp/code/Irr/IRRShared.cpp | 2 +- Engine/lib/assimp/code/LWO/LWOAnimation.cpp | 2 +- Engine/lib/assimp/code/LWO/LWOAnimation.h | 2 +- Engine/lib/assimp/code/LWO/LWOBLoader.cpp | 2 +- Engine/lib/assimp/code/LWO/LWOFileData.h | 2 +- Engine/lib/assimp/code/LWO/LWOLoader.cpp | 4 +- Engine/lib/assimp/code/LWO/LWOLoader.h | 2 +- Engine/lib/assimp/code/LWO/LWOMaterial.cpp | 2 +- Engine/lib/assimp/code/LWS/LWSLoader.cpp | 2 +- Engine/lib/assimp/code/LWS/LWSLoader.h | 2 +- Engine/lib/assimp/code/M3D/M3DExporter.cpp | 648 ++-- Engine/lib/assimp/code/M3D/M3DExporter.h | 12 +- Engine/lib/assimp/code/M3D/M3DImporter.cpp | 1145 +++--- Engine/lib/assimp/code/M3D/M3DImporter.h | 55 +- Engine/lib/assimp/code/M3D/M3DMaterials.h | 12 +- Engine/lib/assimp/code/M3D/M3DWrapper.cpp | 142 + Engine/lib/assimp/code/M3D/M3DWrapper.h | 101 + Engine/lib/assimp/code/M3D/m3d.h | 3339 +++++++++++------ Engine/lib/assimp/code/MD2/MD2FileData.h | 2 +- Engine/lib/assimp/code/MD2/MD2Loader.cpp | 2 +- Engine/lib/assimp/code/MD2/MD2Loader.h | 2 +- Engine/lib/assimp/code/MD2/MD2NormalTable.h | 2 +- Engine/lib/assimp/code/MD3/MD3FileData.h | 2 +- Engine/lib/assimp/code/MD3/MD3Loader.cpp | 4 +- Engine/lib/assimp/code/MD3/MD3Loader.h | 2 +- Engine/lib/assimp/code/MD4/MD4FileData.h | 2 +- Engine/lib/assimp/code/MD5/MD5Loader.cpp | 2 +- Engine/lib/assimp/code/MD5/MD5Loader.h | 2 +- Engine/lib/assimp/code/MD5/MD5Parser.cpp | 2 +- Engine/lib/assimp/code/MD5/MD5Parser.h | 2 +- Engine/lib/assimp/code/MDC/MDCFileData.h | 2 +- Engine/lib/assimp/code/MDC/MDCLoader.cpp | 4 +- Engine/lib/assimp/code/MDC/MDCLoader.h | 2 +- .../assimp/code/MDL/HalfLife/HL1FileData.h | 600 +++ .../code/MDL/HalfLife/HL1ImportDefinitions.h | 64 + .../code/MDL/HalfLife/HL1ImportSettings.h | 85 + .../assimp/code/MDL/HalfLife/HL1MDLLoader.cpp | 1348 +++++++ .../assimp/code/MDL/HalfLife/HL1MDLLoader.h | 241 ++ .../assimp/code/MDL/HalfLife/HL1MeshTrivert.h | 127 + .../code/MDL/HalfLife/HalfLifeMDLBaseHeader.h | 67 + .../assimp/code/MDL/HalfLife/LogFunctions.h | 95 + .../code/MDL/HalfLife/UniqueNameGenerator.cpp | 180 + .../code/MDL/HalfLife/UniqueNameGenerator.h | 81 + .../lib/assimp/code/MDL/MDLDefaultColorMap.h | 2 +- Engine/lib/assimp/code/MDL/MDLFileData.h | 2 +- Engine/lib/assimp/code/MDL/MDLLoader.cpp | 197 +- Engine/lib/assimp/code/MDL/MDLLoader.h | 12 +- .../lib/assimp/code/MDL/MDLMaterialLoader.cpp | 8 +- Engine/lib/assimp/code/MMD/MMDCpp14.h | 2 +- Engine/lib/assimp/code/MMD/MMDImporter.cpp | 2 +- Engine/lib/assimp/code/MMD/MMDImporter.h | 2 +- Engine/lib/assimp/code/MMD/MMDPmdParser.h | 2 +- Engine/lib/assimp/code/MMD/MMDPmxParser.cpp | 2 +- Engine/lib/assimp/code/MMD/MMDPmxParser.h | 2 +- Engine/lib/assimp/code/MMD/MMDVmdParser.h | 2 +- Engine/lib/assimp/code/MS3D/MS3DLoader.cpp | 2 +- Engine/lib/assimp/code/MS3D/MS3DLoader.h | 2 +- .../assimp/code/Material/MaterialSystem.cpp | 14 +- .../lib/assimp/code/Material/MaterialSystem.h | 2 +- Engine/lib/assimp/code/NDO/NDOLoader.cpp | 2 +- Engine/lib/assimp/code/NDO/NDOLoader.h | 2 +- Engine/lib/assimp/code/NFF/NFFLoader.cpp | 2 +- Engine/lib/assimp/code/NFF/NFFLoader.h | 2 +- Engine/lib/assimp/code/OFF/OFFLoader.cpp | 2 +- Engine/lib/assimp/code/OFF/OFFLoader.h | 2 +- Engine/lib/assimp/code/Obj/ObjExporter.cpp | 2 +- Engine/lib/assimp/code/Obj/ObjExporter.h | 2 +- Engine/lib/assimp/code/Obj/ObjFileData.h | 17 +- .../lib/assimp/code/Obj/ObjFileImporter.cpp | 51 +- Engine/lib/assimp/code/Obj/ObjFileImporter.h | 2 +- .../assimp/code/Obj/ObjFileMtlImporter.cpp | 6 +- .../lib/assimp/code/Obj/ObjFileMtlImporter.h | 2 +- Engine/lib/assimp/code/Obj/ObjFileParser.cpp | 50 +- Engine/lib/assimp/code/Obj/ObjFileParser.h | 4 +- Engine/lib/assimp/code/Obj/ObjTools.h | 2 +- .../assimp/code/Ogre/OgreBinarySerializer.cpp | 2 +- .../assimp/code/Ogre/OgreBinarySerializer.h | 2 +- Engine/lib/assimp/code/Ogre/OgreImporter.cpp | 2 +- Engine/lib/assimp/code/Ogre/OgreImporter.h | 2 +- Engine/lib/assimp/code/Ogre/OgreMaterial.cpp | 2 +- .../lib/assimp/code/Ogre/OgreParsingUtils.h | 2 +- Engine/lib/assimp/code/Ogre/OgreStructs.cpp | 2 +- Engine/lib/assimp/code/Ogre/OgreStructs.h | 2 +- .../assimp/code/Ogre/OgreXmlSerializer.cpp | 2 +- .../lib/assimp/code/Ogre/OgreXmlSerializer.h | 2 +- .../assimp/code/OpenGEX/OpenGEXExporter.cpp | 2 +- .../lib/assimp/code/OpenGEX/OpenGEXExporter.h | 2 +- .../assimp/code/OpenGEX/OpenGEXImporter.cpp | 2 +- .../lib/assimp/code/OpenGEX/OpenGEXImporter.h | 2 +- .../lib/assimp/code/OpenGEX/OpenGEXStructs.h | 2 +- Engine/lib/assimp/code/Ply/PlyExporter.cpp | 7 +- Engine/lib/assimp/code/Ply/PlyExporter.h | 2 +- Engine/lib/assimp/code/Ply/PlyLoader.cpp | 2 +- Engine/lib/assimp/code/Ply/PlyLoader.h | 2 +- Engine/lib/assimp/code/Ply/PlyParser.cpp | 2 +- Engine/lib/assimp/code/Ply/PlyParser.h | 2 +- .../code/PostProcessing/ArmaturePopulate.cpp | 284 +- .../code/PostProcessing/ArmaturePopulate.h | 2 +- .../PostProcessing/CalcTangentsProcess.cpp | 2 +- .../code/PostProcessing/CalcTangentsProcess.h | 2 +- .../ComputeUVMappingProcess.cpp | 2 +- .../PostProcessing/ComputeUVMappingProcess.h | 2 +- .../PostProcessing/ConvertToLHProcess.cpp | 2 +- .../code/PostProcessing/ConvertToLHProcess.h | 7 +- .../code/PostProcessing/DeboneProcess.cpp | 2 +- .../code/PostProcessing/DeboneProcess.h | 2 +- .../PostProcessing/DropFaceNormalsProcess.cpp | 2 +- .../PostProcessing/DropFaceNormalsProcess.h | 2 +- .../PostProcessing/EmbedTexturesProcess.cpp | 5 +- .../PostProcessing/EmbedTexturesProcess.h | 2 +- .../code/PostProcessing/FindDegenerates.cpp | 2 +- .../code/PostProcessing/FindDegenerates.h | 2 +- .../PostProcessing/FindInstancesProcess.cpp | 2 +- .../PostProcessing/FindInstancesProcess.h | 2 +- .../PostProcessing/FindInvalidDataProcess.cpp | 2 +- .../PostProcessing/FindInvalidDataProcess.h | 2 +- .../code/PostProcessing/FixNormalsStep.cpp | 2 +- .../code/PostProcessing/FixNormalsStep.h | 2 +- .../GenBoundingBoxesProcess.cpp | 2 +- .../PostProcessing/GenBoundingBoxesProcess.h | 2 +- .../PostProcessing/GenFaceNormalsProcess.cpp | 2 +- .../PostProcessing/GenFaceNormalsProcess.h | 2 +- .../GenVertexNormalsProcess.cpp | 2 +- .../PostProcessing/GenVertexNormalsProcess.h | 2 +- .../PostProcessing/ImproveCacheLocality.cpp | 2 +- .../PostProcessing/ImproveCacheLocality.h | 2 +- .../PostProcessing/JoinVerticesProcess.cpp | 2 +- .../code/PostProcessing/JoinVerticesProcess.h | 2 +- .../LimitBoneWeightsProcess.cpp | 2 +- .../PostProcessing/LimitBoneWeightsProcess.h | 2 +- .../code/PostProcessing/MakeVerboseFormat.cpp | 2 +- .../code/PostProcessing/MakeVerboseFormat.h | 2 +- .../code/PostProcessing/OptimizeGraph.cpp | 431 +-- .../code/PostProcessing/OptimizeGraph.h | 8 +- .../code/PostProcessing/OptimizeMeshes.cpp | 2 +- .../code/PostProcessing/OptimizeMeshes.h | 2 +- .../PostProcessing/PretransformVertices.cpp | 1040 +++-- .../PostProcessing/PretransformVertices.h | 144 +- .../code/PostProcessing/ProcessHelper.cpp | 42 +- .../code/PostProcessing/ProcessHelper.h | 8 +- .../RemoveRedundantMaterials.cpp | 2 +- .../PostProcessing/RemoveRedundantMaterials.h | 2 +- .../code/PostProcessing/RemoveVCProcess.cpp | 2 +- .../code/PostProcessing/RemoveVCProcess.h | 2 +- .../code/PostProcessing/ScaleProcess.cpp | 2 +- .../assimp/code/PostProcessing/ScaleProcess.h | 2 +- .../PostProcessing/SortByPTypeProcess.cpp | 2 +- .../code/PostProcessing/SortByPTypeProcess.h | 2 +- .../SplitByBoneCountProcess.cpp | 447 +++ .../PostProcessing/SplitByBoneCountProcess.h | 111 + .../code/PostProcessing/SplitLargeMeshes.cpp | 2 +- .../code/PostProcessing/SplitLargeMeshes.h | 2 +- .../code/PostProcessing/TextureTransform.cpp | 10 +- .../code/PostProcessing/TextureTransform.h | 2 +- .../PostProcessing/TriangulateProcess.cpp | 2 +- .../code/PostProcessing/TriangulateProcess.h | 2 +- .../PostProcessing/ValidateDataStructure.cpp | 23 +- .../PostProcessing/ValidateDataStructure.h | 2 +- Engine/lib/assimp/code/Q3BSP/Q3BSPFileData.h | 2 +- .../assimp/code/Q3BSP/Q3BSPFileImporter.cpp | 4 +- .../lib/assimp/code/Q3BSP/Q3BSPFileImporter.h | 2 +- .../lib/assimp/code/Q3BSP/Q3BSPFileParser.cpp | 2 +- .../lib/assimp/code/Q3BSP/Q3BSPFileParser.h | 2 +- Engine/lib/assimp/code/Q3D/Q3DLoader.cpp | 2 +- Engine/lib/assimp/code/Q3D/Q3DLoader.h | 2 +- Engine/lib/assimp/code/Raw/RawLoader.cpp | 2 +- Engine/lib/assimp/code/Raw/RawLoader.h | 2 +- Engine/lib/assimp/code/SIB/SIBImporter.cpp | 2 +- Engine/lib/assimp/code/SIB/SIBImporter.h | 2 +- Engine/lib/assimp/code/SMD/SMDLoader.cpp | 6 +- Engine/lib/assimp/code/SMD/SMDLoader.h | 2 +- Engine/lib/assimp/code/STL/STLExporter.cpp | 2 +- Engine/lib/assimp/code/STL/STLExporter.h | 2 +- Engine/lib/assimp/code/STL/STLLoader.cpp | 2 +- Engine/lib/assimp/code/STL/STLLoader.h | 2 +- Engine/lib/assimp/code/Step/STEPFile.h | 2 +- Engine/lib/assimp/code/Step/StepExporter.cpp | 2 +- Engine/lib/assimp/code/Step/StepExporter.h | 2 +- .../assimp/code/Terragen/TerragenLoader.cpp | 2 +- .../lib/assimp/code/Terragen/TerragenLoader.h | 2 +- .../lib/assimp/code/Unreal/UnrealLoader.cpp | 4 +- Engine/lib/assimp/code/Unreal/UnrealLoader.h | 2 +- Engine/lib/assimp/code/X/XFileExporter.cpp | 2 +- Engine/lib/assimp/code/X/XFileExporter.h | 2 +- Engine/lib/assimp/code/X/XFileHelper.h | 2 +- Engine/lib/assimp/code/X/XFileImporter.cpp | 38 +- Engine/lib/assimp/code/X/XFileImporter.h | 2 +- Engine/lib/assimp/code/X/XFileParser.cpp | 2 +- Engine/lib/assimp/code/X/XFileParser.h | 2 +- Engine/lib/assimp/code/X3D/FIReader.cpp | 2 +- Engine/lib/assimp/code/X3D/FIReader.hpp | 2 +- Engine/lib/assimp/code/X3D/X3DImporter.cpp | 2 +- Engine/lib/assimp/code/X3D/X3DImporter.hpp | 2 +- .../code/X3D/X3DImporter_Geometry2D.cpp | 2 +- .../code/X3D/X3DImporter_Geometry3D.cpp | 2 +- .../lib/assimp/code/X3D/X3DImporter_Group.cpp | 2 +- .../lib/assimp/code/X3D/X3DImporter_Light.cpp | 2 +- .../lib/assimp/code/X3D/X3DImporter_Macro.hpp | 2 +- .../assimp/code/X3D/X3DImporter_Metadata.cpp | 2 +- .../code/X3D/X3DImporter_Networking.cpp | 2 +- .../lib/assimp/code/X3D/X3DImporter_Node.hpp | 2 +- .../code/X3D/X3DImporter_Postprocess.cpp | 2 +- .../assimp/code/X3D/X3DImporter_Rendering.cpp | 2 +- .../lib/assimp/code/X3D/X3DImporter_Shape.cpp | 2 +- .../assimp/code/X3D/X3DImporter_Texturing.cpp | 2 +- Engine/lib/assimp/code/X3D/X3DVocabulary.cpp | 2 +- Engine/lib/assimp/code/XGL/XGLLoader.cpp | 4 +- Engine/lib/assimp/code/XGL/XGLLoader.h | 2 +- Engine/lib/assimp/code/glTF/glTFAsset.h | 9 +- Engine/lib/assimp/code/glTF/glTFAsset.inl | 11 +- Engine/lib/assimp/code/glTF/glTFAssetWriter.h | 2 +- .../lib/assimp/code/glTF/glTFAssetWriter.inl | 35 +- Engine/lib/assimp/code/glTF/glTFCommon.cpp | 2 +- Engine/lib/assimp/code/glTF/glTFCommon.h | 19 +- Engine/lib/assimp/code/glTF/glTFExporter.cpp | 123 +- Engine/lib/assimp/code/glTF/glTFExporter.h | 4 +- Engine/lib/assimp/code/glTF/glTFImporter.cpp | 31 +- Engine/lib/assimp/code/glTF/glTFImporter.h | 4 +- Engine/lib/assimp/code/glTF2/glTF2Asset.h | 26 +- Engine/lib/assimp/code/glTF2/glTF2Asset.inl | 82 +- .../lib/assimp/code/glTF2/glTF2AssetWriter.h | 2 +- .../assimp/code/glTF2/glTF2AssetWriter.inl | 61 +- .../lib/assimp/code/glTF2/glTF2Exporter.cpp | 187 +- Engine/lib/assimp/code/glTF2/glTF2Exporter.h | 3 +- .../lib/assimp/code/glTF2/glTF2Importer.cpp | 2143 ++++++----- Engine/lib/assimp/code/glTF2/glTF2Importer.h | 3 +- Engine/lib/assimp/code/res/assimp.rc | 2 +- Engine/lib/assimp/contrib/CMakeLists.txt | 2 +- Engine/lib/assimp/contrib/zip/CMakeLists.txt | 79 +- Engine/lib/assimp/contrib/zip/README.md | 63 +- Engine/lib/assimp/contrib/zip/src/miniz.h | 459 ++- Engine/lib/assimp/contrib/zip/src/zip.c | 79 +- Engine/lib/assimp/contrib/zip/src/zip.h | 464 +-- .../assimp/contrib/zip/test/CMakeLists.txt | 22 +- Engine/lib/assimp/contrib/zip/test/test.c | 42 +- .../lib/assimp/contrib/zip/test/test_miniz.c | 25 +- .../lib/assimp/include/assimp/BaseImporter.h | 2 +- Engine/lib/assimp/include/assimp/Bitmap.h | 2 +- .../lib/assimp/include/assimp/BlobIOSystem.h | 2 +- .../lib/assimp/include/assimp/ByteSwapper.h | 2 +- .../assimp/include/assimp/CreateAnimMesh.h | 2 +- .../assimp/include/assimp/DefaultIOStream.h | 2 +- .../assimp/include/assimp/DefaultIOSystem.h | 2 +- .../assimp/include/assimp/DefaultLogger.hpp | 2 +- Engine/lib/assimp/include/assimp/Defines.h | 2 +- .../lib/assimp/include/assimp/Exceptional.h | 12 +- Engine/lib/assimp/include/assimp/Exporter.hpp | 2 +- .../assimp/include/assimp/GenericProperty.h | 41 +- Engine/lib/assimp/include/assimp/Hash.h | 2 +- Engine/lib/assimp/include/assimp/IOStream.hpp | 2 +- .../assimp/include/assimp/IOStreamBuffer.h | 2 +- Engine/lib/assimp/include/assimp/IOSystem.hpp | 2 +- Engine/lib/assimp/include/assimp/Importer.hpp | 6 +- .../lib/assimp/include/assimp/LineSplitter.h | 4 +- Engine/lib/assimp/include/assimp/LogAux.h | 2 +- .../lib/assimp/include/assimp/LogStream.hpp | 2 +- Engine/lib/assimp/include/assimp/Logger.hpp | 2 +- .../lib/assimp/include/assimp/MathFunctions.h | 2 +- .../assimp/include/assimp/MemoryIOWrapper.h | 2 +- .../lib/assimp/include/assimp/NullLogger.hpp | 2 +- .../lib/assimp/include/assimp/ParsingUtils.h | 2 +- Engine/lib/assimp/include/assimp/Profiler.h | 2 +- .../assimp/include/assimp/ProgressHandler.hpp | 2 +- .../assimp/include/assimp/RemoveComments.h | 2 +- .../lib/assimp/include/assimp/SGSpatialSort.h | 2 +- .../lib/assimp/include/assimp/SceneCombiner.h | 2 +- .../include/assimp/SkeletonMeshBuilder.h | 2 +- .../assimp/include/assimp/SmoothingGroups.h | 2 +- .../assimp/include/assimp/SmoothingGroups.inl | 2 +- .../lib/assimp/include/assimp/SpatialSort.h | 2 +- .../assimp/include/assimp/StandardShapes.h | 2 +- .../lib/assimp/include/assimp/StreamReader.h | 2 +- .../lib/assimp/include/assimp/StreamWriter.h | 2 +- .../assimp/include/assimp/StringComparison.h | 2 +- .../lib/assimp/include/assimp/StringUtils.h | 2 +- .../lib/assimp/include/assimp/Subdivision.h | 2 +- .../lib/assimp/include/assimp/TinyFormatter.h | 2 +- Engine/lib/assimp/include/assimp/Vertex.h | 2 +- Engine/lib/assimp/include/assimp/XMLTools.h | 2 +- .../include/assimp/ZipArchiveIOSystem.h | 2 +- Engine/lib/assimp/include/assimp/aabb.h | 2 +- Engine/lib/assimp/include/assimp/ai_assert.h | 2 +- Engine/lib/assimp/include/assimp/anim.h | 2 +- Engine/lib/assimp/include/assimp/camera.h | 2 +- Engine/lib/assimp/include/assimp/cexport.h | 2 +- Engine/lib/assimp/include/assimp/cfileio.h | 2 +- Engine/lib/assimp/include/assimp/cimport.h | 2 +- Engine/lib/assimp/include/assimp/color4.h | 2 +- Engine/lib/assimp/include/assimp/color4.inl | 2 +- .../assimp/include/assimp/commonMetaData.h | 67 + Engine/lib/assimp/include/assimp/config.h.in | 69 +- Engine/lib/assimp/include/assimp/defs.h | 8 +- .../lib/assimp/include/assimp/importerdesc.h | 2 +- .../lib/assimp/include/assimp/irrXMLWrapper.h | 2 +- Engine/lib/assimp/include/assimp/light.h | 2 +- Engine/lib/assimp/include/assimp/material.h | 6 +- Engine/lib/assimp/include/assimp/material.inl | 2 +- Engine/lib/assimp/include/assimp/matrix3x3.h | 8 +- .../lib/assimp/include/assimp/matrix3x3.inl | 8 +- Engine/lib/assimp/include/assimp/matrix4x4.h | 2 +- .../lib/assimp/include/assimp/matrix4x4.inl | 2 +- Engine/lib/assimp/include/assimp/mesh.h | 2 +- Engine/lib/assimp/include/assimp/metadata.h | 23 +- .../lib/assimp/include/assimp/pbrmaterial.h | 2 +- .../port/AndroidJNI/AndroidJNIIOSystem.h | 2 +- .../lib/assimp/include/assimp/postprocess.h | 2 +- Engine/lib/assimp/include/assimp/qnan.h | 2 +- Engine/lib/assimp/include/assimp/quaternion.h | 2 +- .../lib/assimp/include/assimp/quaternion.inl | 2 +- Engine/lib/assimp/include/assimp/scene.h | 2 +- Engine/lib/assimp/include/assimp/texture.h | 5 +- Engine/lib/assimp/include/assimp/types.h | 2 +- Engine/lib/assimp/include/assimp/vector2.h | 2 +- Engine/lib/assimp/include/assimp/vector2.inl | 2 +- Engine/lib/assimp/include/assimp/vector3.h | 2 +- Engine/lib/assimp/include/assimp/vector3.inl | 2 +- Engine/lib/assimp/include/assimp/version.h | 9 +- Engine/source/T3D/assets/ImageAsset.cpp | 65 + Engine/source/T3D/assets/ImageAsset.h | 11 +- Engine/source/T3D/assets/ShapeAsset.cpp | 60 + Engine/source/T3D/assets/ShapeAsset.h | 3 + Engine/source/T3D/fx/groundCover.cpp | 2 +- Engine/source/T3D/fx/particleEmitter.cpp | 2 + Engine/source/T3D/lightBase.cpp | 4 +- Engine/source/T3D/shapeImage.cpp | 2 +- Engine/source/T3D/zone.cpp | 6 +- Engine/source/environment/sun.cpp | 4 +- Engine/source/gfx/gfxTextureManager.cpp | 2 + .../lighting/shadowMap/lightShadowMap.cpp | 6 +- Engine/source/materials/materialList.cpp | 12 +- Engine/source/materials/processedMaterial.cpp | 2 +- .../source/renderInstance/renderPassManager.h | 2 + .../source/renderInstance/renderProbeMgr.cpp | 198 +- Engine/source/renderInstance/renderProbeMgr.h | 54 + Engine/source/ts/tsShape.cpp | 4 +- Engine/source/util/fpsTracker.cpp | 2 + .../game/core/postFX/scripts/SSAOPostFx.cs | 2 +- .../game/core/rendering/Core_Rendering.module | 5 + .../core/{ => rendering}/shapes/materials.cs | 0 .../core/rendering/shapes/noshape.asset.taml | 6 + .../core/{ => rendering}/shapes/noshape.dts | Bin .../core/{ => rendering}/shapes/noshape.mb | Bin .../game/core/utility/scripts/globals.cs | 2 +- .../levels/ExampleLevel.asset.taml | 3 +- .../BaseGame/game/tools/assetBrowser/main.cs | 12 +- .../assetBrowser/scripts/assetBrowser.cs | 20 - .../tools/assetBrowser/scripts/assetImport.cs | 1527 ++++---- .../assetBrowser/scripts/assetImportConfig.cs | 4 - .../scripts/assetImportConfigEditor.cs | 8 +- .../assetBrowser/scripts/assetTypes/image.cs | 229 +- .../scripts/assetTypes/material.cs | 147 +- .../assetBrowser/scripts/assetTypes/shape.cs | 61 +- .../tools/assetBrowser/scripts/editModule.cs | 9 + .../assetBrowser/scripts/looseFileAudit.cs | 3 +- .../tools/assetBrowser/scripts/popupMenus.cs | 17 +- .../game/tools/base/images/materials.cs | 5 +- .../game/tools/forestEditor/brushes.cs | 3 + .../game/tools/gui/editorSettingsWindow.ed.cs | 1 - .../game/tools/gui/fieldTypes/listField.cs | 2 +- Tools/CMake/libraries/assimp.cmake | 8 +- 545 files changed, 15077 insertions(+), 8437 deletions(-) create mode 100644 Engine/lib/assimp/code/Assbin/AssbinFileWriter.cpp create mode 100644 Engine/lib/assimp/code/Assbin/AssbinFileWriter.h create mode 100644 Engine/lib/assimp/code/Assxml/AssxmlFileWriter.cpp create mode 100644 Engine/lib/assimp/code/Assxml/AssxmlFileWriter.h create mode 100644 Engine/lib/assimp/code/Collada/ColladaHelper.cpp create mode 100644 Engine/lib/assimp/code/Common/material.cpp create mode 100644 Engine/lib/assimp/code/M3D/M3DWrapper.cpp create mode 100644 Engine/lib/assimp/code/M3D/M3DWrapper.h create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/HL1FileData.h create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/HL1ImportDefinitions.h create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/HL1ImportSettings.h create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.cpp create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.h create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/HL1MeshTrivert.h create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/HalfLifeMDLBaseHeader.h create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/LogFunctions.h create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/UniqueNameGenerator.cpp create mode 100644 Engine/lib/assimp/code/MDL/HalfLife/UniqueNameGenerator.h create mode 100644 Engine/lib/assimp/code/PostProcessing/SplitByBoneCountProcess.cpp create mode 100644 Engine/lib/assimp/code/PostProcessing/SplitByBoneCountProcess.h create mode 100644 Engine/lib/assimp/include/assimp/commonMetaData.h rename Templates/BaseGame/game/core/{ => rendering}/shapes/materials.cs (100%) create mode 100644 Templates/BaseGame/game/core/rendering/shapes/noshape.asset.taml rename Templates/BaseGame/game/core/{ => rendering}/shapes/noshape.dts (100%) rename Templates/BaseGame/game/core/{ => rendering}/shapes/noshape.mb (100%) diff --git a/Engine/lib/assimp/code/3DS/3DSConverter.cpp b/Engine/lib/assimp/code/3DS/3DSConverter.cpp index 3c3da36a3..3f0e20bb0 100644 --- a/Engine/lib/assimp/code/3DS/3DSConverter.cpp +++ b/Engine/lib/assimp/code/3DS/3DSConverter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/3DS/3DSExporter.cpp b/Engine/lib/assimp/code/3DS/3DSExporter.cpp index 1117a52ef..14810cbff 100644 --- a/Engine/lib/assimp/code/3DS/3DSExporter.cpp +++ b/Engine/lib/assimp/code/3DS/3DSExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3DS/3DSExporter.h b/Engine/lib/assimp/code/3DS/3DSExporter.h index 035b562cf..9dcd92d58 100644 --- a/Engine/lib/assimp/code/3DS/3DSExporter.h +++ b/Engine/lib/assimp/code/3DS/3DSExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3DS/3DSHelper.h b/Engine/lib/assimp/code/3DS/3DSHelper.h index 8eb4cd97c..e483f1a25 100644 --- a/Engine/lib/assimp/code/3DS/3DSHelper.h +++ b/Engine/lib/assimp/code/3DS/3DSHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3DS/3DSLoader.cpp b/Engine/lib/assimp/code/3DS/3DSLoader.cpp index 3c659d0b0..3e8e08967 100644 --- a/Engine/lib/assimp/code/3DS/3DSLoader.cpp +++ b/Engine/lib/assimp/code/3DS/3DSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/3DS/3DSLoader.h b/Engine/lib/assimp/code/3DS/3DSLoader.h index f57e6a8e3..9181294b3 100644 --- a/Engine/lib/assimp/code/3DS/3DSLoader.h +++ b/Engine/lib/assimp/code/3DS/3DSLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/3MFXmlTags.h b/Engine/lib/assimp/code/3MF/3MFXmlTags.h index ea6aeede0..3f1fc01ed 100644 --- a/Engine/lib/assimp/code/3MF/3MFXmlTags.h +++ b/Engine/lib/assimp/code/3MF/3MFXmlTags.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFExporter.cpp b/Engine/lib/assimp/code/3MF/D3MFExporter.cpp index 1f388ad3e..9d71a54f2 100644 --- a/Engine/lib/assimp/code/3MF/D3MFExporter.cpp +++ b/Engine/lib/assimp/code/3MF/D3MFExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFExporter.h b/Engine/lib/assimp/code/3MF/D3MFExporter.h index e82120247..6a447236b 100644 --- a/Engine/lib/assimp/code/3MF/D3MFExporter.h +++ b/Engine/lib/assimp/code/3MF/D3MFExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFImporter.cpp b/Engine/lib/assimp/code/3MF/D3MFImporter.cpp index 682de684a..2f30c4fc0 100644 --- a/Engine/lib/assimp/code/3MF/D3MFImporter.cpp +++ b/Engine/lib/assimp/code/3MF/D3MFImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFImporter.h b/Engine/lib/assimp/code/3MF/D3MFImporter.h index 3dbdf07bf..638971247 100644 --- a/Engine/lib/assimp/code/3MF/D3MFImporter.h +++ b/Engine/lib/assimp/code/3MF/D3MFImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFOpcPackage.cpp b/Engine/lib/assimp/code/3MF/D3MFOpcPackage.cpp index 873ba8ee8..565790656 100644 --- a/Engine/lib/assimp/code/3MF/D3MFOpcPackage.cpp +++ b/Engine/lib/assimp/code/3MF/D3MFOpcPackage.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/3MF/D3MFOpcPackage.h b/Engine/lib/assimp/code/3MF/D3MFOpcPackage.h index 87d172116..291f8ad53 100644 --- a/Engine/lib/assimp/code/3MF/D3MFOpcPackage.h +++ b/Engine/lib/assimp/code/3MF/D3MFOpcPackage.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/AC/ACLoader.cpp b/Engine/lib/assimp/code/AC/ACLoader.cpp index d4c4bd1a6..ea533743f 100644 --- a/Engine/lib/assimp/code/AC/ACLoader.cpp +++ b/Engine/lib/assimp/code/AC/ACLoader.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AC/ACLoader.h b/Engine/lib/assimp/code/AC/ACLoader.h index cab2c3ae5..1fc654f3c 100644 --- a/Engine/lib/assimp/code/AC/ACLoader.h +++ b/Engine/lib/assimp/code/AC/ACLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/AMF/AMFImporter.cpp b/Engine/lib/assimp/code/AMF/AMFImporter.cpp index dedb6dcdd..df4324d4d 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter.cpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter.hpp b/Engine/lib/assimp/code/AMF/AMFImporter.hpp index 2b8086a06..5994717b8 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter.hpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Geometry.cpp b/Engine/lib/assimp/code/AMF/AMFImporter_Geometry.cpp index f1538e3fb..e9a50b656 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Geometry.cpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Geometry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Macro.hpp b/Engine/lib/assimp/code/AMF/AMFImporter_Macro.hpp index f60c5fbbb..ec06cb999 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Macro.hpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Macro.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Material.cpp b/Engine/lib/assimp/code/AMF/AMFImporter_Material.cpp index 2f36df061..64da12dda 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Material.cpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Material.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Node.hpp b/Engine/lib/assimp/code/AMF/AMFImporter_Node.hpp index a1bf9f008..b7b7836f3 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Node.hpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Node.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/AMF/AMFImporter_Postprocess.cpp b/Engine/lib/assimp/code/AMF/AMFImporter_Postprocess.cpp index 79b5e15e2..8496d8ded 100644 --- a/Engine/lib/assimp/code/AMF/AMFImporter_Postprocess.cpp +++ b/Engine/lib/assimp/code/AMF/AMFImporter_Postprocess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/ASE/ASELoader.cpp b/Engine/lib/assimp/code/ASE/ASELoader.cpp index 8e99214a8..b2155d5e5 100644 --- a/Engine/lib/assimp/code/ASE/ASELoader.cpp +++ b/Engine/lib/assimp/code/ASE/ASELoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/ASE/ASELoader.h b/Engine/lib/assimp/code/ASE/ASELoader.h index b497aa48b..bb7707bb6 100644 --- a/Engine/lib/assimp/code/ASE/ASELoader.h +++ b/Engine/lib/assimp/code/ASE/ASELoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/ASE/ASEParser.cpp b/Engine/lib/assimp/code/ASE/ASEParser.cpp index 913e7b118..efc6ecd0d 100644 --- a/Engine/lib/assimp/code/ASE/ASEParser.cpp +++ b/Engine/lib/assimp/code/ASE/ASEParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/ASE/ASEParser.h b/Engine/lib/assimp/code/ASE/ASEParser.h index 988cbda8d..e55949f99 100644 --- a/Engine/lib/assimp/code/ASE/ASEParser.h +++ b/Engine/lib/assimp/code/ASE/ASEParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Assbin/AssbinExporter.cpp b/Engine/lib/assimp/code/Assbin/AssbinExporter.cpp index 76c823f82..496b39d49 100644 --- a/Engine/lib/assimp/code/Assbin/AssbinExporter.cpp +++ b/Engine/lib/assimp/code/Assbin/AssbinExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -46,799 +46,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER -#include "Common/assbin_chunks.h" -#include "PostProcessing/ProcessHelper.h" +#include "AssbinFileWriter.h" -#include -#include +#include #include #include -#include - -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -#else -# include "../contrib/zlib/zlib.h" -#endif - -#include namespace Assimp { -template -size_t Write(IOStream * stream, const T& v) { - return stream->Write( &v, sizeof(T), 1 ); -} - -// ----------------------------------------------------------------------------------- -// Serialize an aiString -template <> -inline -size_t Write(IOStream * stream, const aiString& s) { - const size_t s2 = (uint32_t)s.length; - stream->Write(&s,4,1); - stream->Write(s.data,s2,1); - - return s2+4; -} - -// ----------------------------------------------------------------------------------- -// Serialize an unsigned int as uint32_t -template <> -inline -size_t Write(IOStream * stream, const unsigned int& w) { - const uint32_t t = (uint32_t)w; - if (w > t) { - // this shouldn't happen, integers in Assimp data structures never exceed 2^32 - throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); - } - - stream->Write(&t,4,1); - - return 4; -} - -// ----------------------------------------------------------------------------------- -// Serialize an unsigned int as uint16_t -template <> -inline -size_t Write(IOStream * stream, const uint16_t& w) { - static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2"); - stream->Write(&w,2,1); - - return 2; -} - -// ----------------------------------------------------------------------------------- -// Serialize a float -template <> -inline -size_t Write(IOStream * stream, const float& f) { - static_assert(sizeof(float)==4, "sizeof(float)==4"); - stream->Write(&f,4,1); - - return 4; -} - -// ----------------------------------------------------------------------------------- -// Serialize a double -template <> -inline -size_t Write(IOStream * stream, const double& f) { - static_assert(sizeof(double)==8, "sizeof(double)==8"); - stream->Write(&f,8,1); - - return 8; -} - -// ----------------------------------------------------------------------------------- -// Serialize a vec3 -template <> -inline -size_t Write(IOStream * stream, const aiVector3D& v) { - size_t t = Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); - - return t; -} - -// ----------------------------------------------------------------------------------- -// Serialize a color value -template <> -inline -size_t Write(IOStream * stream, const aiColor3D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); - - return t; -} - -// ----------------------------------------------------------------------------------- -// Serialize a color value -template <> -inline -size_t Write(IOStream * stream, const aiColor4D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); - t += Write(stream,v.a); - - return t; -} - -// ----------------------------------------------------------------------------------- -// Serialize a quaternion -template <> -inline -size_t Write(IOStream * stream, const aiQuaternion& v) { - size_t t = Write(stream,v.w); - t += Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); - ai_assert(t == 16); - - return 16; -} - -// ----------------------------------------------------------------------------------- -// Serialize a vertex weight -template <> -inline -size_t Write(IOStream * stream, const aiVertexWeight& v) { - size_t t = Write(stream,v.mVertexId); - - return t+Write(stream,v.mWeight); -} - -// ----------------------------------------------------------------------------------- -// Serialize a mat4x4 -template <> -inline -size_t Write(IOStream * stream, const aiMatrix4x4& m) { - for (unsigned int i = 0; i < 4;++i) { - for (unsigned int i2 = 0; i2 < 4;++i2) { - Write(stream,m[i][i2]); - } - } - - return 64; -} - -// ----------------------------------------------------------------------------------- -// Serialize an aiVectorKey -template <> -inline -size_t Write(IOStream * stream, const aiVectorKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); -} - -// ----------------------------------------------------------------------------------- -// Serialize an aiQuatKey -template <> -inline -size_t Write(IOStream * stream, const aiQuatKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); -} - -template -inline -size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) { - T minc, maxc; - ArrayBounds(in,size,minc,maxc); - - const size_t t = Write(stream,minc); - return t + Write(stream,maxc); -} - -// We use this to write out non-byte arrays so that we write using the specializations. -// This way we avoid writing out extra bytes that potentially come from struct alignment. -template -inline -size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { - size_t n = 0; - for (unsigned int i=0; i(stream,in[i]); - - return n; -} - -// ---------------------------------------------------------------------------------- -/** @class AssbinChunkWriter - * @brief Chunk writer mechanism for the .assbin file structure - * - * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), - * the difference being that this takes another IOStream as a "container" in the - * constructor, and when it is destroyed, it appends the magic number, the chunk size, - * and the chunk contents to the container stream. This allows relatively easy chunk - * chunk construction, even recursively. - */ -class AssbinChunkWriter : public IOStream -{ -private: - - uint8_t* buffer; - uint32_t magic; - IOStream * container; - size_t cur_size, cursor, initial; - -private: - // ------------------------------------------------------------------- - void Grow(size_t need = 0) - { - size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); - - const uint8_t* const old = buffer; - buffer = new uint8_t[new_size]; - - if (old) { - memcpy(buffer,old,cur_size); - delete[] old; - } - - cur_size = new_size; - } - -public: - - AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) - : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) - { - } - - virtual ~AssbinChunkWriter() - { - if (container) { - container->Write( &magic, sizeof(uint32_t), 1 ); - container->Write( &cursor, sizeof(uint32_t), 1 ); - container->Write( buffer, 1, cursor ); - } - if (buffer) delete[] buffer; - } - - void * GetBufferPointer() { return buffer; } - - // ------------------------------------------------------------------- - virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { - return 0; - } - virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { - return aiReturn_FAILURE; - } - virtual size_t Tell() const { - return cursor; - } - virtual void Flush() { - // not implemented - } - - virtual size_t FileSize() const { - return cursor; - } - - // ------------------------------------------------------------------- - virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) { - pSize *= pCount; - if (cursor + pSize > cur_size) { - Grow(cursor + pSize); - } - - memcpy(buffer+cursor, pvBuffer, pSize); - cursor += pSize; - - return pCount; - } - -}; - -// ---------------------------------------------------------------------------------- -/** @class AssbinExport - * @brief Assbin exporter class - * - * This class performs the .assbin exporting, and is responsible for the file layout. - */ -class AssbinExport -{ -private: - bool shortened; - bool compressed; - -protected: - // ----------------------------------------------------------------------------------- - void WriteBinaryNode( IOStream * container, const aiNode* node) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); - - unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); - - Write(&chunk,node->mName); - Write(&chunk,node->mTransformation); - Write(&chunk,node->mNumChildren); - Write(&chunk,node->mNumMeshes); - Write(&chunk,nb_metadata); - - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - Write(&chunk,node->mMeshes[i]); - } - - for (unsigned int i = 0; i < node->mNumChildren;++i) { - WriteBinaryNode( &chunk, node->mChildren[i] ); - } - - for (unsigned int i = 0; i < nb_metadata; ++i) { - const aiString& key = node->mMetaData->mKeys[i]; - aiMetadataType type = node->mMetaData->mValues[i].mType; - void* value = node->mMetaData->mValues[i].mData; - - Write(&chunk, key); - Write(&chunk, type); - - switch (type) { - case AI_BOOL: - Write(&chunk, *((bool*) value)); - break; - case AI_INT32: - Write(&chunk, *((int32_t*) value)); - break; - case AI_UINT64: - Write(&chunk, *((uint64_t*) value)); - break; - case AI_FLOAT: - Write(&chunk, *((float*) value)); - break; - case AI_DOUBLE: - Write(&chunk, *((double*) value)); - break; - case AI_AISTRING: - Write(&chunk, *((aiString*) value)); - break; - case AI_AIVECTOR3D: - Write(&chunk, *((aiVector3D*) value)); - break; -#ifdef SWIG - case FORCE_32BIT: -#endif // SWIG - default: - break; - } - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryTexture(IOStream * container, const aiTexture* tex) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); - - Write(&chunk,tex->mWidth); - Write(&chunk,tex->mHeight); - chunk.Write( tex->achFormatHint, sizeof(char), 4 ); - - if(!shortened) { - if (!tex->mHeight) { - chunk.Write(tex->pcData,1,tex->mWidth); - } - else { - chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4); - } - } - - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryBone(IOStream * container, const aiBone* b) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE ); - - Write(&chunk,b->mName); - Write(&chunk,b->mNumWeights); - Write(&chunk,b->mOffsetMatrix); - - // for the moment we write dumb min/max values for the bones, too. - // maybe I'll add a better, hash-like solution later - if (shortened) { - WriteBounds(&chunk,b->mWeights,b->mNumWeights); - } // else write as usual - else WriteArray(&chunk,b->mWeights,b->mNumWeights); - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); - - Write(&chunk,mesh->mPrimitiveTypes); - Write(&chunk,mesh->mNumVertices); - Write(&chunk,mesh->mNumFaces); - Write(&chunk,mesh->mNumBones); - Write(&chunk,mesh->mMaterialIndex); - - // first of all, write bits for all existent vertex components - unsigned int c = 0; - if (mesh->mVertices) { - c |= ASSBIN_MESH_HAS_POSITIONS; - } - if (mesh->mNormals) { - c |= ASSBIN_MESH_HAS_NORMALS; - } - if (mesh->mTangents && mesh->mBitangents) { - c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (!mesh->mTextureCoords[n]) { - break; - } - c |= ASSBIN_MESH_HAS_TEXCOORD(n); - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { - if (!mesh->mColors[n]) { - break; - } - c |= ASSBIN_MESH_HAS_COLOR(n); - } - Write(&chunk,c); - - aiVector3D minVec, maxVec; - if (mesh->mVertices) { - if (shortened) { - WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); - } - if (mesh->mNormals) { - if (shortened) { - WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mNormals,mesh->mNumVertices); - } - if (mesh->mTangents && mesh->mBitangents) { - if (shortened) { - WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices); - } // else write as usual - else { - WriteArray(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteArray(&chunk,mesh->mBitangents,mesh->mNumVertices); - } - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { - if (!mesh->mColors[n]) - break; - - if (shortened) { - WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); - } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (!mesh->mTextureCoords[n]) - break; - - // write number of UV components - Write(&chunk,mesh->mNumUVComponents[n]); - - if (shortened) { - WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); - } - - // write faces. There are no floating-point calculations involved - // in these, so we can write a simple hash over the face data - // to the dump file. We generate a single 32 Bit hash for 512 faces - // using Assimp's standard hashing function. - if (shortened) { - unsigned int processed = 0; - for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) { - - uint32_t hash = 0; - for (unsigned int a = 0; a < job;++a) { - - const aiFace& f = mesh->mFaces[processed+a]; - uint32_t tmp = f.mNumIndices; - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); - for (unsigned int i = 0; i < f.mNumIndices; ++i) { - static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff"); - tmp = static_cast( f.mIndices[i] ); - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); - } - } - Write(&chunk,hash); - } - } - else // else write as usual - { - // if there are less than 2^16 vertices, we can simply use 16 bit integers ... - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - const aiFace& f = mesh->mFaces[i]; - - static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); - Write(&chunk,f.mNumIndices); - - for (unsigned int a = 0; a < f.mNumIndices;++a) { - if (mesh->mNumVertices < (1u<<16)) { - Write(&chunk,f.mIndices[a]); - } - else Write(&chunk,f.mIndices[a]); - } - } - } - - // write bones - if (mesh->mNumBones) { - for (unsigned int a = 0; a < mesh->mNumBones;++a) { - const aiBone* b = mesh->mBones[a]; - WriteBinaryBone(&chunk,b); - } - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY ); - - Write(&chunk,prop->mKey); - Write(&chunk,prop->mSemantic); - Write(&chunk,prop->mIndex); - - Write(&chunk,prop->mDataLength); - Write(&chunk,(unsigned int)prop->mType); - chunk.Write(prop->mData,1,prop->mDataLength); - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); - - Write(&chunk,mat->mNumProperties); - for (unsigned int i = 0; i < mat->mNumProperties;++i) { - WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]); - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM ); - - Write(&chunk,nd->mNodeName); - Write(&chunk,nd->mNumPositionKeys); - Write(&chunk,nd->mNumRotationKeys); - Write(&chunk,nd->mNumScalingKeys); - Write(&chunk,nd->mPreState); - Write(&chunk,nd->mPostState); - - if (nd->mPositionKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); - } - if (nd->mRotationKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); - } - if (nd->mScalingKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); - } - } - - - // ----------------------------------------------------------------------------------- - void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); - - Write(&chunk,anim->mName); - Write(&chunk,anim->mDuration); - Write(&chunk,anim->mTicksPerSecond); - Write(&chunk,anim->mNumChannels); - - for (unsigned int a = 0; a < anim->mNumChannels;++a) { - const aiNodeAnim* nd = anim->mChannels[a]; - WriteBinaryNodeAnim(&chunk,nd); - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryLight( IOStream * container, const aiLight* l ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT ); - - Write(&chunk,l->mName); - Write(&chunk,l->mType); - - if (l->mType != aiLightSource_DIRECTIONAL) { - Write(&chunk,l->mAttenuationConstant); - Write(&chunk,l->mAttenuationLinear); - Write(&chunk,l->mAttenuationQuadratic); - } - - Write(&chunk,l->mColorDiffuse); - Write(&chunk,l->mColorSpecular); - Write(&chunk,l->mColorAmbient); - - if (l->mType == aiLightSource_SPOT) { - Write(&chunk,l->mAngleInnerCone); - Write(&chunk,l->mAngleOuterCone); - } - - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); - - Write(&chunk,cam->mName); - Write(&chunk,cam->mPosition); - Write(&chunk,cam->mLookAt); - Write(&chunk,cam->mUp); - Write(&chunk,cam->mHorizontalFOV); - Write(&chunk,cam->mClipPlaneNear); - Write(&chunk,cam->mClipPlaneFar); - Write(&chunk,cam->mAspect); - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryScene( IOStream * container, const aiScene* scene) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); - - // basic scene information - Write(&chunk,scene->mFlags); - Write(&chunk,scene->mNumMeshes); - Write(&chunk,scene->mNumMaterials); - Write(&chunk,scene->mNumAnimations); - Write(&chunk,scene->mNumTextures); - Write(&chunk,scene->mNumLights); - Write(&chunk,scene->mNumCameras); - - // write node graph - WriteBinaryNode( &chunk, scene->mRootNode ); - - // write all meshes - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - const aiMesh* mesh = scene->mMeshes[i]; - WriteBinaryMesh( &chunk,mesh); - } - - // write materials - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { - const aiMaterial* mat = scene->mMaterials[i]; - WriteBinaryMaterial(&chunk,mat); - } - - // write all animations - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { - const aiAnimation* anim = scene->mAnimations[i]; - WriteBinaryAnim(&chunk,anim); - } - - - // write all textures - for (unsigned int i = 0; i < scene->mNumTextures;++i) { - const aiTexture* mesh = scene->mTextures[i]; - WriteBinaryTexture(&chunk,mesh); - } - - // write lights - for (unsigned int i = 0; i < scene->mNumLights;++i) { - const aiLight* l = scene->mLights[i]; - WriteBinaryLight(&chunk,l); - } - - // write cameras - for (unsigned int i = 0; i < scene->mNumCameras;++i) { - const aiCamera* cam = scene->mCameras[i]; - WriteBinaryCamera(&chunk,cam); - } - - } - -public: - AssbinExport() - : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters - { - } - - // ----------------------------------------------------------------------------------- - // Write a binary model dump - void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) - { - IOStream * out = pIOSystem->Open( pFile, "wb" ); - if (!out) return; - - time_t tt = time(NULL); -#if _WIN32 - tm* p = gmtime(&tt); -#else - struct tm now; - tm* p = gmtime_r(&tt, &now); -#endif - - // header - char s[64]; - memset( s, 0, 64 ); -#if _MSC_VER >= 1400 - sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p)); -#else - ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p)); -#endif - out->Write( s, 44, 1 ); - // == 44 bytes - - Write( out, ASSBIN_VERSION_MAJOR ); - Write( out, ASSBIN_VERSION_MINOR ); - Write( out, aiGetVersionRevision() ); - Write( out, aiGetCompileFlags() ); - Write( out, shortened ); - Write( out, compressed ); - // == 20 bytes - - char buff[256]; - strncpy(buff,pFile,256); - out->Write(buff,sizeof(char),256); - - char cmd[] = "\0"; - strncpy(buff,cmd,128); - out->Write(buff,sizeof(char),128); - - // leave 64 bytes free for future extensions - memset(buff,0xcd,64); - out->Write(buff,sizeof(char),64); - // == 435 bytes - - // ==== total header size: 512 bytes - ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH ); - - // Up to here the data is uncompressed. For compressed files, the rest - // is compressed using standard DEFLATE from zlib. - if (compressed) - { - AssbinChunkWriter uncompressedStream( NULL, 0 ); - WriteBinaryScene( &uncompressedStream, pScene ); - - uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); - uLongf compressedSize = (uLongf)compressBound(uncompressedSize); - uint8_t* compressedBuffer = new uint8_t[ compressedSize ]; - - int res = compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 ); - if(res != Z_OK) - { - delete [] compressedBuffer; - pIOSystem->Close(out); - throw DeadlyExportError("Compression failed."); - } - - out->Write( &uncompressedSize, sizeof(uint32_t), 1 ); - out->Write( compressedBuffer, sizeof(char), compressedSize ); - - delete[] compressedBuffer; - } - else - { - WriteBinaryScene( out, pScene ); - } - - pIOSystem->Close( out ); - } -}; - void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { - AssbinExport exporter; - exporter.WriteBinaryDump( pFile, pIOSystem, pScene ); + DumpSceneToAssbin( + pFile, + "\0", // no command(s). + pIOSystem, + pScene, + false, // shortened? + false); // compressed? } } // end of namespace Assimp diff --git a/Engine/lib/assimp/code/Assbin/AssbinExporter.h b/Engine/lib/assimp/code/Assbin/AssbinExporter.h index 3e13639bb..350ed85e3 100644 --- a/Engine/lib/assimp/code/Assbin/AssbinExporter.h +++ b/Engine/lib/assimp/code/Assbin/AssbinExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Assbin/AssbinFileWriter.cpp b/Engine/lib/assimp/code/Assbin/AssbinFileWriter.cpp new file mode 100644 index 000000000..4bc8f7cac --- /dev/null +++ b/Engine/lib/assimp/code/Assbin/AssbinFileWriter.cpp @@ -0,0 +1,858 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 AssbinFileWriter.cpp + * @brief Implementation of Assbin file writer. + */ + +#include "AssbinFileWriter.h" + +#include "Common/assbin_chunks.h" +#include "PostProcessing/ProcessHelper.h" + +#include +#include +#include +#include + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +# include +#else +# include "../contrib/zlib/zlib.h" +#endif + +#include + +namespace Assimp { + +template +size_t Write(IOStream * stream, const T& v) { + return stream->Write( &v, sizeof(T), 1 ); +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiString +template <> +inline +size_t Write(IOStream * stream, const aiString& s) { + const size_t s2 = (uint32_t)s.length; + stream->Write(&s,4,1); + stream->Write(s.data,s2,1); + + return s2+4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint32_t +template <> +inline +size_t Write(IOStream * stream, const unsigned int& w) { + const uint32_t t = (uint32_t)w; + if (w > t) { + // this shouldn't happen, integers in Assimp data structures never exceed 2^32 + throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); + } + + stream->Write(&t,4,1); + + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize an unsigned int as uint16_t +template <> +inline +size_t Write(IOStream * stream, const uint16_t& w) { + static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2"); + stream->Write(&w,2,1); + + return 2; +} + +// ----------------------------------------------------------------------------------- +// Serialize a float +template <> +inline +size_t Write(IOStream * stream, const float& f) { + static_assert(sizeof(float)==4, "sizeof(float)==4"); + stream->Write(&f,4,1); + + return 4; +} + +// ----------------------------------------------------------------------------------- +// Serialize a double +template <> +inline +size_t Write(IOStream * stream, const double& f) { + static_assert(sizeof(double)==8, "sizeof(double)==8"); + stream->Write(&f,8,1); + + return 8; +} + +// ----------------------------------------------------------------------------------- +// Serialize a vec3 +template <> +inline +size_t Write(IOStream * stream, const aiVector3D& v) { + size_t t = Write(stream,v.x); + t += Write(stream,v.y); + t += Write(stream,v.z); + + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a color value +template <> +inline +size_t Write(IOStream * stream, const aiColor3D& v) { + size_t t = Write(stream,v.r); + t += Write(stream,v.g); + t += Write(stream,v.b); + + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a color value +template <> +inline +size_t Write(IOStream * stream, const aiColor4D& v) { + size_t t = Write(stream,v.r); + t += Write(stream,v.g); + t += Write(stream,v.b); + t += Write(stream,v.a); + + return t; +} + +// ----------------------------------------------------------------------------------- +// Serialize a quaternion +template <> +inline +size_t Write(IOStream * stream, const aiQuaternion& v) { + size_t t = Write(stream,v.w); + t += Write(stream,v.x); + t += Write(stream,v.y); + t += Write(stream,v.z); + ai_assert(t == 16); + + return 16; +} + +// ----------------------------------------------------------------------------------- +// Serialize a vertex weight +template <> +inline +size_t Write(IOStream * stream, const aiVertexWeight& v) { + size_t t = Write(stream,v.mVertexId); + + return t+Write(stream,v.mWeight); +} + +// ----------------------------------------------------------------------------------- +// Serialize a mat4x4 +template <> +inline +size_t Write(IOStream * stream, const aiMatrix4x4& m) { + for (unsigned int i = 0; i < 4;++i) { + for (unsigned int i2 = 0; i2 < 4;++i2) { + Write(stream,m[i][i2]); + } + } + + return 64; +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiVectorKey +template <> +inline +size_t Write(IOStream * stream, const aiVectorKey& v) { + const size_t t = Write(stream,v.mTime); + return t + Write(stream,v.mValue); +} + +// ----------------------------------------------------------------------------------- +// Serialize an aiQuatKey +template <> +inline +size_t Write(IOStream * stream, const aiQuatKey& v) { + const size_t t = Write(stream,v.mTime); + return t + Write(stream,v.mValue); +} + +template +inline +size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) { + T minc, maxc; + ArrayBounds(in,size,minc,maxc); + + const size_t t = Write(stream,minc); + return t + Write(stream,maxc); +} + +// We use this to write out non-byte arrays so that we write using the specializations. +// This way we avoid writing out extra bytes that potentially come from struct alignment. +template +inline +size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { + size_t n = 0; + for (unsigned int i=0; i(stream,in[i]); + + return n; +} + +// ---------------------------------------------------------------------------------- +/** @class AssbinChunkWriter + * @brief Chunk writer mechanism for the .assbin file structure + * + * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), + * the difference being that this takes another IOStream as a "container" in the + * constructor, and when it is destroyed, it appends the magic number, the chunk size, + * and the chunk contents to the container stream. This allows relatively easy chunk + * chunk construction, even recursively. + */ +class AssbinChunkWriter : public IOStream +{ +private: + + uint8_t* buffer; + uint32_t magic; + IOStream * container; + size_t cur_size, cursor, initial; + +private: + // ------------------------------------------------------------------- + void Grow(size_t need = 0) + { + size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); + + const uint8_t* const old = buffer; + buffer = new uint8_t[new_size]; + + if (old) { + memcpy(buffer,old,cur_size); + delete[] old; + } + + cur_size = new_size; + } + +public: + + AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) + : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) + { + } + + virtual ~AssbinChunkWriter() + { + if (container) { + container->Write( &magic, sizeof(uint32_t), 1 ); + container->Write( &cursor, sizeof(uint32_t), 1 ); + container->Write( buffer, 1, cursor ); + } + if (buffer) delete[] buffer; + } + + void * GetBufferPointer() { return buffer; } + + // ------------------------------------------------------------------- + virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { + return 0; + } + virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { + return aiReturn_FAILURE; + } + virtual size_t Tell() const { + return cursor; + } + virtual void Flush() { + // not implemented + } + + virtual size_t FileSize() const { + return cursor; + } + + // ------------------------------------------------------------------- + virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) { + pSize *= pCount; + if (cursor + pSize > cur_size) { + Grow(cursor + pSize); + } + + memcpy(buffer+cursor, pvBuffer, pSize); + cursor += pSize; + + return pCount; + } + +}; + +// ---------------------------------------------------------------------------------- +/** @class AssbinFileWriter + * @brief Assbin file writer class + * + * This class writes an .assbin file, and is responsible for the file layout. + */ +class AssbinFileWriter +{ +private: + bool shortened; + bool compressed; + +protected: + // ----------------------------------------------------------------------------------- + void WriteBinaryNode( IOStream * container, const aiNode* node) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); + + unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); + + Write(&chunk,node->mName); + Write(&chunk,node->mTransformation); + Write(&chunk,node->mNumChildren); + Write(&chunk,node->mNumMeshes); + Write(&chunk,nb_metadata); + + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + Write(&chunk,node->mMeshes[i]); + } + + for (unsigned int i = 0; i < node->mNumChildren;++i) { + WriteBinaryNode( &chunk, node->mChildren[i] ); + } + + for (unsigned int i = 0; i < nb_metadata; ++i) { + const aiString& key = node->mMetaData->mKeys[i]; + aiMetadataType type = node->mMetaData->mValues[i].mType; + void* value = node->mMetaData->mValues[i].mData; + + Write(&chunk, key); + Write(&chunk, type); + + switch (type) { + case AI_BOOL: + Write(&chunk, *((bool*) value)); + break; + case AI_INT32: + Write(&chunk, *((int32_t*) value)); + break; + case AI_UINT64: + Write(&chunk, *((uint64_t*) value)); + break; + case AI_FLOAT: + Write(&chunk, *((float*) value)); + break; + case AI_DOUBLE: + Write(&chunk, *((double*) value)); + break; + case AI_AISTRING: + Write(&chunk, *((aiString*) value)); + break; + case AI_AIVECTOR3D: + Write(&chunk, *((aiVector3D*) value)); + break; +#ifdef SWIG + case FORCE_32BIT: +#endif // SWIG + default: + break; + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryTexture(IOStream * container, const aiTexture* tex) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); + + Write(&chunk,tex->mWidth); + Write(&chunk,tex->mHeight); + // Write the texture format, but don't include the null terminator. + chunk.Write( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 ); + + if(!shortened) { + if (!tex->mHeight) { + chunk.Write(tex->pcData,1,tex->mWidth); + } + else { + chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4); + } + } + + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryBone(IOStream * container, const aiBone* b) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE ); + + Write(&chunk,b->mName); + Write(&chunk,b->mNumWeights); + Write(&chunk,b->mOffsetMatrix); + + // for the moment we write dumb min/max values for the bones, too. + // maybe I'll add a better, hash-like solution later + if (shortened) { + WriteBounds(&chunk,b->mWeights,b->mNumWeights); + } // else write as usual + else WriteArray(&chunk,b->mWeights,b->mNumWeights); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); + + Write(&chunk,mesh->mPrimitiveTypes); + Write(&chunk,mesh->mNumVertices); + Write(&chunk,mesh->mNumFaces); + Write(&chunk,mesh->mNumBones); + Write(&chunk,mesh->mMaterialIndex); + + // first of all, write bits for all existent vertex components + unsigned int c = 0; + if (mesh->mVertices) { + c |= ASSBIN_MESH_HAS_POSITIONS; + } + if (mesh->mNormals) { + c |= ASSBIN_MESH_HAS_NORMALS; + } + if (mesh->mTangents && mesh->mBitangents) { + c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) { + break; + } + c |= ASSBIN_MESH_HAS_TEXCOORD(n); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) { + break; + } + c |= ASSBIN_MESH_HAS_COLOR(n); + } + Write(&chunk,c); + + aiVector3D minVec, maxVec; + if (mesh->mVertices) { + if (shortened) { + WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); + } + if (mesh->mNormals) { + if (shortened) { + WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mNormals,mesh->mNumVertices); + } + if (mesh->mTangents && mesh->mBitangents) { + if (shortened) { + WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices); + WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices); + } // else write as usual + else { + WriteArray(&chunk,mesh->mTangents,mesh->mNumVertices); + WriteArray(&chunk,mesh->mBitangents,mesh->mNumVertices); + } + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!mesh->mColors[n]) + break; + + if (shortened) { + WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); + } + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!mesh->mTextureCoords[n]) + break; + + // write number of UV components + Write(&chunk,mesh->mNumUVComponents[n]); + + if (shortened) { + WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // using Assimp's standard hashing function. + if (shortened) { + unsigned int processed = 0; + for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) { + + uint32_t hash = 0; + for (unsigned int a = 0; a < job;++a) { + + const aiFace& f = mesh->mFaces[processed+a]; + uint32_t tmp = f.mNumIndices; + hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + for (unsigned int i = 0; i < f.mNumIndices; ++i) { + static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff"); + tmp = static_cast( f.mIndices[i] ); + hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + } + } + Write(&chunk,hash); + } + } + else // else write as usual + { + // if there are less than 2^16 vertices, we can simply use 16 bit integers ... + for (unsigned int i = 0; i < mesh->mNumFaces;++i) { + const aiFace& f = mesh->mFaces[i]; + + static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); + Write(&chunk,f.mNumIndices); + + for (unsigned int a = 0; a < f.mNumIndices;++a) { + if (mesh->mNumVertices < (1u<<16)) { + Write(&chunk,f.mIndices[a]); + } + else Write(&chunk,f.mIndices[a]); + } + } + } + + // write bones + if (mesh->mNumBones) { + for (unsigned int a = 0; a < mesh->mNumBones;++a) { + const aiBone* b = mesh->mBones[a]; + WriteBinaryBone(&chunk,b); + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY ); + + Write(&chunk,prop->mKey); + Write(&chunk,prop->mSemantic); + Write(&chunk,prop->mIndex); + + Write(&chunk,prop->mDataLength); + Write(&chunk,(unsigned int)prop->mType); + chunk.Write(prop->mData,1,prop->mDataLength); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); + + Write(&chunk,mat->mNumProperties); + for (unsigned int i = 0; i < mat->mNumProperties;++i) { + WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM ); + + Write(&chunk,nd->mNodeName); + Write(&chunk,nd->mNumPositionKeys); + Write(&chunk,nd->mNumRotationKeys); + Write(&chunk,nd->mNumScalingKeys); + Write(&chunk,nd->mPreState); + Write(&chunk,nd->mPostState); + + if (nd->mPositionKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + } + if (nd->mRotationKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + } + if (nd->mScalingKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + } + } + + + // ----------------------------------------------------------------------------------- + void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); + + Write(&chunk,anim->mName); + Write(&chunk,anim->mDuration); + Write(&chunk,anim->mTicksPerSecond); + Write(&chunk,anim->mNumChannels); + + for (unsigned int a = 0; a < anim->mNumChannels;++a) { + const aiNodeAnim* nd = anim->mChannels[a]; + WriteBinaryNodeAnim(&chunk,nd); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryLight( IOStream * container, const aiLight* l ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT ); + + Write(&chunk,l->mName); + Write(&chunk,l->mType); + + if (l->mType != aiLightSource_DIRECTIONAL) { + Write(&chunk,l->mAttenuationConstant); + Write(&chunk,l->mAttenuationLinear); + Write(&chunk,l->mAttenuationQuadratic); + } + + Write(&chunk,l->mColorDiffuse); + Write(&chunk,l->mColorSpecular); + Write(&chunk,l->mColorAmbient); + + if (l->mType == aiLightSource_SPOT) { + Write(&chunk,l->mAngleInnerCone); + Write(&chunk,l->mAngleOuterCone); + } + + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); + + Write(&chunk,cam->mName); + Write(&chunk,cam->mPosition); + Write(&chunk,cam->mLookAt); + Write(&chunk,cam->mUp); + Write(&chunk,cam->mHorizontalFOV); + Write(&chunk,cam->mClipPlaneNear); + Write(&chunk,cam->mClipPlaneFar); + Write(&chunk,cam->mAspect); + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryScene( IOStream * container, const aiScene* scene) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); + + // basic scene information + Write(&chunk,scene->mFlags); + Write(&chunk,scene->mNumMeshes); + Write(&chunk,scene->mNumMaterials); + Write(&chunk,scene->mNumAnimations); + Write(&chunk,scene->mNumTextures); + Write(&chunk,scene->mNumLights); + Write(&chunk,scene->mNumCameras); + + // write node graph + WriteBinaryNode( &chunk, scene->mRootNode ); + + // write all meshes + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + const aiMesh* mesh = scene->mMeshes[i]; + WriteBinaryMesh( &chunk,mesh); + } + + // write materials + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; + WriteBinaryMaterial(&chunk,mat); + } + + // write all animations + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + const aiAnimation* anim = scene->mAnimations[i]; + WriteBinaryAnim(&chunk,anim); + } + + + // write all textures + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + const aiTexture* mesh = scene->mTextures[i]; + WriteBinaryTexture(&chunk,mesh); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + const aiLight* l = scene->mLights[i]; + WriteBinaryLight(&chunk,l); + } + + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + const aiCamera* cam = scene->mCameras[i]; + WriteBinaryCamera(&chunk,cam); + } + + } + +public: + AssbinFileWriter(bool shortened, bool compressed) + : shortened(shortened), compressed(compressed) + { + } + + // ----------------------------------------------------------------------------------- + // Write a binary model dump + void WriteBinaryDump(const char* pFile, const char* cmd, IOSystem* pIOSystem, const aiScene* pScene) + { + IOStream * out = pIOSystem->Open( pFile, "wb" ); + if (!out) + throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n'); + + auto CloseIOStream = [&]() { + if (out) { + pIOSystem->Close(out); + out = nullptr; // Ensure this is only done once. + } + }; + + try { + time_t tt = time(NULL); +#if _WIN32 + tm* p = gmtime(&tt); +#else + struct tm now; + tm* p = gmtime_r(&tt, &now); +#endif + + // header + char s[64]; + memset(s, 0, 64); +#if _MSC_VER >= 1400 + sprintf_s(s, "ASSIMP.binary-dump.%s", asctime(p)); +#else + ai_snprintf(s, 64, "ASSIMP.binary-dump.%s", asctime(p)); +#endif + out->Write(s, 44, 1); + // == 44 bytes + + Write(out, ASSBIN_VERSION_MAJOR); + Write(out, ASSBIN_VERSION_MINOR); + Write(out, aiGetVersionRevision()); + Write(out, aiGetCompileFlags()); + Write(out, shortened); + Write(out, compressed); + // == 20 bytes + + char buff[256] = {0}; + ai_snprintf(buff, 256, "%s", pFile); + out->Write(buff, sizeof(char), 256); + + memset(buff, 0, sizeof(buff)); + ai_snprintf(buff, 128, "%s", cmd); + out->Write(buff, sizeof(char), 128); + + // leave 64 bytes free for future extensions + memset(buff, 0xcd, 64); + out->Write(buff, sizeof(char), 64); + // == 435 bytes + + // ==== total header size: 512 bytes + ai_assert(out->Tell() == ASSBIN_HEADER_LENGTH); + + // Up to here the data is uncompressed. For compressed files, the rest + // is compressed using standard DEFLATE from zlib. + if (compressed) + { + AssbinChunkWriter uncompressedStream(NULL, 0); + WriteBinaryScene(&uncompressedStream, pScene); + + uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); + uLongf compressedSize = (uLongf)compressBound(uncompressedSize); + uint8_t* compressedBuffer = new uint8_t[compressedSize]; + + int res = compress2(compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9); + if (res != Z_OK) + { + delete[] compressedBuffer; + throw DeadlyExportError("Compression failed."); + } + + out->Write(&uncompressedSize, sizeof(uint32_t), 1); + out->Write(compressedBuffer, sizeof(char), compressedSize); + + delete[] compressedBuffer; + } + else + { + WriteBinaryScene(out, pScene); + } + + CloseIOStream(); + } + catch (...) { + CloseIOStream(); + throw; + } + } +}; + +void DumpSceneToAssbin( + const char* pFile, const char* cmd, IOSystem* pIOSystem, + const aiScene* pScene, bool shortened, bool compressed) { + AssbinFileWriter fileWriter(shortened, compressed); + fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene); +} + +} // end of namespace Assimp diff --git a/Engine/lib/assimp/code/Assbin/AssbinFileWriter.h b/Engine/lib/assimp/code/Assbin/AssbinFileWriter.h new file mode 100644 index 000000000..25db6db2d --- /dev/null +++ b/Engine/lib/assimp/code/Assbin/AssbinFileWriter.h @@ -0,0 +1,66 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 AssbinFileWriter.h + * @brief Declaration of Assbin file writer. + */ + +#ifndef AI_ASSBINFILEWRITER_H_INC +#define AI_ASSBINFILEWRITER_H_INC + +#include +#include +#include + +namespace Assimp { + +void ASSIMP_API DumpSceneToAssbin( + const char* pFile, + const char* cmd, + IOSystem* pIOSystem, + const aiScene* pScene, + bool shortened, + bool compressed); + +} + +#endif // AI_ASSBINFILEWRITER_H_INC diff --git a/Engine/lib/assimp/code/Assbin/AssbinLoader.cpp b/Engine/lib/assimp/code/Assbin/AssbinLoader.cpp index becc3f8fc..71e35cb6a 100644 --- a/Engine/lib/assimp/code/Assbin/AssbinLoader.cpp +++ b/Engine/lib/assimp/code/Assbin/AssbinLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -535,7 +535,7 @@ void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) { tex->mWidth = Read(stream); tex->mHeight = Read(stream); - stream->Read( tex->achFormatHint, sizeof(char), 4 ); + stream->Read( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 ); if(!shortened) { if (!tex->mHeight) { diff --git a/Engine/lib/assimp/code/Assbin/AssbinLoader.h b/Engine/lib/assimp/code/Assbin/AssbinLoader.h index 9f2dde125..e6e99f26e 100644 --- a/Engine/lib/assimp/code/Assbin/AssbinLoader.h +++ b/Engine/lib/assimp/code/Assbin/AssbinLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Assjson/cencode.c b/Engine/lib/assimp/code/Assjson/cencode.c index db99e7efa..bd302100b 100644 --- a/Engine/lib/assimp/code/Assjson/cencode.c +++ b/Engine/lib/assimp/code/Assjson/cencode.c @@ -42,7 +42,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, { state_in->result = result; state_in->step = step_A; - return codechar - code_out; + return (int)(codechar - code_out); } fragment = *plainchar++; result = (fragment & 0x0fc) >> 2; @@ -53,7 +53,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, { state_in->result = result; state_in->step = step_B; - return codechar - code_out; + return (int)(codechar - code_out); } fragment = *plainchar++; result |= (fragment & 0x0f0) >> 4; @@ -64,7 +64,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, { state_in->result = result; state_in->step = step_C; - return codechar - code_out; + return (int)(codechar - code_out); } fragment = *plainchar++; result |= (fragment & 0x0c0) >> 6; @@ -81,7 +81,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, } } /* control should not reach here */ - return codechar - code_out; + return (int)(codechar - code_out); } int base64_encode_blockend(char* code_out, base64_encodestate* state_in) @@ -104,6 +104,6 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in) } *codechar++ = '\n'; - return codechar - code_out; + return (int)(codechar - code_out); } diff --git a/Engine/lib/assimp/code/Assxml/AssxmlExporter.cpp b/Engine/lib/assimp/code/Assxml/AssxmlExporter.cpp index afdecbaf6..720fd5b40 100644 --- a/Engine/lib/assimp/code/Assxml/AssxmlExporter.cpp +++ b/Engine/lib/assimp/code/Assxml/AssxmlExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -46,607 +46,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER -#include "PostProcessing/ProcessHelper.h" - -#include -#include +#include "AssxmlFileWriter.h" #include #include -#include - -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -#else -# include -#endif - -#include -#include - -using namespace Assimp; - namespace Assimp { -namespace AssxmlExport { - -// ----------------------------------------------------------------------------------- -static int ioprintf( IOStream * io, const char *format, ... ) { - using namespace std; - if ( nullptr == io ) { - return -1; - } - - static const int Size = 4096; - char sz[ Size ]; - ::memset( sz, '\0', Size ); - va_list va; - va_start( va, format ); - const unsigned int nSize = vsnprintf( sz, Size-1, format, va ); - ai_assert( nSize < Size ); - va_end( va ); - - io->Write( sz, sizeof(char), nSize ); - - return nSize; -} - -// ----------------------------------------------------------------------------------- -// Convert a name to standard XML format -static void ConvertName(aiString& out, const aiString& in) { - out.length = 0; - for (unsigned int i = 0; i < in.length; ++i) { - switch (in.data[i]) { - case '<': - out.Append("<");break; - case '>': - out.Append(">");break; - case '&': - out.Append("&");break; - case '\"': - out.Append(""");break; - case '\'': - out.Append("'");break; - default: - out.data[out.length++] = in.data[i]; - } - } - out.data[out.length] = 0; -} - -// ----------------------------------------------------------------------------------- -// Write a single node as text dump -static void WriteNode(const aiNode* node, IOStream * io, unsigned int depth) { - char prefix[512]; - for (unsigned int i = 0; i < depth;++i) - prefix[i] = '\t'; - prefix[depth] = '\0'; - - const aiMatrix4x4& m = node->mTransformation; - - aiString name; - ConvertName(name,node->mName); - ioprintf(io,"%s \n" - "%s\t \n" - "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" - "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" - "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" - "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" - "%s\t \n", - prefix,name.data,prefix, - prefix,m.a1,m.a2,m.a3,m.a4, - prefix,m.b1,m.b2,m.b3,m.b4, - prefix,m.c1,m.c2,m.c3,m.c4, - prefix,m.d1,m.d2,m.d3,m.d4,prefix); - - if (node->mNumMeshes) { - ioprintf(io, "%s\t\n%s\t", - prefix,node->mNumMeshes,prefix); - - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - ioprintf(io,"%i ",node->mMeshes[i]); - } - ioprintf(io,"\n%s\t\n",prefix); - } - - if (node->mNumChildren) { - ioprintf(io,"%s\t\n", - prefix,node->mNumChildren); - - for (unsigned int i = 0; i < node->mNumChildren;++i) { - WriteNode(node->mChildren[i],io,depth+2); - } - ioprintf(io,"%s\t\n",prefix); - } - ioprintf(io,"%s\n",prefix); -} - - -// ----------------------------------------------------------------------------------- -// Some chuncks of text will need to be encoded for XML -// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377 -static std::string encodeXML(const std::string& data) { - std::string buffer; - buffer.reserve(data.size()); - for(size_t pos = 0; pos != data.size(); ++pos) { - switch(data[pos]) { - case '&': buffer.append("&"); break; - case '\"': buffer.append("""); break; - case '\'': buffer.append("'"); break; - case '<': buffer.append("<"); break; - case '>': buffer.append(">"); break; - default: buffer.append(&data[pos], 1); break; - } - } - return buffer; -} - -// ----------------------------------------------------------------------------------- -// Write a text model dump -static -void WriteDump(const aiScene* scene, IOStream* io, bool shortened) { - time_t tt = ::time( NULL ); -#if _WIN32 - tm* p = gmtime(&tt); -#else - struct tm now; - tm* p = gmtime_r(&tt, &now); -#endif - ai_assert(nullptr != p); - - // write header - std::string header( - "\n" - "\n\n" - "" - " \n\n" - "\n" - ); - - const unsigned int majorVersion( aiGetVersionMajor() ); - const unsigned int minorVersion( aiGetVersionMinor() ); - const unsigned int rev( aiGetVersionRevision() ); - const char *curtime( asctime( p ) ); - ioprintf( io, header.c_str(), majorVersion, minorVersion, rev, curtime, scene->mFlags, 0 ); - - // write the node graph - WriteNode(scene->mRootNode, io, 0); - -#if 0 - // write cameras - for (unsigned int i = 0; i < scene->mNumCameras;++i) { - aiCamera* cam = scene->mCameras[i]; - ConvertName(name,cam->mName); - - // camera header - ioprintf(io,"\t\n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %f \n" - "\t\t %f \n" - "\t\t %f \n" - "\t\t %f \n" - "\t\n", - name.data, - cam->mUp.x,cam->mUp.y,cam->mUp.z, - cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z, - cam->mPosition.x,cam->mPosition.y,cam->mPosition.z, - cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i); - } - - // write lights - for (unsigned int i = 0; i < scene->mNumLights;++i) { - aiLight* l = scene->mLights[i]; - ConvertName(name,l->mName); - - // light header - ioprintf(io,"\t type=\"%s\"\n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %0 8f %0 8f %0 8f \n", - name.data, - (l->mType == aiLightSource_DIRECTIONAL ? "directional" : - (l->mType == aiLightSource_POINT ? "point" : "spot" )), - l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b, - l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b, - l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b); - - if (l->mType != aiLightSource_DIRECTIONAL) { - ioprintf(io, - "\t\t %0 8f %0 8f %0 8f \n" - "\t\t %f \n" - "\t\t %f \n" - "\t\t %f \n", - l->mPosition.x,l->mPosition.y,l->mPosition.z, - l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic); - } - - if (l->mType != aiLightSource_POINT) { - ioprintf(io, - "\t\t %0 8f %0 8f %0 8f \n", - l->mDirection.x,l->mDirection.y,l->mDirection.z); - } - - if (l->mType == aiLightSource_SPOT) { - ioprintf(io, - "\t\t %f \n" - "\t\t %f \n", - l->mAngleOuterCone,l->mAngleInnerCone); - } - ioprintf(io,"\t\n"); - } -#endif - aiString name; - - // write textures - if (scene->mNumTextures) { - ioprintf(io,"\n",scene->mNumTextures); - for (unsigned int i = 0; i < scene->mNumTextures;++i) { - aiTexture* tex = scene->mTextures[i]; - bool compressed = (tex->mHeight == 0); - - // mesh header - ioprintf(io,"\t \n", - (compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight), - (compressed ? "true" : "false")); - - if (compressed) { - ioprintf(io,"\t\t \n",tex->mWidth); - - if (!shortened) { - for (unsigned int n = 0; n < tex->mWidth;++n) { - ioprintf(io,"\t\t\t%2x",reinterpret_cast(tex->pcData)[n]); - if (n && !(n % 50)) { - ioprintf(io,"\n"); - } - } - } - } - else if (!shortened){ - ioprintf(io,"\t\t \n",tex->mWidth*tex->mHeight*4); - - // const unsigned int width = (unsigned int)std::log10((double)std::max(tex->mHeight,tex->mWidth))+1; - for (unsigned int y = 0; y < tex->mHeight;++y) { - for (unsigned int x = 0; x < tex->mWidth;++x) { - aiTexel* tx = tex->pcData + y*tex->mWidth+x; - unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a; - ioprintf(io,"\t\t\t%2x %2x %2x %2x",r,g,b,a); - - // group by four for readability - if ( 0 == ( x + y*tex->mWidth ) % 4 ) { - ioprintf( io, "\n" ); - } - } - } - } - ioprintf(io,"\t\t\n\t\n"); - } - ioprintf(io,"\n"); - } - - // write materials - if (scene->mNumMaterials) { - ioprintf(io,"\n",scene->mNumMaterials); - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { - const aiMaterial* mat = scene->mMaterials[i]; - - ioprintf(io,"\t\n"); - ioprintf(io,"\t\t\n",mat->mNumProperties); - for (unsigned int n = 0; n < mat->mNumProperties;++n) { - - const aiMaterialProperty* prop = mat->mProperties[n]; - const char* sz = ""; - if (prop->mType == aiPTI_Float) { - sz = "float"; - } - else if (prop->mType == aiPTI_Integer) { - sz = "integer"; - } - else if (prop->mType == aiPTI_String) { - sz = "string"; - } - else if (prop->mType == aiPTI_Buffer) { - sz = "binary_buffer"; - } - - ioprintf(io,"\t\t\tmKey.data, sz, - ::TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex); - - if (prop->mType == aiPTI_Float) { - ioprintf(io," size=\"%i\">\n\t\t\t\t", - static_cast(prop->mDataLength/sizeof(float))); - - for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) { - ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float)))); - } - } - else if (prop->mType == aiPTI_Integer) { - ioprintf(io," size=\"%i\">\n\t\t\t\t", - static_cast(prop->mDataLength/sizeof(int))); - - for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) { - ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int)))); - } - } - else if (prop->mType == aiPTI_Buffer) { - ioprintf(io," size=\"%i\">\n\t\t\t\t", - static_cast(prop->mDataLength)); - - for (unsigned int p = 0; p < prop->mDataLength;++p) { - ioprintf(io,"%2x ",prop->mData[p]); - if (p && 0 == p%30) { - ioprintf(io,"\n\t\t\t\t"); - } - } - } - else if (prop->mType == aiPTI_String) { - ioprintf(io,">\n\t\t\t\t\"%s\"",encodeXML(prop->mData+4).c_str() /* skip length */); - } - ioprintf(io,"\n\t\t\t\n"); - } - ioprintf(io,"\t\t\n"); - ioprintf(io,"\t\n"); - } - ioprintf(io,"\n"); - } - - // write animations - if (scene->mNumAnimations) { - ioprintf(io,"\n",scene->mNumAnimations); - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { - aiAnimation* anim = scene->mAnimations[i]; - - // anim header - ConvertName(name,anim->mName); - ioprintf(io,"\t\n", - name.data, anim->mDuration, anim->mTicksPerSecond); - - // write bone animation channels - if (anim->mNumChannels) { - ioprintf(io,"\t\t\n",anim->mNumChannels); - for (unsigned int n = 0; n < anim->mNumChannels;++n) { - aiNodeAnim* nd = anim->mChannels[n]; - - // node anim header - ConvertName(name,nd->mNodeName); - ioprintf(io,"\t\t\t\n",name.data); - - if (!shortened) { - // write position keys - if (nd->mNumPositionKeys) { - ioprintf(io,"\t\t\t\t\n",nd->mNumPositionKeys); - for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) { - aiVectorKey* vc = nd->mPositionKeys+a; - ioprintf(io,"\t\t\t\t\t\n" - "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", - vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); - } - ioprintf(io,"\t\t\t\t\n"); - } - - // write scaling keys - if (nd->mNumScalingKeys) { - ioprintf(io,"\t\t\t\t\n",nd->mNumScalingKeys); - for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) { - aiVectorKey* vc = nd->mScalingKeys+a; - ioprintf(io,"\t\t\t\t\t\n" - "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", - vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); - } - ioprintf(io,"\t\t\t\t\n"); - } - - // write rotation keys - if (nd->mNumRotationKeys) { - ioprintf(io,"\t\t\t\t\n",nd->mNumRotationKeys); - for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { - aiQuatKey* vc = nd->mRotationKeys+a; - ioprintf(io,"\t\t\t\t\t\n" - "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t\n", - vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w); - } - ioprintf(io,"\t\t\t\t\n"); - } - } - ioprintf(io,"\t\t\t\n"); - } - ioprintf(io,"\t\t\n"); - } - ioprintf(io,"\t\n"); - } - ioprintf(io,"\n"); - } - - // write meshes - if (scene->mNumMeshes) { - ioprintf(io,"\n",scene->mNumMeshes); - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - aiMesh* mesh = scene->mMeshes[i]; - // const unsigned int width = (unsigned int)std::log10((double)mesh->mNumVertices)+1; - - // mesh header - ioprintf(io,"\t\n", - (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""), - (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""), - (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""), - (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""), - mesh->mMaterialIndex); - - // bones - if (mesh->mNumBones) { - ioprintf(io,"\t\t\n",mesh->mNumBones); - - for (unsigned int n = 0; n < mesh->mNumBones;++n) { - aiBone* bone = mesh->mBones[n]; - - ConvertName(name,bone->mName); - // bone header - ioprintf(io,"\t\t\t\n" - "\t\t\t\t \n" - "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" - "\t\t\t\t \n", - name.data, - bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4, - bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4, - bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4, - bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4); - - if (!shortened && bone->mNumWeights) { - ioprintf(io,"\t\t\t\t\n",bone->mNumWeights); - - // bone weights - for (unsigned int a = 0; a < bone->mNumWeights;++a) { - aiVertexWeight* wght = bone->mWeights+a; - - ioprintf(io,"\t\t\t\t\t\n\t\t\t\t\t\t%f\n\t\t\t\t\t\n", - wght->mVertexId,wght->mWeight); - } - ioprintf(io,"\t\t\t\t\n"); - } - ioprintf(io,"\t\t\t\n"); - } - ioprintf(io,"\t\t\n"); - } - - // faces - if (!shortened && mesh->mNumFaces) { - ioprintf(io,"\t\t\n",mesh->mNumFaces); - for (unsigned int n = 0; n < mesh->mNumFaces; ++n) { - aiFace& f = mesh->mFaces[n]; - ioprintf(io,"\t\t\t\n" - "\t\t\t\t",f.mNumIndices); - - for (unsigned int j = 0; j < f.mNumIndices;++j) - ioprintf(io,"%i ",f.mIndices[j]); - - ioprintf(io,"\n\t\t\t\n"); - } - ioprintf(io,"\t\t\n"); - } - - // vertex positions - if (mesh->HasPositions()) { - ioprintf(io,"\t\t \n",mesh->mNumVertices); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mVertices[n].x, - mesh->mVertices[n].y, - mesh->mVertices[n].z); - } - } - ioprintf(io,"\t\t\n"); - } - - // vertex normals - if (mesh->HasNormals()) { - ioprintf(io,"\t\t \n",mesh->mNumVertices); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mNormals[n].x, - mesh->mNormals[n].y, - mesh->mNormals[n].z); - } - } - ioprintf(io,"\t\t\n"); - } - - // vertex tangents and bitangents - if (mesh->HasTangentsAndBitangents()) { - ioprintf(io,"\t\t \n",mesh->mNumVertices); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mTangents[n].x, - mesh->mTangents[n].y, - mesh->mTangents[n].z); - } - } - ioprintf(io,"\t\t\n"); - - ioprintf(io,"\t\t \n",mesh->mNumVertices); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mBitangents[n].x, - mesh->mBitangents[n].y, - mesh->mBitangents[n].z); - } - } - ioprintf(io,"\t\t\n"); - } - - // texture coordinates - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { - if (!mesh->mTextureCoords[a]) - break; - - ioprintf(io,"\t\t \n",mesh->mNumVertices, - a,mesh->mNumUVComponents[a]); - - if (!shortened) { - if (mesh->mNumUVComponents[a] == 3) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", - mesh->mTextureCoords[a][n].x, - mesh->mTextureCoords[a][n].y, - mesh->mTextureCoords[a][n].z); - } - } - else { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f\n", - mesh->mTextureCoords[a][n].x, - mesh->mTextureCoords[a][n].y); - } - } - } - ioprintf(io,"\t\t\n"); - } - - // vertex colors - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { - if (!mesh->mColors[a]) - break; - ioprintf(io,"\t\t \n",mesh->mNumVertices,a); - if (!shortened) { - for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { - ioprintf(io,"\t\t%0 8f %0 8f %0 8f %0 8f\n", - mesh->mColors[a][n].r, - mesh->mColors[a][n].g, - mesh->mColors[a][n].b, - mesh->mColors[a][n].a); - } - } - ioprintf(io,"\t\t\n"); - } - ioprintf(io,"\t\n"); - } - ioprintf(io,"\n"); - } - ioprintf(io,"\n"); -} - -} // end of namespace AssxmlExport - void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { - IOStream * out = pIOSystem->Open( pFile, "wt" ); - if (!out) return; - - bool shortened = false; - AssxmlExport::WriteDump( pScene, out, shortened ); - - pIOSystem->Close( out ); + DumpSceneToAssxml( + pFile, + "\0", // command(s) + pIOSystem, + pScene, + false); // shortened? } } // end of namespace Assimp diff --git a/Engine/lib/assimp/code/Assxml/AssxmlExporter.h b/Engine/lib/assimp/code/Assxml/AssxmlExporter.h index 8ca887eea..a2b40ada1 100644 --- a/Engine/lib/assimp/code/Assxml/AssxmlExporter.h +++ b/Engine/lib/assimp/code/Assxml/AssxmlExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.cpp b/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.cpp new file mode 100644 index 000000000..0ed59e509 --- /dev/null +++ b/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.cpp @@ -0,0 +1,664 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 AssxmlFileWriter.cpp + * @brief Implementation of Assxml file writer. + */ + +#include "AssxmlFileWriter.h" + +#include "PostProcessing/ProcessHelper.h" + +#include +#include +#include +#include + +#include + +#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +# include +#else +# include +#endif + +#include +#include +#include + +using namespace Assimp; + +namespace Assimp { + +namespace AssxmlFileWriter { + +// ----------------------------------------------------------------------------------- +static int ioprintf( IOStream * io, const char *format, ... ) { + using namespace std; + if ( nullptr == io ) { + return -1; + } + + static const int Size = 4096; + char sz[ Size ]; + ::memset( sz, '\0', Size ); + va_list va; + va_start( va, format ); + const unsigned int nSize = vsnprintf( sz, Size-1, format, va ); + ai_assert( nSize < Size ); + va_end( va ); + + io->Write( sz, sizeof(char), nSize ); + + return nSize; +} + +// ----------------------------------------------------------------------------------- +// Convert a name to standard XML format +static void ConvertName(aiString& out, const aiString& in) { + out.length = 0; + for (unsigned int i = 0; i < in.length; ++i) { + switch (in.data[i]) { + case '<': + out.Append("<");break; + case '>': + out.Append(">");break; + case '&': + out.Append("&");break; + case '\"': + out.Append(""");break; + case '\'': + out.Append("'");break; + default: + out.data[out.length++] = in.data[i]; + } + } + out.data[out.length] = 0; +} + +// ----------------------------------------------------------------------------------- +// Write a single node as text dump +static void WriteNode(const aiNode* node, IOStream * io, unsigned int depth) { + char prefix[512]; + for (unsigned int i = 0; i < depth;++i) + prefix[i] = '\t'; + prefix[depth] = '\0'; + + const aiMatrix4x4& m = node->mTransformation; + + aiString name; + ConvertName(name,node->mName); + ioprintf(io,"%s \n" + "%s\t \n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t\t%0 6f %0 6f %0 6f %0 6f\n" + "%s\t \n", + prefix,name.data,prefix, + prefix,m.a1,m.a2,m.a3,m.a4, + prefix,m.b1,m.b2,m.b3,m.b4, + prefix,m.c1,m.c2,m.c3,m.c4, + prefix,m.d1,m.d2,m.d3,m.d4,prefix); + + if (node->mNumMeshes) { + ioprintf(io, "%s\t\n%s\t", + prefix,node->mNumMeshes,prefix); + + for (unsigned int i = 0; i < node->mNumMeshes;++i) { + ioprintf(io,"%u ",node->mMeshes[i]); + } + ioprintf(io,"\n%s\t\n",prefix); + } + + if (node->mNumChildren) { + ioprintf(io,"%s\t\n", + prefix,node->mNumChildren); + + for (unsigned int i = 0; i < node->mNumChildren;++i) { + WriteNode(node->mChildren[i],io,depth+2); + } + ioprintf(io,"%s\t\n",prefix); + } + ioprintf(io,"%s\n",prefix); +} + + +// ----------------------------------------------------------------------------------- +// Some chuncks of text will need to be encoded for XML +// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377 +static std::string encodeXML(const std::string& data) { + std::string buffer; + buffer.reserve(data.size()); + for(size_t pos = 0; pos != data.size(); ++pos) { + switch(data[pos]) { + case '&': buffer.append("&"); break; + case '\"': buffer.append("""); break; + case '\'': buffer.append("'"); break; + case '<': buffer.append("<"); break; + case '>': buffer.append(">"); break; + default: buffer.append(&data[pos], 1); break; + } + } + return buffer; +} + +// ----------------------------------------------------------------------------------- +// Write a text model dump +static +void WriteDump(const char* pFile, const char* cmd, const aiScene* scene, IOStream* io, bool shortened) { + time_t tt = ::time( NULL ); +#if _WIN32 + tm* p = gmtime(&tt); +#else + struct tm now; + tm* p = gmtime_r(&tt, &now); +#endif + ai_assert(nullptr != p); + + std::string c = cmd; + std::string::size_type s; + + // https://sourceforge.net/tracker/?func=detail&aid=3167364&group_id=226462&atid=1067632 + // -- not allowed in XML comments + while((s = c.find("--")) != std::string::npos) { + c[s] = '?'; + } + + // write header + std::string header( + "\n" + "\n\n" + "" + " \n\n" + "\n" + ); + + const unsigned int majorVersion( aiGetVersionMajor() ); + const unsigned int minorVersion( aiGetVersionMinor() ); + const unsigned int rev( aiGetVersionRevision() ); + const char *curtime( asctime( p ) ); + ioprintf( io, header.c_str(), majorVersion, minorVersion, rev, pFile, c.c_str(), curtime, scene->mFlags, 0u ); + + // write the node graph + WriteNode(scene->mRootNode, io, 0); + +#if 0 + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + aiCamera* cam = scene->mCameras[i]; + ConvertName(name,cam->mName); + + // camera header + ioprintf(io,"\t\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\n", + name.data, + cam->mUp.x,cam->mUp.y,cam->mUp.z, + cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z, + cam->mPosition.x,cam->mPosition.y,cam->mPosition.z, + cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i); + } + + // write lights + for (unsigned int i = 0; i < scene->mNumLights;++i) { + aiLight* l = scene->mLights[i]; + ConvertName(name,l->mName); + + // light header + ioprintf(io,"\t type=\"%s\"\n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %0 8f %0 8f %0 8f \n", + name.data, + (l->mType == aiLightSource_DIRECTIONAL ? "directional" : + (l->mType == aiLightSource_POINT ? "point" : "spot" )), + l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b, + l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b, + l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b); + + if (l->mType != aiLightSource_DIRECTIONAL) { + ioprintf(io, + "\t\t %0 8f %0 8f %0 8f \n" + "\t\t %f \n" + "\t\t %f \n" + "\t\t %f \n", + l->mPosition.x,l->mPosition.y,l->mPosition.z, + l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic); + } + + if (l->mType != aiLightSource_POINT) { + ioprintf(io, + "\t\t %0 8f %0 8f %0 8f \n", + l->mDirection.x,l->mDirection.y,l->mDirection.z); + } + + if (l->mType == aiLightSource_SPOT) { + ioprintf(io, + "\t\t %f \n" + "\t\t %f \n", + l->mAngleOuterCone,l->mAngleInnerCone); + } + ioprintf(io,"\t\n"); + } +#endif + aiString name; + + // write textures + if (scene->mNumTextures) { + ioprintf(io,"\n",scene->mNumTextures); + for (unsigned int i = 0; i < scene->mNumTextures;++i) { + aiTexture* tex = scene->mTextures[i]; + bool compressed = (tex->mHeight == 0); + + // mesh header + ioprintf(io,"\t \n", + (compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight), + (compressed ? "true" : "false")); + + if (compressed) { + ioprintf(io,"\t\t \n",tex->mWidth); + + if (!shortened) { + for (unsigned int n = 0; n < tex->mWidth;++n) { + ioprintf(io,"\t\t\t%2x",reinterpret_cast(tex->pcData)[n]); + if (n && !(n % 50)) { + ioprintf(io,"\n"); + } + } + } + } + else if (!shortened){ + ioprintf(io,"\t\t \n",tex->mWidth*tex->mHeight*4); + + // const unsigned int width = (unsigned int)std::log10((double)std::max(tex->mHeight,tex->mWidth))+1; + for (unsigned int y = 0; y < tex->mHeight;++y) { + for (unsigned int x = 0; x < tex->mWidth;++x) { + aiTexel* tx = tex->pcData + y*tex->mWidth+x; + unsigned int r = tx->r,g=tx->g,b=tx->b,a=tx->a; + ioprintf(io,"\t\t\t%2x %2x %2x %2x",r,g,b,a); + + // group by four for readability + if ( 0 == ( x + y*tex->mWidth ) % 4 ) { + ioprintf( io, "\n" ); + } + } + } + } + ioprintf(io,"\t\t\n\t\n"); + } + ioprintf(io,"\n"); + } + + // write materials + if (scene->mNumMaterials) { + ioprintf(io,"\n",scene->mNumMaterials); + for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + const aiMaterial* mat = scene->mMaterials[i]; + + ioprintf(io,"\t\n"); + ioprintf(io,"\t\t\n",mat->mNumProperties); + for (unsigned int n = 0; n < mat->mNumProperties;++n) { + + const aiMaterialProperty* prop = mat->mProperties[n]; + const char* sz = ""; + if (prop->mType == aiPTI_Float) { + sz = "float"; + } + else if (prop->mType == aiPTI_Integer) { + sz = "integer"; + } + else if (prop->mType == aiPTI_String) { + sz = "string"; + } + else if (prop->mType == aiPTI_Buffer) { + sz = "binary_buffer"; + } + + ioprintf(io,"\t\t\tmKey.data, sz, + ::TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex); + + if (prop->mType == aiPTI_Float) { + ioprintf(io," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength/sizeof(float))); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) { + ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float)))); + } + } + else if (prop->mType == aiPTI_Integer) { + ioprintf(io," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength/sizeof(int))); + + for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) { + ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int)))); + } + } + else if (prop->mType == aiPTI_Buffer) { + ioprintf(io," size=\"%i\">\n\t\t\t\t", + static_cast(prop->mDataLength)); + + for (unsigned int p = 0; p < prop->mDataLength;++p) { + ioprintf(io,"%2x ",prop->mData[p]); + if (p && 0 == p%30) { + ioprintf(io,"\n\t\t\t\t"); + } + } + } + else if (prop->mType == aiPTI_String) { + ioprintf(io,">\n\t\t\t\t\"%s\"",encodeXML(prop->mData+4).c_str() /* skip length */); + } + ioprintf(io,"\n\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + ioprintf(io,"\t\n"); + } + ioprintf(io,"\n"); + } + + // write animations + if (scene->mNumAnimations) { + ioprintf(io,"\n",scene->mNumAnimations); + for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + aiAnimation* anim = scene->mAnimations[i]; + + // anim header + ConvertName(name,anim->mName); + ioprintf(io,"\t\n", + name.data, anim->mDuration, anim->mTicksPerSecond); + + // write bone animation channels + if (anim->mNumChannels) { + ioprintf(io,"\t\t\n",anim->mNumChannels); + for (unsigned int n = 0; n < anim->mNumChannels;++n) { + aiNodeAnim* nd = anim->mChannels[n]; + + // node anim header + ConvertName(name,nd->mNodeName); + ioprintf(io,"\t\t\t\n",name.data); + + if (!shortened) { + // write position keys + if (nd->mNumPositionKeys) { + ioprintf(io,"\t\t\t\t\n",nd->mNumPositionKeys); + for (unsigned int a = 0; a < nd->mNumPositionKeys;++a) { + aiVectorKey* vc = nd->mPositionKeys+a; + ioprintf(io,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); + } + ioprintf(io,"\t\t\t\t\n"); + } + + // write scaling keys + if (nd->mNumScalingKeys) { + ioprintf(io,"\t\t\t\t\n",nd->mNumScalingKeys); + for (unsigned int a = 0; a < nd->mNumScalingKeys;++a) { + aiVectorKey* vc = nd->mScalingKeys+a; + ioprintf(io,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z); + } + ioprintf(io,"\t\t\t\t\n"); + } + + // write rotation keys + if (nd->mNumRotationKeys) { + ioprintf(io,"\t\t\t\t\n",nd->mNumRotationKeys); + for (unsigned int a = 0; a < nd->mNumRotationKeys;++a) { + aiQuatKey* vc = nd->mRotationKeys+a; + ioprintf(io,"\t\t\t\t\t\n" + "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t\n", + vc->mTime,vc->mValue.x,vc->mValue.y,vc->mValue.z,vc->mValue.w); + } + ioprintf(io,"\t\t\t\t\n"); + } + } + ioprintf(io,"\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + } + ioprintf(io,"\t\n"); + } + ioprintf(io,"\n"); + } + + // write meshes + if (scene->mNumMeshes) { + ioprintf(io,"\n",scene->mNumMeshes); + for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + aiMesh* mesh = scene->mMeshes[i]; + // const unsigned int width = (unsigned int)std::log10((double)mesh->mNumVertices)+1; + + // mesh header + ioprintf(io,"\t\n", + (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""), + (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""), + mesh->mMaterialIndex); + + // bones + if (mesh->mNumBones) { + ioprintf(io,"\t\t\n",mesh->mNumBones); + + for (unsigned int n = 0; n < mesh->mNumBones;++n) { + aiBone* bone = mesh->mBones[n]; + + ConvertName(name,bone->mName); + // bone header + ioprintf(io,"\t\t\t\n" + "\t\t\t\t \n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n" + "\t\t\t\t \n", + name.data, + bone->mOffsetMatrix.a1,bone->mOffsetMatrix.a2,bone->mOffsetMatrix.a3,bone->mOffsetMatrix.a4, + bone->mOffsetMatrix.b1,bone->mOffsetMatrix.b2,bone->mOffsetMatrix.b3,bone->mOffsetMatrix.b4, + bone->mOffsetMatrix.c1,bone->mOffsetMatrix.c2,bone->mOffsetMatrix.c3,bone->mOffsetMatrix.c4, + bone->mOffsetMatrix.d1,bone->mOffsetMatrix.d2,bone->mOffsetMatrix.d3,bone->mOffsetMatrix.d4); + + if (!shortened && bone->mNumWeights) { + ioprintf(io,"\t\t\t\t\n",bone->mNumWeights); + + // bone weights + for (unsigned int a = 0; a < bone->mNumWeights;++a) { + aiVertexWeight* wght = bone->mWeights+a; + + ioprintf(io,"\t\t\t\t\t\n\t\t\t\t\t\t%f\n\t\t\t\t\t\n", + wght->mVertexId,wght->mWeight); + } + ioprintf(io,"\t\t\t\t\n"); + } + ioprintf(io,"\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + } + + // faces + if (!shortened && mesh->mNumFaces) { + ioprintf(io,"\t\t\n",mesh->mNumFaces); + for (unsigned int n = 0; n < mesh->mNumFaces; ++n) { + aiFace& f = mesh->mFaces[n]; + ioprintf(io,"\t\t\t\n" + "\t\t\t\t",f.mNumIndices); + + for (unsigned int j = 0; j < f.mNumIndices;++j) + ioprintf(io,"%u ",f.mIndices[j]); + + ioprintf(io,"\n\t\t\t\n"); + } + ioprintf(io,"\t\t\n"); + } + + // vertex positions + if (mesh->HasPositions()) { + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mVertices[n].x, + mesh->mVertices[n].y, + mesh->mVertices[n].z); + } + } + ioprintf(io,"\t\t\n"); + } + + // vertex normals + if (mesh->HasNormals()) { + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mNormals[n].x, + mesh->mNormals[n].y, + mesh->mNormals[n].z); + } + } + ioprintf(io,"\t\t\n"); + } + + // vertex tangents and bitangents + if (mesh->HasTangentsAndBitangents()) { + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mTangents[n].x, + mesh->mTangents[n].y, + mesh->mTangents[n].z); + } + } + ioprintf(io,"\t\t\n"); + + ioprintf(io,"\t\t \n",mesh->mNumVertices); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mBitangents[n].x, + mesh->mBitangents[n].y, + mesh->mBitangents[n].z); + } + } + ioprintf(io,"\t\t\n"); + } + + // texture coordinates + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (!mesh->mTextureCoords[a]) + break; + + ioprintf(io,"\t\t \n",mesh->mNumVertices, + a,mesh->mNumUVComponents[a]); + + if (!shortened) { + if (mesh->mNumUVComponents[a] == 3) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y, + mesh->mTextureCoords[a][n].z); + } + } + else { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f\n", + mesh->mTextureCoords[a][n].x, + mesh->mTextureCoords[a][n].y); + } + } + } + ioprintf(io,"\t\t\n"); + } + + // vertex colors + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { + if (!mesh->mColors[a]) + break; + ioprintf(io,"\t\t \n",mesh->mNumVertices,a); + if (!shortened) { + for (unsigned int n = 0; n < mesh->mNumVertices; ++n) { + ioprintf(io,"\t\t%0 8f %0 8f %0 8f %0 8f\n", + mesh->mColors[a][n].r, + mesh->mColors[a][n].g, + mesh->mColors[a][n].b, + mesh->mColors[a][n].a); + } + } + ioprintf(io,"\t\t\n"); + } + ioprintf(io,"\t\n"); + } + ioprintf(io,"\n"); + } + ioprintf(io,"\n"); +} + +} // end of namespace AssxmlFileWriter + +void DumpSceneToAssxml( + const char* pFile, const char* cmd, IOSystem* pIOSystem, + const aiScene* pScene, bool shortened) { + std::unique_ptr file(pIOSystem->Open(pFile, "wt")); + if (!file.get()) { + throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n'); + } + + AssxmlFileWriter::WriteDump(pFile, cmd, pScene, file.get(), shortened); +} + +} // end of namespace Assimp diff --git a/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.h b/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.h new file mode 100644 index 000000000..c10a8a5aa --- /dev/null +++ b/Engine/lib/assimp/code/Assxml/AssxmlFileWriter.h @@ -0,0 +1,65 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 AssxmlFileWriter.h + * @brief Declaration of Assxml file writer. + */ + +#ifndef AI_ASSXMLFILEWRITER_H_INC +#define AI_ASSXMLFILEWRITER_H_INC + +#include +#include +#include + +namespace Assimp { + +void ASSIMP_API DumpSceneToAssxml( + const char* pFile, + const char* cmd, + IOSystem* pIOSystem, + const aiScene* pScene, + bool shortened); + +} + +#endif // AI_ASSXMLFILEWRITER_H_INC diff --git a/Engine/lib/assimp/code/B3D/B3DImporter.cpp b/Engine/lib/assimp/code/B3D/B3DImporter.cpp index ba484ca00..07336df65 100644 --- a/Engine/lib/assimp/code/B3D/B3DImporter.cpp +++ b/Engine/lib/assimp/code/B3D/B3DImporter.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team - - +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -78,7 +76,6 @@ static const aiImporterDesc desc = { "b3d" }; -// (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings #ifdef _MSC_VER # pragma warning (disable: 4018) #endif @@ -86,10 +83,8 @@ static const aiImporterDesc desc = { //#define DEBUG_B3D template -void DeleteAllBarePointers(std::vector& x) -{ - for(auto p : x) - { +void DeleteAllBarePointers(std::vector& x) { + for(auto p : x) { delete p; } } @@ -102,10 +97,14 @@ B3DImporter::~B3DImporter() bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{ size_t pos=pFile.find_last_of( '.' ); - if( pos==string::npos ) return false; + if( pos==string::npos ) { + return false; + } string ext=pFile.substr( pos+1 ); - if( ext.size()!=3 ) return false; + if( ext.size()!=3 ) { + return false; + } return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D'); } @@ -117,30 +116,21 @@ const aiImporterDesc* B3DImporter::GetInfo () const return &desc; } -#ifdef DEBUG_B3D - extern "C"{ void _stdcall AllocConsole(); } -#endif // ------------------------------------------------------------------------------------------------ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){ - -#ifdef DEBUG_B3D - AllocConsole(); - freopen( "conin$","r",stdin ); - freopen( "conout$","w",stdout ); - freopen( "conout$","w",stderr ); - cout<<"Hello world from the B3DImporter!"< file( pIOHandler->Open( pFile)); // Check whether we can read from the file - if( file.get() == NULL) + if( file.get() == nullptr) { throw DeadlyImportError( "Failed to open B3D file " + pFile + "."); + } // check whether the .b3d file is large enough to contain // at least one chunk. size_t fileSize = file->FileSize(); - if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small."); + if( fileSize<8 ) { + throw DeadlyImportError( "B3D File is too small."); + } _pos=0; _buf.resize( fileSize ); @@ -158,14 +148,17 @@ AI_WONT_RETURN void B3DImporter::Oops(){ // ------------------------------------------------------------------------------------------------ AI_WONT_RETURN void B3DImporter::Fail( string str ){ #ifdef DEBUG_B3D - cout<<"Error in B3D file data: "< &v ){ return p; } - // ------------------------------------------------------------------------------------------------ template T **unique_to_array( vector > &v ){ @@ -283,7 +277,6 @@ T **unique_to_array( vector > &v ){ return p; } - // ------------------------------------------------------------------------------------------------ void B3DImporter::ReadTEXS(){ while( ChunkSize() ){ @@ -376,9 +369,13 @@ void B3DImporter::ReadVRTS(){ v.vertex=ReadVec3(); - if( _vflags & 1 ) v.normal=ReadVec3(); + if( _vflags & 1 ) { + v.normal=ReadVec3(); + } - if( _vflags & 2 ) ReadQuat(); //skip v 4bytes... + if( _vflags & 2 ) { + ReadQuat(); //skip v 4bytes... + } for( int i=0;i<_tcsets;++i ){ float t[4]={0,0,0,0}; @@ -386,53 +383,55 @@ void B3DImporter::ReadVRTS(){ t[j]=ReadFloat(); } t[1]=1-t[1]; - if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] ); + if( !i ) { + v.texcoords=aiVector3D( t[0],t[1],t[2] ); + } } } } // ------------------------------------------------------------------------------------------------ -void B3DImporter::ReadTRIS( int v0 ){ - int matid=ReadInt(); - if( matid==-1 ){ - matid=0; - }else if( matid<0 || matid>=(int)_materials.size() ){ +void B3DImporter::ReadTRIS(int v0) { + int matid = ReadInt(); + if (matid == -1) { + matid = 0; + } else if (matid < 0 || matid >= (int)_materials.size()) { #ifdef DEBUG_B3D - cout<<"material id="< mesh(new aiMesh); + std::unique_ptr mesh(new aiMesh); - mesh->mMaterialIndex=matid; - mesh->mNumFaces=0; - mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE; + mesh->mMaterialIndex = matid; + mesh->mNumFaces = 0; + mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - int n_tris=ChunkSize()/12; - aiFace *face=mesh->mFaces=new aiFace[n_tris]; + int n_tris = ChunkSize() / 12; + aiFace *face = mesh->mFaces = new aiFace[n_tris]; - for( int i=0;i=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){ + for (int i = 0; i < n_tris; ++i) { + int i0 = ReadInt() + v0; + int i1 = ReadInt() + v0; + int i2 = ReadInt() + v0; + if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) { #ifdef DEBUG_B3D - cout<<"Bad triangle index: i0="<mNumIndices=3; - face->mIndices=new unsigned[3]; - face->mIndices[0]=i0; - face->mIndices[1]=i1; - face->mIndices[2]=i2; - ++mesh->mNumFaces; - ++face; - } + Fail("Bad triangle index"); + continue; + } + face->mNumIndices = 3; + face->mIndices = new unsigned[3]; + face->mIndices[0] = i0; + face->mIndices[1] = i1; + face->mIndices[2] = i2; + ++mesh->mNumFaces; + ++face; + } - _meshes.emplace_back( std::move(mesh) ); + _meshes.emplace_back(std::move(mesh)); } // ------------------------------------------------------------------------------------------------ @@ -453,29 +452,23 @@ void B3DImporter::ReadMESH(){ } // ------------------------------------------------------------------------------------------------ -void B3DImporter::ReadBONE( int id ){ - while( ChunkSize() ){ - int vertex=ReadInt(); - float weight=ReadFloat(); - if( vertex<0 || vertex>=(int)_vertices.size() ){ - Fail( "Bad vertex index" ); - } +void B3DImporter::ReadBONE(int id) { + while (ChunkSize()) { + int vertex = ReadInt(); + float weight = ReadFloat(); + if (vertex < 0 || vertex >= (int)_vertices.size()) { + Fail("Bad vertex index"); + } - Vertex &v=_vertices[vertex]; - int i; - for( i=0;i<4;++i ){ - if( !v.weights[i] ){ - v.bones[i]=id; - v.weights[i]=weight; - break; - } - } -#ifdef DEBUG_B3D - if( i==4 ){ - cout<<"Too many bone weights"<mNumVertices=n_tris * 3; aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0; - if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ]; - if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; + if( _vflags & 1 ) { + mn=mesh->mNormals=new aiVector3D[ n_verts ]; + } + if( _tcsets ) { + mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; + } aiFace *face=mesh->mFaces; diff --git a/Engine/lib/assimp/code/B3D/B3DImporter.h b/Engine/lib/assimp/code/B3D/B3DImporter.h index d52dac34a..f0568dd16 100644 --- a/Engine/lib/assimp/code/B3D/B3DImporter.h +++ b/Engine/lib/assimp/code/B3D/B3DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/BVH/BVHLoader.cpp b/Engine/lib/assimp/code/BVH/BVHLoader.cpp index cd9ab0843..1110754c2 100644 --- a/Engine/lib/assimp/code/BVH/BVHLoader.cpp +++ b/Engine/lib/assimp/code/BVH/BVHLoader.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/BVH/BVHLoader.h b/Engine/lib/assimp/code/BVH/BVHLoader.h index 33b4e2453..93a3e5e83 100644 --- a/Engine/lib/assimp/code/BVH/BVHLoader.h +++ b/Engine/lib/assimp/code/BVH/BVHLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderBMesh.cpp b/Engine/lib/assimp/code/Blender/BlenderBMesh.cpp index 8a13819a6..039302e12 100644 --- a/Engine/lib/assimp/code/Blender/BlenderBMesh.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderBMesh.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2013, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Blender/BlenderBMesh.h b/Engine/lib/assimp/code/Blender/BlenderBMesh.h index 5b65fb503..893128606 100644 --- a/Engine/lib/assimp/code/Blender/BlenderBMesh.h +++ b/Engine/lib/assimp/code/Blender/BlenderBMesh.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2013, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Blender/BlenderDNA.cpp b/Engine/lib/assimp/code/Blender/BlenderDNA.cpp index f274e02f9..53fb84824 100644 --- a/Engine/lib/assimp/code/Blender/BlenderDNA.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderDNA.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderDNA.h b/Engine/lib/assimp/code/Blender/BlenderDNA.h index 375d0c4bf..16ce960e2 100644 --- a/Engine/lib/assimp/code/Blender/BlenderDNA.h +++ b/Engine/lib/assimp/code/Blender/BlenderDNA.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderDNA.inl b/Engine/lib/assimp/code/Blender/BlenderDNA.inl index 65bc1374c..fd9993008 100644 --- a/Engine/lib/assimp/code/Blender/BlenderDNA.inl +++ b/Engine/lib/assimp/code/Blender/BlenderDNA.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderIntermediate.h b/Engine/lib/assimp/code/Blender/BlenderIntermediate.h index 95fdf0f03..2c480b848 100644 --- a/Engine/lib/assimp/code/Blender/BlenderIntermediate.h +++ b/Engine/lib/assimp/code/Blender/BlenderIntermediate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderLoader.cpp b/Engine/lib/assimp/code/Blender/BlenderLoader.cpp index d39cb9699..93e6d1589 100644 --- a/Engine/lib/assimp/code/Blender/BlenderLoader.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderLoader.h b/Engine/lib/assimp/code/Blender/BlenderLoader.h index d85a82842..8110ac946 100644 --- a/Engine/lib/assimp/code/Blender/BlenderLoader.h +++ b/Engine/lib/assimp/code/Blender/BlenderLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderModifier.cpp b/Engine/lib/assimp/code/Blender/BlenderModifier.cpp index cc7acc929..6f8a5d7ee 100644 --- a/Engine/lib/assimp/code/Blender/BlenderModifier.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderModifier.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderModifier.h b/Engine/lib/assimp/code/Blender/BlenderModifier.h index c260ba1f6..ad6fad68d 100644 --- a/Engine/lib/assimp/code/Blender/BlenderModifier.h +++ b/Engine/lib/assimp/code/Blender/BlenderModifier.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderScene.cpp b/Engine/lib/assimp/code/Blender/BlenderScene.cpp index 39c2793d5..1391a2833 100644 --- a/Engine/lib/assimp/code/Blender/BlenderScene.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderScene.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Blender/BlenderScene.h b/Engine/lib/assimp/code/Blender/BlenderScene.h index dd3f1444c..afa168d49 100644 --- a/Engine/lib/assimp/code/Blender/BlenderScene.h +++ b/Engine/lib/assimp/code/Blender/BlenderScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderSceneGen.h b/Engine/lib/assimp/code/Blender/BlenderSceneGen.h index ce94d0dc2..0c93d17a3 100644 --- a/Engine/lib/assimp/code/Blender/BlenderSceneGen.h +++ b/Engine/lib/assimp/code/Blender/BlenderSceneGen.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Blender/BlenderTessellator.cpp b/Engine/lib/assimp/code/Blender/BlenderTessellator.cpp index d98c2e865..3c1cd6ea8 100644 --- a/Engine/lib/assimp/code/Blender/BlenderTessellator.cpp +++ b/Engine/lib/assimp/code/Blender/BlenderTessellator.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Blender/BlenderTessellator.h b/Engine/lib/assimp/code/Blender/BlenderTessellator.h index 518e56c72..63ea1f828 100644 --- a/Engine/lib/assimp/code/Blender/BlenderTessellator.h +++ b/Engine/lib/assimp/code/Blender/BlenderTessellator.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/C4D/C4DImporter.cpp b/Engine/lib/assimp/code/C4D/C4DImporter.cpp index 6e5b7d39b..24fd6f622 100644 --- a/Engine/lib/assimp/code/C4D/C4DImporter.cpp +++ b/Engine/lib/assimp/code/C4D/C4DImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/C4D/C4DImporter.h b/Engine/lib/assimp/code/C4D/C4DImporter.h index f3b1351f6..f9406c3e0 100644 --- a/Engine/lib/assimp/code/C4D/C4DImporter.h +++ b/Engine/lib/assimp/code/C4D/C4DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/CApi/AssimpCExport.cpp b/Engine/lib/assimp/code/CApi/AssimpCExport.cpp index 7557edcfc..137cc2894 100644 --- a/Engine/lib/assimp/code/CApi/AssimpCExport.cpp +++ b/Engine/lib/assimp/code/CApi/AssimpCExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.cpp b/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.cpp index 5a3a49565..91dd07f37 100644 --- a/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.cpp +++ b/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.h b/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.h index 216232030..298847494 100644 --- a/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.h +++ b/Engine/lib/assimp/code/CApi/CInterfaceIOWrapper.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/CMakeLists.txt b/Engine/lib/assimp/code/CMakeLists.txt index 827f43333..0dff5d9e4 100644 --- a/Engine/lib/assimp/code/CMakeLists.txt +++ b/Engine/lib/assimp/code/CMakeLists.txt @@ -1,7 +1,7 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2019, assimp team +# Copyright (c) 2006-2020, assimp team # # All rights reserved. # @@ -49,7 +49,7 @@ SET( HEADER_PATH ../include/assimp ) if(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) message(WARNING "Requesting Android JNI I/O-System in non-Android toolchain. Resetting ASSIMP_ANDROID_JNIIOSYSTEM to OFF.") set(ASSIMP_ANDROID_JNIIOSYSTEM OFF) -endif(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) +endif() SET( COMPILER_HEADERS ${HEADER_PATH}/Compiler/pushpack1.h @@ -66,6 +66,7 @@ SET( PUBLIC_HEADERS ${HEADER_PATH}/color4.h ${HEADER_PATH}/color4.inl ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h + ${HEADER_PATH}/commonMetaData.h ${HEADER_PATH}/defs.h ${HEADER_PATH}/Defines.h ${HEADER_PATH}/cfileio.h @@ -147,7 +148,7 @@ SET( Core_SRCS IF(MSVC) list(APPEND Core_SRCS "res/assimp.rc") -ENDIF(MSVC) +ENDIF() SET( Logging_SRCS ${HEADER_PATH}/DefaultLogger.hpp @@ -184,8 +185,6 @@ SET( Common_SRCS Common/ScenePreprocessor.cpp Common/ScenePreprocessor.h Common/SkeletonMeshBuilder.cpp - Common/SplitByBoneCountProcess.cpp - Common/SplitByBoneCountProcess.h Common/StandardShapes.cpp Common/TargetAnimation.cpp Common/TargetAnimation.h @@ -197,6 +196,7 @@ SET( Common_SRCS Common/CreateAnimMesh.cpp Common/simd.h Common/simd.cpp + Common/material.cpp ) SOURCE_GROUP(Common FILES ${Common_SRCS}) @@ -220,7 +220,7 @@ IF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER ) C4D/C4DImporter.h ) SOURCE_GROUP( C4D FILES ${C4D_SRCS}) -ENDIF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER ) +ENDIF () # if this variable is set to TRUE, the user can manually disable importers by setting # ASSIMP_BUILD_XXX_IMPORTER to FALSE for each importer @@ -250,35 +250,39 @@ MACRO(ADD_ASSIMP_IMPORTER name) ENDIF() ENDMACRO() -# if this variable is set to TRUE, the user can manually disable exporters by setting -# ASSIMP_BUILD_XXX_EXPORTER to FALSE for each exporter -# if this variable is set to FALSE, the user can manually enable exporters by setting -# ASSIMP_BUILD_XXX_EXPORTER to TRUE for each exporter -OPTION(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_EXPORTER values" TRUE) +if (NOT ASSIMP_NO_EXPORT) -# macro to add the CMake Option ADD_ASSIMP_IMPORTER_ which enables compile of loader -# this way selective loaders can be compiled (reduces filesize + compile time) -MACRO(ADD_ASSIMP_EXPORTER name) - IF (ASSIMP_NO_EXPORT) - set(ASSIMP_EXPORTER_ENABLED FALSE) - ELSEIF (ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT) - set(ASSIMP_EXPORTER_ENABLED TRUE) - IF (DEFINED ASSIMP_BUILD_${name}_EXPORTER AND NOT ASSIMP_BUILD_${name}_EXPORTER) + # if this variable is set to TRUE, the user can manually disable exporters by setting + # ASSIMP_BUILD_XXX_EXPORTER to FALSE for each exporter + # if this variable is set to FALSE, the user can manually enable exporters by setting + # ASSIMP_BUILD_XXX_EXPORTER to TRUE for each exporter + OPTION(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_EXPORTER values" TRUE) + + # macro to add the CMake Option ADD_ASSIMP_IMPORTER_ which enables compile of loader + # this way selective loaders can be compiled (reduces filesize + compile time) + MACRO(ADD_ASSIMP_EXPORTER name) + IF (ASSIMP_NO_EXPORT) set(ASSIMP_EXPORTER_ENABLED FALSE) + ELSEIF (ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT) + set(ASSIMP_EXPORTER_ENABLED TRUE) + IF (DEFINED ASSIMP_BUILD_${name}_EXPORTER AND NOT ASSIMP_BUILD_${name}_EXPORTER) + set(ASSIMP_EXPORTER_ENABLED FALSE) + ENDIF () + ELSE () + set(ASSIMP_EXPORTER_ENABLED ${ASSIMP_BUILD_${name}_EXPORTER}) ENDIF () - ELSE () - set(ASSIMP_EXPORTER_ENABLED ${ASSIMP_BUILD_${name}_EXPORTER}) - ENDIF () - IF (ASSIMP_EXPORTER_ENABLED) - SET(ASSIMP_EXPORTERS_ENABLED "${ASSIMP_EXPORTERS_ENABLED} ${name}") - LIST(APPEND ASSIMP_EXPORTER_SRCS ${ARGN}) - SOURCE_GROUP(${name}_EXPORTER FILES ${ARGN}) - ELSE() - SET(ASSIMP_EXPORTERS_DISABLED "${ASSIMP_EXPORTERS_DISABLED} ${name}") - add_definitions(-DASSIMP_BUILD_NO_${name}_EXPORTER) - ENDIF() -ENDMACRO() + IF (ASSIMP_EXPORTER_ENABLED) + SET(ASSIMP_EXPORTERS_ENABLED "${ASSIMP_EXPORTERS_ENABLED} ${name}") + LIST(APPEND ASSIMP_EXPORTER_SRCS ${ARGN}) + SOURCE_GROUP(${name}_EXPORTER FILES ${ARGN}) + ELSE() + SET(ASSIMP_EXPORTERS_DISABLED "${ASSIMP_EXPORTERS_DISABLED} ${name}") + add_definitions(-DASSIMP_BUILD_NO_${name}_EXPORTER) + ENDIF() + ENDMACRO() + +endif() SET(ASSIMP_LOADER_SRCS "") SET(ASSIMP_IMPORTERS_ENABLED "") # list of enabled importers @@ -305,11 +309,6 @@ ADD_ASSIMP_IMPORTER( 3DS 3DS/3DSLoader.h ) -ADD_ASSIMP_EXPORTER( 3DS - 3DS/3DSExporter.h - 3DS/3DSExporter.cpp -) - ADD_ASSIMP_IMPORTER( AC AC/ACLoader.cpp AC/ACLoader.h @@ -327,16 +326,6 @@ ADD_ASSIMP_IMPORTER( ASSBIN Assbin/AssbinLoader.cpp ) -ADD_ASSIMP_EXPORTER( ASSBIN - Assbin/AssbinExporter.h - Assbin/AssbinExporter.cpp -) - -ADD_ASSIMP_EXPORTER( ASSXML - Assxml/AssxmlExporter.h - Assxml/AssxmlExporter.cpp -) - ADD_ASSIMP_IMPORTER( B3D B3D/B3DImporter.cpp B3D/B3DImporter.h @@ -348,6 +337,7 @@ ADD_ASSIMP_IMPORTER( BVH ) ADD_ASSIMP_IMPORTER( COLLADA + Collada/ColladaHelper.cpp Collada/ColladaHelper.h Collada/ColladaLoader.cpp Collada/ColladaLoader.h @@ -355,11 +345,6 @@ ADD_ASSIMP_IMPORTER( COLLADA Collada/ColladaParser.h ) -ADD_ASSIMP_EXPORTER( COLLADA - Collada/ColladaExporter.h - Collada/ColladaExporter.cpp -) - ADD_ASSIMP_IMPORTER( DXF DXF/DXFLoader.cpp DXF/DXFLoader.h @@ -411,14 +396,11 @@ ADD_ASSIMP_IMPORTER( M3D M3D/M3DMaterials.h M3D/M3DImporter.h M3D/M3DImporter.cpp + M3D/M3DWrapper.h + M3D/M3DWrapper.cpp M3D/m3d.h ) -ADD_ASSIMP_EXPORTER( M3D - M3D/M3DExporter.h - M3D/M3DExporter.cpp -) - ADD_ASSIMP_IMPORTER( MD2 MD2/MD2FileData.h MD2/MD2Loader.cpp @@ -452,6 +434,16 @@ ADD_ASSIMP_IMPORTER( MDL MDL/MDLLoader.cpp MDL/MDLLoader.h MDL/MDLMaterialLoader.cpp + MDL/HalfLife/HalfLifeMDLBaseHeader.h + MDL/HalfLife/HL1FileData.h + MDL/HalfLife/HL1MDLLoader.cpp + MDL/HalfLife/HL1MDLLoader.h + MDL/HalfLife/HL1ImportDefinitions.h + MDL/HalfLife/HL1ImportSettings.h + MDL/HalfLife/HL1MeshTrivert.h + MDL/HalfLife/LogFunctions.h + MDL/HalfLife/UniqueNameGenerator.cpp + MDL/HalfLife/UniqueNameGenerator.h ) SET( MaterialSystem_SRCS @@ -486,11 +478,6 @@ ADD_ASSIMP_IMPORTER( OBJ Obj/ObjTools.h ) -ADD_ASSIMP_EXPORTER( OBJ - Obj/ObjExporter.h - Obj/ObjExporter.cpp -) - ADD_ASSIMP_IMPORTER( OGRE Ogre/OgreImporter.h Ogre/OgreStructs.h @@ -510,11 +497,6 @@ ADD_ASSIMP_IMPORTER( OPENGEX OpenGEX/OpenGEXStructs.h ) -ADD_ASSIMP_EXPORTER( OPENGEX - OpenGEX/OpenGEXExporter.cpp - OpenGEX/OpenGEXExporter.h -) - ADD_ASSIMP_IMPORTER( PLY Ply/PlyLoader.cpp Ply/PlyLoader.h @@ -522,11 +504,6 @@ ADD_ASSIMP_IMPORTER( PLY Ply/PlyParser.h ) -ADD_ASSIMP_EXPORTER( PLY - Ply/PlyExporter.cpp - Ply/PlyExporter.h -) - ADD_ASSIMP_IMPORTER( MS3D MS3D/MS3DLoader.cpp MS3D/MS3DLoader.h @@ -580,7 +557,7 @@ if (ASSIMP_BUILD_IFC_IMPORTER) elseif(CMAKE_COMPILER_IS_MINGW) set_source_files_properties(Importer/IFC/IFCReaderGen1_2x3.cpp Importer/IFC/IFCReaderGen2_2x3.cpp PROPERTIES COMPILE_FLAGS "-O2 -Wa,-mbig-obj") endif() -endif (ASSIMP_BUILD_IFC_IMPORTER) +endif () ADD_ASSIMP_IMPORTER( XGL XGL/XGLLoader.cpp @@ -616,14 +593,86 @@ ADD_ASSIMP_IMPORTER( FBX FBX/FBXCommon.h ) -ADD_ASSIMP_EXPORTER( FBX - FBX/FBXExporter.h - FBX/FBXExporter.cpp - FBX/FBXExportNode.h - FBX/FBXExportNode.cpp - FBX/FBXExportProperty.h - FBX/FBXExportProperty.cpp -) +if (NOT ASSIMP_NO_EXPORT) + + ADD_ASSIMP_EXPORTER( OBJ + Obj/ObjExporter.h + Obj/ObjExporter.cpp) + + ADD_ASSIMP_EXPORTER( OPENGEX + OpenGEX/OpenGEXExporter.cpp + OpenGEX/OpenGEXExporter.h) + + ADD_ASSIMP_EXPORTER( PLY + Ply/PlyExporter.cpp + Ply/PlyExporter.h) + + ADD_ASSIMP_EXPORTER( 3DS + 3DS/3DSExporter.h + 3DS/3DSExporter.cpp) + + ADD_ASSIMP_EXPORTER( ASSBIN + Assbin/AssbinExporter.h + Assbin/AssbinExporter.cpp + Assbin/AssbinFileWriter.h + Assbin/AssbinFileWriter.cpp) + + ADD_ASSIMP_EXPORTER( ASSXML + Assxml/AssxmlExporter.h + Assxml/AssxmlExporter.cpp + Assxml/AssxmlFileWriter.h + Assxml/AssxmlFileWriter.cpp) + + ADD_ASSIMP_EXPORTER(M3D + M3D/M3DExporter.h + M3D/M3DExporter.cpp) + + ADD_ASSIMP_EXPORTER(COLLADA + Collada/ColladaExporter.h + Collada/ColladaExporter.cpp) + + ADD_ASSIMP_EXPORTER( FBX + FBX/FBXExporter.h + FBX/FBXExporter.cpp + FBX/FBXExportNode.h + FBX/FBXExportNode.cpp + FBX/FBXExportProperty.h + FBX/FBXExportProperty.cpp) + + ADD_ASSIMP_EXPORTER( STL + STL/STLExporter.h + STL/STLExporter.cpp) + + ADD_ASSIMP_EXPORTER( X + X/XFileExporter.h + X/XFileExporter.cpp) + + ADD_ASSIMP_EXPORTER( X3D + X3D/X3DExporter.cpp + X3D/X3DExporter.hpp) + + ADD_ASSIMP_EXPORTER( GLTF + glTF/glTFExporter.h + glTF/glTFExporter.cpp + glTF2/glTF2Exporter.h + glTF2/glTF2Exporter.cpp) + + ADD_ASSIMP_EXPORTER( 3MF + 3MF/D3MFExporter.h + 3MF/D3MFExporter.cpp) + + ADD_ASSIMP_EXPORTER( ASSJSON + Assjson/cencode.c + Assjson/cencode.h + Assjson/json_exporter.cpp + Assjson/mesh_splitter.cpp + Assjson/mesh_splitter.h) + + ADD_ASSIMP_EXPORTER( STEP + Step/StepExporter.h + Step/StepExporter.cpp) + +endif() SET( PostProcessing_SRCS PostProcessing/CalcTangentsProcess.cpp @@ -686,6 +735,8 @@ SET( PostProcessing_SRCS PostProcessing/ArmaturePopulate.h PostProcessing/GenBoundingBoxesProcess.cpp PostProcessing/GenBoundingBoxesProcess.h + PostProcessing/SplitByBoneCountProcess.cpp + PostProcessing/SplitByBoneCountProcess.h ) SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS}) @@ -725,11 +776,6 @@ ADD_ASSIMP_IMPORTER( STL STL/STLLoader.h ) -ADD_ASSIMP_EXPORTER( STL - STL/STLExporter.h - STL/STLExporter.cpp -) - ADD_ASSIMP_IMPORTER( TERRAGEN Terragen/TerragenLoader.cpp Terragen/TerragenLoader.h @@ -748,11 +794,6 @@ ADD_ASSIMP_IMPORTER( X X/XFileParser.h ) -ADD_ASSIMP_EXPORTER( X - X/XFileExporter.h - X/XFileExporter.cpp -) - ADD_ASSIMP_IMPORTER( X3D X3D/X3DImporter.cpp X3D/X3DImporter.hpp @@ -773,11 +814,6 @@ ADD_ASSIMP_IMPORTER( X3D X3D/X3DVocabulary.cpp ) -ADD_ASSIMP_EXPORTER( X3D - X3D/X3DExporter.cpp - X3D/X3DExporter.hpp -) - ADD_ASSIMP_IMPORTER( GLTF glTF/glTFCommon.h glTF/glTFCommon.cpp @@ -795,13 +831,6 @@ ADD_ASSIMP_IMPORTER( GLTF glTF2/glTF2Importer.h ) -ADD_ASSIMP_EXPORTER( GLTF - glTF/glTFExporter.h - glTF/glTFExporter.cpp - glTF2/glTF2Exporter.h - glTF2/glTF2Exporter.cpp -) - ADD_ASSIMP_IMPORTER( 3MF 3MF/D3MFImporter.h 3MF/D3MFImporter.cpp @@ -810,11 +839,6 @@ ADD_ASSIMP_IMPORTER( 3MF 3MF/3MFXmlTags.h ) -ADD_ASSIMP_EXPORTER( 3MF - 3MF/D3MFExporter.h - 3MF/D3MFExporter.cpp -) - ADD_ASSIMP_IMPORTER( MMD MMD/MMDCpp14.h MMD/MMDImporter.cpp @@ -825,14 +849,6 @@ ADD_ASSIMP_IMPORTER( MMD MMD/MMDVmdParser.h ) -ADD_ASSIMP_EXPORTER( ASSJSON - Assjson/cencode.c - Assjson/cencode.h - Assjson/json_exporter.cpp - Assjson/mesh_splitter.cpp - Assjson/mesh_splitter.h -) - # Workaround for issue #2406 - force problematic large file to be optimized to prevent string table overflow error # Used -Os instead of -O2 as previous issues had mentioned, since -Os is roughly speaking -O2, excluding any # optimizations that take up extra space. Given that the issue is a string table overflowing, -Os seemed appropriate @@ -855,11 +871,6 @@ ADD_ASSIMP_IMPORTER( STEP Importer/StepFile/StepReaderGen.h ) -ADD_ASSIMP_EXPORTER( STEP - Step/StepExporter.h - Step/StepExporter.cpp -) - if ((NOT ASSIMP_NO_EXPORT) OR (NOT ASSIMP_EXPORTERS_ENABLED STREQUAL "")) SET( Exporter_SRCS Common/Exporter.cpp @@ -878,35 +889,35 @@ SOURCE_GROUP( Extra FILES ${Extra_SRCS}) IF(HUNTER_ENABLED) hunter_add_package(irrXML) find_package(irrXML CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() # irrXML already included in contrib directory by parent CMakeLists.txt. -ENDIF(HUNTER_ENABLED) +ENDIF() # utf8 IF(HUNTER_ENABLED) hunter_add_package(utf8) find_package(utf8 CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() # utf8 is header-only, so Assimp doesn't need to do anything. -ENDIF(HUNTER_ENABLED) +ENDIF() # polyclipping IF(HUNTER_ENABLED) hunter_add_package(polyclipping) find_package(polyclipping CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET( Clipper_SRCS ../contrib/clipper/clipper.hpp ../contrib/clipper/clipper.cpp ) SOURCE_GROUP( Contrib\\Clipper FILES ${Clipper_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # poly2tri IF(HUNTER_ENABLED) hunter_add_package(poly2tri) find_package(poly2tri CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET( Poly2Tri_SRCS ../contrib/poly2tri/poly2tri/common/shapes.cc ../contrib/poly2tri/poly2tri/common/shapes.h @@ -921,13 +932,13 @@ ELSE(HUNTER_ENABLED) ../contrib/poly2tri/poly2tri/sweep/sweep_context.h ) SOURCE_GROUP( Contrib\\Poly2Tri FILES ${Poly2Tri_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # minizip/unzip IF(HUNTER_ENABLED) hunter_add_package(minizip) find_package(minizip CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET( unzip_SRCS ../contrib/unzip/crypt.h ../contrib/unzip/ioapi.c @@ -936,13 +947,13 @@ ELSE(HUNTER_ENABLED) ../contrib/unzip/unzip.h ) SOURCE_GROUP(Contrib\\unzip FILES ${unzip_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # zip (https://github.com/kuba--/zip) IF(HUNTER_ENABLED) hunter_add_package(zip) find_package(zip CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET( ziplib_SRCS ../contrib/zip/src/miniz.h ../contrib/zip/src/zip.c @@ -957,13 +968,13 @@ ELSE(HUNTER_ENABLED) endif() SOURCE_GROUP( ziplib FILES ${ziplib_SRCS} ) -ENDIF(HUNTER_ENABLED) +ENDIF() # openddlparser IF(HUNTER_ENABLED) hunter_add_package(openddlparser) find_package(openddlparser CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() SET ( openddl_parser_SRCS ../contrib/openddlparser/code/OpenDDLParser.cpp ../contrib/openddlparser/code/DDLNode.cpp @@ -980,12 +991,12 @@ ELSE(HUNTER_ENABLED) ../contrib/openddlparser/include/openddlparser/Value.h ) SOURCE_GROUP( Contrib\\openddl_parser FILES ${openddl_parser_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # Open3DGC IF(HUNTER_ENABLED) # Nothing to do, not available in Hunter yet. -ELSE(HUNTER_ENABLED) +ELSE() SET ( open3dgc_SRCS ../contrib/Open3DGC/o3dgcAdjacencyInfo.h ../contrib/Open3DGC/o3dgcArithmeticCodec.cpp @@ -1018,7 +1029,7 @@ ELSE(HUNTER_ENABLED) ../contrib/Open3DGC/o3dgcVector.inl ) SOURCE_GROUP( Contrib\\open3dgc FILES ${open3dgc_SRCS}) -ENDIF(HUNTER_ENABLED) +ENDIF() # Check dependencies for glTF importer with Open3DGC-compression. # RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file @@ -1037,40 +1048,42 @@ ENDIF () IF(HUNTER_ENABLED) hunter_add_package(RapidJSON) find_package(RapidJSON CONFIG REQUIRED) -ELSE(HUNTER_ENABLED) +ELSE() INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" ) INCLUDE_DIRECTORIES( "../contrib" ) -ENDIF(HUNTER_ENABLED) +ENDIF() # VC2010 fixes if(MSVC10) option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF ) if( VC10_STDINT_FIX ) ADD_DEFINITIONS( -D_STDINT ) - endif( VC10_STDINT_FIX ) -endif(MSVC10) + endif() +endif() ADD_DEFINITIONS( -DASSIMP_BUILD_DLL_EXPORT ) if ( MSVC ) ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) -endif ( MSVC ) +endif () IF(NOT HUNTER_ENABLED) if (UNZIP_FOUND) SET (unzip_compile_SRCS "") - else (UNZIP_FOUND) + else () SET (unzip_compile_SRCS ${unzip_SRCS}) INCLUDE_DIRECTORIES( "../contrib/unzip/" ) - endif (UNZIP_FOUND) -ENDIF(NOT HUNTER_ENABLED) + endif () +ENDIF() MESSAGE(STATUS "Enabled importer formats:${ASSIMP_IMPORTERS_ENABLED}") MESSAGE(STATUS "Disabled importer formats:${ASSIMP_IMPORTERS_DISABLED}") -MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}") -MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}") +if (NOT ASSIMP_NO_EXPORT) + MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}") + MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}") +endif() SOURCE_GROUP( include\\assimp FILES ${PUBLIC_HEADERS} ) @@ -1110,12 +1123,12 @@ IF(NOT HUNTER_ENABLED) ${IRRXML_INCLUDE_DIR} ../contrib/openddlparser/include ) -ENDIF(NOT HUNTER_ENABLED) +ENDIF() IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) SET( assimp_src ${assimp_src} ${C4D_SRCS}) INCLUDE_DIRECTORIES(${C4D_INCLUDES}) -ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) +ENDIF () ADD_LIBRARY( assimp ${assimp_src} ) ADD_LIBRARY(assimp::assimp ALIAS assimp) @@ -1139,21 +1152,21 @@ IF(HUNTER_ENABLED) utf8::utf8 zip::zip ) -ELSE(HUNTER_ENABLED) +ELSE() TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ${IRRXML_LIBRARY} ) -ENDIF(HUNTER_ENABLED) +ENDIF() if(ASSIMP_ANDROID_JNIIOSYSTEM) set(ASSIMP_ANDROID_JNIIOSYSTEM_PATH port/AndroidJNI) add_subdirectory(../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/ ../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/) target_link_libraries(assimp android_jniiosystem) -endif(ASSIMP_ANDROID_JNIIOSYSTEM) +endif() IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) TARGET_LINK_LIBRARIES(assimp optimized ${C4D_RELEASE_LIBRARIES}) TARGET_LINK_LIBRARIES(assimp debug ${C4D_DEBUG_LIBRARIES}) TARGET_LINK_LIBRARIES(assimp ${C4D_EXTRA_LIBRARIES}) -ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) +ENDIF () if( MSVC ) # in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix @@ -1199,10 +1212,6 @@ SET_TARGET_PROPERTIES( assimp PROPERTIES ) if (APPLE) - SET_TARGET_PROPERTIES( assimp PROPERTIES - INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR}" - ) - if (BUILD_FRAMEWORK) SET_TARGET_PROPERTIES( assimp PROPERTIES FRAMEWORK TRUE @@ -1218,8 +1227,8 @@ if (APPLE) "../${HEADER_PATH}/Compiler" assimp.framework/Headers/Compiler COMMENT "Copying public ./Compiler/ header files to framework bundle's Headers/Compiler/") - ENDIF(BUILD_FRAMEWORK) -ENDIF(APPLE) + ENDIF() +ENDIF() # Build against external unzip, or add ../contrib/unzip so # assimp can #include "unzip.h" @@ -1227,15 +1236,15 @@ IF(NOT HUNTER_ENABLED) if (UNZIP_FOUND) INCLUDE_DIRECTORIES(${UNZIP_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES}) - else (UNZIP_FOUND) + else () INCLUDE_DIRECTORIES("../") - endif (UNZIP_FOUND) -ENDIF(NOT HUNTER_ENABLED) + endif () +ENDIF() # Add RT-extension library for glTF importer with Open3DGC-compression. IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY}) -ENDIF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) +ENDIF () IF(HUNTER_ENABLED) INSTALL( TARGETS assimp @@ -1246,14 +1255,14 @@ IF(HUNTER_ENABLED) FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} INCLUDES DESTINATION "include") -ELSE(HUNTER_ENABLED) +ELSE() INSTALL( TARGETS assimp LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}) -ENDIF(HUNTER_ENABLED) +ENDIF() INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev) INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev) @@ -1261,7 +1270,7 @@ if (ASSIMP_ANDROID_JNIIOSYSTEM) INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR} COMPONENT assimp-dev) -ENDIF(ASSIMP_ANDROID_JNIIOSYSTEM) +ENDIF() if(MSVC AND ASSIMP_INSTALL_PDB) # When only the static library is built, these properties must diff --git a/Engine/lib/assimp/code/COB/COBLoader.cpp b/Engine/lib/assimp/code/COB/COBLoader.cpp index 19e3cd59e..8e7c81192 100644 --- a/Engine/lib/assimp/code/COB/COBLoader.cpp +++ b/Engine/lib/assimp/code/COB/COBLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -250,7 +250,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill const Mesh& ndmesh = (const Mesh&)(root); if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) { - typedef std::pair Entry; + typedef std::pair Entry; for(const Entry& reflist : ndmesh.temp_map) { { // create mesh size_t n = 0; diff --git a/Engine/lib/assimp/code/COB/COBLoader.h b/Engine/lib/assimp/code/COB/COBLoader.h index 40fed324b..8b3110a32 100644 --- a/Engine/lib/assimp/code/COB/COBLoader.h +++ b/Engine/lib/assimp/code/COB/COBLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/COB/COBScene.h b/Engine/lib/assimp/code/COB/COBScene.h index 90349be70..87f4f4570 100644 --- a/Engine/lib/assimp/code/COB/COBScene.h +++ b/Engine/lib/assimp/code/COB/COBScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/CSM/CSMLoader.cpp b/Engine/lib/assimp/code/CSM/CSMLoader.cpp index 9dbb38467..fbabea12e 100644 --- a/Engine/lib/assimp/code/CSM/CSMLoader.cpp +++ b/Engine/lib/assimp/code/CSM/CSMLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -178,7 +178,7 @@ void CSMImporter::InternReadFile( const std::string& pFile, *ot++ = *buffer++; *ot = '\0'; - nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data); + nda->mNodeName.length = (ai_uint32)(ot-nda->mNodeName.data); } anim->mNumChannels = static_cast(anims_temp.size()); diff --git a/Engine/lib/assimp/code/CSM/CSMLoader.h b/Engine/lib/assimp/code/CSM/CSMLoader.h index 31a814b52..907c7aa43 100644 --- a/Engine/lib/assimp/code/CSM/CSMLoader.h +++ b/Engine/lib/assimp/code/CSM/CSMLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Collada/ColladaExporter.cpp b/Engine/lib/assimp/code/Collada/ColladaExporter.cpp index a93dfa59a..99cdc097b 100644 --- a/Engine/lib/assimp/code/Collada/ColladaExporter.cpp +++ b/Engine/lib/assimp/code/Collada/ColladaExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaExporter.h" #include +#include #include #include #include @@ -277,7 +278,7 @@ void ColladaExporter::WriteHeader() { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; } - if (nullptr == meta || !meta->Get("AuthoringTool", value)) { + if (nullptr == meta || !meta->Get(AI_METADATA_SOURCE_GENERATOR, value)) { mOutput << startstr << "" << "Assimp Exporter" << "" << endstr; } else { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; @@ -287,7 +288,7 @@ void ColladaExporter::WriteHeader() { if (meta->Get("Comments", value)) { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; } - if (meta->Get("Copyright", value)) { + if (meta->Get(AI_METADATA_SOURCE_COPYRIGHT, value)) { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; } if (meta->Get("SourceData", value)) { diff --git a/Engine/lib/assimp/code/Collada/ColladaExporter.h b/Engine/lib/assimp/code/Collada/ColladaExporter.h index 0b4fa59a3..f6c66e279 100644 --- a/Engine/lib/assimp/code/Collada/ColladaExporter.h +++ b/Engine/lib/assimp/code/Collada/ColladaExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Collada/ColladaHelper.cpp b/Engine/lib/assimp/code/Collada/ColladaHelper.cpp new file mode 100644 index 000000000..6f1fed366 --- /dev/null +++ b/Engine/lib/assimp/code/Collada/ColladaHelper.cpp @@ -0,0 +1,107 @@ +/** Helper structures for the Collada loader */ + +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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. + +---------------------------------------------------------------------- +*/ + +#include "ColladaHelper.h" + +#include +#include + +namespace Assimp { +namespace Collada { + +const MetaKeyPairVector MakeColladaAssimpMetaKeys() { + MetaKeyPairVector result; + result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR); + result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT); + return result; +}; + +const MetaKeyPairVector &GetColladaAssimpMetaKeys() { + static const MetaKeyPairVector result = MakeColladaAssimpMetaKeys(); + return result; +} + +const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() { + MetaKeyPairVector result = MakeColladaAssimpMetaKeys(); + for (auto &val : result) + { + ToCamelCase(val.first); + } + return result; +}; + +const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() +{ + static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase(); + return result; +} + +// ------------------------------------------------------------------------------------------------ +// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool" +void ToCamelCase(std::string &text) +{ + if (text.empty()) + return; + // Capitalise first character + auto it = text.begin(); + (*it) = ToUpper(*it); + ++it; + for (/*started above*/ ; it != text.end(); /*iterated below*/) + { + if ((*it) == '_') + { + it = text.erase(it); + if (it != text.end()) + (*it) = ToUpper(*it); + } + else + { + // Make lower case + (*it) = ToLower(*it); + ++it; + } + } +} + +} // namespace Collada +} // namespace Assimp diff --git a/Engine/lib/assimp/code/Collada/ColladaHelper.h b/Engine/lib/assimp/code/Collada/ColladaHelper.h index b7d47da15..c6e2e7ddd 100644 --- a/Engine/lib/assimp/code/Collada/ColladaHelper.h +++ b/Engine/lib/assimp/code/Collada/ColladaHelper.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -104,6 +105,17 @@ enum MorphMethod Relative }; +/** Common metadata keys as */ +typedef std::pair MetaKeyPair; +typedef std::vector MetaKeyPairVector; + +// Collada as lower_case (native) +const MetaKeyPairVector &GetColladaAssimpMetaKeys(); +// Collada as CamelCase (used by Assimp for consistency) +const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase(); + +/** Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool" */ +void ToCamelCase(std::string &text); /** Contains all data for one of the different transformation types */ struct Transform @@ -647,23 +659,37 @@ struct Animation void CombineSingleChannelAnimationsRecursively(Animation *pParent) { + std::set childrenTargets; + bool childrenAnimationsHaveDifferentChannels = true; + for (std::vector::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { Animation *anim = *it; - CombineSingleChannelAnimationsRecursively(anim); - if (anim->mChannels.size() == 1) + if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 && + childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) { + childrenTargets.insert(anim->mChannels[0].mTarget); + } else { + childrenAnimationsHaveDifferentChannels = false; + } + + ++it; + } + + // We only want to combine animations if they have different channels + if (childrenAnimationsHaveDifferentChannels) + { + for (std::vector::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) { + Animation *anim = *it; + pParent->mChannels.push_back(anim->mChannels[0]); it = pParent->mSubAnims.erase(it); delete anim; - } - else - { - ++it; + continue; } } } diff --git a/Engine/lib/assimp/code/Collada/ColladaLoader.cpp b/Engine/lib/assimp/code/Collada/ColladaLoader.cpp index 37529bc98..b78fc0e3b 100644 --- a/Engine/lib/assimp/code/Collada/ColladaLoader.cpp +++ b/Engine/lib/assimp/code/Collada/ColladaLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -963,18 +963,38 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars // catch special case: many animations with the same length, each affecting only a single node. // we need to unite all those single-node-anims to a proper combined animation - for( size_t a = 0; a < mAnims.size(); ++a) { + for(size_t a = 0; a < mAnims.size(); ++a) { aiAnimation* templateAnim = mAnims[a]; - if( templateAnim->mNumChannels == 1) { + + if (templateAnim->mNumChannels == 1) { // search for other single-channel-anims with the same duration std::vector collectedAnimIndices; for( size_t b = a+1; b < mAnims.size(); ++b) { aiAnimation* other = mAnims[b]; if (other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && other->mTicksPerSecond == templateAnim->mTicksPerSecond) - collectedAnimIndices.push_back(b); + collectedAnimIndices.push_back(b); } + // We only want to combine the animations if they have different channels + std::set animTargets; + animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str()); + bool collectedAnimationsHaveDifferentChannels = true; + for (size_t b = 0; b < collectedAnimIndices.size(); ++b) + { + aiAnimation* srcAnimation = mAnims[collectedAnimIndices[b]]; + std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str()); + if (animTargets.find(channelName) == animTargets.end()) { + animTargets.insert(channelName); + } else { + collectedAnimationsHaveDifferentChannels = false; + break; + } + } + + if (!collectedAnimationsHaveDifferentChannels) + continue; + // if there are other animations which fit the template anim, combine all channels into a single anim if (!collectedAnimIndices.empty()) { diff --git a/Engine/lib/assimp/code/Collada/ColladaLoader.h b/Engine/lib/assimp/code/Collada/ColladaLoader.h index d8d3f4f52..198b7a215 100644 --- a/Engine/lib/assimp/code/Collada/ColladaLoader.h +++ b/Engine/lib/assimp/code/Collada/ColladaLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Collada/ColladaParser.cpp b/Engine/lib/assimp/code/Collada/ColladaParser.cpp index 1a7b96189..d0f71d95a 100644 --- a/Engine/lib/assimp/code/Collada/ColladaParser.cpp +++ b/Engine/lib/assimp/code/Collada/ColladaParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include "ColladaParser.h" +#include #include #include #include @@ -249,6 +250,9 @@ void ColladaParser::UriDecodePath(aiString& ss) bool ColladaParser::ReadBoolFromTextContent() { const char* cur = GetTextContent(); + if ( nullptr == cur) { + return false; + } return (!ASSIMP_strincmp(cur, "true", 4) || '0' != *cur); } @@ -257,6 +261,9 @@ bool ColladaParser::ReadBoolFromTextContent() ai_real ColladaParser::ReadFloatFromTextContent() { const char* cur = GetTextContent(); + if ( nullptr == cur ) { + return 0.0; + } return fast_atof(cur); } @@ -276,6 +283,11 @@ void ColladaParser::ReadContents() if (attrib != -1) { const char* version = mReader->getAttributeValue(attrib); + // Store declared format version string + aiString v; + v.Set(version); + mAssetMetaData.emplace(AI_METADATA_SOURCE_FORMAT_VERSION, v ); + if (!::strncmp(version, "1.5", 3)) { mFormat = FV_1_5_n; ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n"); @@ -434,23 +446,39 @@ void ColladaParser::ReadContributorInfo() } } +static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVector &key_renaming, size_t &found_index) { + for (size_t i = 0; i < key_renaming.size(); ++i) { + if (key_renaming[i].first == collada_key) { + found_index = i; + return true; + } + } + found_index = std::numeric_limits::max(); + return false; +} + // ------------------------------------------------------------------------------------------------ // Reads a single string metadata item -void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) -{ - // Metadata such as created, keywords, subject etc - const char* key_char = mReader->getNodeName(); - if (key_char != nullptr) - { +void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) { + const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase(); + // Metadata such as created, keywords, subject etc + const char *key_char = mReader->getNodeName(); + if (key_char != nullptr) { const std::string key_str(key_char); - const char* value_char = TestTextContent(); - if (value_char != nullptr) - { - std::string camel_key_str = key_str; - ToCamelCase(camel_key_str); + const char *value_char = TestTextContent(); + if (value_char != nullptr) { aiString aistr; - aistr.Set(value_char); - metadata.emplace(camel_key_str, aistr); + aistr.Set(value_char); + + std::string camel_key_str(key_str); + ToCamelCase(camel_key_str); + + size_t found_index; + if (FindCommonKey(camel_key_str, key_renaming, found_index)) { + metadata.emplace(key_renaming[found_index].second, aistr); + } else { + metadata.emplace(camel_key_str, aistr); + } } TestClosing(key_str.c_str()); } @@ -458,27 +486,6 @@ void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) SkipElement(); } -// ------------------------------------------------------------------------------------------------ -// Convert underscore_seperated to CamelCase: "authoring_tool" becomes "AuthoringTool" -void ColladaParser::ToCamelCase(std::string &text) -{ - if (text.empty()) - return; - // Capitalise first character - text[0] = ToUpper(text[0]); - for (auto it = text.begin(); it != text.end(); /*iterated below*/) - { - if ((*it) == '_') - { - it = text.erase(it); - if (it != text.end()) - (*it) = ToUpper(*it); - } - else - ++it; - } -} - // ------------------------------------------------------------------------------------------------ // Reads the animation clips void ColladaParser::ReadAnimationClipLibrary() @@ -3234,13 +3241,12 @@ void ColladaParser::ReadScene() // ------------------------------------------------------------------------------------------------ // Aborts the file reading with an exception -AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const -{ +AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const { throw DeadlyImportError(format() << "Collada: " << mFileName << " - " << pError); } -void ColladaParser::ReportWarning(const char* msg, ...) -{ - ai_assert(NULL != msg); + +void ColladaParser::ReportWarning(const char* msg, ...) { + ai_assert(nullptr != msg); va_list args; va_start(args, msg); @@ -3255,11 +3261,11 @@ void ColladaParser::ReportWarning(const char* msg, ...) // ------------------------------------------------------------------------------------------------ // Skips all data until the end node of the current element -void ColladaParser::SkipElement() -{ +void ColladaParser::SkipElement() { // nothing to skip if it's an - if (mReader->isEmptyElement()) + if (mReader->isEmptyElement()) { return; + } // reroute SkipElement(mReader->getNodeName()); @@ -3267,63 +3273,75 @@ void ColladaParser::SkipElement() // ------------------------------------------------------------------------------------------------ // Skips all data until the end node of the given element -void ColladaParser::SkipElement(const char* pElement) -{ +void ColladaParser::SkipElement(const char* pElement) { // copy the current node's name because it'a pointer to the reader's internal buffer, // which is going to change with the upcoming parsing std::string element = pElement; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - if (mReader->getNodeName() == element) + while (mReader->read()) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (mReader->getNodeName() == element) { break; + } + } } } // ------------------------------------------------------------------------------------------------ // Tests for an opening element of the given name, throws an exception if not found -void ColladaParser::TestOpening(const char* pName) -{ +void ColladaParser::TestOpening(const char* pName) { // read element start - if (!mReader->read()) + if (!mReader->read()) { ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element."); + } // whitespace in front is ok, just read again if found - if (mReader->getNodeType() == irr::io::EXN_TEXT) - if (!mReader->read()) + if (mReader->getNodeType() == irr::io::EXN_TEXT) { + if (!mReader->read()) { ThrowException(format() << "Unexpected end of file while reading beginning of <" << pName << "> element."); + } + } - if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) + if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) { ThrowException(format() << "Expected start of <" << pName << "> element."); + } } // ------------------------------------------------------------------------------------------------ // Tests for the closing tag of the given element, throws an exception if not found -void ColladaParser::TestClosing(const char* pName) -{ - // check if we're already on the closing tag and return right away - if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0) +void ColladaParser::TestClosing(const char* pName) { + // check if we have an empty (self-closing) element + if (mReader->isEmptyElement()) { return; + } + + // check if we're already on the closing tag and return right away + if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0) { + return; + } // if not, read some more - if (!mReader->read()) + if (!mReader->read()) { ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); + } // whitespace in front is ok, just read again if found - if (mReader->getNodeType() == irr::io::EXN_TEXT) - if (!mReader->read()) + if (mReader->getNodeType() == irr::io::EXN_TEXT) { + if (!mReader->read()) { ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); + } + } // but this has the be the closing tag, or we're lost - if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) + if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) { ThrowException(format() << "Expected end of <" << pName << "> element."); + } } // ------------------------------------------------------------------------------------------------ // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes -int ColladaParser::GetAttribute(const char* pAttr) const -{ +int ColladaParser::GetAttribute(const char* pAttr) const { int index = TestAttribute(pAttr); - if (index != -1) + if (index != -1) { return index; + } // attribute not found -> throw an exception ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); diff --git a/Engine/lib/assimp/code/Collada/ColladaParser.h b/Engine/lib/assimp/code/Collada/ColladaParser.h index 4e8c8fccf..d1e812bd2 100644 --- a/Engine/lib/assimp/code/Collada/ColladaParser.h +++ b/Engine/lib/assimp/code/Collada/ColladaParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- - Copyright (c) 2006-2019, assimp team + Copyright (c) 2006-2020, assimp team All rights reserved. @@ -94,12 +94,9 @@ namespace Assimp /** Reads contributor information such as author and legal blah */ void ReadContributorInfo(); - /** Reads generic metadata into provided map */ + /** Reads generic metadata into provided map and renames keys for Assimp */ void ReadMetaDataItem(StringMetaData &metadata); - /** Convert underscore_seperated to CamelCase "authoring_tool" becomes "AuthoringTool" */ - static void ToCamelCase(std::string &text); - /** Reads the animation library */ void ReadAnimationLibrary(); diff --git a/Engine/lib/assimp/code/Common/Assimp.cpp b/Engine/lib/assimp/code/Common/Assimp.cpp index 178b2c01d..66588f0bc 100644 --- a/Engine/lib/assimp/code/Common/Assimp.cpp +++ b/Engine/lib/assimp/code/Common/Assimp.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/BaseImporter.cpp b/Engine/lib/assimp/code/Common/BaseImporter.cpp index 5c1e60554..8d7b029ba 100644 --- a/Engine/lib/assimp/code/Common/BaseImporter.cpp +++ b/Engine/lib/assimp/code/Common/BaseImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -191,7 +191,7 @@ void BaseImporter::GetExtensionList(std::set& extensions) { } std::unique_ptr pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { + if (pStream) { // read 200 characters from the file std::unique_ptr _buffer (new char[searchBytes+1 /* for the '\0' */]); char *buffer( _buffer.get() ); @@ -283,7 +283,6 @@ std::string BaseImporter::GetExtension( const std::string& file ) { return ""; } - // thanks to Andy Maloney for the hint std::string ret = file.substr( pos + 1 ); std::transform( ret.begin(), ret.end(), ret.begin(), ToLower); @@ -309,7 +308,7 @@ std::string BaseImporter::GetExtension( const std::string& file ) { }; magic = reinterpret_cast(_magic); std::unique_ptr pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { + if (pStream) { // skip to offset pStream->Seek(offset,aiOrigin_SET); @@ -603,7 +602,7 @@ unsigned int BatchLoader::AddLoadRequest(const std::string& file, } // no, we don't have it. So add it to the queue ... - m_data->requests.push_back(LoadRequest(file,steps,map, m_data->next_id)); + m_data->requests.emplace_back(file, steps, map, m_data->next_id); return m_data->next_id++; } diff --git a/Engine/lib/assimp/code/Common/BaseProcess.cpp b/Engine/lib/assimp/code/Common/BaseProcess.cpp index e247be418..d02653cf2 100644 --- a/Engine/lib/assimp/code/Common/BaseProcess.cpp +++ b/Engine/lib/assimp/code/Common/BaseProcess.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team - - +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -43,45 +41,43 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Implementation of BaseProcess */ -#include #include "BaseProcess.h" -#include -#include #include "Importer.h" +#include +#include +#include using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer BaseProcess::BaseProcess() AI_NO_EXCEPT -: shared() -, progress() -{ + : shared(), + progress() { + // empty } // ------------------------------------------------------------------------------------------------ // Destructor, private as well -BaseProcess::~BaseProcess() -{ +BaseProcess::~BaseProcess() { // nothing to do here } // ------------------------------------------------------------------------------------------------ -void BaseProcess::ExecuteOnScene( Importer* pImp) -{ - ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene); +void BaseProcess::ExecuteOnScene(Importer *pImp) { + ai_assert( nullptr != pImp ); + ai_assert( nullptr != pImp->Pimpl()->mScene); progress = pImp->GetProgressHandler(); - ai_assert(progress); + ai_assert(nullptr != progress); - SetupProperties( pImp ); + SetupProperties(pImp); // catch exceptions thrown inside the PostProcess-Step - try - { + try { Execute(pImp->Pimpl()->mScene); - } catch( const std::exception& err ) { + } catch (const std::exception &err) { // extract error description pImp->Pimpl()->mErrorString = err.what(); @@ -94,14 +90,11 @@ void BaseProcess::ExecuteOnScene( Importer* pImp) } // ------------------------------------------------------------------------------------------------ -void BaseProcess::SetupProperties(const Importer* /*pImp*/) -{ +void BaseProcess::SetupProperties(const Importer * /*pImp*/) { // the default implementation does nothing } // ------------------------------------------------------------------------------------------------ -bool BaseProcess::RequireVerboseFormat() const -{ +bool BaseProcess::RequireVerboseFormat() const { return true; } - diff --git a/Engine/lib/assimp/code/Common/BaseProcess.h b/Engine/lib/assimp/code/Common/BaseProcess.h index 4d5c7a76b..bf1f2586f 100644 --- a/Engine/lib/assimp/code/Common/BaseProcess.h +++ b/Engine/lib/assimp/code/Common/BaseProcess.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team - +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -44,12 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef INCLUDED_AI_BASEPROCESS_H #define INCLUDED_AI_BASEPROCESS_H -#include #include +#include + struct aiScene; -namespace Assimp { +namespace Assimp { class Importer; @@ -60,64 +60,50 @@ class Importer; * to provide additional information to other steps. This is primarily * intended for cross-step optimizations. */ -class SharedPostProcessInfo -{ +class SharedPostProcessInfo { public: - - struct Base - { - virtual ~Base() - {} + struct Base { + virtual ~Base() {} }; //! Represents data that is allocated on the heap, thus needs to be deleted template - struct THeapData : public Base - { - explicit THeapData(T* in) - : data (in) - {} + struct THeapData : public Base { + explicit THeapData(T *in) : + data(in) {} - ~THeapData() - { + ~THeapData() { delete data; } - T* data; + T *data; }; //! Represents static, by-value data not allocated on the heap template - struct TStaticData : public Base - { - explicit TStaticData(T in) - : data (in) - {} + struct TStaticData : public Base { + explicit TStaticData(T in) : + data(in) {} - ~TStaticData() - {} + ~TStaticData() {} T data; }; // some typedefs for cleaner code typedef unsigned int KeyType; - typedef std::map PropertyMap; + typedef std::map PropertyMap; public: - //! Destructor - ~SharedPostProcessInfo() - { + ~SharedPostProcessInfo() { Clean(); } //! Remove all stored properties from the table - void Clean() - { + void Clean() { // invoke the virtual destructor for all stored properties for (PropertyMap::iterator it = pmap.begin(), end = pmap.end(); - it != end; ++it) - { + it != end; ++it) { delete (*it).second; } pmap.clear(); @@ -125,24 +111,21 @@ public: //! Add a heap property to the list template - void AddProperty( const char* name, T* in ){ - AddProperty(name,(Base*)new THeapData(in)); + void AddProperty(const char *name, T *in) { + AddProperty(name, (Base *)new THeapData(in)); } //! Add a static by-value property to the list template - void AddProperty( const char* name, T in ){ - AddProperty(name,(Base*)new TStaticData(in)); + void AddProperty(const char *name, T in) { + AddProperty(name, (Base *)new TStaticData(in)); } - //! Get a heap property template - bool GetProperty( const char* name, T*& out ) const - { - THeapData* t = (THeapData*)GetPropertyInternal(name); - if(!t) - { + bool GetProperty(const char *name, T *&out) const { + THeapData *t = (THeapData *)GetPropertyInternal(name); + if (!t) { out = NULL; return false; } @@ -152,53 +135,34 @@ public: //! Get a static, by-value property template - bool GetProperty( const char* name, T& out ) const - { - TStaticData* t = (TStaticData*)GetPropertyInternal(name); - if(!t)return false; + bool GetProperty(const char *name, T &out) const { + TStaticData *t = (TStaticData *)GetPropertyInternal(name); + if ( nullptr == t) { + return false; + } out = t->data; return true; } //! Remove a property of a specific type - void RemoveProperty( const char* name) { - SetGenericPropertyPtr(pmap,name,NULL); + void RemoveProperty(const char *name) { + SetGenericPropertyPtr(pmap, name, nullptr ); } private: - - void AddProperty( const char* name, Base* data) { - SetGenericPropertyPtr(pmap,name,data); + void AddProperty(const char *name, Base *data) { + SetGenericPropertyPtr(pmap, name, data); } - Base* GetPropertyInternal( const char* name) const { - return GetGenericProperty(pmap,name,NULL); + Base *GetPropertyInternal(const char *name) const { + return GetGenericProperty(pmap, name, nullptr ); } private: - //! Map of all stored properties PropertyMap pmap; }; -#if 0 - -// --------------------------------------------------------------------------- -/** @brief Represents a dependency table for a postprocessing steps. - * - * For future use. - */ - struct PPDependencyTable - { - unsigned int execute_me_before_these; - unsigned int execute_me_after_these; - unsigned int only_if_these_are_not_specified; - unsigned int mutually_exclusive_with; - }; - -#endif - - #define AI_SPP_SPATIAL_SORT "$Spat" // --------------------------------------------------------------------------- @@ -228,7 +192,7 @@ public: * @return true if the process is present in this flag fields, * false if not. */ - virtual bool IsActive( unsigned int pFlags) const = 0; + virtual bool IsActive(unsigned int pFlags) const = 0; // ------------------------------------------------------------------- /** Check whether this step expects its input vertex data to be @@ -241,14 +205,14 @@ public: * the object pointer will be set to NULL). * @param pImp Importer instance (pImp->mScene must be valid) */ - void ExecuteOnScene( Importer* pImp); + void ExecuteOnScene(Importer *pImp); // ------------------------------------------------------------------- /** Called prior to ExecuteOnScene(). * The function is a request to the process to update its configuration * basing on the Importer's configuration property list. */ - virtual void SetupProperties(const Importer* pImp); + virtual void SetupProperties(const Importer *pImp); // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. @@ -256,35 +220,32 @@ public: * This method must be implemented by deriving classes. * @param pScene The imported data to work at. */ - virtual void Execute( aiScene* pScene) = 0; - + virtual void Execute(aiScene *pScene) = 0; // ------------------------------------------------------------------- /** Assign a new SharedPostProcessInfo to the step. This object * allows multiple postprocess steps to share data. * @param sh May be NULL */ - inline void SetSharedData(SharedPostProcessInfo* sh) { + inline void SetSharedData(SharedPostProcessInfo *sh) { shared = sh; } // ------------------------------------------------------------------- /** Get the shared data that is assigned to the step. */ - inline SharedPostProcessInfo* GetSharedData() { + inline SharedPostProcessInfo *GetSharedData() { return shared; } protected: - /** See the doc of #SharedPostProcessInfo for more details */ - SharedPostProcessInfo* shared; + SharedPostProcessInfo *shared; /** Currently active progress handler */ - ProgressHandler* progress; + ProgressHandler *progress; }; - } // end of namespace Assimp #endif // AI_BASEPROCESS_H_INC diff --git a/Engine/lib/assimp/code/Common/Bitmap.cpp b/Engine/lib/assimp/code/Common/Bitmap.cpp index b22b71ea9..7d8225704 100644 --- a/Engine/lib/assimp/code/Common/Bitmap.cpp +++ b/Engine/lib/assimp/code/Common/Bitmap.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/CreateAnimMesh.cpp b/Engine/lib/assimp/code/Common/CreateAnimMesh.cpp index 98b60e531..7317dc45b 100644 --- a/Engine/lib/assimp/code/Common/CreateAnimMesh.cpp +++ b/Engine/lib/assimp/code/Common/CreateAnimMesh.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- Copyright (C) 2016 The Qt Company Ltd. -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/DefaultIOStream.cpp b/Engine/lib/assimp/code/Common/DefaultIOStream.cpp index 829b44731..205f19e37 100644 --- a/Engine/lib/assimp/code/Common/DefaultIOStream.cpp +++ b/Engine/lib/assimp/code/Common/DefaultIOStream.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/DefaultIOSystem.cpp b/Engine/lib/assimp/code/Common/DefaultIOSystem.cpp index 6fdc24dd8..0343cb289 100644 --- a/Engine/lib/assimp/code/Common/DefaultIOSystem.cpp +++ b/Engine/lib/assimp/code/Common/DefaultIOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/DefaultLogger.cpp b/Engine/lib/assimp/code/Common/DefaultLogger.cpp index de3528d2b..adb9ba160 100644 --- a/Engine/lib/assimp/code/Common/DefaultLogger.cpp +++ b/Engine/lib/assimp/code/Common/DefaultLogger.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -107,7 +107,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams, return nullptr; #endif - // Platform-independent default streams + // Platform-independent default streams case aiDefaultLogStream_STDERR: return new StdOStreamLogStream(std::cerr); case aiDefaultLogStream_STDOUT: @@ -121,7 +121,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams, }; // For compilers without dead code path detection - return NULL; + return nullptr; } // ---------------------------------------------------------------------------------- diff --git a/Engine/lib/assimp/code/Common/DefaultProgressHandler.h b/Engine/lib/assimp/code/Common/DefaultProgressHandler.h index bd2cce00b..ebf7f118c 100644 --- a/Engine/lib/assimp/code/Common/DefaultProgressHandler.h +++ b/Engine/lib/assimp/code/Common/DefaultProgressHandler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/Exporter.cpp b/Engine/lib/assimp/code/Common/Exporter.cpp index 8a95ceae5..9f9a33b58 100644 --- a/Engine/lib/assimp/code/Common/Exporter.cpp +++ b/Engine/lib/assimp/code/Common/Exporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -103,7 +103,7 @@ void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperti void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneA3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); +void ExportSceneM3DA(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); @@ -177,7 +177,7 @@ static void setupExporterArray(std::vector &exporte #ifndef ASSIMP_BUILD_NO_M3D_EXPORTER exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0)); - exporters.push_back(Exporter::ExportFormatEntry("a3d", "Model 3D (ascii)", "m3d", &ExportSceneA3D, 0)); + exporters.push_back(Exporter::ExportFormatEntry("m3da", "Model 3D (ascii)", "a3d", &ExportSceneM3DA, 0)); #endif #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER @@ -445,8 +445,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry. ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties; - pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again); - exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); + pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices); exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); pimpl->mProgressHandler->UpdateFileWrite(4, 4); diff --git a/Engine/lib/assimp/code/Common/FileLogStream.h b/Engine/lib/assimp/code/Common/FileLogStream.h index 740c50319..ecff03a7e 100644 --- a/Engine/lib/assimp/code/Common/FileLogStream.h +++ b/Engine/lib/assimp/code/Common/FileLogStream.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/FileSystemFilter.h b/Engine/lib/assimp/code/Common/FileSystemFilter.h index 9923cdbdd..1440cf97d 100644 --- a/Engine/lib/assimp/code/Common/FileSystemFilter.h +++ b/Engine/lib/assimp/code/Common/FileSystemFilter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2008, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Common/Importer.cpp b/Engine/lib/assimp/code/Common/Importer.cpp index 91b50859a..a59ec9812 100644 --- a/Engine/lib/assimp/code/Common/Importer.cpp +++ b/Engine/lib/assimp/code/Common/Importer.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team - - +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -78,6 +76,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include + #include #include #include @@ -119,7 +119,7 @@ void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothro return AllocateFromAssimpHeap::operator new( num_bytes ); } catch( ... ) { - return NULL; + return nullptr; } } @@ -134,9 +134,8 @@ void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) { void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() { try { return AllocateFromAssimpHeap::operator new[]( num_bytes ); - } - catch( ... ) { - return NULL; + } catch( ... ) { + return nullptr; } } @@ -148,7 +147,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) { // Importer constructor. Importer::Importer() : pimpl( new ImporterPimpl ) { - pimpl->mScene = NULL; + pimpl->mScene = nullptr; pimpl->mErrorString = ""; // Allocate a default IO handler @@ -174,14 +173,14 @@ Importer::Importer() // ------------------------------------------------------------------------------------------------ // Destructor of Importer -Importer::~Importer() -{ +Importer::~Importer() { // Delete all import plugins DeleteImporterInstanceList(pimpl->mImporter); // Delete all post-processing plug-ins - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) + for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) { delete pimpl->mPostProcessingSteps[a]; + } // Delete the assigned IO and progress handler delete pimpl->mIOHandler; @@ -199,9 +198,9 @@ Importer::~Importer() // ------------------------------------------------------------------------------------------------ // Register a custom post-processing step -aiReturn Importer::RegisterPPStep(BaseProcess* pImp) -{ - ai_assert(NULL != pImp); +aiReturn Importer::RegisterPPStep(BaseProcess* pImp) { + ai_assert( nullptr != pImp ); + ASSIMP_BEGIN_EXCEPTION_REGION(); pimpl->mPostProcessingSteps.push_back(pImp); @@ -213,9 +212,9 @@ aiReturn Importer::RegisterPPStep(BaseProcess* pImp) // ------------------------------------------------------------------------------------------------ // Register a custom loader plugin -aiReturn Importer::RegisterLoader(BaseImporter* pImp) -{ - ai_assert(NULL != pImp); +aiReturn Importer::RegisterLoader(BaseImporter* pImp) { + ai_assert(nullptr != pImp); + ASSIMP_BEGIN_EXCEPTION_REGION(); // -------------------------------------------------------------------- @@ -242,13 +241,13 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp) pimpl->mImporter.push_back(pImp); ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked); ASSIMP_END_EXCEPTION_REGION(aiReturn); + return AI_SUCCESS; } // ------------------------------------------------------------------------------------------------ // Unregister a custom loader plugin -aiReturn Importer::UnregisterLoader(BaseImporter* pImp) -{ +aiReturn Importer::UnregisterLoader(BaseImporter* pImp) { if(!pImp) { // unregistering a NULL importer is no problem for us ... really! return AI_SUCCESS; @@ -265,13 +264,13 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp) } ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ..."); ASSIMP_END_EXCEPTION_REGION(aiReturn); + return AI_FAILURE; } // ------------------------------------------------------------------------------------------------ // Unregister a custom loader plugin -aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) -{ +aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) { if(!pImp) { // unregistering a NULL ppstep is no problem for us ... really! return AI_SUCCESS; @@ -288,24 +287,22 @@ aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) } ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you .."); ASSIMP_END_EXCEPTION_REGION(aiReturn); + return AI_FAILURE; } // ------------------------------------------------------------------------------------------------ // Supplies a custom IO handler to the importer to open and access files. -void Importer::SetIOHandler( IOSystem* pIOHandler) -{ +void Importer::SetIOHandler( IOSystem* pIOHandler) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); // If the new handler is zero, allocate a default IO implementation. - if (!pIOHandler) - { + if (!pIOHandler) { // Release pointer in the possession of the caller pimpl->mIOHandler = new DefaultIOSystem(); pimpl->mIsDefaultHandler = true; - } - // Otherwise register the custom handler - else if (pimpl->mIOHandler != pIOHandler) - { + } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler delete pimpl->mIOHandler; pimpl->mIOHandler = pIOHandler; pimpl->mIsDefaultHandler = false; @@ -316,29 +313,32 @@ void Importer::SetIOHandler( IOSystem* pIOHandler) // ------------------------------------------------------------------------------------------------ // Get the currently set IO handler IOSystem* Importer::GetIOHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mIOHandler; } // ------------------------------------------------------------------------------------------------ // Check whether a custom IO handler is currently set bool Importer::IsDefaultIOHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mIsDefaultHandler; } // ------------------------------------------------------------------------------------------------ // Supplies a custom progress handler to get regular callbacks during importing void Importer::SetProgressHandler ( ProgressHandler* pHandler ) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); + // If the new handler is zero, allocate a default implementation. - if (!pHandler) - { + if (!pHandler) { // Release pointer in the possession of the caller pimpl->mProgressHandler = new DefaultProgressHandler(); pimpl->mIsDefaultProgressHandler = true; - } - // Otherwise register the custom handler - else if (pimpl->mProgressHandler != pHandler) - { + } else if (pimpl->mProgressHandler != pHandler) { // Otherwise register the custom handler delete pimpl->mProgressHandler; pimpl->mProgressHandler = pHandler; pimpl->mIsDefaultProgressHandler = false; @@ -349,19 +349,22 @@ void Importer::SetProgressHandler ( ProgressHandler* pHandler ) { // ------------------------------------------------------------------------------------------------ // Get the currently set progress handler ProgressHandler* Importer::GetProgressHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mProgressHandler; } // ------------------------------------------------------------------------------------------------ // Check whether a custom progress handler is currently set bool Importer::IsDefaultProgressHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mIsDefaultProgressHandler; } // ------------------------------------------------------------------------------------------------ // Validate post process step flags -bool _ValidateFlags(unsigned int pFlags) -{ +bool _ValidateFlags(unsigned int pFlags) { if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) { ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible"); return false; @@ -375,12 +378,13 @@ bool _ValidateFlags(unsigned int pFlags) // ------------------------------------------------------------------------------------------------ // Free the current scene -void Importer::FreeScene( ) -{ +void Importer::FreeScene( ) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); delete pimpl->mScene; - pimpl->mScene = NULL; + pimpl->mScene = nullptr; pimpl->mErrorString = ""; ASSIMP_END_EXCEPTION_REGION(void); @@ -388,44 +392,48 @@ void Importer::FreeScene( ) // ------------------------------------------------------------------------------------------------ // Get the current error string, if any -const char* Importer::GetErrorString() const -{ - /* Must remain valid as long as ReadFile() or FreeFile() are not called */ +const char* Importer::GetErrorString() const { + ai_assert(nullptr != pimpl); + + // Must remain valid as long as ReadFile() or FreeFile() are not called return pimpl->mErrorString.c_str(); } // ------------------------------------------------------------------------------------------------ // Enable extra-verbose mode -void Importer::SetExtraVerbose(bool bDo) -{ +void Importer::SetExtraVerbose(bool bDo) { + ai_assert(nullptr != pimpl); + pimpl->bExtraVerbose = bDo; } // ------------------------------------------------------------------------------------------------ // Get the current scene -const aiScene* Importer::GetScene() const -{ +const aiScene* Importer::GetScene() const { + ai_assert(nullptr != pimpl); + return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ // Orphan the current scene and return it. -aiScene* Importer::GetOrphanedScene() -{ +aiScene* Importer::GetOrphanedScene() { + ai_assert(nullptr != pimpl); + aiScene* s = pimpl->mScene; ASSIMP_BEGIN_EXCEPTION_REGION(); - pimpl->mScene = NULL; + pimpl->mScene = nullptr; - pimpl->mErrorString = ""; /* reset error string */ + pimpl->mErrorString = ""; // reset error string ASSIMP_END_EXCEPTION_REGION(aiScene*); + return s; } // ------------------------------------------------------------------------------------------------ // Validate post-processing flags -bool Importer::ValidateFlags(unsigned int pFlags) const -{ +bool Importer::ValidateFlags(unsigned int pFlags) const { ASSIMP_BEGIN_EXCEPTION_REGION(); // run basic checks for mutually exclusive flags if(!_ValidateFlags(pFlags)) { @@ -467,8 +475,9 @@ bool Importer::ValidateFlags(unsigned int pFlags) const const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, size_t pLength, unsigned int pFlags, - const char* pHint /*= ""*/) -{ + const char* pHint /*= ""*/) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); if (!pHint) { pHint = ""; @@ -476,12 +485,12 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) { pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; - return NULL; + return nullptr; } // prevent deletion of the previous IOHandler IOSystem* io = pimpl->mIOHandler; - pimpl->mIOHandler = NULL; + pimpl->mIOHandler = nullptr; SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io)); @@ -493,13 +502,13 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, ReadFile(fbuff,pFlags); SetIOHandler(io); - ASSIMP_END_EXCEPTION_REGION(const aiScene*); + ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString); return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ -void WriteLogOpening(const std::string& file) -{ +void WriteLogOpening(const std::string& file) { + ASSIMP_LOG_INFO_F("Load ", file); // print a full version dump. This is nice because we don't @@ -550,8 +559,9 @@ void WriteLogOpening(const std::string& file) // ------------------------------------------------------------------------------------------------ // Reads the given file and returns its contents if successful. -const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) -{ +const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); const std::string pFile(_pFile); @@ -580,7 +590,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) pimpl->mErrorString = "Unable to open file \"" + pFile + "\"."; ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; + return nullptr; } std::unique_ptr profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); @@ -589,7 +599,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } // Find an worker class which can handle the file - BaseImporter* imp = NULL; + BaseImporter* imp = nullptr; SetPropertyInteger("importerIndex", -1); for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { @@ -617,7 +627,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) if( !imp) { pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; + return nullptr; } } @@ -633,7 +643,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // Dispatch the reading to the worker class for this format const aiImporterDesc *desc( imp->GetInfo() ); std::string ext( "unknown" ); - if ( NULL != desc ) { + if ( nullptr != desc ) { ext = desc->mName; } ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." ); @@ -654,15 +664,20 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // If successful, apply all active post processing steps to the imported data if( pimpl->mScene) { + if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) { + if (!pimpl->mScene->mMetaData) { + pimpl->mScene->mMetaData = new aiMetadata; + } + pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext)); + } #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called. - if (pFlags & aiProcess_ValidateDataStructure) - { + if (pFlags & aiProcess_ValidateDataStructure) { ValidateDSProcess ds; ds.ExecuteOnScene (this); if (!pimpl->mScene) { - return NULL; + return nullptr; } } #endif // no validation @@ -695,8 +710,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } } #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS - catch (std::exception &e) - { + catch (std::exception &e) { #if (defined _MSC_VER) && (defined _CPPRTTI) // if we have RTTI get the full name of the exception that occurred pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what(); @@ -705,24 +719,26 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) #endif ASSIMP_LOG_ERROR(pimpl->mErrorString); - delete pimpl->mScene; pimpl->mScene = NULL; + delete pimpl->mScene; pimpl->mScene = nullptr; } #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS // either successful or failure - the pointer expresses it anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); + ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString); + return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ // Apply post-processing to the currently bound scene -const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) -{ +const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); // Return immediately if no scene is active if (!pimpl->mScene) { - return NULL; + return nullptr; } // If no flags are given, return the current scene with no further action @@ -737,12 +753,11 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS // The ValidateDS process plays an exceptional role. It isn't contained in the global // list of post-processing steps, so we need to call it manually. - if (pFlags & aiProcess_ValidateDataStructure) - { + if (pFlags & aiProcess_ValidateDataStructure) { ValidateDSProcess ds; ds.ExecuteOnScene (this); if (!pimpl->mScene) { - return NULL; + return nullptr; } } #endif // no validation @@ -762,11 +777,9 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) std::unique_ptr profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - BaseProcess* process = pimpl->mPostProcessingSteps[a]; pimpl->mProgressHandler->UpdatePostProcess(static_cast(a), static_cast(pimpl->mPostProcessingSteps.size()) ); if( process->IsActive( pFlags)) { - if (profiler) { profiler->BeginRegion("postprocess"); } @@ -803,24 +816,28 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) static_cast(pimpl->mPostProcessingSteps.size()) ); // update private scene flags - if( pimpl->mScene ) + if( pimpl->mScene ) { ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags; + } // clear any data allocated by post-process steps pimpl->mPPShared->Clean(); ASSIMP_LOG_INFO("Leaving post processing pipeline"); ASSIMP_END_EXCEPTION_REGION(const aiScene*); + return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); // Return immediately if no scene is active - if ( NULL == pimpl->mScene ) { - return NULL; + if ( nullptr == pimpl->mScene ) { + return nullptr; } // If no flags are given, return the current scene with no further action @@ -839,7 +856,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess ValidateDSProcess ds; ds.ExecuteOnScene( this ); if ( !pimpl->mScene ) { - return NULL; + return nullptr; } } #endif // no validation @@ -890,46 +907,50 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess // ------------------------------------------------------------------------------------------------ // Helper function to check whether an extension is supported by ASSIMP -bool Importer::IsExtensionSupported(const char* szExtension) const -{ +bool Importer::IsExtensionSupported(const char* szExtension) const { return nullptr != GetImporter(szExtension); } // ------------------------------------------------------------------------------------------------ -size_t Importer::GetImporterCount() const -{ +size_t Importer::GetImporterCount() const { + ai_assert(nullptr != pimpl); + return pimpl->mImporter.size(); } // ------------------------------------------------------------------------------------------------ -const aiImporterDesc* Importer::GetImporterInfo(size_t index) const -{ +const aiImporterDesc* Importer::GetImporterInfo(size_t index) const { + ai_assert(nullptr != pimpl); + if (index >= pimpl->mImporter.size()) { - return NULL; + return nullptr; } return pimpl->mImporter[index]->GetInfo(); } // ------------------------------------------------------------------------------------------------ -BaseImporter* Importer::GetImporter (size_t index) const -{ +BaseImporter* Importer::GetImporter (size_t index) const { + ai_assert(nullptr != pimpl); + if (index >= pimpl->mImporter.size()) { - return NULL; + return nullptr; } return pimpl->mImporter[index]; } // ------------------------------------------------------------------------------------------------ // Find a loader plugin for a given file extension -BaseImporter* Importer::GetImporter (const char* szExtension) const -{ +BaseImporter* Importer::GetImporter (const char* szExtension) const { + ai_assert(nullptr != pimpl); + return GetImporter(GetImporterIndex(szExtension)); } // ------------------------------------------------------------------------------------------------ // Find a loader plugin for a given file extension size_t Importer::GetImporterIndex (const char* szExtension) const { + ai_assert(nullptr != pimpl); ai_assert(nullptr != szExtension); ASSIMP_BEGIN_EXCEPTION_REGION(); @@ -960,8 +981,9 @@ size_t Importer::GetImporterIndex (const char* szExtension) const { // ------------------------------------------------------------------------------------------------ // Helper function to build a list of all file extensions supported by ASSIMP -void Importer::GetExtensionList(aiString& szOut) const -{ +void Importer::GetExtensionList(aiString& szOut) const { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); std::set str; for (std::vector::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { @@ -985,8 +1007,9 @@ void Importer::GetExtensionList(aiString& szOut) const // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyInteger(const char* szName, int iValue) -{ +bool Importer::SetPropertyInteger(const char* szName, int iValue) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mIntProperties, szName,iValue); @@ -996,8 +1019,9 @@ bool Importer::SetPropertyInteger(const char* szName, int iValue) // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) -{ +bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mFloatProperties, szName,iValue); @@ -1007,8 +1031,9 @@ bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyString(const char* szName, const std::string& value) -{ +bool Importer::SetPropertyString(const char* szName, const std::string& value) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mStringProperties, szName,value); @@ -1018,8 +1043,9 @@ bool Importer::SetPropertyString(const char* szName, const std::string& value) // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) -{ +bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mMatrixProperties, szName,value); @@ -1029,40 +1055,43 @@ bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) // ------------------------------------------------------------------------------------------------ // Get a configuration property -int Importer::GetPropertyInteger(const char* szName, - int iErrorReturn /*= 0xffffffff*/) const -{ +int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mIntProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get a configuration property -ai_real Importer::GetPropertyFloat(const char* szName, - ai_real iErrorReturn /*= 10e10*/) const -{ +ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mFloatProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get a configuration property -const std::string Importer::GetPropertyString(const char* szName, - const std::string& iErrorReturn /*= ""*/) const -{ +std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mStringProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get a configuration property -const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, - const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const -{ +aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mMatrixProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get the memory requirements of a single node -inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) -{ +inline +void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) { + if ( nullptr == pcNode ) { + return; + } iScene += sizeof(aiNode); iScene += sizeof(unsigned int) * pcNode->mNumMeshes; iScene += sizeof(void*) * pcNode->mNumChildren; @@ -1074,21 +1103,20 @@ inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) // ------------------------------------------------------------------------------------------------ // Get the memory requirements of the scene -void Importer::GetMemoryRequirements(aiMemoryInfo& in) const -{ +void Importer::GetMemoryRequirements(aiMemoryInfo& in) const { + ai_assert(nullptr != pimpl); + in = aiMemoryInfo(); aiScene* mScene = pimpl->mScene; // return if we have no scene loaded - if (!pimpl->mScene) + if (!mScene) return; - in.total = sizeof(aiScene); // add all meshes - for (unsigned int i = 0; i < mScene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < mScene->mNumMeshes;++i) { in.meshes += sizeof(aiMesh); if (mScene->mMeshes[i]->HasPositions()) { in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; @@ -1105,14 +1133,16 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) { if (mScene->mMeshes[i]->HasVertexColors(a)) { in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices; + } else { + break; } - else break; } for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { if (mScene->mMeshes[i]->HasTextureCoords(a)) { in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; + } else { + break; } - else break; } if (mScene->mMeshes[i]->HasBones()) { in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones; @@ -1131,8 +1161,9 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const in.textures += sizeof(aiTexture); if (pc->mHeight) { in.textures += 4 * pc->mHeight * pc->mWidth; + } else { + in.textures += pc->mWidth; } - else in.textures += pc->mWidth; } in.total += in.textures; @@ -1170,5 +1201,6 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const in.materials += pc->mProperties[a]->mDataLength; } } + in.total += in.materials; } diff --git a/Engine/lib/assimp/code/Common/Importer.h b/Engine/lib/assimp/code/Common/Importer.h index a439d99c2..c31f67caa 100644 --- a/Engine/lib/assimp/code/Common/Importer.h +++ b/Engine/lib/assimp/code/Common/Importer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/ImporterRegistry.cpp b/Engine/lib/assimp/code/Common/ImporterRegistry.cpp index b9f28f035..41aa21979 100644 --- a/Engine/lib/assimp/code/Common/ImporterRegistry.cpp +++ b/Engine/lib/assimp/code/Common/ImporterRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/PolyTools.h b/Engine/lib/assimp/code/Common/PolyTools.h index fbbda0e7d..1b8972877 100644 --- a/Engine/lib/assimp/code/Common/PolyTools.h +++ b/Engine/lib/assimp/code/Common/PolyTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/PostStepRegistry.cpp b/Engine/lib/assimp/code/Common/PostStepRegistry.cpp index 8ff4af040..19382165f 100644 --- a/Engine/lib/assimp/code/Common/PostStepRegistry.cpp +++ b/Engine/lib/assimp/code/Common/PostStepRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -123,7 +123,7 @@ corresponding preprocessor flag to selectively disable steps. # include "PostProcessing/OptimizeGraph.h" #endif #ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS -# include "Common/SplitByBoneCountProcess.h" +# include "PostProcessing/SplitByBoneCountProcess.h" #endif #ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS # include "PostProcessing/DeboneProcess.h" diff --git a/Engine/lib/assimp/code/Common/RemoveComments.cpp b/Engine/lib/assimp/code/Common/RemoveComments.cpp index 91700a769..f7e735c16 100644 --- a/Engine/lib/assimp/code/Common/RemoveComments.cpp +++ b/Engine/lib/assimp/code/Common/RemoveComments.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/SGSpatialSort.cpp b/Engine/lib/assimp/code/Common/SGSpatialSort.cpp index 120070b0a..35ffaae58 100644 --- a/Engine/lib/assimp/code/Common/SGSpatialSort.cpp +++ b/Engine/lib/assimp/code/Common/SGSpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/SceneCombiner.cpp b/Engine/lib/assimp/code/Common/SceneCombiner.cpp index f7b13cc95..29b6082a8 100644 --- a/Engine/lib/assimp/code/Common/SceneCombiner.cpp +++ b/Engine/lib/assimp/code/Common/SceneCombiner.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -1312,7 +1312,6 @@ void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) { aiMetadata* dest = *_dest = aiMetadata::Alloc( src->mNumProperties ); std::copy(src->mKeys, src->mKeys + src->mNumProperties, dest->mKeys); - dest->mValues = new aiMetadataEntry[src->mNumProperties]; for (unsigned int i = 0; i < src->mNumProperties; ++i) { aiMetadataEntry& in = src->mValues[i]; aiMetadataEntry& out = dest->mValues[i]; diff --git a/Engine/lib/assimp/code/Common/ScenePreprocessor.cpp b/Engine/lib/assimp/code/Common/ScenePreprocessor.cpp index 432a3d766..606590519 100644 --- a/Engine/lib/assimp/code/Common/ScenePreprocessor.cpp +++ b/Engine/lib/assimp/code/Common/ScenePreprocessor.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -217,6 +217,7 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) // No rotation keys? Generate a dummy track if (!channel->mNumRotationKeys) { + ai_assert(!channel->mRotationKeys); channel->mNumRotationKeys = 1; channel->mRotationKeys = new aiQuatKey[1]; aiQuatKey& q = channel->mRotationKeys[0]; @@ -225,10 +226,13 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) q.mValue = rotation; ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy rotation track has been generated"); + } else { + ai_assert(channel->mRotationKeys); } // No scaling keys? Generate a dummy track if (!channel->mNumScalingKeys) { + ai_assert(!channel->mScalingKeys); channel->mNumScalingKeys = 1; channel->mScalingKeys = new aiVectorKey[1]; aiVectorKey& q = channel->mScalingKeys[0]; @@ -237,10 +241,13 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) q.mValue = scaling; ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy scaling track has been generated"); + } else { + ai_assert(channel->mScalingKeys); } // No position keys? Generate a dummy track if (!channel->mNumPositionKeys) { + ai_assert(!channel->mPositionKeys); channel->mNumPositionKeys = 1; channel->mPositionKeys = new aiVectorKey[1]; aiVectorKey& q = channel->mPositionKeys[0]; @@ -249,6 +256,8 @@ void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) q.mValue = position; ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy position track has been generated"); + } else { + ai_assert(channel->mPositionKeys); } } } diff --git a/Engine/lib/assimp/code/Common/ScenePreprocessor.h b/Engine/lib/assimp/code/Common/ScenePreprocessor.h index 3f4c8d7c3..e059d1c95 100644 --- a/Engine/lib/assimp/code/Common/ScenePreprocessor.h +++ b/Engine/lib/assimp/code/Common/ScenePreprocessor.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/ScenePrivate.h b/Engine/lib/assimp/code/Common/ScenePrivate.h index f336aafc9..f66f48856 100644 --- a/Engine/lib/assimp/code/Common/ScenePrivate.h +++ b/Engine/lib/assimp/code/Common/ScenePrivate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/SkeletonMeshBuilder.cpp b/Engine/lib/assimp/code/Common/SkeletonMeshBuilder.cpp index 06cfe034e..724359f99 100644 --- a/Engine/lib/assimp/code/Common/SkeletonMeshBuilder.cpp +++ b/Engine/lib/assimp/code/Common/SkeletonMeshBuilder.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/SpatialSort.cpp b/Engine/lib/assimp/code/Common/SpatialSort.cpp index a4f3a4e4b..604b086b7 100644 --- a/Engine/lib/assimp/code/Common/SpatialSort.cpp +++ b/Engine/lib/assimp/code/Common/SpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/StandardShapes.cpp b/Engine/lib/assimp/code/Common/StandardShapes.cpp index 2e5100130..d474c6129 100644 --- a/Engine/lib/assimp/code/Common/StandardShapes.cpp +++ b/Engine/lib/assimp/code/Common/StandardShapes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/StdOStreamLogStream.h b/Engine/lib/assimp/code/Common/StdOStreamLogStream.h index 893e261a2..4f5999775 100644 --- a/Engine/lib/assimp/code/Common/StdOStreamLogStream.h +++ b/Engine/lib/assimp/code/Common/StdOStreamLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/Subdivision.cpp b/Engine/lib/assimp/code/Common/Subdivision.cpp index 60c54939f..08408f867 100644 --- a/Engine/lib/assimp/code/Common/Subdivision.cpp +++ b/Engine/lib/assimp/code/Common/Subdivision.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/TargetAnimation.cpp b/Engine/lib/assimp/code/Common/TargetAnimation.cpp index b8062499f..3c61d2176 100644 --- a/Engine/lib/assimp/code/Common/TargetAnimation.cpp +++ b/Engine/lib/assimp/code/Common/TargetAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/TargetAnimation.h b/Engine/lib/assimp/code/Common/TargetAnimation.h index 91634ab5a..5b9c1881d 100644 --- a/Engine/lib/assimp/code/Common/TargetAnimation.h +++ b/Engine/lib/assimp/code/Common/TargetAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/Version.cpp b/Engine/lib/assimp/code/Common/Version.cpp index cf1da7d5b..f04d12233 100644 --- a/Engine/lib/assimp/code/Common/Version.cpp +++ b/Engine/lib/assimp/code/Common/Version.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -55,7 +55,7 @@ static const char* LEGAL_INFORMATION = "Open Asset Import Library (Assimp).\n" "A free C/C++ library to import various 3D file formats into applications\n\n" -"(c) 2006-2019, assimp team\n" +"(c) 2006-2020, assimp team\n" "License under the terms and conditions of the 3-clause BSD license\n" "http://assimp.org\n" ; @@ -66,6 +66,12 @@ ASSIMP_API const char* aiGetLegalString () { return LEGAL_INFORMATION; } +// ------------------------------------------------------------------------------------------------ +// Get Assimp patch version +ASSIMP_API unsigned int aiGetVersionPatch() { + return VER_PATCH; +} + // ------------------------------------------------------------------------------------------------ // Get Assimp minor version ASSIMP_API unsigned int aiGetVersionMinor () { diff --git a/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.cpp b/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.cpp index 7cfd1a350..e588dc2a4 100644 --- a/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.cpp +++ b/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -58,7 +58,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, { // compute the number of referenced vertices if it wasn't specified by the caller const aiFace* const pcFaceEnd = pcFaces + iNumFaces; - if (!iNumVertices) { + if (0 == iNumVertices) { for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) { ai_assert( nullptr != pcFace ); ai_assert(3 == pcFace->mNumIndices); @@ -68,7 +68,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, } } - mNumVertices = iNumVertices; + mNumVertices = iNumVertices + 1; unsigned int* pi; diff --git a/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.h b/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.h index f3be47612..2226fc1c4 100644 --- a/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.h +++ b/Engine/lib/assimp/code/Common/VertexTriangleAdjacency.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Common/Win32DebugLogStream.h b/Engine/lib/assimp/code/Common/Win32DebugLogStream.h index a6063a261..3a9d89c73 100644 --- a/Engine/lib/assimp/code/Common/Win32DebugLogStream.h +++ b/Engine/lib/assimp/code/Common/Win32DebugLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/ZipArchiveIOSystem.cpp b/Engine/lib/assimp/code/Common/ZipArchiveIOSystem.cpp index 7c37a05f9..8d00da912 100644 --- a/Engine/lib/assimp/code/Common/ZipArchiveIOSystem.cpp +++ b/Engine/lib/assimp/code/Common/ZipArchiveIOSystem.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -343,8 +343,6 @@ namespace Assimp { } ZipArchiveIOSystem::Implement::~Implement() { - m_ArchiveMap.clear(); - if (m_ZipFileHandle != nullptr) { unzClose(m_ZipFileHandle); m_ZipFileHandle = nullptr; diff --git a/Engine/lib/assimp/code/Common/assbin_chunks.h b/Engine/lib/assimp/code/Common/assbin_chunks.h index 15e4af5e7..822df5198 100644 --- a/Engine/lib/assimp/code/Common/assbin_chunks.h +++ b/Engine/lib/assimp/code/Common/assbin_chunks.h @@ -37,7 +37,7 @@ The ASSBIN file format is composed of chunks to represent the hierarchical aiSce This makes the format extensible and allows backward-compatibility with future data structure versions. The <root>/code/assbin_chunks.h header contains some magic constants for use by stand-alone ASSBIN loaders. Also, Assimp's own file writer can be found -in <root>/tools/assimp_cmd/WriteDumb.cpp (yes, the 'b' is no typo ...). +in <root>/tools/assimp_cmd/WriteDump.cpp (yes, the 'b' is no typo ...). @verbatim diff --git a/Engine/lib/assimp/code/Common/material.cpp b/Engine/lib/assimp/code/Common/material.cpp new file mode 100644 index 000000000..f4a29dacf --- /dev/null +++ b/Engine/lib/assimp/code/Common/material.cpp @@ -0,0 +1,97 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 material.cpp +/** Implement common material related functions. */ + +#include +#include + +// ------------------------------------------------------------------------------- +const char* TextureTypeToString(aiTextureType in) +{ + switch (in) + { + case aiTextureType_NONE: + return "n/a"; + case aiTextureType_DIFFUSE: + return "Diffuse"; + case aiTextureType_SPECULAR: + return "Specular"; + case aiTextureType_AMBIENT: + return "Ambient"; + case aiTextureType_EMISSIVE: + return "Emissive"; + case aiTextureType_OPACITY: + return "Opacity"; + case aiTextureType_NORMALS: + return "Normals"; + case aiTextureType_HEIGHT: + return "Height"; + case aiTextureType_SHININESS: + return "Shininess"; + case aiTextureType_DISPLACEMENT: + return "Displacement"; + case aiTextureType_LIGHTMAP: + return "Lightmap"; + case aiTextureType_REFLECTION: + return "Reflection"; + case aiTextureType_BASE_COLOR: + return "BaseColor"; + case aiTextureType_NORMAL_CAMERA: + return "NormalCamera"; + case aiTextureType_EMISSION_COLOR: + return "EmissionColor"; + case aiTextureType_METALNESS: + return "Metalness"; + case aiTextureType_DIFFUSE_ROUGHNESS: + return "DiffuseRoughness"; + case aiTextureType_AMBIENT_OCCLUSION: + return "AmbientOcclusion"; + case aiTextureType_UNKNOWN: + return "Unknown"; + default: + break; + } + ai_assert(false); + return "BUG"; +} diff --git a/Engine/lib/assimp/code/Common/scene.cpp b/Engine/lib/assimp/code/Common/scene.cpp index d15619acf..f56562b1c 100644 --- a/Engine/lib/assimp/code/Common/scene.cpp +++ b/Engine/lib/assimp/code/Common/scene.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/simd.cpp b/Engine/lib/assimp/code/Common/simd.cpp index 04615f408..305445970 100644 --- a/Engine/lib/assimp/code/Common/simd.cpp +++ b/Engine/lib/assimp/code/Common/simd.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Common/simd.h b/Engine/lib/assimp/code/Common/simd.h index 3eecdd458..17856fe72 100644 --- a/Engine/lib/assimp/code/Common/simd.h +++ b/Engine/lib/assimp/code/Common/simd.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/DXF/DXFHelper.h b/Engine/lib/assimp/code/DXF/DXFHelper.h index 0ec8e130b..8140d00c6 100644 --- a/Engine/lib/assimp/code/DXF/DXFHelper.h +++ b/Engine/lib/assimp/code/DXF/DXFHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/DXF/DXFLoader.cpp b/Engine/lib/assimp/code/DXF/DXFLoader.cpp index baf315485..ea877a484 100644 --- a/Engine/lib/assimp/code/DXF/DXFLoader.cpp +++ b/Engine/lib/assimp/code/DXF/DXFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/DXF/DXFLoader.h b/Engine/lib/assimp/code/DXF/DXFLoader.h index 044cf6bcb..5c4f1787e 100644 --- a/Engine/lib/assimp/code/DXF/DXFLoader.h +++ b/Engine/lib/assimp/code/DXF/DXFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXAnimation.cpp b/Engine/lib/assimp/code/FBX/FBXAnimation.cpp index 874914431..9a54f61a0 100644 --- a/Engine/lib/assimp/code/FBX/FBXAnimation.cpp +++ b/Engine/lib/assimp/code/FBX/FBXAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXBinaryTokenizer.cpp b/Engine/lib/assimp/code/FBX/FBXBinaryTokenizer.cpp index a4a2bc8e7..7faa0518b 100644 --- a/Engine/lib/assimp/code/FBX/FBXBinaryTokenizer.cpp +++ b/Engine/lib/assimp/code/FBX/FBXBinaryTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXCommon.h b/Engine/lib/assimp/code/FBX/FBXCommon.h index b28601c74..7f70eb784 100644 --- a/Engine/lib/assimp/code/FBX/FBXCommon.h +++ b/Engine/lib/assimp/code/FBX/FBXCommon.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXCompileConfig.h b/Engine/lib/assimp/code/FBX/FBXCompileConfig.h index 03536a182..5cdaa6960 100644 --- a/Engine/lib/assimp/code/FBX/FBXCompileConfig.h +++ b/Engine/lib/assimp/code/FBX/FBXCompileConfig.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXConverter.cpp b/Engine/lib/assimp/code/FBX/FBXConverter.cpp index d8a22d9f7..22616a480 100644 --- a/Engine/lib/assimp/code/FBX/FBXConverter.cpp +++ b/Engine/lib/assimp/code/FBX/FBXConverter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -60,6 +60,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include #include #include @@ -1562,7 +1564,7 @@ namespace Assimp { bone_map.clear(); } - catch (std::exception&e) { + catch (std::exception&) { std::for_each(bones.begin(), bones.end(), Util::delete_fun()); throw; } @@ -1597,12 +1599,11 @@ namespace Assimp { aiBone *bone = nullptr; if (bone_map.count(deformer_name)) { - std::cout << "retrieved bone from lookup " << bone_name.C_Str() << ". Deformer: " << deformer_name - << std::endl; - bone = bone_map[deformer_name]; - } else { - std::cout << "created new bone " << bone_name.C_Str() << ". Deformer: " << deformer_name << std::endl; - bone = new aiBone(); + ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name); + bone = bone_map[deformer_name]; + } else { + ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name); + bone = new aiBone(); bone->mName = bone_name; // store local transform link for post processing @@ -1648,7 +1649,7 @@ namespace Assimp { bone_map.insert(std::pair(deformer_name, bone)); } - std::cout << "bone research: Indicies size: " << out_indices.size() << std::endl; + ASSIMP_LOG_DEBUG_F("bone research: Indicies size: ", out_indices.size()); // lookup must be populated in case something goes wrong // this also allocates bones to mesh instance outside @@ -2087,7 +2088,14 @@ namespace Assimp { TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh); TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh); TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); + + // 3DSMax PBR + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh); + TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh); } void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) @@ -3604,7 +3612,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa return; } - out->mMetaData = aiMetadata::Alloc(15); + const bool hasGenerator = !doc.Creator().empty(); + + out->mMetaData = aiMetadata::Alloc(16 + (hasGenerator ? 1 : 0)); out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis()); out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign()); out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis()); @@ -3620,6 +3630,11 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa out->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart()); out->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop()); out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate()); + out->mMetaData->Set(15, AI_METADATA_SOURCE_FORMAT_VERSION, aiString(to_string(doc.FBXVersion()))); + if (hasGenerator) + { + out->mMetaData->Set(16, AI_METADATA_SOURCE_GENERATOR, aiString(doc.Creator())); + } } void FBXConverter::TransferDataToScene() diff --git a/Engine/lib/assimp/code/FBX/FBXConverter.h b/Engine/lib/assimp/code/FBX/FBXConverter.h index 46693bdca..c5ad47059 100644 --- a/Engine/lib/assimp/code/FBX/FBXConverter.h +++ b/Engine/lib/assimp/code/FBX/FBXConverter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -421,6 +421,8 @@ private: double& minTime, Model::RotOrder order); + // ------------------------------------------------------------------------------------------------ + // Copy global geometric data and some information about the source asset into scene metadata. void ConvertGlobalSettings(); // ------------------------------------------------------------------------------------------------ diff --git a/Engine/lib/assimp/code/FBX/FBXDeformer.cpp b/Engine/lib/assimp/code/FBX/FBXDeformer.cpp index 692755345..4b76cd0fa 100644 --- a/Engine/lib/assimp/code/FBX/FBXDeformer.cpp +++ b/Engine/lib/assimp/code/FBX/FBXDeformer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXDocument.cpp b/Engine/lib/assimp/code/FBX/FBXDocument.cpp index 506fd978d..ddb971b3f 100644 --- a/Engine/lib/assimp/code/FBX/FBXDocument.cpp +++ b/Engine/lib/assimp/code/FBX/FBXDocument.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXDocument.h b/Engine/lib/assimp/code/FBX/FBXDocument.h index a60d7d9ef..8984b3df7 100644 --- a/Engine/lib/assimp/code/FBX/FBXDocument.h +++ b/Engine/lib/assimp/code/FBX/FBXDocument.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXDocumentUtil.cpp b/Engine/lib/assimp/code/FBX/FBXDocumentUtil.cpp index f84691479..7178e9f26 100644 --- a/Engine/lib/assimp/code/FBX/FBXDocumentUtil.cpp +++ b/Engine/lib/assimp/code/FBX/FBXDocumentUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXDocumentUtil.h b/Engine/lib/assimp/code/FBX/FBXDocumentUtil.h index 2450109e5..2d76ee031 100644 --- a/Engine/lib/assimp/code/FBX/FBXDocumentUtil.h +++ b/Engine/lib/assimp/code/FBX/FBXDocumentUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/FBX/FBXExportNode.cpp b/Engine/lib/assimp/code/FBX/FBXExportNode.cpp index 9b29995cc..53aa719f4 100644 --- a/Engine/lib/assimp/code/FBX/FBXExportNode.cpp +++ b/Engine/lib/assimp/code/FBX/FBXExportNode.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXExportNode.h b/Engine/lib/assimp/code/FBX/FBXExportNode.h index ef3bc781a..2e8f491a1 100644 --- a/Engine/lib/assimp/code/FBX/FBXExportNode.h +++ b/Engine/lib/assimp/code/FBX/FBXExportNode.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXExportProperty.cpp b/Engine/lib/assimp/code/FBX/FBXExportProperty.cpp index f2a63b72b..11ee35003 100644 --- a/Engine/lib/assimp/code/FBX/FBXExportProperty.cpp +++ b/Engine/lib/assimp/code/FBX/FBXExportProperty.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXExportProperty.h b/Engine/lib/assimp/code/FBX/FBXExportProperty.h index d692fe6ee..6baae8b69 100644 --- a/Engine/lib/assimp/code/FBX/FBXExportProperty.h +++ b/Engine/lib/assimp/code/FBX/FBXExportProperty.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXExporter.cpp b/Engine/lib/assimp/code/FBX/FBXExporter.cpp index 9767f9a0a..594951e78 100644 --- a/Engine/lib/assimp/code/FBX/FBXExporter.cpp +++ b/Engine/lib/assimp/code/FBX/FBXExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -1860,6 +1860,7 @@ void FBXExporter::WriteObjects () sdnode.AddChild("Version", int32_t(100)); sdnode.AddChild("UserData", "", ""); + std::set setWeightedVertex; // add indices and weights, if any if (b) { std::vector subdef_indices; @@ -1867,7 +1868,8 @@ void FBXExporter::WriteObjects () int32_t last_index = -1; for (size_t wi = 0; wi < b->mNumWeights; ++wi) { int32_t vi = vertex_indices[b->mWeights[wi].mVertexId]; - if (vi == last_index) { + bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end()); + if (vi == last_index || bIsWeightedAlready) { // only for vertices we exported to fbx // TODO, FIXME: this assumes identically-located vertices // will always deform in the same way. @@ -1877,6 +1879,7 @@ void FBXExporter::WriteObjects () // identical vertex. continue; } + setWeightedVertex.insert(vi); subdef_indices.push_back(vi); subdef_weights.push_back(b->mWeights[wi].mWeight); last_index = vi; diff --git a/Engine/lib/assimp/code/FBX/FBXExporter.h b/Engine/lib/assimp/code/FBX/FBXExporter.h index 1ae727eda..eb8bfaf3b 100644 --- a/Engine/lib/assimp/code/FBX/FBXExporter.h +++ b/Engine/lib/assimp/code/FBX/FBXExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXImportSettings.h b/Engine/lib/assimp/code/FBX/FBXImportSettings.h index 1a4c80f8b..974931b4c 100644 --- a/Engine/lib/assimp/code/FBX/FBXImportSettings.h +++ b/Engine/lib/assimp/code/FBX/FBXImportSettings.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXImporter.cpp b/Engine/lib/assimp/code/FBX/FBXImporter.cpp index afcc1ddc7..571f60883 100644 --- a/Engine/lib/assimp/code/FBX/FBXImporter.cpp +++ b/Engine/lib/assimp/code/FBX/FBXImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXImporter.h b/Engine/lib/assimp/code/FBX/FBXImporter.h index c365b2cdd..63375e40d 100644 --- a/Engine/lib/assimp/code/FBX/FBXImporter.h +++ b/Engine/lib/assimp/code/FBX/FBXImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXMaterial.cpp b/Engine/lib/assimp/code/FBX/FBXMaterial.cpp index f43a8b84b..88ac9db16 100644 --- a/Engine/lib/assimp/code/FBX/FBXMaterial.cpp +++ b/Engine/lib/assimp/code/FBX/FBXMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXMeshGeometry.cpp b/Engine/lib/assimp/code/FBX/FBXMeshGeometry.cpp index 1386e2383..4a3de9f99 100644 --- a/Engine/lib/assimp/code/FBX/FBXMeshGeometry.cpp +++ b/Engine/lib/assimp/code/FBX/FBXMeshGeometry.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -446,14 +446,19 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, return; } std::vector tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); + ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); + + if (tempData.size() != mapping_offsets.size()) { + FBXImporter::LogError(Formatter::format("length of input data unexpected for ByVertice mapping: ") + << tempData.size() << ", expected " << mapping_offsets.size()); + return; + } data_out.resize(vertex_count); - for (size_t i = 0, e = tempData.size(); i < e; ++i) { - + for (size_t i = 0, e = tempData.size(); i < e; ++i) { const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; for (unsigned int j = istart; j < iend; ++j) { - data_out[mappings[j]] = tempData[i]; + data_out[mappings[j]] = tempData[i]; } } } @@ -461,10 +466,17 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, std::vector tempData; ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - data_out.resize(vertex_count); - std::vector uvIndices; ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); + + if (uvIndices.size() != vertex_count) { + FBXImporter::LogError(Formatter::format("length of input data unexpected for ByVertice mapping: ") + << uvIndices.size() << ", expected " << vertex_count); + return; + } + + data_out.resize(vertex_count); + for (size_t i = 0, e = uvIndices.size(); i < e; ++i) { const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; @@ -493,16 +505,17 @@ void ResolveVertexDataArray(std::vector& data_out, const Scope& source, std::vector tempData; ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - data_out.resize(vertex_count); - std::vector uvIndices; ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); if (uvIndices.size() != vertex_count) { - FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping"); + FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygonVertex mapping: ") + << uvIndices.size() << ", expected " << vertex_count); return; } + data_out.resize(vertex_count); + const T empty; unsigned int next = 0; for(int i : uvIndices) { diff --git a/Engine/lib/assimp/code/FBX/FBXMeshGeometry.h b/Engine/lib/assimp/code/FBX/FBXMeshGeometry.h index d6d451217..97265e4b2 100644 --- a/Engine/lib/assimp/code/FBX/FBXMeshGeometry.h +++ b/Engine/lib/assimp/code/FBX/FBXMeshGeometry.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXModel.cpp b/Engine/lib/assimp/code/FBX/FBXModel.cpp index 589af36ac..e34f3a610 100644 --- a/Engine/lib/assimp/code/FBX/FBXModel.cpp +++ b/Engine/lib/assimp/code/FBX/FBXModel.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXNodeAttribute.cpp b/Engine/lib/assimp/code/FBX/FBXNodeAttribute.cpp index b72e5637e..2ebf917e3 100644 --- a/Engine/lib/assimp/code/FBX/FBXNodeAttribute.cpp +++ b/Engine/lib/assimp/code/FBX/FBXNodeAttribute.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXParser.cpp b/Engine/lib/assimp/code/FBX/FBXParser.cpp index 4a9346040..aef59d60c 100644 --- a/Engine/lib/assimp/code/FBX/FBXParser.cpp +++ b/Engine/lib/assimp/code/FBX/FBXParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -367,9 +367,13 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out) // first - next in the fbx token stream comes ',', // which fast_atof could interpret as decimal point. #define MAX_FLOAT_LENGTH 31 - char temp[MAX_FLOAT_LENGTH + 1]; const size_t length = static_cast(t.end()-t.begin()); - std::copy(t.begin(),t.end(),temp); + if (length > MAX_FLOAT_LENGTH) { + return 0.f; + } + + char temp[MAX_FLOAT_LENGTH + 1]; + std::copy(t.begin(), t.end(), temp); temp[std::min(static_cast(MAX_FLOAT_LENGTH),length)] = '\0'; return fast_atof(temp); diff --git a/Engine/lib/assimp/code/FBX/FBXParser.h b/Engine/lib/assimp/code/FBX/FBXParser.h index 7b0cf7203..5d8d00307 100644 --- a/Engine/lib/assimp/code/FBX/FBXParser.h +++ b/Engine/lib/assimp/code/FBX/FBXParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXProperties.cpp b/Engine/lib/assimp/code/FBX/FBXProperties.cpp index 8d7036b6a..f6b804894 100644 --- a/Engine/lib/assimp/code/FBX/FBXProperties.cpp +++ b/Engine/lib/assimp/code/FBX/FBXProperties.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXProperties.h b/Engine/lib/assimp/code/FBX/FBXProperties.h index 58755542f..209d5e940 100644 --- a/Engine/lib/assimp/code/FBX/FBXProperties.h +++ b/Engine/lib/assimp/code/FBX/FBXProperties.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXTokenizer.cpp b/Engine/lib/assimp/code/FBX/FBXTokenizer.cpp index 252cce355..831c40061 100644 --- a/Engine/lib/assimp/code/FBX/FBXTokenizer.cpp +++ b/Engine/lib/assimp/code/FBX/FBXTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXTokenizer.h b/Engine/lib/assimp/code/FBX/FBXTokenizer.h index afa588a47..cadc82770 100644 --- a/Engine/lib/assimp/code/FBX/FBXTokenizer.h +++ b/Engine/lib/assimp/code/FBX/FBXTokenizer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXUtil.cpp b/Engine/lib/assimp/code/FBX/FBXUtil.cpp index c10e057c8..50dd78a4c 100644 --- a/Engine/lib/assimp/code/FBX/FBXUtil.cpp +++ b/Engine/lib/assimp/code/FBX/FBXUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/FBX/FBXUtil.h b/Engine/lib/assimp/code/FBX/FBXUtil.h index b63441885..77bb0ad30 100644 --- a/Engine/lib/assimp/code/FBX/FBXUtil.h +++ b/Engine/lib/assimp/code/FBX/FBXUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/HMP/HMPFileData.h b/Engine/lib/assimp/code/HMP/HMPFileData.h index ab4100174..bad8dde5c 100644 --- a/Engine/lib/assimp/code/HMP/HMPFileData.h +++ b/Engine/lib/assimp/code/HMP/HMPFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/HMP/HMPLoader.cpp b/Engine/lib/assimp/code/HMP/HMPLoader.cpp index d5469181e..0d1334fdd 100644 --- a/Engine/lib/assimp/code/HMP/HMPLoader.cpp +++ b/Engine/lib/assimp/code/HMP/HMPLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/HMP/HMPLoader.h b/Engine/lib/assimp/code/HMP/HMPLoader.h index 421826c91..0371a608b 100644 --- a/Engine/lib/assimp/code/HMP/HMPLoader.h +++ b/Engine/lib/assimp/code/HMP/HMPLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/HMP/HalfLifeFileData.h b/Engine/lib/assimp/code/HMP/HalfLifeFileData.h index ef328edf8..d7db1476c 100644 --- a/Engine/lib/assimp/code/HMP/HalfLifeFileData.h +++ b/Engine/lib/assimp/code/HMP/HalfLifeFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCBoolean.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCBoolean.cpp index 10e7bf3af..01fd43cd2 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCBoolean.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCBoolean.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCCurve.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCCurve.cpp index a817b4f9f..b16df9c5c 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCCurve.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCCurve.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. @@ -323,7 +323,7 @@ public: // oh well. bool have_param = false, have_point = false; IfcVector3 point; - for(const Entry sel :entity.Trim1) { + for(const Entry& sel :entity.Trim1) { if (const ::Assimp::STEP::EXPRESS::REAL* const r = sel->ToPtr<::Assimp::STEP::EXPRESS::REAL>()) { range.first = *r; have_param = true; @@ -340,7 +340,7 @@ public: } } have_param = false, have_point = false; - for(const Entry sel :entity.Trim2) { + for(const Entry& sel :entity.Trim2) { if (const ::Assimp::STEP::EXPRESS::REAL* const r = sel->ToPtr<::Assimp::STEP::EXPRESS::REAL>()) { range.second = *r; have_param = true; diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCGeometry.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCGeometry.cpp index d1c7aee19..bb4d74758 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCGeometry.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCGeometry.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -138,8 +138,9 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m } } } - - ai_assert(outer_polygon_it != end); + if (outer_polygon_it == end) { + return; + } const size_t outer_polygon_size = *outer_polygon_it; const IfcVector3& master_normal = normals[std::distance(begin, outer_polygon_it)]; diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCLoader.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCLoader.cpp index 5c705c256..5dd19f320 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCLoader.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCLoader.h b/Engine/lib/assimp/code/Importer/IFC/IFCLoader.h index 678c60343..4abfe00f1 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCLoader.h +++ b/Engine/lib/assimp/code/Importer/IFC/IFCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCMaterial.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCMaterial.cpp index 5fda0a1de..832712cd4 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCMaterial.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCOpenings.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCOpenings.cpp index d6c40b383..2c6754287 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCOpenings.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCOpenings.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCProfile.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCProfile.cpp index daafc9afe..a1a1b3967 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCProfile.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCProfile.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen1_2x3.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen1_2x3.cpp index f4dbed1d1..58ff47113 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen1_2x3.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen1_2x3.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen2_2x3.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen2_2x3.cpp index 7dabe278e..e6687014d 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen2_2x3.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen2_2x3.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_2x3.h b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_2x3.h index 8b39ccdc2..4605b94cf 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_2x3.h +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_2x3.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.cpp index fdefedb18..9eb3e2446 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.h b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.h index ccfcb6ea0..0f184cd02 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.h +++ b/Engine/lib/assimp/code/Importer/IFC/IFCReaderGen_4.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCUtil.cpp b/Engine/lib/assimp/code/Importer/IFC/IFCUtil.cpp index f6bca91f5..3557b4baa 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCUtil.cpp +++ b/Engine/lib/assimp/code/Importer/IFC/IFCUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/IFC/IFCUtil.h b/Engine/lib/assimp/code/Importer/IFC/IFCUtil.h index 32ae1e07f..cf8c94293 100644 --- a/Engine/lib/assimp/code/Importer/IFC/IFCUtil.h +++ b/Engine/lib/assimp/code/Importer/IFC/IFCUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.cpp b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.cpp index 101dcdfd7..d917c28f3 100644 --- a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.cpp +++ b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.h b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.h index 09f16ba33..a076d1ce9 100644 --- a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.h +++ b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileEncoding.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.cpp b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.cpp index f099d2be7..72f882d6e 100644 --- a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.cpp +++ b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.h b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.h index 9c4b77241..62292792a 100644 --- a/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.h +++ b/Engine/lib/assimp/code/Importer/STEPParser/STEPFileReader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen1.cpp b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen1.cpp index 50c54818e..234300700 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen1.cpp +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen1.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen2.cpp b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen2.cpp index eca09e4e1..a80bb69ef 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen2.cpp +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen2.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen3.cpp b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen3.cpp index d8d81141f..2f25683a8 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileGen3.cpp +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileGen3.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.cpp b/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.cpp index 26c456ac9..28744c785 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.cpp +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.h b/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.h index 70f65fdcf..c6ac08bb6 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.h +++ b/Engine/lib/assimp/code/Importer/StepFile/StepFileImporter.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Importer/StepFile/StepReaderGen.h b/Engine/lib/assimp/code/Importer/StepFile/StepReaderGen.h index 9eb86c332..cb1034e2b 100644 --- a/Engine/lib/assimp/code/Importer/StepFile/StepReaderGen.h +++ b/Engine/lib/assimp/code/Importer/StepFile/StepReaderGen.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/Irr/IRRLoader.cpp b/Engine/lib/assimp/code/Irr/IRRLoader.cpp index e94fd85a4..4361d578a 100644 --- a/Engine/lib/assimp/code/Irr/IRRLoader.cpp +++ b/Engine/lib/assimp/code/Irr/IRRLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Irr/IRRLoader.h b/Engine/lib/assimp/code/Irr/IRRLoader.h index b3ad81a7d..fc6f77031 100644 --- a/Engine/lib/assimp/code/Irr/IRRLoader.h +++ b/Engine/lib/assimp/code/Irr/IRRLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Irr/IRRMeshLoader.cpp b/Engine/lib/assimp/code/Irr/IRRMeshLoader.cpp index 057218464..13db70e91 100644 --- a/Engine/lib/assimp/code/Irr/IRRMeshLoader.cpp +++ b/Engine/lib/assimp/code/Irr/IRRMeshLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/Irr/IRRMeshLoader.h b/Engine/lib/assimp/code/Irr/IRRMeshLoader.h index d8b42d78d..f0d249f71 100644 --- a/Engine/lib/assimp/code/Irr/IRRMeshLoader.h +++ b/Engine/lib/assimp/code/Irr/IRRMeshLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/Irr/IRRShared.cpp b/Engine/lib/assimp/code/Irr/IRRShared.cpp index ecac031ab..5dacc2ae1 100644 --- a/Engine/lib/assimp/code/Irr/IRRShared.cpp +++ b/Engine/lib/assimp/code/Irr/IRRShared.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/LWO/LWOAnimation.cpp b/Engine/lib/assimp/code/LWO/LWOAnimation.cpp index 3a0d2c392..ae9c4c13b 100644 --- a/Engine/lib/assimp/code/LWO/LWOAnimation.cpp +++ b/Engine/lib/assimp/code/LWO/LWOAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/LWO/LWOAnimation.h b/Engine/lib/assimp/code/LWO/LWOAnimation.h index dd29695cc..a46787965 100644 --- a/Engine/lib/assimp/code/LWO/LWOAnimation.h +++ b/Engine/lib/assimp/code/LWO/LWOAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/LWO/LWOBLoader.cpp b/Engine/lib/assimp/code/LWO/LWOBLoader.cpp index b24957072..fe542df1b 100644 --- a/Engine/lib/assimp/code/LWO/LWOBLoader.cpp +++ b/Engine/lib/assimp/code/LWO/LWOBLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/LWO/LWOFileData.h b/Engine/lib/assimp/code/LWO/LWOFileData.h index 7d1f6b1df..33fac8c39 100644 --- a/Engine/lib/assimp/code/LWO/LWOFileData.h +++ b/Engine/lib/assimp/code/LWO/LWOFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/LWO/LWOLoader.cpp b/Engine/lib/assimp/code/LWO/LWOLoader.cpp index 1e5b92c32..cb581f7f5 100644 --- a/Engine/lib/assimp/code/LWO/LWOLoader.cpp +++ b/Engine/lib/assimp/code/LWO/LWOLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -586,7 +586,6 @@ void LWOImporter::GenerateNodeGraph(std::map& apcNodes) root->mName.Set(""); //Set parent of all children, inserting pivots - //std::cout << "Set parent of all children" << std::endl; std::map mapPivot; for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { @@ -618,7 +617,6 @@ void LWOImporter::GenerateNodeGraph(std::map& apcNodes) } //Merge pivot map into node map - //std::cout << "Merge pivot map into node map" << std::endl; for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { apcNodes[itMapPivot->first] = itMapPivot->second; } diff --git a/Engine/lib/assimp/code/LWO/LWOLoader.h b/Engine/lib/assimp/code/LWO/LWOLoader.h index 05b958fd2..680f82923 100644 --- a/Engine/lib/assimp/code/LWO/LWOLoader.h +++ b/Engine/lib/assimp/code/LWO/LWOLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/LWO/LWOMaterial.cpp b/Engine/lib/assimp/code/LWO/LWOMaterial.cpp index b54c21c26..b2304a6be 100644 --- a/Engine/lib/assimp/code/LWO/LWOMaterial.cpp +++ b/Engine/lib/assimp/code/LWO/LWOMaterial.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/LWS/LWSLoader.cpp b/Engine/lib/assimp/code/LWS/LWSLoader.cpp index b52cafa6d..4a9cec4ec 100644 --- a/Engine/lib/assimp/code/LWS/LWSLoader.cpp +++ b/Engine/lib/assimp/code/LWS/LWSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/LWS/LWSLoader.h b/Engine/lib/assimp/code/LWS/LWSLoader.h index eed0491f3..c1321af37 100644 --- a/Engine/lib/assimp/code/LWS/LWSLoader.h +++ b/Engine/lib/assimp/code/LWS/LWSLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/M3D/M3DExporter.cpp b/Engine/lib/assimp/code/M3D/M3DExporter.cpp index c22943396..08a0e4ad8 100644 --- a/Engine/lib/assimp/code/M3D/M3DExporter.cpp +++ b/Engine/lib/assimp/code/M3D/M3DExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -45,7 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define M3D_IMPLEMENTATION #define M3D_NOIMPORTER #define M3D_EXPORTER -#define M3D_ASCII #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER #define M3D_NODUP #endif @@ -55,15 +54,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include // aiGetVersion -#include -#include -#include -#include // StreamWriterLE #include // DeadlyExportError +#include // StreamWriterLE #include // aiTextureType -#include #include +#include +#include // aiGetVersion +#include +#include +#include + +#include "M3DWrapper.h" #include "M3DExporter.h" #include "M3DMaterials.h" @@ -80,316 +81,357 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation * triplets, instead of per bone timestamp + lists) */ -using namespace Assimp; - -namespace Assimp { - - // --------------------------------------------------------------------- - // Worker function for exporting a scene to binary M3D. - // Prototyped and registered in Exporter.cpp - void ExportSceneM3D ( - const char* pFile, - IOSystem* pIOSystem, - const aiScene* pScene, - const ExportProperties* pProperties - ){ - // initialize the exporter - M3DExporter exporter(pScene, pProperties); - - // perform binary export - exporter.doExport(pFile, pIOSystem, false); - } - - // --------------------------------------------------------------------- - // Worker function for exporting a scene to ASCII A3D. - // Prototyped and registered in Exporter.cpp - void ExportSceneA3D ( - const char* pFile, - IOSystem* pIOSystem, - const aiScene* pScene, - const ExportProperties* pProperties - - ){ - // initialize the exporter - M3DExporter exporter(pScene, pProperties); - - // perform ascii export - exporter.doExport(pFile, pIOSystem, true); - } - -} // end of namespace Assimp // ------------------------------------------------------------------------------------------------ -M3DExporter::M3DExporter ( const aiScene* pScene, const ExportProperties* pProperties ) -: mScene(pScene) -, mProperties(pProperties) -, outfile() -, m3d(nullptr) { } - +// Conversion functions // ------------------------------------------------------------------------------------------------ -void M3DExporter::doExport ( - const char* pFile, - IOSystem* pIOSystem, - bool toAscii -){ - // TODO: convert mProperties into M3D_EXP_* flags - (void)mProperties; - - // open the indicated file for writing (in binary / ASCII mode) - outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb")); - if (!outfile) { - throw DeadlyExportError( "could not open output .m3d file: " + std::string(pFile) ); - } - - // use malloc() here because m3d_free() will call free() - m3d = (m3d_t*)calloc(1, sizeof(m3d_t)); - if(!m3d) { - throw DeadlyExportError( "memory allocation error" ); - } - m3d->name = _m3d_safestr((char*)&mScene->mRootNode->mName.data, 2); - - // Create a model from assimp structures - aiMatrix4x4 m; - NodeWalk(mScene->mRootNode, m); - - // serialize the structures - unsigned int size; - unsigned char *output = m3d_save(m3d, M3D_EXP_FLOAT, - M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), &size); - m3d_free(m3d); - if(!output || size < 8) { - throw DeadlyExportError( "unable to serialize into Model 3D" ); - } - - // Write out serialized model - outfile->Write(output, size, 1); - - // explicitly release file pointer, - // so we don't have to rely on class destruction. - outfile.reset(); +// helper to add a vertex (private to NodeWalk) +m3dv_t *AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) { + if (v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0; + if (v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0; + if (v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0; + if (v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0; + vrtx = (m3dv_t *)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t)); + memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t)); + *idx = *numvrtx; + (*numvrtx)++; + return vrtx; } // ------------------------------------------------------------------------------------------------ -// recursive node walker -void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m) -{ - aiMatrix4x4 nm = m * pNode->mTransformation; - - for(unsigned int i = 0; i < pNode->mNumMeshes; i++) { - const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]]; - unsigned int mi = (M3D_INDEX)-1U; - if(mScene->mMaterials) { - // get the material for this mesh - mi = addMaterial(mScene->mMaterials[mesh->mMaterialIndex]); - } - // iterate through the mesh faces - for(unsigned int j = 0; j < mesh->mNumFaces; j++) { - unsigned int n; - const aiFace* face = &(mesh->mFaces[j]); - // only triangle meshes supported for now - if(face->mNumIndices != 3) { - throw DeadlyExportError( "use aiProcess_Triangulate before export" ); - } - // add triangle to the output - n = m3d->numface++; - m3d->face = (m3df_t*)M3D_REALLOC(m3d->face, - m3d->numface * sizeof(m3df_t)); - if(!m3d->face) { - throw DeadlyExportError( "memory allocation error" ); - } - /* set all index to -1 by default */ - m3d->face[n].vertex[0] = m3d->face[n].vertex[1] = m3d->face[n].vertex[2] = - m3d->face[n].normal[0] = m3d->face[n].normal[1] = m3d->face[n].normal[2] = - m3d->face[n].texcoord[0] = m3d->face[n].texcoord[1] = m3d->face[n].texcoord[2] = -1U; - m3d->face[n].materialid = mi; - for(unsigned int k = 0; k < face->mNumIndices; k++) { - // get the vertex's index - unsigned int l = face->mIndices[k]; - unsigned int idx; - m3dv_t vertex; - m3dti_t ti; - // multiply the position vector by the transformation matrix - aiVector3D v = mesh->mVertices[l]; - v *= nm; - vertex.x = v.x; - vertex.y = v.y; - vertex.z = v.z; - vertex.w = 1.0; - vertex.color = 0; - vertex.skinid = -1U; - // add color if defined - if(mesh->HasVertexColors(0)) - vertex.color = mkColor(&mesh->mColors[0][l]); - // save the vertex to the output - m3d->vertex = _m3d_addvrtx(m3d->vertex, &m3d->numvertex, - &vertex, &idx); - m3d->face[n].vertex[k] = (M3D_INDEX)idx; - // do we have texture coordinates? - if(mesh->HasTextureCoords(0)) { - ti.u = mesh->mTextureCoords[0][l].x; - ti.v = mesh->mTextureCoords[0][l].y; - m3d->tmap = _m3d_addtmap(m3d->tmap, &m3d->numtmap, &ti, - &idx); - m3d->face[n].texcoord[k] = (M3D_INDEX)idx; - } - // do we have normal vectors? - if(mesh->HasNormals()) { - vertex.color = 0; - vertex.x = mesh->mNormals[l].x; - vertex.y = mesh->mNormals[l].y; - vertex.z = mesh->mNormals[l].z; - m3d->vertex = _m3d_addnorm(m3d->vertex, &m3d->numvertex, - &vertex, &idx); - m3d->face[n].normal[k] = (M3D_INDEX)idx; - } - } - } - } - // repeat for the children nodes - for (unsigned int i = 0; i < pNode->mNumChildren; i++) { - NodeWalk(pNode->mChildren[i], nm); - } +// helper to add a tmap (private to NodeWalk) +m3dti_t *AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx) { + tmap = (m3dti_t *)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t)); + memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t)); + *idx = *numtmap; + (*numtmap)++; + return tmap; } // ------------------------------------------------------------------------------------------------ // convert aiColor4D into uint32_t -uint32_t M3DExporter::mkColor(aiColor4D* c) -{ - return ((uint8_t)(c->a*255) << 24L) | - ((uint8_t)(c->b*255) << 16L) | - ((uint8_t)(c->g*255) << 8L) | - ((uint8_t)(c->r*255) << 0L); -} - -// ------------------------------------------------------------------------------------------------ -// add a material to the output -M3D_INDEX M3DExporter::addMaterial(const aiMaterial *mat) -{ - unsigned int mi = -1U; - aiColor4D c; - aiString name; - ai_real f; - char *fn; - - if(mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length && - strcmp((char*)&name.data, AI_DEFAULT_MATERIAL_NAME)) { - // check if we have saved a material by this name. This has to be done - // because only the referenced materials should be added to the output - for(unsigned int i = 0; i < m3d->nummaterial; i++) - if(!strcmp((char*)&name.data, m3d->material[i].name)) { - mi = i; - break; - } - // if not found, add the material to the output - if(mi == -1U) { - unsigned int k; - mi = m3d->nummaterial++; - m3d->material = (m3dm_t*)M3D_REALLOC(m3d->material, m3d->nummaterial - * sizeof(m3dm_t)); - if(!m3d->material) { - throw DeadlyExportError( "memory allocation error" ); - } - m3d->material[mi].name = _m3d_safestr((char*)&name.data, 0); - m3d->material[mi].numprop = 0; - m3d->material[mi].prop = NULL; - // iterate through the material property table and see what we got - for(k = 0; k < 15; k++) { - unsigned int j; - if(m3d_propertytypes[k].format == m3dpf_map) - continue; - if(aiProps[k].pKey) { - switch(m3d_propertytypes[k].format) { - case m3dpf_color: - if(mat->Get(aiProps[k].pKey, aiProps[k].type, - aiProps[k].index, c) == AI_SUCCESS) - addProp(&m3d->material[mi], - m3d_propertytypes[k].id, mkColor(&c)); - break; - case m3dpf_float: - if(mat->Get(aiProps[k].pKey, aiProps[k].type, - aiProps[k].index, f) == AI_SUCCESS) - addProp(&m3d->material[mi], - m3d_propertytypes[k].id, - /* not (uint32_t)f, because we don't want to convert - * it, we want to see it as 32 bits of memory */ - *((uint32_t*)&f)); - break; - case m3dpf_uint8: - if(mat->Get(aiProps[k].pKey, aiProps[k].type, - aiProps[k].index, j) == AI_SUCCESS) { - // special conversion for illumination model property - if(m3d_propertytypes[k].id == m3dp_il) { - switch(j) { - case aiShadingMode_NoShading: j = 0; break; - case aiShadingMode_Phong: j = 2; break; - default: j = 1; break; - } - } - addProp(&m3d->material[mi], - m3d_propertytypes[k].id, j); - } - break; - default: - if(mat->Get(aiProps[k].pKey, aiProps[k].type, - aiProps[k].index, j) == AI_SUCCESS) - addProp(&m3d->material[mi], - m3d_propertytypes[k].id, j); - break; - } - } - if(aiTxProps[k].pKey && - mat->GetTexture((aiTextureType)aiTxProps[k].type, - aiTxProps[k].index, &name, NULL, NULL, NULL, - NULL, NULL) == AI_SUCCESS) { - unsigned int i; - for(j = name.length-1; j > 0 && name.data[j]!='.'; j++); - if(j && name.data[j]=='.' && - (name.data[j+1]=='p' || name.data[j+1]=='P') && - (name.data[j+1]=='n' || name.data[j+1]=='N') && - (name.data[j+1]=='g' || name.data[j+1]=='G')) - name.data[j]=0; - // do we have this texture saved already? - fn = _m3d_safestr((char*)&name.data, 0); - for(j = 0, i = -1U; j < m3d->numtexture; j++) - if(!strcmp(fn, m3d->texture[j].name)) { - i = j; - free(fn); - break; - } - if(i == -1U) { - i = m3d->numtexture++; - m3d->texture = (m3dtx_t*)M3D_REALLOC( - m3d->texture, - m3d->numtexture * sizeof(m3dtx_t)); - if(!m3d->texture) { - throw DeadlyExportError( "memory allocation error" ); - } - // we don't need the texture itself, only its name - m3d->texture[i].name = fn; - m3d->texture[i].w = 0; - m3d->texture[i].h = 0; - m3d->texture[i].d = NULL; - } - addProp(&m3d->material[mi], - m3d_propertytypes[k].id + 128, i); - } - } - } - } - return mi; +uint32_t mkColor(aiColor4D *c) { + return ((uint8_t)(c->a * 255) << 24L) | + ((uint8_t)(c->b * 255) << 16L) | + ((uint8_t)(c->g * 255) << 8L) | + ((uint8_t)(c->r * 255) << 0L); } // ------------------------------------------------------------------------------------------------ // add a material property to the output -void M3DExporter::addProp(m3dm_t *m, uint8_t type, uint32_t value) -{ - unsigned int i; - i = m->numprop++; - m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); - if(!m->prop) { throw DeadlyExportError( "memory allocation error" ); } - m->prop[i].type = type; - m->prop[i].value.num = value; +void addProp(m3dm_t *m, uint8_t type, uint32_t value) { + unsigned int i; + i = m->numprop++; + m->prop = (m3dp_t *)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); + if (!m->prop) { + throw DeadlyExportError("memory allocation error"); + } + m->prop[i].type = type; + m->prop[i].value.num = value; } +// ------------------------------------------------------------------------------------------------ +// convert aiString to identifier safe C string. This is a duplication of _m3d_safestr +char *SafeStr(aiString str, bool isStrict) +{ + char *s = (char *)&str.data; + char *d, *ret; + int i, len; + + for(len = str.length + 1; *s && (*s == ' ' || *s == '\t'); s++, len--); + if(len > 255) len = 255; + ret = (char *)M3D_MALLOC(len + 1); + if (!ret) { + throw DeadlyExportError("memory allocation error"); + } + for(i = 0, d = ret; i < len && *s && *s != '\r' && *s != '\n'; s++, d++, i++) { + *d = isStrict && (*s == ' ' || *s == '\t' || *s == '/' || *s == '\\') ? '_' : (*s == '\t' ? ' ' : *s); + } + for(; d > ret && (*(d-1) == ' ' || *(d-1) == '\t'); d--); + *d = 0; + return ret; +} + +// ------------------------------------------------------------------------------------------------ +// add a material to the output +M3D_INDEX addMaterial(const Assimp::M3DWrapper &m3d, const aiMaterial *mat) { + unsigned int mi = M3D_NOTDEFINED; + aiColor4D c; + aiString name; + ai_real f; + char *fn; + + if (mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length && + strcmp((char *)&name.data, AI_DEFAULT_MATERIAL_NAME)) { + // check if we have saved a material by this name. This has to be done + // because only the referenced materials should be added to the output + for (unsigned int i = 0; i < m3d->nummaterial; i++) + if (!strcmp((char *)&name.data, m3d->material[i].name)) { + mi = i; + break; + } + // if not found, add the material to the output + if (mi == M3D_NOTDEFINED) { + unsigned int k; + mi = m3d->nummaterial++; + m3d->material = (m3dm_t *)M3D_REALLOC(m3d->material, m3d->nummaterial * sizeof(m3dm_t)); + if (!m3d->material) { + throw DeadlyExportError("memory allocation error"); + } + m3d->material[mi].name = SafeStr(name, true); + m3d->material[mi].numprop = 0; + m3d->material[mi].prop = NULL; + // iterate through the material property table and see what we got + for (k = 0; k < 15; k++) { + unsigned int j; + if (m3d_propertytypes[k].format == m3dpf_map) + continue; + if (aiProps[k].pKey) { + switch (m3d_propertytypes[k].format) { + case m3dpf_color: + if (mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, c) == AI_SUCCESS) + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, mkColor(&c)); + break; + case m3dpf_float: + if (mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, f) == AI_SUCCESS) + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, + /* not (uint32_t)f, because we don't want to convert + * it, we want to see it as 32 bits of memory */ + *((uint32_t *)&f)); + break; + case m3dpf_uint8: + if (mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, j) == AI_SUCCESS) { + // special conversion for illumination model property + if (m3d_propertytypes[k].id == m3dp_il) { + switch (j) { + case aiShadingMode_NoShading: j = 0; break; + case aiShadingMode_Phong: j = 2; break; + default: j = 1; break; + } + } + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, j); + } + break; + default: + if (mat->Get(aiProps[k].pKey, aiProps[k].type, + aiProps[k].index, j) == AI_SUCCESS) + addProp(&m3d->material[mi], + m3d_propertytypes[k].id, j); + break; + } + } + if (aiTxProps[k].pKey && + mat->GetTexture((aiTextureType)aiTxProps[k].type, + aiTxProps[k].index, &name, NULL, NULL, NULL, + NULL, NULL) == AI_SUCCESS) { + unsigned int i; + for (j = name.length - 1; j > 0 && name.data[j] != '.'; j++) + ; + if (j && name.data[j] == '.' && + (name.data[j + 1] == 'p' || name.data[j + 1] == 'P') && + (name.data[j + 1] == 'n' || name.data[j + 1] == 'N') && + (name.data[j + 1] == 'g' || name.data[j + 1] == 'G')) + name.data[j] = 0; + // do we have this texture saved already? + fn = SafeStr(name, true); + for (j = 0, i = M3D_NOTDEFINED; j < m3d->numtexture; j++) + if (!strcmp(fn, m3d->texture[j].name)) { + i = j; + free(fn); + break; + } + if (i == M3D_NOTDEFINED) { + i = m3d->numtexture++; + m3d->texture = (m3dtx_t *)M3D_REALLOC( + m3d->texture, + m3d->numtexture * sizeof(m3dtx_t)); + if (!m3d->texture) { + throw DeadlyExportError("memory allocation error"); + } + // we don't need the texture itself, only its name + m3d->texture[i].name = fn; + m3d->texture[i].w = 0; + m3d->texture[i].h = 0; + m3d->texture[i].d = NULL; + } + addProp(&m3d->material[mi], + m3d_propertytypes[k].id + 128, i); + } + } + } + } + return mi; +} + +namespace Assimp { + +// --------------------------------------------------------------------- +// Worker function for exporting a scene to binary M3D. +// Prototyped and registered in Exporter.cpp +void ExportSceneM3D( + const char *pFile, + IOSystem *pIOSystem, + const aiScene *pScene, + const ExportProperties *pProperties) { + // initialize the exporter + M3DExporter exporter(pScene, pProperties); + + // perform binary export + exporter.doExport(pFile, pIOSystem, false); +} + +// --------------------------------------------------------------------- +// Worker function for exporting a scene to ASCII A3D. +// Prototyped and registered in Exporter.cpp +void ExportSceneM3DA( + const char *pFile, + IOSystem *pIOSystem, + const aiScene *pScene, + const ExportProperties *pProperties + +) { +#ifdef M3D_ASCII + // initialize the exporter + M3DExporter exporter(pScene, pProperties); + + // perform ascii export + exporter.doExport(pFile, pIOSystem, true); +#else + throw DeadlyExportError("Assimp configured without M3D_ASCII support"); +#endif +} + +// ------------------------------------------------------------------------------------------------ +M3DExporter::M3DExporter(const aiScene *pScene, const ExportProperties *pProperties) : + mScene(pScene), + mProperties(pProperties), + outfile() {} + +// ------------------------------------------------------------------------------------------------ +void M3DExporter::doExport( + const char *pFile, + IOSystem *pIOSystem, + bool toAscii) { + // TODO: convert mProperties into M3D_EXP_* flags + (void)mProperties; + + // open the indicated file for writing (in binary / ASCII mode) + outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb")); + if (!outfile) { + throw DeadlyExportError("could not open output .m3d file: " + std::string(pFile)); + } + + M3DWrapper m3d; + if (!m3d) { + throw DeadlyExportError("memory allocation error"); + } + m3d->name = SafeStr(mScene->mRootNode->mName, false); + + // Create a model from assimp structures + aiMatrix4x4 m; + NodeWalk(m3d, mScene->mRootNode, m); + + // serialize the structures + unsigned int size; + unsigned char *output = m3d.Save(M3D_EXP_FLOAT, M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), size); + + if (!output || size < 8) { + throw DeadlyExportError("unable to serialize into Model 3D"); + } + + // Write out serialized model + outfile->Write(output, size, 1); + + // explicitly release file pointer, + // so we don't have to rely on class destruction. + outfile.reset(); +} + +// ------------------------------------------------------------------------------------------------ +// recursive node walker +void M3DExporter::NodeWalk(const M3DWrapper &m3d, const aiNode *pNode, aiMatrix4x4 m) { + aiMatrix4x4 nm = m * pNode->mTransformation; + + for (unsigned int i = 0; i < pNode->mNumMeshes; i++) { + const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]]; + unsigned int mi = M3D_NOTDEFINED; + if (mScene->mMaterials) { + // get the material for this mesh + mi = addMaterial(m3d, mScene->mMaterials[mesh->mMaterialIndex]); + } + // iterate through the mesh faces + for (unsigned int j = 0; j < mesh->mNumFaces; j++) { + unsigned int n; + const aiFace *face = &(mesh->mFaces[j]); + // only triangle meshes supported for now + if (face->mNumIndices != 3) { + throw DeadlyExportError("use aiProcess_Triangulate before export"); + } + // add triangle to the output + n = m3d->numface++; + m3d->face = (m3df_t *)M3D_REALLOC(m3d->face, + m3d->numface * sizeof(m3df_t)); + if (!m3d->face) { + throw DeadlyExportError("memory allocation error"); + } + /* set all index to -1 by default */ + m3d->face[n].vertex[0] = m3d->face[n].vertex[1] = m3d->face[n].vertex[2] = + m3d->face[n].normal[0] = m3d->face[n].normal[1] = m3d->face[n].normal[2] = + m3d->face[n].texcoord[0] = m3d->face[n].texcoord[1] = m3d->face[n].texcoord[2] = M3D_UNDEF; + m3d->face[n].materialid = mi; + for (unsigned int k = 0; k < face->mNumIndices; k++) { + // get the vertex's index + unsigned int l = face->mIndices[k]; + unsigned int idx; + m3dv_t vertex; + m3dti_t ti; + // multiply the position vector by the transformation matrix + aiVector3D v = mesh->mVertices[l]; + v *= nm; + vertex.x = v.x; + vertex.y = v.y; + vertex.z = v.z; + vertex.w = 1.0; + vertex.color = 0; + vertex.skinid = M3D_UNDEF; + // add color if defined + if (mesh->HasVertexColors(0)) + vertex.color = mkColor(&mesh->mColors[0][l]); + // save the vertex to the output + m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, + &vertex, &idx); + m3d->face[n].vertex[k] = (M3D_INDEX)idx; + // do we have texture coordinates? + if (mesh->HasTextureCoords(0)) { + ti.u = mesh->mTextureCoords[0][l].x; + ti.v = mesh->mTextureCoords[0][l].y; + m3d->tmap = AddTmap(m3d->tmap, &m3d->numtmap, &ti, &idx); + m3d->face[n].texcoord[k] = (M3D_INDEX)idx; + } + // do we have normal vectors? + if (mesh->HasNormals()) { + vertex.x = mesh->mNormals[l].x; + vertex.y = mesh->mNormals[l].y; + vertex.z = mesh->mNormals[l].z; + vertex.color = 0; + m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx); + m3d->face[n].normal[k] = (M3D_INDEX)idx; + } + } + } + } + // repeat for the children nodes + for (unsigned int i = 0; i < pNode->mNumChildren; i++) { + NodeWalk(m3d, pNode->mChildren[i], nm); + } +} +} // namespace Assimp + #endif // ASSIMP_BUILD_NO_M3D_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/Engine/lib/assimp/code/M3D/M3DExporter.h b/Engine/lib/assimp/code/M3D/M3DExporter.h index dfcff8bc9..40fce44d0 100644 --- a/Engine/lib/assimp/code/M3D/M3DExporter.h +++ b/Engine/lib/assimp/code/M3D/M3DExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -48,8 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_M3D_EXPORTER -#include "m3d.h" - #include //#include #include // StreamWriterLE @@ -68,6 +66,8 @@ namespace Assimp class IOStream; class ExportProperties; + class M3DWrapper; + // --------------------------------------------------------------------- /** Helper class to export a given scene to an M3D file. */ // --------------------------------------------------------------------- @@ -83,13 +83,9 @@ namespace Assimp const aiScene* mScene; // the scene to export const ExportProperties* mProperties; // currently unused std::shared_ptr outfile; // file to write to - m3d_t *m3d; // model for the C library to convert to // helper to do the recursive walking - void NodeWalk(const aiNode* pNode, aiMatrix4x4 m); - uint32_t mkColor(aiColor4D* c); - M3D_INDEX addMaterial(const aiMaterial *mat); - void addProp(m3dm_t *m, uint8_t type, uint32_t value); + void NodeWalk(const M3DWrapper &m3d, const aiNode* pNode, aiMatrix4x4 m); }; } diff --git a/Engine/lib/assimp/code/M3D/M3DImporter.cpp b/Engine/lib/assimp/code/M3D/M3DImporter.cpp index fcff49df7..9aee14f75 100644 --- a/Engine/lib/assimp/code/M3D/M3DImporter.cpp +++ b/Engine/lib/assimp/code/M3D/M3DImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -43,16 +43,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER #define M3D_IMPLEMENTATION -#define M3D_ASCII +#define M3D_NONORMALS /* leave the post-processing to Assimp */ +#define M3D_NOWEIGHTS +#define M3D_NOANIMATION -#include -#include #include -#include -#include +#include #include -#include #include +#include +#include +#include +#include + +#include "M3DWrapper.h" #include "M3DImporter.h" #include "M3DMaterials.h" @@ -82,656 +86,721 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ static const aiImporterDesc desc = { - "Model 3D Importer", - "", - "", - "", - aiImporterFlags_SupportBinaryFlavour, - 0, - 0, - 0, - 0, - "m3d a3d" + "Model 3D Importer", + "", + "", + "", + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour, + 0, + 0, + 0, + 0, +#ifdef M3D_ASCII + "m3d a3d" +#else + "m3d" +#endif }; -// workaround: the SDK expects a C callback, but we want to use Assimp::IOSystem to implement that -extern "C" { - void* m3dimporter_pIOHandler; - - unsigned char *m3dimporter_readfile(char *fn, unsigned int *size) { - ai_assert( nullptr != fn ); - ai_assert( nullptr != size ); - std::string file(fn); - std::unique_ptr pStream( - (reinterpret_cast(m3dimporter_pIOHandler))->Open( file, "rb")); - size_t fileSize = pStream->FileSize(); - // should be allocated with malloc(), because the library will call free() to deallocate - unsigned char *data = (unsigned char*)malloc(fileSize); - if( !data || !pStream.get() || !fileSize || fileSize != pStream->Read(data,1,fileSize)) { - pStream.reset(); - *size = 0; - // don't throw a deadly exception, it's not fatal if we can't read an external asset - return nullptr; - } - pStream.reset(); - *size = (int)fileSize; - return data; - } -} - namespace Assimp { using namespace std; // ------------------------------------------------------------------------------------------------ // Default constructor -M3DImporter::M3DImporter() -: mScene(nullptr) -, m3d(nullptr) { } - -// ------------------------------------------------------------------------------------------------ -// Destructor. -M3DImporter::~M3DImporter() {} +M3DImporter::M3DImporter() : + mScene(nullptr) { + // empty + } // ------------------------------------------------------------------------------------------------ // Returns true, if file is a binary or ASCII Model 3D file. -bool M3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler , bool checkSig) const { - const std::string extension = GetExtension(pFile); +bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { + const std::string extension = GetExtension(pFile); - if (extension == "m3d" || extension == "a3d") - return true; - else if (!extension.length() || checkSig) { - if (!pIOHandler) { - return true; - } - /* + if (extension == "m3d" +#ifdef M3D_ASCII + || extension == "a3d" +#endif + ) + return true; + else if (!extension.length() || checkSig) { + if (!pIOHandler) { + return true; + } + /* * don't use CheckMagicToken because that checks with swapped bytes too, leading to false * positives. This magic is not uint32_t, but char[4], so memcmp is the best way const char* tokens[] = {"3DMO", "3dmo"}; return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4); */ - std::unique_ptr pStream (pIOHandler->Open(pFile, "rb")); - unsigned char data[4]; - if(4 != pStream->Read(data,1,4)) { - return false; - } - return !memcmp(data, "3DMO", 4) /* bin */ || !memcmp(data, "3dmo", 4) /* ASCII */; - } - return false; + std::unique_ptr pStream(pIOHandler->Open(pFile, "rb")); + unsigned char data[4]; + if (4 != pStream->Read(data, 1, 4)) { + return false; + } + return !memcmp(data, "3DMO", 4) /* bin */ +#ifdef M3D_ASCII + || !memcmp(data, "3dmo", 4) /* ASCII */ +#endif + ; + } + return false; } // ------------------------------------------------------------------------------------------------ -const aiImporterDesc* M3DImporter::GetInfo() const { - return &desc; +const aiImporterDesc *M3DImporter::GetInfo() const { + return &desc; } // ------------------------------------------------------------------------------------------------ // Model 3D import implementation -void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSystem* pIOHandler) { - // Read file into memory - std::unique_ptr pStream( pIOHandler->Open( file, "rb")); - if( !pStream.get() ) { - throw DeadlyImportError( "Failed to open file " + file + "." ); - } +void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) { + // Read file into memory + std::unique_ptr pStream(pIOHandler->Open(file, "rb")); + if (!pStream.get()) { + throw DeadlyImportError("Failed to open file " + file + "."); + } - // Get the file-size and validate it, throwing an exception when fails - size_t fileSize = pStream->FileSize(); - if( fileSize < 8 ) { - throw DeadlyImportError( "M3D-file " + file + " is too small." ); - } - std::unique_ptr _buffer (new unsigned char[fileSize]); - unsigned char *data( _buffer.get() ); - if(fileSize != pStream->Read(data,1,fileSize)) { - throw DeadlyImportError( "Failed to read the file " + file + "." ); - } + // Get the file-size and validate it, throwing an exception when fails + size_t fileSize = pStream->FileSize(); + if (fileSize < 8) { + throw DeadlyImportError("M3D-file " + file + " is too small."); + } + std::vector buffer(fileSize); + if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) { + throw DeadlyImportError("Failed to read the file " + file + "."); + } + // extra check for binary format's first 8 bytes. Not done for the ASCII variant + if(!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) { + throw DeadlyImportError("Bad binary header in file " + file + "."); + } +#ifdef M3D_ASCII + // make sure there's a terminator zero character, as input must be ASCIIZ + if(!memcmp(buffer.data(), "3dmo", 4)) { + buffer.push_back(0); + } +#endif - // Get the path for external assets - std::string folderName( "./" ); - std::string::size_type pos = file.find_last_of( "\\/" ); - if ( pos != std::string::npos ) { - folderName = file.substr( 0, pos ); - if ( !folderName.empty() ) { - pIOHandler->PushDirectory( folderName ); - } - } - // pass this IOHandler to the C callback - m3dimporter_pIOHandler = pIOHandler; + // Get the path for external assets + std::string folderName("./"); + std::string::size_type pos = file.find_last_of("\\/"); + if (pos != std::string::npos) { + folderName = file.substr(0, pos); + if (!folderName.empty()) { + pIOHandler->PushDirectory(folderName); + } + } //DefaultLogger::create("/dev/stderr", Logger::VERBOSE); - ASSIMP_LOG_DEBUG_F("M3D: loading ", file); + ASSIMP_LOG_DEBUG_F("M3D: loading ", file); - // let the C SDK do the hard work for us - m3d = m3d_load(&data[0], m3dimporter_readfile, free, nullptr); - m3dimporter_pIOHandler = nullptr; - if( !m3d ) { - throw DeadlyImportError( "Unable to parse " + file + " as M3D." ); - } + // let the C SDK do the hard work for us + M3DWrapper m3d(pIOHandler, buffer); - // create the root node - pScene->mRootNode = new aiNode; - pScene->mRootNode->mName = aiString(std::string(std::string(m3d->name))); - pScene->mRootNode->mTransformation = aiMatrix4x4(); - pScene->mRootNode->mNumChildren = 0; - mScene = pScene; + if (!m3d) { + throw DeadlyImportError("Unable to parse " + file + " as M3D."); + } - ASSIMP_LOG_DEBUG("M3D: root node " + std::string(m3d->name)); + // create the root node + pScene->mRootNode = new aiNode; + pScene->mRootNode->mName = aiString(m3d.Name()); + pScene->mRootNode->mTransformation = aiMatrix4x4(); + pScene->mRootNode->mNumChildren = 0; + mScene = pScene; - // now we just have to fill up the Assimp structures in pScene - importMaterials(); - importTextures(); - importBones(-1U, pScene->mRootNode); - importMeshes(); - importAnimations(); + ASSIMP_LOG_DEBUG("M3D: root node " + m3d.Name()); - // we don't need the SDK's version any more - m3d_free(m3d); + // now we just have to fill up the Assimp structures in pScene + importMaterials(m3d); + importTextures(m3d); + importBones(m3d, M3D_NOTDEFINED, pScene->mRootNode); + importMeshes(m3d); + importAnimations(m3d); - // Pop directory stack - if ( pIOHandler->StackSize() > 0 ) { - pIOHandler->PopDirectory(); - } + // Pop directory stack + if (pIOHandler->StackSize() > 0) { + pIOHandler->PopDirectory(); + } } // ------------------------------------------------------------------------------------------------ // convert materials. properties are converted using a static table in M3DMaterials.h -void M3DImporter::importMaterials() -{ - unsigned int i, j, k, l, n; - m3dm_t *m; - aiString name = aiString(AI_DEFAULT_MATERIAL_NAME); - aiColor4D c; - ai_real f; +void M3DImporter::importMaterials(const M3DWrapper &m3d) { + unsigned int i, j, k, l, n; + m3dm_t *m; + aiString name = aiString(AI_DEFAULT_MATERIAL_NAME); + aiColor4D c; + ai_real f; - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); + ai_assert(mScene != nullptr); + ai_assert(m3d); - mScene->mNumMaterials = m3d->nummaterial + 1; - mScene->mMaterials = new aiMaterial*[ m3d->nummaterial + 1 ]; + mScene->mNumMaterials = m3d->nummaterial + 1; + mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials]; - ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials); + ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials); - // add a default material as first - aiMaterial* mat = new aiMaterial; - mat->AddProperty( &name, AI_MATKEY_NAME ); - c.a = 1.0; c.b = c.g = c.r = 0.6; - mat->AddProperty( &c, 1, AI_MATKEY_COLOR_DIFFUSE); - mScene->mMaterials[0] = mat; + // add a default material as first + aiMaterial *mat = new aiMaterial; + mat->AddProperty(&name, AI_MATKEY_NAME); + c.a = 1.0f; + c.b = c.g = c.r = 0.6f; + mat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE); + mScene->mMaterials[0] = mat; - for(i = 0; i < m3d->nummaterial; i++) { - m = &m3d->material[i]; - aiMaterial* mat = new aiMaterial; - name.Set(std::string(m->name)); - mat->AddProperty( &name, AI_MATKEY_NAME ); - for(j = 0; j < m->numprop; j++) { - // look up property type - // 0 - 127 scalar values, - // 128 - 255 the same properties but for texture maps - k = 256; - for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) - if(m->prop[j].type == m3d_propertytypes[l].id || - m->prop[j].type == m3d_propertytypes[l].id + 128) { - k = l; - break; - } - // should never happen, but be safe than sorry - if(k == 256) continue; + if (!m3d->nummaterial || !m3d->material) { + return; + } - // scalar properties - if(m->prop[j].type < 128 && aiProps[k].pKey) { - switch(m3d_propertytypes[k].format) { - case m3dpf_color: - c = mkColor(m->prop[j].value.color); - mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); - break; - case m3dpf_float: - f = m->prop[j].value.fnum; - mat->AddProperty(&f, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); - break; - default: - n = m->prop[j].value.num; - if(m->prop[j].type == m3dp_il) { - switch(n) { - case 0: n = aiShadingMode_NoShading; break; - case 2: n = aiShadingMode_Phong; break; - default: n = aiShadingMode_Gouraud; break; - } - } - mat->AddProperty(&n, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); - break; - } - } - // texture map properties - if(m->prop[j].type >= 128 && aiTxProps[k].pKey && - // extra check, should never happen, do we have the refered texture? - m->prop[j].value.textureid < m3d->numtexture && - m3d->texture[m->prop[j].value.textureid].name) { - name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png")); - mat->AddProperty(&name, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); - n = 0; - mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index); - } - } - mScene->mMaterials[i + 1] = mat; - } + for (i = 0; i < m3d->nummaterial; i++) { + m = &m3d->material[i]; + aiMaterial *mat = new aiMaterial; + name.Set(std::string(m->name)); + mat->AddProperty(&name, AI_MATKEY_NAME); + for (j = 0; j < m->numprop; j++) { + // look up property type + // 0 - 127 scalar values, + // 128 - 255 the same properties but for texture maps + k = 256; + for (l = 0; l < sizeof(m3d_propertytypes) / sizeof(m3d_propertytypes[0]); l++) + if (m->prop[j].type == m3d_propertytypes[l].id || + m->prop[j].type == m3d_propertytypes[l].id + 128) { + k = l; + break; + } + // should never happen, but be safe than sorry + if (k == 256) continue; + + // scalar properties + if (m->prop[j].type < 128 && aiProps[k].pKey) { + switch (m3d_propertytypes[k].format) { + case m3dpf_color: + c = mkColor(m->prop[j].value.color); + mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + break; + case m3dpf_float: + f = m->prop[j].value.fnum; + mat->AddProperty(&f, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + break; + default: + n = m->prop[j].value.num; + if (m->prop[j].type == m3dp_il) { + switch (n) { + case 0: n = aiShadingMode_NoShading; break; + case 2: n = aiShadingMode_Phong; break; + default: n = aiShadingMode_Gouraud; break; + } + } + mat->AddProperty(&n, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index); + break; + } + } + // texture map properties + if (m->prop[j].type >= 128 && aiTxProps[k].pKey && + // extra check, should never happen, do we have the refered texture? + m->prop[j].value.textureid < m3d->numtexture && + m3d->texture[m->prop[j].value.textureid].name) { + name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png")); + mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index); + n = 0; + mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index); + } + } + mScene->mMaterials[i + 1] = mat; + } } // ------------------------------------------------------------------------------------------------ // import textures, this is the simplest of all -void M3DImporter::importTextures() -{ - unsigned int i; - m3dtx_t *t; +void M3DImporter::importTextures(const M3DWrapper &m3d) { + unsigned int i; + const char *formatHint[] = { + "rgba0800", + "rgba0808", + "rgba8880", + "rgba8888" + }; + m3dtx_t *t; - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); + ai_assert(mScene != nullptr); + ai_assert(m3d); - mScene->mNumTextures = m3d->numtexture; - ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures); + mScene->mNumTextures = m3d->numtexture; + ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures); - if(!m3d->numtexture) - return; + if (!m3d->numtexture || !m3d->texture) { + return; + } - mScene->mTextures = new aiTexture*[m3d->numtexture]; - for(i = 0; i < m3d->numtexture; i++) { - t = &m3d->texture[i]; - aiTexture *tx = new aiTexture; - strcpy(tx->achFormatHint, "rgba8888"); - tx->mFilename = aiString(std::string(t->name) + ".png"); - tx->mWidth = t->w; - tx->mHeight = t->h; - tx->pcData = new aiTexel[ tx->mWidth*tx->mHeight ]; - memcpy(tx->pcData, t->d, tx->mWidth*tx->mHeight*4); - mScene->mTextures[i] = tx; - } + mScene->mTextures = new aiTexture *[m3d->numtexture]; + for (i = 0; i < m3d->numtexture; i++) { + unsigned int j, k; + t = &m3d->texture[i]; + aiTexture *tx = new aiTexture; + tx->mFilename = aiString(std::string(t->name) + ".png"); + if (!t->w || !t->h || !t->f || !t->d) { + /* without ASSIMP_USE_M3D_READFILECB, we only have the filename, but no texture data ever */ + tx->mWidth = 0; + tx->mHeight = 0; + memcpy(tx->achFormatHint, "png\000", 4); + tx->pcData = nullptr; + } else { + /* if we have the texture loaded, set format hint and pcData too */ + tx->mWidth = t->w; + tx->mHeight = t->h; + strcpy(tx->achFormatHint, formatHint[t->f - 1]); + tx->pcData = new aiTexel[tx->mWidth * tx->mHeight]; + for (j = k = 0; j < tx->mWidth * tx->mHeight; j++) { + switch (t->f) { + case 1: tx->pcData[j].g = t->d[k++]; break; + case 2: + tx->pcData[j].g = t->d[k++]; + tx->pcData[j].a = t->d[k++]; + break; + case 3: + tx->pcData[j].r = t->d[k++]; + tx->pcData[j].g = t->d[k++]; + tx->pcData[j].b = t->d[k++]; + tx->pcData[j].a = 255; + break; + case 4: + tx->pcData[j].r = t->d[k++]; + tx->pcData[j].g = t->d[k++]; + tx->pcData[j].b = t->d[k++]; + tx->pcData[j].a = t->d[k++]; + break; + } + } + } + mScene->mTextures[i] = tx; + } } // ------------------------------------------------------------------------------------------------ // this is tricky. M3D has a global vertex and UV list, and faces are indexing them // individually. In assimp there're per mesh vertex and UV lists, and they must be // indexed simultaneously. -void M3DImporter::importMeshes() -{ - unsigned int i, j, k, l, numpoly = 3, lastMat = -2U; - std::vector *meshes = new std::vector(); - std::vector *faces = nullptr; - std::vector *vertices = nullptr; - std::vector *normals = nullptr; - std::vector *texcoords = nullptr; - std::vector *colors = nullptr; - std::vector *vertexids = nullptr; - aiMesh *pMesh = nullptr; +void M3DImporter::importMeshes(const M3DWrapper &m3d) { + ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface); - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); - ai_assert(mScene->mRootNode != nullptr); + if (!m3d->numface || !m3d->face || !m3d->numvertex || !m3d->vertex) { + return; + } - ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface); + unsigned int i, j, k, l, numpoly = 3, lastMat = M3D_INDEXMAX; + std::vector *meshes = new std::vector(); + std::vector *faces = nullptr; + std::vector *vertices = nullptr; + std::vector *normals = nullptr; + std::vector *texcoords = nullptr; + std::vector *colors = nullptr; + std::vector *vertexids = nullptr; + aiMesh *pMesh = nullptr; - for(i = 0; i < m3d->numface; i++) { - // we must switch mesh if material changes - if(lastMat != m3d->face[i].materialid) { - lastMat = m3d->face[i].materialid; - if(pMesh && vertices->size() && faces->size()) { - populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids); - meshes->push_back(pMesh); - delete vertexids; // this is not stored in pMesh, just to collect bone vertices - } - pMesh = new aiMesh; - pMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - pMesh->mMaterialIndex = lastMat + 1; - faces = new std::vector(); - vertices = new std::vector(); - normals = new std::vector(); - texcoords = new std::vector(); - colors = new std::vector(); - vertexids = new std::vector(); - } - // add a face to temporary vector - aiFace *pFace = new aiFace; - pFace->mNumIndices = numpoly; - pFace->mIndices = new unsigned int[numpoly]; - for(j = 0; j < numpoly; j++) { - aiVector3D pos, uv, norm; - k = vertices->size(); - pFace->mIndices[j] = k; - l = m3d->face[i].vertex[j]; - pos.x = m3d->vertex[l].x; - pos.y = m3d->vertex[l].y; - pos.z = m3d->vertex[l].z; - vertices->push_back(pos); - colors->push_back(mkColor(m3d->vertex[l].color)); - // add a bone to temporary vector - if(m3d->vertex[l].skinid != -1U &&m3d->vertex[l].skinid != -2U && m3d->skin && m3d->bone) { - // this is complicated, because M3D stores a list of bone id / weight pairs per - // vertex but assimp uses lists of local vertex id/weight pairs per local bone list - vertexids->push_back(l); - } - l = m3d->face[i].texcoord[j]; - if(l != -1U) { - uv.x = m3d->tmap[l].u; - uv.y = m3d->tmap[l].v; - uv.z = 0.0; - texcoords->push_back(uv); - } - l = m3d->face[i].normal[j]; - if(l != -1U) { - norm.x = m3d->vertex[l].x; - norm.y = m3d->vertex[l].y; - norm.z = m3d->vertex[l].z; - normals->push_back(norm); - } - } - faces->push_back(*pFace); - delete pFace; - } - // if there's data left in the temporary vectors, flush them - if(pMesh && vertices->size() && faces->size()) { - populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids); - meshes->push_back(pMesh); - } + ai_assert(mScene != nullptr); + ai_assert(m3d); + ai_assert(mScene->mRootNode != nullptr); - // create global mesh list in scene - mScene->mNumMeshes = meshes->size(); - mScene->mMeshes = new aiMesh*[mScene->mNumMeshes]; - std::copy(meshes->begin(), meshes->end(), mScene->mMeshes); - // create mesh indeces in root node - mScene->mRootNode->mNumMeshes = meshes->size(); - mScene->mRootNode->mMeshes = new unsigned int[meshes->size()]; - for(i = 0; i < meshes->size(); i++) { - mScene->mRootNode->mMeshes[i] = i; - } + for (i = 0; i < m3d->numface; i++) { + // we must switch mesh if material changes + if (lastMat != m3d->face[i].materialid) { + lastMat = m3d->face[i].materialid; + if (pMesh && vertices && vertices->size() && faces && faces->size()) { + populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids); + meshes->push_back(pMesh); + delete faces; + delete vertices; + delete normals; + delete texcoords; + delete colors; + delete vertexids; // this is not stored in pMesh, just to collect bone vertices + } + pMesh = new aiMesh; + pMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + pMesh->mMaterialIndex = lastMat + 1; + faces = new std::vector(); + vertices = new std::vector(); + normals = new std::vector(); + texcoords = new std::vector(); + colors = new std::vector(); + vertexids = new std::vector(); + } + // add a face to temporary vector + aiFace *pFace = new aiFace; + pFace->mNumIndices = numpoly; + pFace->mIndices = new unsigned int[numpoly]; + for (j = 0; j < numpoly; j++) { + aiVector3D pos, uv, norm; + k = static_cast(vertices->size()); + pFace->mIndices[j] = k; + l = m3d->face[i].vertex[j]; + if(l >= m3d->numvertex) continue; + pos.x = m3d->vertex[l].x; + pos.y = m3d->vertex[l].y; + pos.z = m3d->vertex[l].z; + vertices->push_back(pos); + colors->push_back(mkColor(m3d->vertex[l].color)); + // add a bone to temporary vector + if (m3d->vertex[l].skinid != M3D_UNDEF && m3d->vertex[l].skinid != M3D_INDEXMAX && m3d->skin && m3d->bone) { + // this is complicated, because M3D stores a list of bone id / weight pairs per + // vertex but assimp uses lists of local vertex id/weight pairs per local bone list + vertexids->push_back(l); + } + l = m3d->face[i].texcoord[j]; + if (l != M3D_UNDEF && l < m3d->numtmap) { + uv.x = m3d->tmap[l].u; + uv.y = m3d->tmap[l].v; + uv.z = 0.0; + texcoords->push_back(uv); + } + l = m3d->face[i].normal[j]; + if (l != M3D_UNDEF && l < m3d->numvertex) { + norm.x = m3d->vertex[l].x; + norm.y = m3d->vertex[l].y; + norm.z = m3d->vertex[l].z; + normals->push_back(norm); + } + } + faces->push_back(*pFace); + delete pFace; + } + // if there's data left in the temporary vectors, flush them + if (pMesh && vertices->size() && faces->size()) { + populateMesh(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids); + meshes->push_back(pMesh); + } - delete meshes; - if(faces) delete faces; - if(vertices) delete vertices; - if(normals) delete normals; - if(texcoords) delete texcoords; - if(colors) delete colors; - if(vertexids) delete vertexids; + // create global mesh list in scene + mScene->mNumMeshes = static_cast(meshes->size()); + mScene->mMeshes = new aiMesh *[mScene->mNumMeshes]; + std::copy(meshes->begin(), meshes->end(), mScene->mMeshes); + + // create mesh indeces in root node + mScene->mRootNode->mNumMeshes = static_cast(meshes->size()); + mScene->mRootNode->mMeshes = new unsigned int[meshes->size()]; + for (i = 0; i < meshes->size(); i++) { + mScene->mRootNode->mMeshes[i] = i; + } + + delete meshes; + if (faces) delete faces; + if (vertices) delete vertices; + if (normals) delete normals; + if (texcoords) delete texcoords; + if (colors) delete colors; + if (vertexids) delete vertexids; } // ------------------------------------------------------------------------------------------------ // a reentrant node parser. Otherwise this is simple -void M3DImporter::importBones(unsigned int parentid, aiNode *pParent) -{ - unsigned int i, n; +void M3DImporter::importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent) { + unsigned int i, n; - ai_assert(pParent != nullptr); - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); + ai_assert(pParent != nullptr); + ai_assert(mScene != nullptr); + ai_assert(m3d); - ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid); + ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid); - for(n = 0, i = parentid + 1; i < m3d->numbone; i++) - if(m3d->bone[i].parent == parentid) n++; - pParent->mChildren = new aiNode*[n]; + if (!m3d->numbone || !m3d->bone) { + return; + } - for(i = parentid + 1; i < m3d->numbone; i++) { - if(m3d->bone[i].parent == parentid) { - aiNode *pChild = new aiNode; - pChild->mParent = pParent; - pChild->mName = aiString(std::string(m3d->bone[i].name)); - convertPose(&pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori); - pChild->mNumChildren = 0; - pParent->mChildren[pParent->mNumChildren] = pChild; - pParent->mNumChildren++; - importBones(i, pChild); - } - } + for (n = 0, i = parentid + 1; i < m3d->numbone; i++) { + if (m3d->bone[i].parent == parentid) { + n++; + } + } + pParent->mChildren = new aiNode *[n]; + + for (i = parentid + 1; i < m3d->numbone; i++) { + if (m3d->bone[i].parent == parentid) { + aiNode *pChild = new aiNode; + pChild->mParent = pParent; + pChild->mName = aiString(std::string(m3d->bone[i].name)); + convertPose(m3d, &pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori); + pChild->mNumChildren = 0; + pParent->mChildren[pParent->mNumChildren] = pChild; + pParent->mNumChildren++; + importBones(m3d, i, pChild); + } + } } // ------------------------------------------------------------------------------------------------ // this is another headache. M3D stores list of changed bone id/position/orientation triplets and // a timestamp per frame, but assimp needs timestamp and lists of position, orientation lists per // bone, so we have to convert between the two conceptually different representation forms -void M3DImporter::importAnimations() -{ - unsigned int i, j, k, l, pos, ori; - double t; - m3da_t *a; +void M3DImporter::importAnimations(const M3DWrapper &m3d) { + unsigned int i, j, k, l, pos, ori; + double t; + m3da_t *a; - ai_assert(mScene != nullptr); - ai_assert(m3d != nullptr); + ai_assert(mScene != nullptr); + ai_assert(m3d); - mScene->mNumAnimations = m3d->numaction; + mScene->mNumAnimations = m3d->numaction; - ASSIMP_LOG_DEBUG_F("M3D: importAnimations ", mScene->mNumAnimations); + ASSIMP_LOG_DEBUG_F("M3D: importAnimations ", mScene->mNumAnimations); - if(!m3d->numaction || !m3d->numbone) - return; + if (!m3d->numaction || !m3d->action || !m3d->numbone || !m3d->bone || !m3d->vertex) { + return; + } - mScene->mAnimations = new aiAnimation*[m3d->numaction]; - for(i = 0; i < m3d->numaction; i++) { - a = &m3d->action[i]; - aiAnimation *pAnim = new aiAnimation; - pAnim->mName = aiString(std::string(a->name)); - pAnim->mDuration = ((double)a->durationmsec) / 10; - pAnim->mTicksPerSecond = 100; - // now we know how many bones are referenced in this animation - pAnim->mNumChannels = m3d->numbone; - pAnim->mChannels = new aiNodeAnim*[pAnim->mNumChannels]; - for(l = 0; l < m3d->numbone; l++) { - unsigned int n; - pAnim->mChannels[l] = new aiNodeAnim; - pAnim->mChannels[l]->mNodeName = aiString(std::string(m3d->bone[l].name)); - // now n is the size of positions / orientations arrays - pAnim->mChannels[l]->mNumPositionKeys = pAnim->mChannels[l]->mNumRotationKeys = a->numframe; - pAnim->mChannels[l]->mPositionKeys = new aiVectorKey[a->numframe]; - pAnim->mChannels[l]->mRotationKeys = new aiQuatKey[a->numframe]; - pos = m3d->bone[l].pos; - ori = m3d->bone[l].ori; - for(j = n = 0; j < a->numframe; j++) { - t = ((double)a->frame[j].msec) / 10; - for(k = 0; k < a->frame[j].numtransform; k++) { - if(a->frame[j].transform[k].boneid == l) { - pos = a->frame[j].transform[k].pos; - ori = a->frame[j].transform[k].ori; - } - } - m3dv_t *v = &m3d->vertex[pos]; - m3dv_t *q = &m3d->vertex[ori]; - pAnim->mChannels[l]->mPositionKeys[j].mTime = t; - pAnim->mChannels[l]->mPositionKeys[j].mValue.x = v->x; - pAnim->mChannels[l]->mPositionKeys[j].mValue.y = v->y; - pAnim->mChannels[l]->mPositionKeys[j].mValue.z = v->z; - pAnim->mChannels[l]->mRotationKeys[j].mTime = t; - pAnim->mChannels[l]->mRotationKeys[j].mValue.w = q->w; - pAnim->mChannels[l]->mRotationKeys[j].mValue.x = q->x; - pAnim->mChannels[l]->mRotationKeys[j].mValue.y = q->y; - pAnim->mChannels[l]->mRotationKeys[j].mValue.z = q->z; - }// foreach frame - }// foreach bones - mScene->mAnimations[i] = pAnim; - } + mScene->mAnimations = new aiAnimation *[m3d->numaction]; + for (i = 0; i < m3d->numaction; i++) { + a = &m3d->action[i]; + aiAnimation *pAnim = new aiAnimation; + pAnim->mName = aiString(std::string(a->name)); + pAnim->mDuration = ((double)a->durationmsec) / 10; + pAnim->mTicksPerSecond = 100; + // now we know how many bones are referenced in this animation + pAnim->mNumChannels = m3d->numbone; + pAnim->mChannels = new aiNodeAnim *[pAnim->mNumChannels]; + for (l = 0; l < m3d->numbone; l++) { + unsigned int n; + pAnim->mChannels[l] = new aiNodeAnim; + pAnim->mChannels[l]->mNodeName = aiString(std::string(m3d->bone[l].name)); + // now n is the size of positions / orientations arrays + pAnim->mChannels[l]->mNumPositionKeys = pAnim->mChannels[l]->mNumRotationKeys = a->numframe; + pAnim->mChannels[l]->mPositionKeys = new aiVectorKey[a->numframe]; + pAnim->mChannels[l]->mRotationKeys = new aiQuatKey[a->numframe]; + pos = m3d->bone[l].pos; + ori = m3d->bone[l].ori; + for (j = n = 0; j < a->numframe; j++) { + t = ((double)a->frame[j].msec) / 10; + for (k = 0; k < a->frame[j].numtransform; k++) { + if (a->frame[j].transform[k].boneid == l) { + pos = a->frame[j].transform[k].pos; + ori = a->frame[j].transform[k].ori; + } + } + if(pos >= m3d->numvertex || ori >= m3d->numvertex) continue; + m3dv_t *v = &m3d->vertex[pos]; + m3dv_t *q = &m3d->vertex[ori]; + pAnim->mChannels[l]->mPositionKeys[j].mTime = t; + pAnim->mChannels[l]->mPositionKeys[j].mValue.x = v->x; + pAnim->mChannels[l]->mPositionKeys[j].mValue.y = v->y; + pAnim->mChannels[l]->mPositionKeys[j].mValue.z = v->z; + pAnim->mChannels[l]->mRotationKeys[j].mTime = t; + pAnim->mChannels[l]->mRotationKeys[j].mValue.w = q->w; + pAnim->mChannels[l]->mRotationKeys[j].mValue.x = q->x; + pAnim->mChannels[l]->mRotationKeys[j].mValue.y = q->y; + pAnim->mChannels[l]->mRotationKeys[j].mValue.z = q->z; + } // foreach frame + } // foreach bones + mScene->mAnimations[i] = pAnim; + } } // ------------------------------------------------------------------------------------------------ // convert uint32_t into aiColor4D aiColor4D M3DImporter::mkColor(uint32_t c) { - aiColor4D color; - color.a = ((float)((c >> 24)&0xff)) / 255; - color.b = ((float)((c >> 16)&0xff)) / 255; - color.g = ((float)((c >> 8)&0xff)) / 255; - color.r = ((float)((c >> 0)&0xff)) / 255; - return color; + aiColor4D color; + color.a = ((float)((c >> 24) & 0xff)) / 255; + color.b = ((float)((c >> 16) & 0xff)) / 255; + color.g = ((float)((c >> 8) & 0xff)) / 255; + color.r = ((float)((c >> 0) & 0xff)) / 255; + return color; } // ------------------------------------------------------------------------------------------------ // convert a position id and orientation id into a 4 x 4 transformation matrix -void M3DImporter::convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) -{ - ai_assert(m != nullptr); - ai_assert(m3d != nullptr); - ai_assert(posid != -1U && posid < m3d->numvertex); - ai_assert(orientid != -1U && orientid < m3d->numvertex); - m3dv_t *p = &m3d->vertex[posid]; - m3dv_t *q = &m3d->vertex[orientid]; +void M3DImporter::convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) { + ai_assert(m != nullptr); + ai_assert(m3d); + ai_assert(posid != M3D_UNDEF && posid < m3d->numvertex); + ai_assert(orientid != M3D_UNDEF && orientid < m3d->numvertex); + if (!m3d->numvertex || !m3d->vertex) + return; + m3dv_t *p = &m3d->vertex[posid]; + m3dv_t *q = &m3d->vertex[orientid]; - /* quaternion to matrix. Do NOT use aiQuaternion to aiMatrix3x3, gives bad results */ - if(q->x == 0.0 && q->y == 0.0 && q->z >= 0.7071065 && q->z <= 0.7071075 && q->w == 0.0) { - m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0; - m->a1 = m->b2 = m->c3 = -1.0; - } else { - m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); if(m->a1 > -1e-7 && m->a1 < 1e-7) m->a1 = 0.0; - m->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -1e-7 && m->a2 < 1e-7) m->a2 = 0.0; - m->a3 = 2 * (q->x * q->z + q->y * q->w); if(m->a3 > -1e-7 && m->a3 < 1e-7) m->a3 = 0.0; - m->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -1e-7 && m->b1 < 1e-7) m->b1 = 0.0; - m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); if(m->b2 > -1e-7 && m->b2 < 1e-7) m->b2 = 0.0; - m->b3 = 2 * (q->y * q->z - q->x * q->w); if(m->b3 > -1e-7 && m->b3 < 1e-7) m->b3 = 0.0; - m->c1 = 2 * (q->x * q->z - q->y * q->w); if(m->c1 > -1e-7 && m->c1 < 1e-7) m->c1 = 0.0; - m->c2 = 2 * (q->y * q->z + q->x * q->w); if(m->c2 > -1e-7 && m->c2 < 1e-7) m->c2 = 0.0; - m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); if(m->c3 > -1e-7 && m->c3 < 1e-7) m->c3 = 0.0; - } + /* quaternion to matrix. Do NOT use aiQuaternion to aiMatrix3x3, gives bad results */ + if (q->x == 0.0 && q->y == 0.0 && q->z >= 0.7071065 && q->z <= 0.7071075 && q->w == 0.0) { + m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0; + m->a1 = m->b2 = m->c3 = -1.0; + } else { + m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); + if (m->a1 > -M3D_EPSILON && m->a1 < M3D_EPSILON) m->a1 = 0.0; + m->a2 = 2 * (q->x * q->y - q->z * q->w); + if (m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 0.0; + m->a3 = 2 * (q->x * q->z + q->y * q->w); + if (m->a3 > -M3D_EPSILON && m->a3 < M3D_EPSILON) m->a3 = 0.0; + m->b1 = 2 * (q->x * q->y + q->z * q->w); + if (m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 0.0; + m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); + if (m->b2 > -M3D_EPSILON && m->b2 < M3D_EPSILON) m->b2 = 0.0; + m->b3 = 2 * (q->y * q->z - q->x * q->w); + if (m->b3 > -M3D_EPSILON && m->b3 < M3D_EPSILON) m->b3 = 0.0; + m->c1 = 2 * (q->x * q->z - q->y * q->w); + if (m->c1 > -M3D_EPSILON && m->c1 < M3D_EPSILON) m->c1 = 0.0; + m->c2 = 2 * (q->y * q->z + q->x * q->w); + if (m->c2 > -M3D_EPSILON && m->c2 < M3D_EPSILON) m->c2 = 0.0; + m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); + if (m->c3 > -M3D_EPSILON && m->c3 < M3D_EPSILON) m->c3 = 0.0; + } - /* set translation */ - m->a4 = p->x; m->b4 = p->y; m->c4 = p->z; + /* set translation */ + m->a4 = p->x; + m->b4 = p->y; + m->c4 = p->z; - m->d1 = 0; m->d2 = 0; m->d3 = 0; m->d4 = 1; + m->d1 = 0; + m->d2 = 0; + m->d3 = 0; + m->d4 = 1; } // ------------------------------------------------------------------------------------------------ // find a node by name -aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) -{ - unsigned int i; +aiNode *M3DImporter::findNode(aiNode *pNode, aiString name) { + ai_assert(pNode != nullptr); + ai_assert(mScene != nullptr); - ai_assert(pNode != nullptr); - ai_assert(mScene != nullptr); + if (pNode->mName == name) { + return pNode; + } - if(pNode->mName == name) - return pNode; - for(i = 0; i < pNode->mNumChildren; i++) { - aiNode *pChild = findNode(pNode->mChildren[i], name); - if(pChild) return pChild; - } - return nullptr; + for (unsigned int i = 0; i < pNode->mNumChildren; i++) { + aiNode *pChild = findNode(pNode->mChildren[i], name); + if (pChild) { + return pChild; + } + } + return nullptr; } // ------------------------------------------------------------------------------------------------ // fills up offsetmatrix in mBones -void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m) -{ - ai_assert(pNode != nullptr); - ai_assert(mScene != nullptr); +void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m) { + ai_assert(pNode != nullptr); + ai_assert(mScene != nullptr); - if(pNode->mParent) { - calculateOffsetMatrix(pNode->mParent, m); - *m *= pNode->mTransformation; - } else { - *m = pNode->mTransformation; - } + if (pNode->mParent) { + calculateOffsetMatrix(pNode->mParent, m); + *m *= pNode->mTransformation; + } else { + *m = pNode->mTransformation; + } } // ------------------------------------------------------------------------------------------------ // because M3D has a global mesh, global vertex ids and stores materialid on the face, we need // temporary lists to collect data for an aiMesh, which requires local arrays and local indeces // this function fills up an aiMesh with those temporary lists -void M3DImporter::populateMesh(aiMesh *pMesh, std::vector *faces, std::vector *vertices, - std::vector *normals, std::vector *texcoords, std::vector *colors, - std::vector *vertexids) { +void M3DImporter::populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector *faces, std::vector *vertices, + std::vector *normals, std::vector *texcoords, std::vector *colors, + std::vector *vertexids) { - ai_assert(pMesh != nullptr); - ai_assert(faces != nullptr); - ai_assert(vertices != nullptr); - ai_assert(normals != nullptr); - ai_assert(texcoords != nullptr); - ai_assert(colors != nullptr); - ai_assert(vertexids != nullptr); - ai_assert(m3d != nullptr); + ai_assert(pMesh != nullptr); + ai_assert(faces != nullptr); + ai_assert(vertices != nullptr); + ai_assert(normals != nullptr); + ai_assert(texcoords != nullptr); + ai_assert(colors != nullptr); + ai_assert(vertexids != nullptr); + ai_assert(m3d); - ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(), - " numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone); + ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(), + " numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone); - if(vertices->size() && faces->size()) { - pMesh->mNumFaces = faces->size(); - pMesh->mFaces = new aiFace[pMesh->mNumFaces]; - std::copy(faces->begin(), faces->end(), pMesh->mFaces); - pMesh->mNumVertices = vertices->size(); - pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; - std::copy(vertices->begin(), vertices->end(), pMesh->mVertices); - if(normals->size() == vertices->size()) { - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - std::copy(normals->begin(), normals->end(), pMesh->mNormals); - } - if(texcoords->size() == vertices->size()) { - pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices]; - std::copy(texcoords->begin(), texcoords->end(), pMesh->mTextureCoords[0]); - pMesh->mNumUVComponents[0] = 2; - } - if(colors->size() == vertices->size()) { - pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices]; - std::copy(colors->begin(), colors->end(), pMesh->mColors[0]); - } - // this is complicated, because M3D stores a list of bone id / weight pairs per - // vertex but assimp uses lists of local vertex id/weight pairs per local bone list - pMesh->mNumBones = m3d->numbone; - /* we need aiBone with mOffsetMatrix for bones without weights as well */ - if(pMesh->mNumBones) { - pMesh->mBones = new aiBone*[pMesh->mNumBones]; - for(unsigned int i = 0; i < m3d->numbone; i++) { - aiNode *pNode; - pMesh->mBones[i] = new aiBone; - pMesh->mBones[i]->mName = aiString(std::string(m3d->bone[i].name)); - pMesh->mBones[i]->mNumWeights = 0; - pNode = findNode(mScene->mRootNode, pMesh->mBones[i]->mName); - if(pNode) { - calculateOffsetMatrix(pNode, &pMesh->mBones[i]->mOffsetMatrix); - pMesh->mBones[i]->mOffsetMatrix.Inverse(); - } else - pMesh->mBones[i]->mOffsetMatrix = aiMatrix4x4(); - } - if(vertexids->size()) { - unsigned int i, j; - // first count how many vertices we have per bone - for(i = 0; i < vertexids->size(); i++) { - unsigned int s = m3d->vertex[vertexids->at(i)].skinid; - if(s != -1U && s!= -2U) { - for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { - aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); - for(j = 0; j < pMesh->mNumBones; j++) { - if(pMesh->mBones[j]->mName == name) { - pMesh->mBones[j]->mNumWeights++; - break; - } - } - } - } - } - // allocate mWeights - for(j = 0; j < pMesh->mNumBones; j++) { - aiBone *pBone = pMesh->mBones[j]; - if(pBone->mNumWeights) { - pBone->mWeights = new aiVertexWeight[pBone->mNumWeights]; - pBone->mNumWeights = 0; - } - } - // fill up with data - for(i = 0; i < vertexids->size(); i++) { - unsigned int s = m3d->vertex[vertexids->at(i)].skinid; - if(s != -1U && s!= -2U) { - for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { - aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); - for(j = 0; j < pMesh->mNumBones; j++) { - if(pMesh->mBones[j]->mName == name) { - aiBone *pBone = pMesh->mBones[j]; - pBone->mWeights[pBone->mNumWeights].mVertexId = i; - pBone->mWeights[pBone->mNumWeights].mWeight = m3d->skin[s].weight[k]; - pBone->mNumWeights++; - break; - } - } - } // foreach skin - } - } // foreach vertexids - } - } - } + if (vertices->size() && faces->size()) { + pMesh->mNumFaces = static_cast(faces->size()); + pMesh->mFaces = new aiFace[pMesh->mNumFaces]; + std::copy(faces->begin(), faces->end(), pMesh->mFaces); + pMesh->mNumVertices = static_cast(vertices->size()); + pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; + std::copy(vertices->begin(), vertices->end(), pMesh->mVertices); + if (normals->size() == vertices->size()) { + pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; + std::copy(normals->begin(), normals->end(), pMesh->mNormals); + } + if (texcoords->size() == vertices->size()) { + pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices]; + std::copy(texcoords->begin(), texcoords->end(), pMesh->mTextureCoords[0]); + pMesh->mNumUVComponents[0] = 2; + } + if (colors->size() == vertices->size()) { + pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices]; + std::copy(colors->begin(), colors->end(), pMesh->mColors[0]); + } + // this is complicated, because M3D stores a list of bone id / weight pairs per + // vertex but assimp uses lists of local vertex id/weight pairs per local bone list + pMesh->mNumBones = m3d->numbone; + // we need aiBone with mOffsetMatrix for bones without weights as well + if (pMesh->mNumBones && m3d->numbone && m3d->bone) { + pMesh->mBones = new aiBone *[pMesh->mNumBones]; + for (unsigned int i = 0; i < m3d->numbone; i++) { + aiNode *pNode; + pMesh->mBones[i] = new aiBone; + pMesh->mBones[i]->mName = aiString(std::string(m3d->bone[i].name)); + pMesh->mBones[i]->mNumWeights = 0; + pNode = findNode(mScene->mRootNode, pMesh->mBones[i]->mName); + if (pNode) { + calculateOffsetMatrix(pNode, &pMesh->mBones[i]->mOffsetMatrix); + pMesh->mBones[i]->mOffsetMatrix.Inverse(); + } else + pMesh->mBones[i]->mOffsetMatrix = aiMatrix4x4(); + } + if (vertexids->size() && m3d->numvertex && m3d->vertex && m3d->numskin && m3d->skin) { + unsigned int i, j; + // first count how many vertices we have per bone + for (i = 0; i < vertexids->size(); i++) { + if(vertexids->at(i) >= m3d->numvertex) { + continue; + } + unsigned int s = m3d->vertex[vertexids->at(i)].skinid; + if (s != M3D_UNDEF && s != M3D_INDEXMAX) { + for (unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { + aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); + for (j = 0; j < pMesh->mNumBones; j++) { + if (pMesh->mBones[j]->mName == name) { + pMesh->mBones[j]->mNumWeights++; + break; + } + } + } + } + } + // allocate mWeights + for (j = 0; j < pMesh->mNumBones; j++) { + aiBone *pBone = pMesh->mBones[j]; + if (pBone->mNumWeights) { + pBone->mWeights = new aiVertexWeight[pBone->mNumWeights]; + pBone->mNumWeights = 0; + } + } + // fill up with data + for (i = 0; i < vertexids->size(); i++) { + if(vertexids->at(i) >= m3d->numvertex) continue; + unsigned int s = m3d->vertex[vertexids->at(i)].skinid; + if (s != M3D_UNDEF && s != M3D_INDEXMAX && s < m3d->numskin) { + for (unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) { + if(m3d->skin[s].boneid[k] >= m3d->numbone) continue; + aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name)); + for (j = 0; j < pMesh->mNumBones; j++) { + if (pMesh->mBones[j]->mName == name) { + aiBone *pBone = pMesh->mBones[j]; + pBone->mWeights[pBone->mNumWeights].mVertexId = i; + pBone->mWeights[pBone->mNumWeights].mWeight = m3d->skin[s].weight[k]; + pBone->mNumWeights++; + break; + } + } + } // foreach skin + } + } // foreach vertexids + } + } + } } // ------------------------------------------------------------------------------------------------ -} // Namespace Assimp +} // Namespace Assimp #endif // !! ASSIMP_BUILD_NO_M3D_IMPORTER diff --git a/Engine/lib/assimp/code/M3D/M3DImporter.h b/Engine/lib/assimp/code/M3D/M3DImporter.h index 06cc757b6..5c9d4fad8 100644 --- a/Engine/lib/assimp/code/M3D/M3DImporter.h +++ b/Engine/lib/assimp/code/M3D/M3DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -48,7 +48,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER -#include "m3d.h" #include #include #include @@ -60,43 +59,41 @@ struct aiFace; namespace Assimp { +class M3DWrapper; + class M3DImporter : public BaseImporter { public: - /// \brief Default constructor - M3DImporter(); - - /// \brief Destructor - ~M3DImporter(); + /// \brief Default constructor + M3DImporter(); public: - /// \brief Returns whether the class can handle the format of the given file. - /// \remark See BaseImporter::CanRead() for details. - bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; + /// \brief Returns whether the class can handle the format of the given file. + /// \remark See BaseImporter::CanRead() for details. + bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const; private: - aiScene* mScene; // the scene to import to - m3d_t *m3d; // model for the C library to convert from + aiScene *mScene = nullptr; // the scene to import to - //! \brief Appends the supported extension. - const aiImporterDesc* GetInfo () const; + //! \brief Appends the supported extension. + const aiImporterDesc *GetInfo() const; - //! \brief File import implementation. - void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + //! \brief File import implementation. + void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler); - void importMaterials(); - void importTextures(); - void importMeshes(); - void importBones(unsigned int parentid, aiNode *pParent); - void importAnimations(); + void importMaterials(const M3DWrapper &m3d); + void importTextures(const M3DWrapper &m3d); + void importMeshes(const M3DWrapper &m3d); + void importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent); + void importAnimations(const M3DWrapper &m3d); - // helper functions - aiColor4D mkColor(uint32_t c); - void convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid); - aiNode *findNode(aiNode *pNode, aiString name); - void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m); - void populateMesh(aiMesh *pMesh, std::vector *faces, std::vector *verteces, - std::vector *normals, std::vector *texcoords, std::vector *colors, - std::vector *vertexids); + // helper functions + aiColor4D mkColor(uint32_t c); + void convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid); + aiNode *findNode(aiNode *pNode, aiString name); + void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m); + void populateMesh(const M3DWrapper &m3d, aiMesh *pMesh, std::vector *faces, std::vector *verteces, + std::vector *normals, std::vector *texcoords, std::vector *colors, + std::vector *vertexids); }; } // Namespace Assimp diff --git a/Engine/lib/assimp/code/M3D/M3DMaterials.h b/Engine/lib/assimp/code/M3D/M3DMaterials.h index fa02cf42b..469ddf52b 100644 --- a/Engine/lib/assimp/code/M3D/M3DMaterials.h +++ b/Engine/lib/assimp/code/M3D/M3DMaterials.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team Copyright (c) 2019 bzt All rights reserved. @@ -75,7 +75,7 @@ static const aiMatProp aiProps[] = { { AI_MATKEY_REFLECTIVITY }, /* m3dp_Pm */ { NULL, 0, 0 }, /* m3dp_Ps */ { AI_MATKEY_REFRACTI }, /* m3dp_Ni */ - { NULL, 0, 0 }, + { NULL, 0, 0 }, /* m3dp_Nt */ { NULL, 0, 0 }, { NULL, 0, 0 }, { NULL, 0, 0 } @@ -84,20 +84,20 @@ static const aiMatProp aiProps[] = { /* --- Texture Map Properties --- !!!!! must match m3d_propertytypes !!!!! */ static const aiMatProp aiTxProps[] = { { AI_MATKEY_TEXTURE_DIFFUSE(0) }, /* m3dp_map_Kd */ - { AI_MATKEY_TEXTURE_AMBIENT(0) }, /* m3dp_map_Ka */ + { AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION,0) },/* m3dp_map_Ka */ { AI_MATKEY_TEXTURE_SPECULAR(0) }, /* m3dp_map_Ks */ { AI_MATKEY_TEXTURE_SHININESS(0) }, /* m3dp_map_Ns */ { AI_MATKEY_TEXTURE_EMISSIVE(0) }, /* m3dp_map_Ke */ { NULL, 0, 0 }, /* m3dp_map_Tf */ { AI_MATKEY_TEXTURE_HEIGHT(0) }, /* m3dp_bump */ { AI_MATKEY_TEXTURE_OPACITY(0) }, /* m3dp_map_d */ - { AI_MATKEY_TEXTURE_REFLECTION(0) }, /* m3dp_refl */ + { AI_MATKEY_TEXTURE_NORMALS(0) }, /* m3dp_map_N */ { AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE_ROUGHNESS,0) },/* m3dp_map_Pr */ { AI_MATKEY_TEXTURE(aiTextureType_METALNESS,0) }, /* m3dp_map_Pm */ { NULL, 0, 0 }, /* m3dp_map_Ps */ - { AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION,0) },/* m3dp_map_Ni */ - { NULL, 0, 0 }, + { AI_MATKEY_TEXTURE(aiTextureType_REFLECTION,0) }, /* m3dp_map_Ni */ + { NULL, 0, 0 }, /* m3dp_map_Nt */ { NULL, 0, 0 }, { NULL, 0, 0 }, { NULL, 0, 0 } diff --git a/Engine/lib/assimp/code/M3D/M3DWrapper.cpp b/Engine/lib/assimp/code/M3D/M3DWrapper.cpp new file mode 100644 index 000000000..6ab59b2f0 --- /dev/null +++ b/Engine/lib/assimp/code/M3D/M3DWrapper.cpp @@ -0,0 +1,142 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team +Copyright (c) 2019 bzt + +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. + +---------------------------------------------------------------------- +*/ + +#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER + +#include "M3DWrapper.h" + +#include +#include +#include + +#ifdef ASSIMP_USE_M3D_READFILECB + +# if (__cplusplus >= 201103L) || !defined(_MSC_VER) || (_MSC_VER >= 1900) // C++11 and MSVC 2015 onwards +# define threadlocal thread_local +# else +# if defined(_MSC_VER) && (_MSC_VER >= 1800) // there's an alternative for MSVC 2013 +# define threadlocal __declspec(thread) +# else +# define threadlocal +# endif +# endif + +extern "C" { + +// workaround: the M3D SDK expects a C callback, but we want to use Assimp::IOSystem to implement that +threadlocal void *m3dimporter_pIOHandler; + +unsigned char *m3dimporter_readfile(char *fn, unsigned int *size) { + ai_assert(nullptr != fn); + ai_assert(nullptr != size); + std::string file(fn); + std::unique_ptr pStream( + (reinterpret_cast(m3dimporter_pIOHandler))->Open(file, "rb")); + size_t fileSize = 0; + unsigned char *data = NULL; + // sometimes pStream is nullptr in a single-threaded scenario too for some reason + // (should be an empty object returning nothing I guess) + if (pStream) { + fileSize = pStream->FileSize(); + // should be allocated with malloc(), because the library will call free() to deallocate + data = (unsigned char *)malloc(fileSize); + if (!data || !pStream.get() || !fileSize || fileSize != pStream->Read(data, 1, fileSize)) { + pStream.reset(); + *size = 0; + // don't throw a deadly exception, it's not fatal if we can't read an external asset + return nullptr; + } + pStream.reset(); + } + *size = (int)fileSize; + return data; +} +} +#endif + +namespace Assimp { +M3DWrapper::M3DWrapper() { + // use malloc() here because m3d_free() will call free() + m3d_ = (m3d_t *)calloc(1, sizeof(m3d_t)); +} + +M3DWrapper::M3DWrapper(IOSystem *pIOHandler, const std::vector &buffer) { +#ifdef ASSIMP_USE_M3D_READFILECB + // pass this IOHandler to the C callback in a thread-local pointer + m3dimporter_pIOHandler = pIOHandler; + m3d_ = m3d_load(const_cast(buffer.data()), m3dimporter_readfile, free, nullptr); + // Clear the C callback + m3dimporter_pIOHandler = nullptr; +#else + m3d_ = m3d_load(const_cast(buffer.data()), nullptr, nullptr, nullptr); +#endif +} + +M3DWrapper::~M3DWrapper() { + reset(); +} + +void M3DWrapper::reset() { + ClearSave(); + if (m3d_) + m3d_free(m3d_); + m3d_ = nullptr; +} + +unsigned char *M3DWrapper::Save(int quality, int flags, unsigned int &size) { +#if (!(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER)) + ClearSave(); + saved_output_ = m3d_save(m3d_, quality, flags, &size); + return saved_output_; +#else + return nullptr; +#endif +} + +void M3DWrapper::ClearSave() { + if (saved_output_) + M3D_FREE(saved_output_); + saved_output_ = nullptr; +} +} // namespace Assimp + +#endif diff --git a/Engine/lib/assimp/code/M3D/M3DWrapper.h b/Engine/lib/assimp/code/M3D/M3DWrapper.h new file mode 100644 index 000000000..bf3ab7bc9 --- /dev/null +++ b/Engine/lib/assimp/code/M3D/M3DWrapper.h @@ -0,0 +1,101 @@ +#pragma once +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team +Copyright (c) 2019 bzt + +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 M3DWrapper.h +* @brief Declares a class to wrap the C m3d SDK +*/ +#ifndef AI_M3DWRAPPER_H_INC +#define AI_M3DWRAPPER_H_INC +#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER + +#include +#include +#include + +// Assimp specific M3D configuration. Comment out these defines to remove functionality +//#define ASSIMP_USE_M3D_READFILECB +//#define M3D_ASCII + +#include "m3d.h" + +namespace Assimp { +class IOSystem; + +class M3DWrapper { + m3d_t *m3d_ = nullptr; + unsigned char *saved_output_ = nullptr; + +public: + // Construct an empty M3D model + explicit M3DWrapper(); + + // Construct an M3D model from provided buffer + // NOTE: The m3d.h SDK function does not mark the data as const. Have assumed it does not write. + // BUG: SECURITY: The m3d.h SDK cannot be informed of the buffer size. BUFFER OVERFLOW IS CERTAIN + explicit M3DWrapper(IOSystem *pIOHandler, const std::vector &buffer); + + ~M3DWrapper(); + + void reset(); + + // Name + inline std::string Name() const { + if (m3d_) return std::string(m3d_->name); + return std::string(); + } + + // Execute a save + unsigned char *Save(int quality, int flags, unsigned int &size); + void ClearSave(); + + inline explicit operator bool() const { return m3d_ != nullptr; } + + // Allow direct access to M3D API + inline m3d_t *operator->() const { return m3d_; } + inline m3d_t *M3D() const { return m3d_; } +}; +} // namespace Assimp + +#endif + +#endif // AI_M3DWRAPPER_H_INC diff --git a/Engine/lib/assimp/code/M3D/m3d.h b/Engine/lib/assimp/code/M3D/m3d.h index 9ace802ef..d09348497 100644 --- a/Engine/lib/assimp/code/M3D/m3d.h +++ b/Engine/lib/assimp/code/M3D/m3d.h @@ -58,16 +58,26 @@ extern "C" { #define M3D_APIVERSION 0x0100 #ifndef M3D_DOUBLE typedef float M3D_FLOAT; +#ifndef M3D_EPSILON +/* carefully choosen for IEEE 754 don't change */ +#define M3D_EPSILON ((M3D_FLOAT)1e-7) +#endif #else typedef double M3D_FLOAT; +#ifndef M3D_EPSILON +#define M3D_EPSILON ((M3D_FLOAT)1e-14) +#endif #endif #if !defined(M3D_SMALLINDEX) typedef uint32_t M3D_INDEX; +#define M3D_UNDEF 0xffffffff #define M3D_INDEXMAX 0xfffffffe #else typedef uint16_t M3D_INDEX; +#define M3D_UNDEF 0xffff #define M3D_INDEXMAX 0xfffe #endif +#define M3D_NOTDEFINED 0xffffffff #ifndef M3D_NUMBONE #define M3D_NUMBONE 4 #endif @@ -81,7 +91,7 @@ typedef uint16_t M3D_INDEX; #else #define _inline #define _pack -#define _unused +#define _unused __pragma(warning(suppress:4100)) #endif #ifndef __cplusplus #define _register register @@ -96,23 +106,35 @@ typedef uint16_t M3D_INDEX; * 3DMO m3dchunk_t file header chunk, may followed by compressed data * HEAD m3dhdr_t model header chunk * n x m3dchunk_t more chunks follow + * PRVW preview chunk (optional) * CMAP color map chunk (optional) * TMAP texture map chunk (optional) * VRTS vertex data chunk (optional if it's a material library) * BONE bind-pose skeleton, bone hierarchy chunk (optional) * n x m3db_t contains propably more, but at least one bone + * n x m3ds_t skin group records * MTRL* material chunk(s), can be more (optional) * n x m3dp_t each material contains propapbly more, but at least one property * the properties are configurable with a static array, see m3d_propertytypes * n x m3dchunk_t at least one, but maybe more face chunks * PROC* procedural face, or - * MESH* triangle mesh (vertex index list) + * MESH* triangle mesh (vertex index list) or + * SHPE* mathematical shapes like parameterized surfaces + * LBLS* annotation label chunks, can be more (optional) * ACTN* action chunk(s), animation-pose skeletons, can be more (optional) * n x m3dfr_t each action contains probably more, but at least one frame * n x m3dtr_t each frame contains probably more, but at least one transformation * ASET* inlined asset chunk(s), can be more (optional) * OMD3 end chunk + * + * Typical chunks for a game engine: 3DMO, HEAD, CMAP, TMAP, VRTS, BONE, MTRL, MESH, ACTN, OMD3 + * Typical chunks for CAD software: 3DMO, HEAD, PRVW, CMAP, TMAP, VRTS, MTRL, SHPE, LBLS, OMD3 */ +#ifdef _MSC_VER +#pragma pack(push) +#pragma pack(1) +#endif + typedef struct { char magic[4]; uint32_t length; @@ -125,6 +147,10 @@ typedef struct { uint32_t length; } _pack m3dchunk_t; +#ifdef _MSC_VER +#pragma pack(pop) +#endif + /*** in-memory model structure ***/ /* textmap entry */ @@ -132,19 +158,23 @@ typedef struct { M3D_FLOAT u; M3D_FLOAT v; } m3dti_t; +#define m3d_textureindex_t m3dti_t /* texture */ typedef struct { char *name; /* texture name */ - uint32_t *d; /* pixels data */ + uint8_t *d; /* pixels data */ uint16_t w; /* width */ uint16_t h; /* height */ -} _pack m3dtx_t; + uint8_t f; /* format, 1 = grayscale, 2 = grayscale+alpha, 3 = rgb, 4 = rgba */ +} m3dtx_t; +#define m3d_texturedata_t m3dtx_t typedef struct { M3D_INDEX vertexid; M3D_FLOAT weight; } m3dw_t; +#define m3d_weight_t m3dw_t /* bone entry */ typedef struct { @@ -156,12 +186,14 @@ typedef struct { m3dw_t *weight; /* weights for those vertices */ M3D_FLOAT mat4[16]; /* transformation matrix */ } m3db_t; +#define m3d_bone_t m3db_t /* skin: bone per vertex entry */ typedef struct { M3D_INDEX boneid[M3D_NUMBONE]; M3D_FLOAT weight[M3D_NUMBONE]; } m3ds_t; +#define m3d_skin_t m3ds_t /* vertex entry */ typedef struct { @@ -171,7 +203,11 @@ typedef struct { M3D_FLOAT w; uint32_t color; /* default vertex color */ M3D_INDEX skinid; /* skin index */ +#ifdef M3D_VERTEXTYPE + uint8_t type; +#endif } m3dv_t; +#define m3d_vertex_t m3dv_t /* material property formats */ enum { @@ -210,6 +246,7 @@ enum { m3dp_Pm, m3dp_Ps, m3dp_Ni, + m3dp_Nt, m3dp_map_Kd = 128, /* textured display map properties */ m3dp_map_Ka, @@ -219,15 +256,17 @@ enum { m3dp_map_Tf, m3dp_map_Km, /* bump map */ m3dp_map_D, - m3dp_map_il, /* reflection map */ + m3dp_map_N, /* normal map */ m3dp_map_Pr = 192, /* textured physical map properties */ m3dp_map_Pm, m3dp_map_Ps, - m3dp_map_Ni + m3dp_map_Ni, + m3dp_map_Nt }; enum { /* aliases */ m3dp_bump = m3dp_map_Km, + m3dp_map_il = m3dp_map_N, m3dp_refl = m3dp_map_Pm }; @@ -241,6 +280,7 @@ typedef struct { M3D_INDEX textureid; /* if value is a texture, m3dpf_map */ } value; } m3dp_t; +#define m3d_property_t m3dp_t /* material entry */ typedef struct { @@ -248,6 +288,7 @@ typedef struct { uint8_t numprop; /* number of properties */ m3dp_t *prop; /* properties array */ } m3dm_t; +#define m3d_material_t m3dm_t /* face entry */ typedef struct { @@ -256,6 +297,108 @@ typedef struct { M3D_INDEX normal[3]; /* normal vectors */ M3D_INDEX texcoord[3]; /* UV coordinates */ } m3df_t; +#define m3d_face_t m3df_t + +/* shape command types. must match the row in m3d_commandtypes */ +enum { + /* special commands */ + m3dc_use = 0, /* use material */ + m3dc_inc, /* include another shape */ + m3dc_mesh, /* include part of polygon mesh */ + /* approximations */ + m3dc_div, /* subdivision by constant resolution for both u, v */ + m3dc_sub, /* subdivision by constant, different for u and v */ + m3dc_len, /* spacial subdivision by maxlength */ + m3dc_dist, /* subdivision by maxdistance and maxangle */ + /* modifiers */ + m3dc_degu, /* degree for both u, v */ + m3dc_deg, /* separate degree for u and v */ + m3dc_rangeu, /* range for u */ + m3dc_range, /* range for u and v */ + m3dc_paru, /* u parameters (knots) */ + m3dc_parv, /* v parameters */ + m3dc_trim, /* outer trimming curve */ + m3dc_hole, /* inner trimming curve */ + m3dc_scrv, /* spacial curve */ + m3dc_sp, /* special points */ + /* helper curves */ + m3dc_bez1, /* Bezier 1D */ + m3dc_bsp1, /* B-spline 1D */ + m3dc_bez2, /* bezier 2D */ + m3dc_bsp2, /* B-spline 2D */ + /* surfaces */ + m3dc_bezun, /* Bezier 3D with control, UV, normal */ + m3dc_bezu, /* with control and UV */ + m3dc_bezn, /* with control and normal */ + m3dc_bez, /* control points only */ + m3dc_nurbsun, /* B-spline 3D */ + m3dc_nurbsu, + m3dc_nurbsn, + m3dc_nurbs, + m3dc_conn, /* connect surfaces */ + /* geometrical */ + m3dc_line, + m3dc_polygon, + m3dc_circle, + m3dc_cylinder, + m3dc_shpere, + m3dc_torus, + m3dc_cone, + m3dc_cube +}; + +/* shape command argument types */ +enum { + m3dcp_mi_t = 1, /* material index */ + m3dcp_hi_t, /* shape index */ + m3dcp_fi_t, /* face index */ + m3dcp_ti_t, /* texture map index */ + m3dcp_vi_t, /* vertex index */ + m3dcp_qi_t, /* vertex index for quaternions */ + m3dcp_vc_t, /* coordinate or radius, float scalar */ + m3dcp_i1_t, /* int8 scalar */ + m3dcp_i2_t, /* int16 scalar */ + m3dcp_i4_t, /* int32 scalar */ + m3dcp_va_t /* variadic arguments */ +}; + +#define M3D_CMDMAXARG 8 /* if you increase this, add more arguments to the macro below */ +typedef struct { +#ifdef M3D_ASCII +#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (char*)(n), (p), { (a), (b), (c), (d), (e), (f), (g), (h) } } + char *key; +#else +#define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (p), { (a), (b), (c), (d), (e), (f), (g), (h) } } +#endif + uint8_t p; + uint8_t a[M3D_CMDMAXARG]; +} m3dcd_t; + +/* shape command */ +typedef struct { + uint16_t type; /* shape type */ + uint32_t *arg; /* arguments array */ +} m3dc_t; +#define m3d_shapecommand_t m3dc_t + +/* shape entry */ +typedef struct { + char *name; /* name of the mathematical shape */ + M3D_INDEX group; /* group this shape belongs to or -1 */ + uint32_t numcmd; /* number of commands */ + m3dc_t *cmd; /* commands array */ +} m3dh_t; +#define m3d_shape_t m3dh_t + +/* label entry */ +typedef struct { + char *name; /* name of the annotation layer or NULL */ + char *lang; /* language code or NULL */ + char *text; /* the label text */ + uint32_t color; /* color */ + M3D_INDEX vertexid; /* the vertex the label refers to */ +} m3dl_t; +#define m3d_label_t m3dl_t /* frame transformations / working copy skeleton entry */ typedef struct { @@ -263,6 +406,7 @@ typedef struct { M3D_INDEX pos; /* vertex index new position */ M3D_INDEX ori; /* vertex index new orientation (quaternion) */ } m3dtr_t; +#define m3d_transform_t m3dtr_t /* animation frame entry */ typedef struct { @@ -270,6 +414,7 @@ typedef struct { M3D_INDEX numtransform; /* number of transformations in this frame */ m3dtr_t *transform; /* transformations */ } m3dfr_t; +#define m3d_frame_t m3dfr_t /* model action entry */ typedef struct { @@ -278,6 +423,7 @@ typedef struct { M3D_INDEX numframe; /* number of frames in this animation */ m3dfr_t *frame; /* frames array */ } m3da_t; +#define m3d_action_t m3da_t /* inlined asset */ typedef struct { @@ -285,17 +431,19 @@ typedef struct { uint8_t *data; /* compressed asset data */ uint32_t length; /* compressed data length */ } m3di_t; +#define m3d_inlinedasset_t m3di_t /*** in-memory model structure ***/ #define M3D_FLG_FREERAW (1<<0) #define M3D_FLG_FREESTR (1<<1) #define M3D_FLG_MTLLIB (1<<2) +#define M3D_FLG_GENNORM (1<<3) typedef struct { m3dhdr_t *raw; /* pointer to raw data */ char flags; /* internal flags */ - char errcode; /* returned error code */ - char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fi_s; /* decoded sizes for types */ + signed char errcode; /* returned error code */ + char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s,fi_s; /* decoded sizes for types */ char *name; /* name of the model, like "Utah teapot" */ char *license; /* usage condition or license, like "MIT", "LGPL" or "BSD-3clause" */ char *author; /* nickname, email, homepage or github URL etc. */ @@ -316,13 +464,18 @@ typedef struct { M3D_INDEX nummaterial; m3dm_t *material; /* material list */ M3D_INDEX numface; - m3df_t *face; /* model face, triangle mesh */ + m3df_t *face; /* model face, polygon (triangle) mesh */ + M3D_INDEX numshape; + m3dh_t *shape; /* model face, shape commands */ + M3D_INDEX numlabel; + m3dl_t *label; /* annotation labels */ M3D_INDEX numaction; m3da_t *action; /* action animations */ M3D_INDEX numinlined; m3di_t *inlined; /* inlined assets */ - M3D_INDEX numunknown; - m3dchunk_t **unknown; /* unknown chunks, application / engine specific data probably */ + M3D_INDEX numextra; + m3dchunk_t **extra; /* unknown chunks, application / engine specific data probably */ + m3di_t preview; /* preview chunk */ } m3d_t; /*** export parameters ***/ @@ -355,12 +508,14 @@ typedef struct { #define M3D_ERR_UNKMESH -67 #define M3D_ERR_UNKIMG -68 #define M3D_ERR_UNKFRAME -69 -#define M3D_ERR_TRUNC -70 -#define M3D_ERR_CMAP -71 -#define M3D_ERR_TMAP -72 -#define M3D_ERR_VRTS -73 -#define M3D_ERR_BONE -74 -#define M3D_ERR_MTRL -75 +#define M3D_ERR_UNKCMD -70 +#define M3D_ERR_TRUNC -71 +#define M3D_ERR_CMAP -72 +#define M3D_ERR_TMAP -73 +#define M3D_ERR_VRTS -74 +#define M3D_ERR_BONE -75 +#define M3D_ERR_MTRL -76 +#define M3D_ERR_SHPE -77 #define M3D_ERR_ISFATAL(x) ((x) < 0 && (x) > -65) @@ -381,8 +536,6 @@ m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec); /* private prototypes used by both importer and exporter */ -m3ds_t *_m3d_addskin(m3ds_t *skin, uint32_t *numskin, m3ds_t *s, uint32_t *idx); -m3dv_t *_m3d_addnorm(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx); char *_m3d_safestr(char *in, int morelines); /*** C implementation ***/ @@ -404,11 +557,60 @@ static m3dpd_t m3d_propertytypes[] = { M3D_PROPERTYDEF(m3dpf_float, m3dp_Pm, "Pm"), /* metallic, also reflection */ M3D_PROPERTYDEF(m3dpf_float, m3dp_Ps, "Ps"), /* sheen */ M3D_PROPERTYDEF(m3dpf_float, m3dp_Ni, "Ni"), /* index of refraction (optical density) */ + M3D_PROPERTYDEF(m3dpf_float, m3dp_Nt, "Nt"), /* thickness of face in millimeter, for printing */ /* aliases, note that "map_*" aliases are handled automatically */ M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Km, "bump"), + M3D_PROPERTYDEF(m3dpf_map, m3dp_map_N, "map_N"),/* as normal map has no scalar version, it's counterpart is 'il' */ M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Pm, "refl") }; +/* shape command definitions. if more commands start with the same string, the longer must come first */ +static m3dcd_t m3d_commandtypes[] = { + /* technical */ + M3D_CMDDEF(m3dc_use, "use", 1, m3dcp_mi_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_inc, "inc", 3, m3dcp_hi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_mesh, "mesh", 1, m3dcp_fi_t, m3dcp_fi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0), + /* approximations */ + M3D_CMDDEF(m3dc_div, "div", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_sub, "sub", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_len, "len", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_dist, "dist", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + /* modifiers */ + M3D_CMDDEF(m3dc_degu, "degu", 1, m3dcp_i1_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_deg, "deg", 2, m3dcp_i1_t, m3dcp_i1_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_rangeu, "rangeu", 1, m3dcp_ti_t, 0, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_range, "range", 2, m3dcp_ti_t, m3dcp_ti_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_paru, "paru", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_parv, "parv", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_trim, "trim", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_hole, "hole", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_scrv, "scrv", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_sp, "sp", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + /* helper curves */ + M3D_CMDDEF(m3dc_bez1, "bez1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bsp1, "bsp1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bez2, "bez2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bsp2, "bsp2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + /* surfaces */ + M3D_CMDDEF(m3dc_bezun, "bezun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bezu, "bezu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bezn, "bezn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_bez, "bez", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_nurbsun, "nurbsun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_nurbsu, "nurbsu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_nurbsn, "nurbsn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_nurbs, "nurbs", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_conn, "conn", 6, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0), + /* geometrical */ + M3D_CMDDEF(m3dc_line, "line", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_polygon, "polygon", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_circle, "circle", 3, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_cylinder,"cylinder",6, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0), + M3D_CMDDEF(m3dc_shpere, "shpere", 2, m3dcp_vi_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_torus, "torus", 4, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_cone, "cone", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0), + M3D_CMDDEF(m3dc_cube, "cube", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0) +}; #endif #include @@ -419,7 +621,7 @@ static m3dpd_t m3d_propertytypes[] = { stb_image - v2.23 - public domain image loader - http://nothings.org/stb_image.h */ -static const char *stbi__g_failure_reason; +static const char *_m3dstbi__g_failure_reason; enum { @@ -438,57 +640,56 @@ enum STBI__SCAN_header }; -typedef unsigned char stbi_uc; -typedef unsigned short stbi_us; +typedef unsigned short _m3dstbi_us; -typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; -typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; +typedef uint16_t _m3dstbi__uint16; +typedef int16_t _m3dstbi__int16; +typedef uint32_t _m3dstbi__uint32; +typedef int32_t _m3dstbi__int32; typedef struct { - stbi__uint32 img_x, img_y; + _m3dstbi__uint32 img_x, img_y; int img_n, img_out_n; void *io_user_data; int read_from_callbacks; int buflen; - stbi_uc buffer_start[128]; + unsigned char buffer_start[128]; - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original, *img_buffer_original_end; -} stbi__context; + unsigned char *img_buffer, *img_buffer_end; + unsigned char *img_buffer_original, *img_buffer_original_end; +} _m3dstbi__context; typedef struct { int bits_per_channel; int num_channels; int channel_order; -} stbi__result_info; +} _m3dstbi__result_info; #define STBI_ASSERT(v) #define STBI_NOTUSED(v) (void)sizeof(v) -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) +#define STBI__BYTECAST(x) ((unsigned char) ((x) & 255)) #define STBI_MALLOC(sz) M3D_MALLOC(sz) #define STBI_REALLOC(p,newsz) M3D_REALLOC(p,newsz) #define STBI_FREE(p) M3D_FREE(p) #define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) -_inline static stbi_uc stbi__get8(stbi__context *s) +_inline static unsigned char _m3dstbi__get8(_m3dstbi__context *s) { if (s->img_buffer < s->img_buffer_end) return *s->img_buffer++; return 0; } -_inline static int stbi__at_eof(stbi__context *s) +_inline static int _m3dstbi__at_eof(_m3dstbi__context *s) { return s->img_buffer >= s->img_buffer_end; } -static void stbi__skip(stbi__context *s, int n) +static void _m3dstbi__skip(_m3dstbi__context *s, int n) { if (n < 0) { s->img_buffer = s->img_buffer_end; @@ -497,7 +698,7 @@ static void stbi__skip(stbi__context *s, int n) s->img_buffer += n; } -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +static int _m3dstbi__getn(_m3dstbi__context *s, unsigned char *buffer, int n) { if (s->img_buffer+n <= s->img_buffer_end) { memcpy(buffer, s->img_buffer, n); @@ -507,72 +708,72 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) return 0; } -static int stbi__get16be(stbi__context *s) +static int _m3dstbi__get16be(_m3dstbi__context *s) { - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); + int z = _m3dstbi__get8(s); + return (z << 8) + _m3dstbi__get8(s); } -static stbi__uint32 stbi__get32be(stbi__context *s) +static _m3dstbi__uint32 _m3dstbi__get32be(_m3dstbi__context *s) { - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); + _m3dstbi__uint32 z = _m3dstbi__get16be(s); + return (z << 16) + _m3dstbi__get16be(s); } -#define stbi__err(x,y) stbi__errstr(y) -static int stbi__errstr(const char *str) +#define _m3dstbi__err(x,y) _m3dstbi__errstr(y) +static int _m3dstbi__errstr(const char *str) { - stbi__g_failure_reason = str; + _m3dstbi__g_failure_reason = str; return 0; } -_inline static void *stbi__malloc(size_t size) +_inline static void *_m3dstbi__malloc(size_t size) { return STBI_MALLOC(size); } -static int stbi__addsizes_valid(int a, int b) +static int _m3dstbi__addsizes_valid(int a, int b) { if (b < 0) return 0; return a <= 2147483647 - b; } -static int stbi__mul2sizes_valid(int a, int b) +static int _m3dstbi__mul2sizes_valid(int a, int b) { if (a < 0 || b < 0) return 0; if (b == 0) return 1; return a <= 2147483647/b; } -static int stbi__mad2sizes_valid(int a, int b, int add) +static int _m3dstbi__mad2sizes_valid(int a, int b, int add) { - return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); + return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__addsizes_valid(a*b, add); } -static int stbi__mad3sizes_valid(int a, int b, int c, int add) +static int _m3dstbi__mad3sizes_valid(int a, int b, int c, int add) { - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__addsizes_valid(a*b*c, add); + return _m3dstbi__mul2sizes_valid(a, b) && _m3dstbi__mul2sizes_valid(a*b, c) && + _m3dstbi__addsizes_valid(a*b*c, add); } -static void *stbi__malloc_mad2(int a, int b, int add) +static void *_m3dstbi__malloc_mad2(int a, int b, int add) { - if (!stbi__mad2sizes_valid(a, b, add)) return NULL; - return stbi__malloc(a*b + add); + if (!_m3dstbi__mad2sizes_valid(a, b, add)) return NULL; + return _m3dstbi__malloc(a*b + add); } -static void *stbi__malloc_mad3(int a, int b, int c, int add) +static void *_m3dstbi__malloc_mad3(int a, int b, int c, int add) { - if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; - return stbi__malloc(a*b*c + add); + if (!_m3dstbi__mad3sizes_valid(a, b, c, add)) return NULL; + return _m3dstbi__malloc(a*b*c + add); } -static stbi_uc stbi__compute_y(int r, int g, int b) +static unsigned char _m3dstbi__compute_y(int r, int g, int b) { - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); + return (unsigned char) (((r*77) + (g*150) + (29*b)) >> 8); } -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +static unsigned char *_m3dstbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; unsigned char *good; @@ -580,10 +781,10 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r if (req_comp == img_n) return data; STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + good = (unsigned char *) _m3dstbi__malloc_mad3(req_comp, x, y, 0); if (good == NULL) { STBI_FREE(data); - stbi__err("outofmem", "Out of memory"); + _m3dstbi__err("outofmem", "Out of memory"); return NULL; } @@ -601,10 +802,10 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; default: STBI_ASSERT(0); } @@ -615,29 +816,29 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r return good; } -static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +static _m3dstbi__uint16 _m3dstbi__compute_y_16(int r, int g, int b) { - return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); + return (_m3dstbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); } -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +static _m3dstbi__uint16 *_m3dstbi__convert_format16(_m3dstbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; - stbi__uint16 *good; + _m3dstbi__uint16 *good; if (req_comp == img_n) return data; STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + good = (_m3dstbi__uint16 *) _m3dstbi__malloc(req_comp * x * y * 2); if (good == NULL) { STBI_FREE(data); - stbi__err("outofmem", "Out of memory"); + _m3dstbi__err("outofmem", "Out of memory"); return NULL; } for (j=0; j < (int) y; ++j) { - stbi__uint16 *src = data + j * x * img_n ; - stbi__uint16 *dest = good + j * x * req_comp; + _m3dstbi__uint16 *src = data + j * x * img_n ; + _m3dstbi__uint16 *dest = good + j * x * req_comp; #define STBI__COMBO(a,b) ((a)*8+(b)) #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) @@ -649,10 +850,10 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; + STBI__CASE(3,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=_m3dstbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; default: STBI_ASSERT(0); } @@ -668,15 +869,15 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r typedef struct { - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; + _m3dstbi__uint16 fast[1 << STBI__ZFAST_BITS]; + _m3dstbi__uint16 firstcode[16]; int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; -} stbi__zhuffman; + _m3dstbi__uint16 firstsymbol[16]; + unsigned char size[288]; + _m3dstbi__uint16 value[288]; +} _m3dstbi__zhuffman; -_inline static int stbi__bitreverse16(int n) +_inline static int _m3dstbi__bitreverse16(int n) { n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); @@ -685,13 +886,13 @@ _inline static int stbi__bitreverse16(int n) return n; } -_inline static int stbi__bit_reverse(int v, int bits) +_inline static int _m3dstbi__bit_reverse(int v, int bits) { STBI_ASSERT(bits <= 16); - return stbi__bitreverse16(v) >> (16-bits); + return _m3dstbi__bitreverse16(v) >> (16-bits); } -static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) +static int _m3dstbi__zbuild_huffman(_m3dstbi__zhuffman *z, unsigned char *sizelist, int num) { int i,k=0; int code, next_code[16], sizes[17]; @@ -703,15 +904,15 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) sizes[0] = 0; for (i=1; i < 16; ++i) if (sizes[i] > (1 << i)) - return stbi__err("bad sizes", "Corrupt PNG"); + return _m3dstbi__err("bad sizes", "Corrupt PNG"); code = 0; for (i=1; i < 16; ++i) { next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; + z->firstcode[i] = (_m3dstbi__uint16) code; + z->firstsymbol[i] = (_m3dstbi__uint16) k; code = (code + sizes[i]); if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + if (code-1 >= (1 << i)) return _m3dstbi__err("bad codelengths","Corrupt PNG"); z->maxcode[i] = code << (16-i); code <<= 1; k += sizes[i]; @@ -721,11 +922,11 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) int s = sizelist[i]; if (s) { int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; + _m3dstbi__uint16 fastv = (_m3dstbi__uint16) ((s << 9) | i); + z->size [c] = (unsigned char ) s; + z->value[c] = (_m3dstbi__uint16) i; if (s <= STBI__ZFAST_BITS) { - int j = stbi__bit_reverse(next_code[s],s); + int j = _m3dstbi__bit_reverse(next_code[s],s); while (j < (1 << STBI__ZFAST_BITS)) { z->fast[j] = fastv; j += (1 << s); @@ -739,47 +940,47 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) typedef struct { - stbi_uc *zbuffer, *zbuffer_end; + unsigned char *zbuffer, *zbuffer_end; int num_bits; - stbi__uint32 code_buffer; + _m3dstbi__uint32 code_buffer; char *zout; char *zout_start; char *zout_end; int z_expandable; - stbi__zhuffman z_length, z_distance; -} stbi__zbuf; + _m3dstbi__zhuffman z_length, z_distance; +} _m3dstbi__zbuf; -_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +_inline static unsigned char _m3dstbi__zget8(_m3dstbi__zbuf *z) { if (z->zbuffer >= z->zbuffer_end) return 0; return *z->zbuffer++; } -static void stbi__fill_bits(stbi__zbuf *z) +static void _m3dstbi__fill_bits(_m3dstbi__zbuf *z) { do { STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->code_buffer |= (unsigned int) _m3dstbi__zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); } -_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +_inline static unsigned int _m3dstbi__zreceive(_m3dstbi__zbuf *z, int n) { unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); + if (z->num_bits < n) _m3dstbi__fill_bits(z); k = z->code_buffer & ((1 << n) - 1); z->code_buffer >>= n; z->num_bits -= n; return k; } -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +static int _m3dstbi__zhuffman_decode_slowpath(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z) { int b,s,k; - k = stbi__bit_reverse(a->code_buffer, 16); + k = _m3dstbi__bit_reverse(a->code_buffer, 16); for (s=STBI__ZFAST_BITS+1; ; ++s) if (k < z->maxcode[s]) break; @@ -791,10 +992,10 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) return z->value[b]; } -_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +_inline static int _m3dstbi__zhuffman_decode(_m3dstbi__zbuf *a, _m3dstbi__zhuffman *z) { int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); + if (a->num_bits < 16) _m3dstbi__fill_bits(a); b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { s = b >> 9; @@ -802,76 +1003,76 @@ _inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) a->num_bits -= s; return b & 511; } - return stbi__zhuffman_decode_slowpath(a, z); + return _m3dstbi__zhuffman_decode_slowpath(a, z); } -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) +static int _m3dstbi__zexpand(_m3dstbi__zbuf *z, char *zout, int n) { char *q; int cur, limit, old_limit; z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + if (!z->z_expandable) return _m3dstbi__err("output buffer limit","Corrupt PNG"); cur = (int) (z->zout - z->zout_start); limit = old_limit = (int) (z->zout_end - z->zout_start); while (cur + n > limit) limit *= 2; q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); STBI_NOTUSED(old_limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); + if (q == NULL) return _m3dstbi__err("outofmem", "Out of memory"); z->zout_start = q; z->zout = q + cur; z->zout_end = q + limit; return 1; } -static int stbi__zlength_base[31] = { +static int _m3dstbi__zlength_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; -static int stbi__zlength_extra[31]= +static int _m3dstbi__zlength_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; -static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +static int _m3dstbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; -static int stbi__zdist_extra[32] = +static int _m3dstbi__zdist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; -static int stbi__parse_huffman_block(stbi__zbuf *a) +static int _m3dstbi__parse_huffman_block(_m3dstbi__zbuf *a) { char *zout = a->zout; for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); + int z = _m3dstbi__zhuffman_decode(a, &a->z_length); if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG"); if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; + if (!_m3dstbi__zexpand(a, zout, 1)) return 0; zout = a->zout; } *zout++ = (char) z; } else { - stbi_uc *p; + unsigned char *p; int len,dist; if (z == 256) { a->zout = zout; return 1; } z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + len = _m3dstbi__zlength_base[z]; + if (_m3dstbi__zlength_extra[z]) len += _m3dstbi__zreceive(a, _m3dstbi__zlength_extra[z]); + z = _m3dstbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return _m3dstbi__err("bad huffman code","Corrupt PNG"); + dist = _m3dstbi__zdist_base[z]; + if (_m3dstbi__zdist_extra[z]) dist += _m3dstbi__zreceive(a, _m3dstbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return _m3dstbi__err("bad dist","Corrupt PNG"); if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; + if (!_m3dstbi__zexpand(a, zout, len)) return 0; zout = a->zout; } - p = (stbi_uc *) (zout - dist); + p = (unsigned char *) (zout - dist); if (dist == 1) { - stbi_uc v = *p; + unsigned char v = *p; if (len) { do *zout++ = v; while (--len); } } else { if (len) { do *zout++ = *p++; while (--len); } @@ -880,152 +1081,151 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) } } -static int stbi__compute_huffman_codes(stbi__zbuf *a) +static int _m3dstbi__compute_huffman_codes(_m3dstbi__zbuf *a) { - static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137]; - stbi_uc codelength_sizes[19]; + static unsigned char length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + _m3dstbi__zhuffman z_codelength; + unsigned char lencodes[286+32+137]; + unsigned char codelength_sizes[19]; int i,n; - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; + int hlit = _m3dstbi__zreceive(a,5) + 257; + int hdist = _m3dstbi__zreceive(a,5) + 1; + int hclen = _m3dstbi__zreceive(a,4) + 4; int ntot = hlit + hdist; memset(codelength_sizes, 0, sizeof(codelength_sizes)); for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + int s = _m3dstbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (unsigned char) s; } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + if (!_m3dstbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; n = 0; while (n < ntot) { - int c = stbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + int c = _m3dstbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); if (c < 16) - lencodes[n++] = (stbi_uc) c; + lencodes[n++] = (unsigned char) c; else { - stbi_uc fill = 0; + unsigned char fill = 0; if (c == 16) { - c = stbi__zreceive(a,2)+3; - if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + c = _m3dstbi__zreceive(a,2)+3; + if (n == 0) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); fill = lencodes[n-1]; } else if (c == 17) - c = stbi__zreceive(a,3)+3; + c = _m3dstbi__zreceive(a,3)+3; else { STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; + c = _m3dstbi__zreceive(a,7)+11; } - if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + if (ntot - n < c) return _m3dstbi__err("bad codelengths", "Corrupt PNG"); memset(lencodes+n, fill, c); n += c; } } - if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + if (n != ntot) return _m3dstbi__err("bad codelengths","Corrupt PNG"); + if (!_m3dstbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!_m3dstbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; return 1; } -_inline static int stbi__parse_uncompressed_block(stbi__zbuf *a) +_inline static int _m3dstbi__parse_uncompressed_block(_m3dstbi__zbuf *a) { - stbi_uc header[4]; + unsigned char header[4]; int len,nlen,k; if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); + _m3dstbi__zreceive(a, a->num_bits & 7); k = 0; while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); + header[k++] = (unsigned char) (a->code_buffer & 255); a->code_buffer >>= 8; a->num_bits -= 8; } STBI_ASSERT(a->num_bits == 0); while (k < 4) - header[k++] = stbi__zget8(a); + header[k++] = _m3dstbi__zget8(a); len = header[1] * 256 + header[0]; nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (nlen != (len ^ 0xffff)) return _m3dstbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return _m3dstbi__err("read past buffer","Corrupt PNG"); if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; + if (!_m3dstbi__zexpand(a, a->zout, len)) return 0; memcpy(a->zout, a->zbuffer, len); a->zbuffer += len; a->zout += len; return 1; } -static int stbi__parse_zlib_header(stbi__zbuf *a) +static int _m3dstbi__parse_zlib_header(_m3dstbi__zbuf *a) { - int cmf = stbi__zget8(a); + int cmf = _m3dstbi__zget8(a); int cm = cmf & 15; /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); + int flg = _m3dstbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return _m3dstbi__err("bad zlib header","Corrupt PNG"); + if (flg & 32) return _m3dstbi__err("no preset dict","Corrupt PNG"); + if (cm != 8) return _m3dstbi__err("bad compression","Corrupt PNG"); return 1; } -static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; -static void stbi__init_zdefaults(void) +static unsigned char _m3dstbi__zdefault_length[288], _m3dstbi__zdefault_distance[32]; +static void _m3dstbi__init_zdefaults(void) { int i; - for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; - for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; - for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; - for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + for (i=0; i <= 143; ++i) _m3dstbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) _m3dstbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) _m3dstbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) _m3dstbi__zdefault_length[i] = 8; - for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; + for (i=0; i <= 31; ++i) _m3dstbi__zdefault_distance[i] = 5; } -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +static int _m3dstbi__parse_zlib(_m3dstbi__zbuf *a, int parse_header) { int final, type; if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; + if (!_m3dstbi__parse_zlib_header(a)) return 0; a->num_bits = 0; a->code_buffer = 0; do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); + final = _m3dstbi__zreceive(a,1); + type = _m3dstbi__zreceive(a,2); if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) return 0; + if (!_m3dstbi__parse_uncompressed_block(a)) return 0; } else if (type == 3) { return 0; } else { if (type == 1) { - if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + if (!_m3dstbi__zbuild_huffman(&a->z_length , _m3dstbi__zdefault_length , 288)) return 0; + if (!_m3dstbi__zbuild_huffman(&a->z_distance, _m3dstbi__zdefault_distance, 32)) return 0; } else { - if (!stbi__compute_huffman_codes(a)) return 0; + if (!_m3dstbi__compute_huffman_codes(a)) return 0; } - if (!stbi__parse_huffman_block(a)) return 0; + if (!_m3dstbi__parse_huffman_block(a)) return 0; } } while (!final); return 1; } -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +static int _m3dstbi__do_zlib(_m3dstbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) { a->zout_start = obuf; a->zout = obuf; a->zout_end = obuf + olen; a->z_expandable = exp; - - return stbi__parse_zlib(a, parse_header); + _m3dstbi__init_zdefaults(); + return _m3dstbi__parse_zlib(a, parse_header); } -char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +char *_m3dstbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) { - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); + _m3dstbi__zbuf a; + char *p = (char *) _m3dstbi__malloc(initial_size); if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + a.zbuffer = (unsigned char *) buffer; + a.zbuffer_end = (unsigned char *) buffer + len; + if (_m3dstbi__do_zlib(&a, p, initial_size, 1, parse_header)) { if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { @@ -1036,33 +1236,33 @@ char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, typedef struct { - stbi__uint32 length; - stbi__uint32 type; -} stbi__pngchunk; + _m3dstbi__uint32 length; + _m3dstbi__uint32 type; +} _m3dstbi__pngchunk; -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +static _m3dstbi__pngchunk _m3dstbi__get_chunk_header(_m3dstbi__context *s) { - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); + _m3dstbi__pngchunk c; + c.length = _m3dstbi__get32be(s); + c.type = _m3dstbi__get32be(s); return c; } -_inline static int stbi__check_png_header(stbi__context *s) +_inline static int _m3dstbi__check_png_header(_m3dstbi__context *s) { - static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + static unsigned char png_sig[8] = { 137,80,78,71,13,10,26,10 }; int i; for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + if (_m3dstbi__get8(s) != png_sig[i]) return _m3dstbi__err("bad png sig","Not a PNG"); return 1; } typedef struct { - stbi__context *s; - stbi_uc *idata, *expanded, *out; + _m3dstbi__context *s; + unsigned char *idata, *expanded, *out; int depth; -} stbi__png; +} _m3dstbi__png; enum { @@ -1075,7 +1275,7 @@ enum { STBI__F_paeth_first }; -static stbi_uc first_row_filter[5] = +static unsigned char first_row_filter[5] = { STBI__F_none, STBI__F_sub, @@ -1084,7 +1284,7 @@ static stbi_uc first_row_filter[5] = STBI__F_paeth_first }; -static int stbi__paeth(int a, int b, int c) +static int _m3dstbi__paeth(int a, int b, int c) { int p = a + b - c; int pa = abs(p-a); @@ -1095,14 +1295,14 @@ static int stbi__paeth(int a, int b, int c) return c; } -static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +static unsigned char _m3dstbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +static int _m3dstbi__create_png_image_raw(_m3dstbi__png *a, unsigned char *raw, _m3dstbi__uint32 raw_len, int out_n, _m3dstbi__uint32 x, _m3dstbi__uint32 y, int depth, int color) { int bytes = (depth == 16? 2 : 1); - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n*bytes; - stbi__uint32 img_len, img_width_bytes; + _m3dstbi__context *s = a->s; + _m3dstbi__uint32 i,j,stride = x*out_n*bytes; + _m3dstbi__uint32 img_len, img_width_bytes; int k; int img_n = s->img_n; @@ -1111,24 +1311,25 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r int width = x; STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); - if (!a->out) return stbi__err("outofmem", "Out of memory"); + a->out = (unsigned char *) _m3dstbi__malloc_mad3(x, y, output_bytes, 0); + if (!a->out) return _m3dstbi__err("outofmem", "Out of memory"); + if (!_m3dstbi__mad3sizes_valid(img_n, x, depth, 7)) return _m3dstbi__err("too large", "Corrupt PNG"); img_width_bytes = (((img_n * x * depth) + 7) >> 3); img_len = (img_width_bytes + 1) * y; if (s->img_x == x && s->img_y == y) { - if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); + if (raw_len != img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG"); } else { - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + if (raw_len < img_len) return _m3dstbi__err("not enough pixels","Corrupt PNG"); } for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior = cur - stride; + unsigned char *cur = a->out + stride*j; + unsigned char *prior = cur - stride; int filter = *raw++; if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); + return _m3dstbi__err("invalid filter","Corrupt PNG"); if (depth < 8) { STBI_ASSERT(img_width_bytes <= x); @@ -1136,6 +1337,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r filter_bytes = 1; width = img_width_bytes; } + prior = cur - stride; if (j == 0) filter = first_row_filter[filter]; @@ -1145,7 +1347,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r case STBI__F_sub : cur[k] = raw[k]; break; case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(0,prior[k],0)); break; case STBI__F_avg_first : cur[k] = raw[k]; break; case STBI__F_paeth_first: cur[k] = raw[k]; break; } @@ -1181,9 +1383,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k-filter_bytes],0,0)); } break; } #undef STBI__CASE raw += nk; @@ -1198,9 +1400,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + _m3dstbi__paeth(cur[k- output_bytes],0,0)); } break; } #undef STBI__CASE @@ -1215,9 +1417,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r if (depth < 8) { for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; + unsigned char *cur = a->out + stride*j; + unsigned char *in = a->out + stride*j + x*out_n - img_width_bytes; + unsigned char scale = (color == 0) ? _m3dstbi__depth_scale_table[depth] : 1; if (depth == 4) { for (k=x*img_n; k >= 2; k-=2, ++in) { @@ -1274,8 +1476,8 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r } } } else if (depth == 16) { - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; + unsigned char *cur = a->out; + _m3dstbi__uint16 *cur16 = (_m3dstbi__uint16*)cur; for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { *cur16 = (cur[0] << 8) | cur[1]; @@ -1285,16 +1487,16 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r return 1; } -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +static int _m3dstbi__create_png_image(_m3dstbi__png *a, unsigned char *image_data, _m3dstbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) { int bytes = (depth == 16 ? 2 : 1); int out_bytes = out_n * bytes; - stbi_uc *final; + unsigned char *final; int p; if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + return _m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + final = (unsigned char *) _m3dstbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -1304,8 +1506,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + _m3dstbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!_m3dstbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { STBI_FREE(final); return 0; } @@ -1327,11 +1529,11 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 return 1; } -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +static int _m3dstbi__compute_transparency(_m3dstbi__png *z, unsigned char tc[3], int out_n) { - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; + _m3dstbi__context *s = z->s; + _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y; + unsigned char *p = z->out; STBI_ASSERT(out_n == 2 || out_n == 4); @@ -1350,11 +1552,11 @@ static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) return 1; } -static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +static int _m3dstbi__compute_transparency16(_m3dstbi__png *z, _m3dstbi__uint16 tc[3], int out_n) { - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint16 *p = (stbi__uint16*) z->out; + _m3dstbi__context *s = z->s; + _m3dstbi__uint32 i, pixel_count = s->img_x * s->img_y; + _m3dstbi__uint16 *p = (_m3dstbi__uint16*) z->out; STBI_ASSERT(out_n == 2 || out_n == 4); @@ -1373,13 +1575,13 @@ static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int ou return 1; } -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +static int _m3dstbi__expand_png_palette(_m3dstbi__png *a, unsigned char *palette, int len, int pal_img_n) { - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; + _m3dstbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + unsigned char *p, *temp_out, *orig = a->out; - p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); + p = (unsigned char *) _m3dstbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory"); temp_out = p; @@ -1409,228 +1611,177 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) -void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +static int _m3dstbi__parse_png_file(_m3dstbi__png *z, int scan, int req_comp) { - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; -} - -void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag = flag_true_if_should_convert; -} - -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; - - if (s->img_out_n == 3) { - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - p[0] = p[2] * 255 / a; - p[1] = p[1] * 255 / a; - p[2] = t * 255 / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } -} - -#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; - stbi__uint16 tc16[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, is_iphone=0; - stbi__context *s = z->s; + unsigned char palette[1024], pal_img_n=0; + unsigned char has_trans=0, tc[3]; + _m3dstbi__uint16 tc16[3]; + _m3dstbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0; + _m3dstbi__context *s = z->s; z->expanded = NULL; z->idata = NULL; z->out = NULL; - if (!stbi__check_png_header(s)) return 0; + if (!_m3dstbi__check_png_header(s)) return 0; if (scan == STBI__SCAN_type) return 1; for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); + _m3dstbi__pngchunk c = _m3dstbi__get_chunk_header(s); switch (c.type) { case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); + _m3dstbi__skip(s, c.length); break; case STBI__PNG_TYPE('I','H','D','R'): { int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + if (!first) return _m3dstbi__err("multiple IHDR","Corrupt PNG"); first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (c.length != 13) return _m3dstbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = _m3dstbi__get32be(s); if (s->img_x > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)"); + s->img_y = _m3dstbi__get32be(s); if (s->img_y > (1 << 24)) return _m3dstbi__err("too large","Very large image (corrupt?)"); + z->depth = _m3dstbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return _m3dstbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = _m3dstbi__get8(s); if (color > 6) return _m3dstbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return _m3dstbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return _m3dstbi__err("bad ctype","Corrupt PNG"); + comp = _m3dstbi__get8(s); if (comp) return _m3dstbi__err("bad comp method","Corrupt PNG"); + filter= _m3dstbi__get8(s); if (filter) return _m3dstbi__err("bad filter method","Corrupt PNG"); + interlace = _m3dstbi__get8(s); if (interlace>1) return _m3dstbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return _m3dstbi__err("0-pixel image","Corrupt PNG"); if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return _m3dstbi__err("too large", "Image too large to decode"); if (scan == STBI__SCAN_header) return 1; } else { s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + if ((1 << 30) / s->img_x / 4 < s->img_y) return _m3dstbi__err("too large","Corrupt PNG"); } break; } case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return _m3dstbi__err("invalid PLTE","Corrupt PNG"); pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + if (pal_len * 3 != c.length) return _m3dstbi__err("invalid PLTE","Corrupt PNG"); for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); + palette[i*4+0] = _m3dstbi__get8(s); + palette[i*4+1] = _m3dstbi__get8(s); + palette[i*4+2] = _m3dstbi__get8(s); palette[i*4+3] = 255; } break; } case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return _m3dstbi__err("tRNS after IDAT","Corrupt PNG"); if (pal_img_n) { if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + if (pal_len == 0) return _m3dstbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return _m3dstbi__err("bad tRNS len","Corrupt PNG"); pal_img_n = 4; for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); + palette[i*4+3] = _m3dstbi__get8(s); } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + if (!(s->img_n & 1)) return _m3dstbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (_m3dstbi__uint32) s->img_n*2) return _m3dstbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); + for (k = 0; k < s->img_n; ++k) tc16[k] = (_m3dstbi__uint16)_m3dstbi__get16be(s); } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; + for (k = 0; k < s->img_n; ++k) tc[k] = (unsigned char)(_m3dstbi__get16be(s) & 255) * _m3dstbi__depth_scale_table[z->depth]; } } break; } case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return _m3dstbi__err("no PLTE","Corrupt PNG"); if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { - stbi__uint32 idata_limit_old = idata_limit; - stbi_uc *p; + _m3dstbi__uint32 idata_limit_old = idata_limit; + unsigned char *p; if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; while (ioff + c.length > idata_limit) idata_limit *= 2; STBI_NOTUSED(idata_limit_old); - p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + p = (unsigned char *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return _m3dstbi__err("outofmem", "Out of memory"); z->idata = p; } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + if (!_m3dstbi__getn(s, z->idata+ioff,c.length)) return _m3dstbi__err("outofdata","Corrupt PNG"); ioff += c.length; break; } case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + _m3dstbi__uint32 raw_len, bpl; + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + if (z->idata == NULL) return _m3dstbi__err("no IDAT","Corrupt PNG"); bpl = (s->img_x * z->depth + 7) / 8; raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + z->expanded = (unsigned char *) _m3dstbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, 1); if (z->expanded == NULL) return 0; STBI_FREE(z->idata); z->idata = NULL; if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) s->img_out_n = s->img_n+1; else s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (!_m3dstbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; if (has_trans) { if (z->depth == 16) { - if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + if (!_m3dstbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; } else { - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + if (!_m3dstbi__compute_transparency(z, tc, s->img_out_n)) return 0; } } - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); if (pal_img_n) { s->img_n = pal_img_n; s->img_out_n = pal_img_n; if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + if (!_m3dstbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) return 0; + } else if (has_trans) { + ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; return 1; } default: - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (first) return _m3dstbi__err("first not IHDR", "Corrupt PNG"); if ((c.type & (1 << 29)) == 0) { - return stbi__err("invalid_chunk", "PNG not supported: unknown PNG chunk type"); + return _m3dstbi__err("invalid_chunk", "PNG not supported: unknown PNG chunk type"); } - stbi__skip(s, c.length); + _m3dstbi__skip(s, c.length); break; } - stbi__get32be(s); + _m3dstbi__get32be(s); } } -static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +static void *_m3dstbi__do_png(_m3dstbi__png *p, int *x, int *y, int *n, int req_comp, _m3dstbi__result_info *ri) { void *result=NULL; - if (req_comp < 0 || req_comp > 4) { stbi__err("bad req_comp", "Internal error"); return NULL; } - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - ri->bits_per_channel = p->depth; + if (req_comp < 0 || req_comp > 4) { _m3dstbi__err("bad req_comp", "Internal error"); return NULL; } + if (_m3dstbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { if (ri->bits_per_channel == 8) - result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + result = _m3dstbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); else - result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + result = _m3dstbi__convert_format16((_m3dstbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); p->s->img_out_n = req_comp; if (result == NULL) return result; } @@ -1645,12 +1796,16 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st return result; } -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +static void *_m3dstbi__png_load(_m3dstbi__context *s, int *x, int *y, int *comp, int req_comp, _m3dstbi__result_info *ri) { - stbi__png p; + _m3dstbi__png p; p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp, ri); + return _m3dstbi__do_png(&p, x,y,comp,req_comp, ri); } +#define stbi__context _m3dstbi__context +#define stbi__result_info _m3dstbi__result_info +#define stbi__png_load _m3dstbi__png_load +#define stbi_zlib_decode_malloc_guesssize_headerflag _m3dstbi_zlib_decode_malloc_guesssize_headerflag #endif #if defined(M3D_EXPORTER) && !defined(INCLUDE_STB_IMAGE_WRITE_H) @@ -1658,13 +1813,13 @@ static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req stb_image_write - v1.13 - public domain - http://nothings.org/stb/stb_image_write.h */ -typedef unsigned char stbiw_uc; -typedef unsigned short stbiw_us; +typedef unsigned char _m3dstbiw__uc; +typedef unsigned short _m3dstbiw__us; -typedef uint16_t stbiw_uint16; -typedef int16_t stbiw_int16; -typedef uint32_t stbiw_uint32; -typedef int32_t stbiw_int32; +typedef uint16_t _m3dstbiw__uint16; +typedef int16_t _m3dstbiw__int16; +typedef uint32_t _m3dstbiw__uint32; +typedef int32_t _m3dstbiw__int32; #define STBIW_MALLOC(s) M3D_MALLOC(s) #define STBIW_REALLOC(p,ns) M3D_REALLOC(p,ns) @@ -1673,42 +1828,42 @@ typedef int32_t stbiw_int32; #define STBIW_MEMMOVE memmove #define STBIW_UCHAR (uint8_t) #define STBIW_ASSERT(x) -#define stbiw__sbraw(a) ((int *) (a) - 2) -#define stbiw__sbm(a) stbiw__sbraw(a)[0] -#define stbiw__sbn(a) stbiw__sbraw(a)[1] +#define _m3dstbiw___sbraw(a) ((int *) (a) - 2) +#define _m3dstbiw___sbm(a) _m3dstbiw___sbraw(a)[0] +#define _m3dstbiw___sbn(a) _m3dstbiw___sbraw(a)[1] -#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) -#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) -#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) +#define _m3dstbiw___sbneedgrow(a,n) ((a)==0 || _m3dstbiw___sbn(a)+n >= _m3dstbiw___sbm(a)) +#define _m3dstbiw___sbmaybegrow(a,n) (_m3dstbiw___sbneedgrow(a,(n)) ? _m3dstbiw___sbgrow(a,n) : 0) +#define _m3dstbiw___sbgrow(a,n) _m3dstbiw___sbgrowf((void **) &(a), (n), sizeof(*(a))) -#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) -#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) -#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) +#define _m3dstbiw___sbpush(a, v) (_m3dstbiw___sbmaybegrow(a,1), (a)[_m3dstbiw___sbn(a)++] = (v)) +#define _m3dstbiw___sbcount(a) ((a) ? _m3dstbiw___sbn(a) : 0) +#define _m3dstbiw___sbfree(a) ((a) ? STBIW_FREE(_m3dstbiw___sbraw(a)),0 : 0) -static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) +static void *_m3dstbiw___sbgrowf(void **arr, int increment, int itemsize) { - int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; - void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); + int m = *arr ? 2*_m3dstbiw___sbm(*arr)+increment : increment+1; + void *p = STBIW_REALLOC_SIZED(*arr ? _m3dstbiw___sbraw(*arr) : 0, *arr ? (_m3dstbiw___sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); STBIW_ASSERT(p); if (p) { if (!*arr) ((int *) p)[1] = 0; *arr = (void *) ((int *) p + 2); - stbiw__sbm(*arr) = m; + _m3dstbiw___sbm(*arr) = m; } return *arr; } -static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +static unsigned char *_m3dstbiw___zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) { while (*bitcount >= 8) { - stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + _m3dstbiw___sbpush(data, STBIW_UCHAR(*bitbuffer)); *bitbuffer >>= 8; *bitcount -= 8; } return data; } -static int stbiw__zlib_bitrev(int code, int codebits) +static int _m3dstbiw___zlib_bitrev(int code, int codebits) { int res=0; while (codebits--) { @@ -1718,7 +1873,7 @@ static int stbiw__zlib_bitrev(int code, int codebits) return res; } -static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) +static unsigned int _m3dstbiw___zlib_countm(unsigned char *a, unsigned char *b, int limit) { int i; for (i=0; i < limit && i < 258; ++i) @@ -1726,9 +1881,9 @@ static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int l return i; } -static unsigned int stbiw__zhash(unsigned char *data) +static unsigned int _m3dstbiw___zhash(unsigned char *data) { - stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + _m3dstbiw__uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4; @@ -1738,20 +1893,20 @@ static unsigned int stbiw__zhash(unsigned char *data) return hash; } -#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) -#define stbiw__zlib_add(code,codebits) \ - (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) -#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) -#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) -#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) -#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) -#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) -#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) -#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) +#define _m3dstbiw___zlib_flush() (out = _m3dstbiw___zlib_flushf(out, &bitbuf, &bitcount)) +#define _m3dstbiw___zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), _m3dstbiw___zlib_flush()) +#define _m3dstbiw___zlib_huffa(b,c) _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(b,c),c) +#define _m3dstbiw___zlib_huff1(n) _m3dstbiw___zlib_huffa(0x30 + (n), 8) +#define _m3dstbiw___zlib_huff2(n) _m3dstbiw___zlib_huffa(0x190 + (n)-144, 9) +#define _m3dstbiw___zlib_huff3(n) _m3dstbiw___zlib_huffa(0 + (n)-256,7) +#define _m3dstbiw___zlib_huff4(n) _m3dstbiw___zlib_huffa(0xc0 + (n)-280,8) +#define _m3dstbiw___zlib_huff(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : (n) <= 255 ? _m3dstbiw___zlib_huff2(n) : (n) <= 279 ? _m3dstbiw___zlib_huff3(n) : _m3dstbiw___zlib_huff4(n)) +#define _m3dstbiw___zlib_huffb(n) ((n) <= 143 ? _m3dstbiw___zlib_huff1(n) : _m3dstbiw___zlib_huff2(n)) -#define stbiw__ZHASH 16384 +#define _m3dstbiw___ZHASH 16384 -unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; @@ -1760,42 +1915,44 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l unsigned int bitbuf=0; int i,j, bitcount=0; unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); + unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(_m3dstbiw___ZHASH * sizeof(char**)); + if (hash_table == NULL) + return NULL; if (quality < 5) quality = 5; - stbiw__sbpush(out, 0x78); - stbiw__sbpush(out, 0x5e); - stbiw__zlib_add(1,1); - stbiw__zlib_add(1,2); + _m3dstbiw___sbpush(out, 0x78); + _m3dstbiw___sbpush(out, 0x5e); + _m3dstbiw___zlib_add(1,1); + _m3dstbiw___zlib_add(1,2); - for (i=0; i < stbiw__ZHASH; ++i) + for (i=0; i < _m3dstbiw___ZHASH; ++i) hash_table[i] = NULL; i=0; while (i < data_len-3) { - int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; + int h = _m3dstbiw___zhash(data+i)&(_m3dstbiw___ZHASH-1), best=3; unsigned char *bestloc = 0; unsigned char **hlist = hash_table[h]; - int n = stbiw__sbcount(hlist); + int n = _m3dstbiw___sbcount(hlist); for (j=0; j < n; ++j) { if (hlist[j]-data > i-32768) { - int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); + int d = _m3dstbiw___zlib_countm(hlist[j], data+i, data_len-i); if (d >= best) best=d,bestloc=hlist[j]; } } - if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { + if (hash_table[h] && _m3dstbiw___sbn(hash_table[h]) == 2*quality) { STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); - stbiw__sbn(hash_table[h]) = quality; + _m3dstbiw___sbn(hash_table[h]) = quality; } - stbiw__sbpush(hash_table[h],data+i); + _m3dstbiw___sbpush(hash_table[h],data+i); if (bestloc) { - h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); + h = _m3dstbiw___zhash(data+i+1)&(_m3dstbiw___ZHASH-1); hlist = hash_table[h]; - n = stbiw__sbcount(hlist); + n = _m3dstbiw___sbcount(hlist); for (j=0; j < n; ++j) { if (hlist[j]-data > i-32767) { - int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); + int e = _m3dstbiw___zlib_countm(hlist[j], data+i+1, data_len-i-1); if (e > best) { bestloc = NULL; break; @@ -1808,25 +1965,25 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l int d = (int) (data+i - bestloc); STBIW_ASSERT(d <= 32767 && best <= 258); for (j=0; best > lengthc[j+1]-1; ++j); - stbiw__zlib_huff(j+257); - if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + _m3dstbiw___zlib_huff(j+257); + if (lengtheb[j]) _m3dstbiw___zlib_add(best - lengthc[j], lengtheb[j]); for (j=0; d > distc[j+1]-1; ++j); - stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); - if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); + _m3dstbiw___zlib_add(_m3dstbiw___zlib_bitrev(j,5),5); + if (disteb[j]) _m3dstbiw___zlib_add(d - distc[j], disteb[j]); i += best; } else { - stbiw__zlib_huffb(data[i]); + _m3dstbiw___zlib_huffb(data[i]); ++i; } } for (;i < data_len; ++i) - stbiw__zlib_huffb(data[i]); - stbiw__zlib_huff(256); + _m3dstbiw___zlib_huffb(data[i]); + _m3dstbiw___zlib_huff(256); while (bitcount) - stbiw__zlib_add(0,1); + _m3dstbiw___zlib_add(0,1); - for (i=0; i < stbiw__ZHASH; ++i) - (void) stbiw__sbfree(hash_table[i]); + for (i=0; i < _m3dstbiw___ZHASH; ++i) + (void) _m3dstbiw___sbfree(hash_table[i]); STBIW_FREE(hash_table); { @@ -1839,15 +1996,18 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l j += blocklen; blocklen = 5552; } - stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s2)); - stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s1)); + _m3dstbiw___sbpush(out, STBIW_UCHAR(s2 >> 8)); + _m3dstbiw___sbpush(out, STBIW_UCHAR(s2)); + _m3dstbiw___sbpush(out, STBIW_UCHAR(s1 >> 8)); + _m3dstbiw___sbpush(out, STBIW_UCHAR(s1)); } - *out_len = stbiw__sbn(out); - STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); - return (unsigned char *) stbiw__sbraw(out); + *out_len = _m3dstbiw___sbn(out); + STBIW_MEMMOVE(_m3dstbiw___sbraw(out), out, *out_len); + return (unsigned char *) _m3dstbiw___sbraw(out); } +#define stbi_zlib_compress _m3dstbi_zlib_compress +#else +unsigned char * _m3dstbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality); #endif #define M3D_CHUNKMAGIC(m, a,b,c,d) ((m)[0]==(a) && (m)[1]==(b) && (m)[2]==(c) && (m)[3]==(d)) @@ -1856,6 +2016,9 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l #include /* get sprintf */ #include /* sprintf and strtod cares about number locale */ #endif +#ifdef M3D_PROFILING +#include +#endif #if !defined(M3D_NOIMPORTER) && defined(M3D_ASCII) /* helper functions for the ASCII parser */ @@ -1885,7 +2048,7 @@ static char *_m3d_gethex(char *s, uint32_t *ret) static char *_m3d_getint(char *s, uint32_t *ret) { char *e = s; - if(!s || !*s) return s; + if(!s || !*s || *s == '\r' || *s == '\n') return s; for(; *e >= '0' && *e <= '9'; e++); *ret = atoi(s); return e; @@ -1893,54 +2056,13 @@ static char *_m3d_getint(char *s, uint32_t *ret) static char *_m3d_getfloat(char *s, M3D_FLOAT *ret) { char *e = s; - if(!s || !*s) return s; + if(!s || !*s || *s == '\r' || *s == '\n') return s; for(; *e == '-' || *e == '+' || *e == '.' || (*e >= '0' && *e <= '9') || *e == 'e' || *e == 'E'; e++); *ret = (M3D_FLOAT)strtod(s, NULL); return _m3d_findarg(e); } #endif -#if !defined(M3D_NODUP) && (!defined(M3D_NONORMALS) || defined(M3D_EXPORTER)) -/* add vertex to list, only compare x,y,z */ -m3dv_t *_m3d_addnorm(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) -{ - uint32_t i; - if(v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0; - if(v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0; - if(v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0; - if(v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0; - if(vrtx) { - for(i = 0; i < *numvrtx; i++) - if(vrtx[i].x == v->x && vrtx[i].y == v->y && vrtx[i].z == v->z) { *idx = i; return vrtx; } - } - vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t)); - memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t)); - vrtx[*numvrtx].color = 0; - vrtx[*numvrtx].w = (M3D_FLOAT)1.0; - *idx = *numvrtx; - (*numvrtx)++; - return vrtx; -} -#endif -#if !defined(M3D_NODUP) && (defined(M3D_ASCII) || defined(M3D_EXPORTER)) -m3ds_t *_m3d_addskin(m3ds_t *skin, uint32_t *numskin, m3ds_t *s, uint32_t *idx) -{ - uint32_t i; - M3D_FLOAT w = (M3D_FLOAT)0.0; - for(i = 0; i < M3D_NUMBONE && s->weight[i] > (M3D_FLOAT)0.0; i++) - w += s->weight[i]; - if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) - for(i = 0; i < M3D_NUMBONE && s->weight[i] > (M3D_FLOAT)0.0; i++) - s->weight[i] /= w; - if(skin) { - for(i = 0; i < *numskin; i++) - if(!memcmp(&skin[i], s, sizeof(m3ds_t))) { *idx = i; return skin; } - } - skin = (m3ds_t*)M3D_REALLOC(skin, ((*numskin) + 1) * sizeof(m3ds_t)); - memcpy(&skin[*numskin], s, sizeof(m3ds_t)); - *idx = *numskin; - (*numskin)++; - return skin; -} +#if !defined(M3D_NODUP) && (!defined(M3D_NOIMPORTER) || defined(M3D_ASCII) || defined(M3D_EXPORTER)) /* helper function to create safe strings */ char *_m3d_safestr(char *in, int morelines) { @@ -1973,7 +2095,7 @@ char *_m3d_safestr(char *in, int morelines) } for(; o > out && (*(o-1) == ' ' || *(o-1) == '\t' || *(o-1) == '\r' || *(o-1) == '\n'); o--); *o = 0; - out = (char*)M3D_REALLOC(out, (uint64_t)o - (uint64_t)out + 1); + out = (char*)M3D_REALLOC(out, (uintptr_t)o - (uintptr_t)out + 1); } return out; } @@ -1982,28 +2104,20 @@ char *_m3d_safestr(char *in, int morelines) /* helper function to load and decode/generate a texture */ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char *fn) { - unsigned int i, len = 0, w, h; + unsigned int i, len = 0; unsigned char *buff = NULL; char *fn2; +#ifdef STBI__PNG_TYPE + unsigned int w, h; stbi__context s; stbi__result_info ri; +#endif + /* do we have loaded this texture already? */ for(i = 0; i < model->numtexture; i++) if(!strcmp(fn, model->texture[i].name)) return i; - if(readfilecb) { - i = strlen(fn); - if(i < 5 || fn[i - 4] != '.') { - fn2 = (char*)M3D_MALLOC(i + 5); - if(!fn2) { model->errcode = M3D_ERR_ALLOC; return (M3D_INDEX)-1U; } - memcpy(fn2, fn, i); - memcpy(fn2+i, ".png", 5); - buff = (*readfilecb)(fn2, &len); - M3D_FREE(fn2); - } - if(!buff) - buff = (*readfilecb)(fn, &len); - } - if(!buff && model->inlined) { + /* see if it's inlined in the model */ + if(model->inlined) { for(i = 0; i < model->numinlined; i++) if(!strcmp(fn, model->inlined[i].name)) { buff = model->inlined[i].data; @@ -2012,42 +2126,61 @@ M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char break; } } - if(!buff) return (M3D_INDEX)-1U; + /* try to load from external source */ + if(!buff && readfilecb) { + i = (unsigned int)strlen(fn); + if(i < 5 || fn[i - 4] != '.') { + fn2 = (char*)M3D_MALLOC(i + 5); + if(!fn2) { model->errcode = M3D_ERR_ALLOC; return M3D_UNDEF; } + memcpy(fn2, fn, i); + memcpy(fn2+i, ".png", 5); + buff = (*readfilecb)(fn2, &len); + M3D_FREE(fn2); + } + if(!buff) { + buff = (*readfilecb)(fn, &len); + if(!buff) return M3D_UNDEF; + } + } + /* add to textures array */ i = model->numtexture++; model->texture = (m3dtx_t*)M3D_REALLOC(model->texture, model->numtexture * sizeof(m3dtx_t)); if(!model->texture) { - if(freecb) (*freecb)(buff); - model->errcode = M3D_ERR_ALLOC; return (M3D_INDEX)-1U; - } - model->texture[i].w = model->texture[i].h = 0; model->texture[i].d = NULL; - if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') { - s.read_from_callbacks = 0; - s.img_buffer = s.img_buffer_original = (stbi_uc *) buff; - s.img_buffer_end = s.img_buffer_original_end = (stbi_uc *) buff+len; - /* don't use model->texture[i].w directly, it's a uint16_t */ - w = h = 0; - model->texture[i].d = (uint32_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, STBI_rgb_alpha, &ri); - model->texture[i].w = w; - model->texture[i].h = h; - } else { -#ifdef M3D_TX_INTERP - if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) { - M3D_LOG("Unable to generate texture"); - M3D_LOG(fn); - } -#else - M3D_LOG("Unimplemented interpreter"); - M3D_LOG(fn); -#endif - } - if(freecb) (*freecb)(buff); - if(!model->texture[i].d) { - M3D_FREE(model->texture[i].d); - model->errcode = M3D_ERR_UNKIMG; - model->numtexture--; - return (M3D_INDEX)-1U; + if(buff && freecb) (*freecb)(buff); + model->errcode = M3D_ERR_ALLOC; + return M3D_UNDEF; } model->texture[i].name = fn; + model->texture[i].w = model->texture[i].h = 0; model->texture[i].d = NULL; + if(buff) { + if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') { +#ifdef STBI__PNG_TYPE + s.read_from_callbacks = 0; + s.img_buffer = s.img_buffer_original = (unsigned char *) buff; + s.img_buffer_end = s.img_buffer_original_end = (unsigned char *) buff+len; + /* don't use model->texture[i].w directly, it's a uint16_t */ + w = h = len = 0; + ri.bits_per_channel = 8; + model->texture[i].d = (uint8_t*)stbi__png_load(&s, (int*)&w, (int*)&h, (int*)&len, 0, &ri); + model->texture[i].w = w; + model->texture[i].h = h; + model->texture[i].f = (uint8_t)len; +#endif + } else { +#ifdef M3D_TX_INTERP + if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) { + M3D_LOG("Unable to generate texture"); + M3D_LOG(fn); + } +#else + M3D_LOG("Unimplemented interpreter"); + M3D_LOG(fn); +#endif + } + if(freecb) (*freecb)(buff); + } + if(!model->texture[i].d) + model->errcode = M3D_ERR_UNKIMG; return i; } @@ -2074,6 +2207,9 @@ void _m3d_getpr(m3d_t *model, _unused m3dread_t readfilecb, _unused m3dfree_t f } if(freecb && buff) (*freecb)(buff); #else + (void)readfilecb; + (void)freecb; + (void)fn; M3D_LOG("Unimplemented interpreter"); M3D_LOG(fn); model->errcode = M3D_ERR_UNIMPL; @@ -2085,8 +2221,8 @@ _inline static unsigned char *_m3d_getidx(unsigned char *data, char type, M3D_IN { switch(type) { case 1: *idx = data[0] > 253 ? (int8_t)data[0] : data[0]; data++; break; - case 2: *idx = (uint16_t)((data[1]<<8)|data[0]) > 65533 ? (int16_t)((data[1]<<8)|data[0]) : (uint16_t)((data[1]<<8)|data[0]); data += 2; break; - case 4: *idx = (int32_t)((data[3]<<24)|(data[2]<<16)|(data[1]<<8)|data[0]); data += 4; break; + case 2: *idx = *((uint16_t*)data) > 65533 ? *((int16_t*)data) : *((uint16_t*)data); data += 2; break; + case 4: *idx = *((int32_t*)data); data += 4; break; } return data; } @@ -2144,10 +2280,6 @@ void _m3d_inv(M3D_FLOAT *m) memcpy(m, &r, sizeof(r)); } /* compose a coloumn major 4 x 4 matrix from vec3 position and vec4 orientation/rotation quaternion */ -#ifndef M3D_EPSILON -/* carefully choosen for IEEE 754 don't change */ -#define M3D_EPSILON ((M3D_FLOAT)1e-7) -#endif void _m3d_mat(M3D_FLOAT *r, m3dv_t *p, m3dv_t *q) { if(q->x == (M3D_FLOAT)0.0 && q->y == (M3D_FLOAT)0.0 && q->z >=(M3D_FLOAT) 0.7071065 && q->z <= (M3D_FLOAT)0.7071075 && @@ -2170,7 +2302,7 @@ void _m3d_mat(M3D_FLOAT *r, m3dv_t *p, m3dv_t *q) } #endif #if !defined(M3D_NOANIMATION) || !defined(M3D_NONORMALS) -/* fast inverse square root calculation. returns 1/sqrt(x) */ +/* portable fast inverse square root calculation. returns 1/sqrt(x) */ static M3D_FLOAT _m3d_rsq(M3D_FLOAT x) { #ifdef M3D_DOUBLE @@ -2190,30 +2322,40 @@ static M3D_FLOAT _m3d_rsq(M3D_FLOAT x) m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d_t *mtllib) { unsigned char *end, *chunk, *buff, weights[8]; - unsigned int i, j, k, n, am, len = 0, reclen, offs; - char *material; -#ifndef M3D_NONORMALS - unsigned int numnorm = 0; - m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb, vn; - M3D_INDEX *ni = NULL, *vi = NULL; -#endif + unsigned int i, j, k, l, n, am, len = 0, reclen, offs; + char *name, *lang; + float f; m3d_t *model; M3D_INDEX mi; M3D_FLOAT w; + m3dcd_t *cd; + m3dtx_t *tx; + m3dh_t *h; + m3dm_t *m; + m3da_t *a; + m3di_t *t; +#ifndef M3D_NONORMALS + char neednorm = 0; + m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb; +#endif #ifndef M3D_NOANIMATION M3D_FLOAT r[16]; #endif - m3dtx_t *tx; - m3dm_t *m; - m3da_t *a; +#if !defined(M3D_NOWEIGHTS) || !defined(M3D_NOANIMATION) m3db_t *b; - m3di_t *t; +#endif +#ifndef M3D_NOWEIGHTS m3ds_t *sk; +#endif #ifdef M3D_ASCII m3ds_t s; M3D_INDEX bi[M3D_BONEMAXLEVEL+1], level; const char *ol; - char *ptr, *pe; + char *ptr, *pe, *fn; +#endif +#ifdef M3D_PROFILING + struct timeval tv0, tv1, tvd; + gettimeofday(&tv0, NULL); #endif if(!data || (!M3D_CHUNKMAGIC(data, '3','D','M','O') @@ -2250,13 +2392,14 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d pe = _m3d_findnl(ptr); model->scale = (float)strtod(ptr, NULL); ptr = pe; if(model->scale <= (M3D_FLOAT)0.0) model->scale = (M3D_FLOAT)1.0; - model->name = _m3d_safestr(ptr, 0); ptr = _m3d_findnl(ptr); + model->name = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); if(!*ptr) goto asciiend; model->license = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); if(!*ptr) goto asciiend; model->author = _m3d_safestr(ptr, 2); ptr = _m3d_findnl(ptr); if(!*ptr) goto asciiend; - model->desc = _m3d_safestr(ptr, 3); + if(*ptr != '\r' && *ptr != '\n') + model->desc = _m3d_safestr(ptr, 3); while(*ptr) { while(*ptr && *ptr!='\n') ptr++; ptr++; if(*ptr=='\r') ptr++; @@ -2270,6 +2413,17 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d /* make sure there's at least one data row */ pe = ptr; ptr = _m3d_findnl(ptr); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; + /* Preview chunk */ + if(!memcmp(pe, "Preview", 7)) { + if(readfilecb) { + pe = _m3d_safestr(ptr, 0); + if(!pe || !*pe) goto asciiend; + model->preview.data = (*readfilecb)(pe, &model->preview.length); + M3D_FREE(pe); + } + while(*ptr && *ptr != '\r' && *ptr != '\n') + ptr = _m3d_findnl(ptr); + } else /* texture map chunk */ if(!memcmp(pe, "Textmap", 7)) { if(model->tmap) { M3D_LOG("More texture map chunks, should be unique"); goto asciiend; } @@ -2279,8 +2433,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d if(!model->tmap) goto memerr; ptr = _m3d_getfloat(ptr, &model->tmap[i].u); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; - ptr = _m3d_getfloat(ptr, &model->tmap[i].v); - if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; + _m3d_getfloat(ptr, &model->tmap[i].v); ptr = _m3d_findnl(ptr); } } else @@ -2291,8 +2444,10 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d i = model->numvertex++; model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); if(!model->vertex) goto memerr; - model->vertex[i].skinid = (M3D_INDEX)-1U; + memset(&model->vertex[i], 0, sizeof(m3dv_t)); + model->vertex[i].skinid = M3D_UNDEF; model->vertex[i].color = 0; + model->vertex[i].w = (M3D_FLOAT)1.0; ptr = _m3d_getfloat(ptr, &model->vertex[i].x); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; ptr = _m3d_getfloat(ptr, &model->vertex[i].y); @@ -2300,7 +2455,6 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d ptr = _m3d_getfloat(ptr, &model->vertex[i].z); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; ptr = _m3d_getfloat(ptr, &model->vertex[i].w); - if(model->vertex[i].w != 1.0) model->vertex[i].skinid = (M3D_INDEX)-2U; if(!*ptr) goto asciiend; if(*ptr == '#') { ptr = _m3d_gethex(ptr, &model->vertex[i].color); @@ -2308,7 +2462,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d } /* parse skin */ memset(&s, 0, sizeof(m3ds_t)); - for(j = 0; j < M3D_NUMBONE && *ptr && *ptr != '\r' && *ptr != '\n'; j++) { + for(j = 0, w = (M3D_FLOAT)0.0; j < M3D_NUMBONE && *ptr && *ptr != '\r' && *ptr != '\n'; j++) { ptr = _m3d_findarg(ptr); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; ptr = _m3d_getint(ptr, &k); @@ -2316,12 +2470,25 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d if(*ptr == ':') { ptr++; ptr = _m3d_getfloat(ptr, &s.weight[j]); + w += s.weight[j]; } else if(!j) s.weight[j] = (M3D_FLOAT)1.0; if(!*ptr) goto asciiend; } - if(s.boneid[0] != (M3D_INDEX)-1U && s.weight[0] > (M3D_FLOAT)0.0) { - model->skin = _m3d_addskin(model->skin, &model->numskin, &s, &k); + if(s.boneid[0] != M3D_UNDEF && s.weight[0] > (M3D_FLOAT)0.0) { + if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) + for(j = 0; j < M3D_NUMBONE && s.weight[j] > (M3D_FLOAT)0.0; j++) + s.weight[j] /= w; + k = M3D_NOTDEFINED; + if(model->skin) { + for(j = 0; j < model->numskin; j++) + if(!memcmp(&model->skin[j], &s, sizeof(m3ds_t))) { k = j; break; } + } + if(k == M3D_NOTDEFINED) { + k = model->numskin++; + model->skin = (m3ds_t*)M3D_REALLOC(model->skin, model->numskin * sizeof(m3ds_t)); + memcpy(&model->skin[k], &s, sizeof(m3ds_t)); + } model->vertex[i].skinid = (M3D_INDEX)k; } ptr = _m3d_findnl(ptr); @@ -2330,7 +2497,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d /* Skeleton, bone hierarchy */ if(!memcmp(pe, "Bones", 5)) { if(model->bone) { M3D_LOG("More bones chunks, should be unique"); goto asciiend; } - bi[0] = (M3D_INDEX)-1U; + bi[0] = M3D_UNDEF; while(*ptr && *ptr != '\r' && *ptr != '\n') { i = model->numbone++; model->bone = (m3db_t*)M3D_REALLOC(model->bone, model->numbone * sizeof(m3db_t)); @@ -2349,6 +2516,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d ptr = _m3d_findarg(ptr); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; model->bone[i].ori = (M3D_INDEX)k; + model->vertex[k].skinid = M3D_INDEXMAX; pe = _m3d_safestr(ptr, 0); if(!pe || !*pe) goto asciiend; model->bone[i].name = pe; @@ -2410,7 +2578,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d j = m->numprop++; m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t)); if(!m->prop) goto memerr; - m->prop[j].type = n; + m->prop[j].type = n + (k == m3dpf_map && n < 128 ? 128 : 0); switch(k) { case m3dpf_color: ptr = _m3d_gethex(ptr, &m->prop[j].value.color); break; case m3dpf_uint8: @@ -2422,7 +2590,8 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d if(!pe || !*pe) goto asciiend; m->prop[j].value.textureid = _m3d_gettx(model, readfilecb, freecb, pe); if(model->errcode == M3D_ERR_ALLOC) { M3D_FREE(pe); goto memerr; } - if(m->prop[j].value.textureid == (M3D_INDEX)-1U) { + /* this error code only returned if readfilecb was specified */ + if(m->prop[j].value.textureid == M3D_UNDEF) { M3D_LOG("Texture not found"); M3D_LOG(pe); m->numprop--; @@ -2439,7 +2608,7 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d } if(!m->numprop) model->nummaterial--; } else - /* procedural, not implemented yet, skip chunk */ + /* procedural */ if(!memcmp(pe, "Procedural", 10)) { pe = _m3d_safestr(ptr, 0); _m3d_getpr(model, readfilecb, freecb, pe); @@ -2448,21 +2617,26 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d } else /* mesh */ if(!memcmp(pe, "Mesh", 4)) { - mi = (M3D_INDEX)-1U; + mi = M3D_UNDEF; while(*ptr && *ptr != '\r' && *ptr != '\n') { if(*ptr == 'u') { ptr = _m3d_findarg(ptr); if(!*ptr) goto asciiend; - mi = (M3D_INDEX)-1U; + mi = M3D_UNDEF; if(*ptr != '\r' && *ptr != '\n') { pe = _m3d_safestr(ptr, 0); if(!pe || !*pe) goto asciiend; for(j = 0; j < model->nummaterial; j++) - if(!strcmp(pe, model->material[j].name)) { - mi = (M3D_INDEX)j; - break; - } - M3D_FREE(pe); + if(!strcmp(pe, model->material[j].name)) { mi = (M3D_INDEX)j; break; } + if(mi == M3D_UNDEF && !(model->flags & M3D_FLG_MTLLIB)) { + mi = model->nummaterial++; + model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t)); + if(!model->material) goto memerr; + model->material[mi].name = pe; + model->material[mi].numprop = 1; + model->material[mi].prop = NULL; + } else + M3D_FREE(pe); } } else { i = model->numface++; @@ -2492,12 +2666,146 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d if(!*ptr) goto asciiend; } } +#ifndef M3D_NONORMALS + if(model->face[i].normal[j] == M3D_UNDEF) neednorm = 1; +#endif ptr = _m3d_findarg(ptr); } } ptr = _m3d_findnl(ptr); } } else + /* mathematical shape */ + if(!memcmp(pe, "Shape", 5)) { + pe = _m3d_findarg(pe); + if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; + pe = _m3d_safestr(pe, 0); + if(!pe || !*pe) goto asciiend; + i = model->numshape++; + model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3ds_t)); + if(!model->shape) goto memerr; + h = &model->shape[i]; + h->name = pe; + h->group = M3D_UNDEF; + h->numcmd = 0; + h->cmd = NULL; + while(*ptr && *ptr != '\r' && *ptr != '\n') { + if(!memcmp(ptr, "group", 5)) { + ptr = _m3d_findarg(ptr); + ptr = _m3d_getint(ptr, &h->group); + ptr = _m3d_findnl(ptr); + if(h->group != M3D_UNDEF && h->group >= model->numbone) { + M3D_LOG("Unknown bone id as shape group in shape"); + M3D_LOG(pe); + h->group = M3D_UNDEF; + model->errcode = M3D_ERR_SHPE; + } + continue; + } + for(cd = NULL, k = 0; k < (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])); k++) { + j = (unsigned int)strlen(m3d_commandtypes[k].key); + if(!memcmp(ptr, m3d_commandtypes[k].key, j) && (ptr[j] == ' ' || ptr[j] == '\r' || ptr[j] == '\n')) + { cd = &m3d_commandtypes[k]; break; } + } + if(cd) { + j = h->numcmd++; + h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t)); + if(!h->cmd) goto memerr; + h->cmd[j].type = k; + h->cmd[j].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t)); + if(!h->cmd[j].arg) goto memerr; + memset(h->cmd[j].arg, 0, cd->p * sizeof(uint32_t)); + for(k = n = 0, l = cd->p; k < l; k++) { + ptr = _m3d_findarg(ptr); + if(!*ptr) goto asciiend; + if(*ptr == '[') { + ptr = _m3d_findarg(ptr + 1); + if(!*ptr) goto asciiend; + } + if(*ptr == ']' || *ptr == '\r' || *ptr == '\n') break; + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + mi = M3D_UNDEF; + if(*ptr != '\r' && *ptr != '\n') { + pe = _m3d_safestr(ptr, 0); + if(!pe || !*pe) goto asciiend; + for(n = 0; n < model->nummaterial; n++) + if(!strcmp(pe, model->material[n].name)) { mi = (M3D_INDEX)n; break; } + if(mi == M3D_UNDEF && !(model->flags & M3D_FLG_MTLLIB)) { + mi = model->nummaterial++; + model->material = (m3dm_t*)M3D_REALLOC(model->material, + model->nummaterial * sizeof(m3dm_t)); + if(!model->material) goto memerr; + model->material[mi].name = pe; + model->material[mi].numprop = 1; + model->material[mi].prop = NULL; + } else + M3D_FREE(pe); + } + h->cmd[j].arg[k] = mi; + break; + case m3dcp_vc_t: + _m3d_getfloat(ptr, &w); + h->cmd[j].arg[k] = *((uint32_t*)&w); + break; + case m3dcp_va_t: + ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); + n = k + 1; l += (h->cmd[j].arg[k] - 1) * (cd->p - k - 1); + h->cmd[j].arg = (uint32_t*)M3D_REALLOC(h->cmd[j].arg, l * sizeof(uint32_t)); + if(!h->cmd[j].arg) goto memerr; + memset(&h->cmd[j].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t)); + break; + case m3dcp_qi_t: + ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); + model->vertex[h->cmd[i].arg[k]].skinid = M3D_INDEXMAX; + break; + default: + ptr = _m3d_getint(ptr, &h->cmd[j].arg[k]); + break; + } + } + } else { + M3D_LOG("Unknown shape command in"); + M3D_LOG(h->name); + model->errcode = M3D_ERR_UNKCMD; + } + ptr = _m3d_findnl(ptr); + } + if(!h->numcmd) model->numshape--; + } else + /* annotation labels */ + if(!memcmp(pe, "Labels", 6)) { + pe = _m3d_findarg(pe); + if(!*pe) goto asciiend; + if(*pe == '\r' || *pe == '\n') pe = NULL; + else pe = _m3d_safestr(pe, 0); + k = 0; fn = NULL; + while(*ptr && *ptr != '\r' && *ptr != '\n') { + if(*ptr == 'c') { + ptr = _m3d_findarg(ptr); + if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; + ptr = _m3d_gethex(ptr, &k); + } else + if(*ptr == 'l') { + ptr = _m3d_findarg(ptr); + if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; + fn = _m3d_safestr(ptr, 2); + } else { + i = model->numlabel++; + model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t)); + if(!model->label) goto memerr; + model->label[i].name = pe; + model->label[i].lang = fn; + model->label[i].color = k; + ptr = _m3d_getint(ptr, &j); + model->label[i].vertexid = (M3D_INDEX)j; + ptr = _m3d_findarg(ptr); + if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; + model->label[i].text = _m3d_safestr(ptr, 2); + } + ptr = _m3d_findnl(ptr); + } + } else /* action */ if(!memcmp(pe, "Action", 6)) { pe = _m3d_findarg(pe); @@ -2548,6 +2856,33 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d ptr = _m3d_getint(ptr, &k); if(!*ptr || *ptr == '\r' || *ptr == '\n') goto asciiend; a->frame[i].transform[j].ori = (M3D_INDEX)k; + model->vertex[k].skinid = M3D_INDEXMAX; + } + ptr = _m3d_findnl(ptr); + } + } else + /* inlined assets chunk */ + if(!memcmp(pe, "Assets", 6)) { + while(*ptr && *ptr != '\r' && *ptr != '\n') { + if(readfilecb) { + pe = _m3d_safestr(ptr, 2); + if(!pe || !*pe) goto asciiend; + i = model->numinlined++; + model->inlined = (m3di_t*)M3D_REALLOC(model->inlined, model->numinlined * sizeof(m3di_t)); + if(!model->inlined) goto memerr; + t = &model->inlined[i]; + model->inlined[i].data = (*readfilecb)(pe, &model->inlined[i].length); + if(model->inlined[i].data) { + fn = strrchr(pe, '.'); + if(fn && (fn[1] == 'p' || fn[1] == 'P') && (fn[2] == 'n' || fn[2] == 'N') && + (fn[3] == 'g' || fn[3] == 'G')) *fn = 0; + fn = strrchr(pe, '/'); + if(!fn) fn = strrchr(pe, '\\'); + if(!fn) fn = pe; else fn++; + model->inlined[i].name = _m3d_safestr(fn, 0); + } else + model->numinlined--; + M3D_FREE(pe); } ptr = _m3d_findnl(ptr); } @@ -2557,19 +2892,19 @@ m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d pe = _m3d_findarg(pe); if(!*pe || *pe == '\r' || *pe == '\n') goto asciiend; buff = (unsigned char*)_m3d_findnl(ptr); - k = ((uint32_t)((uint64_t)buff - (uint64_t)ptr) / 3) + 1; - i = model->numunknown++; - model->unknown = (m3dchunk_t**)M3D_REALLOC(model->unknown, model->numunknown * sizeof(m3dchunk_t*)); - if(!model->unknown) goto memerr; - model->unknown[i] = (m3dchunk_t*)M3D_MALLOC(k + sizeof(m3dchunk_t)); - if(!model->unknown[i]) goto memerr; - memcpy(&model->unknown[i]->magic, pe, 4); - model->unknown[i]->length = sizeof(m3dchunk_t); - pe = (char*)model->unknown[i] + sizeof(m3dchunk_t); + k = ((uint32_t)((uintptr_t)buff - (uintptr_t)ptr) / 3) + 1; + i = model->numextra++; + model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*)); + if(!model->extra) goto memerr; + model->extra[i] = (m3dchunk_t*)M3D_MALLOC(k + sizeof(m3dchunk_t)); + if(!model->extra[i]) goto memerr; + memcpy(&model->extra[i]->magic, pe, 4); + model->extra[i]->length = sizeof(m3dchunk_t); + pe = (char*)model->extra[i] + sizeof(m3dchunk_t); while(*ptr && *ptr != '\r' && *ptr != '\n') { ptr = _m3d_gethex(ptr, &k); *pe++ = (uint8_t)k; - model->unknown[i]->length++; + model->extra[i]->length++; } } else goto asciiend; @@ -2579,14 +2914,12 @@ asciiend: setlocale(LC_NUMERIC, ol); goto postprocess; } - /* Binary variant */ #endif + /* Binary variant */ if(!M3D_CHUNKMAGIC(data + 8, 'H','E','A','D')) { - stbi__g_failure_reason = "Corrupt file"; buff = (unsigned char *)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)data+8, ((m3dchunk_t*)data)->length-8, 4096, (int*)&len, 1); if(!buff || !len || !M3D_CHUNKMAGIC(buff, 'H','E','A','D')) { - M3D_LOG(stbi__g_failure_reason); if(buff) M3D_FREE(buff); M3D_FREE(model); return NULL; @@ -2594,6 +2927,14 @@ asciiend: buff = (unsigned char*)M3D_REALLOC(buff, len); model->flags |= M3D_FLG_FREERAW; /* mark that we have to free the raw buffer */ data = buff; +#ifdef M3D_PROFILING + gettimeofday(&tv1, NULL); + tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; + tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + printf(" Deflate model %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); + memcpy(&tv0, &tv1, sizeof(struct timeval)); +#endif } else { len = ((m3dhdr_t*)data)->length; data += 8; @@ -2622,11 +2963,15 @@ asciiend: model->bi_s = 1 << ((model->raw->types >>10) & 3); /* bone index size */ model->nb_s = 1 << ((model->raw->types >>12) & 3); /* number of bones per vertex */ model->sk_s = 1 << ((model->raw->types >>14) & 3); /* skin index size */ - model->fi_s = 1 << ((model->raw->types >>16) & 3); /* frame counter size */ + model->fc_s = 1 << ((model->raw->types >>16) & 3); /* frame counter size */ + model->hi_s = 1 << ((model->raw->types >>18) & 3); /* shape index size */ + model->fi_s = 1 << ((model->raw->types >>20) & 3); /* face index size */ if(model->ci_s == 8) model->ci_s = 0; /* optional indices */ if(model->ti_s == 8) model->ti_s = 0; if(model->bi_s == 8) model->bi_s = 0; if(model->sk_s == 8) model->sk_s = 0; + if(model->fc_s == 8) model->fc_s = 0; + if(model->hi_s == 8) model->hi_s = 0; if(model->fi_s == 8) model->fi_s = 0; /* variable limit checks */ @@ -2635,7 +2980,7 @@ asciiend: model->errcode = M3D_ERR_TRUNC; } if(sizeof(M3D_INDEX) == 2 && (model->vi_s > 2 || model->si_s > 2 || model->ci_s > 2 || model->ti_s > 2 || - model->bi_s > 2 || model->sk_s > 2 || model->fi_s > 2)) { + model->bi_s > 2 || model->sk_s > 2 || model->fc_s > 2 || model->hi_s > 2 || model->fi_s > 2)) { M3D_LOG("32 bit indices not supported, unable to load model"); M3D_FREE(model); return NULL; @@ -2646,7 +2991,7 @@ asciiend: return NULL; } if(model->nb_s > M3D_NUMBONE) { - M3D_LOG("Model has more bones per vertex than importer supports"); + M3D_LOG("Model has more bones per vertex than what importer was configured to support"); model->errcode = M3D_ERR_TRUNC; } @@ -2655,11 +3000,11 @@ asciiend: while(buff < end && !M3D_CHUNKMAGIC(buff, 'O','M','D','3')) { data = buff; len = ((m3dchunk_t*)data)->length; - if(len < sizeof(m3dchunk_t)) { + buff += len; + if(len < sizeof(m3dchunk_t) || buff >= end) { M3D_LOG("Invalid chunk size"); break; } - buff += len; len -= sizeof(m3dchunk_t) + model->si_s; /* inlined assets */ @@ -2685,13 +3030,18 @@ memerr: M3D_LOG("Out of memory"); while(chunk < end && !M3D_CHUNKMAGIC(chunk, 'O','M','D','3')) { data = chunk; len = ((m3dchunk_t*)chunk)->length; - if(len < sizeof(m3dchunk_t)) { + chunk += len; + if(len < sizeof(m3dchunk_t) || chunk >= end) { M3D_LOG("Invalid chunk size"); break; } - chunk += len; len -= sizeof(m3dchunk_t); + /* preview chunk */ + if(M3D_CHUNKMAGIC(data, 'P','R','V','W') && len > 0) { + model->preview.length = len; + model->preview.data = data + sizeof(m3dchunk_t); + } else /* color map */ if(M3D_CHUNKMAGIC(data, 'C','M','A','P')) { M3D_LOG("Color map"); @@ -2712,12 +3062,12 @@ memerr: M3D_LOG("Out of memory"); for(i = 0, data += sizeof(m3dchunk_t); data < chunk; i++) { switch(model->vc_s) { case 1: - model->tmap[i].u = (M3D_FLOAT)(data[0]) / 255; - model->tmap[i].v = (M3D_FLOAT)(data[1]) / 255; + model->tmap[i].u = (M3D_FLOAT)(data[0]) / (M3D_FLOAT)255.0; + model->tmap[i].v = (M3D_FLOAT)(data[1]) / (M3D_FLOAT)255.0; break; case 2: - model->tmap[i].u = (M3D_FLOAT)(*((int16_t*)(data+0))) / 65535; - model->tmap[i].v = (M3D_FLOAT)(*((int16_t*)(data+2))) / 65535; + model->tmap[i].u = (M3D_FLOAT)(*((int16_t*)(data+0))) / (M3D_FLOAT)65535.0; + model->tmap[i].v = (M3D_FLOAT)(*((int16_t*)(data+2))) / (M3D_FLOAT)65535.0; break; case 4: model->tmap[i].u = (M3D_FLOAT)(*((float*)(data+0))); @@ -2744,17 +3094,17 @@ memerr: M3D_LOG("Out of memory"); for(i = 0, data += sizeof(m3dchunk_t); data < chunk && i < model->numvertex; i++) { switch(model->vc_s) { case 1: - model->vertex[i].x = (M3D_FLOAT)((int8_t)data[0]) / 127; - model->vertex[i].y = (M3D_FLOAT)((int8_t)data[1]) / 127; - model->vertex[i].z = (M3D_FLOAT)((int8_t)data[2]) / 127; - model->vertex[i].w = (M3D_FLOAT)((int8_t)data[3]) / 127; + model->vertex[i].x = (M3D_FLOAT)((int8_t)data[0]) / (M3D_FLOAT)127.0; + model->vertex[i].y = (M3D_FLOAT)((int8_t)data[1]) / (M3D_FLOAT)127.0; + model->vertex[i].z = (M3D_FLOAT)((int8_t)data[2]) / (M3D_FLOAT)127.0; + model->vertex[i].w = (M3D_FLOAT)((int8_t)data[3]) / (M3D_FLOAT)127.0; data += 4; break; case 2: - model->vertex[i].x = (M3D_FLOAT)((int16_t)((data[1]<<8)|data[0])) / 32767; - model->vertex[i].y = (M3D_FLOAT)((int16_t)((data[3]<<8)|data[2])) / 32767; - model->vertex[i].z = (M3D_FLOAT)((int16_t)((data[5]<<8)|data[4])) / 32767; - model->vertex[i].w = (M3D_FLOAT)((int16_t)((data[7]<<8)|data[6])) / 32767; + model->vertex[i].x = (M3D_FLOAT)(*((int16_t*)(data+0))) / (M3D_FLOAT)32767.0; + model->vertex[i].y = (M3D_FLOAT)(*((int16_t*)(data+2))) / (M3D_FLOAT)32767.0; + model->vertex[i].z = (M3D_FLOAT)(*((int16_t*)(data+4))) / (M3D_FLOAT)32767.0; + model->vertex[i].w = (M3D_FLOAT)(*((int16_t*)(data+6))) / (M3D_FLOAT)32767.0; data += 8; break; case 4: @@ -2778,7 +3128,7 @@ memerr: M3D_LOG("Out of memory"); case 4: model->vertex[i].color = *((uint32_t*)data); data += 4; break; /* case 8: break; */ } - model->vertex[i].skinid = (M3D_INDEX)-1U; + model->vertex[i].skinid = M3D_UNDEF; data = _m3d_getidx(data, model->sk_s, &model->vertex[i].skinid); } } else @@ -2797,15 +3147,6 @@ memerr: M3D_LOG("Out of memory"); } model->numskin = 0; data = _m3d_getidx(data, model->sk_s, &model->numskin); - if(model->numskin) { - model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t)); - if(!model->skin) goto memerr; - for(i = 0; i < model->numskin; i++) - for(j = 0; j < M3D_NUMBONE; j++) { - model->skin[i].boneid[j] = (M3D_INDEX)-1U; - model->skin[i].weight[j] = (M3D_FLOAT)0.0; - } - } /* read bone hierarchy */ for(i = 0; i < model->numbone; i++) { data = _m3d_getidx(data, model->bi_s, &model->bone[i].parent); @@ -2816,41 +3157,55 @@ memerr: M3D_LOG("Out of memory"); model->bone[i].weight = NULL; } /* read skin definitions */ - for(i = 0; data < chunk && i < model->numskin; i++) { - memset(&weights, 0, sizeof(weights)); - if(model->nb_s == 1) weights[0] = 255; - else { - memcpy(&weights, data, model->nb_s); - data += model->nb_s; - } - for(j = 0; j < (unsigned int)model->nb_s; j++) { - if(weights[j]) { - if(j >= M3D_NUMBONE) - data += model->bi_s; - else { - model->skin[i].weight[j] = (M3D_FLOAT)(weights[j]) / 255; - data = _m3d_getidx(data, model->bi_s, &model->skin[i].boneid[j]); + if(model->numskin) { + model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t)); + if(!model->skin) goto memerr; + for(i = 0; data < chunk && i < model->numskin; i++) { + for(j = 0; j < M3D_NUMBONE; j++) { + model->skin[i].boneid[j] = M3D_UNDEF; + model->skin[i].weight[j] = (M3D_FLOAT)0.0; + } + memset(&weights, 0, sizeof(weights)); + if(model->nb_s == 1) weights[0] = 255; + else { + memcpy(&weights, data, model->nb_s); + data += model->nb_s; + } + for(j = 0, w = (M3D_FLOAT)0.0; j < (unsigned int)model->nb_s; j++) { + if(weights[j]) { + if(j >= M3D_NUMBONE) + data += model->bi_s; + else { + model->skin[i].weight[j] = (M3D_FLOAT)(weights[j]) / (M3D_FLOAT)255.0; + w += model->skin[i].weight[j]; + data = _m3d_getidx(data, model->bi_s, &model->skin[i].boneid[j]); + } } } + /* this can occur if model has more bones than what the importer is configured to handle */ + if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) { + for(j = 0; j < M3D_NUMBONE; j++) + model->skin[i].weight[j] /= w; + } } } } else /* material */ if(M3D_CHUNKMAGIC(data, 'M','T','R','L')) { data += sizeof(m3dchunk_t); - M3D_GETSTR(material); + M3D_GETSTR(name); M3D_LOG("Material"); - M3D_LOG(material); + M3D_LOG(name); if(model->ci_s < 4 && !model->numcmap) model->errcode = M3D_ERR_CMAP; for(i = 0; i < model->nummaterial; i++) - if(!strcmp(material, model->material[i].name)) { + if(!strcmp(name, model->material[i].name)) { model->errcode = M3D_ERR_MTRL; M3D_LOG("Multiple definitions for material"); - M3D_LOG(material); - material = NULL; + M3D_LOG(name); + name = NULL; break; } - if(material) { + if(name) { i = model->nummaterial++; if(model->flags & M3D_FLG_MTLLIB) { m = model->material; @@ -2870,9 +3225,8 @@ memerr: M3D_LOG("Out of memory"); } m = &model->material[i]; m->numprop = 0; - m->prop = NULL; - m->name = material; - m->prop = (m3dp_t*)M3D_REALLOC(m->prop, (len / 2) * sizeof(m3dp_t)); + m->name = name; + m->prop = (m3dp_t*)M3D_MALLOC((len / 2) * sizeof(m3dp_t)); if(!m->prop) goto memerr; while(data < chunk) { i = m->numprop++; @@ -2899,12 +3253,13 @@ memerr: M3D_LOG("Out of memory"); case m3dpf_float: m->prop[i].value.fnum = *((float*)data); data += 4; break; case m3dpf_map: - M3D_GETSTR(material); - m->prop[i].value.textureid = _m3d_gettx(model, readfilecb, freecb, material); + M3D_GETSTR(name); + m->prop[i].value.textureid = _m3d_gettx(model, readfilecb, freecb, name); if(model->errcode == M3D_ERR_ALLOC) goto memerr; - if(m->prop[i].value.textureid == (M3D_INDEX)-1U) { + /* this error code only returned if readfilecb was specified */ + if(m->prop[i].value.textureid == M3D_UNDEF) { M3D_LOG("Texture not found"); - M3D_LOG(material); + M3D_LOG(m->name); m->numprop--; } break; @@ -2924,16 +3279,16 @@ memerr: M3D_LOG("Out of memory"); /* face */ if(M3D_CHUNKMAGIC(data, 'P','R','O','C')) { /* procedural surface */ - M3D_GETSTR(material); + M3D_GETSTR(name); M3D_LOG("Procedural surface"); - M3D_LOG(material); - _m3d_getpr(model, readfilecb, freecb, material); + M3D_LOG(name); + _m3d_getpr(model, readfilecb, freecb, name); } else if(M3D_CHUNKMAGIC(data, 'M','E','S','H')) { M3D_LOG("Mesh data"); /* mesh */ data += sizeof(m3dchunk_t); - mi = (M3D_INDEX)-1U; + mi = M3D_UNDEF; am = model->numface; while(data < chunk) { k = *data++; @@ -2941,15 +3296,15 @@ memerr: M3D_LOG("Out of memory"); k &= 15; if(!n) { /* use material */ - mi = (M3D_INDEX)-1U; - M3D_GETSTR(material); - if(material) { + mi = M3D_UNDEF; + M3D_GETSTR(name); + if(name) { for(j = 0; j < model->nummaterial; j++) - if(!strcmp(material, model->material[j].name)) { + if(!strcmp(name, model->material[j].name)) { mi = (M3D_INDEX)j; break; } - if(mi == (M3D_INDEX)-1U) model->errcode = M3D_ERR_MTRL; + if(mi == M3D_UNDEF) model->errcode = M3D_ERR_MTRL; } continue; } @@ -2971,10 +3326,124 @@ memerr: M3D_LOG("Out of memory"); /* normal */ if(k & 2) data = _m3d_getidx(data, model->vi_s, &model->face[i].normal[j]); +#ifndef M3D_NONORMALS + if(model->face[i].normal[j] == M3D_UNDEF) neednorm = 1; +#endif } } model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t)); } else + if(M3D_CHUNKMAGIC(data, 'S','H','P','E')) { + /* mathematical shape */ + data += sizeof(m3dchunk_t); + M3D_GETSTR(name); + M3D_LOG("Mathematical Shape"); + M3D_LOG(name); + i = model->numshape++; + model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3dh_t)); + if(!model->shape) goto memerr; + h = &model->shape[i]; + h->numcmd = 0; + h->cmd = NULL; + h->name = name; + h->group = M3D_UNDEF; + data = _m3d_getidx(data, model->bi_s, &h->group); + if(h->group != M3D_UNDEF && h->group >= model->numbone) { + M3D_LOG("Unknown bone id as shape group in shape"); + M3D_LOG(name); + h->group = M3D_UNDEF; + model->errcode = M3D_ERR_SHPE; + } + while(data < chunk) { + i = h->numcmd++; + h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t)); + if(!h->cmd) goto memerr; + h->cmd[i].type = *data++; + if(h->cmd[i].type & 0x80) { + h->cmd[i].type &= 0x7F; + h->cmd[i].type |= (*data++ << 7); + } + if(h->cmd[i].type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0]))) { + M3D_LOG("Unknown shape command in"); + M3D_LOG(h->name); + model->errcode = M3D_ERR_UNKCMD; + break; + } + cd = &m3d_commandtypes[h->cmd[i].type]; + h->cmd[i].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t)); + if(!h->cmd[i].arg) goto memerr; + memset(h->cmd[i].arg, 0, cd->p * sizeof(uint32_t)); + for(k = n = 0, l = cd->p; k < l; k++) + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + h->cmd[i].arg[k] = M3D_NOTDEFINED; + M3D_GETSTR(name); + if(name) { + for(n = 0; n < model->nummaterial; n++) + if(!strcmp(name, model->material[n].name)) { + h->cmd[i].arg[k] = n; + break; + } + if(h->cmd[i].arg[k] == M3D_NOTDEFINED) model->errcode = M3D_ERR_MTRL; + } + break; + case m3dcp_vc_t: + f = 0.0f; + switch(model->vc_s) { + case 1: f = (float)((int8_t)data[0]) / 127; break; + case 2: f = (float)(*((int16_t*)(data+0))) / 32767; break; + case 4: f = (float)(*((float*)(data+0))); break; + case 8: f = (float)(*((double*)(data+0))); break; + } + h->cmd[i].arg[k] = *((uint32_t*)&f); + data += model->vc_s; + break; + case m3dcp_hi_t: data = _m3d_getidx(data, model->hi_s, &h->cmd[i].arg[k]); break; + case m3dcp_fi_t: data = _m3d_getidx(data, model->fi_s, &h->cmd[i].arg[k]); break; + case m3dcp_ti_t: data = _m3d_getidx(data, model->ti_s, &h->cmd[i].arg[k]); break; + case m3dcp_qi_t: + case m3dcp_vi_t: data = _m3d_getidx(data, model->vi_s, &h->cmd[i].arg[k]); break; + case m3dcp_i1_t: data = _m3d_getidx(data, 1, &h->cmd[i].arg[k]); break; + case m3dcp_i2_t: data = _m3d_getidx(data, 2, &h->cmd[i].arg[k]); break; + case m3dcp_i4_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); break; + case m3dcp_va_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); + n = k + 1; l += (h->cmd[i].arg[k] - 1) * (cd->p - k - 1); + h->cmd[i].arg = (uint32_t*)M3D_REALLOC(h->cmd[i].arg, l * sizeof(uint32_t)); + if(!h->cmd[i].arg) goto memerr; + memset(&h->cmd[i].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t)); + break; + } + } + } else + /* annotation label list */ + if(M3D_CHUNKMAGIC(data, 'L','B','L','S')) { + data += sizeof(m3dchunk_t); + M3D_GETSTR(name); + M3D_GETSTR(lang); + M3D_LOG("Label list"); + if(name) { M3D_LOG(name); } + if(lang) { M3D_LOG(lang); } + if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP; + k = 0; + switch(model->ci_s) { + case 1: k = model->cmap ? model->cmap[data[0]] : 0; data++; break; + case 2: k = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break; + case 4: k = *((uint32_t*)data); data += 4; break; + /* case 8: break; */ + } + reclen = model->vi_s + model->si_s; + i = model->numlabel; model->numlabel += len / reclen; + model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t)); + if(!model->label) goto memerr; + memset(&model->label[i], 0, (model->numlabel - i) * sizeof(m3dl_t)); + for(; data < chunk && i < model->numlabel; i++) { + model->label[i].name = name; + model->label[i].lang = lang; + model->label[i].color = k; + data = _m3d_getidx(data, model->vi_s, &model->label[i].vertexid); + M3D_GETSTR(model->label[i].text); + } + } else /* action */ if(M3D_CHUNKMAGIC(data, 'A','C','T','N')) { M3D_LOG("Action"); @@ -2995,7 +3464,7 @@ memerr: M3D_LOG("Out of memory"); for(i = 0; data < chunk && i < a->numframe; i++) { a->frame[i].msec = *((uint32_t*)data); data += 4; a->frame[i].numtransform = 0; a->frame[i].transform = NULL; - data = _m3d_getidx(data, model->fi_s, &a->frame[i].numtransform); + data = _m3d_getidx(data, model->fc_s, &a->frame[i].numtransform); if(a->frame[i].numtransform > 0) { a->frame[i].transform = (m3dtr_t*)M3D_MALLOC(a->frame[i].numtransform * sizeof(m3dtr_t)); for(j = 0; j < a->frame[i].numtransform; j++) { @@ -3007,10 +3476,10 @@ memerr: M3D_LOG("Out of memory"); } } } else { - i = model->numunknown++; - model->unknown = (m3dchunk_t**)M3D_REALLOC(model->unknown, model->numunknown * sizeof(m3dchunk_t*)); - if(!model->unknown) goto memerr; - model->unknown[i] = (m3dchunk_t*)data; + i = model->numextra++; + model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*)); + if(!model->extra) goto memerr; + model->extra[i] = (m3dchunk_t*)data; } } /* calculate normals, normalize skin weights, create bone/vertex cross-references and calculate transform matrices */ @@ -3018,64 +3487,69 @@ memerr: M3D_LOG("Out of memory"); postprocess: #endif if(model) { + M3D_LOG("Post-process"); +#ifdef M3D_PROFILING + gettimeofday(&tv1, NULL); + tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; + tvd.tv_usec = tv1.tv_usec - tv0.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + printf(" Parsing chunks %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); +#endif #ifndef M3D_NONORMALS - if(model->numface && model->face) { - memset(&vn, 0, sizeof(m3dv_t)); + if(model->numface && model->face && neednorm) { /* if they are missing, calculate triangle normals into a temporary buffer */ - for(i = numnorm = 0; i < model->numface; i++) - if(model->face[i].normal[0] == -1U) { - v0 = &model->vertex[model->face[i].vertex[0]]; v1 = &model->vertex[model->face[i].vertex[1]]; + norm = (m3dv_t*)M3D_MALLOC(model->numface * sizeof(m3dv_t)); + if(!norm) goto memerr; + for(i = 0, n = model->numvertex; i < model->numface; i++) + if(model->face[i].normal[0] == M3D_UNDEF) { + v0 = &model->vertex[model->face[i].vertex[0]]; + v1 = &model->vertex[model->face[i].vertex[1]]; v2 = &model->vertex[model->face[i].vertex[2]]; va.x = v1->x - v0->x; va.y = v1->y - v0->y; va.z = v1->z - v0->z; vb.x = v2->x - v0->x; vb.y = v2->y - v0->y; vb.z = v2->z - v0->z; - vn.x = (va.y * vb.z) - (va.z * vb.y); - vn.y = (va.z * vb.x) - (va.x * vb.z); - vn.z = (va.x * vb.y) - (va.y * vb.x); - w = _m3d_rsq((vn.x * vn.x) + (vn.y * vn.y) + (vn.z * vn.z)); - vn.x *= w; vn.y *= w; vn.z *= w; - norm = _m3d_addnorm(norm, &numnorm, &vn, &j); - if(!ni) { - ni = (M3D_INDEX*)M3D_MALLOC(model->numface * sizeof(M3D_INDEX)); - if(!ni) goto memerr; - } - ni[i] = j; + v0 = &norm[i]; + v0->x = (va.y * vb.z) - (va.z * vb.y); + v0->y = (va.z * vb.x) - (va.x * vb.z); + v0->z = (va.x * vb.y) - (va.y * vb.x); + w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); + v0->x *= w; v0->y *= w; v0->z *= w; + model->face[i].normal[0] = model->face[i].vertex[0] + n; + model->face[i].normal[1] = model->face[i].vertex[1] + n; + model->face[i].normal[2] = model->face[i].vertex[2] + n; } - if(ni && norm) { - vi = (M3D_INDEX*)M3D_MALLOC(model->numvertex * sizeof(M3D_INDEX)); - if(!vi) goto memerr; - /* for each vertex, take the average of the temporary normals and use that */ - for(i = 0, n = model->numvertex; i < n; i++) { - memset(&vn, 0, sizeof(m3dv_t)); - for(j = 0; j < model->numface; j++) - for(k = 0; k < 3; k++) - if(model->face[j].vertex[k] == i) { - vn.x += norm[ni[j]].x; - vn.y += norm[ni[j]].y; - vn.z += norm[ni[j]].z; - } - w = _m3d_rsq((vn.x * vn.x) + (vn.y * vn.y) + (vn.z * vn.z)); - vn.x *= w; vn.y *= w; vn.z *= w; - vn.skinid = -1U; - model->vertex = _m3d_addnorm(model->vertex, &model->numvertex, &vn, &vi[i]); + /* this is the fast way, we don't care if a normal is repeated in model->vertex */ + M3D_LOG("Generating normals"); + model->flags |= M3D_FLG_GENNORM; + model->numvertex <<= 1; + model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t)); + if(!model->vertex) goto memerr; + memset(&model->vertex[n], 0, n * sizeof(m3dv_t)); + for(i = 0; i < model->numface; i++) + for(j = 0; j < 3; j++) { + v0 = &model->vertex[model->face[i].vertex[j] + n]; + v0->x += norm[i].x; + v0->y += norm[i].y; + v0->z += norm[i].z; } - for(j = 0; j < model->numface; j++) - for(k = 0; k < 3; k++) - model->face[j].normal[k] = vi[model->face[j].vertex[k]]; - M3D_FREE(norm); - M3D_FREE(ni); - M3D_FREE(vi); + /* for each vertex, take the average of the temporary normals and use that */ + for(i = 0, v0 = &model->vertex[n]; i < n; i++, v0++) { + w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z)); + v0->x *= w; v0->y *= w; v0->z *= w; + v0->skinid = M3D_UNDEF; } + M3D_FREE(norm); } #endif if(model->numbone && model->bone && model->numskin && model->skin && model->numvertex && model->vertex) { #ifndef M3D_NOWEIGHTS + M3D_LOG("Generating weight cross-reference"); for(i = 0; i < model->numvertex; i++) { - if(model->vertex[i].skinid < M3D_INDEXMAX) { + if(model->vertex[i].skinid < model->numskin) { sk = &model->skin[model->vertex[i].skinid]; w = (M3D_FLOAT)0.0; - for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != (M3D_INDEX)-1U && sk->weight[j] > (M3D_FLOAT)0.0; j++) + for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++) w += sk->weight[j]; - for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != (M3D_INDEX)-1U && sk->weight[j] > (M3D_FLOAT)0.0; j++) { + for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++) { sk->weight[j] /= w; b = &model->bone[sk->boneid[j]]; k = b->numweight++; @@ -3088,9 +3562,10 @@ postprocess: } #endif #ifndef M3D_NOANIMATION + M3D_LOG("Calculating bone transformation matrices"); for(i = 0; i < model->numbone; i++) { b = &model->bone[i]; - if(model->bone[i].parent == (M3D_INDEX)-1U) { + if(model->bone[i].parent == M3D_UNDEF) { _m3d_mat((M3D_FLOAT*)&b->mat4, &model->vertex[b->pos], &model->vertex[b->ori]); } else { _m3d_mat((M3D_FLOAT*)&r, &model->vertex[b->pos], &model->vertex[b->ori]); @@ -3101,6 +3576,13 @@ postprocess: _m3d_inv((M3D_FLOAT*)&model->bone[i].mat4); #endif } +#ifdef M3D_PROFILING + gettimeofday(&tv0, NULL); + tvd.tv_sec = tv0.tv_sec - tv1.tv_sec; + tvd.tv_usec = tv0.tv_usec - tv1.tv_usec; + if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; } + printf(" Post-process %ld.%06ld sec\n", tvd.tv_sec, tvd.tv_usec); +#endif } return model; } @@ -3114,7 +3596,7 @@ m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t M3D_INDEX s = frameid; m3dfr_t *fr; - if(!model || !model->numbone || !model->bone || (actionid != (M3D_INDEX)-1U && (!model->action || + if(!model || !model->numbone || !model->bone || (actionid != M3D_UNDEF && (!model->action || actionid >= model->numaction || frameid >= model->action[actionid].numframe))) { model->errcode = M3D_ERR_UNKFRAME; return skeleton; @@ -3128,7 +3610,7 @@ m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t } goto gen; } - if(actionid == (M3D_INDEX)-1U || !frameid) { + if(actionid == M3D_UNDEF || !frameid) { gen: s = 0; for(i = 0; i < model->numbone; i++) { skeleton[i].boneid = i; @@ -3155,7 +3637,7 @@ gen: s = 0; m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) { unsigned int i, j, l; - M3D_FLOAT r[16], t, d; + M3D_FLOAT r[16], t, c, d, s; m3db_t *ret; m3dv_t *v, *p, *f; m3dtr_t *tmp; @@ -3208,7 +3690,7 @@ m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) tmp[fr->transform[i].boneid].ori = fr->transform[i].ori; } for(i = 0, j = model->numvertex; i < model->numbone; i++) { - /* LERP interpolation of position */ + /* interpolation of position */ if(ret[i].pos != tmp[i].pos) { p = &model->vertex[ret[i].pos]; f = &model->vertex[tmp[i].pos]; @@ -3218,18 +3700,33 @@ m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) v->z = p->z + t * (f->z - p->z); ret[i].pos = j++; } - /* NLERP interpolation of orientation (could have used SLERP, that's nicer, but slower) */ + /* interpolation of orientation */ if(ret[i].ori != tmp[i].ori) { p = &model->vertex[ret[i].ori]; f = &model->vertex[tmp[i].ori]; v = &model->vertex[j]; - d = (p->w * f->w + p->x * f->x + p->y * f->y + p->z * f->z < 0) ? (M3D_FLOAT)-1.0 : (M3D_FLOAT)1.0; - v->x = p->x + t * (d*f->x - p->x); - v->y = p->y + t * (d*f->y - p->y); - v->z = p->z + t * (d*f->z - p->z); - v->w = p->w + t * (d*f->w - p->w); + d = p->w * f->w + p->x * f->x + p->y * f->y + p->z * f->z; + if(d < 0) { d = -d; s = (M3D_FLOAT)-1.0; } else s = (M3D_FLOAT)1.0; +#if 0 + /* don't use SLERP, requires two more variables, libm linkage and it is slow (but nice) */ + a = (M3D_FLOAT)1.0 - t; b = t; + if(d < (M3D_FLOAT)0.999999) { c = acosf(d); b = 1 / sinf(c); a = sinf(a * c) * b; b *= sinf(t * c) * s; } + v->x = p->x * a + f->x * b; + v->y = p->y * a + f->y * b; + v->z = p->z * a + f->z * b; + v->w = p->w * a + f->w * b; +#else + /* approximated NLERP, original approximation by Arseny Kapoulkine, heavily optimized by me */ + c = t - (M3D_FLOAT)0.5; t += t * c * (t - (M3D_FLOAT)1.0) * (((M3D_FLOAT)1.0904 + d * ((M3D_FLOAT)-3.2452 + + d * ((M3D_FLOAT)3.55645 - d * (M3D_FLOAT)1.43519))) * c * c + ((M3D_FLOAT)0.848013 + d * + ((M3D_FLOAT)-1.06021 + d * (M3D_FLOAT)0.215638))); + v->x = p->x + t * (s * f->x - p->x); + v->y = p->y + t * (s * f->y - p->y); + v->z = p->z + t * (s * f->z - p->z); + v->w = p->w + t * (s * f->w - p->w); d = _m3d_rsq(v->w * v->w + v->x * v->x + v->y * v->y + v->z * v->z); v->x *= d; v->y *= d; v->z *= d; v->w *= d; +#endif ret[i].ori = j++; } } @@ -3237,7 +3734,7 @@ m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec) } } for(i = 0; i < model->numbone; i++) { - if(ret[i].parent == (M3D_INDEX)-1U) { + if(ret[i].parent == M3D_UNDEF) { _m3d_mat((M3D_FLOAT*)&ret[i].mat4, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]); } else { _m3d_mat((M3D_FLOAT*)&r, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]); @@ -3271,6 +3768,10 @@ void m3d_free(m3d_t *model) for(i = 0; i < model->numbone; i++) if(model->bone[i].name) M3D_FREE(model->bone[i].name); + if(model->shape) + for(i = 0; i < model->numshape; i++) + if(model->shape[i].name) + M3D_FREE(model->shape[i].name); if(model->material) for(i = 0; i < model->nummaterial; i++) if(model->material[i].name) @@ -3283,10 +3784,36 @@ void m3d_free(m3d_t *model) for(i = 0; i < model->numtexture; i++) if(model->texture[i].name) M3D_FREE(model->texture[i].name); - if(model->unknown) - for(i = 0; i < model->numunknown; i++) - if(model->unknown[i]) - M3D_FREE(model->unknown[i]); + if(model->inlined) + for(i = 0; i < model->numinlined; i++) { + if(model->inlined[i].name) + M3D_FREE(model->inlined[i].name); + if(model->inlined[i].data) + M3D_FREE(model->inlined[i].data); + } + if(model->extra) + for(i = 0; i < model->numextra; i++) + if(model->extra[i]) + M3D_FREE(model->extra[i]); + if(model->label) + for(i = 0; i < model->numlabel; i++) { + if(model->label[i].name) { + for(j = i + 1; j < model->numlabel; j++) + if(model->label[j].name == model->label[i].name) + model->label[j].name = NULL; + M3D_FREE(model->label[i].name); + } + if(model->label[i].lang) { + for(j = i + 1; j < model->numlabel; j++) + if(model->label[j].lang == model->label[i].lang) + model->label[j].lang = NULL; + M3D_FREE(model->label[i].lang); + } + if(model->label[i].text) + M3D_FREE(model->label[i].text); + } + if(model->preview.data) + M3D_FREE(model->preview.data); } #endif if(model->flags & M3D_FLG_FREERAW) M3D_FREE(model->raw); @@ -3301,6 +3828,16 @@ void m3d_free(m3d_t *model) if(model->skin) M3D_FREE(model->skin); if(model->vertex) M3D_FREE(model->vertex); if(model->face) M3D_FREE(model->face); + if(model->shape) { + for(i = 0; i < model->numshape; i++) { + if(model->shape[i].cmd) { + for(j = 0; j < model->shape[i].numcmd; j++) + if(model->shape[i].cmd[j].arg) M3D_FREE(model->shape[i].cmd[j].arg); + M3D_FREE(model->shape[i].cmd); + } + } + M3D_FREE(model->shape); + } if(model->material && !(model->flags & M3D_FLG_MTLLIB)) { for(i = 0; i < model->nummaterial; i++) if(model->material[i].prop) M3D_FREE(model->material[i].prop); @@ -3321,8 +3858,9 @@ void m3d_free(m3d_t *model) } M3D_FREE(model->action); } + if(model->label) M3D_FREE(model->label); if(model->inlined) M3D_FREE(model->inlined); - if(model->unknown) M3D_FREE(model->unknown); + if(model->extra) M3D_FREE(model->extra); free(model); } #endif @@ -3333,6 +3871,31 @@ typedef struct { uint32_t offs; } m3dstr_t; +typedef struct { + m3dti_t data; + M3D_INDEX oldidx; + M3D_INDEX newidx; +} m3dtisave_t; + +typedef struct { + m3dv_t data; + M3D_INDEX oldidx; + M3D_INDEX newidx; + unsigned char norm; +} m3dvsave_t; + +typedef struct { + m3ds_t data; + M3D_INDEX oldidx; + M3D_INDEX newidx; +} m3dssave_t; + +typedef struct { + m3df_t data; + int group; + uint8_t opacity; +} m3dfsave_t; + /* create unique list of strings */ static m3dstr_t *_m3d_addstr(m3dstr_t *str, uint32_t *numstr, char *s) { @@ -3354,7 +3917,7 @@ m3dhdr_t *_m3d_addhdr(m3dhdr_t *h, m3dstr_t *s) { int i; char *safe = _m3d_safestr(s->str, 0); - i = strlen(safe); + i = (int)strlen(safe); h = (m3dhdr_t*)M3D_REALLOC(h, h->length + i+1); if(!h) { M3D_FREE(safe); return NULL; } memcpy((uint8_t*)h + h->length, safe, i+1); @@ -3387,6 +3950,41 @@ static uint32_t _m3d_stridx(m3dstr_t *str, uint32_t numstr, char *s) return 0; } +/* compare to faces by their material */ +static int _m3d_facecmp(const void *a, const void *b) { + const m3dfsave_t *A = (const m3dfsave_t*)a, *B = (const m3dfsave_t*)b; + return A->group != B->group ? A->group - B->group : (A->opacity != B->opacity ? (int)B->opacity - (int)A->opacity : + (int)A->data.materialid - (int)B->data.materialid); +} +/* compare face groups */ +static int _m3d_grpcmp(const void *a, const void *b) { return *((uint32_t*)a) - *((uint32_t*)b); } +/* compare UVs */ +static int _m3d_ticmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3dti_t)); } +/* compare skin groups */ +static int _m3d_skincmp(const void *a, const void *b) { return memcmp(a, b, sizeof(m3ds_t)); } +/* compare vertices */ +static int _m3d_vrtxcmp(const void *a, const void *b) { + int c = memcmp(a, b, 3 * sizeof(M3D_FLOAT)); + if(c) return c; + c = ((m3dvsave_t*)a)->norm - ((m3dvsave_t*)b)->norm; + if(c) return c; + return memcmp(a, b, sizeof(m3dv_t)); +} +/* compare labels */ +static _inline int _m3d_strcmp(char *a, char *b) +{ + if(a == NULL && b != NULL) return -1; + if(a != NULL && b == NULL) return 1; + if(a == NULL && b == NULL) return 0; + return strcmp(a, b); +} +static int _m3d_lblcmp(const void *a, const void *b) { + const m3dl_t *A = (const m3dl_t*)a, *B = (const m3dl_t*)b; + int c = _m3d_strcmp(A->lang, B->lang); + if(!c) c = _m3d_strcmp(A->name, B->name); + if(!c) c = _m3d_strcmp(A->text, B->text); + return c; +} /* compare two colors by HSV value */ _inline static int _m3d_cmapcmp(const void *a, const void *b) { @@ -3421,60 +4019,13 @@ static uint32_t *_m3d_addcmap(uint32_t *cmap, uint32_t *numcmap, uint32_t color) static uint32_t _m3d_cmapidx(uint32_t *cmap, uint32_t numcmap, uint32_t color) { uint32_t i; + if(numcmap >= 65536) + return color; for(i = 0; i < numcmap; i++) if(cmap[i] == color) return i; return 0; } -/* add vertex to list */ -static m3dv_t *_m3d_addvrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx) -{ - uint32_t i; - if(v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0; - if(v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0; - if(v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0; - if(v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0; - if(vrtx) { - for(i = 0; i < *numvrtx; i++) - if(!memcmp(&vrtx[i], v, sizeof(m3dv_t))) { *idx = i; return vrtx; } - } - vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t)); - memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t)); - *idx = *numvrtx; - (*numvrtx)++; - return vrtx; -} - -/* add texture map to list */ -static m3dti_t *_m3d_addtmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *t, uint32_t *idx) -{ - uint32_t i; - if(tmap) { - for(i = 0; i < *numtmap; i++) - if(!memcmp(&tmap[i], t, sizeof(m3dti_t))) { *idx = i; return tmap; } - } - tmap = (m3dti_t*)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t)); - memcpy(&tmap[*numtmap], t, sizeof(m3dti_t)); - *idx = *numtmap; - (*numtmap)++; - return tmap; -} - -/* add material to list */ -static m3dm_t **_m3d_addmtrl(m3dm_t **mtrl, uint32_t *nummtrl, m3dm_t *m, uint32_t *idx) -{ - uint32_t i; - if(mtrl) { - for(i = 0; i < *nummtrl; i++) - if(mtrl[i]->name == m->name || !strcmp(mtrl[i]->name, m->name)) { *idx = i; return mtrl; } - } - mtrl = (m3dm_t**)M3D_REALLOC(mtrl, ((*nummtrl) + 1) * sizeof(m3dm_t*)); - mtrl[*nummtrl] = m; - *idx = *nummtrl; - (*nummtrl)++; - return mtrl; -} - /* add index to output */ static unsigned char *_m3d_addidx(unsigned char *out, char type, uint32_t idx) { switch(type) { @@ -3495,23 +4046,27 @@ static void _m3d_round(int quality, m3dv_t *src, m3dv_t *dst) /* round according to quality */ switch(quality) { case M3D_EXP_INT8: - t = src->x * 127; dst->x = (M3D_FLOAT)t / 127; - t = src->y * 127; dst->y = (M3D_FLOAT)t / 127; - t = src->z * 127; dst->z = (M3D_FLOAT)t / 127; - t = src->w * 127; dst->w = (M3D_FLOAT)t / 127; + t = (int)(src->x * 127 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->x = (M3D_FLOAT)t / (M3D_FLOAT)127.0; + t = (int)(src->y * 127 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->y = (M3D_FLOAT)t / (M3D_FLOAT)127.0; + t = (int)(src->z * 127 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->z = (M3D_FLOAT)t / (M3D_FLOAT)127.0; + t = (int)(src->w * 127 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->w = (M3D_FLOAT)t / (M3D_FLOAT)127.0; break; case M3D_EXP_INT16: - t = src->x * 32767; dst->x = (M3D_FLOAT)t / 32767; - t = src->y * 32767; dst->y = (M3D_FLOAT)t / 32767; - t = src->z * 32767; dst->z = (M3D_FLOAT)t / 32767; - t = src->w * 32767; dst->w = (M3D_FLOAT)t / 32767; + t = (int)(src->x * 32767 + (src->x >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->x = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; + t = (int)(src->y * 32767 + (src->y >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->y = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; + t = (int)(src->z * 32767 + (src->z >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->z = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; + t = (int)(src->w * 32767 + (src->w >= 0 ? (M3D_FLOAT)0.5 : (M3D_FLOAT)-0.5)); dst->w = (M3D_FLOAT)t / (M3D_FLOAT)32767.0; break; } + if(dst->x == (M3D_FLOAT)-0.0) dst->x = (M3D_FLOAT)0.0; + if(dst->y == (M3D_FLOAT)-0.0) dst->y = (M3D_FLOAT)0.0; + if(dst->z == (M3D_FLOAT)-0.0) dst->z = (M3D_FLOAT)0.0; + if(dst->w == (M3D_FLOAT)-0.0) dst->w = (M3D_FLOAT)0.0; } #ifdef M3D_ASCII /* add a bone to ascii output */ -static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX parent, uint32_t level) +static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX parent, uint32_t level, M3D_INDEX *vrtxidx) { uint32_t i, j; char *sn; @@ -3521,9 +4076,9 @@ static char *_m3d_prtbone(char *ptr, m3db_t *bone, M3D_INDEX numbone, M3D_INDEX if(bone[i].parent == parent) { for(j = 0; j < level; j++) *ptr++ = '/'; sn = _m3d_safestr(bone[i].name, 0); - ptr += sprintf(ptr, "%d %d %s\r\n", bone[i].pos, bone[i].ori, sn); + ptr += sprintf(ptr, "%d %d %s\r\n", vrtxidx[bone[i].pos], vrtxidx[bone[i].ori], sn); M3D_FREE(sn); - ptr = _m3d_prtbone(ptr, bone, numbone, i, level + 1); + ptr = _m3d_prtbone(ptr, bone, numbone, i, level + 1, vrtxidx); } } return ptr; @@ -3539,23 +4094,25 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size const char *ol; char *ptr; #endif - char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fi_s; + char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s; char *sn = NULL, *sl = NULL, *sa = NULL, *sd = NULL; - unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE]; - unsigned int i, j, k, l, len, chunklen, *length; - float scale = 0.0f, min_x, max_x, min_y, max_y, min_z, max_z; - uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, numtmap = 0, numbone = 0; - uint32_t numskin = 0, numactn = 0, *actn = NULL, numstr = 0, nummtrl = 0, maxt = 0; + unsigned char *out = NULL, *z = NULL, weights[M3D_NUMBONE], *norm = NULL; + unsigned int i, j, k, l, n, len, chunklen, *length; + M3D_FLOAT scale = (M3D_FLOAT)0.0, min_x, max_x, min_y, max_y, min_z, max_z; + M3D_INDEX last, *vrtxidx = NULL, *mtrlidx = NULL, *tmapidx = NULL, *skinidx = NULL; + uint32_t idx, numcmap = 0, *cmap = NULL, numvrtx = 0, maxvrtx = 0, numtmap = 0, maxtmap = 0, numproc = 0; + uint32_t numskin = 0, maxskin = 0, numstr = 0, maxt = 0, maxbone = 0, numgrp = 0, maxgrp = 0, *grpidx = NULL; + uint8_t *opa; + m3dcd_t *cd; + m3dc_t *cmd; m3dstr_t *str = NULL; - m3dv_t *vrtx = NULL, vertex; - m3dti_t *tmap = NULL, tcoord; - m3db_t *bone = NULL; - m3ds_t *skin = NULL; - m3df_t *face = NULL; + m3dvsave_t *vrtx = NULL, vertex; + m3dtisave_t *tmap = NULL, tcoord; + m3dssave_t *skin = NULL, sk; + m3dfsave_t *face = NULL; m3dhdr_t *h = NULL; - m3dm_t *m, **mtrl = NULL; + m3dm_t *m; m3da_t *a; - M3D_INDEX last; if(!model) { if(size) *size = 0; @@ -3565,235 +4122,417 @@ unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size #ifdef M3D_ASCII if(flags & M3D_EXP_ASCII) quality = M3D_EXP_DOUBLE; #endif - /* collect array elements that are actually referenced */ - if(model->numface && model->face && !(flags & M3D_EXP_NOFACE)) { - face = (m3df_t*)M3D_MALLOC(model->numface * sizeof(m3df_t)); - if(!face) goto memerr; - memset(face, 255, model->numface * sizeof(m3df_t)); - last = (M3D_INDEX)-1U; - for(i = 0; i < model->numface; i++) { - face[i].materialid = (M3D_INDEX)-1U; - if(!(flags & M3D_EXP_NOMATERIAL) && model->face[i].materialid != last) { - last = model->face[i].materialid; - if(last < model->nummaterial) { - mtrl = _m3d_addmtrl(mtrl, &nummtrl, &model->material[last], &face[i].materialid); - if(!mtrl) goto memerr; + vrtxidx = (M3D_INDEX*)M3D_MALLOC(model->numvertex * sizeof(M3D_INDEX)); + if(!vrtxidx) goto memerr; + memset(vrtxidx, 255, model->numvertex * sizeof(M3D_INDEX)); + if(model->numvertex && !(flags & M3D_EXP_NONORMAL)){ + norm = (unsigned char*)M3D_MALLOC(model->numvertex * sizeof(unsigned char)); + if(!norm) goto memerr; + memset(norm, 0, model->numvertex * sizeof(unsigned char)); + } + if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { + mtrlidx = (M3D_INDEX*)M3D_MALLOC(model->nummaterial * sizeof(M3D_INDEX)); + if(!mtrlidx) goto memerr; + memset(mtrlidx, 255, model->nummaterial * sizeof(M3D_INDEX)); + opa = (uint8_t*)M3D_MALLOC(model->nummaterial * 2 * sizeof(M3D_INDEX)); + if(!opa) goto memerr; + memset(opa, 255, model->nummaterial * 2 * sizeof(M3D_INDEX)); + } + if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) { + tmapidx = (M3D_INDEX*)M3D_MALLOC(model->numtmap * sizeof(M3D_INDEX)); + if(!tmapidx) goto memerr; + memset(tmapidx, 255, model->numtmap * sizeof(M3D_INDEX)); + } + /** collect array elements that are actually referenced **/ + if(!(flags & M3D_EXP_NOFACE)) { + /* face */ + if(model->numface && model->face) { + M3D_LOG("Processing mesh face"); + face = (m3dfsave_t*)M3D_MALLOC(model->numface * sizeof(m3dfsave_t)); + if(!face) goto memerr; + for(i = 0; i < model->numface; i++) { + memcpy(&face[i].data, &model->face[i], sizeof(m3df_t)); + face[i].group = 0; + face[i].opacity = 255; + if(!(flags & M3D_EXP_NOMATERIAL) && model->face[i].materialid < model->nummaterial) { + if(model->material[model->face[i].materialid].numprop) { + mtrlidx[model->face[i].materialid] = 0; + if(opa[model->face[i].materialid * 2]) { + m = &model->material[model->face[i].materialid]; + for(j = 0; j < m->numprop; j++) + if(m->prop[j].type == m3dp_Kd) { + opa[model->face[i].materialid * 2 + 1] = ((uint8_t*)&m->prop[j].value.color)[3]; + break; + } + for(j = 0; j < m->numprop; j++) + if(m->prop[j].type == m3dp_d) { + opa[model->face[i].materialid * 2 + 1] = (uint8_t)(m->prop[j].value.fnum * 255); + break; + } + opa[model->face[i].materialid * 2] = 0; + } + face[i].opacity = opa[model->face[i].materialid * 2 + 1]; + } else + face[i].data.materialid = M3D_UNDEF; + } + for(j = 0; j < 3; j++) { + k = model->face[i].vertex[j]; + if(k < model->numvertex) + vrtxidx[k] = 0; + if(!(flags & M3D_EXP_NOCMAP)) { + cmap = _m3d_addcmap(cmap, &numcmap, model->vertex[k].color); + if(!cmap) goto memerr; + } + k = model->face[i].normal[j]; + if(k < model->numvertex && !(flags & M3D_EXP_NONORMAL)) { + vrtxidx[k] = 0; + norm[k] = 1; + } + k = model->face[i].texcoord[j]; + if(k < model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) + tmapidx[k] = 0; + } + /* convert from CW to CCW */ + if(flags & M3D_EXP_IDOSUCK) { + j = face[i].data.vertex[1]; + face[i].data.vertex[1] = face[i].data.vertex[2]; + face[i].data.vertex[2] = face[i].data.vertex[1]; + j = face[i].data.normal[1]; + face[i].data.normal[1] = face[i].data.normal[2]; + face[i].data.normal[2] = face[i].data.normal[1]; + j = face[i].data.texcoord[1]; + face[i].data.texcoord[1] = face[i].data.texcoord[2]; + face[i].data.texcoord[2] = face[i].data.texcoord[1]; } } - for(j = 0; j < 3; j++) { - k = model->face[i].vertex[j]; - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[k], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &idx); - } else - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[k], &idx); - if(!vrtx) goto memerr; - face[i].vertex[j] = (M3D_INDEX)idx; + } + if(model->numshape && model->shape) { + M3D_LOG("Processing shape face"); + for(i = 0; i < model->numshape; i++) { + if(!model->shape[i].numcmd) continue; + str = _m3d_addstr(str, &numstr, model->shape[i].name); + if(!str) goto memerr; + for(j = 0; j < model->shape[i].numcmd; j++) { + cmd = &model->shape[i].cmd[j]; + if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) + continue; + if(cmd->type == m3dc_mesh) { + if(numgrp + 2 < maxgrp) { + maxgrp += 1024; + grpidx = (uint32_t*)realloc(grpidx, maxgrp * sizeof(uint32_t)); + if(!grpidx) goto memerr; + if(!numgrp) { + grpidx[0] = 0; + grpidx[1] = model->numface; + numgrp += 2; + } + } + grpidx[numgrp + 0] = cmd->arg[0]; + grpidx[numgrp + 1] = cmd->arg[0] + cmd->arg[1]; + numgrp += 2; + } + cd = &m3d_commandtypes[cmd->type]; + for(k = n = 0, l = cd->p; k < l; k++) + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + if(!(flags & M3D_EXP_NOMATERIAL) && cmd->arg[k] < model->nummaterial) + mtrlidx[cmd->arg[k]] = 0; + break; + case m3dcp_ti_t: + if(!(flags & M3D_EXP_NOTXTCRD) && cmd->arg[k] < model->numtmap) + tmapidx[cmd->arg[k]] = 0; + break; + case m3dcp_qi_t: + case m3dcp_vi_t: + if(cmd->arg[k] < model->numvertex) + vrtxidx[cmd->arg[k]] = 0; + break; + case m3dcp_va_t: + n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); + break; + } + } + } + } + if(model->numface && face) { + if(numgrp && grpidx) { + qsort(grpidx, numgrp, sizeof(uint32_t), _m3d_grpcmp); + for(i = j = 0; i < model->numface && j < numgrp; i++) { + while(j < numgrp && grpidx[j] < i) j++; + face[i].group = j; + } + } + qsort(face, model->numface, sizeof(m3dfsave_t), _m3d_facecmp); + } + if(grpidx) { M3D_FREE(grpidx); grpidx = NULL; } + if(model->numlabel && model->label) { + M3D_LOG("Processing annotation labels"); + for(i = 0; i < model->numlabel; i++) { + str = _m3d_addstr(str, &numstr, model->label[i].name); + str = _m3d_addstr(str, &numstr, model->label[i].lang); + str = _m3d_addstr(str, &numstr, model->label[i].text); if(!(flags & M3D_EXP_NOCMAP)) { - cmap = _m3d_addcmap(cmap, &numcmap, model->vertex[k].color); + cmap = _m3d_addcmap(cmap, &numcmap, model->label[i].color); if(!cmap) goto memerr; } - k = model->face[i].normal[j]; - if(k < model->numvertex && !(flags & M3D_EXP_NONORMAL)) { - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[k], &vertex); - vrtx = _m3d_addnorm(vrtx, &numvrtx, &vertex, &idx); - } else - vrtx = _m3d_addnorm(vrtx, &numvrtx, &model->vertex[k], &idx); - if(!vrtx) goto memerr; - face[i].normal[j] = (M3D_INDEX)idx; - } - k = model->face[i].texcoord[j]; - if(k < model->numtmap) { - switch(quality) { - case M3D_EXP_INT8: - l = model->tmap[k].u * 255; tcoord.u = (M3D_FLOAT)l / 255; - l = model->tmap[k].v * 255; tcoord.v = (M3D_FLOAT)l / 255; - break; - case M3D_EXP_INT16: - l = model->tmap[k].u * 65535; tcoord.u = (M3D_FLOAT)l / 65535; - l = model->tmap[k].v * 65535; tcoord.v = (M3D_FLOAT)l / 65535; - break; - default: - tcoord.u = model->tmap[k].u; - tcoord.v = model->tmap[k].v; - break; - } - if(flags & M3D_EXP_FLIPTXTCRD) - tcoord.v = (M3D_FLOAT)1.0 - tcoord.v; - tmap = _m3d_addtmap(tmap, &numtmap, &tcoord, &idx); - if(!tmap) goto memerr; - face[i].texcoord[j] = (M3D_INDEX)idx; - } - } - /* convert from CW to CCW */ - if(flags & M3D_EXP_IDOSUCK) { - j = face[i].vertex[1]; - face[i].vertex[1] = face[i].vertex[2]; - face[i].vertex[2] = face[i].vertex[1]; - j = face[i].normal[1]; - face[i].normal[1] = face[i].normal[2]; - face[i].normal[2] = face[i].normal[1]; - j = face[i].texcoord[1]; - face[i].texcoord[1] = face[i].texcoord[2]; - face[i].texcoord[2] = face[i].texcoord[1]; + if(model->label[i].vertexid < model->numvertex) + vrtxidx[model->label[i].vertexid] = 0; } + qsort(model->label, model->numlabel, sizeof(m3dl_t), _m3d_lblcmp); } } else if(!(flags & M3D_EXP_NOMATERIAL)) { /* without a face, simply add all materials, because it can be an mtllib */ - nummtrl = model->nummaterial; + for(i = 0; i < model->nummaterial; i++) + mtrlidx[i] = i; } - /* add colors to color map and texture names to string table */ - for(i = 0; i < nummtrl; i++) { - m = !mtrl ? &model->material[i] : mtrl[i]; - str = _m3d_addstr(str, &numstr, m->name); - if(!str) goto memerr; - for(j = 0; j < mtrl[i]->numprop; j++) { - if(!(flags & M3D_EXP_NOCMAP) && m->prop[j].type < 128) { - for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) { - if(m->prop[j].type == m3d_propertytypes[l].id && m3d_propertytypes[l].format == m3dpf_color) { - cmap = _m3d_addcmap(cmap, &numcmap, m->prop[j].value.color); - if(!cmap) goto memerr; - break; - } - } - } - if(m->prop[j].type >= 128 && m->prop[j].value.textureid < model->numtexture && - model->texture[m->prop[j].value.textureid].name) { - str = _m3d_addstr(str, &numstr, model->texture[m->prop[j].value.textureid].name); - if(!str) goto memerr; - } - } - } - /* get bind-pose skeleton and skin */ + /* bind-pose skeleton */ if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { - numbone = model->numbone; - bone = (m3db_t*)M3D_MALLOC(model->numbone * sizeof(m3db_t)); - if(!bone) goto memerr; - memset(bone, 0, model->numbone * sizeof(m3db_t)); + M3D_LOG("Processing bones"); for(i = 0; i < model->numbone; i++) { - bone[i].parent = model->bone[i].parent; - bone[i].name = model->bone[i].name; - str = _m3d_addstr(str, &numstr, bone[i].name); + str = _m3d_addstr(str, &numstr, model->bone[i].name); if(!str) goto memerr; - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[model->bone[i].pos], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &k); - } else - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[model->bone[i].pos], &k); - if(!vrtx) goto memerr; - bone[i].pos = (M3D_INDEX)k; - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[model->bone[i].ori], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &k); - } else - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[model->bone[i].ori], &k); - if(!vrtx) goto memerr; - bone[i].ori = (M3D_INDEX)k; + k = model->bone[i].pos; + if(k < model->numvertex) + vrtxidx[k] = 0; + k = model->bone[i].ori; + if(k < model->numvertex) + vrtxidx[k] = 0; } } /* actions, animated skeleton poses */ if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) { + M3D_LOG("Processing action list"); for(j = 0; j < model->numaction; j++) { a = &model->action[j]; str = _m3d_addstr(str, &numstr, a->name); if(!str) goto memerr; if(a->numframe > 65535) a->numframe = 65535; for(i = 0; i < a->numframe; i++) { - l = numactn; - numactn += (a->frame[i].numtransform * 2); - if(a->frame[i].numtransform > maxt) - maxt = a->frame[i].numtransform; - actn = (uint32_t*)M3D_REALLOC(actn, numactn * sizeof(uint32_t)); - if(!actn) goto memerr; - for(k = 0; k < a->frame[i].numtransform; k++) { - if(quality < M3D_EXP_FLOAT) { - _m3d_round(quality, &model->vertex[a->frame[i].transform[k].pos], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &actn[l++]); - if(!vrtx) goto memerr; - _m3d_round(quality, &model->vertex[a->frame[i].transform[k].ori], &vertex); - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &vertex, &actn[l++]); - } else { - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[a->frame[i].transform[k].pos], &actn[l++]); - if(!vrtx) goto memerr; - vrtx = _m3d_addvrtx(vrtx, &numvrtx, &model->vertex[a->frame[i].transform[k].ori], &actn[l++]); - } - if(!vrtx) goto memerr; + for(l = 0; l < a->frame[i].numtransform; l++) { + k = a->frame[i].transform[l].pos; + if(k < model->numvertex) + vrtxidx[k] = 0; + k = a->frame[i].transform[l].ori; + if(k < model->numvertex) + vrtxidx[k] = 0; } + if(l > maxt) maxt = l; } } } - /* normalize bounding cube and collect referenced skin records */ - if(numvrtx) { - min_x = min_y = min_z = 1e10; - max_x = max_y = max_z = -1e10; - j = model->numskin && model->skin && !(flags & M3D_EXP_NOBONE); - for(i = 0; i < numvrtx; i++) { - if(j && model->numskin && model->skin && vrtx[i].skinid < M3D_INDEXMAX) { - skin = _m3d_addskin(skin, &numskin, &model->skin[vrtx[i].skinid], &idx); - if(!skin) goto memerr; - vrtx[i].skinid = idx; - } - if(vrtx[i].skinid == (M3D_INDEX)-2U) continue; - if(vrtx[i].x > max_x) max_x = vrtx[i].x; - if(vrtx[i].x < min_x) min_x = vrtx[i].x; - if(vrtx[i].y > max_y) max_y = vrtx[i].y; - if(vrtx[i].y < min_y) min_y = vrtx[i].y; - if(vrtx[i].z > max_z) max_z = vrtx[i].z; - if(vrtx[i].z < min_z) min_z = vrtx[i].z; + /* add colors to color map and texture names to string table */ + if(!(flags & M3D_EXP_NOMATERIAL)) { + M3D_LOG("Processing materials"); + for(i = k = 0; i < model->nummaterial; i++) { + if(mtrlidx[i] == M3D_UNDEF || !model->material[i].numprop) continue; + mtrlidx[i] = k++; + m = &model->material[i]; + str = _m3d_addstr(str, &numstr, m->name); + if(!str) goto memerr; + if(m->prop) + for(j = 0; j < m->numprop; j++) { + if(!(flags & M3D_EXP_NOCMAP) && m->prop[j].type < 128) { + for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++) { + if(m->prop[j].type == m3d_propertytypes[l].id && m3d_propertytypes[l].format == m3dpf_color) { + ((uint8_t*)&m->prop[j].value.color)[3] = opa[i * 2 + 1]; + cmap = _m3d_addcmap(cmap, &numcmap, m->prop[j].value.color); + if(!cmap) goto memerr; + break; + } + } + } + if(m->prop[j].type >= 128 && m->prop[j].value.textureid < model->numtexture && + model->texture[m->prop[j].value.textureid].name) { + str = _m3d_addstr(str, &numstr, model->texture[m->prop[j].value.textureid].name); + if(!str) goto memerr; + } + } } - if(min_x < 0.0f) min_x = -min_x; - if(max_x < 0.0f) max_x = -max_x; - if(min_y < 0.0f) min_y = -min_y; - if(max_y < 0.0f) max_y = -max_y; - if(min_z < 0.0f) min_z = -min_z; - if(max_z < 0.0f) max_z = -max_z; + } + /* if there's only one black color, don't store it */ + if(numcmap == 1 && cmap && !cmap[0]) numcmap = 0; + + /** compress lists **/ + if(model->numtmap && !(flags & M3D_EXP_NOTXTCRD)) { + M3D_LOG("Compressing tmap"); + tmap = (m3dtisave_t*)M3D_MALLOC(model->numtmap * sizeof(m3dtisave_t)); + if(!tmap) goto memerr; + for(i = 0; i < model->numtmap; i++) { + if(tmapidx[i] == M3D_UNDEF) continue; + switch(quality) { + case M3D_EXP_INT8: + l = (unsigned int)(model->tmap[i].u * 255); tcoord.data.u = (M3D_FLOAT)l / (M3D_FLOAT)255.0; + l = (unsigned int)(model->tmap[i].v * 255); tcoord.data.v = (M3D_FLOAT)l / (M3D_FLOAT)255.0; + break; + case M3D_EXP_INT16: + l = (unsigned int)(model->tmap[i].u * 65535); tcoord.data.u = (M3D_FLOAT)l / (M3D_FLOAT)65535.0; + l = (unsigned int)(model->tmap[i].v * 65535); tcoord.data.v = (M3D_FLOAT)l / (M3D_FLOAT)65535.0; + break; + default: + tcoord.data.u = model->tmap[i].u; + tcoord.data.v = model->tmap[i].v; + break; + } + if(flags & M3D_EXP_FLIPTXTCRD) + tcoord.data.v = (M3D_FLOAT)1.0 - tcoord.data.v; + tcoord.oldidx = i; + memcpy(&tmap[numtmap++], &tcoord, sizeof(m3dtisave_t)); + } + if(numtmap) { + qsort(tmap, numtmap, sizeof(m3dtisave_t), _m3d_ticmp); + memcpy(&tcoord.data, &tmap[0], sizeof(m3dti_t)); + for(i = 0; i < numtmap; i++) { + if(memcmp(&tcoord.data, &tmap[i].data, sizeof(m3dti_t))) { + memcpy(&tcoord.data, &tmap[i].data, sizeof(m3dti_t)); + maxtmap++; + } + tmap[i].newidx = maxtmap; + tmapidx[tmap[i].oldidx] = maxtmap; + } + maxtmap++; + } + } + if(model->numskin && model->skin && !(flags & M3D_EXP_NOBONE)) { + M3D_LOG("Compressing skin"); + skinidx = (M3D_INDEX*)M3D_MALLOC(model->numskin * sizeof(M3D_INDEX)); + if(!skinidx) goto memerr; + skin = (m3dssave_t*)M3D_MALLOC(model->numskin * sizeof(m3dssave_t)); + if(!skin) goto memerr; + memset(skinidx, 255, model->numskin * sizeof(M3D_INDEX)); + for(i = 0; i < model->numvertex; i++) { + if(vrtxidx[i] != M3D_UNDEF && model->vertex[i].skinid < model->numskin) + skinidx[model->vertex[i].skinid] = 0; + } + for(i = 0; i < model->numskin; i++) { + if(skinidx[i] == M3D_UNDEF) continue; + memset(&sk, 0, sizeof(m3dssave_t)); + for(j = 0, min_x = (M3D_FLOAT)0.0; j < M3D_NUMBONE && model->skin[i].boneid[j] != M3D_UNDEF && + model->skin[i].weight[j] > (M3D_FLOAT)0.0; j++) { + sk.data.boneid[j] = model->skin[i].boneid[j]; + sk.data.weight[j] = model->skin[i].weight[j]; + min_x += sk.data.weight[j]; + } + if(j > maxbone) maxbone = j; + if(min_x != (M3D_FLOAT)1.0 && min_x != (M3D_FLOAT)0.0) + for(j = 0; j < M3D_NUMBONE && sk.data.weight[j] > (M3D_FLOAT)0.0; j++) + sk.data.weight[j] /= min_x; + sk.oldidx = i; + memcpy(&skin[numskin++], &sk, sizeof(m3dssave_t)); + } + if(numskin) { + qsort(skin, numskin, sizeof(m3dssave_t), _m3d_skincmp); + memcpy(&sk.data, &skin[0].data, sizeof(m3ds_t)); + for(i = 0; i < numskin; i++) { + if(memcmp(&sk.data, &skin[i].data, sizeof(m3ds_t))) { + memcpy(&sk.data, &skin[i].data, sizeof(m3ds_t)); + maxskin++; + } + skin[i].newidx = maxskin; + skinidx[skin[i].oldidx] = maxskin; + } + maxskin++; + } + } + + M3D_LOG("Compressing vertex list"); + min_x = min_y = min_z = (M3D_FLOAT)1e10; + max_x = max_y = max_z = (M3D_FLOAT)-1e10; + if(vrtxidx) { + vrtx = (m3dvsave_t*)M3D_MALLOC(model->numvertex * sizeof(m3dvsave_t)); + if(!vrtx) goto memerr; + for(i = numvrtx = 0; i < model->numvertex; i++) { + if(vrtxidx[i] == M3D_UNDEF) continue; + _m3d_round(quality, &model->vertex[i], &vertex.data); + vertex.norm = norm ? norm[i] : 0; + if(vertex.data.skinid != M3D_INDEXMAX && !vertex.norm) { + vertex.data.skinid = vertex.data.skinid != M3D_UNDEF && skinidx ? skinidx[vertex.data.skinid] : M3D_UNDEF; + if(vertex.data.x > max_x) max_x = vertex.data.x; + if(vertex.data.x < min_x) min_x = vertex.data.x; + if(vertex.data.y > max_y) max_y = vertex.data.y; + if(vertex.data.y < min_y) min_y = vertex.data.y; + if(vertex.data.z > max_z) max_z = vertex.data.z; + if(vertex.data.z < min_z) min_z = vertex.data.z; + } +#ifdef M3D_VERTEXTYPE + vertex.data.type = 0; +#endif + vertex.oldidx = i; + memcpy(&vrtx[numvrtx++], &vertex, sizeof(m3dvsave_t)); + } + if(numvrtx) { + qsort(vrtx, numvrtx, sizeof(m3dvsave_t), _m3d_vrtxcmp); + memcpy(&vertex.data, &vrtx[0].data, sizeof(m3dv_t)); + for(i = 0; i < numvrtx; i++) { + if(memcmp(&vertex.data, &vrtx[i].data, vrtx[i].norm ? 3 * sizeof(M3D_FLOAT) : sizeof(m3dv_t))) { + memcpy(&vertex.data, &vrtx[i].data, sizeof(m3dv_t)); + maxvrtx++; + } + vrtx[i].newidx = maxvrtx; + vrtxidx[vrtx[i].oldidx] = maxvrtx; + } + maxvrtx++; + } + } + if(skinidx) { M3D_FREE(skinidx); skinidx = NULL; } + if(norm) { M3D_FREE(norm); norm = NULL; } + + /* normalize to bounding cube */ + if(numvrtx && !(flags & M3D_EXP_NORECALC)) { + M3D_LOG("Normalizing coordinates"); + if(min_x < (M3D_FLOAT)0.0) min_x = -min_x; + if(max_x < (M3D_FLOAT)0.0) max_x = -max_x; + if(min_y < (M3D_FLOAT)0.0) min_y = -min_y; + if(max_y < (M3D_FLOAT)0.0) max_y = -max_y; + if(min_z < (M3D_FLOAT)0.0) min_z = -min_z; + if(max_z < (M3D_FLOAT)0.0) max_z = -max_z; scale = min_x; if(max_x > scale) scale = max_x; if(min_y > scale) scale = min_y; if(max_y > scale) scale = max_y; if(min_z > scale) scale = min_z; if(max_z > scale) scale = max_z; - if(scale == 0.0f) scale = 1.0f; - if(scale != 1.0f && !(flags & M3D_EXP_NORECALC)) { + if(scale == (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0; + if(scale != (M3D_FLOAT)1.0) { for(i = 0; i < numvrtx; i++) { - if(vrtx[i].skinid == (M3D_INDEX)-2U) continue; - vrtx[i].x /= scale; - vrtx[i].y /= scale; - vrtx[i].z /= scale; + if(vrtx[i].data.skinid == M3D_INDEXMAX) continue; + vrtx[i].data.x /= scale; + vrtx[i].data.y /= scale; + vrtx[i].data.z /= scale; } } } - /* if there's only one black color, don't store it */ - if(numcmap == 1 && cmap && !cmap[0]) numcmap = 0; - /* at least 3 UV coordinate required for texture mapping */ - if(numtmap < 3 && tmap) numtmap = 0; + if(model->scale > (M3D_FLOAT)0.0) scale = model->scale; + if(scale <= (M3D_FLOAT)0.0) scale = (M3D_FLOAT)1.0; + /* meta info */ sn = _m3d_safestr(model->name && *model->name ? model->name : (char*)"(noname)", 2); sl = _m3d_safestr(model->license ? model->license : (char*)"MIT", 2); sa = _m3d_safestr(model->author ? model->author : getenv("LOGNAME"), 2); if(!sn || !sl || !sa) { -memerr: if(face) M3D_FREE(face); +memerr: if(vrtxidx) M3D_FREE(vrtxidx); + if(mtrlidx) M3D_FREE(mtrlidx); + if(tmapidx) M3D_FREE(tmapidx); + if(skinidx) M3D_FREE(skinidx); + if(grpidx) M3D_FREE(grpidx); + if(norm) M3D_FREE(norm); + if(face) M3D_FREE(face); if(cmap) M3D_FREE(cmap); if(tmap) M3D_FREE(tmap); - if(mtrl) M3D_FREE(mtrl); - if(vrtx) M3D_FREE(vrtx); - if(bone) M3D_FREE(bone); if(skin) M3D_FREE(skin); - if(actn) M3D_FREE(actn); + if(str) M3D_FREE(str); + if(vrtx) M3D_FREE(vrtx); if(sn) M3D_FREE(sn); if(sl) M3D_FREE(sl); if(sa) M3D_FREE(sa); if(sd) M3D_FREE(sd); if(out) M3D_FREE(out); - if(str) M3D_FREE(str); if(h) M3D_FREE(h); M3D_LOG("Out of memory"); model->errcode = M3D_ERR_ALLOC; return NULL; } - if(model->scale > (M3D_FLOAT)0.0) scale = (float)model->scale; - if(scale <= 0.0f) scale = 1.0f; + + M3D_LOG("Serializing model"); #ifdef M3D_ASCII if(flags & M3D_EXP_ASCII) { /* use CRLF to make model creators on Win happy... */ @@ -3802,74 +4541,93 @@ memerr: if(face) M3D_FREE(face); ol = setlocale(LC_NUMERIC, NULL); setlocale(LC_NUMERIC, "C"); /* header */ - len = 64 + strlen(sn) + strlen(sl) + strlen(sa) + strlen(sd); + len = 64 + (unsigned int)(strlen(sn) + strlen(sl) + strlen(sa) + strlen(sd)); out = (unsigned char*)M3D_MALLOC(len); if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr = (char*)out; ptr += sprintf(ptr, "3dmodel %g\r\n%s\r\n%s\r\n%s\r\n%s\r\n\r\n", scale, sn, sl, sa, sd); - M3D_FREE(sn); M3D_FREE(sl); M3D_FREE(sa); M3D_FREE(sd); - sn = sl = sa = sd = NULL; + M3D_FREE(sl); M3D_FREE(sa); M3D_FREE(sd); + sl = sa = sd = NULL; + /* preview chunk */ + if(model->preview.data && model->preview.length) { + sl = _m3d_safestr(sn, 0); + if(sl) { + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)20); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "Preview\r\n%s.png\r\n\r\n", sl); + M3D_FREE(sl); sl = NULL; + } + } + M3D_FREE(sn); sn = NULL; /* texture map */ if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + numtmap * 32 + 12; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxtmap * 32) + (uintptr_t)12); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Textmap\r\n"); - for(i = 0; i < numtmap; i++) - ptr += sprintf(ptr, "%g %g\r\n", tmap[i].u, tmap[i].v); + last = M3D_UNDEF; + for(i = 0; i < numtmap; i++) { + if(tmap[i].newidx == last) continue; + last = tmap[i].newidx; + ptr += sprintf(ptr, "%g %g\r\n", tmap[i].data.u, tmap[i].data.v); + } ptr += sprintf(ptr, "\r\n"); } /* vertex chunk */ if(numvrtx && vrtx && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + numvrtx * 128 + 10; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(maxvrtx * 128) + (uintptr_t)10); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Vertex\r\n"); + last = M3D_UNDEF; for(i = 0; i < numvrtx; i++) { - ptr += sprintf(ptr, "%g %g %g %g", vrtx[i].x, vrtx[i].y, vrtx[i].z, vrtx[i].w); - if(!(flags & M3D_EXP_NOCMAP) && vrtx[i].color) - ptr += sprintf(ptr, " #%08x", vrtx[i].color); - if(!(flags & M3D_EXP_NOBONE) && numbone && numskin && vrtx[i].skinid != (M3D_INDEX)-1U && - vrtx[i].skinid != (M3D_INDEX)-2U) { - if(skin[vrtx[i].skinid].weight[0] == (M3D_FLOAT)1.0) - ptr += sprintf(ptr, " %d", skin[vrtx[i].skinid].boneid[0]); + if(vrtx[i].newidx == last) continue; + last = vrtx[i].newidx; + ptr += sprintf(ptr, "%g %g %g %g", vrtx[i].data.x, vrtx[i].data.y, vrtx[i].data.z, vrtx[i].data.w); + if(!(flags & M3D_EXP_NOCMAP) && vrtx[i].data.color) + ptr += sprintf(ptr, " #%08x", vrtx[i].data.color); + if(!(flags & M3D_EXP_NOBONE) && model->numbone && maxskin && vrtx[i].data.skinid < M3D_INDEXMAX) { + if(skin[vrtx[i].data.skinid].data.weight[0] == (M3D_FLOAT)1.0) + ptr += sprintf(ptr, " %d", skin[vrtx[i].data.skinid].data.boneid[0]); else - for(j = 0; j < M3D_NUMBONE && skin[vrtx[i].skinid].boneid[j] != (M3D_INDEX)-1U && - skin[vrtx[i].skinid].weight[j] > (M3D_FLOAT)0.0; j++) - ptr += sprintf(ptr, " %d:%g", skin[vrtx[i].skinid].boneid[j], - skin[vrtx[i].skinid].weight[j]); + for(j = 0; j < M3D_NUMBONE && skin[vrtx[i].data.skinid].data.boneid[j] != M3D_UNDEF && + skin[vrtx[i].data.skinid].data.weight[j] > (M3D_FLOAT)0.0; j++) + ptr += sprintf(ptr, " %d:%g", skin[vrtx[i].data.skinid].data.boneid[j], + skin[vrtx[i].data.skinid].data.weight[j]); } ptr += sprintf(ptr, "\r\n"); } ptr += sprintf(ptr, "\r\n"); } /* bones chunk */ - if(numbone && bone && !(flags & M3D_EXP_NOBONE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + 9; - for(i = 0; i < numbone; i++) { - len += strlen(bone[i].name) + 128; + if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)9); + for(i = 0; i < model->numbone; i++) { + len += (unsigned int)strlen(model->bone[i].name) + 128; } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Bones\r\n"); - ptr = _m3d_prtbone(ptr, bone, numbone, (M3D_INDEX)-1U, 0); + ptr = _m3d_prtbone(ptr, model->bone, model->numbone, M3D_UNDEF, 0, vrtxidx); ptr += sprintf(ptr, "\r\n"); } /* materials */ - if(nummtrl && !(flags & M3D_EXP_NOMATERIAL)) { - for(j = 0; j < nummtrl; j++) { - m = !mtrl ? &model->material[j] : mtrl[j]; + if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { + for(j = 0; j < model->nummaterial; j++) { + if(mtrlidx[j] == M3D_UNDEF || !model->material[j].numprop || !model->material[j].prop) continue; + m = &model->material[j]; sn = _m3d_safestr(m->name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 12; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)12); for(i = 0; i < m->numprop; i++) { if(m->prop[i].type < 128) len += 32; else if(m->prop[i].value.textureid < model->numtexture && model->texture[m->prop[i].value.textureid].name) - len += strlen(model->texture[m->prop[i].value.textureid].name) + 16; + len += (unsigned int)strlen(model->texture[m->prop[i].value.textureid].name) + 16; } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Material %s\r\n", sn); M3D_FREE(sn); sn = NULL; @@ -3918,28 +4676,50 @@ memerr: if(face) M3D_FREE(face); ptr += sprintf(ptr, "\r\n"); } } + /* procedural face */ + if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) { + /* all inlined assets which are not textures should be procedural surfaces */ + for(j = 0; j < model->numinlined; j++) { + if(!model->inlined[j].name || !*model->inlined[j].name || !model->inlined[j].length || !model->inlined[j].data || + (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G')) + continue; + for(i = k = 0; i < model->numtexture; i++) { + if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } + } + if(k) continue; + sn = _m3d_safestr(model->inlined[j].name, 0); + if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)18); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "Procedural\r\n%s\r\n\r\n", sn); + M3D_FREE(sn); sn = NULL; + } + } /* mesh face */ if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { - ptr -= (uint64_t)out; len = (uint64_t)ptr + model->numface * 128 + 6; - last = (M3D_INDEX)-1U; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)(model->numface * 128) + (uintptr_t)6); + last = M3D_UNDEF; if(!(flags & M3D_EXP_NOMATERIAL)) for(i = 0; i < model->numface; i++) { - if(face[i].materialid != last) { - last = face[i].materialid; - if(last < nummtrl) - len += strlen(mtrl[last]->name); + j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : M3D_UNDEF; + if(j != last) { + last = j; + if(last < model->nummaterial) + len += (unsigned int)strlen(model->material[last].name); len += 6; } } - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Mesh\r\n"); - last = (M3D_INDEX)-1U; + last = M3D_UNDEF; for(i = 0; i < model->numface; i++) { - if(!(flags & M3D_EXP_NOMATERIAL) && face[i].materialid != last) { - last = face[i].materialid; - if(last < nummtrl) { - sn = _m3d_safestr(mtrl[last]->name, 0); + j = face[i].data.materialid < model->nummaterial ? face[i].data.materialid : M3D_UNDEF; + if(!(flags & M3D_EXP_NOMATERIAL) && j != last) { + last = j; + if(last < model->nummaterial) { + sn = _m3d_safestr(model->material[last].name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "use %s\r\n", sn); M3D_FREE(sn); sn = NULL; @@ -3948,63 +4728,165 @@ memerr: if(face) M3D_FREE(face); } /* hardcoded triangles. Should be repeated as many times as the number of edges in polygon */ for(j = 0; j < 3; j++) { - ptr += sprintf(ptr, "%s%d", j?" ":"", face[i].vertex[j]); - if(!(flags & M3D_EXP_NOTXTCRD) && (face[i].texcoord[j] != (M3D_INDEX)-1U)) - ptr += sprintf(ptr, "/%d", face[i].texcoord[j]); - if(!(flags & M3D_EXP_NONORMAL) && (face[i].normal[j] != (M3D_INDEX)-1U)) - ptr += sprintf(ptr, "%s/%d", - (flags & M3D_EXP_NOTXTCRD) || (face[i].texcoord[j] == (M3D_INDEX)-1U)? "/" : "", - face[i].normal[j]); + ptr += sprintf(ptr, "%s%d", j?" ":"", vrtxidx[face[i].data.vertex[j]]); + k = M3D_NOTDEFINED; + if(!(flags & M3D_EXP_NOTXTCRD) && (face[i].data.texcoord[j] != M3D_UNDEF) && + (tmapidx[face[i].data.texcoord[j]] != M3D_UNDEF)) { + k = tmapidx[face[i].data.texcoord[j]]; + ptr += sprintf(ptr, "/%d", k); + } + if(!(flags & M3D_EXP_NONORMAL) && (face[i].data.normal[j] != M3D_UNDEF)) + ptr += sprintf(ptr, "%s/%d", k == M3D_NOTDEFINED? "/" : "", vrtxidx[face[i].data.normal[j]]); } ptr += sprintf(ptr, "\r\n"); } ptr += sprintf(ptr, "\r\n"); } + /* mathematical shapes face */ + if(model->numshape && model->numshape && !(flags & M3D_EXP_NOFACE)) { + for(j = 0; j < model->numshape; j++) { + sn = _m3d_safestr(model->shape[j].name, 0); + if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)33); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "Shape %s\r\n", sn); + M3D_FREE(sn); sn = NULL; + if(model->shape[j].group != M3D_UNDEF && !(flags & M3D_EXP_NOBONE)) + ptr += sprintf(ptr, "group %d\r\n", model->shape[j].group); + for(i = 0; i < model->shape[j].numcmd; i++) { + cmd = &model->shape[j].cmd[i]; + if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) + continue; + cd = &m3d_commandtypes[cmd->type]; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(cd->key) + (uintptr_t)3); + for(k = 0; k < cd->p; k++) + switch(cd->a[k]) { + case m3dcp_mi_t: if(cmd->arg[k] != M3D_NOTDEFINED) { len += (unsigned int)strlen(model->material[cmd->arg[k]].name) + 1; } break; + case m3dcp_va_t: len += cmd->arg[k] * (cd->p - k - 1) * 16; k = cd->p; break; + default: len += 16; break; + } + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "%s", cd->key); + for(k = n = 0, l = cd->p; k < l; k++) { + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + if(cmd->arg[k] != M3D_NOTDEFINED) { + sn = _m3d_safestr(model->material[cmd->arg[k]].name, 0); + if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, " %s", sn); + M3D_FREE(sn); sn = NULL; + } + break; + case m3dcp_vc_t: ptr += sprintf(ptr, " %g", *((float*)&cmd->arg[k])); break; + case m3dcp_va_t: ptr += sprintf(ptr, " %d[", cmd->arg[k]); + n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); + break; + default: ptr += sprintf(ptr, " %d", cmd->arg[k]); break; + } + } + ptr += sprintf(ptr, "%s\r\n", l > cd->p ? " ]" : ""); + } + ptr += sprintf(ptr, "\r\n"); + } + } + /* annotation labels */ + if(model->numlabel && model->label && !(flags & M3D_EXP_NOFACE)) { + for(i = 0, j = 3, length = NULL; i < model->numlabel; i++) { + if(model->label[i].name) j += (unsigned int)strlen(model->label[i].name); + if(model->label[i].lang) j += (unsigned int)strlen(model->label[i].lang); + if(model->label[i].text) j += (unsigned int)strlen(model->label[i].text); + j += 40; + } + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)j); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + for(i = 0; i < model->numlabel; i++) { + if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) { + sl = model->label[i].lang; + sn = model->label[i].name; + sd = _m3d_safestr(sn, 0); + if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } + if(i) ptr += sprintf(ptr, "\r\n"); + ptr += sprintf(ptr, "Labels %s\r\n", sd); + M3D_FREE(sd); sd = NULL; + if(model->label[i].color) + ptr += sprintf(ptr, "color #0x%08x\r\n", model->label[i].color); + if(sl && *sl) { + sd = _m3d_safestr(sl, 0); + if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } + ptr += sprintf(ptr, "lang %s\r\n", sd); + M3D_FREE(sd); sd = NULL; + } + } + sd = _m3d_safestr(model->label[i].text, 2); + if(!sd) { setlocale(LC_NUMERIC, ol); sn = sl = NULL; goto memerr; } + ptr += sprintf(ptr, "%d %s\r\n", model->label[i].vertexid, sd); + M3D_FREE(sd); sd = NULL; + } + ptr += sprintf(ptr, "\r\n"); + sn = sl = NULL; + } /* actions */ - if(model->numaction && model->action && numactn && actn && !(flags & M3D_EXP_NOACTION)) { - l = 0; + if(model->numaction && model->action && !(flags & M3D_EXP_NOACTION)) { for(j = 0; j < model->numaction; j++) { a = &model->action[j]; sn = _m3d_safestr(a->name, 0); if(!sn) { setlocale(LC_NUMERIC, ol); goto memerr; } - ptr -= (uint64_t)out; len = (uint64_t)ptr + strlen(sn) + 48; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)strlen(sn) + (uintptr_t)48); for(i = 0; i < a->numframe; i++) len += a->frame[i].numtransform * 128 + 8; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Action %d %s\r\n", a->durationmsec, sn); M3D_FREE(sn); sn = NULL; - if(a->numframe > 65535) a->numframe = 65535; for(i = 0; i < a->numframe; i++) { ptr += sprintf(ptr, "frame %d\r\n", a->frame[i].msec); for(k = 0; k < a->frame[i].numtransform; k++) { - ptr += sprintf(ptr, "%d %d %d\r\n", a->frame[i].transform[k].boneid, actn[l], actn[l + 1]); - l += 2; + ptr += sprintf(ptr, "%d %d %d\r\n", a->frame[i].transform[k].boneid, + vrtxidx[a->frame[i].transform[k].pos], vrtxidx[a->frame[i].transform[k].ori]); } } ptr += sprintf(ptr, "\r\n"); } } + /* inlined assets */ + if(model->numinlined && model->inlined) { + for(i = j = 0; i < model->numinlined; i++) + if(model->inlined[i].name) + j += (unsigned int)strlen(model->inlined[i].name) + 6; + if(j > 0) { + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)j + (uintptr_t)16); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; + if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } + ptr += sprintf(ptr, "Assets\r\n"); + for(i = 0; i < model->numinlined; i++) + if(model->inlined[i].name) + ptr += sprintf(ptr, "%s%s\r\n", model->inlined[i].name, strrchr(model->inlined[i].name, '.') ? "" : ".png"); + ptr += sprintf(ptr, "\r\n"); + } + } /* extra info */ - if(model->numunknown && (flags & M3D_EXP_EXTRA)) { - for(i = 0; i < model->numunknown; i++) { - if(model->unknown[i]->length < 9) continue; - ptr -= (uint64_t)out; len = (uint64_t)ptr + 17 + model->unknown[i]->length * 3; - out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uint64_t)out; + if(model->numextra && (flags & M3D_EXP_EXTRA)) { + for(i = 0; i < model->numextra; i++) { + if(model->extra[i]->length < 9) continue; + ptr -= (uintptr_t)out; len = (unsigned int)((uintptr_t)ptr + (uintptr_t)17 + (uintptr_t)(model->extra[i]->length * 3)); + out = (unsigned char*)M3D_REALLOC(out, len); ptr += (uintptr_t)out; if(!out) { setlocale(LC_NUMERIC, ol); goto memerr; } ptr += sprintf(ptr, "Extra %c%c%c%c\r\n", - model->unknown[i]->magic[0] > ' ' ? model->unknown[i]->magic[0] : '_', - model->unknown[i]->magic[1] > ' ' ? model->unknown[i]->magic[1] : '_', - model->unknown[i]->magic[2] > ' ' ? model->unknown[i]->magic[2] : '_', - model->unknown[i]->magic[3] > ' ' ? model->unknown[i]->magic[3] : '_'); - for(j = 0; j < model->unknown[i]->length; j++) - ptr += sprintf(ptr, "%02x ", *((unsigned char *)model->unknown + sizeof(m3dchunk_t) + j)); + model->extra[i]->magic[0] > ' ' ? model->extra[i]->magic[0] : '_', + model->extra[i]->magic[1] > ' ' ? model->extra[i]->magic[1] : '_', + model->extra[i]->magic[2] > ' ' ? model->extra[i]->magic[2] : '_', + model->extra[i]->magic[3] > ' ' ? model->extra[i]->magic[3] : '_'); + for(j = 0; j < model->extra[i]->length; j++) + ptr += sprintf(ptr, "%02x ", *((unsigned char *)model->extra + sizeof(m3dchunk_t) + j)); ptr--; ptr += sprintf(ptr, "\r\n\r\n"); } } setlocale(LC_NUMERIC, ol); - len = (uint64_t)ptr - (uint64_t)out; + len = (unsigned int)((uintptr_t)ptr - (uintptr_t)out); out = (unsigned char*)M3D_REALLOC(out, len + 1); if(!out) goto memerr; out[len] = 0; @@ -4020,21 +4902,11 @@ memerr: if(face) M3D_FREE(face); memcpy((uint8_t*)h, "HEAD", 4); h->length = sizeof(m3dhdr_t); h->scale = scale; - i = strlen(sn); memcpy((uint8_t*)h + h->length, sn, i+1); h->length += i+1; M3D_FREE(sn); - i = strlen(sl); memcpy((uint8_t*)h + h->length, sl, i+1); h->length += i+1; M3D_FREE(sl); - i = strlen(sa); memcpy((uint8_t*)h + h->length, sa, i+1); h->length += i+1; M3D_FREE(sa); - i = strlen(sd); memcpy((uint8_t*)h + h->length, sd, i+1); h->length += i+1; M3D_FREE(sd); + i = (unsigned int)strlen(sn); memcpy((uint8_t*)h + h->length, sn, i+1); h->length += i+1; M3D_FREE(sn); + i = (unsigned int)strlen(sl); memcpy((uint8_t*)h + h->length, sl, i+1); h->length += i+1; M3D_FREE(sl); + i = (unsigned int)strlen(sa); memcpy((uint8_t*)h + h->length, sa, i+1); h->length += i+1; M3D_FREE(sa); + i = (unsigned int)strlen(sd); memcpy((uint8_t*)h + h->length, sd, i+1); h->length += i+1; M3D_FREE(sd); sn = sl = sa = sd = NULL; - len = 0; - if(!bone) numbone = 0; - if(skin) - for(i = 0; i < numskin; i++) { - for(j = k = 0; j < M3D_NUMBONE; j++) - if(skin[i].boneid[j] != (M3D_INDEX)-1U && skin[i].weight[j] > (M3D_FLOAT)0.0) k++; - if(k > len) len = k; - } - else - numskin = 0; if(model->inlined) for(i = 0; i < model->numinlined; i++) { if(model->inlined[i].name && *model->inlined[i].name && model->inlined[i].length > 0) { @@ -4048,14 +4920,19 @@ memerr: if(face) M3D_FREE(face); if(!h) goto memerr; } vc_s = quality == M3D_EXP_INT8? 1 : (quality == M3D_EXP_INT16? 2 : (quality == M3D_EXP_DOUBLE? 8 : 4)); - vi_s = numvrtx < 254 ? 1 : (numvrtx < 65534 ? 2 : 4); + vi_s = maxvrtx < 254 ? 1 : (maxvrtx < 65534 ? 2 : 4); si_s = h->length - 16 < 254 ? 1 : (h->length - 16 < 65534 ? 2 : 4); ci_s = !numcmap || !cmap ? 0 : (numcmap < 254 ? 1 : (numcmap < 65534 ? 2 : 4)); - ti_s = !numtmap || !tmap ? 0 : (numtmap < 254 ? 1 : (numtmap < 65534 ? 2 : 4)); - bi_s = !numbone || !bone ? 0 : (numbone < 254 ? 1 : (numbone < 65534 ? 2 : 4)); - nb_s = len < 2 ? 1 : (len == 2 ? 2 : (len <= 4 ? 4 : 8)); - sk_s = !numbone || !numskin ? 0 : (numskin < 254 ? 1 : (numskin < 65534 ? 2 : 4)); - fi_s = maxt < 254 ? 1 : (maxt < 65534 ? 2 : 4); + ti_s = !maxtmap || !tmap ? 0 : (maxtmap < 254 ? 1 : (maxtmap < 65534 ? 2 : 4)); + bi_s = !model->numbone || !model->bone || (flags & M3D_EXP_NOBONE)? 0 : (model->numbone < 254 ? 1 : + (model->numbone < 65534 ? 2 : 4)); + nb_s = maxbone < 2 ? 1 : (maxbone == 2 ? 2 : (maxbone <= 4 ? 4 : 8)); + sk_s = !bi_s || !maxskin || !skin ? 0 : (maxskin < 254 ? 1 : (maxskin < 65534 ? 2 : 4)); + fc_s = maxt < 254 ? 1 : (maxt < 65534 ? 2 : 4); + hi_s = !model->numshape || !model->shape || (flags & M3D_EXP_NOFACE)? 0 : (model->numshape < 254 ? 1 : + (model->numshape < 65534 ? 2 : 4)); + fi_s = !model->numface || !model->face || (flags & M3D_EXP_NOFACE)? 0 : (model->numface < 254 ? 1 : + (model->numface < 65534 ? 2 : 4)); h->types = (vc_s == 8 ? (3<<0) : (vc_s == 2 ? (1<<0) : (vc_s == 1 ? (0<<0) : (2<<0)))) | (vi_s == 2 ? (1<<2) : (vi_s == 1 ? (0<<2) : (2<<2))) | (si_s == 2 ? (1<<4) : (si_s == 1 ? (0<<4) : (2<<4))) | @@ -4064,8 +4941,20 @@ memerr: if(face) M3D_FREE(face); (bi_s == 2 ? (1<<10): (bi_s == 1 ? (0<<10): (bi_s == 4 ? (2<<10) : (3<<10)))) | (nb_s == 2 ? (1<<12): (nb_s == 1 ? (0<<12): (2<<12))) | (sk_s == 2 ? (1<<14): (sk_s == 1 ? (0<<14): (sk_s == 4 ? (2<<14) : (3<<14)))) | - (fi_s == 2 ? (1<<16): (fi_s == 1 ? (0<<16): (2<<16))) ; + (fc_s == 2 ? (1<<16): (fc_s == 1 ? (0<<16): (2<<16))) | + (hi_s == 2 ? (1<<18): (hi_s == 1 ? (0<<18): (hi_s == 4 ? (2<<18) : (3<<18)))) | + (fi_s == 2 ? (1<<20): (fi_s == 1 ? (0<<20): (fi_s == 4 ? (2<<20) : (3<<20)))); len = h->length; + /* preview image chunk, must be the first if exists */ + if(model->preview.data && model->preview.length) { + chunklen = 8 + model->preview.length; + h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); + if(!h) goto memerr; + memcpy((uint8_t*)h + len, "PRVW", 4); + *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; + memcpy((uint8_t*)h + len + 8, model->preview.data, model->preview.length); + len += chunklen; + } /* color map */ if(numcmap && cmap && ci_s < 4 && !(flags & M3D_EXP_NOCMAP)) { chunklen = 8 + numcmap * sizeof(uint32_t); @@ -4078,116 +4967,127 @@ memerr: if(face) M3D_FREE(face); } else numcmap = 0; /* texture map */ if(numtmap && tmap && !(flags & M3D_EXP_NOTXTCRD) && !(flags & M3D_EXP_NOFACE)) { - chunklen = 8 + numtmap * vc_s * 2; + chunklen = 8 + maxtmap * vc_s * 2; h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; memcpy((uint8_t*)h + len, "TMAP", 4); - *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; + length = (uint32_t*)((uint8_t*)h + len + 4); out = (uint8_t*)h + len + 8; + last = M3D_UNDEF; for(i = 0; i < numtmap; i++) { + if(tmap[i].newidx == last) continue; + last = tmap[i].newidx; switch(vc_s) { - case 1: *out++ = (uint8_t)(tmap[i].u * 255); *out++ = (uint8_t)(tmap[i].v * 255); break; + case 1: *out++ = (uint8_t)(tmap[i].data.u * 255); *out++ = (uint8_t)(tmap[i].data.v * 255); break; case 2: - *((uint16_t*)out) = (uint16_t)(tmap[i].u * 65535); out += 2; - *((uint16_t*)out) = (uint16_t)(tmap[i].v * 65535); out += 2; + *((uint16_t*)out) = (uint16_t)(tmap[i].data.u * 65535); out += 2; + *((uint16_t*)out) = (uint16_t)(tmap[i].data.v * 65535); out += 2; break; - case 4: *((float*)out) = tmap[i].u; out += 4; *((float*)out) = tmap[i].v; out += 4; break; - case 8: *((double*)out) = tmap[i].u; out += 8; *((double*)out) = tmap[i].v; out += 8; break; + case 4: *((float*)out) = tmap[i].data.u; out += 4; *((float*)out) = tmap[i].data.v; out += 4; break; + case 8: *((double*)out) = tmap[i].data.u; out += 8; *((double*)out) = tmap[i].data.v; out += 8; break; } } + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); out = NULL; - len += chunklen; + len += *length; } /* vertex */ if(numvrtx && vrtx) { - chunklen = 8 + numvrtx * (ci_s + sk_s + 4 * vc_s); + chunklen = 8 + maxvrtx * (ci_s + sk_s + 4 * vc_s); h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; memcpy((uint8_t*)h + len, "VRTS", 4); - *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; + length = (uint32_t*)((uint8_t*)h + len + 4); out = (uint8_t*)h + len + 8; + last = M3D_UNDEF; for(i = 0; i < numvrtx; i++) { + if(vrtx[i].newidx == last) continue; + last = vrtx[i].newidx; switch(vc_s) { case 1: - *out++ = (int8_t)(vrtx[i].x * 127); - *out++ = (int8_t)(vrtx[i].y * 127); - *out++ = (int8_t)(vrtx[i].z * 127); - *out++ = (int8_t)(vrtx[i].w * 127); + *out++ = (int8_t)(vrtx[i].data.x * 127); + *out++ = (int8_t)(vrtx[i].data.y * 127); + *out++ = (int8_t)(vrtx[i].data.z * 127); + *out++ = (int8_t)(vrtx[i].data.w * 127); break; case 2: - *((int16_t*)out) = (int16_t)(vrtx[i].x * 32767); out += 2; - *((int16_t*)out) = (int16_t)(vrtx[i].y * 32767); out += 2; - *((int16_t*)out) = (int16_t)(vrtx[i].z * 32767); out += 2; - *((int16_t*)out) = (int16_t)(vrtx[i].w * 32767); out += 2; + *((int16_t*)out) = (int16_t)(vrtx[i].data.x * 32767); out += 2; + *((int16_t*)out) = (int16_t)(vrtx[i].data.y * 32767); out += 2; + *((int16_t*)out) = (int16_t)(vrtx[i].data.z * 32767); out += 2; + *((int16_t*)out) = (int16_t)(vrtx[i].data.w * 32767); out += 2; break; case 4: - *((float*)out) = vrtx[i].x; out += 4; - *((float*)out) = vrtx[i].y; out += 4; - *((float*)out) = vrtx[i].z; out += 4; - *((float*)out) = vrtx[i].w; out += 4; + *((float*)out) = vrtx[i].data.x; out += 4; + *((float*)out) = vrtx[i].data.y; out += 4; + *((float*)out) = vrtx[i].data.z; out += 4; + *((float*)out) = vrtx[i].data.w; out += 4; break; case 8: - *((double*)out) = vrtx[i].x; out += 8; - *((double*)out) = vrtx[i].y; out += 8; - *((double*)out) = vrtx[i].z; out += 8; - *((double*)out) = vrtx[i].w; out += 8; + *((double*)out) = vrtx[i].data.x; out += 8; + *((double*)out) = vrtx[i].data.y; out += 8; + *((double*)out) = vrtx[i].data.z; out += 8; + *((double*)out) = vrtx[i].data.w; out += 8; break; } - idx = _m3d_cmapidx(cmap, numcmap, vrtx[i].color); + idx = _m3d_cmapidx(cmap, numcmap, vrtx[i].data.color); switch(ci_s) { case 1: *out++ = (uint8_t)(idx); break; case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; - case 4: *((uint32_t*)out) = vrtx[i].color; out += 4; break; + case 4: *((uint32_t*)out) = vrtx[i].data.color; out += 4; break; } - out = _m3d_addidx(out, sk_s, numbone && numskin ? vrtx[i].skinid : -1U); + out = _m3d_addidx(out, sk_s, vrtx[i].data.skinid); } + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); out = NULL; - len += chunklen; + len += *length; } /* bones chunk */ - if(numbone && bone && !(flags & M3D_EXP_NOBONE)) { - i = 8 + bi_s + sk_s + numbone * (bi_s + si_s + 2*vi_s); + if(model->numbone && model->bone && !(flags & M3D_EXP_NOBONE)) { + i = 8 + bi_s + sk_s + model->numbone * (bi_s + si_s + 2*vi_s); chunklen = i + numskin * nb_s * (bi_s + 1); h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; memcpy((uint8_t*)h + len, "BONE", 4); length = (uint32_t*)((uint8_t*)h + len + 4); out = (uint8_t*)h + len + 8; - out = _m3d_addidx(out, bi_s, numbone); - out = _m3d_addidx(out, sk_s, numskin); - for(i = 0; i < numbone; i++) { - out = _m3d_addidx(out, bi_s, bone[i].parent); - out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, bone[i].name)); - out = _m3d_addidx(out, vi_s, bone[i].pos); - out = _m3d_addidx(out, vi_s, bone[i].ori); + out = _m3d_addidx(out, bi_s, model->numbone); + out = _m3d_addidx(out, sk_s, maxskin); + for(i = 0; i < model->numbone; i++) { + out = _m3d_addidx(out, bi_s, model->bone[i].parent); + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->bone[i].name)); + out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].pos]); + out = _m3d_addidx(out, vi_s, vrtxidx[model->bone[i].ori]); } if(numskin && skin && sk_s) { + last = M3D_UNDEF; for(i = 0; i < numskin; i++) { + if(skin[i].newidx == last) continue; + last = skin[i].newidx; memset(&weights, 0, nb_s); - for(j = 0; j < (uint32_t)nb_s && skin[i].boneid[j] != (M3D_INDEX)-1U && - skin[i].weight[j] > (M3D_FLOAT)0.0; j++) - weights[j] = (uint8_t)(skin[i].weight[j] * 255); + for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF && + skin[i].data.weight[j] > (M3D_FLOAT)0.0; j++) + weights[j] = (uint8_t)(skin[i].data.weight[j] * 255); switch(nb_s) { case 1: weights[0] = 255; break; case 2: *((uint16_t*)out) = *((uint16_t*)&weights[0]); out += 2; break; case 4: *((uint32_t*)out) = *((uint32_t*)&weights[0]); out += 4; break; case 8: *((uint64_t*)out) = *((uint64_t*)&weights[0]); out += 8; break; } - for(j = 0; j < (uint32_t)nb_s && skin[i].boneid[j] != (M3D_INDEX)-1U && - skin[i].weight[j] > (M3D_FLOAT)0.0; j++) { - out = _m3d_addidx(out, bi_s, skin[i].boneid[j]); + for(j = 0; j < (uint32_t)nb_s && skin[i].data.boneid[j] != M3D_UNDEF && weights[j]; j++) { + out = _m3d_addidx(out, bi_s, skin[i].data.boneid[j]); *length += bi_s; } } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); out = NULL; len += *length; } /* materials */ - if(nummtrl && !(flags & M3D_EXP_NOMATERIAL)) { - for(j = 0; j < nummtrl; j++) { - m = !mtrl ? &model->material[j] : mtrl[j]; + if(model->nummaterial && !(flags & M3D_EXP_NOMATERIAL)) { + for(j = 0; j < model->nummaterial; j++) { + if(mtrlidx[j] == M3D_UNDEF || !model->material[j].numprop || !model->material[j].prop) continue; + m = &model->material[j]; chunklen = 12 + si_s + m->numprop * 5; h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; @@ -4228,11 +5128,35 @@ memerr: if(face) M3D_FREE(face); break; } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); len += *length; out = NULL; } } + /* procedural face */ + if(model->numinlined && model->inlined && !(flags & M3D_EXP_NOFACE)) { + /* all inlined assets which are not textures should be procedural surfaces */ + for(j = 0; j < model->numinlined; j++) { + if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length < 4 || + !model->inlined[j].data || (model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && + model->inlined[j].data[3] == 'G')) + continue; + for(i = k = 0; i < model->numtexture; i++) { + if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } + } + if(k) continue; + numproc++; + chunklen = 8 + si_s; + h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); + if(!h) goto memerr; + memcpy((uint8_t*)h + len, "PROC", 4); + *((uint32_t*)((uint8_t*)h + len + 4)) = chunklen; + out = (uint8_t*)h + len + 8; + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->inlined[j].name)); + out = NULL; + len += chunklen; + } + } /* mesh face */ if(model->numface && face && !(flags & M3D_EXP_NOFACE)) { chunklen = 8 + si_s + model->numface * (6 * vi_s + 3 * ti_s + si_s + 1); @@ -4241,43 +5165,125 @@ memerr: if(face) M3D_FREE(face); memcpy((uint8_t*)h + len, "MESH", 4); length = (uint32_t*)((uint8_t*)h + len + 4); out = (uint8_t*)h + len + 8; - last = (M3D_INDEX)-1U; + last = M3D_UNDEF; for(i = 0; i < model->numface; i++) { - if(!(flags & M3D_EXP_NOMATERIAL) && face[i].materialid != last) { - last = face[i].materialid; - if(last < nummtrl) { - idx = _m3d_stridx(str, numstr, !mtrl ? model->material[last].name : mtrl[last]->name); - if(idx) { - *out++ = 0; - out = _m3d_addidx(out, si_s, idx); - } - } + if(!(flags & M3D_EXP_NOMATERIAL) && face[i].data.materialid != last) { + last = face[i].data.materialid; + idx = last < model->nummaterial ? _m3d_stridx(str, numstr, model->material[last].name) : 0; + *out++ = 0; + out = _m3d_addidx(out, si_s, idx); } /* hardcoded triangles. */ k = (3 << 4) | - (((flags & M3D_EXP_NOTXTCRD) || ti_s == 8 || (face[i].texcoord[0] == (M3D_INDEX)-1U && - face[i].texcoord[1] == (M3D_INDEX)-1U && face[i].texcoord[2] == (M3D_INDEX)-1U)) ? 0 : 1) | - (((flags & M3D_EXP_NONORMAL) || (face[i].normal[0] == (M3D_INDEX)-1U && - face[i].normal[1] == (M3D_INDEX)-1U && face[i].normal[2] == (M3D_INDEX)-1U)) ? 0 : 2); + (((flags & M3D_EXP_NOTXTCRD) || !ti_s || face[i].data.texcoord[0] == M3D_UNDEF || + face[i].data.texcoord[1] == M3D_UNDEF || face[i].data.texcoord[2] == M3D_UNDEF) ? 0 : 1) | + (((flags & M3D_EXP_NONORMAL) || face[i].data.normal[0] == M3D_UNDEF || + face[i].data.normal[1] == M3D_UNDEF || face[i].data.normal[2] == M3D_UNDEF) ? 0 : 2); *out++ = k; for(j = 0; j < 3; j++) { - out = _m3d_addidx(out, vi_s, face[i].vertex[j]); + out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.vertex[j]]); if(k & 1) - out = _m3d_addidx(out, ti_s, face[i].texcoord[j]); + out = _m3d_addidx(out, ti_s, tmapidx[face[i].data.texcoord[j]]); if(k & 2) - out = _m3d_addidx(out, vi_s, face[i].normal[j]); + out = _m3d_addidx(out, vi_s, vrtxidx[face[i].data.normal[j]]); } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); len += *length; out = NULL; } + /* mathematical shapes face */ + if(model->numshape && model->shape && !(flags & M3D_EXP_NOFACE)) { + for(j = 0; j < model->numshape; j++) { + chunklen = 12 + si_s + model->shape[j].numcmd * (M3D_CMDMAXARG + 1) * 4; + h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); + if(!h) goto memerr; + memcpy((uint8_t*)h + len, "SHPE", 4); + length = (uint32_t*)((uint8_t*)h + len + 4); + out = (uint8_t*)h + len + 8; + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->shape[j].name)); + out = _m3d_addidx(out, bi_s, model->shape[j].group); + for(i = 0; i < model->shape[j].numcmd; i++) { + cmd = &model->shape[j].cmd[i]; + if(cmd->type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0])) || !cmd->arg) + continue; + cd = &m3d_commandtypes[cmd->type]; + *out++ = (cmd->type & 0x7F) | (cmd->type > 127 ? 0x80 : 0); + if(cmd->type > 127) *out++ = (cmd->type >> 7) & 0xff; + for(k = n = 0, l = cd->p; k < l; k++) { + switch(cd->a[((k - n) % (cd->p - n)) + n]) { + case m3dcp_mi_t: + out = _m3d_addidx(out, si_s, cmd->arg[k] < model->nummaterial ? + _m3d_stridx(str, numstr, model->material[cmd->arg[k]].name) : 0); + break; + case m3dcp_vc_t: + min_x = *((float*)&cmd->arg[k]); + switch(vc_s) { + case 1: *out++ = (int8_t)(min_x * 127); break; + case 2: *((int16_t*)out) = (int16_t)(min_x * 32767); out += 2; break; + case 4: *((float*)out) = min_x; out += 4; break; + case 8: *((double*)out) = min_x; out += 8; break; + } + break; + case m3dcp_hi_t: out = _m3d_addidx(out, hi_s, cmd->arg[k]); break; + case m3dcp_fi_t: out = _m3d_addidx(out, fi_s, cmd->arg[k]); break; + case m3dcp_ti_t: out = _m3d_addidx(out, ti_s, cmd->arg[k]); break; + case m3dcp_qi_t: + case m3dcp_vi_t: out = _m3d_addidx(out, vi_s, cmd->arg[k]); break; + case m3dcp_i1_t: out = _m3d_addidx(out, 1, cmd->arg[k]); break; + case m3dcp_i2_t: out = _m3d_addidx(out, 2, cmd->arg[k]); break; + case m3dcp_i4_t: out = _m3d_addidx(out, 4, cmd->arg[k]); break; + case m3dcp_va_t: out = _m3d_addidx(out, 4, cmd->arg[k]); + n = k + 1; l += (cmd->arg[k] - 1) * (cd->p - k - 1); + break; + } + } + } + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); + len += *length; + out = NULL; + } + } + /* annotation labels */ + if(model->numlabel && model->label) { + for(i = 0, length = NULL; i < model->numlabel; i++) { + if(!i || _m3d_strcmp(sl, model->label[i].lang) || _m3d_strcmp(sn, model->label[i].name)) { + sl = model->label[i].lang; + sn = model->label[i].name; + if(length) { + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); + len += *length; + } + chunklen = 8 + 2 * si_s + ci_s + model->numlabel * (vi_s + si_s); + h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); + if(!h) { sn = NULL; sl = NULL; goto memerr; } + memcpy((uint8_t*)h + len, "LBLS", 4); + length = (uint32_t*)((uint8_t*)h + len + 4); + out = (uint8_t*)h + len + 8; + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].name)); + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].lang)); + idx = _m3d_cmapidx(cmap, numcmap, model->label[i].color); + switch(ci_s) { + case 1: *out++ = (uint8_t)(idx); break; + case 2: *((uint16_t*)out) = (uint16_t)(idx); out += 2; break; + case 4: *((uint32_t*)out) = model->label[i].color; out += 4; break; + } + } + out = _m3d_addidx(out, vi_s, vrtxidx[model->label[i].vertexid]); + out = _m3d_addidx(out, si_s, _m3d_stridx(str, numstr, model->label[l].text)); + } + if(length) { + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); + len += *length; + } + out = NULL; + sn = sl = NULL; + } /* actions */ - if(model->numaction && model->action && numactn && actn && numbone && bone && !(flags & M3D_EXP_NOACTION)) { - l = 0; + if(model->numaction && model->action && model->numbone && model->bone && !(flags & M3D_EXP_NOACTION)) { for(j = 0; j < model->numaction; j++) { a = &model->action[j]; - chunklen = 14 + si_s + a->numframe * (4 + fi_s + maxt * (bi_s + 2 * vi_s)); + chunklen = 14 + si_s + a->numframe * (4 + fc_s + maxt * (bi_s + 2 * vi_s)); h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; memcpy((uint8_t*)h + len, "ACTN", 4); @@ -4288,23 +5294,31 @@ memerr: if(face) M3D_FREE(face); *((uint32_t*)out) = (uint32_t)(a->durationmsec); out += 4; for(i = 0; i < a->numframe; i++) { *((uint32_t*)out) = (uint32_t)(a->frame[i].msec); out += 4; - out = _m3d_addidx(out, fi_s, a->frame[i].numtransform); + out = _m3d_addidx(out, fc_s, a->frame[i].numtransform); for(k = 0; k < a->frame[i].numtransform; k++) { out = _m3d_addidx(out, bi_s, a->frame[i].transform[k].boneid); - out = _m3d_addidx(out, vi_s, actn[l++]); - out = _m3d_addidx(out, vi_s, actn[l++]); + out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].pos]); + out = _m3d_addidx(out, vi_s, vrtxidx[a->frame[i].transform[k].ori]); } } - *length = (uint64_t)out - (uint64_t)((uint8_t*)h + len); + *length = (uint32_t)((uintptr_t)out - (uintptr_t)((uint8_t*)h + len)); len += *length; out = NULL; } } /* inlined assets */ - if(model->numinlined && model->inlined && (flags & M3D_EXP_INLINE)) { + if(model->numinlined && model->inlined && (numproc || (flags & M3D_EXP_INLINE))) { for(j = 0; j < model->numinlined; j++) { - if(!model->inlined[j].name || !*model->inlined[j].name || !model->inlined[j].length) + if(!model->inlined[j].name || !model->inlined[j].name[0] || model->inlined[j].length<4 || !model->inlined[j].data) continue; + if(!(flags & M3D_EXP_INLINE)) { + if(model->inlined[j].data[1] == 'P' && model->inlined[j].data[2] == 'N' && model->inlined[j].data[3] == 'G') + continue; + for(i = k = 0; i < model->numtexture; i++) { + if(!strcmp(model->inlined[j].name, model->texture[i].name)) { k = 1; break; } + } + if(k) continue; + } chunklen = 8 + si_s + model->inlined[j].length; h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; @@ -4318,14 +5332,14 @@ memerr: if(face) M3D_FREE(face); } } /* extra chunks */ - if(model->numunknown && model->unknown && (flags & M3D_EXP_EXTRA)) { - for(j = 0; j < model->numunknown; j++) { - if(!model->unknown[j] || model->unknown[j]->length < 8) + if(model->numextra && model->extra && (flags & M3D_EXP_EXTRA)) { + for(j = 0; j < model->numextra; j++) { + if(!model->extra[j] || model->extra[j]->length < 8) continue; - chunklen = model->unknown[j]->length; + chunklen = model->extra[j]->length; h = (m3dhdr_t*)M3D_REALLOC(h, len + chunklen); if(!h) goto memerr; - memcpy((uint8_t*)h + len, model->unknown[j], chunklen); + memcpy((uint8_t*)h + len, model->extra[j], chunklen); len += chunklen; } } @@ -4336,6 +5350,7 @@ memerr: if(face) M3D_FREE(face); len += 4; /* zlib compress */ if(!(flags & M3D_EXP_NOZLIB)) { + M3D_LOG("Deflating chunks"); z = stbi_zlib_compress((unsigned char *)h, len, (int*)&l, 9); if(z && l > 0 && l < len) { len = l; M3D_FREE(h); h = (m3dhdr_t*)z; } } @@ -4348,15 +5363,17 @@ memerr: if(face) M3D_FREE(face); memcpy(out + 8, h, len - 8); } if(size) *size = out ? len : 0; + if(vrtxidx) M3D_FREE(vrtxidx); + if(mtrlidx) M3D_FREE(mtrlidx); + if(tmapidx) M3D_FREE(tmapidx); + if(skinidx) M3D_FREE(skinidx); + if(norm) M3D_FREE(norm); if(face) M3D_FREE(face); if(cmap) M3D_FREE(cmap); if(tmap) M3D_FREE(tmap); - if(mtrl) M3D_FREE(mtrl); - if(vrtx) M3D_FREE(vrtx); - if(bone) M3D_FREE(bone); if(skin) M3D_FREE(skin); - if(actn) M3D_FREE(actn); if(str) M3D_FREE(str); + if(vrtx) M3D_FREE(vrtx); if(h) M3D_FREE(h); return out; } @@ -4397,6 +5414,14 @@ namespace M3D { this->model = m3d_load((unsigned char *)&data[0], ReadFileCB, FreeCB, mtllib.model); #else Model(); +#endif + } + Model(_unused const unsigned char *data, _unused m3dread_t ReadFileCB, + _unused m3dfree_t FreeCB, _unused M3D::Model mtllib) { +#ifndef M3D_NOIMPORTER + this->model = m3d_load((unsigned char*)data, ReadFileCB, FreeCB, mtllib.model); +#else + Model(); #endif } ~Model() { m3d_free(this->model); } @@ -4413,6 +5438,9 @@ namespace M3D { void setDescription(std::string desc) { this->model->desc = (char*)desc.c_str(); } float getScale() { return this->model->scale; } void setScale(float scale) { this->model->scale = scale; } + std::vector getPreview() { return this->model->preview.data ? + std::vector(this->model->preview.data, this->model->preview.data + this->model->preview.length) : + std::vector(); } std::vector getColorMap() { return this->model->cmap ? std::vector(this->model->cmap, this->model->cmap + this->model->numcmap) : std::vector(); } std::vector getTextureMap() { return this->model->tmap ? std::vector(this->model->tmap, @@ -4462,6 +5490,18 @@ namespace M3D { this->model->vertex + this->model->numvertex) : std::vector(); } std::vector getFace() { return this->model->face ? std::vector(this->model->face, this->model->face + this->model->numface) : std::vector(); } + std::vector getShape() { return this->model->shape ? std::vector(this->model->shape, + this->model->shape + this->model->numshape) : std::vector(); } + std::string getShapeName(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape && + this->model->shape[idx].name && this->model->shape[idx].name[0] ? + std::string(this->model->shape[idx].name) : nullptr; } + unsigned int getShapeGroup(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape ? + this->model->shape[idx].group : 0xFFFFFFFF; } + std::vector getShapeCommands(int idx) { return idx >= 0 && (unsigned int)idx < this->model->numshape && + this->model->shape[idx].cmd ? std::vector(this->model->shape[idx].cmd, this->model->shape[idx].cmd + + this->model->shape[idx].numcmd) : std::vector(); } + std::vector getAnnotationLabels() { return this->model->label ? std::vector(this->model->label, + this->model->label + this->model->numlabel) : std::vector(); } std::vector getSkin() { return this->model->skin ? std::vector(this->model->skin, this->model->skin + this->model->numskin) : std::vector(); } std::vector getActions() { return this->model->action ? std::vector(this->model->action, @@ -4491,9 +5531,9 @@ namespace M3D { return std::vector(pose, pose + this->model->numbone); } std::vector getInlinedAssets() { return this->model->inlined ? std::vector(this->model->inlined, this->model->inlined + this->model->numinlined) : std::vector(); } - std::vector> getUnknowns() { return this->model->unknown ? - std::vector>(this->model->unknown, - this->model->unknown + this->model->numunknown) : std::vector>(); } + std::vector> getExtras() { return this->model->extra ? + std::vector>(this->model->extra, + this->model->extra + this->model->numextra) : std::vector>(); } std::vector Save(_unused int quality, _unused int flags) { #ifdef M3D_EXPORTER unsigned int size; @@ -4513,6 +5553,7 @@ namespace M3D { public: Model(const std::string &data, m3dread_t ReadFileCB, m3dfree_t FreeCB); Model(const std::vector data, m3dread_t ReadFileCB, m3dfree_t FreeCB); + Model(const unsigned char *data, m3dread_t ReadFileCB, m3dfree_t FreeCB); Model(); ~Model(); @@ -4528,6 +5569,7 @@ namespace M3D { void setDescription(std::string desc); float getScale(); void setScale(float scale); + std::vector getPreview(); std::vector getColorMap(); std::vector getTextureMap(); std::vector getTextures(); @@ -4542,6 +5584,11 @@ namespace M3D { m3dtx_t* getMaterialPropertyMap(int idx, int type); std::vector getVertices(); std::vector getFace(); + std::vector getShape(); + std::string getShapeName(int idx); + unsigned int getShapeGroup(int idx); + std::vector getShapeCommands(int idx); + std::vector getAnnotationLabels(); std::vector getSkin(); std::vector getActions(); std::string getActionName(int aidx); @@ -4552,7 +5599,7 @@ namespace M3D { std::vector getActionFrame(int aidx, int fidx, std::vector skeleton); std::vector getActionPose(int aidx, unsigned int msec); std::vector getInlinedAssets(); - std::vector> getUnknowns(); + std::vector> getExtras(); std::vector Save(int quality, int flags); }; diff --git a/Engine/lib/assimp/code/MD2/MD2FileData.h b/Engine/lib/assimp/code/MD2/MD2FileData.h index 9fcb8b0e2..911cd4b98 100644 --- a/Engine/lib/assimp/code/MD2/MD2FileData.h +++ b/Engine/lib/assimp/code/MD2/MD2FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD2/MD2Loader.cpp b/Engine/lib/assimp/code/MD2/MD2Loader.cpp index 7023c0fa3..473ab99bc 100644 --- a/Engine/lib/assimp/code/MD2/MD2Loader.cpp +++ b/Engine/lib/assimp/code/MD2/MD2Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/MD2/MD2Loader.h b/Engine/lib/assimp/code/MD2/MD2Loader.h index a3863f366..cbebc90a4 100644 --- a/Engine/lib/assimp/code/MD2/MD2Loader.h +++ b/Engine/lib/assimp/code/MD2/MD2Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD2/MD2NormalTable.h b/Engine/lib/assimp/code/MD2/MD2NormalTable.h index f82b57683..c5c790872 100644 --- a/Engine/lib/assimp/code/MD2/MD2NormalTable.h +++ b/Engine/lib/assimp/code/MD2/MD2NormalTable.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD3/MD3FileData.h b/Engine/lib/assimp/code/MD3/MD3FileData.h index 2acd6631f..a98af199c 100644 --- a/Engine/lib/assimp/code/MD3/MD3FileData.h +++ b/Engine/lib/assimp/code/MD3/MD3FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD3/MD3Loader.cpp b/Engine/lib/assimp/code/MD3/MD3Loader.cpp index 1e78b6e05..2051ecdda 100644 --- a/Engine/lib/assimp/code/MD3/MD3Loader.cpp +++ b/Engine/lib/assimp/code/MD3/MD3Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -973,7 +973,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, aiScene* pScene, IOS AI_SWAP2( pcVertices[i].Z ); AI_SWAP4( pcUVs[i].U ); - AI_SWAP4( pcUVs[i].U ); + AI_SWAP4( pcUVs[i].V ); } for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i) { AI_SWAP4(pcTriangles[i].INDEXES[0]); diff --git a/Engine/lib/assimp/code/MD3/MD3Loader.h b/Engine/lib/assimp/code/MD3/MD3Loader.h index 01b840228..8d8304345 100644 --- a/Engine/lib/assimp/code/MD3/MD3Loader.h +++ b/Engine/lib/assimp/code/MD3/MD3Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD4/MD4FileData.h b/Engine/lib/assimp/code/MD4/MD4FileData.h index ed3dc65e7..880df3230 100644 --- a/Engine/lib/assimp/code/MD4/MD4FileData.h +++ b/Engine/lib/assimp/code/MD4/MD4FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2010, ASSIMP Development Team +Copyright (c) 2006-2020, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/Engine/lib/assimp/code/MD5/MD5Loader.cpp b/Engine/lib/assimp/code/MD5/MD5Loader.cpp index a4aed8d70..8c41794e7 100644 --- a/Engine/lib/assimp/code/MD5/MD5Loader.cpp +++ b/Engine/lib/assimp/code/MD5/MD5Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/MD5/MD5Loader.h b/Engine/lib/assimp/code/MD5/MD5Loader.h index e15cc3fb9..196ffb69a 100644 --- a/Engine/lib/assimp/code/MD5/MD5Loader.h +++ b/Engine/lib/assimp/code/MD5/MD5Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MD5/MD5Parser.cpp b/Engine/lib/assimp/code/MD5/MD5Parser.cpp index 37490212f..0d3b9c74a 100644 --- a/Engine/lib/assimp/code/MD5/MD5Parser.cpp +++ b/Engine/lib/assimp/code/MD5/MD5Parser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team diff --git a/Engine/lib/assimp/code/MD5/MD5Parser.h b/Engine/lib/assimp/code/MD5/MD5Parser.h index f7ff5303f..692cb72ba 100644 --- a/Engine/lib/assimp/code/MD5/MD5Parser.h +++ b/Engine/lib/assimp/code/MD5/MD5Parser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MDC/MDCFileData.h b/Engine/lib/assimp/code/MDC/MDCFileData.h index 052473158..9ec73c170 100644 --- a/Engine/lib/assimp/code/MDC/MDCFileData.h +++ b/Engine/lib/assimp/code/MDC/MDCFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MDC/MDCLoader.cpp b/Engine/lib/assimp/code/MDC/MDCLoader.cpp index 084ec6024..db4cdef54 100644 --- a/Engine/lib/assimp/code/MDC/MDCLoader.cpp +++ b/Engine/lib/assimp/code/MDC/MDCLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team @@ -355,7 +355,7 @@ void MDCImporter::InternReadFile( // swap all texture coordinates for (unsigned int i = 0; i < pcSurface->ulNumVertices;++i) { - AI_SWAP4( pcUVs->v ); + AI_SWAP4( pcUVs->u ); AI_SWAP4( pcUVs->v ); } diff --git a/Engine/lib/assimp/code/MDC/MDCLoader.h b/Engine/lib/assimp/code/MDC/MDCLoader.h index a21b8a55a..abd23bb19 100644 --- a/Engine/lib/assimp/code/MDC/MDCLoader.h +++ b/Engine/lib/assimp/code/MDC/MDCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2020, assimp team All rights reserved. diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1FileData.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1FileData.h new file mode 100644 index 000000000..a3cbb3439 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1FileData.h @@ -0,0 +1,600 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 HL1FileData.h + * @brief Definition of in-memory structures for the + * Half-Life 1 MDL file format. + */ + +#ifndef AI_HL1FILEDATA_INCLUDED +#define AI_HL1FILEDATA_INCLUDED + +#include "HalfLifeMDLBaseHeader.h" + +#include +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +using vec3_t = float[3]; + +/** \struct Header_HL1 + * \brief Data structure for the HL1 MDL file header. + */ +struct Header_HL1 : HalfLifeMDLBaseHeader { + //! The model name. + char name[64]; + + //! The total file size in bytes. + int32_t length; + + //! Ideal eye position. + vec3_t eyeposition; + + //! Ideal movement hull size. + vec3_t min; + vec3_t max; + + //! Clipping bounding box. + vec3_t bbmin; + vec3_t bbmax; + + //! Was "flags". + int32_t unused; + + //! The number of bones. + int32_t numbones; + + //! Offset to the first bone chunk. + int32_t boneindex; + + //! The number of bone controllers. + int32_t numbonecontrollers; + + //! Offset to the first bone controller chunk. + int32_t bonecontrollerindex; + + //! The number of hitboxes. + int32_t numhitboxes; + + //! Offset to the first hitbox chunk. + int32_t hitboxindex; + + //! The number of sequences. + int32_t numseq; + + //! Offset to the first sequence description chunk. + int32_t seqindex; + + //! The number of sequence groups. + int32_t numseqgroups; + + //! Offset to the first sequence group chunk. + int32_t seqgroupindex; + + //! The number of textures. + int32_t numtextures; + + //! Offset to the first texture chunk. + int32_t textureindex; + + //! Offset to the first texture's image data. + int32_t texturedataindex; + + //! The number of replaceable textures. + int32_t numskinref; + + //! The number of skin families. + int32_t numskinfamilies; + + //! Offset to the first replaceable texture. + int32_t skinindex; + + //! The number of bodyparts. + int32_t numbodyparts; + + //! Offset the the first bodypart. + int32_t bodypartindex; + + //! The number of attachments. + int32_t numattachments; + + //! Offset the the first attachment chunk. + int32_t attachmentindex; + + //! Was "soundtable". + int32_t unused2; + + //! Was "soundindex". + int32_t unused3; + + //! Was "soundgroups". + int32_t unused4; + + //! Was "soundgroupindex". + int32_t unused5; + + //! The number of nodes in the sequence transition graph. + int32_t numtransitions; + + //! Offset the the first sequence transition. + int32_t transitionindex; +} PACK_STRUCT; + +/** \struct SequenceHeader_HL1 + * \brief Data structure for the file header of a demand loaded + * HL1 MDL sequence group file. + */ +struct SequenceHeader_HL1 : HalfLifeMDLBaseHeader { + //! The sequence group file name. + char name[64]; + + //! The total file size in bytes. + int32_t length; +} PACK_STRUCT; + +/** \struct Bone_HL1 + * \brief Data structure for a bone in HL1 MDL files. + */ +struct Bone_HL1 { + //! The bone name. + char name[32]; + + //! The parent bone index. (-1) If it has no parent. + int32_t parent; + + //! Was "flags". + int32_t unused; + + //! Available bone controller per motion type. + //! (-1) if no controller is available. + int32_t bonecontroller[6]; + + /*! Default position and rotation values where + * scale[0] = position.X + * scale[1] = position.Y + * scale[2] = position.Z + * scale[3] = rotation.X + * scale[4] = rotation.Y + * scale[5] = rotation.Z + */ + float value[6]; + + /*! Compressed scale values where + * scale[0] = position.X scale + * scale[1] = position.Y scale + * scale[2] = position.Z scale + * scale[3] = rotation.X scale + * scale[4] = rotation.Y scale + * scale[5] = rotation.Z scale + */ + float scale[6]; +} PACK_STRUCT; + +/** \struct BoneController_HL1 + * \brief Data structure for a bone controller in HL1 MDL files. + */ +struct BoneController_HL1 { + //! Bone affected by this controller. + int32_t bone; + + //! The motion type. + int32_t type; + + //! The minimum and maximum values. + float start; + float end; + + // Was "rest". + int32_t unused; + + // The bone controller channel. + int32_t index; +} PACK_STRUCT; + +/** \struct Hitbox_HL1 + * \brief Data structure for a hitbox in HL1 MDL files. + */ +struct Hitbox_HL1 { + //! The bone this hitbox follows. + int32_t bone; + + //! The hit group. + int32_t group; + + //! The hitbox minimum and maximum extents. + vec3_t bbmin; + vec3_t bbmax; +} PACK_STRUCT; + +/** \struct SequenceGroup_HL1 + * \brief Data structure for a sequence group in HL1 MDL files. + */ +struct SequenceGroup_HL1 { + //! A textual name for this sequence group. + char label[32]; + + //! The file name. + char name[64]; + + //! Was "cache". + int32_t unused; + + //! Was "data". + int32_t unused2; +} PACK_STRUCT; + +//! The type of blending for a sequence. +enum SequenceBlendMode_HL1 { + NoBlend = 1, + TwoWayBlending = 2, + FourWayBlending = 4, +}; + +/** \struct SequenceDesc_HL1 + * \brief Data structure for a sequence description in HL1 MDL files. + */ +struct SequenceDesc_HL1 { + //! The sequence name. + char label[32]; + + //! Frames per second. + float fps; + + //! looping/non-looping flags. + int32_t flags; + + //! The sequence activity. + int32_t activity; + + //! The sequence activity weight. + int32_t actweight; + + //! The number of animation events. + int32_t numevents; + + //! Offset the the first animation event chunk. + int32_t eventindex; + + //! The number of frames in the sequence. + int32_t numframes; + + //! Was "numpivots". + int32_t unused; + + //! Was "pivotindex". + int32_t unused2; + + //! Linear motion type. + int32_t motiontype; + + //! Linear motion bone. + int32_t motionbone; + + //! Linear motion. + vec3_t linearmovement; + + //! Was "automoveposindex". + int32_t unused3; + + //! Was "automoveangleindex". + int32_t unused4; + + //! The sequence minimum and maximum extents. + vec3_t bbmin; + vec3_t bbmax; + + //! The number of blend animations. + int32_t numblends; + + //! Offset to first the AnimValueOffset_HL1 chunk. + //! This offset is relative to the SequenceHeader_HL1 of the file + //! that contains the animation data. + int32_t animindex; + + //! The motion type of each blend controller. + int32_t blendtype[2]; + + //! The starting value of each blend controller. + float blendstart[2]; + + //! The ending value of each blend controller. + float blendend[2]; + + //! Was "blendparent". + int32_t unused5; + + //! The sequence group. + int32_t seqgroup; + + //! The node at entry in the sequence transition graph. + int32_t entrynode; + + //! The node at exit in the sequence transition graph. + int32_t exitnode; + + //! Transition rules. + int32_t nodeflags; + + //! Was "nextseq" + int32_t unused6; +} PACK_STRUCT; + +/** \struct AnimEvent_HL1 + * \brief Data structure for an animation event in HL1 MDL files. + */ +struct AnimEvent_HL1 { + //! The frame at which this animation event occurs. + int32_t frame; + + //! The script event type. + int32_t event; + + //! was "type" + int32_t unused; + + //! Options. Could be path to sound WAVE files. + char options[64]; +} PACK_STRUCT; + +/** \struct Attachment_HL1 + * \brief Data structure for an attachment in HL1 MDL files. + */ +struct Attachment_HL1 { + //! Was "name". + char unused[32]; + + //! Was "type". + int32_t unused2; + + //! The bone this attachment follows. + int32_t bone; + + //! The attachment origin. + vec3_t org; + + //! Was "vectors" + vec3_t unused3[3]; +} PACK_STRUCT; + +/** \struct AnimValueOffset_HL1 + * \brief Data structure to hold offsets (one per motion type) + * to the first animation frame value for a single bone + * in HL1 MDL files. + */ +struct AnimValueOffset_HL1 { + unsigned short offset[6]; +} PACK_STRUCT; + +/** \struct AnimValue_HL1 + * \brief Data structure for an animation frame in HL1 MDL files. + */ +union AnimValue_HL1 { + struct { + uint8_t valid; + uint8_t total; + } num; + short value; +} PACK_STRUCT; + +/** \struct Bodypart_HL1 + * \brief Data structure for a bodypart in HL1 MDL files. + */ +struct Bodypart_HL1 { + //! The bodypart name. + char name[64]; + + //! The number of available models for this bodypart. + int32_t nummodels; + + //! Used to convert from a global model index + //! to a local bodypart model index. + int32_t base; + + //! The offset to the first model chunk. + int32_t modelindex; +} PACK_STRUCT; + +/** \struct Texture_HL1 + * \brief Data structure for a texture in HL1 MDL files. + */ +struct Texture_HL1 { + //! Texture file name. + char name[64]; + + //! Texture flags. + int32_t flags; + + //! Texture width in pixels. + int32_t width; + + //! Texture height in pixels. + int32_t height; + + //! Offset to the image data. + //! This offset is relative to the texture file header. + int32_t index; +} PACK_STRUCT; + +/** \struct Model_HL1 + * \brief Data structure for a model in HL1 MDL files. + */ +struct Model_HL1 { + //! Model name. + char name[64]; + + //! Was "type". + int32_t unused; + + //! Was "boundingradius". + float unused2; + + //! The number of meshes in the model. + int32_t nummesh; + + //! Offset to the first mesh chunk. + int32_t meshindex; + + //! The number of unique vertices. + int32_t numverts; + + //! Offset to the vertex bone array. + int32_t vertinfoindex; + + //! Offset to the vertex array. + int32_t vertindex; + + //! The number of unique normals. + int32_t numnorms; + + //! Offset to the normal bone array. + int32_t norminfoindex; + + //! Offset to the normal array. + int32_t normindex; + + //! Was "numgroups". + int32_t unused3; + + //! Was "groupindex". + int32_t unused4; +} PACK_STRUCT; + +/** \struct Mesh_HL1 + * \brief Data structure for a mesh in HL1 MDL files. + */ +struct Mesh_HL1 { + //! Can be interpreted as the number of triangles in the mesh. + int32_t numtris; + + //! Offset to the start of the tris sequence. + int32_t triindex; + + //! The skin index. + int32_t skinref; + + //! The number of normals in the mesh. + int32_t numnorms; + + //! Was "normindex". + int32_t unused; +} PACK_STRUCT; + +/** \struct Trivert + * \brief Data structure for a trivert in HL1 MDL files. + */ +struct Trivert { + //! Index into Model_HL1 vertex array. + short vertindex; + + //! Index into Model_HL1 normal array. + short normindex; + + //! Texture coordinates in absolute space (unnormalized). + short s, t; +} PACK_STRUCT; + +#include + +#if (!defined AI_MDL_HL1_VERSION) +#define AI_MDL_HL1_VERSION 10 +#endif +#if (!defined AI_MDL_HL1_MAX_TRIANGLES) +#define AI_MDL_HL1_MAX_TRIANGLES 20000 +#endif +#if (!defined AI_MDL_HL1_MAX_VERTICES) +#define AI_MDL_HL1_MAX_VERTICES 2048 +#endif +#if (!defined AI_MDL_HL1_MAX_SEQUENCES) +#define AI_MDL_HL1_MAX_SEQUENCES 2048 +#endif +#if (!defined AI_MDL_HL1_MAX_SEQUENCE_GROUPS) +#define AI_MDL_HL1_MAX_SEQUENCE_GROUPS 32 +#endif +#if (!defined AI_MDL_HL1_MAX_TEXTURES) +#define AI_MDL_HL1_MAX_TEXTURES 100 +#endif +#if (!defined AI_MDL_HL1_MAX_SKIN_FAMILIES) +#define AI_MDL_HL1_MAX_SKIN_FAMILIES 100 +#endif +#if (!defined AI_MDL_HL1_MAX_BONES) +#define AI_MDL_HL1_MAX_BONES 128 +#endif +#if (!defined AI_MDL_HL1_MAX_BODYPARTS) +#define AI_MDL_HL1_MAX_BODYPARTS 32 +#endif +#if (!defined AI_MDL_HL1_MAX_MODELS) +#define AI_MDL_HL1_MAX_MODELS 32 +#endif +#if (!defined AI_MDL_HL1_MAX_MESHES) +#define AI_MDL_HL1_MAX_MESHES 256 +#endif +#if (!defined AI_MDL_HL1_MAX_EVENTS) +#define AI_MDL_HL1_MAX_EVENTS 1024 +#endif +#if (!defined AI_MDL_HL1_MAX_BONE_CONTROLLERS) +#define AI_MDL_HL1_MAX_BONE_CONTROLLERS 8 +#endif +#if (!defined AI_MDL_HL1_MAX_ATTACHMENTS) +#define AI_MDL_HL1_MAX_ATTACHMENTS 512 +#endif + +// lighting options +#if (!defined AI_MDL_HL1_STUDIO_NF_FLATSHADE) +#define AI_MDL_HL1_STUDIO_NF_FLATSHADE 0x0001 +#endif +#if (!defined AI_MDL_HL1_STUDIO_NF_CHROME) +#define AI_MDL_HL1_STUDIO_NF_CHROME 0x0002 +#endif +#if (!defined AI_MDL_HL1_STUDIO_NF_ADDITIVE) +#define AI_MDL_HL1_STUDIO_NF_ADDITIVE 0x0020 +#endif +#if (!defined AI_MDL_HL1_STUDIO_NF_MASKED) +#define AI_MDL_HL1_STUDIO_NF_MASKED 0x0040 +#endif + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_HL1FILEDATA_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportDefinitions.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportDefinitions.h new file mode 100644 index 000000000..29b1cdceb --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportDefinitions.h @@ -0,0 +1,64 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 HL1ImportDefinitions.h + * @brief HL1 MDL loader specific definitions. + */ + +#ifndef AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED +#define AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED + +#define AI_MDL_HL1_NODE_ROOT "" +#define AI_MDL_HL1_NODE_BODYPARTS "" +#define AI_MDL_HL1_NODE_BONES "" +#define AI_MDL_HL1_NODE_BONE_CONTROLLERS "" +#define AI_MDL_HL1_NODE_SEQUENCE_INFOS "" +#define AI_MDL_HL1_NODE_SEQUENCE_GROUPS "" +#define AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH "" +#define AI_MDL_HL1_NODE_ATTACHMENTS "" +#define AI_MDL_HL1_NODE_HITBOXES "" +#define AI_MDL_HL1_NODE_GLOBAL_INFO "" +#define AI_MDL_HL1_NODE_ANIMATION_EVENTS "AnimationEvents" +#define AI_MDL_HL1_NODE_BLEND_CONTROLLERS "BlendControllers" + +#define AI_MDL_HL1_MATKEY_CHROME(type, N) "$mat.HL1.chrome", type, N + +#endif // AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportSettings.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportSettings.h new file mode 100644 index 000000000..50be1f366 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1ImportSettings.h @@ -0,0 +1,85 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 HL1ImportSettings.h + * @brief Half-Life 1 MDL loader configuration settings. + */ + +#ifndef AI_HL1IMPORTSETTINGS_INCLUDED +#define AI_HL1IMPORTSETTINGS_INCLUDED + +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +struct HL1ImportSettings { + HL1ImportSettings() : + read_animations(false), + read_animation_events(false), + read_blend_controllers(false), + read_sequence_groups_info(false), + read_sequence_transitions(false), + read_attachments(false), + read_bone_controllers(false), + read_hitboxes(false), + read_textures(false), + read_misc_global_info(false) { + } + + bool read_animations; + bool read_animation_events; + bool read_blend_controllers; + bool read_sequence_groups_info; + bool read_sequence_transitions; + bool read_attachments; + bool read_bone_controllers; + bool read_hitboxes; + bool read_textures; + bool read_misc_global_info; +}; + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_HL1IMPORTSETTINGS_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.cpp b/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.cpp new file mode 100644 index 000000000..c18528e59 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.cpp @@ -0,0 +1,1348 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 HL1MDLLoader.cpp + * @brief Implementation for the Half-Life 1 MDL loader. + */ + +#include "HL1MDLLoader.h" +#include "HL1ImportDefinitions.h" +#include "HL1MeshTrivert.h" +#include "UniqueNameGenerator.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef MDL_HALFLIFE_LOG_WARN_HEADER +#undef MDL_HALFLIFE_LOG_WARN_HEADER +#endif +#define MDL_HALFLIFE_LOG_HEADER "[Half-Life 1 MDL] " +#include "LogFunctions.h" + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +// ------------------------------------------------------------------------------------------------ +HL1MDLLoader::HL1MDLLoader( + aiScene *scene, + IOSystem *io, + const unsigned char *buffer, + const std::string &file_path, + const HL1ImportSettings &import_settings) : + scene_(scene), + io_(io), + buffer_(buffer), + file_path_(file_path), + import_settings_(import_settings), + header_(nullptr), + texture_header_(nullptr), + anim_headers_(nullptr), + texture_buffer_(nullptr), + anim_buffers_(nullptr), + num_sequence_groups_(0), + rootnode_children_(), + unique_name_generator_(), + unique_sequence_names_(), + unique_sequence_groups_names_(), + temp_bones_(), + num_blend_controllers_(0), + total_models_(0) { + load_file(); +} + +// ------------------------------------------------------------------------------------------------ +HL1MDLLoader::~HL1MDLLoader() { + release_resources(); +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::release_resources() { + if (buffer_ != texture_buffer_) { + delete[] texture_buffer_; + texture_buffer_ = nullptr; + } + + if (num_sequence_groups_ && anim_buffers_) { + for (int i = 1; i < num_sequence_groups_; ++i) { + if (anim_buffers_[i]) { + delete[] anim_buffers_[i]; + anim_buffers_[i] = nullptr; + } + } + + delete[] anim_buffers_; + anim_buffers_ = nullptr; + } + + if (anim_headers_) { + delete[] anim_headers_; + anim_headers_ = nullptr; + } + + // Root has some children nodes. so let's proceed them + if (!rootnode_children_.empty()) { + // Here, it means that the nodes were not added to the + // scene root node. We still have to delete them. + for (auto it = rootnode_children_.begin(); it != rootnode_children_.end(); ++it) { + if (*it) { + delete *it; + } + } + // Ensure this happens only once. + rootnode_children_.clear(); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::load_file() { + try { + header_ = (const Header_HL1 *)buffer_; + validate_header(header_, false); + + // Create the root scene node. + scene_->mRootNode = new aiNode(AI_MDL_HL1_NODE_ROOT); + + load_texture_file(); + + if (import_settings_.read_animations) { + load_sequence_groups_files(); + } + + read_textures(); + read_skins(); + + read_bones(); + read_meshes(); + + if (import_settings_.read_animations) { + read_sequence_groups_info(); + read_animations(); + read_sequence_infos(); + if (import_settings_.read_sequence_transitions) + read_sequence_transitions(); + } + + if (import_settings_.read_attachments) { + read_attachments(); + } + + if (import_settings_.read_hitboxes) { + read_hitboxes(); + } + + if (import_settings_.read_bone_controllers) { + read_bone_controllers(); + } + + read_global_info(); + + if (!header_->numbodyparts) { + // This could be an MDL external texture file. In this case, + // add this flag to allow the scene to be loaded even if it + // has no meshes. + scene_->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } + + // Append children to root node. + if (rootnode_children_.size()) { + scene_->mRootNode->addChildren( + static_cast(rootnode_children_.size()), + rootnode_children_.data()); + + // Clear the list of nodes so they will not be destroyed + // when resources are released. + rootnode_children_.clear(); + } + + release_resources(); + + } catch (...) { + release_resources(); + throw; + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::validate_header(const Header_HL1 *header, bool is_texture_header) { + if (is_texture_header) { + // Every single Half-Life model is assumed to have at least one texture. + if (!header->numtextures) { + throw DeadlyImportError(MDL_HALFLIFE_LOG_HEADER "There are no textures in the file"); + } + + if (header->numtextures > AI_MDL_HL1_MAX_TEXTURES) { + log_warning_limit_exceeded(header->numtextures, "textures"); + } + + if (header->numskinfamilies > AI_MDL_HL1_MAX_SKIN_FAMILIES) { + log_warning_limit_exceeded(header->numskinfamilies, "skin families"); + } + + } else { + + if (header->numbodyparts > AI_MDL_HL1_MAX_BODYPARTS) { + log_warning_limit_exceeded(header->numbodyparts, "bodyparts"); + } + + if (header->numbones > AI_MDL_HL1_MAX_BONES) { + log_warning_limit_exceeded(header->numbones, "bones"); + } + + if (header->numbonecontrollers > AI_MDL_HL1_MAX_BONE_CONTROLLERS) { + log_warning_limit_exceeded(header->numbonecontrollers, "bone controllers"); + } + + if (header->numseq > AI_MDL_HL1_MAX_SEQUENCES) { + log_warning_limit_exceeded(header->numseq, "sequences"); + } + + if (header->numseqgroups > AI_MDL_HL1_MAX_SEQUENCE_GROUPS) { + log_warning_limit_exceeded(header->numseqgroups, "sequence groups"); + } + + if (header->numattachments > AI_MDL_HL1_MAX_ATTACHMENTS) { + log_warning_limit_exceeded(header->numattachments, "attachments"); + } + } +} + +// ------------------------------------------------------------------------------------------------ +/* + Load textures. + + There are two ways for textures to be stored in a Half-Life model: + + 1. Directly in the MDL file (filePath) or + 2. In an external MDL file. + + Due to the way StudioMDL works (tool used to compile SMDs into MDLs), + it is assumed that an external texture file follows the naming + convention: T.mdl. Note the extra (T) at the end of the + model name. + + .e.g For a given model named MyModel.mdl + + The external texture file name would be MyModelT.mdl +*/ +void HL1MDLLoader::load_texture_file() { + if (header_->numtextures == 0) { + // Load an external MDL texture file. + std::string texture_file_path = + DefaultIOSystem::absolutePath(file_path_) + io_->getOsSeparator() + + DefaultIOSystem::completeBaseName(file_path_) + "T." + + BaseImporter::GetExtension(file_path_); + + load_file_into_buffer(texture_file_path, texture_buffer_); + } else { + // Model has no external texture file. This means the texture is stored inside the main MDL file. + texture_buffer_ = const_cast(buffer_); + } + + texture_header_ = (const Header_HL1 *)texture_buffer_; + + // Validate texture header. + validate_header(texture_header_, true); +} + +// ------------------------------------------------------------------------------------------------ +/* + Load sequence group files if any. + + Due to the way StudioMDL works (tool used to compile SMDs into MDLs), + it is assumed that a sequence group file follows the naming + convention: 0X.mdl. Note the extra (0X) at the end of + the model name, where (X) is the sequence group. + + .e.g For a given model named MyModel.mdl + + Sequence group 1 => MyModel01.mdl + Sequence group 2 => MyModel02.mdl + Sequence group X => MyModel0X.mdl + +*/ +void HL1MDLLoader::load_sequence_groups_files() { + if (header_->numseqgroups <= 1) { + return; + } + + num_sequence_groups_ = header_->numseqgroups; + + anim_buffers_ = new unsigned char *[num_sequence_groups_]; + anim_headers_ = new SequenceHeader_HL1 *[num_sequence_groups_]; + for (int i = 0; i < num_sequence_groups_; ++i) { + anim_buffers_[i] = nullptr; + anim_headers_[i] = nullptr; + } + + std::string file_path_without_extension = + DefaultIOSystem::absolutePath(file_path_) + + io_->getOsSeparator() + + DefaultIOSystem::completeBaseName(file_path_); + + for (int i = 1; i < num_sequence_groups_; ++i) { + std::stringstream ss; + ss << file_path_without_extension; + ss << std::setw(2) << std::setfill('0') << i; + ss << '.' << BaseImporter::GetExtension(file_path_); + + std::string sequence_file_path = ss.str(); + + load_file_into_buffer(sequence_file_path, anim_buffers_[i]); + + anim_headers_[i] = (SequenceHeader_HL1 *)anim_buffers_[i]; + } +} + +// ------------------------------------------------------------------------------------------------ +// Read an MDL texture. +void HL1MDLLoader::read_texture(const Texture_HL1 *ptexture, + uint8_t *data, uint8_t *pal, aiTexture *pResult, + aiColor3D &last_palette_color) { + pResult->mFilename = ptexture->name; + pResult->mWidth = static_cast(ptexture->width); + pResult->mHeight = static_cast(ptexture->height); + pResult->achFormatHint[0] = 'r'; + pResult->achFormatHint[1] = 'g'; + pResult->achFormatHint[2] = 'b'; + pResult->achFormatHint[3] = 'a'; + pResult->achFormatHint[4] = '8'; + pResult->achFormatHint[5] = '8'; + pResult->achFormatHint[6] = '8'; + pResult->achFormatHint[7] = '8'; + pResult->achFormatHint[8] = '\0'; + + const size_t num_pixels = pResult->mWidth * pResult->mHeight; + aiTexel *out = pResult->pcData = new aiTexel[num_pixels]; + + // Convert indexed 8 bit to 32 bit RGBA. + for (size_t i = 0; i < num_pixels; ++i, ++out) { + out->r = pal[data[i] * 3]; + out->g = pal[data[i] * 3 + 1]; + out->b = pal[data[i] * 3 + 2]; + out->a = 255; + } + + // Get the last palette color. + last_palette_color.r = pal[255 * 3]; + last_palette_color.g = pal[255 * 3 + 1]; + last_palette_color.b = pal[255 * 3 + 2]; +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_textures() { + const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex); + unsigned char *pin = texture_buffer_; + + scene_->mNumTextures = scene_->mNumMaterials = texture_header_->numtextures; + scene_->mTextures = new aiTexture *[scene_->mNumTextures]; + scene_->mMaterials = new aiMaterial *[scene_->mNumMaterials]; + + for (int i = 0; i < texture_header_->numtextures; ++i) { + scene_->mTextures[i] = new aiTexture(); + + aiColor3D last_palette_color; + read_texture(&ptexture[i], + pin + ptexture[i].index, + pin + ptexture[i].width * ptexture[i].height + ptexture[i].index, + scene_->mTextures[i], + last_palette_color); + + aiMaterial *scene_material = scene_->mMaterials[i] = new aiMaterial(); + + const aiTextureType texture_type = aiTextureType_DIFFUSE; + aiString texture_name(ptexture[i].name); + scene_material->AddProperty(&texture_name, AI_MATKEY_TEXTURE(texture_type, 0)); + + // Is this a chrome texture? + int chrome = ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_CHROME ? 1 : 0; + scene_material->AddProperty(&chrome, 1, AI_MDL_HL1_MATKEY_CHROME(texture_type, 0)); + + if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_FLATSHADE) { + // Flat shading. + const aiShadingMode shading_mode = aiShadingMode_Flat; + scene_material->AddProperty(&shading_mode, 1, AI_MATKEY_SHADING_MODEL); + } + + if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_ADDITIVE) { + // Additive texture. + const aiBlendMode blend_mode = aiBlendMode_Additive; + scene_material->AddProperty(&blend_mode, 1, AI_MATKEY_BLEND_FUNC); + } else if (ptexture[i].flags & AI_MDL_HL1_STUDIO_NF_MASKED) { + // Texture with 1 bit alpha test. + const aiTextureFlags use_alpha = aiTextureFlags_UseAlpha; + scene_material->AddProperty(&use_alpha, 1, AI_MATKEY_TEXFLAGS(texture_type, 0)); + scene_material->AddProperty(&last_palette_color, 1, AI_MATKEY_COLOR_TRANSPARENT); + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_skins() { + // Read skins, if any. + if (texture_header_->numskinfamilies <= 1) { + return; + } + + // Pointer to base texture index. + short *default_skin_ptr = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex); + + // Start at first replacement skin. + short *replacement_skin_ptr = default_skin_ptr + texture_header_->numskinref; + + for (int i = 1; i < texture_header_->numskinfamilies; ++i, replacement_skin_ptr += texture_header_->numskinref) { + for (int j = 0; j < texture_header_->numskinref; ++j) { + if (default_skin_ptr[j] != replacement_skin_ptr[j]) { + // Save replacement textures. + aiString skinMaterialId(scene_->mTextures[replacement_skin_ptr[j]]->mFilename); + scene_->mMaterials[default_skin_ptr[j]]->AddProperty(&skinMaterialId, AI_MATKEY_TEXTURE_DIFFUSE(i)); + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_bones() { + if (!header_->numbones) { + return; + } + + const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex); + + std::vector unique_bones_names(header_->numbones); + for (int i = 0; i < header_->numbones; ++i) { + unique_bones_names[i] = pbone[i].name; + } + + // Ensure bones have unique names. + unique_name_generator_.set_template_name("Bone"); + unique_name_generator_.make_unique(unique_bones_names); + + temp_bones_.resize(header_->numbones); + + aiNode *bones_node = new aiNode(AI_MDL_HL1_NODE_BONES); + rootnode_children_.push_back(bones_node); + bones_node->mNumChildren = static_cast(header_->numbones); + bones_node->mChildren = new aiNode *[bones_node->mNumChildren]; + + // Create bone matrices in local space. + for (int i = 0; i < header_->numbones; ++i) { + aiNode *bone_node = temp_bones_[i].node = bones_node->mChildren[i] = new aiNode(unique_bones_names[i]); + + aiVector3D angles(pbone[i].value[3], pbone[i].value[4], pbone[i].value[5]); + temp_bones_[i].absolute_transform = bone_node->mTransformation = + aiMatrix4x4(aiVector3D(1), aiQuaternion(angles.y, angles.z, angles.x), + aiVector3D(pbone[i].value[0], pbone[i].value[1], pbone[i].value[2])); + + if (pbone[i].parent == -1) { + bone_node->mParent = scene_->mRootNode; + } else { + bone_node->mParent = bones_node->mChildren[pbone[i].parent]; + + temp_bones_[i].absolute_transform = + temp_bones_[pbone[i].parent].absolute_transform * bone_node->mTransformation; + } + + temp_bones_[i].offset_matrix = temp_bones_[i].absolute_transform; + temp_bones_[i].offset_matrix.Inverse(); + } +} + +// ------------------------------------------------------------------------------------------------ +/* + Read meshes. + + Half-Life MDLs are structured such that each MDL + contains one or more 'bodypart(s)', which contain one + or more 'model(s)', which contains one or more mesh(es). + + * Bodyparts are used to group models that may be replaced + in the game .e.g a character could have a 'heads' group, + 'torso' group, 'shoes' group, with each group containing + different 'model(s)'. + + * Models, also called 'sub models', contain vertices as + well as a reference to each mesh used by the sub model. + + * Meshes contain a list of tris, also known as 'triverts'. + Each tris contains the following information: + + 1. The index of the position to use for the vertex. + 2. The index of the normal to use for the vertex. + 3. The S coordinate to use for the vertex UV. + 4. The T coordinate ^ + + These tris represent the way to represent the triangles + for each mesh. Depending on how the tool compiled the MDL, + those triangles were saved as strips and or fans. + + NOTE: Each tris is NOT unique. This means that you + might encounter the same vertex index but with a different + normal index, S coordinate, T coordinate. + + In addition, each mesh contains the texture's index. + + ------------------------------------------------------ + With the details above, there are several things to + take into consideration. + + * The Half-Life models store the vertices by sub model + rather than by mesh. Due to Assimp's structure, it + is necessary to remap each model vertex to be used + per mesh. Unfortunately, this has the consequence + to duplicate vertices. + + * Because the mesh triangles are comprised of strips and + fans, it is necessary to convert each primitive to + triangles, respectively (3 indices per face). +*/ +void HL1MDLLoader::read_meshes() { + if (!header_->numbodyparts) { + return; + } + + int total_verts = 0; + int total_triangles = 0; + total_models_ = 0; + + const Bodypart_HL1 *pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex); + const Model_HL1 *pmodel = nullptr; + const Mesh_HL1 *pmesh = nullptr; + + const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex); + short *pskinref = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex); + + scene_->mNumMeshes = 0; + + std::vector unique_bodyparts_names; + unique_bodyparts_names.resize(header_->numbodyparts); + + // Count the number of meshes. + + for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) { + unique_bodyparts_names[i] = pbodypart->name; + + pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex); + for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel) { + scene_->mNumMeshes += pmodel->nummesh; + total_verts += pmodel->numverts; + } + + total_models_ += pbodypart->nummodels; + } + + // Display limit infos. + if (total_verts > AI_MDL_HL1_MAX_VERTICES) { + log_warning_limit_exceeded(total_verts, "vertices"); + } + + if (scene_->mNumMeshes > AI_MDL_HL1_MAX_MESHES) { + log_warning_limit_exceeded(scene_->mNumMeshes, "meshes"); + } + + if (total_models_ > AI_MDL_HL1_MAX_MODELS) { + log_warning_limit_exceeded(total_models_, "models"); + } + + // Ensure bodyparts have unique names. + unique_name_generator_.set_template_name("Bodypart"); + unique_name_generator_.make_unique(unique_bodyparts_names); + + // Now do the same for each model. + pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex); + + // Prepare template name for bodypart models. + std::vector unique_models_names; + unique_models_names.resize(total_models_); + + unsigned int model_index = 0; + + for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) { + pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex); + for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel, ++model_index) + unique_models_names[model_index] = pmodel->name; + } + + unique_name_generator_.set_template_name("Model"); + unique_name_generator_.make_unique(unique_models_names); + + unsigned int mesh_index = 0; + + scene_->mMeshes = new aiMesh *[scene_->mNumMeshes]; + + pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex); + + /* Create a node that will represent the mesh hierarchy. + + + | + +-- bodypart --+-- model -- [mesh index, mesh index, ...] + | | + | +-- model -- [mesh index, mesh index, ...] + | | + | ... + | + |-- bodypart -- ... + | + ... + */ + aiNode *bodyparts_node = new aiNode(AI_MDL_HL1_NODE_BODYPARTS); + rootnode_children_.push_back(bodyparts_node); + bodyparts_node->mNumChildren = static_cast(header_->numbodyparts); + bodyparts_node->mChildren = new aiNode *[bodyparts_node->mNumChildren]; + aiNode **bodyparts_node_ptr = bodyparts_node->mChildren; + + // The following variables are defined here so they don't have + // to be recreated every iteration. + + // Model_HL1 vertices, in bind pose space. + std::vector bind_pose_vertices; + + // Model_HL1 normals, in bind pose space. + std::vector bind_pose_normals; + + // Used to contain temporary information for building a mesh. + std::vector triverts; + + std::vector tricmds; + + // Which triverts to use for the mesh. + std::vector mesh_triverts_indices; + + std::vector mesh_faces; + + /* triverts that have the same vertindex, but have different normindex,s,t values. + Similar triverts are mapped from vertindex to a list of similar triverts. */ + std::map> triverts_similars; + + // triverts per bone. + std::map> bone_triverts; + + /** This function adds a trivert index to the list of triverts per bone. + * \param[in] bone The bone that affects the trivert at index \p trivert_index. + * \param[in] trivert_index The trivert index. + */ + auto AddTrivertToBone = [&](int bone, short trivert_index) { + if (bone_triverts.count(bone) == 0) + bone_triverts.insert({ bone, std::set{ trivert_index }}); + else + bone_triverts[bone].insert(trivert_index); + }; + + /** This function creates and appends a new trivert to the list of triverts. + * \param[in] trivert The trivert to use as a prototype. + * \param[in] bone The bone that affects \p trivert. + */ + auto AddSimilarTrivert = [&](const Trivert &trivert, const int bone) { + HL1MeshTrivert new_trivert(trivert); + new_trivert.localindex = static_cast(mesh_triverts_indices.size()); + + short new_trivert_index = static_cast(triverts.size()); + + if (triverts_similars.count(trivert.vertindex) == 0) + triverts_similars.insert({ trivert.vertindex, std::set{ new_trivert_index }}); + else + triverts_similars[trivert.vertindex].insert(new_trivert_index); + + triverts.push_back(new_trivert); + + mesh_triverts_indices.push_back(new_trivert_index); + tricmds.push_back(new_trivert.localindex); + AddTrivertToBone(bone, new_trivert.localindex); + }; + + model_index = 0; + + for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart, ++bodyparts_node_ptr) { + pmodel = (const Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex); + + // Create bodypart node for the mesh tree hierarchy. + aiNode *bodypart_node = (*bodyparts_node_ptr) = new aiNode(unique_bodyparts_names[i]); + bodypart_node->mParent = bodyparts_node; + bodypart_node->mMetaData = aiMetadata::Alloc(1); + bodypart_node->mMetaData->Set(0, "Base", pbodypart->base); + + bodypart_node->mNumChildren = static_cast(pbodypart->nummodels); + bodypart_node->mChildren = new aiNode *[bodypart_node->mNumChildren]; + aiNode **bodypart_models_ptr = bodypart_node->mChildren; + + for (int j = 0; j < pbodypart->nummodels; + ++j, ++pmodel, ++bodypart_models_ptr, ++model_index) { + + pmesh = (const Mesh_HL1 *)((uint8_t *)header_ + pmodel->meshindex); + + uint8_t *pvertbone = ((uint8_t *)header_ + pmodel->vertinfoindex); + uint8_t *pnormbone = ((uint8_t *)header_ + pmodel->norminfoindex); + vec3_t *pstudioverts = (vec3_t *)((uint8_t *)header_ + pmodel->vertindex); + vec3_t *pstudionorms = (vec3_t *)((uint8_t *)header_ + pmodel->normindex); + + // Each vertex and normal is in local space, so transform + // each of them to bring them in bind pose. + bind_pose_vertices.resize(pmodel->numverts); + bind_pose_normals.resize(pmodel->numnorms); + for (size_t k = 0; k < bind_pose_vertices.size(); ++k) { + const vec3_t &vert = pstudioverts[k]; + bind_pose_vertices[k] = temp_bones_[pvertbone[k]].absolute_transform * aiVector3D(vert[0], vert[1], vert[2]); + } + for (size_t k = 0; k < bind_pose_normals.size(); ++k) { + const vec3_t &norm = pstudionorms[k]; + // Compute the normal matrix to transform the normal into bind pose, + // without affecting its length. + const aiMatrix4x4 normal_matrix = aiMatrix4x4(temp_bones_[pnormbone[k]].absolute_transform).Inverse().Transpose(); + bind_pose_normals[k] = normal_matrix * aiVector3D(norm[0], norm[1], norm[2]); + } + + // Create model node for the mesh tree hierarchy. + aiNode *model_node = (*bodypart_models_ptr) = new aiNode(unique_models_names[model_index]); + model_node->mParent = bodypart_node; + model_node->mNumMeshes = static_cast(pmodel->nummesh); + model_node->mMeshes = new unsigned int[model_node->mNumMeshes]; + unsigned int *model_meshes_ptr = model_node->mMeshes; + + for (int k = 0; k < pmodel->nummesh; ++k, ++pmesh, ++mesh_index, ++model_meshes_ptr) { + *model_meshes_ptr = mesh_index; + + // Read triverts. + short *ptricmds = (short *)((uint8_t *)header_ + pmesh->triindex); + float texcoords_s_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].width; + float texcoords_t_scale = 1.0f / (float)ptexture[pskinref[pmesh->skinref]].height; + + // Reset the data for the upcoming mesh. + triverts.clear(); + triverts.resize(pmodel->numverts); + mesh_triverts_indices.clear(); + mesh_faces.clear(); + triverts_similars.clear(); + bone_triverts.clear(); + + int l; + while ((l = *(ptricmds++))) { + bool is_triangle_fan = false; + + if (l < 0) { + l = -l; + is_triangle_fan = true; + } + + // Clear the list of tris for the upcoming tris. + tricmds.clear(); + + for (; l > 0; l--, ptricmds += 4) { + const Trivert *input_trivert = reinterpret_cast(ptricmds); + const int bone = pvertbone[input_trivert->vertindex]; + + HL1MeshTrivert *private_trivert = &triverts[input_trivert->vertindex]; + if (private_trivert->localindex == -1) { + // First time referenced. + *private_trivert = *input_trivert; + private_trivert->localindex = static_cast(mesh_triverts_indices.size()); + mesh_triverts_indices.push_back(input_trivert->vertindex); + tricmds.push_back(private_trivert->localindex); + AddTrivertToBone(bone, private_trivert->localindex); + } else if (*private_trivert == *input_trivert) { + // Exists and is the same. + tricmds.push_back(private_trivert->localindex); + } else { + // No similar trivert associated to the trivert currently processed. + if (triverts_similars.count(input_trivert->vertindex) == 0) + AddSimilarTrivert(*input_trivert, bone); + else { + // Search in the list of similar triverts to see if the + // trivert in process is already registered. + short similar_index = -1; + for (auto it = triverts_similars[input_trivert->vertindex].cbegin(); + similar_index == -1 && it != triverts_similars[input_trivert->vertindex].cend(); + ++it) { + if (triverts[*it] == *input_trivert) + similar_index = *it; + } + + // If a similar trivert has been found, reuse it. + // Otherwise, add it. + if (similar_index == -1) + AddSimilarTrivert(*input_trivert, bone); + else + tricmds.push_back(triverts[similar_index].localindex); + } + } + } + + // Build mesh faces. + const int num_faces = static_cast(tricmds.size() - 2); + mesh_faces.reserve(num_faces); + + if (is_triangle_fan) { + for (int i = 0; i < num_faces; ++i) { + mesh_faces.push_back(HL1MeshFace{ + tricmds[0], + tricmds[i + 1], + tricmds[i + 2] }); + } + } else { + for (int i = 0; i < num_faces; ++i) { + if (i & 1) { + // Preserve winding order. + mesh_faces.push_back(HL1MeshFace{ + tricmds[i + 1], + tricmds[i], + tricmds[i + 2] }); + } else { + mesh_faces.push_back(HL1MeshFace{ + tricmds[i], + tricmds[i + 1], + tricmds[i + 2] }); + } + } + } + + total_triangles += num_faces; + } + + // Create the scene mesh. + aiMesh *scene_mesh = scene_->mMeshes[mesh_index] = new aiMesh(); + scene_mesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_TRIANGLE; + scene_mesh->mMaterialIndex = pskinref[pmesh->skinref]; + + scene_mesh->mNumVertices = static_cast(mesh_triverts_indices.size()); + + if (scene_mesh->mNumVertices) { + scene_mesh->mVertices = new aiVector3D[scene_mesh->mNumVertices]; + scene_mesh->mNormals = new aiVector3D[scene_mesh->mNumVertices]; + + scene_mesh->mNumUVComponents[0] = 2; + scene_mesh->mTextureCoords[0] = new aiVector3D[scene_mesh->mNumVertices]; + + // Add vertices. + for (unsigned int v = 0; v < scene_mesh->mNumVertices; ++v) { + const HL1MeshTrivert *pTrivert = &triverts[mesh_triverts_indices[v]]; + scene_mesh->mVertices[v] = bind_pose_vertices[pTrivert->vertindex]; + scene_mesh->mNormals[v] = bind_pose_normals[pTrivert->normindex]; + scene_mesh->mTextureCoords[0][v] = aiVector3D( + pTrivert->s * texcoords_s_scale, + pTrivert->t * texcoords_t_scale, 0); + } + + // Add face and indices. + scene_mesh->mNumFaces = static_cast(mesh_faces.size()); + scene_mesh->mFaces = new aiFace[scene_mesh->mNumFaces]; + + for (unsigned int f = 0; f < scene_mesh->mNumFaces; ++f) { + aiFace *face = &scene_mesh->mFaces[f]; + face->mNumIndices = 3; + face->mIndices = new unsigned int[3]; + face->mIndices[0] = mesh_faces[f].v0; + face->mIndices[1] = mesh_faces[f].v1; + face->mIndices[2] = mesh_faces[f].v2; + } + + // Add mesh bones. + scene_mesh->mNumBones = static_cast(bone_triverts.size()); + scene_mesh->mBones = new aiBone *[scene_mesh->mNumBones]; + + aiBone **scene_bone_ptr = scene_mesh->mBones; + + for (auto bone_it = bone_triverts.cbegin(); + bone_it != bone_triverts.cend(); + ++bone_it, ++scene_bone_ptr) { + const int bone_index = bone_it->first; + + aiBone *scene_bone = (*scene_bone_ptr) = new aiBone(); + scene_bone->mName = temp_bones_[bone_index].node->mName; + + scene_bone->mOffsetMatrix = temp_bones_[bone_index].offset_matrix; + + auto vertex_ids = bone_triverts.at(bone_index); + + // Add vertex weight per bone. + scene_bone->mNumWeights = static_cast(vertex_ids.size()); + aiVertexWeight *vertex_weight_ptr = scene_bone->mWeights = new aiVertexWeight[scene_bone->mNumWeights]; + + for (auto vertex_it = vertex_ids.begin(); + vertex_it != vertex_ids.end(); + ++vertex_it, ++vertex_weight_ptr) { + vertex_weight_ptr->mVertexId = *vertex_it; + vertex_weight_ptr->mWeight = 1.0f; + } + } + } + } + } + } + + if (total_triangles > AI_MDL_HL1_MAX_TRIANGLES) { + log_warning_limit_exceeded(total_triangles, "triangles"); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_animations() { + if (!header_->numseq) { + return; + } + + const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex); + const SequenceGroup_HL1 *pseqgroup = nullptr; + const AnimValueOffset_HL1 *panim = nullptr; + const AnimValue_HL1 *panimvalue = nullptr; + + unique_sequence_names_.resize(header_->numseq); + for (int i = 0; i < header_->numseq; ++i) + unique_sequence_names_[i] = pseqdesc[i].label; + + // Ensure sequences have unique names. + unique_name_generator_.set_template_name("Sequence"); + unique_name_generator_.make_unique(unique_sequence_names_); + + scene_->mNumAnimations = 0; + + int highest_num_blend_animations = SequenceBlendMode_HL1::NoBlend; + + // Count the total number of animations. + for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) { + scene_->mNumAnimations += pseqdesc->numblends; + highest_num_blend_animations = std::max(pseqdesc->numblends, highest_num_blend_animations); + } + + // Get the number of available blend controllers for global info. + get_num_blend_controllers(highest_num_blend_animations, num_blend_controllers_); + + pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex); + + aiAnimation **scene_animations_ptr = scene_->mAnimations = new aiAnimation *[scene_->mNumAnimations]; + + for (int sequence = 0; sequence < header_->numseq; ++sequence, ++pseqdesc) { + pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex) + pseqdesc->seqgroup; + + if (pseqdesc->seqgroup == 0) { + panim = (const AnimValueOffset_HL1 *)((uint8_t *)header_ + pseqgroup->unused2 + pseqdesc->animindex); + } else { + panim = (const AnimValueOffset_HL1 *)((uint8_t *)anim_headers_[pseqdesc->seqgroup] + pseqdesc->animindex); + } + + for (int blend = 0; blend < pseqdesc->numblends; ++blend, ++scene_animations_ptr) { + + const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex); + + aiAnimation *scene_animation = (*scene_animations_ptr) = new aiAnimation(); + + scene_animation->mName = unique_sequence_names_[sequence]; + scene_animation->mTicksPerSecond = pseqdesc->fps; + scene_animation->mDuration = static_cast(pseqdesc->fps) * pseqdesc->numframes; + scene_animation->mNumChannels = static_cast(header_->numbones); + scene_animation->mChannels = new aiNodeAnim *[scene_animation->mNumChannels]; + + for (int bone = 0; bone < header_->numbones; bone++, ++pbone, ++panim) { + aiNodeAnim *node_anim = scene_animation->mChannels[bone] = new aiNodeAnim(); + node_anim->mNodeName = temp_bones_[bone].node->mName; + + node_anim->mNumPositionKeys = pseqdesc->numframes; + node_anim->mNumRotationKeys = node_anim->mNumPositionKeys; + node_anim->mNumScalingKeys = 0; + + node_anim->mPositionKeys = new aiVectorKey[node_anim->mNumPositionKeys]; + node_anim->mRotationKeys = new aiQuatKey[node_anim->mNumRotationKeys]; + + for (int frame = 0; frame < pseqdesc->numframes; ++frame) { + aiVectorKey *position_key = &node_anim->mPositionKeys[frame]; + aiQuatKey *rotation_key = &node_anim->mRotationKeys[frame]; + + aiVector3D angle1; + for (int j = 0; j < 3; ++j) { + if (panim->offset[j + 3] != 0) { + // Read compressed rotation delta. + panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j + 3]); + extract_anim_value(panimvalue, frame, pbone->scale[j + 3], angle1[j]); + } + + // Add the default rotation value. + angle1[j] += pbone->value[j + 3]; + + if (panim->offset[j] != 0) { + // Read compressed position delta. + panimvalue = (const AnimValue_HL1 *)((uint8_t *)panim + panim->offset[j]); + extract_anim_value(panimvalue, frame, pbone->scale[j], position_key->mValue[j]); + } + + // Add the default position value. + position_key->mValue[j] += pbone->value[j]; + } + + position_key->mTime = rotation_key->mTime = static_cast(frame); + /* The Half-Life engine uses X as forward, Y as left, Z as up. Therefore, + pitch,yaw,roll is represented as (YZX). */ + rotation_key->mValue = aiQuaternion(angle1.y, angle1.z, angle1.x); + rotation_key->mValue.Normalize(); + } + } + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_sequence_groups_info() { + if (!header_->numseqgroups) { + return; + } + + aiNode *sequence_groups_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_GROUPS); + rootnode_children_.push_back(sequence_groups_node); + + sequence_groups_node->mNumChildren = static_cast(header_->numseqgroups); + sequence_groups_node->mChildren = new aiNode *[sequence_groups_node->mNumChildren]; + + const SequenceGroup_HL1 *pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex); + + unique_sequence_groups_names_.resize(header_->numseqgroups); + for (int i = 0; i < header_->numseqgroups; ++i) { + unique_sequence_groups_names_[i] = pseqgroup[i].label; + } + + // Ensure sequence groups have unique names. + unique_name_generator_.set_template_name("SequenceGroup"); + unique_name_generator_.make_unique(unique_sequence_groups_names_); + + for (int i = 0; i < header_->numseqgroups; ++i, ++pseqgroup) { + aiNode *sequence_group_node = sequence_groups_node->mChildren[i] = new aiNode(unique_sequence_groups_names_[i]); + sequence_group_node->mParent = sequence_groups_node; + + aiMetadata *md = sequence_group_node->mMetaData = aiMetadata::Alloc(1); + if (i == 0) { + /* StudioMDL does not write the file name for the default sequence group, + so we will write it. */ + md->Set(0, "File", aiString(file_path_)); + } else { + md->Set(0, "File", aiString(pseqgroup->name)); + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_sequence_infos() { + if (!header_->numseq) { + return; + } + + const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex); + + aiNode *sequence_infos_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS); + rootnode_children_.push_back(sequence_infos_node); + + sequence_infos_node->mNumChildren = static_cast(header_->numseq); + sequence_infos_node->mChildren = new aiNode *[sequence_infos_node->mNumChildren]; + + std::vector sequence_info_node_children; + + int animation_index = 0; + for (int i = 0; i < header_->numseq; ++i, ++pseqdesc) { + // Clear the list of children for the upcoming sequence info node. + sequence_info_node_children.clear(); + + aiNode *sequence_info_node = sequence_infos_node->mChildren[i] = new aiNode(unique_sequence_names_[i]); + sequence_info_node->mParent = sequence_infos_node; + + // Setup sequence info node Metadata. + aiMetadata *md = sequence_info_node->mMetaData = aiMetadata::Alloc(16); + md->Set(0, "AnimationIndex", animation_index); + animation_index += pseqdesc->numblends; + + // Reference the sequence group by name. This allows us to search a particular + // sequence group by name using aiNode(s). + md->Set(1, "SequenceGroup", aiString(unique_sequence_groups_names_[pseqdesc->seqgroup])); + md->Set(2, "FramesPerSecond", pseqdesc->fps); + md->Set(3, "NumFrames", pseqdesc->numframes); + md->Set(4, "NumBlends", pseqdesc->numblends); + md->Set(5, "Activity", pseqdesc->activity); + md->Set(6, "ActivityWeight", pseqdesc->actweight); + md->Set(7, "MotionFlags", pseqdesc->motiontype); + md->Set(8, "MotionBone", temp_bones_[pseqdesc->motionbone].node->mName); + md->Set(9, "LinearMovement", aiVector3D(pseqdesc->linearmovement[0], pseqdesc->linearmovement[1], pseqdesc->linearmovement[2])); + md->Set(10, "BBMin", aiVector3D(pseqdesc->bbmin[0], pseqdesc->bbmin[1], pseqdesc->bbmin[2])); + md->Set(11, "BBMax", aiVector3D(pseqdesc->bbmax[0], pseqdesc->bbmax[1], pseqdesc->bbmax[2])); + md->Set(12, "EntryNode", pseqdesc->entrynode); + md->Set(13, "ExitNode", pseqdesc->exitnode); + md->Set(14, "NodeFlags", pseqdesc->nodeflags); + md->Set(15, "Flags", pseqdesc->flags); + + if (import_settings_.read_blend_controllers) { + int num_blend_controllers; + if (get_num_blend_controllers(pseqdesc->numblends, num_blend_controllers) && num_blend_controllers) { + // Read blend controllers info. + aiNode *blend_controllers_node = new aiNode(AI_MDL_HL1_NODE_BLEND_CONTROLLERS); + sequence_info_node_children.push_back(blend_controllers_node); + blend_controllers_node->mParent = sequence_info_node; + blend_controllers_node->mNumChildren = static_cast(num_blend_controllers); + blend_controllers_node->mChildren = new aiNode *[blend_controllers_node->mNumChildren]; + + for (unsigned int j = 0; j < blend_controllers_node->mNumChildren; ++j) { + aiNode *blend_controller_node = blend_controllers_node->mChildren[j] = new aiNode(); + blend_controller_node->mParent = blend_controllers_node; + + aiMetadata *md = blend_controller_node->mMetaData = aiMetadata::Alloc(3); + md->Set(0, "Start", pseqdesc->blendstart[j]); + md->Set(1, "End", pseqdesc->blendend[j]); + md->Set(2, "MotionFlags", pseqdesc->blendtype[j]); + } + } + } + + if (import_settings_.read_animation_events && pseqdesc->numevents) { + // Read animation events. + + if (pseqdesc->numevents > AI_MDL_HL1_MAX_EVENTS) { + log_warning_limit_exceeded( + "Sequence " + std::string(pseqdesc->label), + pseqdesc->numevents, "animation events"); + } + + const AnimEvent_HL1 *pevent = (const AnimEvent_HL1 *)((uint8_t *)header_ + pseqdesc->eventindex); + + aiNode *pEventsNode = new aiNode(AI_MDL_HL1_NODE_ANIMATION_EVENTS); + sequence_info_node_children.push_back(pEventsNode); + pEventsNode->mParent = sequence_info_node; + pEventsNode->mNumChildren = static_cast(pseqdesc->numevents); + pEventsNode->mChildren = new aiNode *[pEventsNode->mNumChildren]; + + for (unsigned int j = 0; j < pEventsNode->mNumChildren; ++j, ++pevent) { + aiNode *pEvent = pEventsNode->mChildren[j] = new aiNode(); + pEvent->mParent = pEventsNode; + + aiMetadata *md = pEvent->mMetaData = aiMetadata::Alloc(3); + md->Set(0, "Frame", pevent->frame); + md->Set(1, "ScriptEvent", pevent->event); + md->Set(2, "Options", aiString(pevent->options)); + } + } + + if (sequence_info_node_children.size()) { + sequence_info_node->addChildren( + static_cast(sequence_info_node_children.size()), + sequence_info_node_children.data()); + } + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_sequence_transitions() { + if (!header_->numtransitions) { + return; + } + + // Read sequence transition graph. + aiNode *transition_graph_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH); + rootnode_children_.push_back(transition_graph_node); + + uint8_t *ptransitions = ((uint8_t *)header_ + header_->transitionindex); + aiMetadata *md = transition_graph_node->mMetaData = aiMetadata::Alloc(header_->numtransitions * header_->numtransitions); + for (unsigned int i = 0; i < md->mNumProperties; ++i) + md->Set(i, std::to_string(i), static_cast(ptransitions[i])); +} + +void HL1MDLLoader::read_attachments() { + if (!header_->numattachments) { + return; + } + + const Attachment_HL1 *pattach = (const Attachment_HL1 *)((uint8_t *)header_ + header_->attachmentindex); + + aiNode *attachments_node = new aiNode(AI_MDL_HL1_NODE_ATTACHMENTS); + rootnode_children_.push_back(attachments_node); + attachments_node->mNumChildren = static_cast(header_->numattachments); + attachments_node->mChildren = new aiNode *[attachments_node->mNumChildren]; + + for (int i = 0; i < header_->numattachments; ++i, ++pattach) { + aiNode *attachment_node = attachments_node->mChildren[i] = new aiNode(); + attachment_node->mParent = attachments_node; + attachment_node->mMetaData = aiMetadata::Alloc(2); + attachment_node->mMetaData->Set(0, "Position", aiVector3D(pattach->org[0], pattach->org[1], pattach->org[2])); + // Reference the bone by name. This allows us to search a particular + // bone by name using aiNode(s). + attachment_node->mMetaData->Set(1, "Bone", temp_bones_[pattach->bone].node->mName); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_hitboxes() { + if (!header_->numhitboxes) { + return; + } + + const Hitbox_HL1 *phitbox = (const Hitbox_HL1 *)((uint8_t *)header_ + header_->hitboxindex); + + aiNode *hitboxes_node = new aiNode(AI_MDL_HL1_NODE_HITBOXES); + rootnode_children_.push_back(hitboxes_node); + hitboxes_node->mNumChildren = static_cast(header_->numhitboxes); + hitboxes_node->mChildren = new aiNode *[hitboxes_node->mNumChildren]; + + for (int i = 0; i < header_->numhitboxes; ++i, ++phitbox) { + aiNode *hitbox_node = hitboxes_node->mChildren[i] = new aiNode(); + hitbox_node->mParent = hitboxes_node; + + aiMetadata *md = hitbox_node->mMetaData = aiMetadata::Alloc(4); + // Reference the bone by name. This allows us to search a particular + // bone by name using aiNode(s). + md->Set(0, "Bone", temp_bones_[phitbox->bone].node->mName); + md->Set(1, "HitGroup", phitbox->group); + md->Set(2, "BBMin", aiVector3D(phitbox->bbmin[0], phitbox->bbmin[1], phitbox->bbmin[2])); + md->Set(3, "BBMax", aiVector3D(phitbox->bbmax[0], phitbox->bbmax[1], phitbox->bbmax[2])); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_bone_controllers() { + if (!header_->numbonecontrollers) { + return; + } + + const BoneController_HL1 *pbonecontroller = (const BoneController_HL1 *)((uint8_t *)header_ + header_->bonecontrollerindex); + + aiNode *bones_controller_node = new aiNode(AI_MDL_HL1_NODE_BONE_CONTROLLERS); + rootnode_children_.push_back(bones_controller_node); + bones_controller_node->mNumChildren = static_cast(header_->numbonecontrollers); + bones_controller_node->mChildren = new aiNode *[bones_controller_node->mNumChildren]; + + for (int i = 0; i < header_->numbonecontrollers; ++i, ++pbonecontroller) { + aiNode *bone_controller_node = bones_controller_node->mChildren[i] = new aiNode(); + bone_controller_node->mParent = bones_controller_node; + + aiMetadata *md = bone_controller_node->mMetaData = aiMetadata::Alloc(5); + // Reference the bone by name. This allows us to search a particular + // bone by name using aiNode(s). + md->Set(0, "Bone", temp_bones_[pbonecontroller->bone].node->mName); + md->Set(1, "MotionFlags", pbonecontroller->type); + md->Set(2, "Start", pbonecontroller->start); + md->Set(3, "End", pbonecontroller->end); + md->Set(4, "Channel", pbonecontroller->index); + } +} + +// ------------------------------------------------------------------------------------------------ +void HL1MDLLoader::read_global_info() { + aiNode *global_info_node = new aiNode(AI_MDL_HL1_NODE_GLOBAL_INFO); + rootnode_children_.push_back(global_info_node); + + aiMetadata *md = global_info_node->mMetaData = aiMetadata::Alloc(import_settings_.read_misc_global_info ? 16 : 11); + md->Set(0, "Version", AI_MDL_HL1_VERSION); + md->Set(1, "NumBodyparts", header_->numbodyparts); + md->Set(2, "NumModels", total_models_); + md->Set(3, "NumBones", header_->numbones); + md->Set(4, "NumAttachments", import_settings_.read_attachments ? header_->numattachments : 0); + md->Set(5, "NumSkinFamilies", texture_header_->numskinfamilies); + md->Set(6, "NumHitboxes", import_settings_.read_hitboxes ? header_->numhitboxes : 0); + md->Set(7, "NumBoneControllers", import_settings_.read_bone_controllers ? header_->numbonecontrollers : 0); + md->Set(8, "NumSequences", import_settings_.read_animations ? header_->numseq : 0); + md->Set(9, "NumBlendControllers", import_settings_.read_blend_controllers ? num_blend_controllers_ : 0); + md->Set(10, "NumTransitionNodes", import_settings_.read_sequence_transitions ? header_->numtransitions : 0); + + if (import_settings_.read_misc_global_info) { + md->Set(11, "EyePosition", aiVector3D(header_->eyeposition[0], header_->eyeposition[1], header_->eyeposition[2])); + md->Set(12, "HullMin", aiVector3D(header_->min[0], header_->min[1], header_->min[2])); + md->Set(13, "HullMax", aiVector3D(header_->max[0], header_->max[1], header_->max[2])); + md->Set(14, "CollisionMin", aiVector3D(header_->bbmin[0], header_->bbmin[1], header_->bbmin[2])); + md->Set(15, "CollisionMax", aiVector3D(header_->bbmax[0], header_->bbmax[1], header_->bbmax[2])); + } +} + +// ------------------------------------------------------------------------------------------------ +/** @brief This method reads a compressed anim value. +* +* @note The structure of this method is taken from HL2 source code. +* Although this is from HL2, it's implementation is almost identical +* to code found in HL1 SDK. See HL1 and HL2 SDKs for more info. +* +* source: +* HL1 source code. +* file: studio_render.cpp +* function(s): CalcBoneQuaternion and CalcBonePosition +* +* HL2 source code. +* file: bone_setup.cpp +* function(s): ExtractAnimValue +*/ +void HL1MDLLoader::extract_anim_value( + const AnimValue_HL1 *panimvalue, + int frame, float bone_scale, float &value) { + int k = frame; + + // find span of values that includes the frame we want + while (panimvalue->num.total <= k) { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + } + + // Bah, missing blend! + if (panimvalue->num.valid > k) { + value = panimvalue[k + 1].value * bone_scale; + } else { + value = panimvalue[panimvalue->num.valid].value * bone_scale; + } +} + +// ------------------------------------------------------------------------------------------------ +// Get the number of blend controllers. +bool HL1MDLLoader::get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers) { + + switch (num_blend_animations) { + case SequenceBlendMode_HL1::NoBlend: + num_blend_controllers = 0; + return true; + case SequenceBlendMode_HL1::TwoWayBlending: + num_blend_controllers = 1; + return true; + case SequenceBlendMode_HL1::FourWayBlending: + num_blend_controllers = 2; + return true; + default: + num_blend_controllers = 0; + ASSIMP_LOG_WARN(MDL_HALFLIFE_LOG_HEADER "Unsupported number of blend animations (" + std::to_string(num_blend_animations) + ")"); + return false; + } +} + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.h new file mode 100644 index 000000000..c4293259c --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1MDLLoader.h @@ -0,0 +1,241 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 HL1MDLLoader.h + * @brief Declaration of the Half-Life 1 MDL loader. + */ + +#ifndef AI_HL1MDLLOADER_INCLUDED +#define AI_HL1MDLLOADER_INCLUDED + +#include "HL1FileData.h" +#include "HL1ImportSettings.h" +#include "UniqueNameGenerator.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +class HL1MDLLoader { +public: + HL1MDLLoader() = delete; + HL1MDLLoader(const HL1MDLLoader &) = delete; + + /** See variables descriptions at the end for more details. */ + HL1MDLLoader( + aiScene *scene, + IOSystem *io, + const unsigned char *buffer, + const std::string &file_path, + const HL1ImportSettings &import_settings); + + ~HL1MDLLoader(); + + void load_file(); + +protected: + /** \brief Validate the header data structure of a Half-Life 1 MDL file. + * \param[in] header Input header to be validated. + * \param[in] is_texture_header Whether or not we are reading an MDL + * texture file. + */ + void validate_header(const Header_HL1 *header, bool is_texture_header); + + void load_texture_file(); + void load_sequence_groups_files(); + void read_textures(); + void read_skins(); + void read_bones(); + void read_meshes(); + void read_animations(); + void read_sequence_groups_info(); + void read_sequence_infos(); + void read_sequence_transitions(); + void read_attachments(); + void read_hitboxes(); + void read_bone_controllers(); + void read_global_info(); + +private: + void release_resources(); + + /** \brief Load a file and copy it's content to a buffer. + * \param file_path The path to the file to be loaded. + * \param buffer A pointer to a buffer to receive the data. + */ + template + void load_file_into_buffer(const std::string &file_path, unsigned char *&buffer); + + /** \brief Read an MDL texture. + * \param[in] ptexture A pointer to an MDL texture. + * \param[in] data A pointer to the data from \p ptexture. + * \param[in] pal A pointer to the texture palette from \p ptexture. + * \param[in,out] pResult A pointer to the output resulting Assimp texture. + * \param[in,out] last_palette_color The last color from the image palette. + */ + void read_texture(const Texture_HL1 *ptexture, + uint8_t *data, uint8_t *pal, aiTexture *pResult, + aiColor3D &last_palette_color); + + /** \brief This method reads a compressed anim value. + * \param[in] panimvalue A pointer to the animation data. + * \param[in] frame The frame to look for. + * \param[in] bone_scale The current bone scale to apply to the compressed value. + * \param[in,out] value The decompressed anim value at \p frame. + */ + void extract_anim_value(const AnimValue_HL1 *panimvalue, + int frame, float bone_scale, float &value); + + /** + * \brief Given the number of blend animations, determine the number of blend controllers. + * + * \param[in] num_blend_animations The number of blend animations. + * \param[out] num_blend_controllers The number of blend controllers. + * \return True if the number of blend controllers was determined. False otherwise. + */ + static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers); + + /** Output scene to be filled */ + aiScene *scene_; + + /** Output I/O handler. Required for additional IO operations. */ + IOSystem *io_; + + /** Buffer from MDLLoader class. */ + const unsigned char *buffer_; + + /** The full file path to the MDL file we are trying to load. + * Used to locate other MDL files since MDL may store resources + * in external MDL files. */ + const std::string &file_path_; + + /** Configuration for HL1 MDL */ + const HL1ImportSettings &import_settings_; + + /** Main MDL header. */ + const Header_HL1 *header_; + + /** External MDL texture header. */ + const Header_HL1 *texture_header_; + + /** External MDL animation headers. + * One for each loaded animation file. */ + SequenceHeader_HL1 **anim_headers_; + + /** Texture file data. */ + unsigned char *texture_buffer_; + + /** Animation files data. */ + unsigned char **anim_buffers_; + + /** The number of sequence groups. */ + int num_sequence_groups_; + + /** The list of children to be appended to the scene's root node. */ + std::vector rootnode_children_; + + /** A unique name generator. Used to generate names for MDL values + * that may have empty/duplicate names. */ + UniqueNameGenerator unique_name_generator_; + + /** The list of unique sequence names. */ + std::vector unique_sequence_names_; + + /** The list of unique sequence groups names. */ + std::vector unique_sequence_groups_names_; + + /** Structure to store temporary bone information. */ + struct TempBone { + + TempBone() : + node(nullptr), + absolute_transform(), + offset_matrix() {} + + aiNode *node; + aiMatrix4x4 absolute_transform; + aiMatrix4x4 offset_matrix; + }; + + std::vector temp_bones_; + + /** The number of available bone controllers in the model. */ + int num_blend_controllers_; + + /** Self explanatory. */ + int total_models_; +}; + +// ------------------------------------------------------------------------------------------------ +template +void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) { + if (!io_->Exists(file_path)) + throw DeadlyImportError("Missing file " + DefaultIOSystem::fileName(file_path) + "."); + + std::unique_ptr file(io_->Open(file_path)); + + if (file.get() == NULL) + throw DeadlyImportError("Failed to open MDL file " + DefaultIOSystem::fileName(file_path) + "."); + + const size_t file_size = file->FileSize(); + if (file_size < sizeof(MDLFileHeader)) + throw DeadlyImportError("MDL file is too small."); + + buffer = new unsigned char[1 + file_size]; + file->Read((void *)buffer, 1, file_size); + buffer[file_size] = '\0'; +} + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_HL1MDLLOADER_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HL1MeshTrivert.h b/Engine/lib/assimp/code/MDL/HalfLife/HL1MeshTrivert.h new file mode 100644 index 000000000..b61765663 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HL1MeshTrivert.h @@ -0,0 +1,127 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 HL1MeshTrivert.h + * @brief This file contains the class declaration for the + * HL1 mesh trivert class. + */ + +#ifndef AI_HL1MESHTRIVERT_INCLUDED +#define AI_HL1MESHTRIVERT_INCLUDED + +#include "HL1FileData.h" + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +/* A class to help map model triverts to mesh triverts. */ +struct HL1MeshTrivert { + HL1MeshTrivert() : + vertindex(-1), + normindex(-1), + s(0), + t(0), + localindex(-1) { + } + + HL1MeshTrivert(short vertindex, short normindex, short s, short t, short localindex) : + vertindex(vertindex), + normindex(normindex), + s(s), + t(t), + localindex() { + } + + HL1MeshTrivert(const Trivert &a) : + vertindex(a.vertindex), + normindex(a.normindex), + s(a.s), + t(a.t), + localindex(-1) { + } + + inline bool operator==(const Trivert &a) const { + return vertindex == a.vertindex && + normindex == a.normindex && + s == a.s && + t == a.t; + } + + inline bool operator!=(const Trivert &a) const { + return !(*this == a); + } + + inline bool operator==(const HL1MeshTrivert &a) const { + return localindex == a.localindex && + vertindex == a.vertindex && + normindex == a.normindex && + s == a.s && + t == a.t; + } + + inline bool operator!=(const HL1MeshTrivert &a) const { + return !(*this == a); + } + + inline HL1MeshTrivert &operator=(const Trivert &other) { + vertindex = other.vertindex; + normindex = other.normindex; + s = other.s; + t = other.t; + return *this; + } + + short vertindex; + short normindex; + short s, t; + short localindex; +}; + +struct HL1MeshFace { + short v0, v1, v2; +}; + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_HL1MESHTRIVERT_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/HalfLifeMDLBaseHeader.h b/Engine/lib/assimp/code/MDL/HalfLife/HalfLifeMDLBaseHeader.h new file mode 100644 index 000000000..f26f8735d --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/HalfLifeMDLBaseHeader.h @@ -0,0 +1,67 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 HalfLifeMDLBaseHeader.h */ + +#ifndef AI_HALFLIFEMDLBASEHEADER_INCLUDED +#define AI_HALFLIFEMDLBASEHEADER_INCLUDED + +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +/** Used to interface different Valve MDL formats. */ +struct HalfLifeMDLBaseHeader +{ + //! Magic number: "IDST"/"IDSQ" + char ident[4]; + + //! The file format version. + int32_t version; +}; + +} +} +} + +#endif // AI_HALFLIFEMDLBASEHEADER_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/LogFunctions.h b/Engine/lib/assimp/code/MDL/HalfLife/LogFunctions.h new file mode 100644 index 000000000..5e18a8df7 --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/LogFunctions.h @@ -0,0 +1,95 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 LogFunctions.h */ + +#ifndef AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED +#define AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED + +#include +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +/** + * \brief A function to log precise messages regarding limits exceeded. + * + * \param[in] subject Subject. + * \param[in] current_amount Current amount. + * \param[in] direct_object Direct object. + * LIMIT Limit constant. + * + * Example: Model has 100 textures, which exceeds the limit (50) + * + * where \p subject is 'Model' + * \p current_amount is '100' + * \p direct_object is 'textures' + * LIMIT is '50' + */ +template +static inline void log_warning_limit_exceeded( + const std::string &subject, int current_amount, + const std::string &direct_object) { + + ASSIMP_LOG_WARN(MDL_HALFLIFE_LOG_HEADER + + subject + + " has " + + std::to_string(current_amount) + " " + + direct_object + + ", which exceeds the limit (" + + std::to_string(LIMIT) + + ")"); +} + +/** \brief Same as above, but uses 'Model' as the subject. */ +template +static inline void log_warning_limit_exceeded(int current_amount, + const std::string &direct_object) { + log_warning_limit_exceeded("Model", current_amount, direct_object); +} + +} // namespace HalfLife +} // namespace MDL +} // namespace Assimp + +#endif // AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED diff --git a/Engine/lib/assimp/code/MDL/HalfLife/UniqueNameGenerator.cpp b/Engine/lib/assimp/code/MDL/HalfLife/UniqueNameGenerator.cpp new file mode 100644 index 000000000..417a6baef --- /dev/null +++ b/Engine/lib/assimp/code/MDL/HalfLife/UniqueNameGenerator.cpp @@ -0,0 +1,180 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, 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 UniqueNameGenerator.cpp + * @brief Implementation for the unique name generator. + */ + +#include "UniqueNameGenerator.h" +#include +#include +#include +#include + +namespace Assimp { +namespace MDL { +namespace HalfLife { + +UniqueNameGenerator::UniqueNameGenerator() : + template_name_("unnamed"), + separator_("_") { +} + +UniqueNameGenerator::UniqueNameGenerator(const char *template_name) : + template_name_(template_name), + separator_("_") { +} + +UniqueNameGenerator::UniqueNameGenerator(const char *template_name, const char *separator) : + template_name_(template_name), + separator_(separator) { +} + +UniqueNameGenerator::~UniqueNameGenerator() { +} + +void UniqueNameGenerator::make_unique(std::vector &names) { + struct DuplicateInfo { + DuplicateInfo() : + indices(), + next_id(0) { + } + + std::list indices; + size_t next_id; + }; + + std::vector empty_names_indices; + std::vector template_name_duplicates; + std::map names_to_duplicates; + + const std::string template_name_with_separator(template_name_ + separator_); + + auto format_name = [&](const std::string &base_name, size_t id) -> std::string { + return base_name + separator_ + std::to_string(id); + }; + + auto generate_unique_name = [&](const std::string &base_name) -> std::string { + auto *duplicate_info = &names_to_duplicates[base_name]; + + std::string new_name = ""; + + bool found_identical_name; + bool tried_with_base_name_only = false; + do { + // Assume that no identical name exists. + found_identical_name = false; + + if (!tried_with_base_name_only) { + // First try with only the base name. + new_name = base_name; + } else { + // Create the name expected to be unique. + new_name = format_name(base_name, duplicate_info->next_id); + } + + // Check in the list of duplicates for an identical name. + for (size_t i = 0; + i < names.size() && + !found_identical_name; + ++i) { + if (new_name == names[i]) + found_identical_name = true; + } + + if (tried_with_base_name_only) + ++duplicate_info->next_id; + + tried_with_base_name_only = true; + + } while (found_identical_name); + + return new_name; + }; + + for (size_t i = 0; i < names.size(); ++i) { + // Check for empty names. + if (names[i].find_first_not_of(' ') == std::string::npos) { + empty_names_indices.push_back(i); + continue; + } + + /* Check for potential duplicate. + a) Either if this name is the same as the template name or + b)