diff --git a/build.gradle b/build.gradle index 4f76995..ef08ea3 100644 --- a/build.gradle +++ b/build.gradle @@ -75,7 +75,7 @@ task javadocJar(type: Jar, dependsOn: javadoc) { test { useJUnitPlatform() -// minHeapSize = "16G" + maxHeapSize = "1G" // systemProperties['junit.jupiter.execution.parallel.enabled'] = true // maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1 // forkEvery = 1 diff --git a/src/main/kotlin/assimp/assimp.kt b/src/main/kotlin/assimp/assimp.kt index 7a852a5..af918e9 100644 --- a/src/main/kotlin/assimp/assimp.kt +++ b/src/main/kotlin/assimp/assimp.kt @@ -20,7 +20,7 @@ fun Mat4.decompose(pScaling: AiVector3D, pRotation: AiQuaternion, pPosition: AiV val vCols = listOf( AiVector3D(this[0, 0], this[1, 0], this[2, 0]), AiVector3D(this[0, 1], this[1, 1], this[2, 1]), - AiVector3D(this[0 ,2], this[1, 2], this[2, 2])) + AiVector3D(this[0, 2], this[1, 2], this[2, 2])) /* extract the scaling factors */ pScaling.x = vCols[0].length() @@ -54,12 +54,18 @@ operator fun AiMatrix4x4.times(vector: AiVector3D) = AiVector3D( internal const val epsilon = 10e-3f val Vec3.isBlack: Boolean get() = abs(r) < epsilon && abs(g) < epsilon && abs(b) < epsilon + /** Byte Order Mark * https://unicode-table.com/en/FEFF/ * https://stackoverflow.com/questions/26407406/cannot-find-zero-width-no-break-space-when-reading-file?rq=1 */ -val Char.isByteOrderMark: Boolean - get() = equals('\uFFFE') // UTF-16LE - || equals('\uFEFF') // UTF-16BE +val String.byteOrderMarkLength: Int + get() = when { + // UTF-16LE or UTF-16BE + get(0) == '\uFFFE' || get(0) == '\uFEFF' -> 1 + // UTF-8 + get(0) == '\u00EF' && get(1) == '\u00BB' && get(2) == '\u00BF' -> 3 + else -> 0 + } object ASSIMP { diff --git a/src/main/kotlin/assimp/format/obj/ObjFileData.kt b/src/main/kotlin/assimp/format/obj/ObjFileData.kt index 2901ceb..9355718 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileData.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileData.kt @@ -166,7 +166,7 @@ data class Model( /** Maximum dimension of texture coordinates */ var textureCoordDim: Int = 0, //! Current mesh instance - var m_pCurrentMesh: Mesh? = null, + var currentMesh: Mesh? = null, //! Vector with stored meshes var m_Meshes: MutableList = mutableListOf(), //! Material map diff --git a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt index 35b0270..b245053 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt @@ -183,12 +183,12 @@ class ObjFileImporter : BaseImporter() { AiPrimitiveType.POINT -> for (i in 0 until it.m_vertices.size) { val mNumIndices = 1 uiIdxCount += mNumIndices - repeat(mNumIndices, { face.add(0) }) + repeat(mNumIndices) { face += 0 } } else -> { val uiNumIndices = it.m_vertices.size uiIdxCount += uiNumIndices - repeat(uiNumIndices, { face.add(0) }) + repeat(uiNumIndices) { face += 0 } } } faces.add(face) @@ -223,7 +223,7 @@ class ObjFileImporter : BaseImporter() { // Allocate buffer for normal vectors if (pModel.m_Normals.isNotEmpty() && pObjMesh.m_hasNormals) { - System.err.println("pMesh.numVertices: ${pMesh.numVertices}") +// System.err.println("pMesh.numVertices: ${pMesh.numVertices}") pMesh.normals = MutableList(pMesh.numVertices) { // System.err.println(it) AiVector3D() diff --git a/src/main/kotlin/assimp/format/obj/ObjFileMtlImporter.kt b/src/main/kotlin/assimp/format/obj/ObjFileMtlImporter.kt index b2de56c..b46f76a 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileMtlImporter.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileMtlImporter.kt @@ -1,6 +1,5 @@ package assimp.format.obj -import assimp.isByteOrderMark import assimp.logger import assimp.words import glm_.f @@ -28,10 +27,8 @@ class ObjFileMtlImporter(buffer: List, private val model: Model) { for (line in buffer) { val trimmedLine = line.trim() - val words = when { - trimmedLine[0].isByteOrderMark -> trimmedLine.drop(1) - else -> trimmedLine - }.words + + val words = trimmedLine.words when (words[0][0]) { 'k', 'K' -> when (words[0][1]) { @@ -100,7 +97,7 @@ class ObjFileMtlImporter(buffer: List, private val model: Model) { // New Material created model.materialLib.add(name) model.materialMap[name] = it - model.m_pCurrentMesh?.m_uiMaterialIndex = model.materialLib.lastIndex + model.currentMesh?.m_uiMaterialIndex = model.materialLib.lastIndex } } } diff --git a/src/main/kotlin/assimp/format/obj/ObjFileParser.kt b/src/main/kotlin/assimp/format/obj/ObjFileParser.kt index a803bde..898a706 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileParser.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileParser.kt @@ -26,7 +26,7 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { // create default material and store it model.defaultMaterial = Material(DEFAULT_MATERIAL) model.materialLib.add(DEFAULT_MATERIAL) - model.materialMap.put(DEFAULT_MATERIAL, model.defaultMaterial!!) + model.materialMap[DEFAULT_MATERIAL] = model.defaultMaterial!! // Start parsing the file @@ -84,11 +84,9 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { // Parse a material desc. setter 'u' -> if (words[0] == "usemtl") getMaterialDesc(line) // Parse a material library or merging group ('mg') - 'm' -> { - when (words[0]) { - "mg" -> getGroupNumberAndResolution() - "mtllib" -> getMaterialLib(words) - } + 'm' -> when (words[0]) { + "mg" -> getGroupNumberAndResolution() + "mtllib" -> getMaterialLib(words) } // Parse group name 'g' -> getGroupName(line) @@ -185,9 +183,9 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { // Create a default object, if nothing is there if (model.m_pCurrent == null) createObject(DefaultObjName) // Assign face to mesh - if (model.m_pCurrentMesh == null) createMesh(DefaultObjName) + if (model.currentMesh == null) createMesh(DefaultObjName) // Store the face - with(model.m_pCurrentMesh!!) { + with(model.currentMesh!!) { m_Faces.add(face) m_uiNumIndices += face.m_vertices.size m_uiUVCoordinates[0] += face.m_texturCoords.size @@ -206,9 +204,8 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { createMesh(objName) model.currentMaterial?.let { - model.m_pCurrentMesh!!.m_uiMaterialIndex = - model.materialLib.indexOfFirst { it == model.currentMaterial!!.materialName } - model.m_pCurrentMesh!!.m_pMaterial = model.currentMaterial + model.currentMesh!!.m_uiMaterialIndex = getMaterialIndex(it.materialName) + model.currentMesh!!.m_pMaterial = it } } @@ -216,8 +213,8 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { // Creates a new mesh fun createMesh(meshName: String) { - model.m_pCurrentMesh = Mesh(meshName) - model.m_Meshes.add(model.m_pCurrentMesh!!) + model.currentMesh = Mesh(meshName) + model.m_Meshes.add(model.currentMesh!!) val meshId = model.m_Meshes.size - 1 if (model.m_pCurrent != null) model.m_pCurrent!!.m_Meshes.add(meshId) @@ -248,7 +245,7 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { if (needsNewMesh(strName)) createMesh(strName) - model.m_pCurrentMesh!!.m_uiMaterialIndex = model.materialLib.indexOfFirst { it == strName } + model.currentMesh!!.m_uiMaterialIndex = getMaterialIndex(strName) } // ------------------------------------------------------------------- @@ -256,14 +253,14 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { fun needsNewMesh(materialName: String): Boolean { // If no mesh data yet - if (model.m_pCurrentMesh == null) return true + if (model.currentMesh == null) return true var newMat = false - val matIdx = model.materialLib.indexOfFirst { it == materialName } - val curMatIdx = model.m_pCurrentMesh!!.m_uiMaterialIndex + val matIdx = getMaterialIndex(materialName) + val curMatIdx = model.currentMesh!!.m_uiMaterialIndex if (curMatIdx != Mesh.NoMaterial && curMatIdx != matIdx // no need create a new mesh if no faces in current lets say 'usemtl' goes straight after 'g' - && model.m_pCurrentMesh!!.m_Faces.size > 0) + && model.currentMesh!!.m_Faces.size > 0) // New material -> only one material per mesh, so we need to create a new material newMat = true @@ -302,11 +299,21 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { // Import material library data from file. // Some exporters (e.g. Silo) will happily write out empty material files if the model doesn't use any materials, so we allow that. - val buffer = ioSystem.open(pFile).reader().readLines().filter(String::isNotBlank) + val buffer = ioSystem.open(pFile).reader().readLines().filterTo(ArrayList(), String::isNotBlank) + + val bom = buffer[0].byteOrderMarkLength + if(bom != 0) + buffer[0] = buffer[0].drop(bom) ObjFileMtlImporter(buffer, model) } + /** Returns the index of the material. Is -1 if not material was found. */ + fun getMaterialIndex(materialName: String): Int = when { + materialName.isEmpty() -> -1 + else -> model.materialLib.indexOf(materialName) + } + // ------------------------------------------------------------------- // Getter for a group name. fun getGroupName(line: String) { diff --git a/src/test/kotlin/assimp/md3/europeanFnt.kt b/src/test/kotlin/assimp/md3/europeanFnt.kt index 7855142..76ddfd4 100644 --- a/src/test/kotlin/assimp/md3/europeanFnt.kt +++ b/src/test/kotlin/assimp/md3/europeanFnt.kt @@ -10,9 +10,9 @@ import java.nio.file.* object europeanFnt { - operator fun invoke(fileName: String, shaderName: String) { - val fileName = fileName.replace('/', File.separatorChar) - val shaderName = shaderName.replace('/', File.separatorChar) + operator fun invoke(fileName_: String, shaderName_: String) { + val fileName = fileName_.replace('/', File.separatorChar) + val shaderName = shaderName_.replace('/', File.separatorChar) logger.info("load from file $fileName") Importer().readFile(getResource(fileName))?.verify() ?: fail("could not load $fileName") diff --git a/src/test/kotlin/assimp/obj/car.kt b/src/test/kotlin/assimp/obj/car.kt index b406f7f..1476b29 100644 --- a/src/test/kotlin/assimp/obj/car.kt +++ b/src/test/kotlin/assimp/obj/car.kt @@ -109,6 +109,7 @@ object car { } materialIndex shouldBe 1 + name shouldBe "1" } meshes[37].apply { diff --git a/src/test/kotlin/assimp/obj/obj.kt b/src/test/kotlin/assimp/obj/obj.kt index af64500..7719472 100644 --- a/src/test/kotlin/assimp/obj/obj.kt +++ b/src/test/kotlin/assimp/obj/obj.kt @@ -8,13 +8,12 @@ class obj : StringSpec() { val path = "$models/OBJ" init { - "box"{ box("$path/box.obj") } - "cube"{ cube("$path/cube.obj") } - "nanosuit" { nanosuit("$path/nanosuit") } - System.gc() +// "box"{ box("$path/box.obj") } +// "cube"{ cube("$path/cube.obj") } +// "nanosuit" { nanosuit("$path/nanosuit") } "wall"{ wall("$path/wall.obj") } - "spider"{ spider.obj("$path/spider") } - "shelter" { shelter("$path/shelter") } - "car" { car("$path/car") } +// "spider"{ spider.obj("$path/spider") } +// "shelter" { shelter("$path/shelter") } +// "car" { car("$path/car") } } } \ No newline at end of file