Skip to content
This repository has been archived by the owner on Feb 10, 2023. It is now read-only.

Commit

Permalink
feat(core): add abstracts
Browse files Browse the repository at this point in the history
  • Loading branch information
nartc committed Nov 14, 2021
1 parent 9b29d39 commit abca9b5
Show file tree
Hide file tree
Showing 19 changed files with 1,171 additions and 8 deletions.
18 changes: 18 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@ export * from './lib/models';
export * from './lib/core.module';
export * from './lib/canvas.component';

export * from './lib/three/object-3d';
export * from './lib/three/object-3d.controller';
export * from './lib/three/object-3d-watched-controller.di';
export * from './lib/three/object-3d-material-geometry';
export * from './lib/three/animation-participant';
export * from './lib/three/attribute';
export * from './lib/three/curve';
export * from './lib/three/geometry';
export * from './lib/three/helper';
export * from './lib/three/light';
export * from './lib/three/line';
export * from './lib/three/material';
export * from './lib/three/mesh';
export * from './lib/three/sprite';
export * from './lib/three/texture';

export * from './lib/utils/apply-props.util';

export * from './lib/services/loader.service';

export * from './lib/stores/animation.store';
Expand Down
7 changes: 3 additions & 4 deletions packages/core/src/lib/core.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { NgtCanvasComponent } from './canvas.component';
import { NgtObject3dControllerDirective } from './three/object-3d.controller';

@NgModule({
imports: [CommonModule],
declarations: [NgtCanvasComponent],
exports: [NgtCanvasComponent],
declarations: [NgtCanvasComponent, NgtObject3dControllerDirective],
exports: [NgtCanvasComponent, NgtObject3dControllerDirective],
})
export class NgtCoreModule {}
13 changes: 11 additions & 2 deletions packages/core/src/lib/services/loader.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { Injectable, OnDestroy } from '@angular/core';
import { defer, forkJoin, Observable, of, shareReplay, throwError } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import {
catchError,
defer,
forkJoin,
map,
Observable,
of,
shareReplay,
tap,
throwError,
} from 'rxjs';
import * as THREE from 'three';
import type { GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
import type {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/lib/stores/instances.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ export class InstancesStore extends EnhancedComponentStore<InstancesStoreState>
};
});

