@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
150 lines (111 loc) • 3.96 kB
JavaScript
import Vector3 from "../../../../../core/geom/Vector3.js";
import Entity from "../../../../ecs/Entity.js";
import { EventType } from "../../../../ecs/EventType.js";
import Renderable from "../../../../ecs/renderable/Renderable.js";
import { RenderableFlags } from "../../../../ecs/renderable/RenderableFlags.js";
import { Transform } from "../../../../ecs/transform/Transform.js";
import ThreeFactory from "../../../three/ThreeFactory.js";
import {
RIBBON_ATTRIBUTE_ADDRESS_AGE,
RIBBON_ATTRIBUTE_ADDRESS_UV_OFFSET
} from "../../../trail/x/ribbon_attributes_spec.js";
import { RibbonX } from "../../../trail/x/RibbonX.js";
export class RibbonPathBuilder {
constructor() {
/**
*
* @type {RibbonPathStyle|null}
*/
this.style = null;
/**
*
* @type {Path|null}
*/
this.path = null;
/**
*
* @type {RibbonXPlugin|null}
*/
this.plugin = null;
}
/**
*
* @param {RibbonPathStyle} style
*/
setStyle(style) {
this.style = style;
}
/**
*
* @param {Path} path
*/
setPath(path) {
this.path = path;
}
/**
*
* @param {RibbonXPlugin} plugin
*/
setPlugin(plugin) {
this.plugin = plugin;
}
/**
*
* @param {Entity[]} destination
*/
build(destination) {
const path = this.path;
const pointCount = path.getPointCount();
/**
*
* @type {RibbonPathStyle|null}
*/
const style = this.style;
const ribbon_count_count = pointCount * style.resolution;
const ribbon = new RibbonX();
ribbon.buildGeometry();
ribbon.setCount(ribbon_count_count);
const v3 = new Vector3();
const path_total_length = path.computeLength();
for (let i = 0; i < ribbon_count_count; i++) {
const f = i / (ribbon_count_count - 1);
path.sample(v3, f * path_total_length);
ribbon.setPointColor(i, 255, 255, 255);
ribbon.setPointPosition(i, v3.x, v3.y, v3.z);
ribbon.setPointThickness(i, style.thickness);
ribbon.setPointAttribute_Scalar(i, RIBBON_ATTRIBUTE_ADDRESS_UV_OFFSET, f);
ribbon.setPointAlpha(i, 0.5);
ribbon.setPointAttribute_Scalar(i, RIBBON_ATTRIBUTE_ADDRESS_AGE, 0);
}
if (pointCount > 0) {
// write first position again to ensure all segments have correct direction
path.sample(v3, 0);
ribbon.setPointPosition(0, v3.x, v3.y, v3.z);
}
const plugin = this.plugin;
const engine = plugin.engine;
const graphics = engine.graphics;
const geometry = ribbon.getGeometry();
const material = plugin.obtain_material_x(style.material);
const mesh = ThreeFactory.createMesh(geometry, material);
const renderable = new Renderable(mesh);
renderable.clearFlag(RenderableFlags.BoundingBoxNeedsUpdate);
ribbon.computeBoundingBox(renderable.boundingBox);
const entityBuilder = new Entity()
.add(renderable)
.add(new Transform());
function setResolution() {
material.uniforms.resolution.value.copy(graphics.viewport.size);
}
function handleEntityRemoved() {
graphics.viewport.size.onChanged.remove(setResolution);
}
entityBuilder.on.built.add(() => {
// set resolution
setResolution();
graphics.viewport.size.onChanged.add(setResolution);
entityBuilder.addEventListener(EventType.EntityRemoved, handleEntityRemoved);
});
destination.push(entityBuilder);
}
}