@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
260 lines (205 loc) • 7.39 kB
JavaScript
import { EngineConfiguration } from "../../src/engine/EngineConfiguration.js";
import { EngineHarness } from "../../src/engine/EngineHarness.js";
import { GameAssetType } from "../../src/engine/asset/GameAssetType.js";
import { TextureAssetLoader } from "../../src/engine/asset/loaders/texture/TextureAssetLoader.js";
import Vector3 from "../../src/core/geom/Vector3.js";
import Entity from "../../src/engine/ecs/Entity.js";
import Terrain from "../../src/engine/ecs/terrain/ecs/Terrain.js";
import { ImageRGBADataLoader } from "../../src/engine/asset/loaders/image/ImageRGBADataLoader.js";
import TerrainSystem from "../../src/engine/ecs/terrain/ecs/TerrainSystem.js";
import Water from "../../src/engine/graphics/ecs/water/Water.js";
import {
AmbientOcclusionPostProcessEffect
} from "../../src/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js";
import { TerrainLayer } from "../../src/engine/ecs/terrain/ecs/layers/TerrainLayer.js";
import Mesh from "../../src/engine/graphics/ecs/mesh/Mesh.js";
import { Transform } from "../../src/engine/ecs/transform/Transform.js";
import { MeshSystem } from "../../src/engine/graphics/ecs/mesh/MeshSystem.js";
import { url_to_data_url } from "../../src/core/binary/url_to_data_url.js";
import ButtonView from "../../src/view/elements/button/ButtonView.js";
import {downloadAsFile} from "../../src/core/binary/downloadAsFile.js";
const HEIGHT_RANGE = 64;
const eh = new EngineHarness();
/**
*
* @param {Sampler2D} source
* @param {Terrain} terrain
*/
function scale_terrain_heights(source, terrain) {
const source_height_data = source.data;
const sampler_pixel_count = source_height_data.length;
const terrain_height_data = terrain.samplerHeight.data;
let divisor;
if (source_height_data instanceof Uint8Array) {
divisor = 255;
} else if (source_height_data instanceof Uint16Array) {
divisor = 65536 - 1;
}
for (let i = 0; i < sampler_pixel_count; i++) {
const source_v = source_height_data[i];
const b0 = source_v & 0xFF;
const b1 = (source_v >> 8) & 0xFF;
let rotated_v;
rotated_v = b1 | (b0 << 8);
terrain_height_data[i] = (rotated_v / divisor) * HEIGHT_RANGE
}
}
/**
*
* @param {Engine} engine
*/
async function main(engine) {
const TERRAIN_SIZE_X = 1024;
const TERRAIN_SIZE_Y = 512;
await EngineHarness.buildBasics({
engine,
enableWater: false,
enableTerrain: false,
focus: new Vector3(250, 40, 128),
yaw: -Math.PI,
pitch: 0.91,
distance: 100
});
/**
*
* @type {EntityComponentDataset}
*/
const ecd = engine.entityManager.dataset;
const terrain = new Terrain();
terrain.size.set(TERRAIN_SIZE_X / 4, TERRAIN_SIZE_Y / 4);
terrain.resolution = 4;
terrain.gridScale = 2;
terrain.splat.resize(TERRAIN_SIZE_X, TERRAIN_SIZE_Y, 3);
// load height map
const am = engine.assetManager;
/**
*
* @type {Sampler2D}
*/
const sampler = await load_sampler('moicon/23_Nov_21_Skogplanter/01/splat_height_2.png', am);
async function load_splat_layer(path, index) {
const sampler = await load_sampler(path, am);
terrain.splat.writeLayerFromSampler(sampler, index, 0);
}
await load_splat_layer("moicon/23_Nov_21_Skogplanter/01/splat_green.png", 0);
await load_splat_layer("moicon/23_Nov_21_Skogplanter/01/splat_dirt.png", 1);
await load_splat_layer("moicon/23_Nov_21_Skogplanter/01/splat_stone.png", 2);
terrain.samplerHeight.resize(sampler.width, sampler.height);
scale_terrain_heights(sampler, terrain);
terrain.layers.resolution.set(1024, 1024);
terrain.layers.addLayer(TerrainLayer.from(
"moicon/23_Nov_21_Skogplanter/01/textures/Grass_2.png",
20,
20
));
terrain.layers.addLayer(TerrainLayer.from(
"moicon/23_Nov_21_Skogplanter/01/textures/Ground_1_dark.png",
20,
20
));
terrain.layers.addLayer(TerrainLayer.from(
"moicon/23_Nov_21_Skogplanter/01/textures/Sand_01.png",
20,
20
));
terrain.build(am);
const water = new Water();
water.level.set(5);
water.shoreDepthTransition.set(0.1, 0.3);
water.scattering.set(3);
new Entity()
.add(terrain)
// .add(water)
.build(ecd);
await terrain.buildLightMap(1);
const transform = Transform.fromJSON({
position: new Vector3(256, 45, 128),
scale: new Vector3(0.54, 0.54, 0.54)
});
load_gltf("moicon/23_Nov_21_Skogplanter/02/model.gltf", engine, transform);
// load_gltf("moicon/23_Nov_21_Skogplanter/03/model.gltf", engine, transform);
// load_gltf("moicon/23_Nov_21_Skogplanter/04/model.gltf", engine, transform);
engine.gui.view.addChild(new ButtonView({
name: 'Download',
async action() {
for (const layer of terrain.layers.layers.data) {
// embed textures
layer.textureDiffuseURL = await url_to_data_url(layer.textureDiffuseURL);
}
// we wrap the terrain data into "component json" format that meep editor recognizes to make this compatible with the standalone terrain editor
const json_payload = {
type: "Terrain",
data: terrain.toJSON()
};
downloadAsFile(
JSON.stringify(json_payload),
'terrain.json'
);
},
css: {
bottom: '4px',
left: '4px',
position: 'absolute',
background: 'white',
border: '1px solid black',
padding: '2px',
pointerEvents: 'auto'
}
}));
}
/**
*
* @param {EngineHarness} harness
*/
async function init(harness) {
const engine = eh.engine;
await makeConfig(engine).apply(engine);
await eh.initialize();
main(engine);
}
init(eh);
/**
*
* @param {Engine} engine
* @return {EngineConfiguration}
*/
function makeConfig(engine) {
const r = new EngineConfiguration();
// configure engine here, add systems, loaders etc.
r.addLoader(GameAssetType.Texture, new TextureAssetLoader());
r.addLoader(GameAssetType.Image, new ImageRGBADataLoader());
r.addSystem(new TerrainSystem(engine.graphics, engine.assetManager));
r.addSystem(new MeshSystem(engine));
r.addPlugin(AmbientOcclusionPostProcessEffect);
return r;
}
/**
*
* @param {string} path
* @param {AssetManager} am
*/
async function load_sampler(path, am) {
const asset = await am.promise(path, 'image');
/**
*
* @type {Sampler2D}
*/
const sampler = asset.create();
return sampler;
}
/**
*
* @param {string} path
* @param {Engine} engine
* @param {Transform} transform
*/
async function load_gltf(path, engine, transform) {
const em = engine.entityManager;
const ecd = em.dataset;
new Entity()
.add(Mesh.fromJSON({
url: path
}))
.add(transform)
.build(ecd);
}