quackscape/assets/js/scene.js
Kumi 429975833a
feat: integrate aframe-click-drag and improve
skybox handling

Introduced the @kumitterer/aframe-click-drag-component for enhanced
interaction within the VR editor, enabling objects to be click-draggable
except for the skybox element. This selective application of click-drag
functionality enriches user experience by preserving the intended static
background. Additionally, refactored the A-Frame dependency management,
ensuring a coherent and up-to-date project structure.

- Upgraded and consolidated A-Frame imports across JavaScript files for
consistency.
- Excluded the "A-SKY" element from click-drag attributes to avoid
unintended interactions with the scene background.
- Added deep-equal package for enhanced object comparison
functionalities.

This update aims to streamline user interactions within 3D scenes,
offering more intuitive and immersive navigation capabilities.
2024-03-27 19:54:48 +01:00

165 lines
4.6 KiB
JavaScript

import { getScene } from "./api";
import { loadSidebar } from "./scene/sidebar";
import { loadNavbar } from "./scene/navbar";
import aframe from "aframe";
import { Dropdown, Collapse } from "bootstrap";
import "../scss/frontend.scss";
import "../css/scene.css";
// Detect iOS devices
// There is probably a better way to handle issues there, but...
var iOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
// Define the <quackscape-scene> element
class QuackscapeScene extends HTMLElement {
connectedCallback() {
// When one is created, automatically load the scene
this.scene = this.getAttribute("scene");
this.embedded = this.getAttribute("embedded") != undefined;
this.x = this.getAttribute("x") | 0;
this.y = this.getAttribute("y") | 0;
this.z = this.getAttribute("z") | 0;
this.navbar = this.getAttribute("navbar") != undefined;
this.sidebar = this.getAttribute("sidebar") != undefined;
loadScene(this.scene, this.x, this.y, this.z, this, this.embedded);
if (this.navbar) {
loadNavbar(this.scene, this);
}
else if (this.sidebar) {
loadSidebar(this.scene, this);
}
}
}
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
});
customElements.define("quackscape-scene", QuackscapeScene);
// Function to load a scene into a destination object
// x and y signify the initial looking direction, -1 for the scene's default
async function loadScene(
scene_id,
x = -1,
y = -1,
z = -1,
destination = null,
embedded = false
) {
// Get WebGL maximum texture size
var canvas = document.createElement("canvas");
var gl =
canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (!gl) {
alert("Unable to initialize WebGL. Your browser may not support it.");
return;
}
var maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
if (iOS) {
maxTextureSize = Math.min(8192, maxTextureSize);
}
// Get scene information from API
getScene(scene_id).then((response) => {
var scene = response.obj;
// Get largest image that will fit in the texture size from scene.resolutions
// First, order the resolutions by width
var resolutions = scene.base_content.resolutions.sort(
(a, b) => b.width - a.width
);
// Then, find the first resolution that is less than or equal to the max texture size
var content = resolutions.find(
(resolution) => resolution.width <= maxTextureSize
);
// Select a destination element if not specified
if (!destination) {
destination = document.getElementsByTagName("quackscape-scene")[0];
}
destination.setAttribute("id", scene_id);
// Start by removing any existing scenes
var scenes = document.getElementsByTagName("a-scene");
if (scenes.length > 0) {
scenes[0].remove();
}
// Now, build the scene element
var a_scene = document.createElement("a-scene");
a_scene.setAttribute("cursor", "rayOrigin: mouse");
if (embedded) {
a_scene.setAttribute("embedded", "embedded");
}
// Create a-camera element
var rig = document.createElement("a-entity");
rig.setAttribute("id", "rig");
// Rotate camera if requested
if (x != -1 && y != -1 && z != -1) {
rig.setAttribute("rotation", x + " " + y + " " + z);
}
var camera = document.createElement("a-camera");
camera.setAttribute("wasd-controls-enabled", "false"); // TODO: Find a more elegant way to disable z axis movement
rig.appendChild(camera);
a_scene.appendChild(rig);
// Create a-assets element
var assets = document.createElement("a-assets");
a_scene.appendChild(assets);
// Add background image as sky
var sky = document.createElement("a-sky");
sky.setAttribute("src", "#" + content.id);
a_scene.appendChild(sky);
// Add img element to assets
var background = document.createElement("img");
background.setAttribute("id", content.id);
background.setAttribute("src", content.file);
assets.appendChild(background);
// Add elements to scene
scene.elements.forEach((element) => {
var node = document.createElement(element.data.tag);
node.setAttribute("id", element.data.id);
for (const [key, value] of Object.entries(element.data.attributes)) {
node.setAttribute(key, value);
}
// Add node to scene
a_scene.appendChild(node);
});
destination.appendChild(a_scene);
// Dispatch a signal for the editor to pick up
const loaded_event = new CustomEvent("loadedQuackscapeScene");
document.dispatchEvent(loaded_event);
});
}
window.loadScene = loadScene;
window.aframe = aframe;
export { loadScene };