Skip to content

Commit fdf6c5a

Browse files
committed
Add support to load required files only when they are needed.
1 parent 6bf6b47 commit fdf6c5a

16 files changed

Lines changed: 286 additions & 58 deletions

README.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ assimpjs ().then (function (ajs) {
4646
}
4747

4848
// import model
49-
let result = ajs.ImportModel (fileList);
49+
let result = ajs.ImportFileList (fileList);
5050

5151
// parse the result json
5252
let resultJson = JSON.parse (result);
@@ -77,7 +77,35 @@ assimpjs.then ((ajs) => {
7777
);
7878

7979
// import model
80-
let result = ajs.ImportModel (fileList);
80+
let result = ajs.ImportFileList (fileList);
81+
82+
// parse the result json
83+
let resultJson = JSON.parse (result);
84+
});
85+
```
86+
87+
It's also possible to delay load the required files so they have to be loaded only when the importer needs them. In this case you have to provide only the name and content of the main file, and implement callbacks to provide additional files.
88+
89+
```js
90+
let fs = require ('fs');
91+
const assimpjs = require ('./assimpjs.js')();
92+
93+
assimpjs.then ((ajs) => {
94+
// import model
95+
let result = ajs.ImportFile (
96+
// file name
97+
'cube_with_materials.obj',
98+
// file content as arraybuffer
99+
fs.readFileSync ('testfiles/cube_with_materials.obj'),
100+
// check if file exists by name
101+
function (fileName) {
102+
return fs.existsSync ('testfiles/' + fileName);
103+
},
104+
// get file content as arraybuffer by name
105+
function (fileName) {
106+
return fs.readFileSync ('testfiles/' + fileName);
107+
}
108+
);
81109

82110
// parse the result json
83111
let resultJson = JSON.parse (result);

assimpjs/example/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ int main (int argc, const char* argv[])
3434
fileList.AddFile (file.path, file.content);
3535
}
3636

37-
ImportModel (fileList);
37+
ImportFileList (fileList);
3838
return 0;
3939
}

assimpjs/src/assimpjs.cpp

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <stdio.h>
1111
#include <iostream>
1212

