@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
148 lines (107 loc) • 3.55 kB
JavaScript
import { AbstractRenderAdapter } from "./AbstractRenderAdapter.js";
import { HashMap } from "../../../../../../core/collection/map/HashMap.js";
import { InstancedMeshGroup } from "../../../../geometry/instancing/InstancedMeshGroup.js";
import { ShadedGeometryFlags } from "../../ShadedGeometryFlags.js";
import { StreamDrawUsage } from "three";
import { SGCacheKey } from "./SGCacheKey.js";
const INSTANCED_EQUALITY_FLAGS = ShadedGeometryFlags.CastShadow
| ShadedGeometryFlags.ReceiveShadow
;
/**
* @readonly
* @type {SGCacheKey}
*/
const scratch_key = new SGCacheKey();
export class InstancedRendererAdapter extends AbstractRenderAdapter {
/**
*
* @type {HashMap<SGCacheKey, InstancedMeshGroup>}
* @private
*/
__instanced_meshes = new HashMap();
/**
*
* @type {Set<InstancedMeshGroup>}
* @private
*/
__active_meshes = new Set();
score(geometry, material, instance_count) {
if (instance_count > 16) {
return 1;
} else if (instance_count < 4) {
return -1;
} else {
return 0;
}
}
/**
*
* @param {ShadedGeometry} sg
* @returns {InstancedMeshGroup}
* @private
*/
__get_instanced_mesh(sg) {
scratch_key.fromSG(sg);
// mask out some flags
scratch_key.flags &= INSTANCED_EQUALITY_FLAGS
let im = this.__instanced_meshes.get(scratch_key);
if (im !== undefined) {
return im;
} else {
im = new InstancedMeshGroup();
im.instance_usage = StreamDrawUsage;
im.shrinkFactor = 0; // prevent shrinking as we're essentially rebuilding this geometry frame
im.draw_mode = sg.mode;
im.setMaterial(sg.material);
im.setGeometry(sg.geometry);
im.mesh.castShadow = sg.getFlag(ShadedGeometryFlags.CastShadow);
im.mesh.receiveShadow = sg.getFlag(ShadedGeometryFlags.ReceiveShadow);
this.__instanced_meshes.set(scratch_key.clone(), im);
return im;
}
}
add(sg) {
const mesh = this.__get_instanced_mesh(sg);
const index = mesh.count;
const new_size = index + 1;
if (new_size > mesh.capacity) {
mesh.ensureCapacity(new_size);
}
mesh.setTransformAt(index, sg.transform);
mesh.count = new_size;
this.__active_meshes.add(mesh);
}
/**
*
* @param {THREE.WebGLRenderer} renderer
* @param {CameraView} view
*/
build_start(renderer, view) {
this.clear();
}
build_end() {
const objects = this.__objects;
for (const activeMesh of this.__active_meshes) {
// force underlying geometry to update
activeMesh.setCount(activeMesh.getCount());
activeMesh.requestAttributeUpdate();
objects[this.__object_count++] = activeMesh.mesh;
}
}
clear() {
super.clear();
const meshes = this.__active_meshes;
for (const mesh of meshes) {
mesh.setCount(0);
}
meshes.clear();
}
dispose() {
this.clear();
// release GPU memory
this.__instanced_meshes.forEach((value, key) => {
value.dispose();
});
this.__instanced_meshes.clear();
}
}