Skip to content

Commit

Permalink
Refactor and clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
reindernijhoff committed Nov 14, 2023
1 parent c8fe213 commit 03d5193
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 64 deletions.
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Panorama Renderer

The panorama-renderer is a lightweight package that allows you to render equirectangular panoramas using WebGL.

## Getting started

### Installing

Add `@mediamonks/panorama-renderer` to your project:

```sh
npm i @mediamonks/panorama-renderer
```
## Basic usage

Simple panorama rendering on canvas. Make sure the image is loaded before creating the renderer.

```ts
import { PanoramaRenderer } from '@mediamonks/panorama-renderer';

const renderer = PanoramaRenderer(wrapperElement, image, { loop: true });
```

## Building

In order to build seng-event, ensure that you have [Git](http://git-scm.com/downloads)
and [Node.js](http://nodejs.org/) installed.

Clone a copy of the repo:
```sh
git clone https://github.com/mediamonks/panorama-renderer.git
```

Change to the image-effect-renderer directory:
```sh
cd panorama-renderer
```

Install dev dependencies:
```sh
npm i
```

Build package:
```sh
npm run build
```
13 changes: 5 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
{
"name": "@mediamonks/panorama-renderer",
"version": "1.0.0",
"description": "The image-effect-renderer is lightweight package that allows you to run WebGL fragment shaders in your website using WebGL. It can be used to apply effects to HTML image or video sources.",
"description": "The panorama-renderer is a lightweight package that allows you to render equirectangular panoramas using WebGL.",
"keywords": [
"fragment shader",
"webgl",
"image",
"video",
"effect",
"shadertoy",
"glsl",
"shader",
"oneshader"
"panorama",
"360",
"equirectangular",
"equirectangular panorama"
],
"repository": "git@github.com:mediamonks/panorama-renderer.git",
"author": "Reinder Nijhoff <reinder@mediamonks.com>",
Expand Down
106 changes: 54 additions & 52 deletions src/lib/MouseListener.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,56 @@
import type {Vec2} from "./Math.js";

class MouseButton {
public press: boolean = false; // currently pressed
public down: boolean = false; // moment of press start
public oldDown: boolean = false;
public hit: boolean = false;
public downTime: number = 0;
}

export default class MouseListener {
private canvas: HTMLCanvasElement;
private mousePos: Float32Array = new Float32Array([0, 0]);
private previousMousePos: Float32Array = new Float32Array([0, 0]);
private mouseVelocity: Float32Array = new Float32Array([0, 0]);
private normalized: Float32Array = new Float32Array([0, 0]);
private mouseClickCallbacks: any[] = [];
private readonly canvas: HTMLCanvasElement;
private mousePos: Vec2 = {x: 0, y: 0};
private previousMousePos: Vec2 = {x: 0, y: 0};
private mouseVelocity: Vec2 = {x: 0, y: 0};
private normalized: Vec2 = {x: 0, y: 0};
private mouseClickCallbacks: (() => void)[] = [];
private buttons: MouseButton[] = [];
private resetSpeed: boolean = false;

private touchMoveListener: any;
private endListener: any;
private mouseMoveListener: any;

constructor(canvas: HTMLCanvasElement) {
this.canvas = canvas;

for (let i = 0; i < 3; i++) {
this.buttons.push(new MouseButton());
}

this.touchMoveListener = (e: { targetTouches: any[]; }) => this.setMouse(e.targetTouches[0]);
this.mouseMoveListener = (e: any) => this.setMouse(e);
this.endListener = () => {
this.buttons[0].press = false;
};

this.canvas.addEventListener('touchstart', this.onMouseStart, false);
this.canvas.addEventListener('touchmove', this.touchMoveListener, false);
this.canvas.addEventListener('touchend', this.endListener, false);
this.canvas.addEventListener('touchcancel', this.endListener, false);
this.canvas.addEventListener('mousedown', this.onMouseStart, false);
this.canvas.addEventListener('mousemove', this.mouseMoveListener, false);
this.canvas.addEventListener('mouseup', this.endListener, false);
this.canvas.addEventListener('mousecancel', this.endListener, false);
this.canvas.addEventListener('mouseout', this.endListener, false);
this.canvas.addEventListener('touchstart', this.onMouseStart.bind(this), false);
this.canvas.addEventListener('touchmove', this.touchMoveListener.bind(this), false);
this.canvas.addEventListener('touchend', this.endListener.bind(this), false);
this.canvas.addEventListener('touchcancel', this.endListener.bind(this), false);
this.canvas.addEventListener('mousedown', this.onMouseStart.bind(this), false);
this.canvas.addEventListener('mousemove', this.mouseMoveListener.bind(this), false);
this.canvas.addEventListener('mouseup', this.endListener.bind(this), false);
this.canvas.addEventListener('mousecancel', this.endListener.bind(this), false);
this.canvas.addEventListener('mouseout', this.endListener.bind(this), false);
}

private touchMoveListener(e: TouchEvent) {
this.setMouse(e.targetTouches[0]);
}

private onMouseStart = (event: any): void => {
private mouseMoveListener(e: MouseEvent) {
this.setMouse(e);
}

private endListener() {
this.buttons[0].press = false;
}

private onMouseStart(event: TouchEvent | MouseEvent) {
event.preventDefault();

let isTouch = false;
if (window['TouchEvent'] && event instanceof TouchEvent) {
if (event instanceof TouchEvent) {
isTouch = true;
this.setMouse((<TouchEvent>event).targetTouches[0]);
} else {
Expand All @@ -58,57 +60,57 @@ export default class MouseListener {
this.resetSpeed = true;
this.buttons[isTouch ? 0 : event.which - 1].press = true;

for (let i = 0; i < this.mouseClickCallbacks.length; i++) {
this.mouseClickCallbacks[i].call(this);
}
};
this.mouseClickCallbacks.forEach((callback) => {
callback();
});
}

private setMouse(event: any): void {
this.mousePos[0] = event.pageX;
this.mousePos[1] = event.pageY;
private setMouse(event: MouseEvent | Touch): void {
this.mousePos.x = event.pageX;
this.mousePos.y = event.pageY;
}

public getNormalizedVelocity(): Float32Array {
return this.mouseVelocity;
public get normalizedVelocity(): Vec2 {
return {...this.mouseVelocity};
}

public get mouseDown(): boolean {
return this.buttons[0].press;
}

public update(): void {
this.normalized[0] = this.mousePos[0] / this.canvas.clientWidth;
this.normalized[1] = this.mousePos[1] / this.canvas.clientHeight;
public click(callback: () => void) {
this.mouseClickCallbacks.push(callback);
}

public update(dt: number): void {
this.normalized.x = this.mousePos.x / this.canvas.clientWidth;
this.normalized.y = this.mousePos.y / this.canvas.clientHeight;

if (this.resetSpeed) {
this.resetSpeed = false;
this.mouseVelocity[0] = 0;
this.mouseVelocity[1] = 0;
this.mouseVelocity.x = 0;
this.mouseVelocity.y = 0;
} else {
this.mouseVelocity[0] = this.normalized[0] - this.previousMousePos[0];
this.mouseVelocity[1] = this.normalized[1] - this.previousMousePos[1];
this.mouseVelocity.x = this.normalized.x - this.previousMousePos.x;
this.mouseVelocity.y = this.normalized.y - this.previousMousePos.y;
}
this.previousMousePos[0] = this.normalized[0];
this.previousMousePos[1] = this.normalized[1];
this.previousMousePos.x = this.normalized.x;
this.previousMousePos.y = this.normalized.y;

// this section makes sure a drag is not used as a click
// when the mouse is released after a press longer than 0.25 sec, it is not a click
for (let i = 0; i < 3; i++) {
const button: MouseButton = this.buttons[i];
button.hit = false;
button.down = false;

if (this.buttons[i].press) {
if (button.downTime === 0) {
button.down = true;
}
button.downTime++;
button.downTime += dt;
} else {
button.hit = button.downTime < 15 && button.oldDown;
button.downTime = 0;
}

button.oldDown = button.press;
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/lib/RotationController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,22 @@ export default class RotationController implements IRotationController {
}

public update(dt: number, rotation: Quat, animated: boolean): Quat {
this.mouseListener.update();
this.mouseListener.update(dt);

// aspect ratio can change
const aspect = this.renderer.aspectRatio;
const z = 0.5 / Math.tan(this.renderer.fov * 0.5);
const fovH = Math.atan2(aspect * 0.5, z) * 2;

if (this.mouseListener.mouseDown) {
const ms = this.mouseListener.getNormalizedVelocity();
const ms = this.mouseListener.normalizedVelocity;
this.lastUserRotateSpeed.x = lerp(
-ms[0] * fovH * (1 / dt),
-ms.x * fovH * (1 / dt),
this.currentRotateSpeed.x,
this.options.inertia,
);
this.lastUserRotateSpeed.y = lerp(
ms[1] * this.renderer.fov * (1 / dt),
ms.y * this.renderer.fov * (1 / dt),
this.currentRotateSpeed.y,
this.options.inertia,
);
Expand Down

0 comments on commit 03d5193

Please sign in to comment.