UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

236 lines (197 loc) • 6.64 kB
import { Color } from "../../../../../core/color/Color.js"; import { TubeMaterialType } from "./TubeMaterialType.js"; import { assert } from "../../../../../core/assert.js"; import { MatcapMaterialDefinition } from "./MatcapMaterialDefinition.js"; import { CapType } from "./CapType.js"; import { StandardMaterialDefinition } from "./StandardMaterialDefinition.js"; import { BasicMaterialDefinition } from "./BasicMaterialDefinition.js"; import { PathNormalType } from "./PathNormalType.js"; import Vector3 from "../../../../../core/geom/Vector3.js"; const DEFAULT_COLOR = Object.freeze({ r: 1, g: 1, b: 1 }); export class TubePathStyle { constructor() { /** * * @type {Color} */ this.color = new Color(1, 1, 1); /** * @type {TubeMaterialType} */ this.material_type = TubeMaterialType.Unknown; /** * * @type {StandardMaterialDefinition|MatcapMaterialDefinition|BasicMaterialDefinition|null} */ this.material = null; /** * * @type {number} */ this.opacity = 1; /** * * @type {number} */ this.width = 1; /** * * @type {number[]} */ this.shape = build_circle_shape(16); /** * * @type {number[]|Float32Array|null} */ this.shape_normals = null; /** * * @type {number} */ this.resolution = 10; /** * * @type {boolean} */ this.cast_shadow = false; /** * * @type {boolean} */ this.receive_shadow = false; /** * @type {PathNormalType} */ this.path_normal_type = PathNormalType.Automatic; /** * * @type {Vector3} */ this.path_normal = Vector3.up; /** * Which parts of the path to visualise, in normalized offsets * @example [ 0, 1 ] = whole path * @example [ 0, 0.5 ] = first half of the path * @example [ 0.5, 0.6 ] = segment from 50% along the path, to 60% along the path * @example [ 0, 0.1, 0.9, 1] = first 10% of the path, and last 10% of the path * @type {number[]} */ this.path_mask = [0, 1]; /** * @type {CapType} */ this.cap_type = CapType.Flat; } /** * @deprecated * @param {number} v */ set radial_resolution(v) { console.warn(".radial_resolution property is deprecated, use .shape directly instead"); this.shape = build_circle_shape(v); } static fromJSON(j) { const r = new TubePathStyle(); r.fromJSON(j); return r; } /** * * @param {string|{r:number,g:number,b:number}} color * @param material_type * @param material * @param opacity * @param width * @param radial_resolution * @param resolution * @param cast_shadow * @param receive_shadow * @param path_mask * @param cap_type * @param shape * @param path_normal * @param path_normal_type */ fromJSON({ color = DEFAULT_COLOR, material_type, material, opacity = 1, width = 1, /** * @deprecated */ radial_resolution = 16, resolution = 10, cast_shadow = false, receive_shadow = false, path_mask = [0, 1], cap_type = CapType.None, shape, path_normal = Vector3.up, path_normal_type = PathNormalType.Automatic }) { assert.enum(material_type, TubeMaterialType, 'material_type'); assert.isNumber(opacity, 'opacity'); assert.isNumber(width, 'width'); assert.isNumber(resolution, 'resolution'); assert.isBoolean(cast_shadow, 'cast_shadow'); assert.isBoolean(receive_shadow, 'receive_shadow'); assert.defined(path_mask, 'path_mask'); assert.notNull(path_mask, 'path_mask'); assert.greaterThanOrEqual(path_mask.length, 2, 'path_mask length bust be at least 2'); assert.ok(path_mask.length % 2 === 0, 'path_mask length bust be multiple of 2'); assert.enum(cap_type, CapType, 'cap_type'); assert.enum(path_normal_type, PathNormalType, 'path_normal_type'); if (shape === undefined) { // legacy API, using circle assert.isNumber(radial_resolution, 'radial_resolution'); shape = build_circle_shape(radial_resolution); } this.shape = shape; if (typeof color === 'string') { this.color.parse(color); } else { this.color.fromJSON(color); } this.material_type = material_type; this.opacity = opacity; this.width = width; this.resolution = resolution; this.cast_shadow = cast_shadow; this.receive_shadow = receive_shadow; this.path_mask = path_mask; this.cap_type = cap_type; switch (material_type) { case TubeMaterialType.Matcap: this.material = new MatcapMaterialDefinition(); break; case TubeMaterialType.Standard: this.material = new StandardMaterialDefinition(); break; case TubeMaterialType.Basic: this.material = new BasicMaterialDefinition(); break; default: throw new Error(`Unsupported material type '${material_type}'`); } this.material.fromJSON(material); this.path_normal.fromJSON(path_normal); this.path_normal_type = path_normal_type; } } /** * * @param {number} radial_segments * @returns {Float32Array} */ function build_circle_shape(radial_segments) { const shape = new Float32Array(2 * radial_segments); for (let i = 0; i < radial_segments; i++) { const angle = Math.PI * 2 - Math.PI * 2 * (i / radial_segments); const i2 = i * 2; shape[i2] = Math.cos(angle); shape[i2 + 1] = Math.sin(angle); } return shape; }