UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

171 lines (131 loc) 4.12 kB
import { AbstractParticleRenderer } from "../AbstractParticleRenderer.js"; import { DataTexture, FloatType, RGBAFormat } from "three"; import { TextureAtlas } from "../../../../texture/atlas/TextureAtlas.js"; import IdPool from "../../../../../../core/IdPool.js"; import { AtlasPatch } from "../../../../texture/atlas/AtlasPatch.js"; const EMPTY_PATCH = new AtlasPatch(); export class BillboardParticleRenderer extends AbstractParticleRenderer { constructor() { super(); /** * * @type {WebGL2RenderingContext} * @private */ this.__gl = null; /** * Images for billboards are referenced by an unsigned integer. This integer is used for looking up actual UV coordinates for image patch inside the atlas * @type {DataTexture} * @private */ this.__image_lookup_texture = new DataTexture(new Uint8Array(0), 0, 0, RGBAFormat, FloatType); this.__image_lookup_texture.generateMipmaps = false; /** * * @type {number} * @private */ this.__image_atlas_padding = 4; /** * * @type {TextureAtlas} * @private */ this.__image_atlas = new TextureAtlas(); /** * * @type {Map<number, AtlasPatch>} * @private */ this.__image_atlas_patches = new Map(); /** * * @type {IdPool} * @private */ this.__image_ids = new IdPool(); /** * * @type {boolean} * @private */ this.__image_lookup_texture_needs_update = false; } __updateImageLookupTexture() { // clear the flag this.__image_lookup_texture_needs_update = false; } /** * Create a new image slot * @returns {number} ID of newly created image */ createImage() { const id = this.__image_ids.get(); this.__image_atlas_patches.set(id, EMPTY_PATCH); return id; } /** * Remove image * @param {number} id * @returns {boolean} */ deleteImage(id) { if (!this.__image_ids.isUsed(id)) { // ID is not used return false; } this.__image_ids.release(id); /** * * @type {AtlasPatch} */ const patch = this.__image_atlas_patches.get(id); this.__image_atlas_patches.delete(id); this.__image_atlas.remove(patch); return true; } /** * Upload an image into a given slot * @param {number} id Image ID * @param {Sampler2D} data */ uploadImage(id, data) { const existing_patch = this.__image_atlas_patches.get(id); if (existing_patch === undefined) { throw new Error(`No patch data for ID '${id}'`); } if (existing_patch !== EMPTY_PATCH) { this.__image_atlas.remove(existing_patch); } const patch = this.__image_atlas.add(data, this.__image_atlas_padding); this.__image_atlas_patches.set(id, patch); } startup() { const engine = this.engine; } finalize() { // release resources } initialize(engine) { super.initialize(engine); this.__gl = engine.graphics.renderer.getContext(); //initialize the material } render(commands) { this.__image_atlas.update(); if (this.__image_lookup_texture_needs_update) { this.__updateImageLookupTexture(); } commands.forEach(this.__render, this); } /** * * @param {ParticleRenderSpecification} spec * @param {EmitterAttributeData} data * @private */ __render(spec, data) { // TODO upload attribute data into relevant shader slots // TODO upload uniform data into relevant shader slots } }