Skip to content

Commit dc18fef

Browse files
committed
first test run of complete node preview. Connected nodes will generate a script that will be evaluated to obtain the material and then passed to the preview scene.
1 parent 639a707 commit dc18fef

31 files changed

+693
-212
lines changed

src/Editor.ts

Lines changed: 28 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export class Editor {
3030
private focusedChild :Node|undefined;
3131
private mouse:Vector2Like = {x:0, y:0}
3232
private aspectCorrection = 1;
33+
private canvasAspect:number;
3334

3435
private handIcon : HandIcon;
3536

@@ -77,12 +78,14 @@ export class Editor {
7778
this._ctx = canvas.getContext('2d')!; //TODO:handle error
7879
this._ctx.font = Theme.config.fontSize+'px '+Theme.config.fontFamily;
7980

80-
const aspect = canvas.width / canvas.height;
81-
this.aspectCorrection = ( canvas.offsetWidth/canvas.offsetHeight )*aspect
82-
83-
// fix aspect ratio...
81+
this.canvasAspect = this.canvas.width / this.canvas.height;
82+
this.aspectCorrection = ( this.canvas.offsetWidth/this.canvas.offsetHeight )*this.canvasAspect;
83+
8484
this.ctx.scale(1, this.aspectCorrection) ;
8585

86+
window.addEventListener("resize", this.onResize.bind(this));
87+
88+
8689
// Double Click
8790
onDoubleClick(canvas, ev=>this.showNodeCreationMenu(ev));
8891

@@ -149,13 +152,7 @@ export class Editor {
149152
canvas.addEventListener('mousemove', (event) => {
150153
let scale = this.ctx.getTransform().a; // Get the current scale (assuming uniform scaling)
151154
const mousePos = this.getMousePos( event);
152-
const canvasPos = this.getCanvasMousePosition(mousePos);
153-
154-
// if( this.boxSelectionStart )
155-
// {
156-
// this.selectNodesInsideBoxSelection(this.boxSelectionStart, canvasPos);
157-
// return;
158-
// }
155+
const canvasPos = this.getCanvasMousePosition(mousePos);
159156

160157
let sx = ( mousePos.x - this.mouse.x ) ;
161158
let sy = ( mousePos.y - this.mouse.y ) ;
@@ -197,8 +194,7 @@ export class Editor {
197194
{
198195
//
199196
// update tail of "open" connections
200-
//
201-
///this.connections.filter(c=>!( isOutlet(c.to) )).forEach( c=>c.to=mousePos);
197+
//
202198
this.connections.setOrphansTarget( mousePos );
203199
}
204200

@@ -270,6 +266,7 @@ export class Editor {
270266
});
271267

272268
this.selectedOutlet = outlet;
269+
this.clearBoxSelection();
273270
}
274271
else
275272
{
@@ -278,10 +275,9 @@ export class Editor {
278275

279276
});
280277

281-
if( this.selectedOutlet ) {
282-
this.clearBoxSelection();
283-
break;
284-
}
278+
if( this.selectedOutlet )
279+
continue; //<------------------ we continue because we want to keep looping to collect all outlets.
280+
285281
//#endregion
286282

287283
//#region Click on element...
@@ -305,9 +301,7 @@ export class Editor {
305301
// default... will make the object move...
306302
this.focusedChild = obj;
307303
this.bingToTop(obj);
308-
309-
310-
304+
311305
break; //<-- to avoid processing childrens under us....
312306
}
313307

@@ -328,7 +322,7 @@ export class Editor {
328322
&& this.selectedOutlet!.isCompatible( outlet )
329323
&& ( outlet.owner !== this.selectedOutlet!.owner )
330324
; // TODO: check for outlet TYPE compatibility
331-
});
325+
});
332326
}
333327

