From affb66225409d1e0638991e6549d66d7ca106b4c Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Fri, 31 Aug 2018 20:02:41 +0200 Subject: [PATCH 01/20] some todos Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/Importer.kt | 2 +- src/main/kotlin/assimp/format/fbx/fbxImporter.kt | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/assimp/Importer.kt b/src/main/kotlin/assimp/Importer.kt index fd3b901..4954a50 100644 --- a/src/main/kotlin/assimp/Importer.kt +++ b/src/main/kotlin/assimp/Importer.kt @@ -303,7 +303,7 @@ constructor() { } // Get file size for progress handler - val fileSize = File(file).length().i + val fileSize = File(file).length().i // TODO not working with fromMemory // Dispatch the reading to the worker class for this format val desc = imp.info diff --git a/src/main/kotlin/assimp/format/fbx/fbxImporter.kt b/src/main/kotlin/assimp/format/fbx/fbxImporter.kt index dc7f211..ca7ab1b 100644 --- a/src/main/kotlin/assimp/format/fbx/fbxImporter.kt +++ b/src/main/kotlin/assimp/format/fbx/fbxImporter.kt @@ -46,9 +46,7 @@ import assimp.format.AiConfig import tokenizeBinary import java.io.File import java.io.RandomAccessFile -import java.net.URI -import java.nio.ByteBuffer -import java.nio.ByteOrder +import java.nio.* import java.nio.channels.FileChannel /** @file FbxImporter.h @@ -112,6 +110,7 @@ class FbxImporter : BaseImporter() { override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { + // TODO not working with fromMemory val f = File(file) if (!f.canRead()) throw Error("Could not open file for reading") From 0415bfc2181e95ff6f1f3e0851020832a6dfd2ab Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Fri, 31 Aug 2018 20:09:44 +0200 Subject: [PATCH 02/20] enabled read from memory tests Signed-off-by: Burkhard Mittelbach --- src/test/kotlin/assimp/anchor.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/kotlin/assimp/anchor.kt b/src/test/kotlin/assimp/anchor.kt index 33fceef..6a95819 100644 --- a/src/test/kotlin/assimp/anchor.kt +++ b/src/test/kotlin/assimp/anchor.kt @@ -49,8 +49,6 @@ fun Importer.testFile(path: String, flags: AiPostProcessStepsFlags = 0, failOnNu scene?.verify() } - /* - TODO enable tests once read from memory is properly implemented // test readFileFromMemory val bytes = FileInputStream(File(path)).readBytes() val buffer = BufferUtils.createByteBuffer(bytes.size).also { it.put(bytes); it.flip() } @@ -64,7 +62,6 @@ fun Importer.testFile(path: String, flags: AiPostProcessStepsFlags = 0, failOnNu } else { memScene?.verify() } - */ return scene } \ No newline at end of file From 219f838aa7368e9e3b83d9f5dfa5e60d634bc756 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Fri, 31 Aug 2018 22:34:14 +0200 Subject: [PATCH 03/20] fixed readFromMem for FBX Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/MemoryIOWrapper.kt | 2 +- .../kotlin/assimp/format/fbx/fbxImporter.kt | 10 ++-- src/test/kotlin/assimp/anchor.kt | 46 ++++++++++++------- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/assimp/MemoryIOWrapper.kt b/src/main/kotlin/assimp/MemoryIOWrapper.kt index d5e8824..ff77392 100644 --- a/src/main/kotlin/assimp/MemoryIOWrapper.kt +++ b/src/main/kotlin/assimp/MemoryIOWrapper.kt @@ -23,7 +23,7 @@ class MemoryIOSystem(val buffer: ByteBuffer) : IOSystem{ // I guess it should never happen anyways so an exception is fine if(!pFile.startsWith(AI_MEMORYIO_MAGIC_FILENAME)) throw IOException("File does not exist! $pFile") - return MemoryIOStream(buffer, pFile) + return MemoryIOStream(buffer.duplicate(), pFile) } class MemoryIOStream(val buffer: ByteBuffer, override val filename: String = "") : IOStream { diff --git a/src/main/kotlin/assimp/format/fbx/fbxImporter.kt b/src/main/kotlin/assimp/format/fbx/fbxImporter.kt index ca7ab1b..a86a607 100644 --- a/src/main/kotlin/assimp/format/fbx/fbxImporter.kt +++ b/src/main/kotlin/assimp/format/fbx/fbxImporter.kt @@ -110,15 +110,13 @@ class FbxImporter : BaseImporter() { override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { - // TODO not working with fromMemory - val f = File(file) - if (!f.canRead()) throw Error("Could not open file for reading") - /* read entire file into memory - no streaming for this, fbx files can grow large, but the assimp output data structure then becomes very large, too. Assimp doesn't support streaming for its output data structures so the net win with streaming input data would be very low. */ - val fileChannel = RandomAccessFile(f, "r").channel - val input = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()).order(ByteOrder.nativeOrder()) + val input = ioSystem.open(file).read().use { + val bytes = it.readBytes() + ByteBuffer.wrap(bytes).order(ByteOrder.nativeOrder()) + } /* broadphase tokenizing pass in which we identify the core syntax elements of FBX (brackets, commas, key:value mappings) */ diff --git a/src/test/kotlin/assimp/anchor.kt b/src/test/kotlin/assimp/anchor.kt index 6a95819..2d98f83 100644 --- a/src/test/kotlin/assimp/anchor.kt +++ b/src/test/kotlin/assimp/anchor.kt @@ -33,6 +33,11 @@ fun Importer.testFile(path: URL, flags: AiPostProcessStepsFlags = 0, failOnNull: return testFile(path.file, flags, failOnNull, verify) } + +// TODO temp +var testReadFile = true +var testReadFromMemory = true + /** * calls both [Importer.readFile] and [Importer.readFileFromMemory] and verifies it using [verify]. * This fails if [failOnNull] is set and either of the above returns null. @@ -40,27 +45,34 @@ fun Importer.testFile(path: URL, flags: AiPostProcessStepsFlags = 0, failOnNull: * @return the result of [Importer.readFile] */ fun Importer.testFile(path: String, flags: AiPostProcessStepsFlags = 0, failOnNull: Boolean = true, verify: AiScene.() -> Unit = {}): AiScene? { - - // test readFile - val scene = readFile(path, flags) - if (scene == null && failOnNull) { - fail("readFile returned 'null' for $path") - } else { - scene?.verify() + logger.info { "Testing read $path:" } + var scene: AiScene? = null + if(testReadFile) { + logger.info { "reading from file:"} + // test readFile + scene = readFile(path, flags) + if (scene == null && failOnNull) { + fail("readFile returned 'null' for $path") + } else { + scene?.verify() + } } - // test readFileFromMemory - val bytes = FileInputStream(File(path)).readBytes() - val buffer = BufferUtils.createByteBuffer(bytes.size).also { it.put(bytes); it.flip() } + if(testReadFromMemory) { + logger.info { "reading from memory:" } + // test readFileFromMemory + val bytes = FileInputStream(File(path)).readBytes() + val buffer = BufferUtils.createByteBuffer(bytes.size).also { it.put(bytes); it.flip() } - val hintStart = path.indexOfLast { it == '.' } - val hint = path.substring(hintStart + 1) + val hintStart = path.indexOfLast { it == '.' } + val hint = path.substring(hintStart + 1) - val memScene = readFileFromMemory(buffer, flags, hint) - if (memScene == null && failOnNull) { - fail("readFileFromMemory returned 'null' for $path") - } else { - memScene?.verify() + val memScene = readFileFromMemory(buffer, flags, hint) + if (memScene == null && failOnNull) { + fail("readFileFromMemory returned 'null' for $path") + } else { + memScene?.verify() + } } return scene From bb201d6c07c8d15bfc15f263a9359cd6bccb925b Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Mon, 3 Sep 2018 14:01:07 +0200 Subject: [PATCH 04/20] fixed readFromMem for Direct X Importer Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/format/X/XFileImporter.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/assimp/format/X/XFileImporter.kt b/src/main/kotlin/assimp/format/X/XFileImporter.kt index 4145a41..a2f1728 100644 --- a/src/main/kotlin/assimp/format/X/XFileImporter.kt +++ b/src/main/kotlin/assimp/format/X/XFileImporter.kt @@ -2,7 +2,7 @@ package assimp.format.X import assimp.* import assimp.AiFace -import java.io.File +import java.io.* class XFileImporter : BaseImporter() { @@ -24,16 +24,19 @@ class XFileImporter : BaseImporter() { } override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { + // Read file into memory - val file_ = File(file) - if (!file_.canRead()) throw FileSystemException(file_, null, "Failed to open file \$pFile.") + if (!ioSystem.exists(file)) throw IOException("Failed to open file $file.") + + val stream = ioSystem.open(file).read() + val bytes = stream.readBytes() // Get the file-size and validate it, throwing an exception when fails - val fileSize = file_.length() + val fileSize = bytes.size if (fileSize < 16) throw Error("XFile is too small.") - val bytes = file_.readBytes() + //val bytes = file_.readBytes() mBuffer = Pointer(Array(bytes.size, { i -> bytes[i].toChar() })) //Assuming every byte is a char. // parse the file into a temporary representation val parser = XFileParser(mBuffer) From 8416b26a3efc2aa004e6721b538503e2f336df8d Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Mon, 3 Sep 2018 16:29:18 +0200 Subject: [PATCH 05/20] added IOStream size, not yet used everywhere some todos about importers not working from memory Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/DefaultIOSystem.kt | 3 +++ src/main/kotlin/assimp/IOStream.kt | 5 +++++ src/main/kotlin/assimp/Importer.kt | 2 +- src/main/kotlin/assimp/MemoryIOWrapper.kt | 3 +++ src/main/kotlin/assimp/format/blender/BlenderLoader.kt | 2 ++ src/main/kotlin/assimp/format/md2/Md2Loader.kt | 1 + src/main/kotlin/assimp/format/md3/Md3Loader.kt | 1 + src/main/kotlin/assimp/format/ply/PlyLoader.kt | 1 + src/main/kotlin/assimp/format/stl/STLLoader.kt | 1 + 9 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/assimp/DefaultIOSystem.kt b/src/main/kotlin/assimp/DefaultIOSystem.kt index db1ada9..dc210b1 100644 --- a/src/main/kotlin/assimp/DefaultIOSystem.kt +++ b/src/main/kotlin/assimp/DefaultIOSystem.kt @@ -29,5 +29,8 @@ class DefaultIOSystem : IOSystem { get() = path.fileName.toString() override fun parentPath() = path.parent.toAbsolutePath().toString() + + override val length: Long + get() = path.toFile().length() } } \ No newline at end of file diff --git a/src/main/kotlin/assimp/IOStream.kt b/src/main/kotlin/assimp/IOStream.kt index 4431001..b420c2e 100644 --- a/src/main/kotlin/assimp/IOStream.kt +++ b/src/main/kotlin/assimp/IOStream.kt @@ -15,4 +15,9 @@ interface IOStream { fun reader() : BufferedReader fun parentPath() : String + + /** + * length of the IOStream in bytes + */ + val length: Long } \ No newline at end of file diff --git a/src/main/kotlin/assimp/Importer.kt b/src/main/kotlin/assimp/Importer.kt index 4954a50..8ce85b5 100644 --- a/src/main/kotlin/assimp/Importer.kt +++ b/src/main/kotlin/assimp/Importer.kt @@ -303,7 +303,7 @@ constructor() { } // Get file size for progress handler - val fileSize = File(file).length().i // TODO not working with fromMemory + val fileSize = ioSystem.open(file).length.i // Dispatch the reading to the worker class for this format val desc = imp.info diff --git a/src/main/kotlin/assimp/MemoryIOWrapper.kt b/src/main/kotlin/assimp/MemoryIOWrapper.kt index ff77392..9fe1297 100644 --- a/src/main/kotlin/assimp/MemoryIOWrapper.kt +++ b/src/main/kotlin/assimp/MemoryIOWrapper.kt @@ -40,6 +40,9 @@ class MemoryIOSystem(val buffer: ByteBuffer) : IOSystem{ } override fun parentPath(): String = "" + + override val length: Long + get() = buffer.size.toLong() } } diff --git a/src/main/kotlin/assimp/format/blender/BlenderLoader.kt b/src/main/kotlin/assimp/format/blender/BlenderLoader.kt index c58179e..51edb9a 100644 --- a/src/main/kotlin/assimp/format/blender/BlenderLoader.kt +++ b/src/main/kotlin/assimp/format/blender/BlenderLoader.kt @@ -47,6 +47,8 @@ class BlenderImporter : BaseImporter() { override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { + // TODO read file from mem + val fileChannel = RandomAccessFile(File(file), "r").channel buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()).order(ByteOrder.nativeOrder()) diff --git a/src/main/kotlin/assimp/format/md2/Md2Loader.kt b/src/main/kotlin/assimp/format/md2/Md2Loader.kt index e5336b1..e4d1e50 100644 --- a/src/main/kotlin/assimp/format/md2/Md2Loader.kt +++ b/src/main/kotlin/assimp/format/md2/Md2Loader.kt @@ -109,6 +109,7 @@ class Md2Importer : BaseImporter() { * See BaseImporter.internReadFile() for details */ override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { + // TODO read mem file val file = File(file) // Check whether we can read from the file diff --git a/src/main/kotlin/assimp/format/md3/Md3Loader.kt b/src/main/kotlin/assimp/format/md3/Md3Loader.kt index 1d38974..4f0d3fa 100644 --- a/src/main/kotlin/assimp/format/md3/Md3Loader.kt +++ b/src/main/kotlin/assimp/format/md3/Md3Loader.kt @@ -393,6 +393,7 @@ class Md3Importer : BaseImporter() { if (configHandleMP && readMultipartFile()) return // Check whether we can read from the file + // TODO read mem file val f = File(file) if (!f.canRead()) throw Error("Failed to open MD3 file $file.") diff --git a/src/main/kotlin/assimp/format/ply/PlyLoader.kt b/src/main/kotlin/assimp/format/ply/PlyLoader.kt index fff0e51..a461e3c 100644 --- a/src/main/kotlin/assimp/format/ply/PlyLoader.kt +++ b/src/main/kotlin/assimp/format/ply/PlyLoader.kt @@ -40,6 +40,7 @@ class PlyLoader : BaseImporter() { // Imports the given file into the given scene structure. override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { + // TODO read mem file val file = File(file) // Check whether we can read from the file diff --git a/src/main/kotlin/assimp/format/stl/STLLoader.kt b/src/main/kotlin/assimp/format/stl/STLLoader.kt index 0e70806..81b47e9 100644 --- a/src/main/kotlin/assimp/format/stl/STLLoader.kt +++ b/src/main/kotlin/assimp/format/stl/STLLoader.kt @@ -102,6 +102,7 @@ class StlImporter : BaseImporter() { // Imports the given file into the given scene structure. override fun internReadFile(pFile: String, ioSystem: IOSystem, scene: AiScene) { + // TODO read mem file val file = File(pFile) // Check whether we can read from the file From 8d476a69397100d7439de64536482560a663e1a6 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Mon, 3 Sep 2018 16:40:20 +0200 Subject: [PATCH 06/20] cleaning up code adding more todos *sigh* :wink: Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/Importer.kt | 1 - src/main/kotlin/assimp/format/blender/BlenderLoader.kt | 1 - src/main/kotlin/assimp/format/fbx/fbxImporter.kt | 3 --- src/main/kotlin/assimp/format/md2/Md2Loader.kt | 1 - src/main/kotlin/assimp/format/md3/Md3Loader.kt | 3 ++- src/main/kotlin/assimp/format/obj/ObjFileParser.kt | 2 +- src/main/kotlin/assimp/format/ply/PlyLoader.kt | 1 - src/main/kotlin/assimp/format/stl/STLLoader.kt | 1 - src/test/kotlin/assimp/obj/shelter.kt | 2 -- 9 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/assimp/Importer.kt b/src/main/kotlin/assimp/Importer.kt index 8ce85b5..3675032 100644 --- a/src/main/kotlin/assimp/Importer.kt +++ b/src/main/kotlin/assimp/Importer.kt @@ -48,7 +48,6 @@ import assimp.postProcess.ValidateDSProcess import glm_.BYTES import glm_.i import glm_.size -import java.io.File import java.net.URI import java.net.URL import java.nio.ByteBuffer diff --git a/src/main/kotlin/assimp/format/blender/BlenderLoader.kt b/src/main/kotlin/assimp/format/blender/BlenderLoader.kt index 51edb9a..ff758f1 100644 --- a/src/main/kotlin/assimp/format/blender/BlenderLoader.kt +++ b/src/main/kotlin/assimp/format/blender/BlenderLoader.kt @@ -7,7 +7,6 @@ import glm_.toUnsignedInt import uno.kotlin.parseInt import java.io.File import java.io.RandomAccessFile -import java.net.URI import java.nio.ByteBuffer import java.nio.ByteOrder import java.nio.channels.FileChannel diff --git a/src/main/kotlin/assimp/format/fbx/fbxImporter.kt b/src/main/kotlin/assimp/format/fbx/fbxImporter.kt index a86a607..0065472 100644 --- a/src/main/kotlin/assimp/format/fbx/fbxImporter.kt +++ b/src/main/kotlin/assimp/format/fbx/fbxImporter.kt @@ -44,10 +44,7 @@ package assimp.format.fbx import assimp.* import assimp.format.AiConfig import tokenizeBinary -import java.io.File -import java.io.RandomAccessFile import java.nio.* -import java.nio.channels.FileChannel /** @file FbxImporter.h * @brief Declaration of the FBX main importer class */ diff --git a/src/main/kotlin/assimp/format/md2/Md2Loader.kt b/src/main/kotlin/assimp/format/md2/Md2Loader.kt index e4d1e50..5671c93 100644 --- a/src/main/kotlin/assimp/format/md2/Md2Loader.kt +++ b/src/main/kotlin/assimp/format/md2/Md2Loader.kt @@ -52,7 +52,6 @@ import glm_.f import glm_.i import java.io.File import java.io.RandomAccessFile -import java.net.URI import java.nio.ByteOrder import java.nio.channels.FileChannel diff --git a/src/main/kotlin/assimp/format/md3/Md3Loader.kt b/src/main/kotlin/assimp/format/md3/Md3Loader.kt index 4f0d3fa..80451df 100644 --- a/src/main/kotlin/assimp/format/md3/Md3Loader.kt +++ b/src/main/kotlin/assimp/format/md3/Md3Loader.kt @@ -48,7 +48,6 @@ import glm_.i import glm_.size import java.io.File import java.io.RandomAccessFile -import java.net.URI import java.nio.ByteBuffer import java.nio.ByteOrder import java.nio.channels.FileChannel @@ -120,6 +119,7 @@ object Q3Shader { * @return false if file is not accessible */ fun loadShader(fill: ShaderData, file: String): Boolean { + // TODO load from mem val f = File(file) if (!f.exists()) return false // if we can't access the file, don't worry and return @@ -273,6 +273,7 @@ object Q3Shader { * @return false if file is not accessible */ fun loadSkin(fill: SkinData, file: String): Boolean { + // TODO load from mem val f = File(file) if (!f.canRead()) return false // if we can't access the file, don't worry and return diff --git a/src/main/kotlin/assimp/format/obj/ObjFileParser.kt b/src/main/kotlin/assimp/format/obj/ObjFileParser.kt index 560de67..ec2c4e1 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileParser.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileParser.kt @@ -265,7 +265,7 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { System.err.println("OBJ: Unable to locate material file $filename") val strMatFallbackName = filename.substring(0, filename.length - 3) + "mtl" println("OBJ: Opening fallback material file $strMatFallbackName") - if (!File(strMatFallbackName).exists()) { + if (!File(strMatFallbackName).exists()) { // TODO read file from mem System.err.println("OBJ: Unable to locate fallback material file $strMatFallbackName") return } diff --git a/src/main/kotlin/assimp/format/ply/PlyLoader.kt b/src/main/kotlin/assimp/format/ply/PlyLoader.kt index a461e3c..a9a2eff 100644 --- a/src/main/kotlin/assimp/format/ply/PlyLoader.kt +++ b/src/main/kotlin/assimp/format/ply/PlyLoader.kt @@ -6,7 +6,6 @@ import assimp.* import java.io.File import java.io.IOException import java.io.RandomAccessFile -import java.net.URI import java.nio.ByteOrder import java.nio.channels.FileChannel diff --git a/src/main/kotlin/assimp/format/stl/STLLoader.kt b/src/main/kotlin/assimp/format/stl/STLLoader.kt index 81b47e9..ee00605 100644 --- a/src/main/kotlin/assimp/format/stl/STLLoader.kt +++ b/src/main/kotlin/assimp/format/stl/STLLoader.kt @@ -6,7 +6,6 @@ import unsigned.ushr import java.io.File import java.io.IOException import java.io.RandomAccessFile -import java.net.URI import java.nio.ByteBuffer import java.nio.ByteOrder import java.nio.channels.FileChannel diff --git a/src/test/kotlin/assimp/obj/shelter.kt b/src/test/kotlin/assimp/obj/shelter.kt index fd2624e..83a42c8 100644 --- a/src/test/kotlin/assimp/obj/shelter.kt +++ b/src/test/kotlin/assimp/obj/shelter.kt @@ -4,8 +4,6 @@ import assimp.* import glm_.mat4x4.Mat4 import glm_.vec3.Vec3 import io.kotlintest.shouldBe -import java.io.File -import java.net.URI /** * Created by Sunny on 19/01/2018. From d58d67e30fad59fa84642891c02c311f16f626db Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Mon, 3 Sep 2018 17:35:18 +0200 Subject: [PATCH 07/20] Refactored ByteBuffer creation from IOStream in importers Signed-off-by: Burkhard Mittelbach --- README.md | 26 ++++++++++++++ src/main/kotlin/assimp/DefaultIOSystem.kt | 16 ++++++--- src/main/kotlin/assimp/IOStream.kt | 3 ++ src/main/kotlin/assimp/IOSystem.kt | 4 +-- src/main/kotlin/assimp/MemoryIOWrapper.kt | 12 ++++--- .../assimp/format/blender/BlenderLoader.kt | 5 +-- .../kotlin/assimp/format/fbx/fbxImporter.kt | 5 +-- .../kotlin/assimp/format/md2/Md2Loader.kt | 15 ++++---- .../kotlin/assimp/format/md3/Md3Loader.kt | 10 +++--- .../assimp/format/obj/ObjFileImporter.kt | 7 ++-- .../kotlin/assimp/format/ply/PlyLoader.kt | 35 ++++++++----------- .../kotlin/assimp/format/stl/STLLoader.kt | 21 ++++------- src/test/kotlin/assimp/blender/blender.kt | 9 ++--- 13 files changed, 92 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 4100e78..afd19be 100644 --- a/README.md +++ b/README.md @@ -60,3 +60,29 @@ Disadvantages: - code needs to be ported from cpp to java - code needs to be maintained - a little slower compared to cpp when loading big meshes if not using assbin + +### Read from memory status + +TODO remove before final push to kotlin-graphics/master + +#### Format tests: + +Working: + +- Direct X +- collada +- ply + +Failing: + +- assbin +- fbx +- md2 +- md3 +- md5 +- obj +- stl + +Disabled: + +- blender \ No newline at end of file diff --git a/src/main/kotlin/assimp/DefaultIOSystem.kt b/src/main/kotlin/assimp/DefaultIOSystem.kt index dc210b1..04ee555 100644 --- a/src/main/kotlin/assimp/DefaultIOSystem.kt +++ b/src/main/kotlin/assimp/DefaultIOSystem.kt @@ -1,19 +1,21 @@ package assimp import java.io.* +import java.nio.* +import java.nio.channels.* import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths class DefaultIOSystem : IOSystem { - override fun exists(pFile: String) = File(pFile).exists() + override fun exists(file: String) = File(file).exists() - override fun open(pFile: String): IOStream { + override fun open(file: String): IOStream { - val path: Path = Paths.get(pFile) + val path: Path = Paths.get(file) if (!Files.exists(path)) - throw IOException("File doesn't exist: $pFile") + throw IOException("File doesn't exist: $file") return FileIOStream(path) @@ -32,5 +34,11 @@ class DefaultIOSystem : IOSystem { override val length: Long get() = path.toFile().length() + + override fun readBytes(): ByteBuffer { + RandomAccessFile(path.toFile(), "r").channel.use {fileChannel -> + return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()).order(ByteOrder.nativeOrder()) + } + } } } \ No newline at end of file diff --git a/src/main/kotlin/assimp/IOStream.kt b/src/main/kotlin/assimp/IOStream.kt index b420c2e..17e2663 100644 --- a/src/main/kotlin/assimp/IOStream.kt +++ b/src/main/kotlin/assimp/IOStream.kt @@ -2,6 +2,7 @@ package assimp import java.io.BufferedReader import java.io.InputStream +import java.nio.* import java.nio.file.Path interface IOStream { @@ -20,4 +21,6 @@ interface IOStream { * length of the IOStream in bytes */ val length: Long + + fun readBytes(): ByteBuffer } \ No newline at end of file diff --git a/src/main/kotlin/assimp/IOSystem.kt b/src/main/kotlin/assimp/IOSystem.kt index 15d33a8..8c8926d 100644 --- a/src/main/kotlin/assimp/IOSystem.kt +++ b/src/main/kotlin/assimp/IOSystem.kt @@ -5,9 +5,9 @@ import java.io.File /** Interface to the file system. */ interface IOSystem { - fun exists(pFile: String): Boolean + fun exists(file: String): Boolean - fun open(pFile : String): IOStream + fun open(file : String): IOStream fun close(ioStream: IOStream) = Unit // TODO unused ? diff --git a/src/main/kotlin/assimp/MemoryIOWrapper.kt b/src/main/kotlin/assimp/MemoryIOWrapper.kt index 9fe1297..5ab10b8 100644 --- a/src/main/kotlin/assimp/MemoryIOWrapper.kt +++ b/src/main/kotlin/assimp/MemoryIOWrapper.kt @@ -14,16 +14,16 @@ const val AI_MEMORYIO_MAGIC_FILENAME_LENGTH = 17 class MemoryIOSystem(val buffer: ByteBuffer) : IOSystem{ /** Tests for the existence of a file at the given path. */ - override fun exists(pFile: String): Boolean = pFile.startsWith(AI_MEMORYIO_MAGIC_FILENAME) + override fun exists(file: String): Boolean = file.startsWith(AI_MEMORYIO_MAGIC_FILENAME) - override fun open(pFile: String): IOStream { + override fun open(file: String): IOStream { // TODO assimp originally returns null, but this would be against the current interface. // I guess it should never happen anyways so an exception is fine - if(!pFile.startsWith(AI_MEMORYIO_MAGIC_FILENAME)) throw IOException("File does not exist! $pFile") + if(!file.startsWith(AI_MEMORYIO_MAGIC_FILENAME)) throw IOException("File does not exist! $file") - return MemoryIOStream(buffer.duplicate(), pFile) + return MemoryIOStream(buffer, file) } class MemoryIOStream(val buffer: ByteBuffer, override val filename: String = "") : IOStream { @@ -32,7 +32,7 @@ class MemoryIOSystem(val buffer: ByteBuffer) : IOSystem{ get() = null override fun read(): InputStream { - return ByteBufferBackedInputStream(buffer) + return ByteBufferBackedInputStream(readBytes()) } override fun reader(): BufferedReader { @@ -43,6 +43,8 @@ class MemoryIOSystem(val buffer: ByteBuffer) : IOSystem{ override val length: Long get() = buffer.size.toLong() + + override fun readBytes(): ByteBuffer = buffer.duplicate() } } diff --git a/src/main/kotlin/assimp/format/blender/BlenderLoader.kt b/src/main/kotlin/assimp/format/blender/BlenderLoader.kt index ff758f1..2873f7e 100644 --- a/src/main/kotlin/assimp/format/blender/BlenderLoader.kt +++ b/src/main/kotlin/assimp/format/blender/BlenderLoader.kt @@ -46,10 +46,7 @@ class BlenderImporter : BaseImporter() { override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { - // TODO read file from mem - - val fileChannel = RandomAccessFile(File(file), "r").channel - buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()).order(ByteOrder.nativeOrder()) + buffer = ioSystem.open(file).readBytes() var match = buffer.strncmp(tokens) if (!match) { diff --git a/src/main/kotlin/assimp/format/fbx/fbxImporter.kt b/src/main/kotlin/assimp/format/fbx/fbxImporter.kt index 0065472..04738ce 100644 --- a/src/main/kotlin/assimp/format/fbx/fbxImporter.kt +++ b/src/main/kotlin/assimp/format/fbx/fbxImporter.kt @@ -110,10 +110,7 @@ class FbxImporter : BaseImporter() { /* read entire file into memory - no streaming for this, fbx files can grow large, but the assimp output data structure then becomes very large, too. Assimp doesn't support streaming for its output data structures so the net win with streaming input data would be very low. */ - val input = ioSystem.open(file).read().use { - val bytes = it.readBytes() - ByteBuffer.wrap(bytes).order(ByteOrder.nativeOrder()) - } + val input = ioSystem.open(file).readBytes() /* broadphase tokenizing pass in which we identify the core syntax elements of FBX (brackets, commas, key:value mappings) */ diff --git a/src/main/kotlin/assimp/format/md2/Md2Loader.kt b/src/main/kotlin/assimp/format/md2/Md2Loader.kt index 5671c93..fb0fb9d 100644 --- a/src/main/kotlin/assimp/format/md2/Md2Loader.kt +++ b/src/main/kotlin/assimp/format/md2/Md2Loader.kt @@ -108,19 +108,17 @@ class Md2Importer : BaseImporter() { * See BaseImporter.internReadFile() for details */ override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { - // TODO read mem file - val file = File(file) - // Check whether we can read from the file - if (!file.canRead()) + if (!ioSystem.exists(file)) throw Error("Failed to open MD2 file $file") + val stream = ioSystem.open(file) + // check whether the md3 file is large enough to contain at least the file header - fileSize = file.length().i + fileSize = stream.length.i if (fileSize < MD2.Header.size) throw Error("MD2 File is too small") - val fileChannel = RandomAccessFile(file, "r").channel - val buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()).order(ByteOrder.nativeOrder()) + val buffer = stream.readBytes() header = MD2.Header(buffer).apply { validate(fileSize, configFrameID) } @@ -171,7 +169,8 @@ class Md2Importer : BaseImporter() { // apply a default material helper.color = AiMaterial.Color(diffuse = AiColor3D(0.6f), specular = AiColor3D(0.6f), ambient = AiColor3D(0.05f)) helper.name = AI_DEFAULT_MATERIAL_NAME - val fileName = file.name.substringAfterLast('\\').substringBeforeLast('.') + // TODO read from memory, does not yet support multiple files in one read + val fileName = file.substringAfterLast('\\').substringBeforeLast('.') helper.textures.add(AiMaterial.Texture(file = "$fileName.bmp", type = AiTexture.Type.diffuse)) } diff --git a/src/main/kotlin/assimp/format/md3/Md3Loader.kt b/src/main/kotlin/assimp/format/md3/Md3Loader.kt index 80451df..c10fffd 100644 --- a/src/main/kotlin/assimp/format/md3/Md3Loader.kt +++ b/src/main/kotlin/assimp/format/md3/Md3Loader.kt @@ -395,16 +395,14 @@ class Md3Importer : BaseImporter() { // Check whether we can read from the file // TODO read mem file - val f = File(file) - if (!f.canRead()) throw Error("Failed to open MD3 file $file.") + if (!ioSystem.exists(file)) throw Error("Failed to open MD3 file $file.") + val stream = ioSystem.open(file) // Check whether the md3 file is large enough to contain the header - fileSize = f.length().i + fileSize = stream.length.i if (fileSize < MD3.Header.size) throw Error("MD3 File is too small.") - // Allocate storage and copy the contents of the file to a memory buffer - val fileChannel = RandomAccessFile(f, "r").channel - val buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()).order(ByteOrder.nativeOrder()) + val buffer = stream.readBytes() header = MD3.Header(buffer) // Validate the file header diff --git a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt index ee871e5..6976988 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt @@ -38,12 +38,13 @@ class ObjFileImporter : BaseImporter() { if (!ioSystem.exists(file)) throw IOException("Failed to open file $file.") // Get the file-size and validate it, throwing an exception when fails - //val fileSize = this.file.length() + val stream = ioSystem.open(file) + val fileSize = stream.length - //if (fileSize < ObjMinSize) throw Error("OBJ-file is too small.") + if (fileSize < ObjMinSize) throw Error("OBJ-file is too small.") // parse the file into a temporary representation - val parser = ObjFileParser(ioSystem.open(file), ioSystem) + val parser = ObjFileParser(stream, ioSystem) // And create the proper return structures out of it createDataFromImport(parser.m_pModel, scene, ioSystem) diff --git a/src/main/kotlin/assimp/format/ply/PlyLoader.kt b/src/main/kotlin/assimp/format/ply/PlyLoader.kt index a9a2eff..f7d138d 100644 --- a/src/main/kotlin/assimp/format/ply/PlyLoader.kt +++ b/src/main/kotlin/assimp/format/ply/PlyLoader.kt @@ -3,11 +3,8 @@ package assimp.format.ply import glm_.* import glm_.vec3.Vec3 import assimp.* -import java.io.File import java.io.IOException -import java.io.RandomAccessFile import java.nio.ByteOrder -import java.nio.channels.FileChannel /** * Created by elect on 10/12/2016. @@ -39,42 +36,38 @@ class PlyLoader : BaseImporter() { // Imports the given file into the given scene structure. override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { - // TODO read mem file - val file = File(file) - // Check whether we can read from the file - if (!file.canRead()) throw IOException("Failed to open PLY file $file.") + if (!ioSystem.exists(file)) throw IOException("Failed to open PLY file $file.") // allocate storage and copy the contents of the file to a memory buffer - val fileChannel = RandomAccessFile(file, "r").channel - val mBuffer2 = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()).order(ByteOrder.nativeOrder()) + val buffer = ioSystem.open(file).readBytes() // the beginning of the file must be PLY - magic, magic - if (mBuffer2.nextWord().toLowerCase() != "ply") throw Error("Invalid .ply file: Magic number 'ply' is no there") + if (buffer.nextWord().toLowerCase() != "ply") throw Error("Invalid .ply file: Magic number 'ply' is no there") - mBuffer2.skipSpacesAndLineEnd() + buffer.skipSpacesAndLineEnd() // determine the format of the file data val sPlyDom = DOM() - if (mBuffer2.nextWord() == "format") { + if (buffer.nextWord() == "format") { - val format = mBuffer2.nextWord() + val format = buffer.nextWord() if (format == "ascii") { - mBuffer2.skipLine() - if (!DOM.parseInstance(mBuffer2, sPlyDom)) + buffer.skipLine() + if (!DOM.parseInstance(buffer, sPlyDom)) throw Error("Invalid .ply file: Unable to build DOM (#1)") } else { // revert ascii - mBuffer2.position(mBuffer2.position() - format.length) + buffer.position(buffer.position() - format.length) - if (mBuffer2.startsWith("binary_")) { + if (buffer.startsWith("binary_")) { - val bIsBE = mBuffer2.get(mBuffer2.position()) == 'b'.b || mBuffer2.get(mBuffer2.position()) == 'B'.b - mBuffer2.order(if (bIsBE) ByteOrder.BIG_ENDIAN else ByteOrder.LITTLE_ENDIAN) + val bIsBE = buffer.get(buffer.position()) == 'b'.b || buffer.get(buffer.position()) == 'B'.b + buffer.order(if (bIsBE) ByteOrder.BIG_ENDIAN else ByteOrder.LITTLE_ENDIAN) // skip the line, parse the rest of the header and build the DOM - mBuffer2.skipLine() - if (!DOM.parseInstanceBinary(mBuffer2, sPlyDom)) + buffer.skipLine() + if (!DOM.parseInstanceBinary(buffer, sPlyDom)) throw Error("Invalid .ply file: Unable to build DOM (#2)") } else throw Error("Invalid .ply file: Unknown file format") diff --git a/src/main/kotlin/assimp/format/stl/STLLoader.kt b/src/main/kotlin/assimp/format/stl/STLLoader.kt index ee00605..36b35c0 100644 --- a/src/main/kotlin/assimp/format/stl/STLLoader.kt +++ b/src/main/kotlin/assimp/format/stl/STLLoader.kt @@ -3,12 +3,8 @@ package assimp.format.stl import assimp.* import glm_.* import unsigned.ushr -import java.io.File import java.io.IOException -import java.io.RandomAccessFile import java.nio.ByteBuffer -import java.nio.ByteOrder -import java.nio.channels.FileChannel import java.util.* /** @@ -99,22 +95,17 @@ class StlImporter : BaseImporter() { // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. - override fun internReadFile(pFile: String, ioSystem: IOSystem, scene: AiScene) { - - // TODO read mem file - val file = File(pFile) + override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { // Check whether we can read from the file - if (!file.canRead()) throw IOException("Failed to open STL file $pFile.") + if (!ioSystem.exists(file)) throw IOException("Failed to open STL file $file.") - fileSize = file.length().i + val stream = ioSystem.open(file) - // allocate storage and copy the contents of the file to a memory buffer - val fileChannel = RandomAccessFile(file, "r").channel - val mBuffer2 = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()).order(ByteOrder.nativeOrder()) + fileSize = stream.length.i this.pScene = scene - this.mBuffer = mBuffer2 + this.mBuffer = stream.readBytes() // the default vertex color is light gray. clrColorDefault put 0.6f @@ -128,7 +119,7 @@ class StlImporter : BaseImporter() { bMatClr = loadBinaryFile() else if (isAsciiSTL(mBuffer, fileSize)) loadASCIIFile() - else throw Error("Failed to determine STL storage representation for $pFile.") + else throw Error("Failed to determine STL storage representation for $file.") // add all created meshes to the single node scene.rootNode.numMeshes = scene.numMeshes diff --git a/src/test/kotlin/assimp/blender/blender.kt b/src/test/kotlin/assimp/blender/blender.kt index ded4164..8a30f8c 100644 --- a/src/test/kotlin/assimp/blender/blender.kt +++ b/src/test/kotlin/assimp/blender/blender.kt @@ -1,6 +1,7 @@ package assimp.blender import assimp.models +import assimp.obj.* import io.kotlintest.specs.StringSpec class blender : StringSpec() { @@ -8,9 +9,9 @@ class blender : StringSpec() { val path = models + "/BLEND/" init { -// "blender default 250 compressed"{ blenderDefault_250_compressed(path + "BlenderDefault_250_Compressed.blend") } -// "spider"{ spider(path + "spider.obj") } -// "nanosuit" { nanosuit(path + "nanosuit/nanosuit.obj") } -// "shelter" { shelter(path + "statie B01.obj")} + "blender default 250 compressed".config(enabled = false){ blenderDefault_250_compressed(path + "BlenderDefault_250_Compressed.blend") } + //"spider"{ spider(path + "spider.obj") } + //"nanosuit" { nanosuit(path + "nanosuit/nanosuit.obj") } + //"shelter" { shelter(path + "statie B01.obj")} } } \ No newline at end of file From d8d11014412ab4282eb8f685d8b69b3e560fa5d8 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Mon, 3 Sep 2018 19:01:51 +0200 Subject: [PATCH 08/20] Fixed byte order bug in read from memory Signed-off-by: Burkhard Mittelbach --- README.md | 4 ++-- src/main/kotlin/assimp/IOStream.kt | 4 ++++ src/main/kotlin/assimp/MemoryIOWrapper.kt | 9 +++++++-- src/test/kotlin/assimp/anchor.kt | 4 ++-- src/test/kotlin/assimp/fbx/fbx.kt | 1 + 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index afd19be..21913a8 100644 --- a/README.md +++ b/README.md @@ -72,16 +72,16 @@ Working: - Direct X - collada - ply +- fbx +- stl Failing: - assbin -- fbx - md2 - md3 - md5 - obj -- stl Disabled: diff --git a/src/main/kotlin/assimp/IOStream.kt b/src/main/kotlin/assimp/IOStream.kt index 17e2663..cfd4daf 100644 --- a/src/main/kotlin/assimp/IOStream.kt +++ b/src/main/kotlin/assimp/IOStream.kt @@ -22,5 +22,9 @@ interface IOStream { */ val length: Long + /** + * reads the ioStream into a byte buffer. + * The byte order of the buffer is be [ByteOrder.nativeOrder]. + */ fun readBytes(): ByteBuffer } \ No newline at end of file diff --git a/src/main/kotlin/assimp/MemoryIOWrapper.kt b/src/main/kotlin/assimp/MemoryIOWrapper.kt index 5ab10b8..5b62882 100644 --- a/src/main/kotlin/assimp/MemoryIOWrapper.kt +++ b/src/main/kotlin/assimp/MemoryIOWrapper.kt @@ -23,7 +23,7 @@ class MemoryIOSystem(val buffer: ByteBuffer) : IOSystem{ // I guess it should never happen anyways so an exception is fine if(!file.startsWith(AI_MEMORYIO_MAGIC_FILENAME)) throw IOException("File does not exist! $file") - return MemoryIOStream(buffer, file) + return MemoryIOStream(buffer.duplicate().order(ByteOrder.nativeOrder()), file) } class MemoryIOStream(val buffer: ByteBuffer, override val filename: String = "") : IOStream { @@ -44,7 +44,12 @@ class MemoryIOSystem(val buffer: ByteBuffer) : IOSystem{ override val length: Long get() = buffer.size.toLong() - override fun readBytes(): ByteBuffer = buffer.duplicate() + // TODO figure out whether or not I should call dup here + // do multiple calls of read() on the default implementation generate input streams + // with positions that match each other or not? + // If I move duplicate back here I need to also adjust the byte order here + // Then I no longer need to change it in MemoryIOSystem.open + override fun readBytes(): ByteBuffer = buffer } } diff --git a/src/test/kotlin/assimp/anchor.kt b/src/test/kotlin/assimp/anchor.kt index 2d98f83..9c79d55 100644 --- a/src/test/kotlin/assimp/anchor.kt +++ b/src/test/kotlin/assimp/anchor.kt @@ -1,9 +1,9 @@ package assimp import io.kotlintest.* -import org.lwjgl.BufferUtils import java.io.* import java.net.URL +import java.nio.* /** * Created by elect on 14/01/2017. @@ -62,7 +62,7 @@ fun Importer.testFile(path: String, flags: AiPostProcessStepsFlags = 0, failOnNu logger.info { "reading from memory:" } // test readFileFromMemory val bytes = FileInputStream(File(path)).readBytes() - val buffer = BufferUtils.createByteBuffer(bytes.size).also { it.put(bytes); it.flip() } + val buffer = ByteBuffer.wrap(bytes) val hintStart = path.indexOfLast { it == '.' } val hint = path.substring(hintStart + 1) diff --git a/src/test/kotlin/assimp/fbx/fbx.kt b/src/test/kotlin/assimp/fbx/fbx.kt index 0802e10..0ba717f 100644 --- a/src/test/kotlin/assimp/fbx/fbx.kt +++ b/src/test/kotlin/assimp/fbx/fbx.kt @@ -2,6 +2,7 @@ package assimp.fbx import assimp.* import io.kotlintest.specs.StringSpec +import java.nio.* /** * Created by elect on 24/01/2017. From ba4580d87dc51dfe59f84f7f5edb1b11315d3cb6 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Wed, 5 Sep 2018 23:55:48 +0200 Subject: [PATCH 09/20] MemoryIOSystem now supports multiple files ObjImporter now loads multi file objects Signed-off-by: Burkhard Mittelbach --- README.md | 2 +- src/main/kotlin/assimp/DefaultIOSystem.kt | 22 ++-- src/main/kotlin/assimp/IOStream.kt | 7 +- src/main/kotlin/assimp/IOSystem.kt | 2 +- src/main/kotlin/assimp/Importer.kt | 72 +++++++++++- src/main/kotlin/assimp/MemoryIOWrapper.kt | 50 ++++++--- .../assimp/format/obj/ObjFileImporter.kt | 60 +++++++++- .../kotlin/assimp/format/obj/ObjFileParser.kt | 10 +- src/test/kotlin/assimp/anchor.kt | 106 +++++++++++++++++- src/test/kotlin/assimp/obj/box.kt | 4 +- src/test/kotlin/assimp/obj/nanosuit.kt | 10 +- src/test/kotlin/assimp/obj/obj.kt | 39 ++++++- src/test/kotlin/assimp/obj/spider.kt | 8 +- 13 files changed, 336 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 21913a8..1a1ebd8 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ Working: - ply - fbx - stl +- obj Failing: @@ -81,7 +82,6 @@ Failing: - md2 - md3 - md5 -- obj Disabled: diff --git a/src/main/kotlin/assimp/DefaultIOSystem.kt b/src/main/kotlin/assimp/DefaultIOSystem.kt index 04ee555..e4bab8d 100644 --- a/src/main/kotlin/assimp/DefaultIOSystem.kt +++ b/src/main/kotlin/assimp/DefaultIOSystem.kt @@ -18,27 +18,33 @@ class DefaultIOSystem : IOSystem { throw IOException("File doesn't exist: $file") - return FileIOStream(path) + return FileIOStream(path, this) } - class FileIOStream(override val path: Path) : IOStream { + class FileIOStream(private val pathObject: Path, override val osSystem: DefaultIOSystem) : IOStream { - override fun read() = FileInputStream(path.toFile()) + override val path: String + get() = pathObject.toString() - override fun reader() = BufferedReader(FileReader(path.toFile())) + override fun read() = FileInputStream(file) + + override fun reader() = BufferedReader(FileReader(file)) override val filename: String - get() = path.fileName.toString() + get() = pathObject.fileName.toString() - override fun parentPath() = path.parent.toAbsolutePath().toString() + override val parentPath = pathObject.parent.toAbsolutePath().toString() override val length: Long - get() = path.toFile().length() + get() = file.length() override fun readBytes(): ByteBuffer { - RandomAccessFile(path.toFile(), "r").channel.use {fileChannel -> + RandomAccessFile(file, "r").channel.use {fileChannel -> return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()).order(ByteOrder.nativeOrder()) } } + + val file: File + get() = pathObject.toFile() } } \ No newline at end of file diff --git a/src/main/kotlin/assimp/IOStream.kt b/src/main/kotlin/assimp/IOStream.kt index cfd4daf..392e30e 100644 --- a/src/main/kotlin/assimp/IOStream.kt +++ b/src/main/kotlin/assimp/IOStream.kt @@ -3,11 +3,10 @@ package assimp import java.io.BufferedReader import java.io.InputStream import java.nio.* -import java.nio.file.Path interface IOStream { - val path : Path? + val path : String val filename: String @@ -15,7 +14,7 @@ interface IOStream { fun reader() : BufferedReader - fun parentPath() : String + val parentPath : String /** * length of the IOStream in bytes @@ -27,4 +26,6 @@ interface IOStream { * The byte order of the buffer is be [ByteOrder.nativeOrder]. */ fun readBytes(): ByteBuffer + + val osSystem: IOSystem } \ No newline at end of file diff --git a/src/main/kotlin/assimp/IOSystem.kt b/src/main/kotlin/assimp/IOSystem.kt index 8c8926d..d3e64e2 100644 --- a/src/main/kotlin/assimp/IOSystem.kt +++ b/src/main/kotlin/assimp/IOSystem.kt @@ -11,5 +11,5 @@ interface IOSystem { fun close(ioStream: IOStream) = Unit // TODO unused ? - fun getOsSeperator(): String = File.separator + val osSeparator: String get() = File.separator } \ No newline at end of file diff --git a/src/main/kotlin/assimp/Importer.kt b/src/main/kotlin/assimp/Importer.kt index 3675032..5c67bb4 100644 --- a/src/main/kotlin/assimp/Importer.kt +++ b/src/main/kotlin/assimp/Importer.kt @@ -372,8 +372,7 @@ constructor() { * * @note This is a straightforward way to decode models from memory buffers, but it doesn't handle model formats * that spread their data across multiple files or even directories. Examples include OBJ or MD3, which outsource - * parts of their material info into external scripts. If you need full functionality, provide a custom IOSystem - * to make Assimp find these files and use the regular readFile() API. + * parts of their material info into external scripts. If you need full functionality you can use [readFilesFromMemory] */ fun readFileFromMemory(buffer: ByteBuffer, flags: Int, hint: String = ""): AiScene? { if (buffer.size == 0 || hint.length > MaxLenHint) { @@ -384,9 +383,52 @@ constructor() { // prevent deletion of previous IOSystem val io = impl.ioSystem - ioHandler = MemoryIOSystem(buffer) - val fileName = "$AI_MEMORYIO_MAGIC_FILENAME.$hint" + ioHandler = MemoryIOSystem(fileName to buffer) + + readFile(fileName, flags) + + impl.ioSystem = io + + return impl.scene + } + + /**Reads the given file from a memory buffer and returns its contents if successful. + * + * If the call succeeds, the contents of the file are returned as a pointer to an AiScene object. The returned data + * is intended to be read-only, the importer object keeps ownership of the data and will destroy it upon + * destruction. If the import fails, null is returned. + * A human-readable error description can be retrieved by accessing errorString. The previous scene will be deleted + * during this call. + * Calling this method doesn't affect the active IOSystem. + * + * @param fileName name of the base file + * @param files a map containing the names and all the files required to read the scene (base file, materials, + * textures, etc). + * @param flags Optional post processing steps to be executed after a successful import. Provide a bitwise + * combination of the AiPostProcessSteps flags. If you wish to inspect the imported scene first in order to + * fine-tune your post-processing setup, consider to use applyPostProcessing(). + * @return A pointer to the imported data, null if the import failed. + * The pointer to the scene remains in possession of the Importer instance. Use getOrphanedScene() to take + * ownership of it. + */ + fun readFilesFromMemory(fileName: String, files: Map, flags: Int): AiScene? { + + for((name, buffer) in files) { + if(buffer.size == 0){ + impl.errorString = "buffer $name is empty" + return null + } + } + if(!files.containsKey(fileName)){ + impl.errorString = "fileName ($fileName) not in files" + return null + } + + val io = impl.ioSystem + + ioHandler = MemoryIOSystem(files) + readFile(fileName, flags) impl.ioSystem = io @@ -394,6 +436,28 @@ constructor() { return impl.scene } + /**Reads the given file from a memory buffer and returns its contents if successful. + * + * If the call succeeds, the contents of the file are returned as a pointer to an AiScene object. The returned data + * is intended to be read-only, the importer object keeps ownership of the data and will destroy it upon + * destruction. If the import fails, null is returned. + * A human-readable error description can be retrieved by accessing errorString. The previous scene will be deleted + * during this call. + * Calling this method doesn't affect the active IOSystem. + * + * @param fileName name of the base file + * @param flags Optional post processing steps to be executed after a successful import. Provide a bitwise + * combination of the AiPostProcessSteps flags. If you wish to inspect the imported scene first in order to + * fine-tune your post-processing setup, consider to use applyPostProcessing(). + * @param files the files required to read the scene (base file, materials, textures, etc) as a pair with their name. + * @return A pointer to the imported data, null if the import failed. + * The pointer to the scene remains in possession of the Importer instance. Use getOrphanedScene() to take + * ownership of it. + */ + fun readFilesFromMemory(fileName: String, flags: Int, vararg files: Pair): AiScene? { + return readFilesFromMemory(fileName, files.toMap(), flags) + } + /** Apply post-processing to an already-imported scene. * * This is strictly equivalent to calling readFile() with the same flags. However, you can use this separate diff --git a/src/main/kotlin/assimp/MemoryIOWrapper.kt b/src/main/kotlin/assimp/MemoryIOWrapper.kt index 5b62882..d635558 100644 --- a/src/main/kotlin/assimp/MemoryIOWrapper.kt +++ b/src/main/kotlin/assimp/MemoryIOWrapper.kt @@ -3,7 +3,6 @@ package assimp import glm_.* import java.io.* import java.nio.* -import java.nio.file.* import java.io.IOException @@ -11,25 +10,37 @@ import java.io.IOException const val AI_MEMORYIO_MAGIC_FILENAME = "\$\$\$___magic___\$\$\$" const val AI_MEMORYIO_MAGIC_FILENAME_LENGTH = 17 -class MemoryIOSystem(val buffer: ByteBuffer) : IOSystem{ +class MemoryIOSystem : IOSystem{ - /** Tests for the existence of a file at the given path. */ - override fun exists(file: String): Boolean = file.startsWith(AI_MEMORYIO_MAGIC_FILENAME) + val memoryFiles: MutableMap = hashMapOf() + + constructor(buffer: ByteBuffer) { + memoryFiles[AI_MEMORYIO_MAGIC_FILENAME] = buffer + } + + constructor(vararg buffers: Pair): this(buffers.toMap()) + + constructor(buffers: Map){ + memoryFiles.putAll(buffers) + } + /** Tests for the existence of a file at the given path. */ + override fun exists(file: String): Boolean = memoryFiles.containsKey(file) + override fun open(file: String): IOStream { - // TODO assimp originally returns null, but this would be against the current interface. - // I guess it should never happen anyways so an exception is fine - if(!file.startsWith(AI_MEMORYIO_MAGIC_FILENAME)) throw IOException("File does not exist! $file") + val buffer = memoryFiles[file] ?: throw IOException("File does not exist! $file") - return MemoryIOStream(buffer.duplicate().order(ByteOrder.nativeOrder()), file) + return MemoryIOStream(buffer, file, this) } - class MemoryIOStream(val buffer: ByteBuffer, override val filename: String = "") : IOStream { + class MemoryIOStream(val buffer: ByteBuffer, override val path: String, override val osSystem: MemoryIOSystem) : IOStream { - override val path: Path? - get() = null + override val filename: String = run { + val lastIndex = path.lastIndexOf(osSystem.osSeparator) + path.substring(lastIndex + 1) + } override fun read(): InputStream { return ByteBufferBackedInputStream(readBytes()) @@ -39,17 +50,20 @@ class MemoryIOSystem(val buffer: ByteBuffer) : IOSystem{ return BufferedReader(InputStreamReader(read())) } - override fun parentPath(): String = "" + override val parentPath: String = run { + var parent = path.removeSuffix(filename) + parent = parent.removeSuffix(osSystem.osSeparator) + + // ensures that if the path starts with "./" it will always be at least that + if(parent == ".") parent = ".${osSystem.osSeparator}" + + parent + } override val length: Long get() = buffer.size.toLong() - // TODO figure out whether or not I should call dup here - // do multiple calls of read() on the default implementation generate input streams - // with positions that match each other or not? - // If I move duplicate back here I need to also adjust the byte order here - // Then I no longer need to change it in MemoryIOSystem.open - override fun readBytes(): ByteBuffer = buffer + override fun readBytes(): ByteBuffer = buffer.duplicate().order(ByteOrder.nativeOrder()) } } diff --git a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt index 6976988..b4a1a4b 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt @@ -1,8 +1,12 @@ package assimp.format.obj import assimp.* -import gli_.gli -import java.io.IOException +import gli_.* +import gli_.tga.* +import java.io.* +import java.lang.IllegalArgumentException +import javax.imageio.* +import javax.imageio.spi.* /** * Created by elect on 21/11/2016. @@ -426,7 +430,7 @@ class ObjFileImporter : BaseImporter() { //If the default io system is in place, we can use the java.io.File api and list directories //to match files even where case is mangled - val actualFile = (ioSystem.open(file) as DefaultIOSystem.FileIOStream).path.toFile() + val actualFile = (ioSystem.open(file) as DefaultIOSystem.FileIOStream).file when { actualFile.parentFile.listFiles().any { it.name == cleaned } -> { @@ -444,8 +448,29 @@ class ObjFileImporter : BaseImporter() { else -> logger.warn { "OBJ/MTL: Texture image not found --> $cleaned" } } } else { - //no such luck with custom io systems i'm afraid - //TODO gli load from bytebuf ? + val parentPath = ioSystem.open(file).parentPath + ioSystem.osSeparator + + when { + ioSystem.exists(parentPath + cleaned) -> { + + val texFile = ioSystem.open(parentPath + cleaned) + + val typeStart = texFile.filename.lastIndexOf(".") + 1 + val type = texFile.filename.substring(typeStart) + + scene.textures[name] = loadImageFromMemory(texFile, type) + } + ioSystem.exists(parentPath + cleaned.toUpperCase()) -> { + // try case insensitive + val texFile = ioSystem.open(parentPath + cleaned.toUpperCase()) + + val typeStart = texFile.filename.lastIndexOf(".") + 1 + val type = texFile.filename.substring(typeStart).toLowerCase() + + scene.textures[name] = loadImageFromMemory(texFile, type) + } + else -> logger.warn { "OBJ/MTL: Texture image not found --> $cleaned" } + } } } else { @@ -457,6 +482,31 @@ class ObjFileImporter : BaseImporter() { } +// TODO this is pretty much a copy past from gli.read(...) and should be added there +private fun loadImageFromMemory(file: IOStream, type: String): Texture { + return when(type) { + "dds" -> gli.loadDds(file.readBytes()) + "kmg" -> gli.loadKmg(file.readBytes()) + "ktx" -> gli.loadKtx(file.readBytes()) + "jpeg", "jpg", "png", "gif", "bmp", "wbmp" -> { + val image = ImageIO.read(file.read()) + gli.createTexture(image) + } + "tga" -> { + if(!tgaAdded){ + IIORegistry.getDefaultInstance().registerServiceProvider(TgaImageReaderSpi()) + tgaAdded = true + } + val image = ImageIO.read(file.read()) + gli.createTexture(image) + } + else -> throw IllegalArgumentException("Type not supported") + } +} + + +private var tgaAdded = false + diff --git a/src/main/kotlin/assimp/format/obj/ObjFileParser.kt b/src/main/kotlin/assimp/format/obj/ObjFileParser.kt index ec2c4e1..afbd880 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileParser.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileParser.kt @@ -256,16 +256,18 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { if (words.size < 2) throw Error("File name of the material is absent.") // get the name of the mat file with spaces - var filename = ObjTools.getNameWithSpace(words, 1) + val filename = ObjTools.getNameWithSpace(words, 1) - val pFile = file.parentPath() + "/" + filename //windows can just suck it + val pFile = file.parentPath + ioSystem.osSeparator + filename //windows can just suck it println(pFile) if (!ioSystem.exists(pFile)) { - System.err.println("OBJ: Unable to locate material file $filename") + logger.error { "OBJ: Unable to locate material file $filename" } + + // TODO ?? what happens here? val strMatFallbackName = filename.substring(0, filename.length - 3) + "mtl" println("OBJ: Opening fallback material file $strMatFallbackName") - if (!File(strMatFallbackName).exists()) { // TODO read file from mem + if (!ioSystem.exists(strMatFallbackName)) { System.err.println("OBJ: Unable to locate fallback material file $strMatFallbackName") return } diff --git a/src/test/kotlin/assimp/anchor.kt b/src/test/kotlin/assimp/anchor.kt index 9c79d55..235e5e7 100644 --- a/src/test/kotlin/assimp/anchor.kt +++ b/src/test/kotlin/assimp/anchor.kt @@ -29,7 +29,11 @@ fun getResource(resource: String): URL = ClassLoader.getSystemResource(resource) * * @return the result of [Importer.readFile] */ -fun Importer.testFile(path: URL, flags: AiPostProcessStepsFlags = 0, failOnNull: Boolean = true, verify: AiScene.() -> Unit = {}): AiScene? { +fun Importer.testFile(path: URL, + flags: AiPostProcessStepsFlags = 0, + failOnNull: Boolean = true, + verify: AiScene.() -> Unit = {}) + : AiScene? { return testFile(path.file, flags, failOnNull, verify) } @@ -44,7 +48,11 @@ var testReadFromMemory = true * * @return the result of [Importer.readFile] */ -fun Importer.testFile(path: String, flags: AiPostProcessStepsFlags = 0, failOnNull: Boolean = true, verify: AiScene.() -> Unit = {}): AiScene? { +fun Importer.testFile(path: String, + flags: AiPostProcessStepsFlags = 0, + failOnNull: Boolean = true, + verify: AiScene.() -> Unit = {}): AiScene? { + logger.info { "Testing read $path:" } var scene: AiScene? = null if(testReadFile) { @@ -73,6 +81,100 @@ fun Importer.testFile(path: String, flags: AiPostProcessStepsFlags = 0, failOnNu } else { memScene?.verify() } + + if(scene == null) scene = memScene + } + + return scene +} + +/** + * calls both [Importer.readFile] and [Importer.readFilesFromMemory] and verifies it using [verify]. + * This fails if [failOnNull] is set and either of the above returns null. + * + * The first path in [paths] will be used for the base path + * + * @return the result of [Importer.readFile] + */ +fun Importer.testURLs(vararg paths: URL, + flags: AiPostProcessStepsFlags = 0, + failOnNull: Boolean = true, + verify: AiScene.() -> Unit = {}): AiScene? { + return testURLs(listOf(*paths), flags, failOnNull, verify) +} + +/** + * calls both [Importer.readFile] and [Importer.readFilesFromMemory] and verifies it using [verify]. + * This fails if [failOnNull] is set and either of the above returns null. + * + * The first path in [paths] will be used for the base path + * + * @return the result of [Importer.readFile] + */ +fun Importer.testURLs(paths: List, + flags: AiPostProcessStepsFlags = 0, + failOnNull: Boolean = true, + verify: AiScene.() -> Unit = {}): AiScene? { + return testFiles(paths.map(URL::getPath), flags, failOnNull, verify) +} + +/** + * calls both [Importer.readFile] and [Importer.readFilesFromMemory] and verifies it using [verify]. + * This fails if [failOnNull] is set and either of the above returns null. + * + * The first path in [paths] will be used for the base path + * + * @return the result of [Importer.readFile] + */ +fun Importer.testFiles(vararg paths: String, + flags: AiPostProcessStepsFlags = 0, + failOnNull: Boolean = true, + verify: AiScene.() -> Unit = {}): AiScene? { + return testFiles(listOf(*paths), flags, failOnNull, verify) +} + +/** + * calls both [Importer.readFile] and [Importer.readFilesFromMemory] and verifies it using [verify]. + * This fails if [failOnNull] is set and either of the above returns null. + * + * The first path in [paths] will be used for the base path + * + * @return the result of [Importer.readFile] + */ +fun Importer.testFiles(paths: List, + flags: AiPostProcessStepsFlags = 0, + failOnNull: Boolean = true, + verify: AiScene.() -> Unit = {}): AiScene? { + + val baseFile = paths[0] + + logger.info { "Testing read $baseFile:" } + + var scene: AiScene? = null + if(testReadFile){ + logger.info { "reading from file:"} + // test readFile + scene = readFile(baseFile, flags) + if (scene == null && failOnNull) { + fail("readFile returned 'null' for $baseFile") + } else { + scene?.verify() + } + } + + if(testReadFromMemory) { + logger.info { "reading from memory:" } + + val files = paths.map { it to ByteBuffer.wrap(FileInputStream(File(it)).readBytes()) }.toMap() + + val memScene = readFilesFromMemory(baseFile, files, flags) + if (memScene == null && failOnNull) { + fail("readFileFromMemory returned 'null' for $baseFile") + } else { + memScene?.verify() + } + + if(scene == null) scene = memScene } return scene diff --git a/src/test/kotlin/assimp/obj/box.kt b/src/test/kotlin/assimp/obj/box.kt index ac04194..255c812 100644 --- a/src/test/kotlin/assimp/obj/box.kt +++ b/src/test/kotlin/assimp/obj/box.kt @@ -4,8 +4,6 @@ import assimp.* import glm_.mat4x4.Mat4 import glm_.vec3.Vec3 import io.kotlintest.shouldBe -import uno.kotlin.uri -import uno.kotlin.url /** * Created by elect on 16/11/2016. @@ -15,7 +13,7 @@ object box { operator fun invoke(fileName: String) { - Importer().testFile(getResource(fileName)) { + Importer().testURLs(getResource(fileName)) { with(rootNode) { diff --git a/src/test/kotlin/assimp/obj/nanosuit.kt b/src/test/kotlin/assimp/obj/nanosuit.kt index d1006bd..2ac2811 100644 --- a/src/test/kotlin/assimp/obj/nanosuit.kt +++ b/src/test/kotlin/assimp/obj/nanosuit.kt @@ -8,8 +8,11 @@ import java.util.* object nanosuit { - operator fun invoke(fileName: String) { - Importer().testFile(getResource(fileName)) { + operator fun invoke(fileName: String, matName: String, vararg imagePath: String) { + + val imageURLs = imagePath.map { getResource(it) }.toTypedArray() + + Importer().testURLs(getResource(fileName), getResource(matName), *imageURLs) { with(rootNode) { @@ -430,6 +433,9 @@ object nanosuit { uvwsrc shouldBe 0 } } + + // numTextures shouldBe 23 // TODO not set + textures.size shouldBe 23 } } } \ No newline at end of file diff --git a/src/test/kotlin/assimp/obj/obj.kt b/src/test/kotlin/assimp/obj/obj.kt index 50bad51..b28bfae 100644 --- a/src/test/kotlin/assimp/obj/obj.kt +++ b/src/test/kotlin/assimp/obj/obj.kt @@ -11,8 +11,41 @@ class obj : StringSpec() { "cube"{ cube(path + "cube.obj") } "wall"{ wall(path + "wall.obj") } "box"{ box(path + "box.obj") } - "spider"{ spider(path + "spider.obj") } - "nanosuit" { nanosuit(path + "nanosuit/nanosuit.obj") } - "shelter" { shelter(path + "statie B01.obj")} + + "spider"{ spider(path + "spider.obj", + path + "spider.mtl", + path + "wal67ar_small.jpg", + path + "wal69ar_small.jpg", + path + "SpiderTex.jpg", + path + "drkwood2.jpg", + path + "engineflare1.jpg") } + + "nanosuit" { nanosuit(path + "nanosuit/nanosuit.obj", + path + "nanosuit/nanosuit.mtl", + path + "nanosuit/arm_showroom_ddn.png", + path + "nanosuit/arm_showroom_refl.png", + path + "nanosuit/arm_dif.png", + path + "nanosuit/arm_showroom_spec.png", + path + "nanosuit/body_dif.png", + path + "nanosuit/body_showroom_ddn.png", + path + "nanosuit/body_showroom_refl.png", + path + "nanosuit/body_showroom_spec.png", + path + "nanosuit/glass_ddn.png", + path + "nanosuit/glass_refl.png", + path + "nanosuit/glass_dif.png", + path + "nanosuit/hand_showroom_ddn.png", + path + "nanosuit/hand_showroom_refl.png", + path + "nanosuit/hand_dif.png", + path + "nanosuit/hand_showroom_spec.png", + path + "nanosuit/helmet_showroom_ddn.png", + path + "nanosuit/helmet_showroom_refl.png", + path + "nanosuit/helmet_diff.png", + path + "nanosuit/helmet_showroom_spec.png", + path + "nanosuit/leg_showroom_ddn.png", + path + "nanosuit/leg_showroom_refl.png", + path + "nanosuit/leg_dif.png", + path + "nanosuit/leg_showroom_spec.png") } + + "shelter".config(enabled = false) { shelter(path + "statie B01.obj")} // TODO this file exists, but there is a problem with finding it, I guess due to the space in the filename } } \ No newline at end of file diff --git a/src/test/kotlin/assimp/obj/spider.kt b/src/test/kotlin/assimp/obj/spider.kt index f5c4f84..5102c0c 100644 --- a/src/test/kotlin/assimp/obj/spider.kt +++ b/src/test/kotlin/assimp/obj/spider.kt @@ -8,9 +8,10 @@ import java.util.* object spider { - operator fun invoke(fileName: String) { + operator fun invoke(fileName: String, matName: String, img1: String, img2: String, img3: String, img4: String, img5: String) { - Importer().testFile(getResource(fileName)){ + Importer().testURLs(getResource(fileName), getResource(matName), + getResource(img1), getResource(img2), getResource(img3), getResource(img4), getResource(img5)){ with(rootNode) { @@ -199,6 +200,9 @@ object spider { } textures[0].file shouldBe ".\\engineflare1.jpg" } + + // numTextures shouldBe 5 // TODO numTextures is not set + textures.size shouldBe 5 } } } \ No newline at end of file From 9b6c20d3e44f7c0521b5b86633d5f67ad73499f0 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Wed, 5 Sep 2018 23:57:45 +0200 Subject: [PATCH 10/20] removed unnecessary file.exists checks Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/format/X/XFileImporter.kt | 3 --- src/main/kotlin/assimp/format/md2/Md2Loader.kt | 4 ---- src/main/kotlin/assimp/format/md3/Md3Loader.kt | 2 -- src/main/kotlin/assimp/format/obj/ObjFileImporter.kt | 3 +-- src/main/kotlin/assimp/format/ply/PlyLoader.kt | 3 --- src/main/kotlin/assimp/format/stl/STLLoader.kt | 3 --- 6 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/main/kotlin/assimp/format/X/XFileImporter.kt b/src/main/kotlin/assimp/format/X/XFileImporter.kt index a2f1728..22edc69 100644 --- a/src/main/kotlin/assimp/format/X/XFileImporter.kt +++ b/src/main/kotlin/assimp/format/X/XFileImporter.kt @@ -25,9 +25,6 @@ class XFileImporter : BaseImporter() { override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { - // Read file into memory - if (!ioSystem.exists(file)) throw IOException("Failed to open file $file.") - val stream = ioSystem.open(file).read() val bytes = stream.readBytes() diff --git a/src/main/kotlin/assimp/format/md2/Md2Loader.kt b/src/main/kotlin/assimp/format/md2/Md2Loader.kt index fb0fb9d..6614f94 100644 --- a/src/main/kotlin/assimp/format/md2/Md2Loader.kt +++ b/src/main/kotlin/assimp/format/md2/Md2Loader.kt @@ -108,10 +108,6 @@ class Md2Importer : BaseImporter() { * See BaseImporter.internReadFile() for details */ override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { - // Check whether we can read from the file - if (!ioSystem.exists(file)) - throw Error("Failed to open MD2 file $file") - val stream = ioSystem.open(file) // check whether the md3 file is large enough to contain at least the file header diff --git a/src/main/kotlin/assimp/format/md3/Md3Loader.kt b/src/main/kotlin/assimp/format/md3/Md3Loader.kt index c10fffd..9568ffd 100644 --- a/src/main/kotlin/assimp/format/md3/Md3Loader.kt +++ b/src/main/kotlin/assimp/format/md3/Md3Loader.kt @@ -393,9 +393,7 @@ class Md3Importer : BaseImporter() { // Load multi-part model file, if necessary if (configHandleMP && readMultipartFile()) return - // Check whether we can read from the file // TODO read mem file - if (!ioSystem.exists(file)) throw Error("Failed to open MD3 file $file.") val stream = ioSystem.open(file) // Check whether the md3 file is large enough to contain the header diff --git a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt index b4a1a4b..38fbd57 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt @@ -38,8 +38,7 @@ class ObjFileImporter : BaseImporter() { override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { // Read file into memory - this.file = file//File(file) - if (!ioSystem.exists(file)) throw IOException("Failed to open file $file.") + this.file = file // Get the file-size and validate it, throwing an exception when fails val stream = ioSystem.open(file) diff --git a/src/main/kotlin/assimp/format/ply/PlyLoader.kt b/src/main/kotlin/assimp/format/ply/PlyLoader.kt index f7d138d..a01bb85 100644 --- a/src/main/kotlin/assimp/format/ply/PlyLoader.kt +++ b/src/main/kotlin/assimp/format/ply/PlyLoader.kt @@ -36,9 +36,6 @@ class PlyLoader : BaseImporter() { // Imports the given file into the given scene structure. override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { - // Check whether we can read from the file - if (!ioSystem.exists(file)) throw IOException("Failed to open PLY file $file.") - // allocate storage and copy the contents of the file to a memory buffer val buffer = ioSystem.open(file).readBytes() diff --git a/src/main/kotlin/assimp/format/stl/STLLoader.kt b/src/main/kotlin/assimp/format/stl/STLLoader.kt index 36b35c0..719f5a6 100644 --- a/src/main/kotlin/assimp/format/stl/STLLoader.kt +++ b/src/main/kotlin/assimp/format/stl/STLLoader.kt @@ -97,9 +97,6 @@ class StlImporter : BaseImporter() { // Imports the given file into the given scene structure. override fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) { - // Check whether we can read from the file - if (!ioSystem.exists(file)) throw IOException("Failed to open STL file $file.") - val stream = ioSystem.open(file) fileSize = stream.length.i From 0d00c5cbc1b439f5535fd862697d95b8c6ebddde Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 6 Sep 2018 02:16:03 +0200 Subject: [PATCH 11/20] removed some warnings Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/DefaultIOSystem.kt | 4 +--- src/main/kotlin/assimp/format/obj/ObjFileParser.kt | 2 +- src/test/kotlin/X/helpers.kt | 6 +++--- src/test/kotlin/assimp/collada/color teapot spheres.kt | 2 +- .../kotlin/assimp/collada/treasure_smooth Pretransform.kt | 2 +- src/test/kotlin/assimp/collada/treasure_smooth.kt | 2 +- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/assimp/DefaultIOSystem.kt b/src/main/kotlin/assimp/DefaultIOSystem.kt index e4bab8d..f4cc654 100644 --- a/src/main/kotlin/assimp/DefaultIOSystem.kt +++ b/src/main/kotlin/assimp/DefaultIOSystem.kt @@ -3,7 +3,6 @@ package assimp import java.io.* import java.nio.* import java.nio.channels.* -import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths @@ -14,10 +13,9 @@ class DefaultIOSystem : IOSystem { override fun open(file: String): IOStream { val path: Path = Paths.get(file) - if (!Files.exists(path)) + if (!exists(file)) throw IOException("File doesn't exist: $file") - return FileIOStream(path, this) } diff --git a/src/main/kotlin/assimp/format/obj/ObjFileParser.kt b/src/main/kotlin/assimp/format/obj/ObjFileParser.kt index afbd880..515a819 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileParser.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileParser.kt @@ -258,7 +258,7 @@ class ObjFileParser(private val file: IOStream, val ioSystem: IOSystem) { // get the name of the mat file with spaces val filename = ObjTools.getNameWithSpace(words, 1) - val pFile = file.parentPath + ioSystem.osSeparator + filename //windows can just suck it + val pFile = "${file.parentPath}${ioSystem.osSeparator}$filename" println(pFile) if (!ioSystem.exists(pFile)) { diff --git a/src/test/kotlin/X/helpers.kt b/src/test/kotlin/X/helpers.kt index fc4b254..90885db 100644 --- a/src/test/kotlin/X/helpers.kt +++ b/src/test/kotlin/X/helpers.kt @@ -59,13 +59,13 @@ fun compareTextures(texture: Texture, texture1: Texture) { texture.baseLayer shouldBe texture1.baseLayer texture.baseLevel shouldBe texture1.baseLevel compareCache(texture.cache, texture1.cache) - texture.format.shouldEqual(texture1.format) + texture.format shouldBe texture1.format texture.maxFace shouldBe texture1.maxFace texture.maxLayer shouldBe texture1.maxLayer texture.maxLevel shouldBe texture1.maxLevel texture.size shouldBe texture1.size - texture.swizzles.shouldEqual(texture1.swizzles) - texture.target.shouldEqual(texture1.target) + texture.swizzles shouldBe texture1.swizzles + texture.target shouldBe texture1.target } fun compareCache(cache: Cache, cache1: Cache) { diff --git a/src/test/kotlin/assimp/collada/color teapot spheres.kt b/src/test/kotlin/assimp/collada/color teapot spheres.kt index a4cbf68..175ea58 100644 --- a/src/test/kotlin/assimp/collada/color teapot spheres.kt +++ b/src/test/kotlin/assimp/collada/color teapot spheres.kt @@ -3,7 +3,7 @@ package assimp.collada import assimp.* import glm_.mat4x4.Mat4 import glm_.vec3.Vec3 -import io.kotlintest.matchers.shouldBe +import io.kotlintest.shouldBe import java.net.URL object `color teapot spheres` { diff --git a/src/test/kotlin/assimp/collada/treasure_smooth Pretransform.kt b/src/test/kotlin/assimp/collada/treasure_smooth Pretransform.kt index c5cfe50..cdf70e1 100644 --- a/src/test/kotlin/assimp/collada/treasure_smooth Pretransform.kt +++ b/src/test/kotlin/assimp/collada/treasure_smooth Pretransform.kt @@ -3,7 +3,7 @@ package assimp.collada import assimp.* import glm_.mat4x4.Mat4 import glm_.vec3.Vec3 -import io.kotlintest.matchers.shouldBe +import io.kotlintest.shouldBe import java.net.URL object `treasure_smooth Pretransform` { diff --git a/src/test/kotlin/assimp/collada/treasure_smooth.kt b/src/test/kotlin/assimp/collada/treasure_smooth.kt index 0a8fa0d..5c454f0 100644 --- a/src/test/kotlin/assimp/collada/treasure_smooth.kt +++ b/src/test/kotlin/assimp/collada/treasure_smooth.kt @@ -3,7 +3,7 @@ package assimp.collada import assimp.* import glm_.mat4x4.Mat4 import glm_.vec3.Vec3 -import io.kotlintest.matchers.shouldBe +import io.kotlintest.shouldBe import java.net.URL object treasure_smooth { From 1070491b5c592cc264758009f567fedcbb76e09f Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 6 Sep 2018 02:20:38 +0200 Subject: [PATCH 12/20] removed boblampclean_assbin.kt (file is exact copy of assbin.kt just with a different test name) Signed-off-by: Burkhard Mittelbach --- .../assimp/assbin/boblampclean_assbin.kt | 40 ------------------- 1 file changed, 40 deletions(-) delete mode 100644 src/test/kotlin/assimp/assbin/boblampclean_assbin.kt diff --git a/src/test/kotlin/assimp/assbin/boblampclean_assbin.kt b/src/test/kotlin/assimp/assbin/boblampclean_assbin.kt deleted file mode 100644 index 01ddd4b..0000000 --- a/src/test/kotlin/assimp/assbin/boblampclean_assbin.kt +++ /dev/null @@ -1,40 +0,0 @@ -package assimp.assbin - -import assimp.* -import io.kotlintest.specs.StringSpec - -// TODO -class `boblampclean assbin` : StringSpec() { - - val boblampclean = "ogldev/boblampclean.assbin" - - init { - -// val anims_with_full_rotations_between_keys = "anims_with_full_rotations_between_keys.assbin" -// -// anims_with_full_rotations_between_keys { -// -// val scene = Importer().readFile(assbin + anims_with_full_rotations_between_keys)!! -// println() -//// scene.flags shouldBe 0 -// } -// - - - boblampclean { - - val scene = Importer().testFile(getResource("$assbin/$boblampclean")) - - println() - } - - val minigun = "MDL/MDL3 (3DGS A4)/minigun.assbin" - - minigun { - - val scene = Importer().testFile(getResource("$assbin/$minigun")) - - println() - } - } -} \ No newline at end of file From fef0c5d12d99a96c42c068480ad4acd567500bb8 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 6 Sep 2018 02:39:37 +0200 Subject: [PATCH 13/20] Fixed bug where URLs with spaces would not be resolved Signed-off-by: Burkhard Mittelbach --- src/test/kotlin/assimp/anchor.kt | 53 ++++++++++++++++++++++++--- src/test/kotlin/assimp/obj/obj.kt | 2 +- src/test/kotlin/assimp/obj/shelter.kt | 4 +- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/test/kotlin/assimp/anchor.kt b/src/test/kotlin/assimp/anchor.kt index 235e5e7..7b15d90 100644 --- a/src/test/kotlin/assimp/anchor.kt +++ b/src/test/kotlin/assimp/anchor.kt @@ -2,8 +2,9 @@ package assimp import io.kotlintest.* import java.io.* -import java.net.URL +import java.net.* import java.nio.* +import java.nio.file.* /** * Created by elect on 14/01/2017. @@ -32,9 +33,21 @@ fun getResource(resource: String): URL = ClassLoader.getSystemResource(resource) fun Importer.testFile(path: URL, flags: AiPostProcessStepsFlags = 0, failOnNull: Boolean = true, - verify: AiScene.() -> Unit = {}) - : AiScene? { - return testFile(path.file, flags, failOnNull, verify) + verify: AiScene.() -> Unit = {}): AiScene? { + return testFile(path.toURI(), flags, failOnNull, verify) +} + +/** + * calls both [Importer.readFile] and [Importer.readFileFromMemory] and verifies it using [verify]. + * This fails if [failOnNull] is set and either of the above returns null. + * + * @return the result of [Importer.readFile] + */ +fun Importer.testFile(path: URI, + flags: AiPostProcessStepsFlags = 0, + failOnNull: Boolean = true, + verify: AiScene.() -> Unit = {}): AiScene? { + return testFile(Paths.get(path).toAbsolutePath().toString(), flags, failOnNull, verify) } @@ -115,7 +128,37 @@ fun Importer.testURLs(paths: List, flags: AiPostProcessStepsFlags = 0, failOnNull: Boolean = true, verify: AiScene.() -> Unit = {}): AiScene? { - return testFiles(paths.map(URL::getPath), flags, failOnNull, verify) + return testURIs(paths.map(URL::toURI), flags, failOnNull, verify) +} + +/** + * calls both [Importer.readFile] and [Importer.readFilesFromMemory] and verifies it using [verify]. + * This fails if [failOnNull] is set and either of the above returns null. + * + * The first path in [paths] will be used for the base path + * + * @return the result of [Importer.readFile] + */ +fun Importer.testURIs(vararg paths: URI, + flags: AiPostProcessStepsFlags = 0, + failOnNull: Boolean = true, + verify: AiScene.() -> Unit = {}): AiScene? { + return testURIs(listOf(*paths), flags, failOnNull, verify) +} + +/** + * calls both [Importer.readFile] and [Importer.readFilesFromMemory] and verifies it using [verify]. + * This fails if [failOnNull] is set and either of the above returns null. + * + * The first path in [paths] will be used for the base path + * + * @return the result of [Importer.readFile] + */ +fun Importer.testURIs(paths: List, + flags: AiPostProcessStepsFlags = 0, + failOnNull: Boolean = true, + verify: AiScene.() -> Unit = {}): AiScene? { + return testFiles(paths.map { Paths.get(it).toAbsolutePath().toString() }, flags, failOnNull, verify) } /** diff --git a/src/test/kotlin/assimp/obj/obj.kt b/src/test/kotlin/assimp/obj/obj.kt index b28bfae..f266c88 100644 --- a/src/test/kotlin/assimp/obj/obj.kt +++ b/src/test/kotlin/assimp/obj/obj.kt @@ -46,6 +46,6 @@ class obj : StringSpec() { path + "nanosuit/leg_dif.png", path + "nanosuit/leg_showroom_spec.png") } - "shelter".config(enabled = false) { shelter(path + "statie B01.obj")} // TODO this file exists, but there is a problem with finding it, I guess due to the space in the filename + "shelter" { shelter(path + "statie B01.obj",path + "statie B01.mtl")} } } \ No newline at end of file diff --git a/src/test/kotlin/assimp/obj/shelter.kt b/src/test/kotlin/assimp/obj/shelter.kt index 83a42c8..0fdcaaa 100644 --- a/src/test/kotlin/assimp/obj/shelter.kt +++ b/src/test/kotlin/assimp/obj/shelter.kt @@ -11,9 +11,9 @@ import io.kotlintest.shouldBe object shelter { - operator fun invoke(fileName: String) { + operator fun invoke(fileName: String, matName: String) { - Importer().testFile(getResource(fileName)) { + Importer().testURLs(getResource(fileName), getResource(matName)) { with(rootNode) { From 0dc97b8ecd973bdc6cc13e7bbd88e4932b69128d Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 6 Sep 2018 03:49:47 +0200 Subject: [PATCH 14/20] Fixed read byte bug in ByteBufferBackedInputStream. stupid number conversions Signed-off-by: Burkhard Mittelbach --- README.md | 2 +- src/main/kotlin/assimp/MemoryIOWrapper.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1a1ebd8..3d18207 100644 --- a/README.md +++ b/README.md @@ -75,10 +75,10 @@ Working: - fbx - stl - obj +- assbin Failing: -- assbin - md2 - md3 - md5 diff --git a/src/main/kotlin/assimp/MemoryIOWrapper.kt b/src/main/kotlin/assimp/MemoryIOWrapper.kt index d635558..ef611e4 100644 --- a/src/main/kotlin/assimp/MemoryIOWrapper.kt +++ b/src/main/kotlin/assimp/MemoryIOWrapper.kt @@ -87,7 +87,7 @@ private class ByteBufferBackedInputStream(val buf: ByteBuffer) : InputStream() { override fun read(): Int { return if (!buf.hasRemaining()) { -1 - } else (buf.get() and 0xFF).toInt() + } else buf.get().toInt() and 0xFF } /** From f7c9b0e5a4c9122327248ef010b84480d91781a0 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 6 Sep 2018 05:16:54 +0200 Subject: [PATCH 15/20] MD2 and MD5 is working properly. MD3 is stupid Signed-off-by: Burkhard Mittelbach --- README.md | 4 +-- src/main/kotlin/assimp/MemoryIOWrapper.kt | 1 - .../kotlin/assimp/format/md3/Md3Loader.kt | 30 ++++++++++--------- .../kotlin/assimp/format/md5/MD5Loader.kt | 4 +-- src/test/kotlin/assimp/md2/faerie.kt | 10 ++++--- src/test/kotlin/assimp/md2/md2.kt | 2 +- src/test/kotlin/assimp/md5/boarMan.kt | 2 +- src/test/kotlin/assimp/md5/md5.kt | 1 + src/test/kotlin/assimp/md5/simpleCube.kt | 2 +- 9 files changed, 30 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 3d18207..325bb57 100644 --- a/README.md +++ b/README.md @@ -76,12 +76,12 @@ Working: - stl - obj - assbin +- md2 +- md5 Failing: -- md2 - md3 -- md5 Disabled: diff --git a/src/main/kotlin/assimp/MemoryIOWrapper.kt b/src/main/kotlin/assimp/MemoryIOWrapper.kt index ef611e4..5573b70 100644 --- a/src/main/kotlin/assimp/MemoryIOWrapper.kt +++ b/src/main/kotlin/assimp/MemoryIOWrapper.kt @@ -24,7 +24,6 @@ class MemoryIOSystem : IOSystem{ memoryFiles.putAll(buffers) } - /** Tests for the existence of a file at the given path. */ override fun exists(file: String): Boolean = memoryFiles.containsKey(file) diff --git a/src/main/kotlin/assimp/format/md3/Md3Loader.kt b/src/main/kotlin/assimp/format/md3/Md3Loader.kt index 9568ffd..84a9b23 100644 --- a/src/main/kotlin/assimp/format/md3/Md3Loader.kt +++ b/src/main/kotlin/assimp/format/md3/Md3Loader.kt @@ -118,14 +118,15 @@ object Q3Shader { * @param io IOSystem to be used for reading * @return false if file is not accessible */ - fun loadShader(fill: ShaderData, file: String): Boolean { - // TODO load from mem - val f = File(file) - if (!f.exists()) return false // if we can't access the file, don't worry and return + fun loadShader(fill: ShaderData, file: String, ioSystem: IOSystem): Boolean { + + if (!ioSystem.exists(file)) return false // if we can't access the file, don't worry and return + + val reader = ioSystem.open(file).reader() logger.info { "Loading Quake3 shader file $file" } // read file in memory and remove comments from it (C++ style) and empty or blank lines - val lines = f.readLines().filter { !it.startsWith("//") && it.isNotEmpty() && it.isNotBlank() } + val lines = reader.readLines().filter { !it.startsWith("//") && it.isNotEmpty() && it.isNotBlank() } .map { it.trim() } // and trim it var curData: Q3Shader.ShaderDataBlock? = null @@ -272,15 +273,16 @@ object Q3Shader { * @param io IOSystem to be used for reading * @return false if file is not accessible */ - fun loadSkin(fill: SkinData, file: String): Boolean { - // TODO load from mem - val f = File(file) - if (!f.canRead()) return false // if we can't access the file, don't worry and return + fun loadSkin(fill: SkinData, file: String, ioSystem: IOSystem): Boolean { + + if (!ioSystem.exists(file)) return false // if we can't access the file, don't worry and return logger.info { "Loading Quake3 skin file $file" } + val ioStream = ioSystem.open(file) + // read file in memory - val s = f.length() + val s = ioStream.length TODO() // std::vector _buff(s+1);const char* buff = &_buff[0]; // f->Read(&_buff[0],s,1); @@ -393,7 +395,6 @@ class Md3Importer : BaseImporter() { // Load multi-part model file, if necessary if (configHandleMP && readMultipartFile()) return - // TODO read mem file val stream = ioSystem.open(file) // Check whether the md3 file is large enough to contain the header @@ -740,7 +741,7 @@ class Md3Importer : BaseImporter() { } assert(s != -1) val skinFile = path + filename.substring(0, s) + "_$configSkinFile.skin" - Q3Shader.loadSkin(fill, skinFile) + Q3Shader.loadSkin(fill, skinFile, ioSystem) } /** Try to read the shader for a MD3 file @@ -752,8 +753,9 @@ class Md3Importer : BaseImporter() { // If no specific dir or file is given, use our default search behaviour if (configShaderFile.isEmpty()) { - if (!Q3Shader.loadShader(fill, "$path../../../scripts/$modelFile.shader")) - Q3Shader.loadShader(fill, "$path../../../scripts/$filename.shader") + // TODO read from memory: how do we resolve ../../.. + if (!Q3Shader.loadShader(fill, "$path../../../scripts/$modelFile.shader", ioSystem)) + Q3Shader.loadShader(fill, "$path../../../scripts/$filename.shader", ioSystem) } else { TODO() // // If the given string specifies a file, load this file. diff --git a/src/main/kotlin/assimp/format/md5/MD5Loader.kt b/src/main/kotlin/assimp/format/md5/MD5Loader.kt index eb92521..683993d 100644 --- a/src/main/kotlin/assimp/format/md5/MD5Loader.kt +++ b/src/main/kotlin/assimp/format/md5/MD5Loader.kt @@ -151,7 +151,7 @@ class Md5Importer : BaseImporter() { ioFile = ioSystem.open(file + "md5mesh") } catch(e : IOException) { // Check whether we can read from the file - logger.warn { "Failed to access MD5MESH file: $file" } + logger.warn { "Failed to access MD5MESH file: ${file}md5mesh" } return } loadFileIntoMemory(ioFile.reader()) @@ -320,7 +320,7 @@ class Md5Importer : BaseImporter() { ioFile = ioSystem.open(file + "md5anim") } catch(e : IOException) { // Check whether we can read from the file - logger.warn { "Failed to access MD5ANIM file: $file" } + logger.warn { "Failed to access MD5ANIM file: ${file}md5anim" } return } loadFileIntoMemory(ioFile.reader()) diff --git a/src/test/kotlin/assimp/md2/faerie.kt b/src/test/kotlin/assimp/md2/faerie.kt index e06b873..a2dde63 100644 --- a/src/test/kotlin/assimp/md2/faerie.kt +++ b/src/test/kotlin/assimp/md2/faerie.kt @@ -3,13 +3,14 @@ package assimp.md2 import assimp.* import glm_.mat4x4.Mat4 import glm_.vec3.Vec3 -import io.kotlintest.shouldBe +import io.kotlintest.* +import io.kotlintest.matchers.endWith object faerie { - operator fun invoke(fileName: String) { + operator fun invoke(fileName: String, imgFile: String) { - Importer().testFile(getResource(fileName)){ + Importer().testURLs(getResource(fileName), getResource(imgFile)){ flags shouldBe 0 @@ -59,7 +60,8 @@ object faerie { ambient shouldBe Vec3(0.0500000007) } textures[0].type shouldBe AiTexture.Type.diffuse - textures[0].file shouldBe "faerie.bmp" + //textures[0].file shouldBe "faerie.bmp" + textures[0].file!! should endWith("faerie.bmp") name shouldBe "DefaultMaterial" } } diff --git a/src/test/kotlin/assimp/md2/md2.kt b/src/test/kotlin/assimp/md2/md2.kt index 9f9f211..d82ad91 100644 --- a/src/test/kotlin/assimp/md2/md2.kt +++ b/src/test/kotlin/assimp/md2/md2.kt @@ -12,6 +12,6 @@ class md2 : StringSpec() { val path = "$models/MD2/" init { - "faerie" { faerie(path + "faerie.md2") } + "faerie" { faerie(path + "faerie.md2", path + "faerie2.bmp") } } } \ No newline at end of file diff --git a/src/test/kotlin/assimp/md5/boarMan.kt b/src/test/kotlin/assimp/md5/boarMan.kt index 5d6361c..6e9d8e8 100644 --- a/src/test/kotlin/assimp/md5/boarMan.kt +++ b/src/test/kotlin/assimp/md5/boarMan.kt @@ -9,7 +9,7 @@ object boarMan { operator fun invoke(fileName: String) { - Importer().testFile(getResource(fileName)) { + Importer().testURLs(getResource(fileName)) { flags shouldBe 0 diff --git a/src/test/kotlin/assimp/md5/md5.kt b/src/test/kotlin/assimp/md5/md5.kt index e8728bc..f65af91 100644 --- a/src/test/kotlin/assimp/md5/md5.kt +++ b/src/test/kotlin/assimp/md5/md5.kt @@ -16,5 +16,6 @@ class md5 : StringSpec() { init { "simple cube" { simpleCube(path + "SimpleCube.md5mesh") } "boar man" { boarMan(path_ + "BoarMan.md5mesh") } + // TODO no tests for anim files } } \ No newline at end of file diff --git a/src/test/kotlin/assimp/md5/simpleCube.kt b/src/test/kotlin/assimp/md5/simpleCube.kt index c7bd589..4834b59 100644 --- a/src/test/kotlin/assimp/md5/simpleCube.kt +++ b/src/test/kotlin/assimp/md5/simpleCube.kt @@ -9,7 +9,7 @@ object simpleCube { operator fun invoke(fileName: String) { - Importer().testFile(getResource(fileName)) { + Importer().testURLs(getResource(fileName)) { flags shouldBe 0 From 01c4c028aab7924b8995f8c90d019903240e2513 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 6 Sep 2018 07:00:57 +0200 Subject: [PATCH 16/20] fix bug using wrong reference to ioSystem Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/BaseImporter.kt | 10 ++++------ src/main/kotlin/assimp/format/md3/Md3Loader.kt | 8 ++++---- src/main/kotlin/assimp/format/obj/ObjFileImporter.kt | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/assimp/BaseImporter.kt b/src/main/kotlin/assimp/BaseImporter.kt index 475ff2b..d765c19 100644 --- a/src/main/kotlin/assimp/BaseImporter.kt +++ b/src/main/kotlin/assimp/BaseImporter.kt @@ -19,7 +19,6 @@ abstract class BaseImporter { /** Currently set progress handler. */ var progress: ProgressHandler? = null - var ioSystem: IOSystem = ASSIMP.defaultIOSystem /** Returns whether the class can handle the format of the given file. *. * The implementation should be as quick as possible. A check for the file extension is enough. If no suitable @@ -47,7 +46,8 @@ abstract class BaseImporter { * exception is thrown somewhere in internReadFile(), this function will catch it and transform it into a suitable * response to the caller. */ - fun readFile(imp: Importer, pIOHandler: IOSystem = ioSystem, filePath: String): AiScene? { + fun readFile(imp: Importer, ioHandler: IOSystem = ASSIMP.defaultIOSystem, filePath: String): AiScene? { + progress = imp.progressHandler assert(progress != null) @@ -59,7 +59,7 @@ abstract class BaseImporter { // dispatch importing try { - internReadFile(filePath, pIOHandler, sc) + internReadFile(filePath, ioHandler, sc) } catch (err: Exception) { // extract error description err.printStackTrace() @@ -119,9 +119,7 @@ abstract class BaseImporter { * @param file Path of the file to be imported. * @param scene The scene object to hold the imported data. Null is not a valid parameter. * */ - open fun internReadFile(file: String, ioSystem: IOSystem = this.ioSystem, scene: AiScene) = Unit//internReadFile(file.uri, scene) - - //open fun internReadFile(file: URI, pIOHandler: IOSystem, scene: AiScene) = Unit + open fun internReadFile(file: String, ioSystem: IOSystem, scene: AiScene) = Unit companion object { /** Extract file extension from a string diff --git a/src/main/kotlin/assimp/format/md3/Md3Loader.kt b/src/main/kotlin/assimp/format/md3/Md3Loader.kt index 84a9b23..0252b21 100644 --- a/src/main/kotlin/assimp/format/md3/Md3Loader.kt +++ b/src/main/kotlin/assimp/format/md3/Md3Loader.kt @@ -420,10 +420,10 @@ class Md3Importer : BaseImporter() { scene.numMaterials = header.numSurfaces // Now read possible skins from .skin file val skins = Q3Shader.SkinData() - readSkin(skins) + readSkin(skins, ioSystem) // And check whether we can locate a shader file for this model val shadersData = Q3Shader.ShaderData() - readShader(shadersData) + readShader(shadersData, ioSystem) // Adjust all texture paths in the shader val headerName = header.name @@ -732,7 +732,7 @@ class Md3Importer : BaseImporter() { /** Try to read the skin for a MD3 file * @param fill Receives output information */ - fun readSkin(fill: Q3Shader.SkinData) { + fun readSkin(fill: Q3Shader.SkinData, ioSystem: IOSystem) { // skip any postfixes (e.g. lower_1.md3) var s = filename.lastIndexOf('_') if (s == -1) { @@ -746,7 +746,7 @@ class Md3Importer : BaseImporter() { /** Try to read the shader for a MD3 file * @param fill Receives output information */ - fun readShader(fill: Q3Shader.ShaderData) { + fun readShader(fill: Q3Shader.ShaderData, ioSystem: IOSystem) { // Determine Q3 model name from given path val last = path.substring(0, path.length - 2).lastIndexOf(File.separatorChar) val modelFile = path.substring(last + 1, path.length - 1) diff --git a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt index 38fbd57..0e81e89 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt @@ -410,7 +410,7 @@ class ObjFileImporter : BaseImporter() { } /** Load textures */ - fun loadTextures(scene: AiScene, ioSystem: IOSystem = this.ioSystem) { + fun loadTextures(scene: AiScene, ioSystem: IOSystem = ASSIMP.defaultIOSystem) { scene.materials.forEach { mtl -> From a1df627c6c2379f5ec52a9bc4d24744fb2a9e2ca Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 6 Sep 2018 07:23:17 +0200 Subject: [PATCH 17/20] MD3 relative path workaround Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/Importer.kt | 2 +- src/test/kotlin/assimp/md3/europeanFnt.kt | 412 +++++++++++----------- src/test/kotlin/assimp/md3/md3.kt | 3 +- 3 files changed, 217 insertions(+), 200 deletions(-) diff --git a/src/main/kotlin/assimp/Importer.kt b/src/main/kotlin/assimp/Importer.kt index 5c67bb4..d83d908 100644 --- a/src/main/kotlin/assimp/Importer.kt +++ b/src/main/kotlin/assimp/Importer.kt @@ -454,7 +454,7 @@ constructor() { * The pointer to the scene remains in possession of the Importer instance. Use getOrphanedScene() to take * ownership of it. */ - fun readFilesFromMemory(fileName: String, flags: Int, vararg files: Pair): AiScene? { + fun readFilesFromMemory(fileName: String, vararg files: Pair, flags: Int = 0): AiScene? { return readFilesFromMemory(fileName, files.toMap(), flags) } diff --git a/src/test/kotlin/assimp/md3/europeanFnt.kt b/src/test/kotlin/assimp/md3/europeanFnt.kt index e55a1c1..0de0fbd 100644 --- a/src/test/kotlin/assimp/md3/europeanFnt.kt +++ b/src/test/kotlin/assimp/md3/europeanFnt.kt @@ -3,217 +3,233 @@ package assimp.md3 import assimp.* import glm_.mat4x4.Mat4 import glm_.vec3.Vec3 -import io.kotlintest.shouldBe +import io.kotlintest.* +import java.io.* +import java.nio.* +import java.nio.file.* object europeanFnt { - operator fun invoke(fileName: String) { + operator fun invoke(fileName: String, shaderName: String) { - Importer().testFile(getResource(fileName)) { + Importer().readFile(getResource(fileName))?.verify() ?: fail("could not load $fileName") - flags shouldBe 0 + fun String.loadFile(): ByteBuffer { + val file = Paths.get(getResource(this).toURI()).toAbsolutePath().toFile() + return ByteBuffer.wrap(FileInputStream(file).readBytes()) + } - with(rootNode) { - name shouldBe "" - transformation shouldBe Mat4( - 1f, 0f, 0f, 0f, - 0f, 0f, -1f, 0f, - 0f, 1f, 0f, 0f, - 0f, 0f, 0f, 1f) - parent shouldBe null - numChildren shouldBe 0 - children.isEmpty() shouldBe true + val baseFileBuffer = fileName.loadFile() + val shaderBuffer = shaderName.loadFile() - numMeshes shouldBe 5 - meshes[0] shouldBe 0 - } + Importer().readFilesFromMemory(fileName,fileName to baseFileBuffer, shaderName to shaderBuffer) + ?.verify() ?: fail("could not load $fileName from memory") + } - with(meshes[0]) { + private fun AiScene.verify() { - primitiveTypes shouldBe 4 - numVertices shouldBe 336 - numFaces shouldBe 112 + flags shouldBe 0 - vertices[0] shouldBe Vec3(84.7812500f, 39.1875000f, 27.0468750f) - vertices[167] shouldBe Vec3(-63.3906250f, -40.9218750f, 13.2656250f) - vertices[335] shouldBe Vec3(-66.7500000f, 38.8437500f, 15.7343750f) + with(rootNode) { + name shouldBe "" + transformation shouldBe Mat4( + 1f, 0f, 0f, 0f, + 0f, 0f, -1f, 0f, + 0f, 1f, 0f, 0f, + 0f, 0f, 0f, 1f) + parent shouldBe null + numChildren shouldBe 0 + children.isEmpty() shouldBe true + + numMeshes shouldBe 5 + meshes[0] shouldBe 0 + } + + with(meshes[0]) { - normals[0] shouldBe Vec3(0.5348365f, -0.013129499f, -0.8448536f) - normals[167] shouldBe Vec3(-1.6606013E-16f, -0.9039893f, -0.42755508f) - normals[335] shouldBe Vec3(-0.9423873f, 0.31132272f, -0.12241068f) + primitiveTypes shouldBe 4 + numVertices shouldBe 336 + numFaces shouldBe 112 - textureCoords[0][0][0] shouldBe 0.0498498604f - textureCoords[0][0][1] shouldBe 0.616048455f - textureCoords[0][167][0] shouldBe 0.0527787320f - textureCoords[0][167][1] shouldBe 0.612726867f - textureCoords[0][335][0] shouldBe 0.0801433548f - textureCoords[0][335][1] shouldBe 0.583810389f + vertices[0] shouldBe Vec3(84.7812500f, 39.1875000f, 27.0468750f) + vertices[167] shouldBe Vec3(-63.3906250f, -40.9218750f, 13.2656250f) + vertices[335] shouldBe Vec3(-66.7500000f, 38.8437500f, 15.7343750f) - for (i in 0..111 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 1, i + 2) + normals[0] shouldBe Vec3(0.5348365f, -0.013129499f, -0.8448536f) + normals[167] shouldBe Vec3(-1.6606013E-16f, -0.9039893f, -0.42755508f) + normals[335] shouldBe Vec3(-0.9423873f, 0.31132272f, -0.12241068f) - name.isEmpty() shouldBe true - } - with(meshes[1]) { + textureCoords[0][0][0] shouldBe 0.0498498604f + textureCoords[0][0][1] shouldBe 0.616048455f + textureCoords[0][167][0] shouldBe 0.0527787320f + textureCoords[0][167][1] shouldBe 0.612726867f + textureCoords[0][335][0] shouldBe 0.0801433548f + textureCoords[0][335][1] shouldBe 0.583810389f + + for (i in 0..111 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 1, i + 2) - primitiveTypes shouldBe 4 - numVertices shouldBe 528 - numFaces shouldBe 176 - - vertices[0] shouldBe Vec3(76.5937500f, 21.5312500f, 16.8750000f) - vertices[263] shouldBe Vec3(-39.5312500f, -38.6250000f, 34.0468750f) - vertices[527] shouldBe Vec3(50.3281250f, -37.1718750f, 16.9843750f) - - normals[0] shouldBe Vec3(0.5348365f, -0.8445991f, 0.024541229f) - normals[263] shouldBe Vec3(0.18502302f, -0.30869228f, 0.9329928f) - normals[527] shouldBe Vec3(-0.5139479f, -0.8574703f, 0.024541229f) - - textureCoords[0][0][0] shouldBe 0.0963503048f - textureCoords[0][0][1] shouldBe 0.951211274f - textureCoords[0][263][0] shouldBe 0.948739946f - textureCoords[0][263][1] shouldBe 0.898761094f - textureCoords[0][527][0] shouldBe 0.948739946f - textureCoords[0][527][1] shouldBe 0.755133688f - - for (i in 0..175 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 2, i + 1) - - name.isEmpty() shouldBe true - } - with(meshes[2]) { - - primitiveTypes shouldBe 4 - numVertices shouldBe 1050 - numFaces shouldBe 350 - - vertices[0] shouldBe Vec3(65.5312500f, 12.1093750f, 54.4531250f) - vertices[524] shouldBe Vec3(87.4843750f, -36.6250000f, 40.0625000f) - vertices[1049] shouldBe Vec3(-79.0781250f, -33.5781250f, 29.2343750f) - - normals[0] shouldBe Vec3(-0.31792322f, 0.31792322f, 0.8932243f) - normals[524] shouldBe Vec3(0.89080405f, -0.44839308f, 0.07356457f) - normals[1049] shouldBe Vec3(-0.794514f, -0.58925176f, 0.14673047f) - - textureCoords[0][0][0] shouldBe 0.387118787f - textureCoords[0][0][1] shouldBe 0.285972953f - textureCoords[0][524][0] shouldBe 0.908088386f - textureCoords[0][524][1] shouldBe 0.706875503f - textureCoords[0][1049][0] shouldBe 0.923744082f - textureCoords[0][1049][1] shouldBe 0.848480046f - - for (i in 0..349 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 2, i + 1) - - name.isEmpty() shouldBe true - } - with(meshes[3]) { - - primitiveTypes shouldBe 4 - numVertices shouldBe 114 - numFaces shouldBe 38 - - vertices[0] shouldBe Vec3(29.1406250f, 12.8437500f, 43.5156250f) - vertices[56] shouldBe Vec3(33.1093750f, 12.8125000f, 50.9531250f) - vertices[113] shouldBe Vec3(29.1406250f, 12.8437500f, 43.5156250f) - - normals[0] shouldBe Vec3(-0.9984946f, -0.024511667f, 0.049067676f) - normals[56] shouldBe Vec3(-0.47125477f, 0.011568655f, -0.8819213f) - normals[113] shouldBe Vec3(-0.9984946f, -0.024511667f, 0.049067676f) - - textureCoords[0][0][0] shouldBe 0.125758305f - textureCoords[0][0][1] shouldBe 0.741084099f - textureCoords[0][56][0] shouldBe 0.250173688f - textureCoords[0][56][1] shouldBe 0.923741937f - textureCoords[0][113][0] shouldBe 0.0367676802f - textureCoords[0][113][1] shouldBe 0.726932108f - - for (i in 0..37 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 1, i + 2) - - name.isEmpty() shouldBe true - } - with(meshes[4]) { - - primitiveTypes shouldBe 4 - numVertices shouldBe 6 - numFaces shouldBe 2 - - vertices[0] shouldBe Vec3(45.9218750f, 23.6718750f, 53.6406250f) - vertices[2] shouldBe Vec3(36.2812500f, 23.6718750f, 73.0781250f) - vertices[5] shouldBe Vec3(45.9375000f, -23.5156250f, 53.5312500f) - - normals[0] shouldBe Vec3(0.8932243f, 0.0f, 0.44961134f) - normals[2] shouldBe Vec3(0.8932243f, 0.0f, 0.44961134f) - normals[5] shouldBe Vec3(0.8932243f, 0.0f, 0.44961134f) - - textureCoords[0][0][0] shouldBe 0.999992669f - textureCoords[0][0][1] shouldBe 0.00579905510f - textureCoords[0][2][0] shouldBe 1.00000000f - textureCoords[0][2][1] shouldBe 0.999242306f - textureCoords[0][5][0] shouldBe 0f - textureCoords[0][5][1] shouldBe 0f - - for (i in 0..1 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 2, i + 1) - - name.isEmpty() shouldBe true - } - numMaterials shouldBe 5 - - with(materials[0]) { - shadingModel shouldBe AiShadingMode.gouraud - with(color!!) { - ambient shouldBe Vec3(0.0500000007) - diffuse shouldBe Vec3(1f) - specular shouldBe Vec3(1f) - } - name shouldBe "MD3_[default][windscreen]" - textures[0].file shouldBe "textures/sfx/glass.tga.tga" - textures[0].flags shouldBe AiTexture.Flags.ignoreAlpha.i - } - with(materials[1]) { - shadingModel shouldBe AiShadingMode.gouraud - with(color!!) { - ambient shouldBe Vec3(0.0500000007) - diffuse shouldBe Vec3(1f) - specular shouldBe Vec3(1f) - } - name shouldBe "MD3_[default][steering]" - twoSided shouldBe true - blendFunc shouldBe AiBlendMode.default - textures[0].file shouldBe "euro_frnt_2.tga" - textures[0].flags shouldBe AiTexture.Flags.useAlpha.i - } - with(materials[2]) { - shadingModel shouldBe AiShadingMode.gouraud - with(color!!) { - ambient shouldBe Vec3(0.0500000007) - diffuse shouldBe Vec3(1f) - specular shouldBe Vec3(1f) - } - name shouldBe "MD3_[default][body]" - textures[0].file shouldBe "european_fnt.tga" - textures[0].flags shouldBe AiTexture.Flags.ignoreAlpha.i - } - with(materials[3]) { - shadingModel shouldBe AiShadingMode.gouraud - with(color!!) { - ambient shouldBe Vec3(0.0500000007) - diffuse shouldBe Vec3(1f) - specular shouldBe Vec3(1f) - } - name shouldBe "MD3_[default][wheels]" - textures[0].file shouldBe "european_fnt.tga" - textures[0].flags shouldBe AiTexture.Flags.ignoreAlpha.i - } - with(materials[4]) { - shadingModel shouldBe AiShadingMode.gouraud - with(color!!) { - ambient shouldBe Vec3(0.0500000007) - diffuse shouldBe Vec3(1f) - specular shouldBe Vec3(1f) - } - name shouldBe "MD3_[default][wheel_arches]" - twoSided shouldBe true - blendFunc shouldBe AiBlendMode.default - textures[0].file shouldBe "euro_frnt_2.tga" - textures[0].flags shouldBe AiTexture.Flags.useAlpha.i - } - } - } + name.isEmpty() shouldBe true + } + with(meshes[1]) { + + primitiveTypes shouldBe 4 + numVertices shouldBe 528 + numFaces shouldBe 176 + + vertices[0] shouldBe Vec3(76.5937500f, 21.5312500f, 16.8750000f) + vertices[263] shouldBe Vec3(-39.5312500f, -38.6250000f, 34.0468750f) + vertices[527] shouldBe Vec3(50.3281250f, -37.1718750f, 16.9843750f) + + normals[0] shouldBe Vec3(0.5348365f, -0.8445991f, 0.024541229f) + normals[263] shouldBe Vec3(0.18502302f, -0.30869228f, 0.9329928f) + normals[527] shouldBe Vec3(-0.5139479f, -0.8574703f, 0.024541229f) + + textureCoords[0][0][0] shouldBe 0.0963503048f + textureCoords[0][0][1] shouldBe 0.951211274f + textureCoords[0][263][0] shouldBe 0.948739946f + textureCoords[0][263][1] shouldBe 0.898761094f + textureCoords[0][527][0] shouldBe 0.948739946f + textureCoords[0][527][1] shouldBe 0.755133688f + + for (i in 0..175 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 2, i + 1) + + name.isEmpty() shouldBe true + } + with(meshes[2]) { + + primitiveTypes shouldBe 4 + numVertices shouldBe 1050 + numFaces shouldBe 350 + + vertices[0] shouldBe Vec3(65.5312500f, 12.1093750f, 54.4531250f) + vertices[524] shouldBe Vec3(87.4843750f, -36.6250000f, 40.0625000f) + vertices[1049] shouldBe Vec3(-79.0781250f, -33.5781250f, 29.2343750f) + + normals[0] shouldBe Vec3(-0.31792322f, 0.31792322f, 0.8932243f) + normals[524] shouldBe Vec3(0.89080405f, -0.44839308f, 0.07356457f) + normals[1049] shouldBe Vec3(-0.794514f, -0.58925176f, 0.14673047f) + + textureCoords[0][0][0] shouldBe 0.387118787f + textureCoords[0][0][1] shouldBe 0.285972953f + textureCoords[0][524][0] shouldBe 0.908088386f + textureCoords[0][524][1] shouldBe 0.706875503f + textureCoords[0][1049][0] shouldBe 0.923744082f + textureCoords[0][1049][1] shouldBe 0.848480046f + + for (i in 0..349 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 2, i + 1) + + name.isEmpty() shouldBe true + } + with(meshes[3]) { + + primitiveTypes shouldBe 4 + numVertices shouldBe 114 + numFaces shouldBe 38 + + vertices[0] shouldBe Vec3(29.1406250f, 12.8437500f, 43.5156250f) + vertices[56] shouldBe Vec3(33.1093750f, 12.8125000f, 50.9531250f) + vertices[113] shouldBe Vec3(29.1406250f, 12.8437500f, 43.5156250f) + + normals[0] shouldBe Vec3(-0.9984946f, -0.024511667f, 0.049067676f) + normals[56] shouldBe Vec3(-0.47125477f, 0.011568655f, -0.8819213f) + normals[113] shouldBe Vec3(-0.9984946f, -0.024511667f, 0.049067676f) + + textureCoords[0][0][0] shouldBe 0.125758305f + textureCoords[0][0][1] shouldBe 0.741084099f + textureCoords[0][56][0] shouldBe 0.250173688f + textureCoords[0][56][1] shouldBe 0.923741937f + textureCoords[0][113][0] shouldBe 0.0367676802f + textureCoords[0][113][1] shouldBe 0.726932108f + + for (i in 0..37 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 1, i + 2) + + name.isEmpty() shouldBe true + } + with(meshes[4]) { + + primitiveTypes shouldBe 4 + numVertices shouldBe 6 + numFaces shouldBe 2 + + vertices[0] shouldBe Vec3(45.9218750f, 23.6718750f, 53.6406250f) + vertices[2] shouldBe Vec3(36.2812500f, 23.6718750f, 73.0781250f) + vertices[5] shouldBe Vec3(45.9375000f, -23.5156250f, 53.5312500f) + + normals[0] shouldBe Vec3(0.8932243f, 0.0f, 0.44961134f) + normals[2] shouldBe Vec3(0.8932243f, 0.0f, 0.44961134f) + normals[5] shouldBe Vec3(0.8932243f, 0.0f, 0.44961134f) + + textureCoords[0][0][0] shouldBe 0.999992669f + textureCoords[0][0][1] shouldBe 0.00579905510f + textureCoords[0][2][0] shouldBe 1.00000000f + textureCoords[0][2][1] shouldBe 0.999242306f + textureCoords[0][5][0] shouldBe 0f + textureCoords[0][5][1] shouldBe 0f + + for (i in 0..1 * 3 step 3) faces[i / 3] shouldBe mutableListOf(i, i + 2, i + 1) + + name.isEmpty() shouldBe true + } + numMaterials shouldBe 5 + + with(materials[0]) { + shadingModel shouldBe AiShadingMode.gouraud + with(color!!) { + ambient shouldBe Vec3(0.0500000007) + diffuse shouldBe Vec3(1f) + specular shouldBe Vec3(1f) + } + name shouldBe "MD3_[default][windscreen]" + textures[0].file shouldBe "textures/sfx/glass.tga.tga" + textures[0].flags shouldBe AiTexture.Flags.ignoreAlpha.i + } + with(materials[1]) { + shadingModel shouldBe AiShadingMode.gouraud + with(color!!) { + ambient shouldBe Vec3(0.0500000007) + diffuse shouldBe Vec3(1f) + specular shouldBe Vec3(1f) + } + name shouldBe "MD3_[default][steering]" + twoSided shouldBe true + blendFunc shouldBe AiBlendMode.default + textures[0].file shouldBe "euro_frnt_2.tga" + textures[0].flags shouldBe AiTexture.Flags.useAlpha.i + } + with(materials[2]) { + shadingModel shouldBe AiShadingMode.gouraud + with(color!!) { + ambient shouldBe Vec3(0.0500000007) + diffuse shouldBe Vec3(1f) + specular shouldBe Vec3(1f) + } + name shouldBe "MD3_[default][body]" + textures[0].file shouldBe "european_fnt.tga" + textures[0].flags shouldBe AiTexture.Flags.ignoreAlpha.i + } + with(materials[3]) { + shadingModel shouldBe AiShadingMode.gouraud + with(color!!) { + ambient shouldBe Vec3(0.0500000007) + diffuse shouldBe Vec3(1f) + specular shouldBe Vec3(1f) + } + name shouldBe "MD3_[default][wheels]" + textures[0].file shouldBe "european_fnt.tga" + textures[0].flags shouldBe AiTexture.Flags.ignoreAlpha.i + } + with(materials[4]) { + shadingModel shouldBe AiShadingMode.gouraud + with(color!!) { + ambient shouldBe Vec3(0.0500000007) + diffuse shouldBe Vec3(1f) + specular shouldBe Vec3(1f) + } + name shouldBe "MD3_[default][wheel_arches]" + twoSided shouldBe true + blendFunc shouldBe AiBlendMode.default + textures[0].file shouldBe "euro_frnt_2.tga" + textures[0].flags shouldBe AiTexture.Flags.useAlpha.i + } + } } \ No newline at end of file diff --git a/src/test/kotlin/assimp/md3/md3.kt b/src/test/kotlin/assimp/md3/md3.kt index 754f285..f90a11b 100644 --- a/src/test/kotlin/assimp/md3/md3.kt +++ b/src/test/kotlin/assimp/md3/md3.kt @@ -14,6 +14,7 @@ class md3 : StringSpec() { init { // "watercan" { watercan(path + "watercan.md3") } - "european font" { europeanFnt(path + "q3root/models/mapobjects/kt_kubalwagon/european_fnt_v2.md3") } + "european font" { europeanFnt(path + "q3root/models/mapobjects/kt_kubalwagon/european_fnt_v2.md3", + path + "q3root/models/mapobjects/kt_kubalwagon/../../../scripts/kt_kubalwagon.shader") } } } \ No newline at end of file From 04f84f0addb5d832e0c22e622cb0b7de7d6def2f Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 6 Sep 2018 07:34:49 +0200 Subject: [PATCH 18/20] some final cleanups Signed-off-by: Burkhard Mittelbach --- README.md | 28 +--------- .../kotlin/assimp/format/X/XFileImporter.kt | 1 - .../kotlin/assimp/format/md2/Md2Loader.kt | 1 - .../assimp/format/obj/ObjFileImporter.kt | 52 +++++-------------- src/test/kotlin/assimp/md2/faerie.kt | 1 - src/test/kotlin/assimp/md3/europeanFnt.kt | 1 + 6 files changed, 16 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 325bb57..14302a4 100644 --- a/README.md +++ b/README.md @@ -59,30 +59,4 @@ Advantages: Disadvantages: - code needs to be ported from cpp to java - code needs to be maintained -- a little slower compared to cpp when loading big meshes if not using assbin - -### Read from memory status - -TODO remove before final push to kotlin-graphics/master - -#### Format tests: - -Working: - -- Direct X -- collada -- ply -- fbx -- stl -- obj -- assbin -- md2 -- md5 - -Failing: - -- md3 - -Disabled: - -- blender \ No newline at end of file +- a little slower compared to cpp when loading big meshes if not using assbin \ No newline at end of file diff --git a/src/main/kotlin/assimp/format/X/XFileImporter.kt b/src/main/kotlin/assimp/format/X/XFileImporter.kt index 22edc69..8f96148 100644 --- a/src/main/kotlin/assimp/format/X/XFileImporter.kt +++ b/src/main/kotlin/assimp/format/X/XFileImporter.kt @@ -33,7 +33,6 @@ class XFileImporter : BaseImporter() { if (fileSize < 16) throw Error("XFile is too small.") - //val bytes = file_.readBytes() mBuffer = Pointer(Array(bytes.size, { i -> bytes[i].toChar() })) //Assuming every byte is a char. // parse the file into a temporary representation val parser = XFileParser(mBuffer) diff --git a/src/main/kotlin/assimp/format/md2/Md2Loader.kt b/src/main/kotlin/assimp/format/md2/Md2Loader.kt index 6614f94..6ae271b 100644 --- a/src/main/kotlin/assimp/format/md2/Md2Loader.kt +++ b/src/main/kotlin/assimp/format/md2/Md2Loader.kt @@ -165,7 +165,6 @@ class Md2Importer : BaseImporter() { // apply a default material helper.color = AiMaterial.Color(diffuse = AiColor3D(0.6f), specular = AiColor3D(0.6f), ambient = AiColor3D(0.05f)) helper.name = AI_DEFAULT_MATERIAL_NAME - // TODO read from memory, does not yet support multiple files in one read val fileName = file.substringAfterLast('\\').substringBeforeLast('.') helper.textures.add(AiMaterial.Texture(file = "$fileName.bmp", type = AiTexture.Type.diffuse)) } diff --git a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt index 0e81e89..309340c 100644 --- a/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt +++ b/src/main/kotlin/assimp/format/obj/ObjFileImporter.kt @@ -424,52 +424,28 @@ class ObjFileImporter : BaseImporter() { while (!name[i].isLetter()) i++ val cleaned = name.substring(i) // e.g: .\wal67ar_small.jpg -> wal67ar_small.jpg - if(ioSystem is DefaultIOSystem) { + val parentPath = ioSystem.open(file).parentPath + ioSystem.osSeparator - //If the default io system is in place, we can use the java.io.File api and list directories - //to match files even where case is mangled + when { + ioSystem.exists(parentPath + cleaned) -> { - val actualFile = (ioSystem.open(file) as DefaultIOSystem.FileIOStream).file + val texFile = ioSystem.open(parentPath + cleaned) - when { - actualFile.parentFile.listFiles().any { it.name == cleaned } -> { + val typeStart = texFile.filename.lastIndexOf(".") + 1 + val type = texFile.filename.substring(typeStart) - val texFile = actualFile.parentFile.listFiles().first { it.name == cleaned }!! - scene.textures[name] = gli.load(texFile.toPath()) - - } - actualFile.parentFile.listFiles().any { it.name.toUpperCase() == cleaned.toUpperCase() } -> { - // try case insensitive - val texFile = actualFile.parentFile.listFiles().first { it.name.toUpperCase() == cleaned.toUpperCase() }!! - scene.textures[name] = gli.load(texFile.toPath()) - - } - else -> logger.warn { "OBJ/MTL: Texture image not found --> $cleaned" } + scene.textures[name] = loadImageFromMemory(texFile, type) } - } else { - val parentPath = ioSystem.open(file).parentPath + ioSystem.osSeparator - - when { - ioSystem.exists(parentPath + cleaned) -> { + ioSystem.exists(parentPath + cleaned.toUpperCase()) -> { + // try case insensitive + val texFile = ioSystem.open(parentPath + cleaned.toUpperCase()) - val texFile = ioSystem.open(parentPath + cleaned) + val typeStart = texFile.filename.lastIndexOf(".") + 1 + val type = texFile.filename.substring(typeStart).toLowerCase() - val typeStart = texFile.filename.lastIndexOf(".") + 1 - val type = texFile.filename.substring(typeStart) - - scene.textures[name] = loadImageFromMemory(texFile, type) - } - ioSystem.exists(parentPath + cleaned.toUpperCase()) -> { - // try case insensitive - val texFile = ioSystem.open(parentPath + cleaned.toUpperCase()) - - val typeStart = texFile.filename.lastIndexOf(".") + 1 - val type = texFile.filename.substring(typeStart).toLowerCase() - - scene.textures[name] = loadImageFromMemory(texFile, type) - } - else -> logger.warn { "OBJ/MTL: Texture image not found --> $cleaned" } + scene.textures[name] = loadImageFromMemory(texFile, type) } + else -> logger.warn { "OBJ/MTL: Texture image not found --> $cleaned" } } } else { diff --git a/src/test/kotlin/assimp/md2/faerie.kt b/src/test/kotlin/assimp/md2/faerie.kt index a2dde63..0b51e11 100644 --- a/src/test/kotlin/assimp/md2/faerie.kt +++ b/src/test/kotlin/assimp/md2/faerie.kt @@ -60,7 +60,6 @@ object faerie { ambient shouldBe Vec3(0.0500000007) } textures[0].type shouldBe AiTexture.Type.diffuse - //textures[0].file shouldBe "faerie.bmp" textures[0].file!! should endWith("faerie.bmp") name shouldBe "DefaultMaterial" } diff --git a/src/test/kotlin/assimp/md3/europeanFnt.kt b/src/test/kotlin/assimp/md3/europeanFnt.kt index 0de0fbd..0c57679 100644 --- a/src/test/kotlin/assimp/md3/europeanFnt.kt +++ b/src/test/kotlin/assimp/md3/europeanFnt.kt @@ -14,6 +14,7 @@ object europeanFnt { Importer().readFile(getResource(fileName))?.verify() ?: fail("could not load $fileName") + // TODO temp workaround for relative paths in load from memory fun String.loadFile(): ByteBuffer { val file = Paths.get(getResource(this).toURI()).toAbsolutePath().toFile() return ByteBuffer.wrap(FileInputStream(file).readBytes()) From 56fe528f61ae25ab519d5e29fa38e15329fc8a67 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 6 Sep 2018 07:49:29 +0200 Subject: [PATCH 19/20] final final cleanup Signed-off-by: Burkhard Mittelbach --- src/test/kotlin/assimp/anchor.kt | 84 ++++++++++++++------------------ 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/src/test/kotlin/assimp/anchor.kt b/src/test/kotlin/assimp/anchor.kt index 7b15d90..d4a601a 100644 --- a/src/test/kotlin/assimp/anchor.kt +++ b/src/test/kotlin/assimp/anchor.kt @@ -50,11 +50,6 @@ fun Importer.testFile(path: URI, return testFile(Paths.get(path).toAbsolutePath().toString(), flags, failOnNull, verify) } - -// TODO temp -var testReadFile = true -var testReadFromMemory = true - /** * calls both [Importer.readFile] and [Importer.readFileFromMemory] and verifies it using [verify]. * This fails if [failOnNull] is set and either of the above returns null. @@ -68,36 +63,33 @@ fun Importer.testFile(path: String, logger.info { "Testing read $path:" } var scene: AiScene? = null - if(testReadFile) { - logger.info { "reading from file:"} - // test readFile - scene = readFile(path, flags) - if (scene == null && failOnNull) { - fail("readFile returned 'null' for $path") - } else { - scene?.verify() - } + + logger.info { "reading from file:"} + + scene = readFile(path, flags) + if (scene == null && failOnNull) { + fail("readFile returned 'null' for $path") + } else { + scene?.verify() } - if(testReadFromMemory) { - logger.info { "reading from memory:" } - // test readFileFromMemory - val bytes = FileInputStream(File(path)).readBytes() - val buffer = ByteBuffer.wrap(bytes) + logger.info { "reading from memory:" } - val hintStart = path.indexOfLast { it == '.' } - val hint = path.substring(hintStart + 1) + val bytes = FileInputStream(File(path)).readBytes() + val buffer = ByteBuffer.wrap(bytes) - val memScene = readFileFromMemory(buffer, flags, hint) - if (memScene == null && failOnNull) { - fail("readFileFromMemory returned 'null' for $path") - } else { - memScene?.verify() - } + val hintStart = path.indexOfLast { it == '.' } + val hint = path.substring(hintStart + 1) - if(scene == null) scene = memScene + val memScene = readFileFromMemory(buffer, flags, hint) + if (memScene == null && failOnNull) { + fail("readFileFromMemory returned 'null' for $path") + } else { + memScene?.verify() } + if(scene == null) scene = memScene + return scene } @@ -193,32 +185,28 @@ fun Importer.testFiles(paths: List, logger.info { "Testing read $baseFile:" } - var scene: AiScene? = null - if(testReadFile){ - logger.info { "reading from file:"} - // test readFile - scene = readFile(baseFile, flags) - if (scene == null && failOnNull) { - fail("readFile returned 'null' for $baseFile") - } else { - scene?.verify() - } + logger.info { "reading from file:"} + // test readFile + var scene = readFile(baseFile, flags) + if (scene == null && failOnNull) { + fail("readFile returned 'null' for $baseFile") + } else { + scene?.verify() } - if(testReadFromMemory) { - logger.info { "reading from memory:" } - val files = paths.map { it to ByteBuffer.wrap(FileInputStream(File(it)).readBytes()) }.toMap() + logger.info { "reading from memory:" } - val memScene = readFilesFromMemory(baseFile, files, flags) - if (memScene == null && failOnNull) { - fail("readFileFromMemory returned 'null' for $baseFile") - } else { - memScene?.verify() - } + val files = paths.map { it to ByteBuffer.wrap(FileInputStream(File(it)).readBytes()) }.toMap() - if(scene == null) scene = memScene + val memScene = readFilesFromMemory(baseFile, files, flags) + if (memScene == null && failOnNull) { + fail("readFileFromMemory returned 'null' for $baseFile") + } else { + memScene?.verify() } + if(scene == null) scene = memScene + return scene } \ No newline at end of file From 31e2f45387945a2a26fbf06298e5b873ddce50d8 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Fri, 7 Sep 2018 07:41:42 +0200 Subject: [PATCH 20/20] fixed osSeperator bug on windows Signed-off-by: Burkhard Mittelbach --- src/main/kotlin/assimp/format/md3/Md3Loader.kt | 5 +++-- src/test/kotlin/assimp/md3/europeanFnt.kt | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/assimp/format/md3/Md3Loader.kt b/src/main/kotlin/assimp/format/md3/Md3Loader.kt index 0252b21..321cf64 100644 --- a/src/main/kotlin/assimp/format/md3/Md3Loader.kt +++ b/src/main/kotlin/assimp/format/md3/Md3Loader.kt @@ -754,8 +754,9 @@ class Md3Importer : BaseImporter() { // If no specific dir or file is given, use our default search behaviour if (configShaderFile.isEmpty()) { // TODO read from memory: how do we resolve ../../.. - if (!Q3Shader.loadShader(fill, "$path../../../scripts/$modelFile.shader", ioSystem)) - Q3Shader.loadShader(fill, "$path../../../scripts/$filename.shader", ioSystem) + val relativePath = "../../../scripts/".replace("/", ioSystem.osSeparator) // I hate windoof paths + if (!Q3Shader.loadShader(fill, "$path$relativePath$modelFile.shader", ioSystem)) + Q3Shader.loadShader(fill, "$path$relativePath$filename.shader", ioSystem) } else { TODO() // // If the given string specifies a file, load this file. diff --git a/src/test/kotlin/assimp/md3/europeanFnt.kt b/src/test/kotlin/assimp/md3/europeanFnt.kt index 0c57679..7855142 100644 --- a/src/test/kotlin/assimp/md3/europeanFnt.kt +++ b/src/test/kotlin/assimp/md3/europeanFnt.kt @@ -11,9 +11,13 @@ 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) + logger.info("load from file $fileName") Importer().readFile(getResource(fileName))?.verify() ?: fail("could not load $fileName") + logger.info("load from memory $fileName") // TODO temp workaround for relative paths in load from memory fun String.loadFile(): ByteBuffer { val file = Paths.get(getResource(this).toURI()).toAbsolutePath().toFile()