Skip to content

Commit f09a522

Browse files
authored
Merge pull request #61 from radical-data/45-add-camera-source-node
Sketchy version of camera nodes :)
2 parents b4384fd + 88dedbb commit f09a522

4 files changed

Lines changed: 98 additions & 1 deletion

File tree

src/lib/engine/HydraEngine.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ const trimUndefTail = (xs: unknown[]) => {
4040
return a;
4141
};
4242

43+
const CAMERA_SOURCE_INDEX = 0;
44+
4345
function makeIssueKey(kind: IssueKind, parts: Array<string | number | undefined>): string {
4446
return [kind, ...parts.map((p) => (p ?? '').toString())].join(':');
4547
}
@@ -70,6 +72,9 @@ export class HydraEngine {
7072
private typeByName = new Map<string, TransformType>();
7173
private inputsByName = new Map<string, string[]>();
7274

75+
private isCameraInitialised = false;
76+
private cameraInitError: string | null = null;
77+
7378
private onWindowResize(): void {
7479
if (!this.canvas) return;
7580

@@ -84,6 +89,28 @@ export class HydraEngine {
8489
}
8590
}
8691

92+
private initCameraSource(): void {
93+
if (this.isCameraInitialised || this.cameraInitError || !this.hydra) return;
94+
95+
this.isCameraInitialised = true;
96+
97+
try {
98+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
99+
const hydraAny = this.hydra as any;
100+
const source = hydraAny.sources?.[CAMERA_SOURCE_INDEX];
101+
102+
if (!source || typeof source.initCam !== 'function') {
103+
throw new Error('Hydra camera source not available');
104+
}
105+
106+
source.initCam();
107+
} catch (error) {
108+
this.cameraInitError =
109+
error instanceof Error ? error.message : 'Unknown error initialising camera source';
110+
console.warn('Camera initialisation failed:', error);
111+
}
112+
}
113+
87114
async init(canvas: HTMLCanvasElement): Promise<void> {
88115
this.canvas = canvas;
89116
this.canvas.style.backgroundColor = '#000000';
@@ -211,6 +238,55 @@ export class HydraEngine {
211238
return result;
212239
}
213240

241+
if (node.type === 'camera') {
242+
if (!this.hydra) {
243+
const result: BuildResult = {
244+
ok: false,
245+
issues: [
246+
{
247+
key: makeIssueKey('RUNTIME_EXECUTION_ERROR', [node.id]),
248+
kind: 'RUNTIME_EXECUTION_ERROR',
249+
severity: 'error',
250+
message: 'Hydra is not initialised; cannot use camera source',
251+
nodeId: node.id
252+
}
253+
]
254+
};
255+
memo.set(nodeId, result);
256+
return result;
257+
}
258+
259+
this.initCameraSource();
260+
261+
if (this.cameraInitError) {
262+
const result: BuildResult = {
263+
ok: false,
264+
issues: [
265+
{
266+
key: makeIssueKey('RUNTIME_EXECUTION_ERROR', [node.id]),
267+
kind: 'RUNTIME_EXECUTION_ERROR',
268+
severity: 'error',
269+
message: this.cameraInitError,
270+
nodeId: node.id
271+
}
272+
]
273+
};
274+
memo.set(nodeId, result);
275+
return result;
276+
}
277+
278+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
279+
const gens = this.generators as any;
280+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
281+
const hydraAny = this.hydra as any;
282+
const source = hydraAny.sources?.[CAMERA_SOURCE_INDEX];
283+
const chain = typeof gens.src === 'function' ? gens.src(source) : gens.solid?.(0, 0, 0, 1);
284+
285+
const result: BuildResult = { ok: true, chain };
286+
memo.set(nodeId, result);
287+
return result;
288+
}
289+
214290
// Validate transform exists
215291
const tType = this.typeByName.get(node.type);
216292
if (!tType) {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { NodeDefinition } from '../../types.js';
2+
3+
export const cameraDefinition: NodeDefinition = {
4+
id: 'camera',
5+
label: 'Camera',
6+
category: 'source',
7+
inputs: [],
8+
outputs: [
9+
{
10+
id: 'color',
11+
type: 'color'
12+
}
13+
],
14+
build: (ctx) => {
15+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
16+
const gens = ctx.generators as any;
17+
return gens.src?.(0) ?? null;
18+
}
19+
};

src/lib/nodes/registry.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { NodeDefinition } from '../types.js';
22
import { generateAllDefinitions, overrideDefinition } from './auto-definitions.js';
3+
import { cameraDefinition } from './definitions/camera.js';
34
import { outDefinition } from './definitions/out.js';
4-
55
let nodeDefinitions: Map<string, NodeDefinition> | null = null;
66
let initPromise: Promise<void> | null = null;
77

@@ -11,6 +11,7 @@ async function initializeRegistry(): Promise<void> {
1111
const autoDefinitions = await generateAllDefinitions();
1212
nodeDefinitions = new Map<string, NodeDefinition>(autoDefinitions);
1313

14+
nodeDefinitions.set('camera', cameraDefinition);
1415
// Override nodes with custom UX
1516
nodeDefinitions.set(
1617
'osc',

src/lib/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface HydraBuildCtx {
3232
}
3333

3434
export type HydraChain = unknown; // TODO: Fix when hydra-ts types are resolved
35+
3536
export interface IRNode {
3637
id: string;
3738
type: string;

0 commit comments

Comments
 (0)