@gjsify/example-dom-three-loader-ldraw 0.1.7 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/dist/browser.js +8558 -33688
- package/dist/gjs.js +3967 -47953
- package/dist/gjs.node.mjs +4381 -0
- package/dist/index.html +1 -0
- package/dist/webgl.css +7 -32
- package/package.json +51 -21
- package/src/assets/models/ldraw/officialLibrary/CAlicense.txt +248 -0
- package/src/assets/models/ldraw/officialLibrary/CAreadme.txt +81 -0
- package/src/assets/models/ldraw/officialLibrary/Readme.txt +125 -0
- package/src/assets/models/ldraw/officialLibrary/models/10174-1-ImperialAT-ST-UCS.mpd_Packed.mpd +32672 -0
- package/src/assets/models/ldraw/officialLibrary/models/1621-1-LunarMPVVehicle.mpd_Packed.mpd +12465 -0
- package/src/assets/models/ldraw/officialLibrary/models/30023-1-Lighthouse.ldr_Packed.mpd +4364 -0
- package/src/assets/models/ldraw/officialLibrary/models/30051-1-X-wingFighter-Mini.mpd_Packed.mpd +4500 -0
- package/src/assets/models/ldraw/officialLibrary/models/30054-1-AT-ST-Mini.mpd_Packed.mpd +6449 -0
- package/src/assets/models/ldraw/officialLibrary/models/4489-1-AT-AT-Mini.mpd_Packed.mpd +7242 -0
- package/src/assets/models/ldraw/officialLibrary/models/4494-1-Imperial Shuttle-Mini.mpd_Packed.mpd +5530 -0
- package/src/assets/models/ldraw/officialLibrary/models/4838-1-MiniVehicles.mpd_Packed.mpd +4880 -0
- package/src/assets/models/ldraw/officialLibrary/models/4915-1-MiniConstruction.mpd_Packed.mpd +6481 -0
- package/src/assets/models/ldraw/officialLibrary/models/4918-1-MiniFlyers.mpd_Packed.mpd +5518 -0
- package/src/assets/models/ldraw/officialLibrary/models/5935-1-IslandHopper.mpd_Packed.mpd +17313 -0
- package/src/assets/models/ldraw/officialLibrary/models/6965-1-TIEIntercep_4h4MXk5.mpd_Packed.mpd +2839 -0
- package/src/assets/models/ldraw/officialLibrary/models/6966-1-JediStarfighter-Mini.mpd_Packed.mpd +4087 -0
- package/src/assets/models/ldraw/officialLibrary/models/7140-1-X-wingFighter.mpd_Packed.mpd +28548 -0
- package/src/assets/models/ldraw/officialLibrary/models/889-1-RadarTruck.mpd_Packed.mpd +8429 -0
- package/src/assets/models/ldraw/officialLibrary/models/car.ldr_Packed.mpd +5969 -0
- package/src/browser/browser-main.ts +4 -0
- package/src/browser/browser.ts +199 -0
- package/src/browser/index.html +11 -0
- package/src/browser/webgl.css +28 -0
- package/src/gjs/gjs.ts +31 -0
- package/src/gjs/ldraw-window.blp +87 -0
- package/src/gjs/ldraw-window.ts +132 -0
- package/src/models.ts +28 -0
- package/src/three-demo.ts +242 -0
- package/dist/adwaita-sans-400-VCQV646T.ttf +0 -0
- package/dist/browser.css +0 -10
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// Browser UI for three-loader-ldraw example.
|
|
2
|
+
// Mirrors the GJS/Adwaita UI using @gjsify/adwaita-web.
|
|
3
|
+
// Ported from refs/three/examples/webgl_loader_ldraw.html
|
|
4
|
+
// Original: MIT license, three.js authors (https://threejs.org)
|
|
5
|
+
// This software uses the LDraw Parts Library (http://www.ldraw.org), CC BY 2.0.
|
|
6
|
+
|
|
7
|
+
import '@gjsify/adwaita-web';
|
|
8
|
+
import '@gjsify/adwaita-web/style.css';
|
|
9
|
+
import type { AdwOverlaySplitView } from '@gjsify/adwaita-web';
|
|
10
|
+
import { start, MODEL_LIST, DEFAULT_MODEL_INDEX, type LDrawDemo } from '../three-demo.js';
|
|
11
|
+
|
|
12
|
+
export interface MountOptions {
|
|
13
|
+
assetBase?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* What the website's `<ShowcaseEmbed>` holds on to: it pauses a demo that
|
|
18
|
+
* scrolls out of view, so an always-animating scene does not keep a GPU busy
|
|
19
|
+
* off-screen.
|
|
20
|
+
*/
|
|
21
|
+
export interface ShowcaseHandle {
|
|
22
|
+
pause(): void;
|
|
23
|
+
resume(): void;
|
|
24
|
+
readonly isPaused: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function mount(container: HTMLElement, options?: MountOptions): ShowcaseHandle {
|
|
28
|
+
const { assetBase } = options ?? {};
|
|
29
|
+
|
|
30
|
+
const win = document.createElement('adw-window');
|
|
31
|
+
win.setAttribute('width', '1100');
|
|
32
|
+
win.setAttribute('height', '700');
|
|
33
|
+
|
|
34
|
+
const headerBar = document.createElement('adw-header-bar');
|
|
35
|
+
headerBar.setAttribute('title', 'LDraw Loader');
|
|
36
|
+
|
|
37
|
+
// A showcase has two hosts — the standalone page and the website embed — and only the former
|
|
38
|
+
// loads `browser/webgl.css`, so the layout has to live here rather than in that stylesheet.
|
|
39
|
+
const splitView = document.createElement('adw-overlay-split-view') as AdwOverlaySplitView;
|
|
40
|
+
splitView.setAttribute('min-sidebar-width', '280');
|
|
41
|
+
splitView.setAttribute('max-sidebar-width', '400');
|
|
42
|
+
splitView.setAttribute('sidebar-width-fraction', '0.30');
|
|
43
|
+
splitView.setAttribute('show-sidebar', '');
|
|
44
|
+
|
|
45
|
+
// Inline styles for the same reason as the GL container below.
|
|
46
|
+
const sidebarContent = document.createElement('div');
|
|
47
|
+
sidebarContent.setAttribute('slot', 'sidebar');
|
|
48
|
+
sidebarContent.className = 'adw-sidebar-content';
|
|
49
|
+
sidebarContent.style.cssText = 'padding:12px;display:flex;flex-direction:column;gap:12px';
|
|
50
|
+
|
|
51
|
+
const modelGroup = document.createElement('adw-preferences-group');
|
|
52
|
+
modelGroup.setAttribute('title', 'Model');
|
|
53
|
+
|
|
54
|
+
const modelRow = document.createElement('adw-combo-row');
|
|
55
|
+
modelRow.setAttribute('title', 'Model');
|
|
56
|
+
modelRow.setAttribute('items', JSON.stringify(MODEL_LIST.map((m) => m.name)));
|
|
57
|
+
modelRow.setAttribute('selected', String(DEFAULT_MODEL_INDEX));
|
|
58
|
+
|
|
59
|
+
modelGroup.append(modelRow);
|
|
60
|
+
|
|
61
|
+
// Rendering group
|
|
62
|
+
const renderGroup = document.createElement('adw-preferences-group');
|
|
63
|
+
renderGroup.setAttribute('title', 'Rendering');
|
|
64
|
+
|
|
65
|
+
const flatColorsRow = document.createElement('adw-switch-row');
|
|
66
|
+
flatColorsRow.setAttribute('title', 'Flat Colors');
|
|
67
|
+
|
|
68
|
+
const mergeModelRow = document.createElement('adw-switch-row');
|
|
69
|
+
mergeModelRow.setAttribute('title', 'Merge Model');
|
|
70
|
+
|
|
71
|
+
const smoothNormalsRow = document.createElement('adw-switch-row');
|
|
72
|
+
smoothNormalsRow.setAttribute('title', 'Smooth Normals');
|
|
73
|
+
smoothNormalsRow.setAttribute('active', '');
|
|
74
|
+
|
|
75
|
+
renderGroup.append(flatColorsRow, mergeModelRow, smoothNormalsRow);
|
|
76
|
+
|
|
77
|
+
// Display group
|
|
78
|
+
const displayGroup = document.createElement('adw-preferences-group');
|
|
79
|
+
displayGroup.setAttribute('title', 'Display');
|
|
80
|
+
|
|
81
|
+
const buildingStepRow = document.createElement('adw-spin-row');
|
|
82
|
+
buildingStepRow.setAttribute('title', 'Building Step');
|
|
83
|
+
buildingStepRow.setAttribute('min', '0');
|
|
84
|
+
buildingStepRow.setAttribute('max', '0');
|
|
85
|
+
buildingStepRow.setAttribute('step', '1');
|
|
86
|
+
buildingStepRow.setAttribute('value', '0');
|
|
87
|
+
|
|
88
|
+
const displayLinesRow = document.createElement('adw-switch-row');
|
|
89
|
+
displayLinesRow.setAttribute('title', 'Display Lines');
|
|
90
|
+
displayLinesRow.setAttribute('active', '');
|
|
91
|
+
|
|
92
|
+
const conditionalLinesRow = document.createElement('adw-switch-row');
|
|
93
|
+
conditionalLinesRow.setAttribute('title', 'Conditional Lines');
|
|
94
|
+
conditionalLinesRow.setAttribute('active', '');
|
|
95
|
+
|
|
96
|
+
displayGroup.append(buildingStepRow, displayLinesRow, conditionalLinesRow);
|
|
97
|
+
|
|
98
|
+
sidebarContent.append(modelGroup, renderGroup, displayGroup);
|
|
99
|
+
|
|
100
|
+
// GL container (content slot) — inline styles so the showcase
|
|
101
|
+
// is self-contained and works regardless of host CSS.
|
|
102
|
+
const glContainer = document.createElement('div');
|
|
103
|
+
glContainer.setAttribute('slot', 'content');
|
|
104
|
+
glContainer.id = 'gl-area-container';
|
|
105
|
+
glContainer.style.cssText = 'flex:1;position:relative;min-width:0;min-height:0';
|
|
106
|
+
|
|
107
|
+
const canvas = document.createElement('canvas');
|
|
108
|
+
canvas.id = 'webgl-canvas';
|
|
109
|
+
canvas.style.cssText = 'display:block;width:100%;height:100%;position:absolute;inset:0';
|
|
110
|
+
glContainer.append(canvas);
|
|
111
|
+
|
|
112
|
+
splitView.append(sidebarContent, glContainer);
|
|
113
|
+
win.append(headerBar, splitView);
|
|
114
|
+
container.append(win);
|
|
115
|
+
|
|
116
|
+
// Sync canvas size
|
|
117
|
+
new ResizeObserver(() => {
|
|
118
|
+
canvas.width = glContainer.clientWidth;
|
|
119
|
+
canvas.height = glContainer.clientHeight;
|
|
120
|
+
}).observe(glContainer);
|
|
121
|
+
canvas.width = glContainer.clientWidth;
|
|
122
|
+
canvas.height = glContainer.clientHeight;
|
|
123
|
+
|
|
124
|
+
// Start three.js
|
|
125
|
+
const demo = start(canvas, { assetBase }, (numSteps) => {
|
|
126
|
+
// Update building step range when model loads
|
|
127
|
+
buildingStepRow.setAttribute('max', String(numSteps - 1));
|
|
128
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- adw-spin-row is a custom element with no TypeScript type for .value property
|
|
129
|
+
(buildingStepRow as any).value = numSteps - 1;
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
connectControls(
|
|
133
|
+
demo,
|
|
134
|
+
modelRow as AdwRow,
|
|
135
|
+
flatColorsRow as AdwRow,
|
|
136
|
+
mergeModelRow as AdwRow,
|
|
137
|
+
smoothNormalsRow as AdwRow,
|
|
138
|
+
buildingStepRow as AdwRow,
|
|
139
|
+
displayLinesRow as AdwRow,
|
|
140
|
+
conditionalLinesRow as AdwRow,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
pause: () => demo.pause(),
|
|
145
|
+
resume: () => demo.resume(),
|
|
146
|
+
get isPaused() {
|
|
147
|
+
return demo.isPaused;
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Adwaita web components expose custom properties (.selected, .active, .value) not in HTMLElement types.
|
|
153
|
+
type AdwRow = HTMLElement & Record<string, unknown>;
|
|
154
|
+
|
|
155
|
+
function connectControls(
|
|
156
|
+
demo: LDrawDemo,
|
|
157
|
+
modelRow: AdwRow,
|
|
158
|
+
flatColorsRow: AdwRow,
|
|
159
|
+
mergeModelRow: AdwRow,
|
|
160
|
+
smoothNormalsRow: AdwRow,
|
|
161
|
+
buildingStepRow: AdwRow,
|
|
162
|
+
displayLinesRow: AdwRow,
|
|
163
|
+
conditionalLinesRow: AdwRow,
|
|
164
|
+
) {
|
|
165
|
+
modelRow.addEventListener('notify::selected', () => {
|
|
166
|
+
demo.effectController.modelIndex = modelRow.selected as number;
|
|
167
|
+
demo.reloadObject(true);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
flatColorsRow.addEventListener('notify::active', () => {
|
|
171
|
+
demo.effectController.flatColors = flatColorsRow.active as boolean;
|
|
172
|
+
demo.reloadObject(false);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
mergeModelRow.addEventListener('notify::active', () => {
|
|
176
|
+
demo.effectController.mergeModel = mergeModelRow.active as boolean;
|
|
177
|
+
demo.reloadObject(false);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
smoothNormalsRow.addEventListener('notify::active', () => {
|
|
181
|
+
demo.effectController.smoothNormals = smoothNormalsRow.active as boolean;
|
|
182
|
+
demo.reloadObject(false);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
buildingStepRow.addEventListener('notify::value', () => {
|
|
186
|
+
demo.effectController.buildingStep = buildingStepRow.value as number;
|
|
187
|
+
demo.updateVisibility();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
displayLinesRow.addEventListener('notify::active', () => {
|
|
191
|
+
demo.effectController.displayLines = displayLinesRow.active as boolean;
|
|
192
|
+
demo.updateVisibility();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
conditionalLinesRow.addEventListener('notify::active', () => {
|
|
196
|
+
demo.effectController.conditionalLines = conditionalLinesRow.active as boolean;
|
|
197
|
+
demo.updateVisibility();
|
|
198
|
+
});
|
|
199
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>LDraw Loader — gjsify</title>
|
|
6
|
+
<link rel="stylesheet" href="./webgl.css" type="text/css" />
|
|
7
|
+
<link rel="stylesheet" href="./browser.css" type="text/css" />
|
|
8
|
+
<script src="./browser.js" type="module" defer></script>
|
|
9
|
+
</head>
|
|
10
|
+
<body></body>
|
|
11
|
+
</html>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* Page chrome for the STANDALONE `index.html` only — how the window is centred
|
|
2
|
+
on an otherwise empty page. The window's own layout (sidebar vs. GL area) is
|
|
3
|
+
deliberately NOT here: `browser.ts` builds an <adw-overlay-split-view> and
|
|
4
|
+
inline-styles the GL container, because the website embeds `mount()` without
|
|
5
|
+
ever loading this file, and a layout that lives here is a layout the embed
|
|
6
|
+
does not get. */
|
|
7
|
+
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
html, body {
|
|
15
|
+
width: 100%;
|
|
16
|
+
height: 100%;
|
|
17
|
+
overflow: hidden;
|
|
18
|
+
background: #2d2d2d;
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
adw-window {
|
|
25
|
+
max-width: 100%;
|
|
26
|
+
max-height: 100%;
|
|
27
|
+
}
|
|
28
|
+
|
package/src/gjs/gjs.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// GJS/Adwaita entry point for three-loader-ldraw example.
|
|
2
|
+
// Ported from refs/three/examples/webgl_loader_ldraw.html
|
|
3
|
+
// Original: MIT license, three.js authors (https://threejs.org)
|
|
4
|
+
// This software uses the LDraw Parts Library (http://www.ldraw.org), CC BY 2.0.
|
|
5
|
+
|
|
6
|
+
import Adw from 'gi://Adw?version=1';
|
|
7
|
+
import Gio from 'gi://Gio?version=2.0';
|
|
8
|
+
|
|
9
|
+
import { installDevtools } from '@gjsify/devtools';
|
|
10
|
+
import { LDrawWindow } from './ldraw-window.js';
|
|
11
|
+
|
|
12
|
+
const app = new Adw.Application({
|
|
13
|
+
application_id: 'gjsify.examples.three-loader-ldraw',
|
|
14
|
+
flags: Gio.ApplicationFlags.FLAGS_NONE,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Opt-in devtools control plane — a no-op unless GJSIFY_DEVTOOLS is set, so
|
|
18
|
+
// production runs are unaffected. It is how the rendered model gets verified
|
|
19
|
+
// without a human: the model arrives through an async loader, so "the window
|
|
20
|
+
// opened" proves nothing about what is in the GLArea.
|
|
21
|
+
app.connect('startup', () => installDevtools(app));
|
|
22
|
+
|
|
23
|
+
app.connect('activate', () => {
|
|
24
|
+
let win = app.get_active_window();
|
|
25
|
+
if (!win) win = new LDrawWindow(app);
|
|
26
|
+
win.present();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// runAsync (NOT the sync run()): the GJS-recommended lifecycle, and the required
|
|
30
|
+
// one on the `--app node` reverse bridge where a sync run() deadlocks.
|
|
31
|
+
await app.runAsync([]);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
using Gtk 4.0;
|
|
2
|
+
using Adw 1;
|
|
3
|
+
|
|
4
|
+
template $LDrawWindow: Adw.ApplicationWindow {
|
|
5
|
+
default-width: 1100;
|
|
6
|
+
default-height: 700;
|
|
7
|
+
title: "LDraw Loader";
|
|
8
|
+
|
|
9
|
+
content: Gtk.Box {
|
|
10
|
+
orientation: vertical;
|
|
11
|
+
|
|
12
|
+
Adw.HeaderBar {}
|
|
13
|
+
|
|
14
|
+
Gtk.Box {
|
|
15
|
+
orientation: horizontal;
|
|
16
|
+
hexpand: true;
|
|
17
|
+
vexpand: true;
|
|
18
|
+
|
|
19
|
+
Gtk.ScrolledWindow {
|
|
20
|
+
width-request: 320;
|
|
21
|
+
hexpand: false;
|
|
22
|
+
hscrollbar-policy: never;
|
|
23
|
+
|
|
24
|
+
Gtk.Box {
|
|
25
|
+
orientation: vertical;
|
|
26
|
+
spacing: 12;
|
|
27
|
+
margin-top: 12;
|
|
28
|
+
margin-bottom: 12;
|
|
29
|
+
margin-start: 12;
|
|
30
|
+
margin-end: 12;
|
|
31
|
+
|
|
32
|
+
Adw.PreferencesGroup {
|
|
33
|
+
title: "Model";
|
|
34
|
+
|
|
35
|
+
Adw.ComboRow modelRow {
|
|
36
|
+
title: "Model";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Adw.PreferencesGroup {
|
|
41
|
+
title: "Rendering";
|
|
42
|
+
|
|
43
|
+
Adw.SwitchRow flatColorsRow {
|
|
44
|
+
title: "Flat Colors";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Adw.SwitchRow mergeModelRow {
|
|
48
|
+
title: "Merge Model";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Adw.SwitchRow smoothNormalsRow {
|
|
52
|
+
title: "Smooth Normals";
|
|
53
|
+
active: true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Adw.PreferencesGroup {
|
|
58
|
+
title: "Display";
|
|
59
|
+
|
|
60
|
+
Adw.SpinRow buildingStepRow {
|
|
61
|
+
title: "Building Step";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
Adw.SwitchRow displayLinesRow {
|
|
65
|
+
title: "Display Lines";
|
|
66
|
+
active: true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Adw.SwitchRow conditionalLinesRow {
|
|
70
|
+
title: "Conditional Lines";
|
|
71
|
+
active: true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Gtk.Separator {
|
|
78
|
+
orientation: vertical;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Gtk.Box glAreaContainer {
|
|
82
|
+
hexpand: true;
|
|
83
|
+
vexpand: true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// Adwaita window for the LDraw loader example.
|
|
2
|
+
// Uses a Blueprint template for the UI layout and WebGLBridge for WebGL.
|
|
3
|
+
// Ported from refs/three/examples/webgl_loader_ldraw.html
|
|
4
|
+
// Original: MIT license, three.js authors (https://threejs.org)
|
|
5
|
+
// This software uses the LDraw Parts Library (http://www.ldraw.org), CC BY 2.0.
|
|
6
|
+
|
|
7
|
+
import GObject from 'gi://GObject?version=2.0';
|
|
8
|
+
import Gtk from 'gi://Gtk?version=4.0';
|
|
9
|
+
import Adw from 'gi://Adw?version=1';
|
|
10
|
+
import { WebGLBridge } from '@gjsify/webgl';
|
|
11
|
+
import { start, MODEL_LIST, DEFAULT_MODEL_INDEX, type LDrawDemo } from '../three-demo.js';
|
|
12
|
+
import Template from './ldraw-window.blp';
|
|
13
|
+
|
|
14
|
+
export class LDrawWindow extends Adw.ApplicationWindow {
|
|
15
|
+
declare private _glAreaContainer: Gtk.Box;
|
|
16
|
+
declare private _modelRow: Adw.ComboRow;
|
|
17
|
+
declare private _flatColorsRow: Adw.SwitchRow;
|
|
18
|
+
declare private _mergeModelRow: Adw.SwitchRow;
|
|
19
|
+
declare private _smoothNormalsRow: Adw.SwitchRow;
|
|
20
|
+
declare private _buildingStepRow: Adw.SpinRow;
|
|
21
|
+
declare private _displayLinesRow: Adw.SwitchRow;
|
|
22
|
+
declare private _conditionalLinesRow: Adw.SwitchRow;
|
|
23
|
+
|
|
24
|
+
static {
|
|
25
|
+
GObject.registerClass(
|
|
26
|
+
{
|
|
27
|
+
GTypeName: 'LDrawWindow',
|
|
28
|
+
Template,
|
|
29
|
+
InternalChildren: [
|
|
30
|
+
'glAreaContainer',
|
|
31
|
+
'modelRow',
|
|
32
|
+
'flatColorsRow',
|
|
33
|
+
'mergeModelRow',
|
|
34
|
+
'smoothNormalsRow',
|
|
35
|
+
'buildingStepRow',
|
|
36
|
+
'displayLinesRow',
|
|
37
|
+
'conditionalLinesRow',
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
this,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
constructor(application: Adw.Application) {
|
|
45
|
+
super({ application });
|
|
46
|
+
|
|
47
|
+
// Model ComboRow
|
|
48
|
+
this._modelRow.set_model(Gtk.StringList.new(MODEL_LIST.map((m) => m.name)));
|
|
49
|
+
this._modelRow.set_selected(DEFAULT_MODEL_INDEX);
|
|
50
|
+
|
|
51
|
+
// Building step SpinRow (initial range, updated on model load)
|
|
52
|
+
this._buildingStepRow.set_adjustment(
|
|
53
|
+
new Gtk.Adjustment({
|
|
54
|
+
lower: 0,
|
|
55
|
+
upper: 0,
|
|
56
|
+
step_increment: 1,
|
|
57
|
+
value: 0,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Create and insert WebGL widget
|
|
62
|
+
const glArea = new WebGLBridge();
|
|
63
|
+
glArea.set_hexpand(true);
|
|
64
|
+
glArea.set_vexpand(true);
|
|
65
|
+
glArea.installGlobals();
|
|
66
|
+
this._glAreaContainer.append(glArea);
|
|
67
|
+
|
|
68
|
+
Object.defineProperty(globalThis, 'innerWidth', {
|
|
69
|
+
get: () => glArea.get_allocated_width(),
|
|
70
|
+
configurable: true,
|
|
71
|
+
});
|
|
72
|
+
Object.defineProperty(globalThis, 'innerHeight', {
|
|
73
|
+
get: () => glArea.get_allocated_height(),
|
|
74
|
+
configurable: true,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
glArea.onReady((canvas) => {
|
|
78
|
+
// The bundle's own directory, derived in URI SPACE rather than by
|
|
79
|
+
// pasting `file://` onto a native path. `GLib.filename_from_uri()`
|
|
80
|
+
// hands back a PLATFORM path, which on win32 is `C:\…\dist` — and
|
|
81
|
+
// `file://${that}/` makes `C:` the URI hostname, so every model
|
|
82
|
+
// fetch is refused for an invalid host. Same defect the pixel
|
|
83
|
+
// showcase paid for in ce4eb6aa1; keep the two spellings identical.
|
|
84
|
+
const assetBase = new URL('./', import.meta.url).href;
|
|
85
|
+
|
|
86
|
+
const demo = start(canvas, { assetBase }, (numSteps) => {
|
|
87
|
+
// Update building step range on model load
|
|
88
|
+
const adj = this._buildingStepRow.get_adjustment();
|
|
89
|
+
adj.set_upper(numSteps - 1);
|
|
90
|
+
adj.set_value(numSteps - 1);
|
|
91
|
+
});
|
|
92
|
+
this.connectControls(demo);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private connectControls(demo: LDrawDemo) {
|
|
97
|
+
this._modelRow.connect('notify::selected', () => {
|
|
98
|
+
demo.effectController.modelIndex = this._modelRow.selected;
|
|
99
|
+
demo.reloadObject(true);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
this._flatColorsRow.connect('notify::active', () => {
|
|
103
|
+
demo.effectController.flatColors = this._flatColorsRow.active;
|
|
104
|
+
demo.reloadObject(false);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
this._mergeModelRow.connect('notify::active', () => {
|
|
108
|
+
demo.effectController.mergeModel = this._mergeModelRow.active;
|
|
109
|
+
demo.reloadObject(false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
this._smoothNormalsRow.connect('notify::active', () => {
|
|
113
|
+
demo.effectController.smoothNormals = this._smoothNormalsRow.active;
|
|
114
|
+
demo.reloadObject(false);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
this._buildingStepRow.connect('notify::value', () => {
|
|
118
|
+
demo.effectController.buildingStep = this._buildingStepRow.get_value();
|
|
119
|
+
demo.updateVisibility();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
this._displayLinesRow.connect('notify::active', () => {
|
|
123
|
+
demo.effectController.displayLines = this._displayLinesRow.active;
|
|
124
|
+
demo.updateVisibility();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
this._conditionalLinesRow.connect('notify::active', () => {
|
|
128
|
+
demo.effectController.conditionalLines = this._conditionalLinesRow.active;
|
|
129
|
+
demo.updateVisibility();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
package/src/models.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Shared model list for the LDraw viewer.
|
|
2
|
+
// LDraw.org CC BY 2.0 Parts Library.
|
|
3
|
+
|
|
4
|
+
export interface ModelEntry {
|
|
5
|
+
name: string;
|
|
6
|
+
file: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const MODEL_LIST: readonly ModelEntry[] = [
|
|
10
|
+
{ name: 'Car', file: 'models/car.ldr_Packed.mpd' },
|
|
11
|
+
{ name: 'Lunar Vehicle', file: 'models/1621-1-LunarMPVVehicle.mpd_Packed.mpd' },
|
|
12
|
+
{ name: 'Radar Truck', file: 'models/889-1-RadarTruck.mpd_Packed.mpd' },
|
|
13
|
+
{ name: 'Trailer', file: 'models/4838-1-MiniVehicles.mpd_Packed.mpd' },
|
|
14
|
+
{ name: 'Bulldozer', file: 'models/4915-1-MiniConstruction.mpd_Packed.mpd' },
|
|
15
|
+
{ name: 'Helicopter', file: 'models/4918-1-MiniFlyers.mpd_Packed.mpd' },
|
|
16
|
+
{ name: 'Plane', file: 'models/5935-1-IslandHopper.mpd_Packed.mpd' },
|
|
17
|
+
{ name: 'Lighthouse', file: 'models/30023-1-Lighthouse.ldr_Packed.mpd' },
|
|
18
|
+
{ name: 'X-Wing mini', file: 'models/30051-1-X-wingFighter-Mini.mpd_Packed.mpd' },
|
|
19
|
+
{ name: 'AT-ST mini', file: 'models/30054-1-AT-ST-Mini.mpd_Packed.mpd' },
|
|
20
|
+
{ name: 'AT-AT mini', file: 'models/4489-1-AT-AT-Mini.mpd_Packed.mpd' },
|
|
21
|
+
{ name: 'Shuttle', file: 'models/4494-1-Imperial Shuttle-Mini.mpd_Packed.mpd' },
|
|
22
|
+
{ name: 'TIE Interceptor', file: 'models/6965-1-TIEIntercep_4h4MXk5.mpd_Packed.mpd' },
|
|
23
|
+
{ name: 'Star fighter', file: 'models/6966-1-JediStarfighter-Mini.mpd_Packed.mpd' },
|
|
24
|
+
{ name: 'X-Wing', file: 'models/7140-1-X-wingFighter.mpd_Packed.mpd' },
|
|
25
|
+
{ name: 'AT-ST', file: 'models/10174-1-ImperialAT-ST-UCS.mpd_Packed.mpd' },
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
export const DEFAULT_MODEL_INDEX = 0; // Car
|