@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
171 lines (131 loc) • 4.12 kB
JavaScript
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
}
}