UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

260 lines (205 loc) • 7.39 kB
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); }