UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

174 lines (136 loc) 4.79 kB
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(); } } } }