227 lines
7.4 KiB
JavaScript
227 lines
7.4 KiB
JavaScript
/*
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
const kMonacoBaseUrl = 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.17.1/min/';
|
|
|
|
const materialList = document.getElementById("material-list");
|
|
const materialDetail = document.getElementById("material-detail");
|
|
const footer = document.getElementsByTagName("footer")[0];
|
|
const shaderSource = document.getElementById("shader-source");
|
|
const matDetailTemplate = document.getElementById("material-detail-template");
|
|
const matListTemplate = document.getElementById("material-list-template");
|
|
|
|
const gMaterialDatabase = {};
|
|
|
|
let gSocket = null;
|
|
let gEditor = null;
|
|
let gCurrentMaterial = "00000000";
|
|
let gCurrentShader = { matid: "00000000", glindex: -1, vkindex: -1, metalindex: -1 };
|
|
let gCurrentSocketId = 0;
|
|
|
|
require.config({ paths: { "vs": `${kMonacoBaseUrl}vs` }});
|
|
|
|
window.MonacoEnvironment = {
|
|
getWorkerUrl: function(workerId, label) {
|
|
return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
|
|
self.MonacoEnvironment = {
|
|
baseUrl: '${kMonacoBaseUrl}'
|
|
};
|
|
importScripts('${kMonacoBaseUrl}vs/base/worker/workerMain.js');`
|
|
)}`;
|
|
}
|
|
};
|
|
|
|
document.querySelector("body").addEventListener("click", (evt) => {
|
|
const anchor = evt.target.closest("a");
|
|
if (!anchor) {
|
|
return;
|
|
}
|
|
|
|
// Handle selection of a material.
|
|
if (anchor.classList.contains("material")) {
|
|
selectMaterial(anchor.dataset.matid);
|
|
return;
|
|
}
|
|
|
|
// Handle selection of a shader.
|
|
if (anchor.classList.contains("shader")) {
|
|
selectShader(anchor.dataset);
|
|
return;
|
|
}
|
|
|
|
});
|
|
|
|
function fetchMaterial(matid) {
|
|
fetch(`api/material?matid=${matid}`).then(function(response) {
|
|
return response.json();
|
|
}).then(function(matInfo) {
|
|
if (matid in gMaterialDatabase) {
|
|
return;
|
|
}
|
|
matInfo.matid = matid;
|
|
gMaterialDatabase[matid] = matInfo;
|
|
for (const shader of matInfo.opengl) fetchShader({glindex: shader.index}, matInfo);
|
|
for (const shader of matInfo.vulkan) fetchShader({vkindex: shader.index}, matInfo);
|
|
for (const shader of matInfo.metal) fetchShader({metalindex: shader.index}, matInfo);
|
|
renderMaterialList();
|
|
});
|
|
}
|
|
|
|
function startSocket() {
|
|
const url = new URL(document.URL)
|
|
const ws = new WebSocket(`ws://${url.host}`);
|
|
|
|
const reconnect = () => {
|
|
gSocket = null;
|
|
setTimeout(() => startSocket(), 3000);
|
|
};
|
|
|
|
// When a new server has come online, ask it what materials it has.
|
|
ws.addEventListener("open", () => {
|
|
footer.innerText = `connection ${gCurrentSocketId}`;
|
|
gCurrentSocketId++;
|
|
|
|
fetch("api/matids").then(function(response) {
|
|
return response.json();
|
|
}).then(function(matInfo) {
|
|
for (matid of matInfo) {
|
|
if (!(matid in gMaterialDatabase)) {
|
|
fetchMaterial(matid);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
ws.addEventListener("close", (e) => {
|
|
footer.innerText = "no connection";
|
|
reconnect();
|
|
});
|
|
|
|
ws.addEventListener("message", event => {
|
|
const matid = event.data;
|
|
fetchMaterial(matid);
|
|
});
|
|
|
|
gSocket = ws;
|
|
}
|
|
|
|
function fetchMaterials() {
|
|
fetch("api/materials").then(function(response) {
|
|
return response.json();
|
|
}).then(function(matJson) {
|
|
for (const matInfo of matJson) {
|
|
if (matInfo.matid in gMaterialDatabase) {
|
|
continue;
|
|
}
|
|
gMaterialDatabase[matInfo.matid] = matInfo;
|
|
for (const shader of matInfo.opengl) fetchShader({glindex: shader.index}, matInfo);
|
|
for (const shader of matInfo.vulkan) fetchShader({vkindex: shader.index}, matInfo);
|
|
for (const shader of matInfo.metal) fetchShader({metalindex: shader.index}, matInfo);
|
|
}
|
|
selectMaterial(matJson[0].matid);
|
|
});
|
|
}
|
|
|
|
function fetchShader(selection, matinfo) {
|
|
let query, target;
|
|
if (selection.glindex >= 0) {
|
|
query = `type=glsl&glindex=${selection.glindex}`;
|
|
target = matinfo.opengl[parseInt(selection.glindex)];
|
|
}
|
|
if (selection.vkindex >= 0) {
|
|
query = `type=spirv&vkindex=${selection.vkindex}`;
|
|
target = matinfo.vulkan[parseInt(selection.vkindex)];
|
|
}
|
|
if (selection.metalindex >= 0) {
|
|
query = `type=glsl&metalindex=${selection.metalindex}`;
|
|
target = matinfo.metal[parseInt(selection.metalindex)];
|
|
}
|
|
fetch(`api/shader?matid=${matinfo.matid}&${query}`).then(function(response) {
|
|
return response.text();
|
|
}).then(function(shaderText) {
|
|
target.text = shaderText;
|
|
});
|
|
}
|
|
|
|
function renderMaterialList() {
|
|
const materials = [];
|
|
for (const matid in gMaterialDatabase) {
|
|
const item = gMaterialDatabase[matid];
|
|
item.classes = matid === gCurrentMaterial ? "active" : "";
|
|
materials.push(item);
|
|
}
|
|
materialList.innerHTML = Mustache.render(matListTemplate.innerHTML, { "material": materials } );
|
|
}
|
|
|
|
function updateClassList(array, indexProperty, selectedIndex) {
|
|
for (let item of array) {
|
|
const active = parseInt(item[indexProperty]) === selectedIndex;
|
|
item.classes = active ? "active" : "";
|
|
}
|
|
}
|
|
|
|
function renderMaterialDetail() {
|
|
const mat = gMaterialDatabase[gCurrentMaterial];
|
|
const ok = mat.matid === gCurrentShader.matid;
|
|
updateClassList(mat.opengl, "index", ok ? parseInt(gCurrentShader.glindex) : -1);
|
|
updateClassList(mat.vulkan, "index", ok ? parseInt(gCurrentShader.vkindex) : -1);
|
|
updateClassList(mat.metal, "index", ok ? parseInt(gCurrentShader.metalindex) : -1);
|
|
materialDetail.innerHTML = Mustache.render(matDetailTemplate.innerHTML, mat);
|
|
}
|
|
|
|
function selectShader(selection) {
|
|
const mat = gMaterialDatabase[gCurrentMaterial];
|
|
let text;
|
|
if (selection.glindex >= 0) text = mat.opengl[parseInt(selection.glindex)].text;
|
|
if (selection.vkindex >= 0) text = mat.vulkan[parseInt(selection.vkindex)].text;
|
|
if (selection.metalindex >= 0) text = mat.metal[parseInt(selection.metalindex)].text;
|
|
if (!text) {
|
|
console.error("Shader source not yet available.");
|
|
return;
|
|
}
|
|
gCurrentShader = selection;
|
|
gCurrentShader.matid = gCurrentMaterial;
|
|
renderMaterialDetail();
|
|
gEditor.setValue(text);
|
|
shaderSource.style.visibility = "visible";
|
|
}
|
|
|
|
function selectMaterial(matid) {
|
|
gCurrentMaterial = matid;
|
|
renderMaterialList();
|
|
renderMaterialDetail();
|
|
}
|
|
|
|
function init() {
|
|
require(["vs/editor/editor.main"], function () {
|
|
gEditor = monaco.editor.create(shaderSource, {
|
|
value: "",
|
|
language: "cpp",
|
|
scrollBeyondLastLine: false,
|
|
readOnly: false,
|
|
minimap: { enabled: false }
|
|
});
|
|
fetchMaterials();
|
|
});
|
|
|
|
Mustache.parse(matDetailTemplate.innerHTML);
|
|
Mustache.parse(matListTemplate.innerHTML);
|
|
|
|
startSocket();
|
|
}
|
|
|
|
init();
|