Skip to content

Commit 8e750b1

Browse files
committed
feat(plugin): prep
1 parent a47eaaa commit 8e750b1

File tree

5 files changed

+401
-8
lines changed

5 files changed

+401
-8
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
Auto-generated by: angular-three-plugin:gltf<% if (size) { %>
3+
Size: <%= size %><% } %><% if (header) { %>
4+
<%= header %><% } %><% if (extras) { %>
5+
<%= extras %><% } %>
6+
*/
7+
8+
import type * as THREE from 'three';
9+
import { Group<%= threeImports %> } from 'three';
10+
import { extend, type NgtThreeElements, NgtObjectEvents<% if (args) { %>, NgtArgs<% } %> } from 'angular-three';
11+
import { Component, ChangeDetectionStrategy, CUSTOM_ELEMENTS_SCHEMA, input, viewChild, ElementRef, inject, effect<% if (animations.length) { %>, computed, model<% } %> } from '@angular/core';
12+
import { injectGLTF } from 'angular-three-soba/loaders';
13+
import type { GLTF } from 'three-stdlib';<% if (animations.length) { %>
14+
import { injectAnimations, type NgtsAnimationClips, type NgtsAnimationApi } from 'angular-three-soba/misc';<% } %><% if (perspective) { %>
15+
import { NgtsPerspectiveCamera } from 'angular-three-soba/cameras';<% } %><% if (orthographic) { %>
16+
import { NgtsOrthographicCamera } from 'angular-three-soba/cameras';<% } %>
17+
<% if (useImportAttribute) { %>
18+
// @ts-expect-error - import .glb/.gltf file
19+
import <%= gltfName %> from '.<%= gltfPath %>' with { loader: 'file' };
20+
<% } %>
21+
<% if (preload) { %>
22+
injectGLTF(() => <% if (useImportAttribute) { %><%= gltfName %><% } else { %>'<%= gltfPath %>'<% } %>);
23+
<% } %>
24+
<% if (animations.length) { %>
25+
type ActionName = <% animations.map(clip => "\""+ clip.name + "\"").join(" | ") %>;
26+
type <%= gltfAnimationTypeName %> = NgtsAnimationClips<ActionName>;
27+
export type <%= gltfAnimationApiTypeName %> = Exclude<NgtsAnimationApi<<%= gltfAnimationTypeName %>>, { get isReady(): false }>;
28+
<% } %>
29+
export type <%= gltfResultTypeName %> = GLTF & {
30+
nodes: {
31+
<% meshes.map(({ name, type }) => "\'" + name + "\'" + ": THREE." + type).join(';\n') %>
32+
<% bones.map(({ name, type }) => "\'" + name + "\'" + ": THREE." + type).join(';\n') %>
33+
};
34+
materials: {
35+
<% materials.map(({ name, type }) => "\'" + name + "\'" + ": THREE." + type).join(';\n') %>
36+
};<% if (animations.length) { %>
37+
animations: <%= gltfAnimationTypeName %>[];<% } %>
38+
};
39+
40+
@Component({
41+
selector: '<%= selector %>',
42+
template: `
43+
@if (gltf(); as gltf) {
44+
<ngt-group #model [parameters]="options()" [dispose]="null">
45+
<%= scene %>
46+
47+
<ng-content />
48+
</ngt-group>
49+
}
50+
`,
51+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
52+
changeDetection: ChangeDetectionStrategy.OnPush,
53+
hostDirectives: [
54+
{
55+
directive: NgtObjectEvents,
56+
outputs: ['click', 'dblclick', 'contextmenu', 'pointerup', 'pointerdown', 'pointerover', 'pointerout', 'pointerenter', 'pointerleave', 'pointermove', 'pointermissed', 'pointercancel', 'wheel'],
57+
},
58+
],<% if (angularImports.length) { %>
59+
imports: [<% angularImports.join(', ') %>]<% } %>
60+
})
61+
export class <%= className %> {
62+
protected readonly Math = Math;
63+
64+
options = input({} as Partial<NgtThreeElements['ngt-group']>);<% if (animations.length) { %>
65+
animations = model<<%= gltfAnimationApiTypeName %>>();<% } %>
66+
67+
modelRef = viewChild<ElementRef<Group>>('model');
68+
69+
protected gltf = injectGLTF<<%= gltfResultTypeName %>>(() => ${options.importattribute && !url.startsWith("http") ? gltfName : `"${url}"`}${gltfOptions ? `, ${JSON.stringify(gltfOptions)}` : ""});
70+
71+
constructor() {
72+
extend({ Group${ngtTypesArr.length ? ", " + ngtTypesArr.join(", ") : ""} });
73+
74+
${
75+
hasAnimations
76+
? `
77+
const animations = injectAnimations(this.gltf, this.modelRef);
78+
effect(() => {
79+
if (animations.${useNewAnimationApi ? "isReady" : "ready()"}) {
80+
this.animations.set(animations);
81+
}
82+
}${options.ngVer < 19 ? ", { allowSignalWrites: true }" : ""})
83+
`
84+
: ""
85+
}
86+
87+
const objectEvents = inject(NgtObjectEvents, { host: true });
88+
effect(() => {
89+
const model = this.modelRef()?.nativeElement;
90+
if (!model) return;
91+
92+
objectEvents.ngtObjectEvents.set(model);
93+
}${options.ngVer < 19 ? ", { allowSignalWrites: true }" : ""});
94+
}
95+
}

