Create AIScene instance from the file's content

0

I'm writing a Java web service where it is possible to upload a 3D object, operate on it and store it.

What I'm trying to do is creating an AIScene instance using a byte[] as an input parameter which is the file itself (it's content).

I have found no way to do this in the docs, all import methods require a path.

Right now I'm taking a look at both the lwjgl java version of Assimp as well as the C++ version. It doesn't matter which one is used to solve the issue.

Edit: the code I'm trying to get done:

@Override
public String uploadFile(MultipartFile file) {
    AIFileIO fileIo = AIFileIO.create();
    AIFileOpenProcI fileOpenProc = new AIFileOpenProc() {
        public long invoke(long pFileIO, long fileName, long openMode) {
            AIFile aiFile = AIFile.create();
            final ByteBuffer data;

            try {
                data = ByteBuffer.wrap(file.getBytes());
            } catch (IOException e) {
                throw new RuntimeException();
            }

            AIFileReadProcI fileReadProc = new AIFileReadProc() {
                public long invoke(long pFile, long pBuffer, long size, long count) {
                    long max = Math.min(data.remaining(), size * count);
                    memCopy(memAddress(data) + data.position(), pBuffer, max);
                    return max;
                }
            };
            AIFileSeekI fileSeekProc = new AIFileSeek() {
                public int invoke(long pFile, long offset, int origin) {
                    if (origin == Assimp.aiOrigin_CUR) {
                        data.position(data.position() + (int) offset);
                    } else if (origin == Assimp.aiOrigin_SET) {
                        data.position((int) offset);
                    } else if (origin == Assimp.aiOrigin_END) {
                        data.position(data.limit() + (int) offset);
                    }
                    return 0;
                }
            };
            AIFileTellProcI fileTellProc = new AIFileTellProc() {
                public long invoke(long pFile) {
                    return data.limit();
                }
            };
            aiFile.ReadProc(fileReadProc);
            aiFile.SeekProc(fileSeekProc);
            aiFile.FileSizeProc(fileTellProc);
            return aiFile.address();
        }
    };
    AIFileCloseProcI fileCloseProc = new AIFileCloseProc() {
        public void invoke(long pFileIO, long pFile) {
            /* Nothing to do */
        }
    };
    fileIo.set(fileOpenProc, fileCloseProc, NULL);
    AIScene scene = aiImportFileEx(file.getName(),
            aiProcess_JoinIdenticalVertices | aiProcess_Triangulate, fileIo); // ISSUE HERE. file.getName() is not a path, just a name. so is getOriginalName() in my case. 

    try{
        Long id = scene.mMeshes().get(0);
        AIMesh mesh = AIMesh.create(id);
        AIVector3D vertex = mesh.mVertices().get(0);

        return mesh.mName().toString() + ": " + (vertex.x() + " " + vertex.y() + " " + vertex.z());
    }catch(Exception e){
        e.printStackTrace();
    }
    return "fail";
}

When debugging the method I get an access violation in the method that binds to the native:

public static long naiImportFileEx(long pFile, int pFlags, long pFS)

this is the message:

#

A fatal error has been detected by the Java Runtime Environment:

#

EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000007400125d, pid=6400, tid=0x0000000000003058

#

JRE version: Java(TM) SE Runtime Environment (8.0_201-b09) (build 1.8.0_201-b09)

Java VM: Java HotSpot(TM) 64-Bit Server VM (25.201-b09 mixed mode windows-amd64 compressed oops)

Problematic frame:

V [jvm.dll+0x1e125d]

#

Failed to write core dump. Minidumps are not enabled by default on client versions of Windows

#

An error report file with more information is saved as:

C:\Users\ragos\IdeaProjects\objectstore3d\hs_err_pid6400.log

#

If you would like to submit a bug report, please visit:

http://bugreport.java.com/bugreport/crash.jsp

#

spring
lwjgl
assimp
asked on Stack Overflow Mar 24, 2019 by agiro • edited Mar 24, 2019 by agiro

1 Answer

0

It is possible if we use the aiImportFileFromMemory method.

The approach I wanted to follow was copied from a github demo and actually copies the buffer around unnecessarily.

The reason for the access violation was the use of indirect buffers (for more info why that is a problem, check this out).

The solution is not nearly as complicated as the code I initially pasted:

@Override
    public String uploadFile(MultipartFile file) throws IOException {
        ByteBuffer buffer = BufferUtils.createByteBuffer((int) file.getSize());
        buffer.put(file.getBytes());
        buffer.flip();
        AIScene scene = Assimp.aiImportFileFromMemory(buffer,aiProcess_Triangulate, (ByteBuffer) null);
        Long id = scene.mMeshes().get(0);
        AIMesh mesh = AIMesh.create(id);
        AIVector3D vertex = mesh.mVertices().get(0);
        return mesh.mName().dataString() + ": " + (vertex.x() + " " + vertex.y() + " " + vertex.z());
    }

Here I create a direct buffer with the appropriate size, load the data and flip it (this part is a must.) After that let Assimp do its magic so you get pointers to the structure. With the return statement I just check if I got the valid data.

edit

As in the comments it was pointed out, this implementation is limited to a single file upload and assumes it gets everything that is necessary from that one MultipartFile, it won't work well with referenced formats. See docs for more detail.

The demo that was linked in the question's comments which was used in the question as a base has a different use case to my original one.

answered on Stack Overflow Mar 25, 2019 by agiro • edited Mar 25, 2019 by agiro

User contributions licensed under CC BY-SA 3.0