@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
174 lines (136 loc) • 4.79 kB
JavaScript
import { assert } from "../../../../../core/assert.js";
import {
bvh_query_user_data_overlaps_frustum
} from "../../../../../core/bvh2/bvh3/query/bvh_query_user_data_overlaps_frustum.js";
import { ShadedGeometry } from "../ShadedGeometry.js";
import { ShadedGeometryFlags } from "../ShadedGeometryFlags.js";
import { AbstractRenderAdapter } from "./adapters/AbstractRenderAdapter.js";
import { GenericRendererAdapter } from "./adapters/GenericRendererAdapter.js";
import { InstancedRendererAdapter } from "./adapters/InstancedRendererAdapter.js";
/**
*
* @type {number[]}
*/
const collection_array = [];
/**
* 1 - collect visible meshes
* 2 - figure out how to render a given mesh
*/
export class ShadedGeometryRendererContext {
constructor() {
/**
* @readonly
* @type {AbstractRenderAdapter[]}
*/
this.adapters = [
new GenericRendererAdapter(),
new InstancedRendererAdapter()
];
}
/**
* Performs maintenance on the context, mainly to check the hash tables for changes
* @return {Generator}
*/
* maintain() {
const adapters = this.adapters;
for (let i = 0; i < adapters.length; i++) {
const adapter = adapters[i];
if (adapter === undefined) {
// adapter may disappear between invocations, since this is a continuation-type function
continue;
}
// delegate to adapter's maintenance
yield* adapter.maintain();
}
}
/**
*
* @param {number} index
* @param {AbstractRenderAdapter} adapter
*/
setAdapter(index, adapter) {
assert.isNonNegativeInteger(index, 'index');
assert.defined(adapter, 'adapter');
assert.equal(adapter.isShadedGeometryRenderAdapter, true, 'adapter.isShadedGeometryRenderAdapter !== true');
const adapters = this.adapters;
const existing = adapters[index];
if (existing !== undefined) {
// dispose of existing adapter
existing.dispose();
}
adapters[index] = adapter;
}
/**
*
* @param {number} index
* @returns {boolean}
*/
removeAdapter(index) {
assert.isNonNegativeInteger(index, 'index');
const adapter = this.adapters[index];
if (adapter === undefined) {
return false;
}
delete this.adapters[index];
adapter.dispose();
return true;
}
/**
*
* @param {THREE.Object3D[]} destination
* @param {number} destination_offset
* @param {THREE.WebGLRenderer} renderer
* @param {CameraView} view
* @param {BVH} bvh
* @param {EntityComponentDataset} ecd
*/
collect(destination, destination_offset, renderer, view, bvh, ecd) {
const adapters = this.adapters;
const adapter_count = adapters.length;
let i = 0, j = 0;
for (; i < adapter_count; i++) {
const adapter = adapters[i];
adapter.build_start(renderer, view);
}
// get all meshes
const intersection_count = bvh_query_user_data_overlaps_frustum(collection_array, 0, bvh, view.frustum);
const sg_component_index = ecd.computeComponentTypeIndex(ShadedGeometry);
for (i = 0; i < intersection_count; i++) {
const entity = collection_array[i];
/**
*
* @type {ShadedGeometry}
*/
const sg = ecd.getComponentByIndex(entity, sg_component_index);
if ((sg.flags & ShadedGeometryFlags.Visible) === 0) {
// not visible
continue;
}
if (!sg.material.visible) {
// material is not visible, skip
continue;
}
const adapter = adapters[sg.draw_method];
adapter.add(sg);
}
let additions = 0;
for (i = 0; i < adapter_count; i++) {
const adapter = adapters[i];
adapter.build_end();
const adapter_object_count = adapter.object_count;
for (j = 0; j < adapter_object_count; j++) {
const object3D = adapter.objects[j];
destination[destination_offset + additions] = object3D;
additions++;
}
}
return additions;
}
dispose() {
for (const adapter of this.adapters) {
if (adapter !== undefined) {
adapter.dispose();
}
}
}
}