readonly saveBufferGeometry = this.updater<{
readonly saveGeometry = this.updater<{
geometry: THREE.BufferGeometry;
id?: string;
}>((state, { geometry, id = geometry.uuid }) => ({
...state,
bufferGeometries: { ...state.geometries, [id]: geometry },
}));

readonly removeBufferGeometry = this.updater<string>((state, id) => {
readonly removeGeometry = this.updater<string>((state, id) => {
const { [id]: _, ...geometries } = state.geometries;

return {
Expand Down
59 changes: 59 additions & 0 deletions packages/core/src/lib/three/animation-participant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
Directive,
EventEmitter,
NgZone,
OnDestroy,
Output,
} from '@angular/core';
import * as THREE from 'three';
import type { NgtAnimationReady } from '../models';
import { AnimationStore } from '../stores/animation.store';

@Directive()
export abstract class NgtAnimationLoopParticipant<TObject = unknown>
implements OnDestroy
{
@Output() animateReady = new EventEmitter<NgtAnimationReady<TObject>>();

private animateTeardown?: () => void;

protected constructor(
protected animationStore: AnimationStore,
protected ngZone: NgZone
) {}

protected participate(animateObject: TObject) {
this.ngZone.runOutsideAngular(() => {
if (this.animateReady.observed) {
if (animateObject instanceof THREE.Object3D) {
this.animateTeardown = this.animationStore.registerAnimation(
animateObject as THREE.Object3D,
(obj, state) => {
this.animateReady.emit({
animateObject: obj as unknown as TObject,
renderState: state,
});
}
);
} else {
this.animateTeardown = this.animationStore.registerAnimation(
(state) => {
this.animateReady.emit({
animateObject,
renderState: state,
});
}
);
}
}
});
}

ngOnDestroy() {
this.ngZone.runOutsideAngular(() => {
if (this.animateTeardown) {
this.animateTeardown();
}
});
}
}
78 changes: 78 additions & 0 deletions packages/core/src/lib/three/attribute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
Directive,
Input,
NgZone,
OnChanges,
OnDestroy,
OnInit,
Optional,
} from '@angular/core';
import * as THREE from 'three';
import type { AnyConstructor } from '../models';
import { NgtGeometry } from './geometry';

@Directive()
export abstract class NgtAttribute<
TAttribute extends THREE.BufferAttribute = THREE.BufferAttribute
> implements OnInit, OnChanges, OnDestroy
{
@Input() attach?: THREE.BuiltinShaderAttributeName;

abstract attributeType: AnyConstructor<TAttribute>;

protected constructor(
protected ngZone: NgZone,
@Optional() protected geometryDirective?: NgtGeometry
) {}

private _extraArgs: unknown[] = [];

protected set extraArgs(v: unknown[]) {
this._extraArgs = v;
this.ngZone.runOutsideAngular(() => {
this.init();
});
}

private _attribute?: TAttribute;

ngOnChanges() {
this.ngZone.runOutsideAngular(() => {
if (this.attribute) {
this.attribute.needsUpdate = true;
}
});
}

ngOnInit() {
this.ngZone.runOutsideAngular(() => {
if (!this.attribute) {
this.init();
}
});
}

private init() {
if (this.geometryDirective && this.attach) {
this._attribute = new this.attributeType(...this._extraArgs);
if (this.attribute) {
this.geometryDirective.geometry.setAttribute(
this.attach,
this.attribute
);
}
}
}

ngOnDestroy() {
this.ngZone.runOutsideAngular(() => {
if (this.geometryDirective && this.attach) {
this.geometryDirective.geometry.deleteAttribute(this.attach);
}
});
}

get attribute(): TAttribute | undefined {
return this._attribute;
}
}
52 changes: 52 additions & 0 deletions packages/core/src/lib/three/curve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Directive, Input, NgZone, OnInit, Optional } from '@angular/core';
import * as THREE from 'three';
import type { AnyConstructor } from '../models';
import { NgtGeometry } from './geometry';

@Directive()
export abstract class NgtCurve<
TCurve extends THREE.Curve<THREE.Vector> = THREE.Curve<THREE.Vector>
> implements OnInit
{
@Input() divisions?: number;

abstract curveType: AnyConstructor<TCurve>;

private _extraArgs: unknown[] = [];

protected set extraArgs(v: unknown[]) {
this._extraArgs = v;
this.ngZone.runOutsideAngular(() => {
this.init();
});
}

protected constructor(
protected ngZone: NgZone,
@Optional() protected geometryDirective?: NgtGeometry
) {}

private _curve?: TCurve;

ngOnInit() {
this.ngZone.runOutsideAngular(() => {
if (!this.curve) {
this.init();
}
});
}

private init() {
this._curve = new this.curveType(...this._extraArgs);
if (this.curve && this.geometryDirective) {
const points = this.curve.getPoints(this.divisions);
this.geometryDirective.geometry.setFromPoints(
points as unknown as THREE.Vector3[] | THREE.Vector2[]
);
}
}

get curve(): TCurve | undefined {
return this._curve;
}
}
65 changes: 65 additions & 0 deletions packages/core/src/lib/three/geometry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {
Directive,
Input,
NgZone,
OnDestroy,
OnInit,
SkipSelf,
} from '@angular/core';
import * as THREE from 'three';
import type { AnyConstructor } from '../models';
import { InstancesStore } from '../stores/instances.store';

@Directive()
export abstract class NgtGeometry<
TGeometry extends THREE.BufferGeometry = THREE.BufferGeometry
> implements OnInit, OnDestroy
{
@Input() ngtId?: string;

protected constructor(
@SkipSelf() protected instancesStore: InstancesStore,
protected ngZone: NgZone
) {}

abstract geometryType: AnyConstructor<TGeometry>;

private _extraArgs: unknown[] = [];
protected set extraArgs(v: unknown[]) {
this._extraArgs = v;
this.ngZone.runOutsideAngular(() => {
this.init();
});
}

ngOnInit() {
this.ngZone.runOutsideAngular(() => {
if (!this.geometry) {
this.init();
}
});
}

private init() {
this._geometry = new this.geometryType(...this._extraArgs);

this.instancesStore.saveGeometry({
id: this.ngtId,
geometry: this._geometry,
});
}

private _geometry!: TGeometry;
get geometry(): TGeometry {
return this._geometry;
}

ngOnDestroy() {
this.ngZone.runOutsideAngular(() => {
if (this.geometry) {
this.instancesStore.removeGeometry(this.ngtId || this.geometry.uuid);
this.geometry.dispose();
}
});
}
}
50 changes: 50 additions & 0 deletions packages/core/src/lib/three/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Directive, OnChanges, OnInit } from '@angular/core';
import * as THREE from 'three';
import type { AnyConstructor } from '../models';
import { NgtObject3d } from './object-3d';

@Directive()
export abstract class NgtHelper<THelper extends THREE.Object3D>
extends NgtObject3d<THelper>
implements OnInit, OnChanges
{
abstract helperType: AnyConstructor<THelper>;

private _extraArgs: unknown[] = [];

private _helper!: THelper;

protected set extraArgs(v: unknown[]) {
this._extraArgs = v;
this.ngZone.runOutsideAngular(() => {
this.init();
});
}

ngOnChanges() {
super.ngOnChanges();
this.inputChangeHandler();
}

inputChangeHandler = () => {
if (!this.object3d) {
this.init();
}
};

ngOnInit() {
this.inputChangeHandler();
}

protected initObject() {
try {
this._helper = new this.helperType(...this._extraArgs);
} catch (e) {
console.log('Failed to initialize Helper');
}
}

get object3d(): THelper {
return this._helper;
}
}
Loading

0 comments on commit abca9b5

Please sign in to comment.