@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
196 lines (140 loc) • 5.26 kB
JavaScript
import { ClampToEdgeWrapping, DataTexture, NearestFilter, RedIntegerFormat, UnsignedIntType } from "three";
import { assert } from "../../../../core/assert.js";
import { UINT32_MAX } from "../../../../core/binary/UINT32_MAX.js";
import { compose_tile_address } from "./tile/compose_tile_address.js";
import { decompose_finger_print } from "./tile/decompose_finger_print.js";
const EMPTY_TILE = UINT32_MAX;
/*
ENCODING:
22 bit : slot index
10 bit : tile mip
*/
/**
* Represents entire mip pyramid of tiles, where each tile slot points to an actual resident tile
*/
export class VirtualTextureMemoryMapping {
/**
* In tiles
* @type {number}
*/
get max_mip_level(){
return this.
}
new Uint32Array(1),
1,
1,
RedIntegerFormat,
UnsignedIntType
)
get texture() {
return this.
}
constructor() {
const texture = this.
texture.name = "Virtual Texture / Dereference Mapping"
texture.unpackAlignment = 1;
texture.format = RedIntegerFormat;
texture.type = UnsignedIntType;
texture.internalFormat = "R32UI";
texture.generateMipmaps = false;
texture.wrapS = ClampToEdgeWrapping;
texture.wrapT = ClampToEdgeWrapping;
texture.magFilter = NearestFilter;
texture.minFilter = NearestFilter;
}
/**
*
* @param {number} resolution in tiles
*/
set resolution(resolution) {
assert.isNonNegativeInteger(resolution, 'resolution');
if (this.
return;
}
this.
//max mip
const max_mip_level = Math.log2(resolution);
const desired_size = compose_tile_address(max_mip_level + 1, 0, 0);
const texture_dimension = Math.ceil(Math.sqrt(desired_size));
const size = texture_dimension*texture_dimension;
this.
const arrayBuffer = new ArrayBuffer(size * 4);
this.
const texture = this.
texture.dispose();
texture.image.data = this.
texture.image.width = texture_dimension;
texture.image.height = texture_dimension;
texture.needsUpdate = true;
}
get resolution() {
return this.
}
/**
*
* @param {VirtualTexturePage} page
*/
set residency(page) {
const tiles = page.resident_tiles;
const tile_count = tiles.length;
// clear pyramid
const pyramid = this.
pyramid.fill(EMPTY_TILE);
// fill by residence
for (let i = 0; i < tile_count; i++) {
const tile = tiles[i];
const fingerPrint = tile.finger_print;
const { mip, x, y } = decompose_finger_print(fingerPrint);
const address = compose_tile_address(mip, x, y);
const encoded =
(tile.page_slot & 0x3FFFFF)
| ((mip & 0x3FF) << 22) //mip
;
pyramid[address] = encoded;
}
// back-fill empty slots
for (let mip = 1; mip <= this.
const mip_resolution = 1 << mip;
for (let y = 0; y < mip_resolution; y++) {
for (let x = 0; x < mip_resolution; x++) {
const tile_address = compose_tile_address(mip, x, y);
if (pyramid[tile_address] !== EMPTY_TILE) {
// page is filled, all is good, move on
continue;
}
const parent_mip = mip - 1;
const parent_x = x >>> 1;
const parent_y = y >>> 1;
const parent_tile_address = compose_tile_address(parent_mip, parent_x, parent_y);
const parent_encoded_tile = pyramid[parent_tile_address];
// decode parent tile
const tile_index = (parent_encoded_tile) & 0x3FFFFF
const tile_mip = (parent_encoded_tile >> 22) & 0x3FF
// swap in parent tile
const encoded_tile =
(tile_index)
| (tile_mip << 22)
;
pyramid[tile_address] = encoded_tile;
}
}
}
// request texture update
this.
}
getTileMetadata(x,y,mip){
const tile_address = compose_tile_address(mip, x, y);
const encoded_tile = this.
return {
slot: encoded_tile & 0x3FFFFF,
mip: ((encoded_tile >> 22) & 0x3FF)
};
}
dispose() {
this.
}
}