Skip to content

Commit 08a7baa

Browse files
committed
feat(plugin): wip gltf generator
1 parent 7d0ad62 commit 08a7baa

File tree

6 files changed

+234
-4
lines changed

6 files changed

+234
-4
lines changed

Diff for: libs/plugin/generators.json

+14-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
"factory": "./src/generators/add-soba/generator",
1111
"schema": "./src/generators/add-soba/schema.json",
1212
"description": "Add angular-three-soba to your project"
13+
},
14+
"gltf": {
15+
"factory": "./src/generators/gltf/generator",
16+
"schema": "./src/generators/gltf/schema.json",
17+
"description": "gltf generator"
1318
}
1419
},
1520
"schematics": {
@@ -18,10 +23,15 @@
1823
"schema": "./src/generators/init/schema.json",
1924
"description": "Add Angular Three with proper packages and config"
2025
},
21-
"add-soba": {
22-
"factory": "./src/generators/add-soba/compat",
23-
"schema": "./src/generators/add-soba/schema.json",
24-
"description": "Add angular-three-soba to your project"
26+
"add-soba": {
27+
"factory": "./src/generators/add-soba/compat",
28+
"schema": "./src/generators/add-soba/schema.json",
29+
"description": "Add angular-three-soba to your project"
30+
},
31+
"gltf": {
32+
"factory": "./src/generators/gltf/compat",
33+
"schema": "./src/generators/gltf/schema.json",
34+
"description": "gltf generator"
2535
}
2636
}
2737
}

Diff for: libs/plugin/src/generators/gltf/compat.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { convertNxGenerator } from '@nx/devkit';
2+
import gltfGenerator from './generator';
3+
4+
export default convertNxGenerator(gltfGenerator);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { CUSTOM_ELEMENTS_SCHEMA, Component, ChangeDetectionStrategy } from '@angular/core';
2+
import { extend, NgtGroup } from 'angular-three';
3+
import { injectGLTF } from 'angular-three-soba/loaders';
4+
import * as THREE from 'three';
5+
import { GLTF } from 'three-stdlib';
6+
7+
interface <%= className %>GLTFResult extends GLTF {
8+
nodes: {},
9+
materials: {}
10+
}
11+
12+
interface <%= className %>Options extends Partial<NgtGroup> {
13+
/* more options */
14+
}
15+
16+
@Component({
17+
selector: '<%= selector %>',
18+
standalone: true,
19+
template: `
20+
@if (gltf(); as gltf) {
21+
<ngt-group [dispose]="null" [parameters]="options()">
22+
</ngt-group>
23+
}
24+
`,
25+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
26+
changeDetection: ChangeDetectionStrategy.OnPush,
27+
})
28+
export class <%= className %> {
29+
options = input({} as <%= className %>Options);
30+
31+
gltf = injectGLTF(() => '<%= runtimeGltfPath %>') as Signal<<%= className %>GLTFResult | null>;
32+
33+
constructor() {
34+
extend({ Group: THREE.Group });
35+
}
36+
}

Diff for: libs/plugin/src/generators/gltf/generator.spec.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Tree } from '@nx/devkit';
2+
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
3+
4+
describe('gltf generator', () => {
5+
let tree: Tree;
6+
7+
beforeEach(() => {
8+
tree = createTreeWithEmptyWorkspace();
9+
});
10+
11+
it('should run successfully', async () => {
12+
expect(true).toBe(true);
13+
});
14+
15+
// it('should run successfully', async () => {
16+
// await gltfGenerator(tree, options);
17+
// const config = readProjectConfiguration(tree, 'test');
18+
// expect(config).toBeDefined();
19+
// });
20+
});