334328
//
@@ -383,35 +377,7 @@ export class Editor {
383377
this.focusedChild = undefined;
384378
}
385379
else
386-
{
387-
388-
// check if we are on top of an oulet...
389-
390-
// this.objs.forEach( obj=>{
391-
392-
// //
393-
// // create a connection between the current compatible outlets...
394-
// //
395-
// if( obj.pressetOutlet( cursor.x-obj.x, cursor.y-obj.y, outlet =>{
396-
397-
// this.destroyConnectionsUsing( outlet )
398-
399-
// //
400-
// // filer valid outlets
401-
// //
402-
// const outlets = this.connections.filter( c=>
403-
// !("child" in c.to) //must not have an ending
404-
// && c.from.isInput!=outlet.isInput //oposite kind (input->output)
405-
// );
406-
407-
// outlets.forEach( c => {
408-
// c.to = outlet;
409-
// })
410-
411-
412-
// } )) return;
413-
414-
// });
380+
{
415381

416382
if( this.chosenOutlet.length )
417383
{
@@ -422,31 +388,29 @@ export class Editor {
422388
this.destroyConnectionsUsing( this.chosenOutlet[0].outlet );
423389

424390
this.connections.setOrphansTarget( this.chosenOutlet[0].outlet );
425-
426-
console.log("CONNECT", this.chosenOutlet[0].outlet)
427-
// this.connections.forEach( connection => {
428-
429-
// if( !("owner" in connection.to))
430-
// {
431-
// connection.to = this.chosenOutlet[0].outlet;
432-
// }
433-
434-
// });
391+
435392
}
436393

437394
this.chosenOutlet.length=0;
438395
this.availableOutlets.length=0;
439396

440397
//remove connections with no end...
441-
this.connections.purge( c=>isOutlet(c.to) )
442-
// let clean = this.connections.filter( c=>"owner" in c.to);
443-
// this.connections.length=0;
444-
// this.connections.push(...clean)
398+
this.connections.purge( c=>isOutlet(c.to) )
445399
}
446400
});
447401
//#endregion
448402
}
449403

404+
protected onResize() {
405+
const newAspectCorrection = ( this.canvas.offsetWidth/this.canvas.offsetHeight )*this.canvasAspect;
406+
407+
const xChange = this.aspectCorrection/newAspectCorrection;
408+
409+
this.aspectCorrection = newAspectCorrection;
410+
411+
this.ctx.scale(xChange, 1) ;
412+
}
413+
450414
get ctx() {
451415
return this._ctx;
452416
}

src/ThreeScene.ts

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
1-
import * as THREE from 'three';
1+
import { clamp } from 'three/src/math/MathUtils.js';
2+
import * as THREE from 'three/webgpu';
3+
import { WebGPURenderer } from 'three/webgpu';
24

