Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Isolate and abstract three.js related code. #50

Merged
merged 14 commits into from
Sep 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,40 @@
## Features

This isn't a ready-to-use game. It's a library of loosely-coupled components that
implement some of Visual Pinball's features.
together implement [Visual Pinball](https://sourceforge.net/projects/vpinball/)'s
player for the web.

Visual Pinball's player can be split into three parts:
The player can be split into three parts:

1. The rendering engine
2. The physics engine
3. The scripting engine

This library allows exporting a VPX file into a [three.js](https://threejs.org/)
scene, which covers the first point. A physics loop is implemented by the `Player`
class. Collision detection and rigid body dynamics is now ported, covering the
second part. Work on the third has begun with the wiring set up and simple
This library provides an abstraction layer for rendering with [three.js](https://threejs.org/),
which covers the first point. A physics loop is implemented by the `Player`
class. Collision detection and rigid body dynamics are fully ported, covering the
second part. Work on scripting has begun with the wiring set up and simple
statements working. More info about how we go about this can be found [here](https://github.com/freezy/vpweb/issues/1).

### Rendering

VPX-JS allows reading a VPX file file and exporting a three.js scene directly
in the browser. However, it also supports export to [GLTF](https://www.khronos.org/gltf/)
files, which is nice, because it allows off-loading the export to a server.
VPX-JS reads Visual Pinball's VPX format and extracts all meshes in VP's internal
format. Using an abstraction layer, any WebGL framework can convert this format
and construct a scene. An adapter for three.js is shipped with this library.

So why use this when Visual Pinball already has an [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file)
export feature? Well, VPX-JS does some more things:
Additionally, VPX-JS supports direct export to [GLTF](https://www.khronos.org/gltf/)
files, which is nice, because it allows off-loading the export to a server. It's
also nice because GLTF allows doing stuff that Visual Pinball's [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file)
export doesn't, for example:

- GLTF is somewhat more powerful than OBJ. It allows us to include materials,
textures and lights in one single file.
- VPX-JS does some optimizations when reading data from the `.vpx` file:
- Include materials, textures and lights in one single file
- Apply optimizations:
- PNG textures with no transparency are converted to JPEG
- PNG textures with transparency are [PNG-crushed](https://en.wikipedia.org/wiki/Pngcrush)
- Meshes are compressed using [Draco](https://google.github.io/draco/)
- It's platform-independent, so you can run it on Linux and MacOS as well.

![image](https://user-images.githubusercontent.com/70426/56841267-0419fc00-688d-11e9-9996-6d84070da392.png)
*A table in the browser using three.js*

### Physics

Expand Down
9 changes: 6 additions & 3 deletions bin/vpt2glb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@

import { existsSync, writeFileSync } from 'fs';
import { basename, dirname, resolve } from 'path';
import { Logger, Table } from '../lib';
import { NodeBinaryReader } from '../lib/io/binary-reader.node';
import { TableExporter } from '../lib/vpt/table/table-exporter';
import { Logger } from '../lib/util/logger';
import { Table } from '../lib/vpt/table/table';

(async () => {

Expand Down Expand Up @@ -90,11 +92,12 @@ import { NodeBinaryReader } from '../lib/io/binary-reader.node';


console.log('Parsing file from %s...', vpxPath);
const vpt = await Table.load(new NodeBinaryReader(vpxPath));
const table = await Table.load(new NodeBinaryReader(vpxPath));
const exporter = new TableExporter(table);
const loaded = Date.now();

console.log('Exporting file to %s...', glbPath);
const glb = await vpt.exportGlb({
const glb = await exporter.exportGlb({

applyTextures,
applyMaterials,
Expand Down
2 changes: 1 addition & 1 deletion bin/vptscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

import { existsSync } from 'fs';
import { resolve } from 'path';
import { Table } from '../lib';
import { NodeBinaryReader } from '../lib/io/binary-reader.node';
import { Table } from '../lib/vpt/table/table';

(async () => {

Expand Down
6 changes: 3 additions & 3 deletions lib/game/ianimatable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { Object3D } from 'three';
import { Table } from '..';
import { IRenderApi } from '../render/irender-api';
import { Table } from '../vpt/table/table';
import { IPlayable } from './iplayable';
import { Player } from './player';
import { PlayerPhysics } from './player-physics';
Expand All @@ -37,7 +37,7 @@ export interface IAnimatable<STATE> extends IPlayable {

getState(): STATE;

applyState(obj: Object3D, table: Table, player: Player, oldState: STATE): void;
applyState<NODE, GEOMETRY, POINT_LIGHT>(obj: NODE, renderApi: IRenderApi<NODE, GEOMETRY, POINT_LIGHT>, table: Table, player: Player, oldState: STATE): void;
}

export interface IAnimation {
Expand Down
6 changes: 3 additions & 3 deletions lib/game/imovable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { Object3D } from 'three';
import { Table } from '..';
import { MoverObject } from '../physics/mover-object';
import { IRenderApi } from '../render/irender-api';
import { ItemState } from '../vpt/item-state';
import { Table } from '../vpt/table/table';
import { IPlayable } from './iplayable';
import { Player } from './player';

Expand All @@ -30,5 +30,5 @@ export interface IMovable<STATE extends ItemState> extends IPlayable {

getState(): STATE;

applyState(obj: Object3D, table: Table, player: Player, oldState: STATE): void;
applyState<NODE, GEOMETRY, POINT_LIGHT>(obj: NODE, renderApi: IRenderApi<NODE, GEOMETRY, POINT_LIGHT>, table: Table, player: Player, oldState: STATE): void;
}
2 changes: 1 addition & 1 deletion lib/game/iplayable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { Table } from '..';
import { Table } from '../vpt/table/table';
import { IItem } from './iitem';
import { Player } from './player';

Expand Down
17 changes: 8 additions & 9 deletions lib/game/irenderable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,28 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { BufferGeometry, Material as ThreeMaterial, MeshStandardMaterial } from 'three';
import { Table } from '..';
import { Meshes } from '../vpt/item-data';
import { IRenderApi } from '../render/irender-api';
import { Material } from '../vpt/material';
import { Mesh } from '../vpt/mesh';
import { VpTableExporterOptions } from '../vpt/table/table-exporter';
import { Table, TableGenerateOptions } from '../vpt/table/table';
import { Texture } from '../vpt/texture';
import { IItem } from './iitem';

export interface IRenderable extends IItem {

getMeshes(table: Table, opts: VpTableExporterOptions): Meshes;
getMeshes<NODE, GEOMETRY, POINT_LIGHT>(table: Table, renderApi: IRenderApi<NODE, GEOMETRY, POINT_LIGHT>, opts: TableGenerateOptions): Meshes<GEOMETRY>;

isVisible(table: Table): boolean;
}

postProcessMaterial?(table: Table, geometry: BufferGeometry, material: MeshStandardMaterial): MeshStandardMaterial | MeshStandardMaterial[];
export interface Meshes<GEOMETRY> {
[key: string]: RenderInfo<GEOMETRY>;
}

export interface RenderInfo {
export interface RenderInfo<GEOMETRY> {
mesh?: Mesh;
geometry?: BufferGeometry;
geometry?: GEOMETRY;
map?: Texture;
normalMap?: Texture;
material?: Material;
threeMaterial?: ThreeMaterial;
}
2 changes: 1 addition & 1 deletion lib/game/player-physics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { Table } from '..';
import { degToRad } from '../math/float';
import { Vertex3D } from '../math/vertex3d';
import { CollisionEvent } from '../physics/collision-event';
Expand All @@ -40,6 +39,7 @@ import { Ball } from '../vpt/ball/ball';
import { BallData } from '../vpt/ball/ball-data';
import { BallState } from '../vpt/ball/ball-state';
import { FlipperMover } from '../vpt/flipper/flipper-mover';
import { Table } from '../vpt/table/table';
import { IBallCreationPosition } from './player';

const SLOW_MO = 1; // the lower, the slower
Expand Down
5 changes: 3 additions & 2 deletions lib/gltf/export-gltf.node.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Scene } from 'three';
import { ParseOptions, VpTableExporterOptions } from '../vpt/table/table-exporter';
import { TableGenerateGltfOptions } from '../vpt/table/table';
import { TableExportOptions } from '../vpt/table/table-exporter';
import { GLTFExporter } from './gltf-exporter';

export function exportGltf(scene: Scene, opts: VpTableExporterOptions, gltfOpts?: ParseOptions) {
export function exportGltf(scene: Scene, opts: TableExportOptions, gltfOpts?: TableGenerateGltfOptions) {
const gltfExporter = new GLTFExporter(Object.assign({}, { embedImages: true, optimizeImages: opts.optimizeTextures }, gltfOpts));
return gltfExporter.parse(scene);
}
8 changes: 4 additions & 4 deletions lib/gltf/gltf-exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
Vector3,
} from 'three';
import { logger } from '../util/logger';
import { ParseOptions } from '../vpt/table/table-exporter';
import { TableGenerateGltfOptions } from '../vpt/table/table';
import {
GltfAnimationSampler,
GltfBufferView,
Expand Down Expand Up @@ -141,7 +141,7 @@ const PATH_PROPERTIES: { [key: string]: string } = {
export class GLTFExporter {

private started = false;
private options: ParseOptions;
private options: TableGenerateGltfOptions;
private byteOffset: number = 0;
private buffers: Buffer[] = [];
private pending: Array<() => Promise<void>> = [];
Expand All @@ -162,8 +162,8 @@ export class GLTFExporter {
},
};

constructor(options?: ParseOptions) {
const DEFAULT_OPTIONS: ParseOptions = {
constructor(options?: TableGenerateGltfOptions) {
const DEFAULT_OPTIONS: TableGenerateGltfOptions = {
binary: false,
optimizeImages: false,
trs: false,
Expand Down
2 changes: 1 addition & 1 deletion lib/gltf/image.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { State } from 'gm';
import * as sharp from 'sharp';
import { Stream } from 'stream';

import { Storage } from '..';
import { Storage } from '../io/ole-doc';
import { logger } from '../util/logger';
import { Binary } from '../vpt/binary';
import { IImage } from './image';
Expand Down
6 changes: 3 additions & 3 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

export { Table } from './vpt/table/table';
export { OleCompoundDoc, Storage } from './io/ole-doc';
export { Logger } from './util/logger';
// export { Table } from './vpt/table/table';
// export { OleCompoundDoc, Storage } from './io/ole-doc';
// export { Logger } from './util/logger';
23 changes: 0 additions & 23 deletions lib/math/matrix3d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { Matrix4, Object3D } from 'three';
import { Pool } from '../util/object-pool';
import { f4, fr } from './float';

Expand Down Expand Up @@ -149,28 +148,6 @@ export class Matrix3D {
return this;
}

public applyToObject3D(obj: Object3D) {
if (!obj.matrix) {
obj.matrix = new Matrix4();
} else {
obj.matrix.identity();
}
const m4 = Pool.GENERIC.Matrix4.get();
this.applyToThreeMatrix4(m4);
obj.applyMatrix(m4);
Pool.GENERIC.Matrix4.release(m4);
}

public applyToThreeMatrix4(matrix: Matrix4): Matrix4 {
matrix.set(
this._11, this._21, this._31, this._41,
this._12, this._22, this._32, this._42,
this._13, this._23, this._33, this._43,
this._14, this._24, this._34, this._44,
);
return matrix;
}

private static multiplyMatrices(a: Matrix3D, b: Matrix3D, recycle = false): Matrix3D {
/* istanbul ignore else: we always recycle now */
const result = recycle ? Matrix3D.claim() : new Matrix3D();
Expand Down
8 changes: 4 additions & 4 deletions lib/physics/hit-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { Table } from '..';
import { Event } from '../game/event';
import { EventProxy } from '../game/event-proxy';
import { PlayerPhysics } from '../game/player-physics';
Expand All @@ -26,6 +25,7 @@ import { FRect3D } from '../math/frect3d';
import { Vertex3D } from '../math/vertex3d';
import { Ball } from '../vpt/ball/ball';
import { IPhysicalData } from '../vpt/item-data';
import { Table } from '../vpt/table/table';
import { CollisionEvent } from './collision-event';
import { CollisionType } from './collision-type';

Expand Down Expand Up @@ -173,9 +173,9 @@ export abstract class HitObject {
public applyPhysics(data: IPhysicalData, table: Table) {
const mat = table.getMaterial(data.szPhysicsMaterial);
if (mat && !data.overwritePhysics) {
this.setElasticity(mat.fElasticity, mat.fElasticityFalloff);
this.setFriction(mat.fFriction);
this.setScatter(degToRad(mat.fScatterAngle));
this.setElasticity(mat.elasticity, mat.elasticityFalloff);
this.setFriction(mat.friction);
this.setScatter(degToRad(mat.scatterAngle));

} else {
this.setElasticity(data.elasticity, data.elasticityFalloff);
Expand Down
18 changes: 18 additions & 0 deletions lib/render/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Rendering

VPX-JS abstracts the rendering layer and delegates it to a third party WebGL
framework. That means it doesn't come with a ready-to-use web application but
only provides tools and APIs that make it easy to integrate.

The `IRenderApi` interface is the link between the framework and the VPX-JS
engine. It makes the following assumptions:

- A mesh consists of a bunch of vertices together with a set of indices.
- Meshes can be grouped together, and their transformation matrix is relative
to its parent.
- The framework's materials are using physically-based rendering using the
Metallic-Roughness workflow.

VPX-JS ships with [three.js](https://threejs.org) and [Babylon.js](https://www.babylonjs.com/)
adapters. What you basically do is create your scene, instantiate the respective
adapter implementing `ÌRenderAPi` and use it to update the scene every frame.
Loading