Diff for: libs/plugin/src/generators/gltf/generator.ts

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { formatFiles, logger, names, readJson, readProjectConfiguration, Tree, workspaceRoot } from '@nx/devkit';
2+
import { prompt } from 'enquirer';
3+
import { addSobaGenerator } from '../add-soba/generator';
4+
5+
export interface GltfGeneratorSchema {
6+
gltfPath: string;
7+
project: string;
8+
console: boolean;
9+
modelName: string;
10+
meshopt: boolean;
11+
outputPath?: string;
12+
draco?: boolean | string;
13+
}
14+
15+
function normalizeOptions(options: GltfGeneratorSchema) {
16+
let { gltfPath, project, console, modelName, outputPath, draco, meshopt } = options;
17+
18+
if (draco == null) {
19+
draco = true;
20+
}
21+
22+
return { gltfPath, project, console, modelName, outputPath, draco, meshopt };
23+
}
24+
25+
function buildSelector(fileName: string, prefix: string) {
26+
return `${prefix}-${fileName}`;
27+
}
28+
29+
export async function gltfGenerator(tree: Tree, options: GltfGeneratorSchema) {
30+
const packageJson = readJson(tree, 'package.json');
31+
const hasAngularThreeSoba =
32+
packageJson['dependencies']['angular-three-soba'] || packageJson['devDependencies']['angular-three-soba'];
33+
34+
if (!hasAngularThreeSoba) {
35+
logger.warn(`[NGT] angular-three-soba must be installed to use the GLTF generator`);
36+
const { initSoba } = await prompt<{ initSoba: boolean }>({
37+
type: 'confirm',
38+
name: 'initSoba',
39+
message: 'Would you like to initialize angular-three-soba?',
40+
initial: true,
41+
});
42+
if (!initSoba) return;
43+
await addSobaGenerator(tree);
44+
}
45+
46+
try {
47+
const injectGLTF = await import('angular-three-soba/loaders').then((m) => m.injectGLTF);
48+
49+
const { gltfPath, project, console: toConsole, modelName, outputPath, draco, meshopt } = normalizeOptions(options);
50+
51+
let runtimeGltfPath: string;
52+
53+
if (!gltfPath.startsWith('http')) {
54+
const { path } = await prompt<{ path: string }>({
55+
type: 'input',
56+
name: 'path',
57+
message: 'What is the path to the asset file to be used at runtime (with injectGLTF)?',
58+
required: true,
59+
});
60+
runtimeGltfPath = path;
61+
} else {
62+
runtimeGltfPath = gltfPath;
63+
}
64+
65+
injectGLTF.preload(() => runtimeGltfPath, {
66+
useDraco: draco,
67+
useMeshOpt: meshopt,
68+
onLoad: (data) => {
69+
console.log('data', data);
70+
},
71+
});
72+
73+
const projectConfig = readProjectConfiguration(tree, project);
74+
const modelNames = names(modelName);
75+
const tmpPath = `${workspaceRoot}/tmp/ngt-gltf/${modelNames.fileName}`;
76+
const output = toConsole ? tmpPath : (outputPath ?? (projectConfig.sourceRoot || `${projectConfig.root}/src`));
77+
78+
// NOTE: even if user passes in "console", we still generate the files.
79+
// But we generate them to a temporary destination then we'll remove them printing to console.
80+
// generateFiles(tree, 'files', output, {
81+
// tmpl: '',
82+
// fileName: modelNames.fileName,
83+
// className: modelNames.className,
84+
// selector: buildSelector(
85+
// modelNames.fileName,
86+
// 'prefix' in projectConfig && typeof projectConfig.prefix === 'string' ? projectConfig.prefix : 'app',
87+
// ),
88+
// runtimeGltfPath,
89+
// });
90+
91+
await formatFiles(tree);
92+
93+
if (toConsole) {
94+
// print to console
95+
// delete the files in tmp
96+
}
97+
} catch (e) {
98+
logger.error(`[NGT] Error generating GLTF files: ${e}`);
99+
}
100+
}
101+
102+
export default gltfGenerator;

Diff for: libs/plugin/src/generators/gltf/schema.json

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"$schema": "https://json-schema.org/schema",
3+
"$id": "Gltf",
4+
"title": "",
5+
"type": "object",
6+
"properties": {
7+
"gltfPath": {
8+
"type": "string",
9+
"description": "",
10+
"$default": {
11+
"$source": "argv",
12+
"index": 0
13+
},
14+
"x-prompt": "Where is your gltf file located?"
15+
},
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+
},
24+
"console": {
25+
"type": "boolean",
26+
"description": "Print to console instead of writing to file",
27+
"default": false
28+
},
29+
"modelName": {
30+
"type": "string",
31+
"description": "Name of the model",
32+
"default": "Model"
33+
},
34+
"outputPath": {
35+
"type": "string",
36+
"description": "The output path of the generated component",
37+
"alias": ["o", "output"]
38+
},
39+
"draco": {
40+
"oneOf": [
41+
{
42+
"type": "boolean",
43+
"description": "Use Draco compression"
44+
},
45+
{
46+
"type": "string",
47+
"description": "Use Draco compression with a specific path"
48+
}
49+
]
50+
},
51+
"meshopt": {
52+
"type": "boolean",
53+
"description": "Use Meshopt compression",
54+
"default": true
55+
}
56+
},
57+
"required": ["gltfPath", "project"]
58+
}

0 commit comments

Comments
 (0)