@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
189 lines (138 loc) • 5.33 kB
JavaScript
import { Mesh, MeshBasicMaterial, NearestFilter, PlaneBufferGeometry } from "three";
import { Cache } from "../../../core/cache/Cache.js";
import { returnOne } from "../../../core/function/returnOne.js";
import { strictEquals } from "../../../core/function/strictEquals.js";
import Vector2 from "../../../core/geom/Vector2.js";
import ObservedValue from "../../../core/model/ObservedValue.js";
import { GameAssetType } from "../../../engine/asset/GameAssetType.js";
import { MinimapWorldLayer } from "./MinimapWorldLayer.js";
export class MinimapTerrainGL extends MinimapWorldLayer {
/**
*
* @param {AssetManager} assetManager
*/
constructor({ assetManager }) {
super();
const textureCache = new Cache({
maxWeight: 2,
keyEqualityFunction: strictEquals,
keyHashFunction: returnOne,
});
const geometry = new PlaneBufferGeometry(1, 1, 1, 1);
const material = new MeshBasicMaterial({ color: 0xFFFFFF });
const mesh = new Mesh(geometry, material);
mesh.rotation.x = -Math.PI * 0.5;
const self = this;
/**
*
* @returns {TerrainPreview}
*/
function getPreview() {
const terrain = self.terrain.getValue();
if (terrain === null) {
return null;
}
/**
*
* @type {TerrainPreview}
*/
const preview = terrain.preview;
return preview;
}
function setTexture(texture) {
material.map = texture;
updateMesh();
// trigger a render request
self.needsRender = true;
}
function updateTexture() {
const url = getPreview().url;
//check cache
const cachedTexture = textureCache.get(url);
if (cachedTexture !== null) {
//use cached texture
setTexture(cachedTexture);
} else {
//get texture from asset manager
assetManager.promise(url, GameAssetType.Texture)
.then(function (asset) {
/**
*
* @type {Texture}
*/
const texture = asset.create();
texture.flipY = true;
// mipmaps are necessary for a decent performance when zooming out of the map
texture.generateMipamps = true;
texture.magFilter = NearestFilter; // don't blur pixels
material.needsUpdate = true;
setTexture(texture);
textureCache.put(url, texture);
});
}
}
function updateMesh() {
const terrain = self.terrain.getValue();
if (terrain === null) {
return null;
}
const resolution = new Vector2(2048, 2048);
if (material.map !== null) {
/**
* @type {Image}
*/
const image = material.map.image;
const naturalWidth = image.naturalWidth;
const naturalHeight = image.naturalHeight;
resolution.set(naturalWidth, naturalHeight);
}
/**
*
* @type {TerrainPreview}
*/
const preview = terrain.preview;
const scale = preview.scale;
const offset = preview.offset;
const mLeft = offset.x * scale.x;
const mTop = offset.y * scale.y;
const nX = resolution.x * scale.x;
const nY = resolution.y * scale.y;
mesh.scale.set(nX, nY, 1);
mesh.position.set(-mLeft + nX / 2, 1, -mTop + nY / 2);
// trigger a render request
self.needsRender = true;
}
this.object = mesh;
/**
*
* @type {ObservedValue<Terrain>}
*/
this.terrain = new ObservedValue(null);
/**
*
* @param {Terrain} terrain
* @param {Terrain} oldTerrain
* @private
*/
this.__setTerrain = function setTerrain(terrain, oldTerrain) {
if (terrain !== null) {
terrain.preview.offset.onChanged.add(updateMesh);
terrain.preview.scale.onChanged.add(updateMesh);
updateMesh();
updateTexture();
}
if (oldTerrain !== null) {
oldTerrain.preview.offset.onChanged.remove(updateMesh);
oldTerrain.preview.scale.onChanged.remove(updateMesh);
}
};
}
startup() {
this.terrain.onChanged.add(this.__setTerrain);
this.__setTerrain(this.terrain.getValue(), null);
}
shutdown() {
this.terrain.onChanged.remove(this.__setTerrain);
this.__setTerrain(null, this.terrain.getValue());
}
}