13-
static const aiScene* ImportModelByMainFile (Assimp::Importer& importer, const File* file)
13+
static const aiScene* ImportFileListByMainFile (Assimp::Importer& importer, const File* file)
1414
{
1515
try {
1616
const aiScene* scene = importer.ReadFile (file->path,
@@ -30,24 +30,8 @@ static std::string CreateErrorJson (const std::string& errorCode)
3030
return "{\"error\":\"" + errorCode + "\"}";
3131
}
3232

33-
std::string ImportModel (const FileList& fileList)
33+
static std::string CreateResultJson (const aiScene* scene)
3434
{
35-
if (fileList.FileCount () == 0) {
36-
return CreateErrorJson ("no_file_specified");
37-
}
38-
39-
Assimp::Importer importer;
40-
importer.SetIOHandler (new FileListIOSystemAdapter (fileList));
41-
42-
const aiScene* scene = nullptr;
43-
for (size_t fileIndex = 0; fileIndex < fileList.FileCount (); fileIndex++) {
44-
const File* file = fileList.GetFile (fileIndex);
45-
scene = ImportModelByMainFile (importer, file);
46-
if (scene != nullptr) {
47-
break;
48-
}
49-
}
50-
5135
if (scene == nullptr) {
5236
return CreateErrorJson ("model_import_failed");
5337
}
@@ -68,16 +52,92 @@ std::string ImportModel (const FileList& fileList)
6852
return resultJson;
6953
}
7054

55+
std::string ImportFile (const File& file, const FileLoader& loader)
56+
{
57+
Assimp::Importer importer;
58+
importer.SetIOHandler (new DelayLoadedIOSystemAdapter (file, loader));
59+
const aiScene* scene = ImportFileListByMainFile (importer, &file);
60+
return CreateResultJson (scene);
61+
}
62+
63+
std::string ImportFileList (const FileList& fileList)
64+
{
65+
if (fileList.FileCount () == 0) {
66+
return CreateErrorJson ("no_file_specified");
67+
}
68+
69+
Assimp::Importer importer;
70+
importer.SetIOHandler (new FileListIOSystemAdapter (fileList));
71+
72+
const aiScene* scene = nullptr;
73+
for (size_t fileIndex = 0; fileIndex < fileList.FileCount (); fileIndex++) {
74+
const File* file = fileList.GetFile (fileIndex);
75+
scene = ImportFileListByMainFile (importer, file);
76+
if (scene != nullptr) {
77+
break;
78+
}
79+
}
80+
81+
return CreateResultJson (scene);
82+
}
83+
7184
#ifdef EMSCRIPTEN
7285

86+
std::string ImportFileEmscripten (
87+
const std::string& name,
88+
const emscripten::val& content,
89+
const emscripten::val& existsFunc,
90+
const emscripten::val& loadFunc)
91+
{
92+
class FileLoaderEmscripten : public FileLoader
93+
{
94+
public:
95+
FileLoaderEmscripten (const emscripten::val& existsFunc, const emscripten::val& loadFunc) :
96+
existsFunc (existsFunc),
97+
loadFunc (loadFunc)
98+
{
99+
}
100+
101+
virtual bool Exists (const char* pFile) const override
102+
{
103+
if (existsFunc.isUndefined () || existsFunc.isNull ()) {
104+
return false;
105+
}
106+
std::string fileName = GetFileName (pFile);
107+
emscripten::val exists = existsFunc (fileName);
108+
return exists.as<bool> ();
109+
}
110+
111+
virtual Buffer Load (const char* pFile) const override
112+
{
113+
if (loadFunc.isUndefined () || loadFunc.isNull ()) {
114+
return {};
115+
}
116+
std::string fileName = GetFileName (pFile);
117+
emscripten::val fileBuffer = loadFunc (fileName);
118+
return emscripten::vecFromJSArray<std::uint8_t> (fileBuffer);
119+
}
120+
121+
private:
122+
const emscripten::val& existsFunc;
123+
const emscripten::val& loadFunc;
124+
};
125+
126+
Buffer buffer = emscripten::vecFromJSArray<std::uint8_t> (content);
127+
File file (name, buffer);
128+
FileLoaderEmscripten loader (existsFunc, loadFunc);
129+
return ImportFile (file, loader);
130+
}
131+
73132
EMSCRIPTEN_BINDINGS (assimpjs)
74133
{
75134
emscripten::class_<FileList> ("FileList")
76135
.constructor<> ()
77136
.function ("AddFile", &FileList::AddFileEmscripten)
78137
;
79138

80-
emscripten::function<std::string, const FileList&> ("ImportModel", &ImportModel);
139+
emscripten::function<std::string, const std::string&, const emscripten::val&, const emscripten::val&, const emscripten::val&> ("ImportFile", &ImportFileEmscripten);
140+
emscripten::function<std::string, const FileList&> ("ImportFileList", &ImportFileList);
81141
}
82142

83143
#endif

assimpjs/src/assimpjs.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
#endif
77

88
#include "filelist.hpp"
9+
#include "fileio.hpp"
910

1011
#include <vector>
1112
#include <string>
1213

13-
std::string ImportModel (const FileList& fileList);
14+
std::string ImportFile (const File& file, const FileLoader& loader);
15+
std::string ImportFileList (const FileList& fileList);
1416

1517
#endif

assimpjs/src/fileio.cpp

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,25 @@ static char GetOsSeparator ()
1111
#endif
1212
}
1313

14-
BufferIOStreamAdapter::BufferIOStreamAdapter (const Buffer& buffer) :
14+
FileLoader::FileLoader ()
15+
{
16+
17+
}
18+
19+
FileLoader::~FileLoader ()
20+
{
21+
22+
}
23+
24+
BufferIOStreamAdapter::BufferIOStreamAdapter (const Buffer* buffer) :
1525
buffer (buffer),
1626
position (0)
1727
{
1828
}
1929

2030
BufferIOStreamAdapter::~BufferIOStreamAdapter ()
2131
{
32+
2233
}
2334

2435
size_t BufferIOStreamAdapter::Read (void* pvBuffer, size_t pSize, size_t pCount)
@@ -28,7 +39,7 @@ size_t BufferIOStreamAdapter::Read (void* pvBuffer, size_t pSize, size_t pCount)
2839
if (readableElemCount == 0) {
2940
return 0;
3041
}
31-
memcpy (pvBuffer, &buffer[position], readableElemCount * pSize);
42+
memcpy (pvBuffer, buffer->data () + position, readableElemCount * pSize);
3243
position += readableElemCount * pSize;
3344
return readableElemCount;
3445
}
@@ -48,7 +59,7 @@ aiReturn BufferIOStreamAdapter::Seek (size_t pOffset, aiOrigin pOrigin)
4859
position += pOffset;
4960
break;
5061
case aiOrigin_END:
51-
position = buffer.size () - pOffset;
62+
position = buffer->size () - pOffset;
5263
break;
5364
default:
5465
break;
@@ -63,14 +74,66 @@ size_t BufferIOStreamAdapter::Tell () const
6374

6475
size_t BufferIOStreamAdapter::FileSize () const
6576
{
66-
return buffer.size ();
77+
return buffer->size ();
6778
}
6879