libs/plugin/src/generators/gltf/files/src/index.ts.template

Lines changed: 0 additions & 1 deletion
This file was deleted.

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

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,55 @@
11
import { Tree } from '@nx/devkit';
2+
import { GenerateNGT } from './utils/generate-ngt';
23

3-
export interface GltfGeneratorSchema {}
4+
export interface GltfGeneratorSchema {
5+
modelPath: string;
6+
output: string;
7+
className: string;
8+
selectorPrefix: string;
9+
draco: boolean;
10+
bones: boolean;
11+
meta: boolean;
12+
shadows: boolean;
13+
precision: number;
14+
console: boolean;
15+
instance: boolean;
16+
instanceAll: boolean;
17+
resolution: number;
18+
keepMeshes: boolean;
19+
keepMaterials: boolean;
20+
keepAttributes: boolean;
21+
format: string;
22+
simplify: boolean;
23+
ratio: number;
24+
error: number;
25+
verbose: boolean;
26+
}
427

528
export async function gltfGenerator(tree: Tree, options: GltfGeneratorSchema) {
6-
const test = await import('@rosskevin/gltfjsx');
7-
console.log(test);
29+
const { loadGLTF, AnalyzedGLTF, gltfTransform, Log, allPruneStrategies } = await import('@rosskevin/gltfjsx');
30+
31+
const gltf = await loadGLTF('');
32+
33+
const analyzed = new AnalyzedGLTF(
34+
gltf,
35+
{
36+
log: new Log({ debug: options.verbose, silent: false }),
37+
bones: options.bones,
38+
meta: options.meta,
39+
shadows: options.shadows,
40+
instance: options.instance,
41+
instanceall: options.instanceAll,
42+
keepgroups: false,
43+
keepnames: true,
44+
precision: options.precision,
45+
},
46+
allPruneStrategies,
47+
);
48+
49+
const generateNGT = new GenerateNGT(analyzed, options);
50+
51+
const test = await generateNGT.print(analyzed.gltf.scene);
52+
853
// await formatFiles(tree);
954
}
1055

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

Lines changed: 127 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,138 @@
33
"title": "Generate component from GLTF",
44
"type": "object",
55
"properties": {
6-
"name": {
6+
"modelPath": {
77
"type": "string",
8-
"description": "",
8+
"description": "GLTF model path",
9+
"alias": "path",
910
"$default": {
1011
"$source": "argv",
1112
"index": 0
1213
},
13-
"x-prompt": "What name would you like to use?"
14+
"x-prompt": "Path to GLTF model from workspace root?"
15+
},
16+
"output": {
17+
"type": "string",
18+
"description": "Output path",
19+
"alias": "o",
20+
"x-prompt": "Where to output the component?"
21+
},
22+
"className": {
23+
"type": "string",
24+
"description": "Name to use for the generated component class",
25+
"alias": "C",
26+
"default": "Model",
27+
"x-prompt": "Enter the name of the component class to generate (default: Model)"
28+
},
29+
"selectorPrefix": {
30+
"type": "string",
31+
"description": "Prefix to use for the generated component selector",
32+
"alias": "pre",
33+
"default": "app",
34+
"x-prompt": "Enter the prefix to use for the generated component selector (default: app)"
35+
},
36+
"draco": {
37+
"type": "boolean",
38+
"description": "Use DracoLoader",
39+
"alias": "d",
40+
"default": false
41+
},
42+
"bones": {
43+
"type": "boolean",
44+
"description": "Layout Bones declaratively",
45+
"alias": "b",
46+
"default": false
47+
},
48+
"meta": {
49+
"type": "boolean",
50+
"decsription": "Include metadata (as userData)",
51+
"alias": "m",
52+
"default": false
53+
},
54+
"shadows": {
55+
"type": "boolean",
56+
"description": "Let mesh cast and receive shadows",
57+
"alias": "s",
58+
"default": false
59+
},
60+
"precision": {
61+
"type": "number",
62+
"description": "Number of fractional digits (default: 3)",
63+
"alias": "p",
64+
"default": 3
65+
},
66+
"console": {
67+
"type": "boolean",
68+
"description": "Prints to console",
69+
"alias": "c",
70+
"default": false
71+
},
72+
"instance": {
73+
"type": "boolean",
74+
"description": "Instance re-occuring geometry",
75+
"alias": "i",
76+
"default": false
77+
},
78+
"instanceAll": {
79+
"type": "boolean",
80+
"description": "Instance every geometry (for cheaper re-use)",
81+
"alias": "I",
82+
"default": false
83+
},
84+
"resolution": {
85+
"type": "number",
86+
"description": "Resolution for texture resizing (default: 1024)",
87+
"alias": "R",
88+
"default": 1024
89+
},
90+
"keepMeshes": {
91+
"type": "boolean",
92+
"description": "Do not join compatible meshes",
93+
"alias": "j",
94+
"default": false
95+
},
96+
"keepMaterials": {
97+
"type": "boolean",
98+
"description": "Do not palette join materials",
99+
"alias": "M",
100+
"default": false
101+
},
102+
"keepAttributes": {
103+
"type": "boolean",
104+
"description": "Whether to keep unused vertex attributes, such as UVs without an assigned texture",
105+
"alias": "a",
106+
"default": false
107+
},
108+
"format": {
109+
"type": "string",
110+
"description": "Texture format jpeg | png | webp | avif (default: \"webp\")",
111+
"alias": "f",
112+
"default": "webp"
113+
},
114+
"simplify": {
115+
"type": "boolean",
116+
"description": "Mesh simplification (default: false)",
117+
"alias": "S",
118+
"default": false
119+
},
120+
"ratio": {
121+
"type": "number",
122+
"description": "Simplifier ratio (default: 0)",
123+
"alias": "r",
124+
"default": 0
125+
},
126+
"error": {
127+
"type": "number",
128+
"description": "Simplifier error threshold (default: 0.0001)",
129+
"alias": "e",
130+
"default": 0.0001
131+
},
132+
"verbose": {
133+
"type": "boolean",
134+
"description": "Verbose log",
135+
"alias": "debug",
136+
"default": false
14137
}
15138
},
16-
"required": ["name"]
139+
"required": ["modelPath", "output"]
17140
}

0 commit comments

Comments
 (0)