35
export class ThreeScene {
46
readonly scene:THREE.Scene;
57
readonly camera:THREE.PerspectiveCamera;
6-
readonly renderer:THREE.WebGLRenderer;
8+
readonly renderer:WebGPURenderer;
79
readonly objHolder:THREE.Object3D;
810
private clock:THREE.Clock;
911
readonly ambientLight:THREE.AmbientLight;
12+
readonly directionalLight:THREE.DirectionalLight;
1013
private objs:THREE.Mesh[]=[]
1114
readonly pointLight:THREE.PointLight;
1215
private mouse:THREE.Vector2 = new THREE.Vector2();
1316
rotationSpeed = 1;
17+
protected _currentObjectIndex = 0;
18+
19+
private materialNotSet = new THREE.MeshStandardMaterial({ color: 0xcccccc });
1420

1521
constructor() {
1622
this.scene = new THREE.Scene();
1723
this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
1824

19-
this.renderer = new THREE.WebGLRenderer();
25+
this.renderer = new WebGPURenderer();
2026
this.renderer.setSize( window.innerWidth, window.innerHeight );
2127
this.renderer.setClearColor(0x1d1d1d)
2228

@@ -25,36 +31,58 @@ export class ThreeScene {
2531

2632
this.ambientLight = new THREE.AmbientLight(0xffffff,0.1);
2733
this.pointLight = new THREE.PointLight(0xffffff,5,15);
34+
this.directionalLight = new THREE.DirectionalLight()
35+
2836

2937
window.addEventListener('mousemove', (event) => {
3038
// Normalize mouse coordinates to [-1, 1]
3139
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
3240
this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
3341
});
3442

43+
window.addEventListener("resize", ev=>{
44+
// Update camera aspect ratio
45+
this.camera.aspect = window.innerWidth / window.innerHeight;
46+
this.camera.updateProjectionMatrix();
47+
48+
// Update renderer size
49+
this.renderer.setSize(window.innerWidth, window.innerHeight);
50+
})
51+
3552
this.buildScene()
3653
}
3754

38-
protected buildScene() {
39-
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
40-
const material = new THREE.MeshStandardMaterial( { color: 0xcccccc } );
41-
const cube = new THREE.Mesh( geometry, material );
55+
protected buildScene() {
56+
const material = this.materialNotSet;
57+
58+
//
59+
// dummy objects
60+
//
61+
const cube = new THREE.Mesh( new THREE.BoxGeometry( 2, 2, 2 ), material );
62+
cube.name="Cube";
63+
this.objs.push( cube );
64+
this.objHolder.add(cube);
65+
66+
const sphere = new THREE.Mesh( new THREE.SphereGeometry(1), material );
67+
sphere.name="Sphere";
68+
sphere.visible = false;
69+
this.objs.push( sphere );
70+
this.objHolder.add( sphere );
71+
4272

43-
this.objHolder.add(cube);
4473
this.scene.add( this.objHolder )
4574

4675
this.camera.position.z = 4;
47-
this.camera.position.x = -4;
76+
this.camera.position.x = -3;
4877

4978
this.scene.add( this.ambientLight );
50-
this.objs.push( cube );
79+
this.scene.add( this.directionalLight );
80+
5181

52-
const dirLight = new THREE.DirectionalLight()
53-
this.scene.add( dirLight );
5482

5583
this.scene.add( this.pointLight );
5684

57-
this.pointLight.intensity = 3
85+
this.pointLight.intensity = 15
5886
this.pointLight.position.z = 3
5987
}
6088

@@ -69,7 +97,7 @@ export class ThreeScene {
6997
const dir = vector.sub(this.camera.position).normalize();
7098

7199
// We want the light to be at a fixed Z in world space (e.g., Z = 2)
72-
const fixedZ = 2;
100+
const fixedZ = 2
73101

74102
// Calculate the distance from the camera to the plane at fixedZ
75103
const distance = (fixedZ - this.camera.position.z) / dir.z;
@@ -79,6 +107,18 @@ export class ThreeScene {
79107

80108
// Update the light's position
81109
this.pointLight.position.set(pos.x, pos.y, fixedZ);
110+
111+
}
112+
113+
get meshes() { return this.objs }
114+
115+
get currentObjectIndex() {
116+
return this._currentObjectIndex;
117+
}
118+
119+
set currentObjectIndex(index:number) {
120+
this._currentObjectIndex = clamp( index, 0, this.objs.length-1 );
121+
this.objs.forEach( (obj,i)=>obj.visible = i==index )
82122
}
83123

84124
render() {
@@ -89,4 +129,36 @@ export class ThreeScene {
89129
this.objHolder.rotateX(delta*this.rotationSpeed)
90130
this.renderer.render( this.scene, this.camera );
91131
}
132+
133+
setMaterial(index: number, material?: THREE.Material) {
134+
135+
material ??= this.materialNotSet;
136+
137+
this.objs.forEach((obj: THREE.Mesh) => {
138+
if (Array.isArray(obj.material)) {
139+
// Object has multiple materials
140+
if (index < obj.material.length) {
141+
obj.material[index] = material;
142+
} else {
143+
// Create missing material slots
144+
while (obj.material.length <= index) {
145+
obj.material.push(this.materialNotSet);
146+
}
147+
obj.material[index] = material;
148+
}
149+
} else {
150+
// Object has a single material
151+
if (index === 0) {
152+
obj.material = material;
153+
} else {
154+
// Change to an array of materials
155+
obj.material = [obj.material];
156+
while (obj.material.length <= index) {
157+
obj.material.push(this.materialNotSet);
158+
}
159+
obj.material[index] = material;
160+
}
161+
}
162+
});
163+
}
92164
}

src/components/ColorPicker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export class ColorPicker extends InteractiveLayoutElement implements IOverlayRe
125125
const rgb = [c.r, c.g, c.b];
126126
this.RGBSliders.forEach( (slider,i)=>slider.value = rgb[i]);
127127

128-
const hsl:number[] = Object.values( c.getHSL( this.hsl ) );
128+
const hsl:number[] = Object.values( this.hsl );// c.getHSL( this.hsl ) );
129129

130130
this.HSLSliders.forEach( (slider, i)=>slider.value=hsl[i])
131131

src/components/ColorWheel.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ export class ColorWheel extends InteractiveLayoutElement {
111111

112112
set color( c:Color ) {
113113
this._color = c;
114-
const saturation = this.hsl.s;
115-
114+
const saturation = this.hsl.s;
116115
c.getHSL(this.hsl);
117116
this.hsl.s = saturation;
118117
}

0 commit comments

Comments
 (0)