6980
void BufferIOStreamAdapter::Flush ()
7081
{
7182

7283
}
7384

85+
OwnerBufferIOStreamAdapter::OwnerBufferIOStreamAdapter (const Buffer* buffer) :
86+
BufferIOStreamAdapter (buffer)
87+
{
88+
}
89+
90+
OwnerBufferIOStreamAdapter::~OwnerBufferIOStreamAdapter ()
91+
{
92+
delete buffer;
93+
}
94+
95+
DelayLoadedIOSystemAdapter::DelayLoadedIOSystemAdapter (const File& file, const FileLoader& loader) :
96+
file (file),
97+
loader (loader)
98+
{
99+
}
100+
101+
DelayLoadedIOSystemAdapter::~DelayLoadedIOSystemAdapter ()
102+
{
103+
104+
}
105+
106+
bool DelayLoadedIOSystemAdapter::Exists (const char* pFile) const
107+
{
108+
if (GetFileName (file.path) == GetFileName (pFile)) {
109+
return true;
110+
}
111+
return loader.Exists (pFile);
112+
}
113+
114+
Assimp::IOStream* DelayLoadedIOSystemAdapter::Open (const char* pFile, const char* pMode)
115+
{
116+
if (GetFileName (file.path) == GetFileName (pFile)) {
117+
return new BufferIOStreamAdapter (&file.content);
118+
}
119+
if (!loader.Exists (pFile)) {
120+
return nullptr;
121+
}
122+
Buffer buffer = loader.Load (pFile);
123+
Buffer* bufferPtr = new Buffer (buffer);
124+
return new OwnerBufferIOStreamAdapter (bufferPtr);
125+
}
126+
127+
void DelayLoadedIOSystemAdapter::Close (Assimp::IOStream* pFile)
128+
{
129+
delete pFile;
130+
}
131+
132+
char DelayLoadedIOSystemAdapter::getOsSeparator () const
133+
{
134+
return GetOsSeparator ();
135+
}
136+
74137
FileListIOSystemAdapter::FileListIOSystemAdapter (const FileList& fileList) :
75138
fileList (fileList)
76139
{
@@ -92,7 +155,7 @@ Assimp::IOStream* FileListIOSystemAdapter::Open (const char* pFile, const char*
92155
if (foundFile == nullptr) {
93156
return nullptr;
94157
}
95-
return new BufferIOStreamAdapter (foundFile->content);
158+
return new BufferIOStreamAdapter (&foundFile->content);
96159
}
97160

98161
void FileListIOSystemAdapter::Close (Assimp::IOStream* pFile)

assimpjs/src/fileio.hpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,20 @@
66

77
#include "filelist.hpp"
88

9+
class FileLoader
10+
{
11+
public:
12+
FileLoader ();
13+
virtual ~FileLoader ();
14+
15+
virtual bool Exists (const char* pFile) const = 0;
16+
virtual Buffer Load (const char* pFile) const = 0;
17+
};
18+
919
class BufferIOStreamAdapter : public Assimp::IOStream
1020
{
1121
public:
12-
BufferIOStreamAdapter (const Buffer& buffer);
22+
BufferIOStreamAdapter (const Buffer* buffer);
1323
virtual ~BufferIOStreamAdapter ();
1424

1525
virtual size_t Read (void* pvBuffer, size_t pSize, size_t pCount) override;
@@ -21,11 +31,35 @@ class BufferIOStreamAdapter : public Assimp::IOStream
2131
virtual size_t FileSize () const override;
2232
virtual void Flush () override;
2333

24-
private:
25-
const Buffer& buffer;
34+
protected:
35+
const Buffer* buffer;
2636
size_t position;
2737
};
2838

39+
class OwnerBufferIOStreamAdapter : public BufferIOStreamAdapter
40+
{
41+
public:
42+
OwnerBufferIOStreamAdapter (const Buffer* buffer);
43+
virtual ~OwnerBufferIOStreamAdapter ();
44+
};
45+
46+
class DelayLoadedIOSystemAdapter : public Assimp::IOSystem
47+
{
48+
public:
49+
DelayLoadedIOSystemAdapter (const File& file, const FileLoader& loader);
50+
virtual ~DelayLoadedIOSystemAdapter ();
51+
52+
virtual bool Exists (const char* pFile) const override;
53+
virtual Assimp::IOStream* Open (const char* pFile, const char* pMode) override;
54+
virtual void Close (Assimp::IOStream* pFile) override;
55+
56+
virtual char getOsSeparator () const override;
57+
58+
private:
59+
const File& file;
60+
const FileLoader& loader;
61+
};
62+
2963
class FileListIOSystemAdapter : public Assimp::IOSystem
3064
{
3165
public:

0 commit comments

Comments
 (0)