@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
178 lines (125 loc) • 5.73 kB
JavaScript
import { SurfacePoint3 } from "../../src/core/geom/3d/SurfacePoint3.js";
import Vector2 from "../../src/core/geom/Vector2.js";
import Vector3 from "../../src/core/geom/Vector3.js";
import { obtainTerrain } from "../../src/engine/ecs/terrain/util/obtainTerrain.js";
import { Transform } from "../../src/engine/ecs/transform/Transform.js";
import Mesh from "../../src/engine/graphics/ecs/mesh/Mesh.js";
import { MeshEvents } from "../../src/engine/graphics/ecs/mesh/MeshEvents.js";
import { make_ray_from_viewport_position } from "../../src/engine/graphics/make_ray_from_viewport_position.js";
import BottomLeftResizeHandleView from "../../src/view/elements/BottomLeftResizeHandleView.js";
import ComponentAddAction from "../actions/concrete/ComponentAddAction.js";
import EntityCreateAction from "../actions/concrete/EntityCreateAction.js";
import SelectionAddAction from "../actions/concrete/SelectionAddAction.js";
import SelectionClearAction from "../actions/concrete/SelectionClearAction.js";
import MeshLibraryView from "./library/MeshLibraryView.js";
/**
*
* @param {Editor} editor
*/
export function prepareMeshLibrary(editor) {
let resolveEngine;
const pEngine = new Promise(function (resolve, reject) {
resolveEngine = resolve;
});
/**
*
* @type {Promise<GraphicsEngine>}
*/
const pGraphicsEngine = pEngine.then(function (e) {
return e.graphics;
});
const pRenderer = pGraphicsEngine.then(function (graphicsEngine) {
return graphicsEngine.renderer;
});
const pAssetManager = pEngine.then(e => e.assetManager);
const meshLibraryView = new MeshLibraryView(
editor.meshLibrary,
pAssetManager,
pRenderer
);
function handleDropEvent(event) {
event.stopPropagation();
event.preventDefault();
const dataText = event.dataTransfer.getData('text/json');
if (dataText === "") {
//no data
return;
}
const data = JSON.parse(dataText);
const type = data.type;
if (type !== "Mesh") {
//wrong type
return;
}
const url = data.url;
const engine = editor.engine;
const graphics = engine.graphics;
const position = new Vector2(event.clientX, event.clientY);
graphics.viewport.positionGlobalToLocal(position, position);
const normalizedPosition = new Vector2();
//compute world position for drop
const ray = make_ray_from_viewport_position(engine, position);
const source = ray.origin;
const direction = ray.direction;
const entityManager = engine.entityManager;
const ecd = entityManager.dataset;
const terrain = obtainTerrain(ecd);
const worldPosition = new Vector3();
const mesh = new Mesh();
mesh.castShadow = true;
mesh.receiveShadow = true;
const transform = new Transform();
const actions = editor.actions;
actions.mark('New Mesh Placed from Library');
const entityCreateAction = new EntityCreateAction();
actions.do(entityCreateAction);
const sp3 = new SurfacePoint3();
const hit_found = terrain.raycastFirstSync(sp3, source.x, source.y, source.z, direction.x, direction.y, direction.z);
function handleMeshSetEvent() {
const bb = mesh.boundingBox;
const c0 = new Vector3(bb.x0, bb.y0, bb.z0);
const c1 = new Vector3(bb.x1, bb.y1, bb.z1);
const diagonal = c0.distanceTo(c1);
const offset = direction.clone().multiplyScalar(diagonal);
transform.position.add(offset);
//remove listener
ecd.removeEntityEventListener(entityCreateAction.entity, MeshEvents.DataSet, handleMeshSetEvent);
}
if (hit_found) {
//got a terrain ray hit, set world placement position to that point
worldPosition.copy(sp3.position);
} else {
//set position to the source of the ray pick if there's nothing else available
worldPosition.copy(source);
//wait for mesh to load
ecd.addEntityEventListener(entityCreateAction.entity, MeshEvents.DataSet, handleMeshSetEvent);
}
transform.position.copy(worldPosition);
mesh.url = url;
actions.doMany([
new ComponentAddAction(entityCreateAction.entity, transform),
new ComponentAddAction(entityCreateAction.entity, mesh),
//automatically select newly placed object
new SelectionClearAction(),
new SelectionAddAction([entityCreateAction.entity])
]);
}
function handleDragOverEvent(event) {
event.preventDefault();
}
meshLibraryView.on.linked.add(function () {
resolveEngine(editor.engine);
const viewport = editor.engine.graphics.viewport;
viewport.el.addEventListener('drop', handleDropEvent);
viewport.el.addEventListener('dragover', handleDragOverEvent);
});
meshLibraryView.on.unlinked.add(function () {
const viewport = editor.engine.graphics.viewport;
viewport.el.removeEventListener('drop', handleDropEvent);
viewport.el.removeEventListener('dragover', handleDragOverEvent);
});
meshLibraryView.size.set(400, 400);
const resizeHandleView = new BottomLeftResizeHandleView(meshLibraryView);
meshLibraryView.addChild(resizeHandleView);
return meshLibraryView;
}