Skip to content

Commit 5095308

Browse files
committed
fix(soba): another attempt with gltf generator using node-three-gltf
1 parent 466fdbe commit 5095308

File tree

6 files changed

+130
-77
lines changed

6 files changed

+130
-77
lines changed

libs/core/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@
2525
"@angular/common": ">=18.0.0 <19.0.0",
2626
"@angular/core": ">=18.0.0 <19.0.0",
2727
"ngxtension": ">=3.0.0",
28-
"three": ">=0.148.0 <0.168.0"
28+
"three": ">=0.148.0 <0.168.0",
29+
"node-three-gltf": ">=1.0.0 <2.0.0"
2930
},
31+
"peerDependenciesMeta": {
32+
"node-three-gltf": {
33+
"optional": true
34+
}
35+
},
3036
"dependencies": {
3137
"tslib": "^2.3.0",
3238
"@nx/devkit": "^19.0.0",

libs/plugin/src/generators/gltf/generator.ts

Lines changed: 52 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
import { formatFiles, logger, names, readJson, readProjectConfiguration, Tree, workspaceRoot } from '@nx/devkit';
1+
import {
2+
formatFiles,
3+
getProjects,
4+
logger,
5+
names,
6+
readJson,
7+
readProjectConfiguration,
8+
Tree,
9+
workspaceRoot,
10+
} from '@nx/devkit';
211
import { prompt } from 'enquirer';
3-
import { readFileSync } from 'node:fs';
4-
import { DRACOLoader, GLTFLoader, MeshoptDecoder } from 'three-stdlib';
12+
import { join } from 'node:path';
513
import { addSobaGenerator } from '../add-soba/generator';
14+
import { parse } from './utils';
615

716
export interface GltfGeneratorSchema {
817
gltfPath: string;
9-
project: string;
1018
console: boolean;
1119
modelName: string;
1220
meshopt: boolean;
@@ -15,61 +23,19 @@ export interface GltfGeneratorSchema {
1523
}
1624

1725
function normalizeOptions(options: GltfGeneratorSchema) {
18-
let { gltfPath, project, console, modelName, outputPath, draco, meshopt } = options;
26+
let { gltfPath, console, modelName, outputPath, draco, meshopt } = options;
1927

2028
if (draco == null) {
2129
draco = true;
2230
}
2331

24-
return { gltfPath, project, console, modelName, outputPath, draco, meshopt };
32+
return { gltfPath, console, modelName, outputPath, draco, meshopt };
2533
}
2634

2735
function buildSelector(fileName: string, prefix: string) {
2836
return `${prefix}-${fileName}`;
2937
}
3038

31-
function toArrayBuffer(buf: Buffer) {
32-
const ab = new ArrayBuffer(buf.length);
33-
const view = new Uint8Array(ab);
34-
for (let i = 0; i < buf.length; ++i) view[i] = buf[i];
35-
return ab;
36-
}
37-
38-
let dracoLoader: DRACOLoader | null = null;
39-
let decoderPath = 'https://www.gstatic.com/draco/versioned/decoders/1.5.5/';
40-
const loader = new GLTFLoader();
41-
42-
function load(input: string, draco: boolean | string, meshopt: boolean) {
43-
if (draco) {
44-
if (!dracoLoader) {
45-
dracoLoader = new DRACOLoader();
46-
}
47-
48-
dracoLoader.setDecoderPath(typeof draco === 'string' ? draco : decoderPath);
49-
(loader as GLTFLoader).setDRACOLoader(dracoLoader);
50-
}
51-
52-
if (meshopt) {
53-
(loader as GLTFLoader).setMeshoptDecoder(typeof MeshoptDecoder === 'function' ? MeshoptDecoder() : MeshoptDecoder);
54-
}
55-
56-
const data = input.startsWith('http')
57-
? null
58-
: (() => {
59-
const fileContent = readFileSync(input);
60-
return toArrayBuffer(fileContent);
61-
})();
62-
const operationFactory = (onLoad: (data: any) => void, onError: (error: ErrorEvent) => void) => {
63-
return input.startsWith('http')
64-
? loader.load.call(loader, input, onLoad, () => {}, onError)
65-
: loader.parse.call(loader, data, input, onLoad, onError);
66-
};
67-
68-
return new Promise((resolve, reject) => {
69-
operationFactory(resolve, reject);
70-
});
71-
}
72-
7339
export async function gltfGenerator(tree: Tree, options: GltfGeneratorSchema) {
7440
const packageJson = readJson(tree, 'package.json');
7541
const hasAngularThreeSoba =
@@ -87,40 +53,60 @@ export async function gltfGenerator(tree: Tree, options: GltfGeneratorSchema) {
8753
await addSobaGenerator(tree);
8854
}
8955

90-
try {
91-
// const injectGLTF = await loadEsmModule<typeof import('angular-three-soba/loaders')>(
92-
// 'angular-three-soba/loaders',
93-
// ).then((m) => m.injectGLTF);
94-
// // const injectGLTF = await import('angular-three-soba/loaders').then((m) => m.injectGLTF);
95-
// const injectGLTF = require('angular-three-soba/loaders').injectGLTF;
56+
const projects = getProjects(tree);
57+
const applicationProjects = Array.from(projects.entries()).reduce((acc, [projectName, project]) => {
58+
if (project.projectType === 'application') {
59+
acc.push(projectName);
60+
}
61+
return acc;
62+
}, [] as string[]);
63+
64+
let { project } = await prompt<{ project: string }>({
65+
type: 'select',
66+
name: 'project',
67+
message: 'What project would you like to generate the model component for?',
68+
choices: [...applicationProjects, 'custom'],
69+
required: true,
70+
});
71+
72+
if (project === 'custom') {
73+
const { projectName } = await prompt<{ projectName: string }>({
74+
type: 'input',
75+
name: 'projectName',
76+
message: 'What is the name of the project to generate the model component for?',
77+
required: true,
78+
});
79+
project = projectName;
80+
}
9681

97-
const { gltfPath, project, console: toConsole, modelName, outputPath, draco, meshopt } = normalizeOptions(options);
82+
const projectConfig = readProjectConfiguration(tree, project);
83+
84+
if (!projectConfig) {
85+
logger.error(`[NGT] ${project} is not a project`);
86+
return;
87+
}
88+
89+
try {
90+
const { gltfPath, console: toConsole, modelName, outputPath, draco, meshopt } = normalizeOptions(options);
9891

9992
let runtimeGltfPath: string;
10093

10194
if (!gltfPath.startsWith('http')) {
10295
const { path } = await prompt<{ path: string }>({
10396
type: 'input',
10497
name: 'path',
105-
message: 'What is the path to the asset file to be used at runtime (with injectGLTF)?',
98+
message: 'What is the path to the asset file to be used at runtime with injectGLTF?',
10699
required: true,
107100
});
108101
runtimeGltfPath = path;
109102
} else {
110-
runtimeGltfPath = gltfPath;
103+
runtimeGltfPath = join(workspaceRoot, gltfPath);
111104
}
112105

113-
await load(runtimeGltfPath, draco, meshopt);
106+
const data = await parse(runtimeGltfPath, draco, meshopt);
114107

115-
// injectGLTF.preload(() => runtimeGltfPath, {
116-
// useDraco: draco,
117-
// useMeshOpt: meshopt,
118-
// onLoad: (data) => {
119-
// console.log('data', data);
120-
// },
121-
// });
108+
console.log(data);
122109

123-
const projectConfig = readProjectConfiguration(tree, project);
124110
const modelNames = names(modelName);
125111
const tmpPath = `${workspaceRoot}/tmp/ngt-gltf/${modelNames.fileName}`;
126112
const output = toConsole ? tmpPath : (outputPath ?? (projectConfig.sourceRoot || `${projectConfig.root}/src`));

libs/plugin/src/generators/gltf/schema.json

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{
2-
"$schema": "https://json-schema.org/schema",
32
"$id": "Gltf",
43
"title": "",
54
"type": "object",
@@ -13,14 +12,6 @@
1312
},
1413
"x-prompt": "Where is your gltf file located?"
1514
},
16-
"project": {
17-
"type": "string",
18-
"description": "The name of the project to generate the model component for.",
19-
"x-prompt": "What project would you like to generate the model component for?",
20-
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
21-
"x-dropdown": "projects",
22-
"x-priority": "important"
23-
},
2415
"console": {
2516
"type": "boolean",
2617
"description": "Print to console instead of writing to file",
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { DRACOLoader, GLTFLoader } from 'node-three-gltf';
2+
import { readFileSync } from 'node:fs';
3+
import { MeshoptDecoder } from 'three-stdlib';
4+
5+
function toArrayBuffer(buf: Buffer) {
6+
const ab = new ArrayBuffer(buf.length);
7+
const view = new Uint8Array(ab);
8+
for (let i = 0; i < buf.length; ++i) view[i] = buf[i];
9+
return ab;
10+
}
11+
12+
let dracoLoader: DRACOLoader | null = null;
13+
let decoderPath = 'https://www.gstatic.com/draco/versioned/decoders/1.5.5/';
14+
15+
const loader = new GLTFLoader();
16+
17+
export function parse(input: string, draco: boolean | string, meshopt: boolean) {
18+
if (draco) {
19+
if (!dracoLoader) {
20+
dracoLoader = new DRACOLoader();
21+
}
22+
23+
dracoLoader.decoderPath = typeof draco === 'string' ? draco : decoderPath;
24+
(loader as GLTFLoader).setDRACOLoader(dracoLoader);
25+
}
26+
27+
if (meshopt) {
28+
(loader as GLTFLoader).setMeshoptDecoder(typeof MeshoptDecoder === 'function' ? MeshoptDecoder() : MeshoptDecoder);
29+
}
30+
31+
const data = input.startsWith('http')
32+
? null
33+
: (() => {
34+
const fileContent = readFileSync(input);
35+
return toArrayBuffer(fileContent);
36+
})();
37+
38+
const operation = (onLoad: (data: any) => void, onError: (error: ErrorEvent) => void) => {
39+
return input.startsWith('http')
40+
? loader.load.call(loader, input, onLoad, () => {}, onError)
41+
: loader.parse.call(loader, data, input, onLoad, onError);
42+
};
43+
44+
return new Promise((resolve, reject) => {
45+
operation(resolve, reject);
46+
});
47+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
"meshline": "^3.3.1",
140140
"ngxtension": "^4.0.0",
141141
"nice-color-palettes": "^3.0.0",
142+
"node-three-gltf": "^1.8.1",
142143
"prismjs": "^1.29.0",
143144
"react": "^18.3.1",
144145
"react-dom": "^18.3.1",

pnpm-lock.yaml

Lines changed: 23 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)