Socket
Socket
Sign inDemoInstall

picimo

Package Overview
Dependencies
2
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.30 to 0.0.31

9

build/controls/Map2DPanControl.js

@@ -203,11 +203,8 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

} = view;
const {
pixelRatioH,
pixelRatioV
} = projection;
const [viewWidth, viewHeight, pixelRatioH, pixelRatioV] = projection.getViewRect();
view.centerX -= panX / pixelRatioH;
view.centerY -= panY / pixelRatioV; // TODO do we really need this?
view.width = projection.width;
view.height = projection.height;
view.width = viewWidth;
view.height = viewHeight;
}

@@ -214,0 +211,0 @@

@@ -44,4 +44,5 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

this.centerY = centerY;
this.width = projection.width;
this.height = projection.height;
const [viewWidth, viewHeight] = projection.getViewRect();
this.width = viewWidth;
this.height = viewHeight;
this.layerTileWidth = layerTileWidth;

@@ -76,5 +77,12 @@ this.layerTileHeight = layerTileHeight;

update(width = this.projection.width, height = this.projection.height) {
this.width = width;
this.height = height;
update(width, height) {
if (width == null || height == null) {
const [viewWidth, viewHeight] = this.projection.getViewRect();
this.width = width !== null && width !== void 0 ? width : viewWidth;
this.height = height !== null && height !== void 0 ? height : viewHeight;
} else {
this.width = width;
this.height = height;
}
const renderer = this[$renderer];

@@ -81,0 +89,0 @@ renderer.setOrigin(-this.centerX, -this.centerY);

@@ -0,38 +1,125 @@

function _classPrivateFieldGet(receiver, privateMap) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to get private field on non-instance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to set private field on non-instance"); } if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } return value; }
import { OrthographicCamera } from 'three';
import { Projection } from './Projection';
import { ProjectionRules } from './ProjectionRules';
import { calcViewSize } from './lib/calcViewSize';
const DEFAULT_DISTANCE = 100;
const DEFAULT_NEAR = 0.1;
const DEFAULT_FAR = 100000;
export class OrthographicProjection extends Projection {
updateOrtho(width, height, specs) {
var _specs$near, _specs$far, _specs$distance;
this.width = width;
this.height = height;
var _camera = new WeakMap();
var _width = new WeakMap();
var _height = new WeakMap();
var _pixelRatioH = new WeakMap();
var _pixelRatioV = new WeakMap();
var _plane = new WeakMap();
var _config = new WeakMap();
export class OrthographicProjection {
constructor(plane, rules) {
_camera.set(this, {
writable: true,
value: void 0
});
_width.set(this, {
writable: true,
value: 0
});
_height.set(this, {
writable: true,
value: 0
});
_pixelRatioH.set(this, {
writable: true,
value: 1
});
_pixelRatioV.set(this, {
writable: true,
value: 1
});
_plane.set(this, {
writable: true,
value: void 0
});
_config.set(this, {
writable: true,
value: void 0
});
_classPrivateFieldSet(this, _plane, plane);
_classPrivateFieldSet(this, _config, ProjectionRules.create(rules));
}
getCamera() {
return _classPrivateFieldGet(this, _camera);
}
getViewRect() {
return [_classPrivateFieldGet(this, _width), _classPrivateFieldGet(this, _height), _classPrivateFieldGet(this, _pixelRatioH), _classPrivateFieldGet(this, _pixelRatioV)];
}
updateViewRect(actualWidth, actualHeight) {
var _specs$near, _specs$far;
const {
specs
} = _classPrivateFieldGet(this, _config).findMatchingRule(actualWidth, actualHeight);
const [viewWidth, viewHeight] = calcViewSize(actualWidth, actualHeight, specs);
_classPrivateFieldSet(this, _width, viewWidth);
_classPrivateFieldSet(this, _height, viewHeight);
_classPrivateFieldSet(this, _pixelRatioH, actualWidth / viewWidth);
_classPrivateFieldSet(this, _pixelRatioV, actualHeight / viewHeight);
const near = (_specs$near = specs.near) !== null && _specs$near !== void 0 ? _specs$near : DEFAULT_NEAR;
const far = (_specs$far = specs.far) !== null && _specs$far !== void 0 ? _specs$far : DEFAULT_FAR;
const distance = (_specs$distance = specs.distance) !== null && _specs$distance !== void 0 ? _specs$distance : DEFAULT_DISTANCE;
const [halfWidth, halfHeight] = [width / 2, height / 2];
const {
camera
} = this;
const [halfWidth, halfHeight] = [viewWidth / 2, viewHeight / 2];
if (!camera) {
if (!_classPrivateFieldGet(this, _camera)) {
var _specs$distance;
// === Create camera
this.camera = new OrthographicCamera(-halfWidth, halfWidth, halfHeight, -halfHeight, near, far);
this.applyPlaneRotation();
this.applyCameraDistance(distance);
// TODO create one camera for each specs ?!
_classPrivateFieldSet(this, _camera, new OrthographicCamera(-halfWidth, halfWidth, halfHeight, -halfHeight, near, far));
_classPrivateFieldGet(this, _plane).applyRotation(_classPrivateFieldGet(this, _camera));
_classPrivateFieldGet(this, _camera).position[_classPrivateFieldGet(this, _plane).distancePropName] = (_specs$distance = specs.distance) !== null && _specs$distance !== void 0 ? _specs$distance : DEFAULT_DISTANCE;
} else {
// Update camera
camera.left = -halfWidth;
camera.right = halfWidth;
camera.top = halfHeight;
camera.bottom = -halfHeight;
camera.near = near;
camera.far = far;
camera.updateProjectionMatrix();
_classPrivateFieldGet(this, _camera).left = -halfWidth;
_classPrivateFieldGet(this, _camera).right = halfWidth;
_classPrivateFieldGet(this, _camera).top = halfHeight;
_classPrivateFieldGet(this, _camera).bottom = -halfHeight;
_classPrivateFieldGet(this, _camera).near = near;
_classPrivateFieldGet(this, _camera).far = far;
}
_classPrivateFieldGet(this, _camera).updateProjectionMatrix();
}
getZoom(_distanceToPojectionPlane) {
return 1;
}
}
//# sourceMappingURL=OrthographicProjection.js.map
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to get private field on non-instance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to set private field on non-instance"); } if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } return value; }
import { PerspectiveCamera } from 'three';
import { Projection } from './Projection'; // import { Logger } from "../../utils";
import { ProjectionRules } from './ProjectionRules';
import { calcViewSize } from './lib/calcViewSize';
const DEFAULT_DISTANCE = 300;
const DEFAULT_NEAR = 0.1;
const DEFAULT_FAR = 100000;
// const logger = new Logger('picimo.ParallaxProjection', 1000, 4);
export class ParallaxProjection extends Projection {
constructor(...args) {
super(...args);
_defineProperty(this, "initialDistance", void 0);
var _camera = new WeakMap();
var _width = new WeakMap();
var _height = new WeakMap();
var _pixelRatioH = new WeakMap();
var _pixelRatioV = new WeakMap();
var _plane = new WeakMap();
var _config = new WeakMap();
var _initialDistance = new WeakMap();
export class ParallaxProjection {
constructor(plane, rules) {
_defineProperty(this, "fovy", void 0);
_camera.set(this, {
writable: true,
value: void 0
});
_width.set(this, {
writable: true,
value: 0
});
_height.set(this, {
writable: true,
value: 0
});
_pixelRatioH.set(this, {
writable: true,
value: 1
});
_pixelRatioV.set(this, {
writable: true,
value: 1
});
_plane.set(this, {
writable: true,
value: void 0
});
_config.set(this, {
writable: true,
value: void 0
});
_initialDistance.set(this, {
writable: true,
value: void 0
});
_classPrivateFieldSet(this, _plane, plane);
_classPrivateFieldSet(this, _config, ProjectionRules.create(rules));
}
updateOrtho(width, height, specs) {
var _specs$near, _specs$far, _specs$distance;
getCamera() {
return _classPrivateFieldGet(this, _camera);
}
this.width = width;
this.height = height;
const near = (_specs$near = specs.near) !== null && _specs$near !== void 0 ? _specs$near : DEFAULT_NEAR;
const far = (_specs$far = specs.far) !== null && _specs$far !== void 0 ? _specs$far : DEFAULT_FAR;
const distance = (_specs$distance = specs.distance) !== null && _specs$distance !== void 0 ? _specs$distance : DEFAULT_DISTANCE;
const aspect = width / height;
const halfHeight = height / 2;
const fovy = 2 * Math.atan(halfHeight / distance) * 180 / Math.PI;
this.fovy = fovy;
getViewRect() {
return [_classPrivateFieldGet(this, _width), _classPrivateFieldGet(this, _height), _classPrivateFieldGet(this, _pixelRatioH), _classPrivateFieldGet(this, _pixelRatioV)];
}
updateViewRect(actualWidth, actualHeight) {
var _specs$distance;
const {
camera
} = this;
specs
} = _classPrivateFieldGet(this, _config).findMatchingRule(actualWidth, actualHeight);
if (!camera) {
const [viewWidth, viewHeight] = calcViewSize(actualWidth, actualHeight, specs);
_classPrivateFieldSet(this, _width, viewWidth);
_classPrivateFieldSet(this, _height, viewHeight);
_classPrivateFieldSet(this, _pixelRatioH, actualWidth / viewWidth);
_classPrivateFieldSet(this, _pixelRatioV, actualHeight / viewHeight);
const distance = (_specs$distance = specs.distance) !== null && _specs$distance !== void 0 ? _specs$distance : DEFAULT_DISTANCE;
const aspect = viewWidth / viewHeight;
const halfHeight = viewHeight / 2;
this.fovy = 2 * Math.atan(halfHeight / distance) * 180 / Math.PI;
if (!_classPrivateFieldGet(this, _camera)) {
var _specs$near, _specs$far;
// === Create camera
this.camera = new PerspectiveCamera(fovy, aspect, near, far);
this.applyPlaneRotation();
this.applyCameraDistance(distance);
this.initialDistance = distance;
// TODO create one camera for each specs ?!
const near = (_specs$near = specs.near) !== null && _specs$near !== void 0 ? _specs$near : DEFAULT_NEAR;
const far = (_specs$far = specs.far) !== null && _specs$far !== void 0 ? _specs$far : DEFAULT_FAR;
_classPrivateFieldSet(this, _camera, new PerspectiveCamera(this.fovy, aspect, near, far));
_classPrivateFieldGet(this, _plane).applyRotation(_classPrivateFieldGet(this, _camera));
_classPrivateFieldGet(this, _camera).position[_classPrivateFieldGet(this, _plane).distancePropName] = distance;
_classPrivateFieldSet(this, _initialDistance, distance);
} else {
// === Update camera
camera.fov = fovy;
camera.aspect = aspect;
camera.updateProjectionMatrix();
_classPrivateFieldGet(this, _camera).fov = this.fovy;
_classPrivateFieldGet(this, _camera).aspect = aspect;
}
_classPrivateFieldGet(this, _camera).updateProjectionMatrix();
}
getZoom(distanceToProjectionPlane) {
if (distanceToProjectionPlane === 0) return 1;
const d = this.initialDistance - distanceToProjectionPlane;
return Math.tan(this.fovy / 2 * Math.PI / 180) * d / (this.height / 2);
if (distanceToProjectionPlane === 0) return 1; // TODO [initial=>current]distance === length(camera.position) ?!
const d = _classPrivateFieldGet(this, _initialDistance) - distanceToProjectionPlane;
return Math.tan(this.fovy / 2 * Math.PI / 180) * d / (_classPrivateFieldGet(this, _height) / 2);
}

@@ -54,0 +139,0 @@

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to get private field on non-instance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to set private field on non-instance"); } if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } return value; }
import { Scene } from 'three';
import { Logger } from '../utils';
const log = new Logger('picimo.Stage2D');
/**
* A `Stage2D` is a `THREE.Scene` with a `Projection`.
*
* This helper class does not bring new features, but simplifies the handling of
* a `THREE.Scene`, `THREE.Camera`, `Projection` and `Display`.
*
* It offers the `resize()` and `frame()` methods, with which you can easily connect to
* the 'Display' class: `display.on(stage2d)`
*
* The `resize()` method updates the projection and should be called whenever
* the 2d dimension of the render target changes.
*
* The `frame()` method renders the scene with the camera from the projection.
*/
var _projection = new WeakMap();
var _curProjWidth = new WeakMap();
var _curProjHeight = new WeakMap();
export class Stage2D extends Scene {

@@ -12,26 +37,41 @@ constructor(projection) {

_defineProperty(this, "_projection", void 0);
_projection.set(this, {
writable: true,
value: void 0
});
_defineProperty(this, "_currentWidth", 0);
_curProjWidth.set(this, {
writable: true,
value: 0
});
_defineProperty(this, "_currentHeight", 0);
_curProjHeight.set(this, {
writable: true,
value: 0
});
this._projection = projection;
this.projection = projection;
}
set projection(projection) {
this._projection = projection;
projection.update(this._currentWidth, this._currentHeight);
_classPrivateFieldSet(this, _projection, projection);
projection === null || projection === void 0 ? void 0 : projection.updateViewRect(_classPrivateFieldGet(this, _curProjWidth), _classPrivateFieldGet(this, _curProjHeight));
}
get projection() {
return this._projection;
return _classPrivateFieldGet(this, _projection);
}
get camera() {
var _this$_projection;
var _classPrivateFieldGet2;
return (_this$_projection = this._projection) === null || _this$_projection === void 0 ? void 0 : _this$_projection.camera;
return (_classPrivateFieldGet2 = _classPrivateFieldGet(this, _projection)) === null || _classPrivateFieldGet2 === void 0 ? void 0 : _classPrivateFieldGet2.getCamera();
}
/**
* Update the projection.
* Should be called whenever the 2d dimension of the render target changes.
*/
resize({

@@ -46,14 +86,25 @@ width,

if (projection) {
this._currentWidth = width;
this._currentHeight = height;
projection.update(width, height);
const prevWidth = _classPrivateFieldGet(this, _curProjWidth);
if (log.DEBUG) {
log.log(`resize: ${width}x${height}, projection: ${projection.width}x${projection.height}`);
const prevHeight = _classPrivateFieldGet(this, _curProjHeight);
if (prevWidth !== width || prevHeight !== height) {
_classPrivateFieldSet(this, _curProjWidth, width);
_classPrivateFieldSet(this, _curProjHeight, height);
projection.updateViewRect(width, height);
if (log.DEBUG) {
log.log(`resize: ${width}x${height}, projection: ${projection.getViewRect().slice(0, 2).join('x')}`);
}
}
} else if (log.DEBUG) {
log.log(`resize: w=${width} h=${height}`);
}
}
/**
* Render the scene with the camera from the projection.
* But does not do anything, if `renderOnFrame` is `false`.
*/
frame({

@@ -60,0 +111,0 @@ display

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { Plane as ThreePlane, Vector3 } from 'three';
import { Plane as ThreePlane, Quaternion, Vector3 } from 'three';
export class Plane {

@@ -10,2 +10,4 @@ constructor(type) {

_defineProperty(this, "distancePropName", void 0);
this.type = type;

@@ -15,7 +17,15 @@

this.threePlane = new ThreePlane();
this.distancePropName = 'z';
} else {
this.threePlane = new ThreePlane(new Vector3(0, 1, 0));
this.distancePropName = 'y';
}
}
applyRotation(camera) {
if (this.type === 'xz') {
camera.applyQuaternion(new Quaternion().setFromAxisAngle(new Vector3(1, 0, 0), Math.PI * -0.5));
}
}
}

@@ -22,0 +32,0 @@

{
"name": "picimo",
"version": "0.0.30",
"version": "0.0.31",
"description": "A typescript library for my personal visual gfx and game dev experiments based on three.js",

@@ -5,0 +5,0 @@ "main": "dist/picimo.min.js",

@@ -19,3 +19,3 @@ > ## 🛠 Status: In Development

For more detailed API usage and examples, please visit the [kitchen-sink app](../kitchen-sink) or if you are more on the [_react_](https://reactjs.org/)-side, please try the components from [picimo-r3f](../picimo-r3f).
For more detailed API usage and examples, please visit the [kitchen-sink app](../kitchen-sink) or the [examples/](../../examples/) directory.

@@ -22,0 +22,0 @@ ## How to import in your own projects

@@ -157,3 +157,8 @@ import {Map2DView} from '../map2d';

const {projection} = view;
const {pixelRatioH, pixelRatioV} = projection;
const [
viewWidth,
viewHeight,
pixelRatioH,
pixelRatioV,
] = projection.getViewRect();

@@ -164,4 +169,4 @@ view.centerX -= panX / pixelRatioH;

// TODO do we really need this?
view.width = projection.width;
view.height = projection.height;
view.width = viewWidth;
view.height = viewHeight;
}

@@ -168,0 +173,0 @@

@@ -50,4 +50,5 @@ import {IProjection} from '../projection';

this.centerY = centerY;
this.width = projection.width;
this.height = projection.height;
const [viewWidth, viewHeight] = projection.getViewRect();
this.width = viewWidth;
this.height = viewHeight;
this.layerTileWidth = layerTileWidth;

@@ -82,8 +83,11 @@ this.layerTileHeight = layerTileHeight;

update(
width: number = this.projection.width,
height: number = this.projection.height,
): void {
this.width = width;
this.height = height;
update(width?: number, height?: number): void {
if (width == null || height == null) {
const [viewWidth, viewHeight] = this.projection.getViewRect();
this.width = width ?? viewWidth;
this.height = height ?? viewHeight;
} else {
this.width = width;
this.height = height;
}

@@ -90,0 +94,0 @@ const renderer = this[$renderer];

import {Camera} from 'three';
export interface IProjection {
camera: Camera;
getCamera(): Camera;
update(currentWidth: number, currentHeight: number): void;
updateViewRect(width: number, height: number): void;
width: number;
height: number;
/**
* @returns [width, height, pixelRatioH, pixelRatioV]
*/
getViewRect(): [number, number, number, number];
pixelRatioH: number;
pixelRatioV: number;
// origin: Vector2;
/**
* Return zoom factor (in relation to the projection plane)
* Calculate zoom factor (in relation to the projection plane)
*/
getZoom(distanceToProjectionPlane: number): number;
// TODO setZoom(baseFactor) ?! --> NO, only for ParallaxProjection
// TODO add a projectionPlane (THREE.Plane with position) ??
}
import {OrthographicCamera} from 'three';
import {Plane} from '../utils';
import {IProjection} from './IProjection';
import {IProjectionRule} from './IProjectionRule';
import {IProjectionSpecs} from './IProjectionSpecs';
import {Projection} from './Projection';
import {ProjectionRules} from './ProjectionRules';
import {calcViewSize} from './lib/calcViewSize';

@@ -27,24 +33,55 @@ const DEFAULT_DISTANCE = 100;

export class OrthographicProjection extends Projection<
IOrthographicProjectionSpecs,
OrthographicCamera
> {
updateOrtho(
width: number,
height: number,
specs: IOrthographicProjectionSpecs,
) {
this.width = width;
this.height = height;
export type OrthographicProjectionRule = IProjectionRule<IOrthographicProjectionSpecs>;
export type OrthographicConfig =
| IOrthographicProjectionSpecs
| OrthographicProjectionRule[];
export class OrthographicProjection implements IProjection {
#camera: OrthographicCamera;
#width = 0;
#height = 0;
#pixelRatioH = 1;
#pixelRatioV = 1;
readonly #plane: Plane;
readonly #config: ProjectionRules<OrthographicProjectionRule>;
constructor(plane: Plane, rules: OrthographicConfig) {
this.#plane = plane;
this.#config = ProjectionRules.create(rules);
}
getCamera(): OrthographicCamera {
return this.#camera;
}
getViewRect(): [number, number, number, number] {
return [this.#width, this.#height, this.#pixelRatioH, this.#pixelRatioV];
}
updateViewRect(actualWidth: number, actualHeight: number): void {
const {specs} = this.#config.findMatchingRule(actualWidth, actualHeight);
const [viewWidth, viewHeight] = calcViewSize(
actualWidth,
actualHeight,
specs,
);
this.#width = viewWidth;
this.#height = viewHeight;
this.#pixelRatioH = actualWidth / viewWidth;
this.#pixelRatioV = actualHeight / viewHeight;
const near = specs.near ?? DEFAULT_NEAR;
const far = specs.far ?? DEFAULT_FAR;
const distance = specs.distance ?? DEFAULT_DISTANCE;
const [halfWidth, halfHeight] = [viewWidth / 2, viewHeight / 2];
const [halfWidth, halfHeight] = [width / 2, height / 2];
const {camera} = this;
if (!camera) {
if (!this.#camera) {
// === Create camera
this.camera = new OrthographicCamera(
// TODO create one camera for each specs ?!
this.#camera = new OrthographicCamera(
-halfWidth,

@@ -57,15 +94,20 @@ halfWidth,

);
this.applyPlaneRotation();
this.applyCameraDistance(distance);
this.#plane.applyRotation(this.#camera);
this.#camera.position[this.#plane.distancePropName] =
specs.distance ?? DEFAULT_DISTANCE;
} else {
// Update camera
camera.left = -halfWidth;
camera.right = halfWidth;
camera.top = halfHeight;
camera.bottom = -halfHeight;
camera.near = near;
camera.far = far;
camera.updateProjectionMatrix();
this.#camera.left = -halfWidth;
this.#camera.right = halfWidth;
this.#camera.top = halfHeight;
this.#camera.bottom = -halfHeight;
this.#camera.near = near;
this.#camera.far = far;
}
this.#camera.updateProjectionMatrix();
}
getZoom(_distanceToPojectionPlane: number): number {
return 1;
}
}
import {PerspectiveCamera} from 'three';
import {Plane} from '../utils';
import {IProjection} from './IProjection';
import {IProjectionRule} from './IProjectionRule';
import {IProjectionSpecs} from './IProjectionSpecs';
import {Projection} from './Projection';
import {ProjectionRules} from './ProjectionRules';
import {calcViewSize} from './lib/calcViewSize';
// import { Logger } from "../../utils";
const DEFAULT_DISTANCE = 300;

@@ -29,42 +33,72 @@ const DEFAULT_NEAR = 0.1;

// const logger = new Logger('picimo.ParallaxProjection', 1000, 4);
export type ParallaxProjectionRule = IProjectionRule<IParallaxProjectionSpecs>;
export class ParallaxProjection extends Projection<
IParallaxProjectionSpecs,
PerspectiveCamera
> {
initialDistance: number;
export type ParallaxConfig =
| IParallaxProjectionSpecs
| ParallaxProjectionRule[];
export class ParallaxProjection implements IProjection {
fovy: number;
updateOrtho(
width: number,
height: number,
specs: IParallaxProjectionSpecs,
): void {
this.width = width;
this.height = height;
#camera: PerspectiveCamera;
const near = specs.near ?? DEFAULT_NEAR;
const far = specs.far ?? DEFAULT_FAR;
#width = 0;
#height = 0;
#pixelRatioH = 1;
#pixelRatioV = 1;
readonly #plane: Plane;
readonly #config: ProjectionRules<ParallaxProjectionRule>;
#initialDistance: number;
constructor(plane: Plane, rules: ParallaxConfig) {
this.#plane = plane;
this.#config = ProjectionRules.create(rules);
}
getCamera(): PerspectiveCamera {
return this.#camera;
}
getViewRect(): [number, number, number, number] {
return [this.#width, this.#height, this.#pixelRatioH, this.#pixelRatioV];
}
updateViewRect(actualWidth: number, actualHeight: number): void {
const {specs} = this.#config.findMatchingRule(actualWidth, actualHeight);
const [viewWidth, viewHeight] = calcViewSize(
actualWidth,
actualHeight,
specs,
);
this.#width = viewWidth;
this.#height = viewHeight;
this.#pixelRatioH = actualWidth / viewWidth;
this.#pixelRatioV = actualHeight / viewHeight;
const distance = specs.distance ?? DEFAULT_DISTANCE;
const aspect = viewWidth / viewHeight;
const halfHeight = viewHeight / 2;
const aspect = width / height;
const halfHeight = height / 2;
const fovy = (2 * Math.atan(halfHeight / distance) * 180) / Math.PI;
this.fovy = (2 * Math.atan(halfHeight / distance) * 180) / Math.PI;
this.fovy = fovy;
const {camera} = this;
if (!camera) {
if (!this.#camera) {
// === Create camera
this.camera = new PerspectiveCamera(fovy, aspect, near, far);
this.applyPlaneRotation();
this.applyCameraDistance(distance);
this.initialDistance = distance;
// TODO create one camera for each specs ?!
const near = specs.near ?? DEFAULT_NEAR;
const far = specs.far ?? DEFAULT_FAR;
this.#camera = new PerspectiveCamera(this.fovy, aspect, near, far);
this.#plane.applyRotation(this.#camera);
this.#camera.position[this.#plane.distancePropName] = distance;
this.#initialDistance = distance;
} else {
// === Update camera
camera.fov = fovy;
camera.aspect = aspect;
camera.updateProjectionMatrix();
this.#camera.fov = this.fovy;
this.#camera.aspect = aspect;
}
this.#camera.updateProjectionMatrix();
}

@@ -74,7 +108,8 @@

if (distanceToProjectionPlane === 0) return 1;
const d = this.initialDistance - distanceToProjectionPlane;
// TODO [initial=>current]distance === length(camera.position) ?!
const d = this.#initialDistance - distanceToProjectionPlane;
return (
(Math.tan(((this.fovy / 2) * Math.PI) / 180) * d) / (this.height / 2)
(Math.tan(((this.fovy / 2) * Math.PI) / 180) * d) / (this.#height / 2)
);
}
}

@@ -22,4 +22,4 @@ # Projection

1. Create the projection (eg. configure a parallax projection for the display canvas, or define an orthogonal projection for your render-to-texture target)
2. (Repeatedly) update the projection by calling `projection.update(width, height)` on _each frame_, or whenever the render-to-texture buffer dimension changes)
3. Use the `projection.camera` to render your scene
2. (Repeatedly) update the projection by calling `projection.updateViewRect(width, height)` on _each frame_, or whenever the render-to-texture buffer dimension changes)
3. Use the `projection.getCamera()` to render your scene

@@ -30,3 +30,3 @@ ## Configuration

These rules determine how the dimension of the projection plane should be, based on the resolution of the render target (&larr; `projection.update(width, height)`)
These rules determine how the dimension of the projection plane should be, based on the resolution of the render target (&larr; `projection.updateViewRect(width, height)`)

@@ -33,0 +33,0 @@ A rule may have one or more **constraints**. The first rule applies where constraints fit.

@@ -10,44 +10,72 @@ import {Scene, Camera} from 'three';

/**
* A `Stage2D` is a `THREE.Scene` with a `Projection`.
*
* This helper class does not bring new features, but simplifies the handling of
* a `THREE.Scene`, `THREE.Camera`, `Projection` and `Display`.
*
* It offers the `resize()` and `frame()` methods, with which you can easily connect to
* the 'Display' class: `display.on(stage2d)`
*
* The `resize()` method updates the projection and should be called whenever
* the 2d dimension of the render target changes.
*
* The `frame()` method renders the scene with the camera from the projection.
*/
export class Stage2D extends Scene {
renderOnFrame = true;
private _projection: IProjection;
private _currentWidth: number = 0;
private _currentHeight: number = 0;
#projection: IProjection;
#curProjWidth = 0;
#curProjHeight = 0;
constructor(projection?: IProjection) {
super();
this._projection = projection;
this.projection = projection;
}
set projection(projection: IProjection) {
this._projection = projection;
projection.update(this._currentWidth, this._currentHeight);
this.#projection = projection;
projection?.updateViewRect(this.#curProjWidth, this.#curProjHeight);
}
get projection(): IProjection {
return this._projection;
return this.#projection;
}
get camera(): Camera {
return this._projection?.camera;
return this.#projection?.getCamera();
}
resize({width, height}: {width: number; height: number}) {
/**
* Update the projection.
* Should be called whenever the 2d dimension of the render target changes.
*/
resize({width, height}: {width: number; height: number}): void {
const {projection} = this;
if (projection) {
this._currentWidth = width;
this._currentHeight = height;
projection.update(width, height);
if (log.DEBUG) {
log.log(
`resize: ${width}x${height}, projection: ${projection.width}x${projection.height}`,
);
const prevWidth = this.#curProjWidth;
const prevHeight = this.#curProjHeight;
if (prevWidth !== width || prevHeight !== height) {
this.#curProjWidth = width;
this.#curProjHeight = height;
projection.updateViewRect(width, height);
if (log.DEBUG) {
log.log(
`resize: ${width}x${height}, projection: ${projection
.getViewRect()
.slice(0, 2)
.join('x')}`,
);
}
}
} else if (log.DEBUG) {
log.log(`resize: w=${width} h=${height}`);
}
}
frame({display}: {display: Display}) {
/**
* Render the scene with the camera from the projection.
* But does not do anything, if `renderOnFrame` is `false`.
*/
frame({display}: {display: Display}): void {
const {camera, renderOnFrame} = this;

@@ -54,0 +82,0 @@ if (camera && renderOnFrame) {

@@ -1,2 +0,2 @@

import {Plane as ThreePlane, Vector3} from 'three';
import {Camera, Plane as ThreePlane, Quaternion, Vector3} from 'three';

@@ -9,2 +9,3 @@ export class Plane {

readonly threePlane: ThreePlane;
readonly distancePropName: 'y' | 'z';

@@ -15,6 +16,16 @@ constructor(type: 'xy' | 'xz') {

this.threePlane = new ThreePlane();
this.distancePropName = 'z';
} else {
this.threePlane = new ThreePlane(new Vector3(0, 1, 0));
this.distancePropName = 'y';
}
}
applyRotation(camera: Camera): void {
if (this.type === 'xz') {
camera.applyQuaternion(
new Quaternion().setFromAxisAngle(new Vector3(1, 0, 0), Math.PI * -0.5),
);
}
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc