Compare commits

..

No commits in common. "9d6c8b6888a3ee3be2932dcff3a709503e8eb105" and "b1122bdbf56e115d9abbde81da2c5f13f0532bc9" have entirely different histories.

9 changed files with 59 additions and 296 deletions

View File

@ -1,60 +0,0 @@
const controlGrid = document.getElementById("control-parent");
function parseColor(c)
{
const groups = c.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/i);
if (groups == null) {
throw new Error("invalid color", c);
} else {
return [parseInt(groups[1], 16), parseInt(groups[2], 16), parseInt(groups[3], 16)];
}
}
class ColorInput {
constructor(label, defaultValue)
{
const parent = controlGrid;
const labelE = document.createElement("label");
labelE.innerHTML = label;
const inputE = document.createElement("input");
inputE.type = "color";
inputE.className = "span-2";
const rowE = document.createElement("row");
const sepE = document.createElement("row-separator");
rowE.appendChild(labelE);
rowE.appendChild(inputE);
parent.appendChild(rowE);
parent.appendChild(sepE);
this.label = label;
this.input = inputE;
this.lastValue = undefined;
const storageValue = localStorage.getItem(this.label);
if (storageValue !== null) {
this.input.value = storageValue;
} else {
this.input.value = defaultValue;
}
this.update();
}
update()
{
const rawValue = this.input.value;
if (rawValue !== this.lastValue) {
this.lastValue = rawValue;
localStorage.setItem(this.label, rawValue);
}
return parseColor(rawValue);
}
};
export { ColorInput };

47
font.js
View File

@ -110,18 +110,6 @@ class FontRenderer {
} }
} }
font_layout__draw(s)
{
const length = Math.min(s.length, this.maxStringLength - 1);
for (let i = 0; i < length; i++) {
const c = s.charCodeAt(i) % 256;
this.stringBuffer[i] = c;
}
this.stringBuffer[length] = 0;
this.exports.font_layout__draw(this.fontLayoutAddress, this.stringBufferAddress);
}
constructor(device, canvasFormat, viewUniformBuffer, wgsl, module, fontBufferSrc) constructor(device, canvasFormat, viewUniformBuffer, wgsl, module, fontBufferSrc)
{ {
const label = "font"; const label = "font";
@ -139,12 +127,6 @@ class FontRenderer {
this.maxGlyphs = 1024; this.maxGlyphs = 1024;
this.fontLayoutAddress = this.exports.font_layout__create(this.fontBufferAddress, this.maxGlyphs); this.fontLayoutAddress = this.exports.font_layout__create(this.fontBufferAddress, this.maxGlyphs);
// text buffer
this.maxStringLength = 1024;
this.stringBufferAddress = this.exports.mem_alloc(this.maxStringLength);
this.stringBuffer = new Uint8Array(this.module.memory.buffer, this.stringBufferAddress);
this.lastString = undefined;
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// shader module // shader module
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -275,7 +257,7 @@ class FontRenderer {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
this.sliders = makeSliders(); this.sliders = makeSliders();
this.sliderArray = new Float32Array(4 * 6); this.sliderArray = new Float32Array(4 * 4);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// buffers // buffers
@ -299,21 +281,6 @@ class FontRenderer {
update(device, frameNumber) update(device, frameNumber)
{ {
const configuration = updateSliders(this.sliders);
//////////////////////////////////////////////////////////////////////
// string draw
//////////////////////////////////////////////////////////////////////
if (this.lastString === undefined || this.lastString !== configuration.text) {
this.lastString = configuration.text;
this.font_layout__draw(configuration.text);
}
//////////////////////////////////////////////////////////////////////
// layout buffer
//////////////////////////////////////////////////////////////////////
this.instanceCount = this.exports.font_layout__layout_buffer_index(this.fontLayoutAddress); this.instanceCount = this.exports.font_layout__layout_buffer_index(this.fontLayoutAddress);
const layoutBufferSize = this.instanceCount * 4 * 4; const layoutBufferSize = this.instanceCount * 4 * 4;
@ -324,6 +291,8 @@ class FontRenderer {
// sliders // sliders
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
const configuration = updateSliders(this.sliders);
this.sliderArray[0] = configuration.mode; this.sliderArray[0] = configuration.mode;
this.sliderArray[1] = configuration.scale; this.sliderArray[1] = configuration.scale;
this.sliderArray[2] = configuration.translateX; this.sliderArray[2] = configuration.translateX;
@ -344,14 +313,6 @@ class FontRenderer {
this.sliderArray[14] = configuration.outlineThreshold; this.sliderArray[14] = configuration.outlineThreshold;
this.sliderArray[15] = configuration.outlineScale; this.sliderArray[15] = configuration.outlineScale;
this.sliderArray[16] = configuration.insideColor[0] / 255.0;
this.sliderArray[17] = configuration.insideColor[1] / 255.0;
this.sliderArray[18] = configuration.insideColor[2] / 255.0;
this.sliderArray[20] = configuration.outlineColor[0] / 255.0;
this.sliderArray[21] = configuration.outlineColor[1] / 255.0;
this.sliderArray[22] = configuration.outlineColor[2] / 255.0;
device.queue.writeBuffer(this.frames[frameNumber].configurationBuffer, 0, device.queue.writeBuffer(this.frames[frameNumber].configurationBuffer, 0,
this.sliderArray); this.sliderArray);
@ -381,6 +342,8 @@ async function loadFont(device, canvasFormat, viewUniformBuffer, module)
const renderer = new FontRenderer(device, canvasFormat, viewUniformBuffer, fontWgsl, module, liberationBuffer); const renderer = new FontRenderer(device, canvasFormat, viewUniformBuffer, fontWgsl, module, liberationBuffer);
module.instance.exports.font_layout__draw(renderer.fontLayoutAddress);
return renderer; return renderer;
} }

View File

@ -26,9 +26,6 @@ struct Config {
supersampleOffset: f32, supersampleOffset: f32,
outlineThreshold: f32, outlineThreshold: f32,
outlineScale: f32, outlineScale: f32,
insideColor: vec4f,
outlineColor: vec4f,
}; };
struct GlyphBuffer { struct GlyphBuffer {
@ -157,8 +154,8 @@ const offsets = array(
fn supersampleColor(texture: vec2f, s: vec2f, p: vec2f) -> vec4f fn supersampleColor(texture: vec2f, s: vec2f, p: vec2f) -> vec4f
{ {
let insideColor = vec4f(config.insideColor.xyz, 1); let insideColor = vec4f(1, 1, 1, 1);
let outlineColor = vec4f(config.outlineColor.xyz, 1); let outlineColor = vec4f(0, 0, 0, 1);
let outsideColor = vec4f(0, 0, 0, 0); let outsideColor = vec4f(0, 0, 0, 0);
let dx = dpdx(texture.x * s.x); let dx = dpdx(texture.x * s.x);
@ -226,13 +223,11 @@ fn fragmentMain(input: VertexOutput) -> FragmentOutput
var output: FragmentOutput; var output: FragmentOutput;
if (config.mode == 1) { if (config.mode == 0) {
output.color = subpixelColor(input.texture, s, p); output.color = subpixelColor(input.texture, s, p);
} else { } else {
output.color = supersampleColor(input.texture, s, p); output.color = supersampleColor(input.texture, s, p);
} }
output.color = vec4f(output.color.xyz / output.color.w, output.color.w);
return output; return output;
} }

View File

@ -1,15 +1,13 @@
import { Slider } from "./slider.js" import { Slider } from "./slider.js"
import { Select } from "./select.js" import { Select } from "./select.js"
import { RowHeader } from "./row-header.js" import { RowHeader } from "./row-header.js"
import { TextInput } from "./text-input.js"
import { ColorInput } from "./color-input.js"
function makeSliders() function makeSliders()
{ {
const sliders = { const sliders = {
subpixelOptions: new RowHeader("global options"), subpixelOptions: new RowHeader("global options"),
mode: new Select("mode", ["supersampling", "subpixel"]), mode: new Select("mode", ["subpixel", "supersampling"]),
scale: new Slider("scale", 0.0, 0.05), scale: new Slider("scale", 0.0, 0.01),
translateX: new Slider("translate x", -1, 1), translateX: new Slider("translate x", -1, 1),
translateY: new Slider("translate y", -1, 1), translateY: new Slider("translate y", -1, 1),
multisampleCount: new Slider("multisampleCount", 1, 4, 1), multisampleCount: new Slider("multisampleCount", 1, 4, 1),
@ -17,10 +15,8 @@ function makeSliders()
distanceThreshold: new Slider("distance threshold", 0.25, 0.75), distanceThreshold: new Slider("distance threshold", 0.25, 0.75),
distanceScale: new Slider("distance scale", 0.0, 20.0), distanceScale: new Slider("distance scale", 0.0, 20.0),
aliasingEnable: new Slider("aliasing enable", 0, 1, 1), aliasingEnable: new Slider("aliasing enable", 0, 1, 1),
//rampMin: new Slider("ramp min", 0, 1.0),
text: new TextInput("text"), //rampMax: new Slider("ramp max", 0, 1.0),
insideColor: new ColorInput("inside color", "#ffffff"),
outlineColor: new ColorInput("outline color", "#000000"),
subpixelOptions: new RowHeader("subpixel mode options"), subpixelOptions: new RowHeader("subpixel mode options"),
subpixelEnable: new Slider("subpixel enable", 0, 1, 1), subpixelEnable: new Slider("subpixel enable", 0, 1, 1),
@ -38,13 +34,13 @@ function makeSliders()
//colorOffset: new Slider("color offset", 0.0, 3.1415), //colorOffset: new Slider("color offset", 0.0, 3.1415),
}; };
const defaults = {"undefined":"0","subpixel offset":"62","text":"supersampling","bone length":"32","outline scale":"208","ramp min":"0","dist. threshold":"513","velocity acc.":"385","gamma":"494","aliasing enable":"1","outline threshold":"335","outline color":"#000000","threshold offset":"265","outline. threshold":"512","outline offset":"0","inside color":"#ffffff","color mix":"0","scale":"89","supersample count":"1","distance threshold":"494","supersamples":"0","distance offset":"513","translate y":"381","ramp max":"1024","multisampleCount":"1","supersample offset":"248","subpixel enable":"1","translate x":"581","color offset":"118","velocity damp.":"796","distance scale":"49","threshold scale":"739","bone count":"40","color scale":"148","subpixel strength":"348"};
/* /*
const defaults = {"color scale":"148","bone length":"32","outline scale":"37","dist. threshold":"562","velocity acc.":"385","translate x":"464","outline threshold":"433","translate y":"495","bone count":"40","outline offset":"482","scale":"229","outline. threshold":"512","color offset":"118","distance offset":"676","threshold offset":"265","velocity damp.":"796","distance scale":"404","threshold scale":"739","color mix":"0"};
for (let slider of Object.values(sliders)) { for (let slider of Object.values(sliders)) {
if (slider.label in defaults) { if (slider.label in defaults) {
slider.input.value = defaults[slider.label]; slider.input.value = defaults[slider.label];
} }
} }
*/ */
return sliders; return sliders;

View File

@ -61,27 +61,13 @@
border-bottom: 2px solid #888 !important; border-bottom: 2px solid #888 !important;
} }
select, option, input[type="text"] { select, option {
font: 0.8rem sans-serif; font: 0.8rem sans-serif;
} }
input[type="button"] {
width: calc(100% - 1.1em);
grid-column: 1 / span 3;
}
input[type="range"], input[type="text"] {
height: 1rem;
}
input[type="color"] {
height: 1.25rem;
}
input[type="range"] { input[type="range"] {
height: 1rem;
width: calc(100% - 0.5em); width: calc(100% - 0.5em);
} }
input[type="text"] {
width: calc(100% - 1em);
}
.span-2 { .span-2 {
grid-column: span 2; grid-column: span 2;
width: calc(100% - 0.5em); width: calc(100% - 0.5em);
@ -105,10 +91,6 @@
<control-root> <control-root>
<control-main> <control-main>
<control-grid id="control-parent"> <control-grid id="control-parent">
<row>
<input id="download-render-buffer" type="button" value="download render buffer"></input>
</row>
<row-separator></row-separator>
</control-grid> </control-grid>
</control-main> </control-main>
</control-root> </control-root>

130
index.js
View File

@ -56,7 +56,6 @@ module.memory = memory;
var depthTexture = undefined; var depthTexture = undefined;
var multisampleTexture = undefined; var multisampleTexture = undefined;
var copyTexture = undefined;
const eyeValueX = document.getElementById("eye-value-x"); const eyeValueX = document.getElementById("eye-value-x");
const eyeValueY = document.getElementById("eye-value-y"); const eyeValueY = document.getElementById("eye-value-y");
@ -65,9 +64,6 @@ const eyeValueZ = document.getElementById("eye-value-z");
const yawValue = document.getElementById("yaw"); const yawValue = document.getElementById("yaw");
const pitchValue = document.getElementById("pitch"); const pitchValue = document.getElementById("pitch");
var downloadRenderBufferPending = false;
var tempBuffer = undefined;
function recreateDepth(canvasTexture, sampleCount) function recreateDepth(canvasTexture, sampleCount)
{ {
const depthResized = depthTexture === undefined || canvasTexture.width != depthTexture.width || canvasTexture.height != depthTexture.height; const depthResized = depthTexture === undefined || canvasTexture.width != depthTexture.width || canvasTexture.height != depthTexture.height;
@ -85,33 +81,6 @@ function recreateDepth(canvasTexture, sampleCount)
}); });
} }
const tempBufferSize = canvasTexture.width * canvasTexture.height * 4;
const tempResized = tempBuffer === undefined || tempBufferSize != tempBuffer.size;
if (tempResized) {
if (tempBuffer !== undefined) {
tempBuffer.destroy();
}
tempBuffer = device.createBuffer({
label: "temp buffer",
size: tempBufferSize,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});
}
const copyResized = copyTexture === undefined || canvasTexture.width !== copyTexture.width || canvasTexture.height !== copyTexture.height;
if (copyResized) {
if (copyTexture !== undefined) {
copyTexture.destroy();
}
copyTexture = device.createTexture({
format: canvasTexture.format,
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
size: [canvasTexture.width, canvasTexture.height],
sampleCount: 1,
});
}
if (sampleCount > 1) { if (sampleCount > 1) {
const multisampleResized = multisampleTexture === undefined || canvasTexture.width !== multisampleTexture.width || canvasTexture.height !== multisampleTexture.height; const multisampleResized = multisampleTexture === undefined || canvasTexture.width !== multisampleTexture.width || canvasTexture.height !== multisampleTexture.height;
if (multisampleResized || multisampleTexture.sampleCount !== sampleCount) { if (multisampleResized || multisampleTexture.sampleCount !== sampleCount) {
@ -208,18 +177,9 @@ function handleKeyup(e)
} }
} }
function handleDownloadButton(e)
{
downloadRenderBufferPending = true;
console.log("download framebuffer");
}
window.addEventListener('keydown', handleKeydown, false); window.addEventListener('keydown', handleKeydown, false);
window.addEventListener('keyup', handleKeyup, false); window.addEventListener('keyup', handleKeyup, false);
const downloadRenderBufferButton = document.getElementById("download-render-buffer");
downloadRenderBufferButton.addEventListener("click", handleDownloadButton, false);
function updateView() function updateView()
{ {
const lu = keyState[KEY.W] === true; const lu = keyState[KEY.W] === true;
@ -300,30 +260,7 @@ canvas.addEventListener("mousemove", onMouseMove);
var canRender = false; var canRender = false;
var frameNumber = 0; var frameNumber = 0;
function tgaBlob(texture, mappedRange) var tempBuffer = undefined;
{
const tgaHeaderSize = 18;
const tgaBuffer = new ArrayBuffer(mappedRange.byteLength + tgaHeaderSize);
const tgaView = new DataView(tgaBuffer);
tgaView.setUint8(0, 0); // idLength
tgaView.setUint8(1, 0); // colorMapType
tgaView.setUint8(2, 2); // imageTypeCode: 2 uncompressed RGB
tgaView.setUint16(3, 0, true); // colorMap origin
tgaView.setUint16(5, 0, true); // colorMap length
tgaView.setUint8(7, 0); // colorMap depth
tgaView.setUint16(8, 0, true); // xOrigin
tgaView.setUint16(10, 0, true); // yOrigin
tgaView.setUint16(12, texture.width, true); // width
tgaView.setUint16(14, texture.height, true); // height
tgaView.setUint8(16, 32); // bits per pixel
const descriptor = ((8 << 0) | // number of attribute bits
(1 << 5) | // origin in upper left
(0 << 6)); // non-interleaved
tgaView.setUint8(17, descriptor); // descriptor
const tgaU8 = new Uint8Array(tgaBuffer);
tgaU8.set(new Uint8Array(mappedRange), 18);
return new Blob([tgaBuffer]);
}
function render2() function render2()
{ {
@ -344,19 +281,16 @@ function render2()
updateView(); updateView();
//const clearValue = ; const clearValue = { r: 0.2, g: 0.2, b: 0.4, a: 1.0 };
const clearValue = (downloadRenderBufferPending) ? { r: 0.0, g: 0.0, b: 0.0, a: 0.0 } : { r: 0.2, g: 0.2, b: 0.4, a: 1.0 };
const viewTexture = (downloadRenderBufferPending) ? copyTexture : canvasTexture;
const attachment0 = (sampleCount == 1) ? { const attachment0 = (sampleCount == 1) ? {
view: viewTexture.createView(), view: canvasTexture.createView(),
loadOp: "clear", loadOp: "clear",
clearValue: clearValue, clearValue: clearValue,
storeOp: "store", storeOp: "store",
} : { } : {
view: multisampleTexture.createView(), view: multisampleTexture.createView(),
resolveTarget: viewTexture.createView(), resolveTarget: canvasTexture.createView(),
loadOp: "clear", loadOp: "clear",
clearValue: clearValue, clearValue: clearValue,
storeOp: "store", storeOp: "store",
@ -384,40 +318,44 @@ function render2()
renderPass.end(); renderPass.end();
if (downloadRenderBufferPending) { /*
encoder.copyTextureToBuffer({ encoder.copyTextureToBuffer({
texture: copyTexture, texture: multisampleTexture,
}, { }, {
buffer: tempBuffer, buffer: tempBuffer,
bytesPerRow: canvasTexture.width * 4, bytesPerRow: canvasTexture.width * 4 * 4,
}, { }, {
width: copyTexture.width, width: canvasTexture.width,
height: copyTexture.height, height: canvasTexture.height,
depthOrArrayLayers: 1, depthOrArrayLayers: 1,
}); });
} */
const commandBuffer = encoder.finish(); const commandBuffer = encoder.finish();
device.queue.submit([commandBuffer]); device.queue.submit([commandBuffer]);
frameNumber = (frameNumber + 1) % 2; frameNumber = (frameNumber + 1) % 2;
if (downloadRenderBufferPending) { /*
tempBuffer.mapAsync(GPUMapMode.READ).then(() => { tempBuffer.mapAsync(GPUMapMode.READ).then(() => {
const mappedRange = tempBuffer.getMappedRange(); // arraybuffer const readBuffer = tempBuffer.getMappedRange(); // arraybuffer
const blob = tgaBlob(copyTexture, mappedRange); //console.log(mousePositionClick);
const url = URL.createObjectURL(blob); const x = mousePositionClick[0];
const a = document.createElement("a"); const y = mousePositionClick[1];
a.setAttribute("href", url); const f32ReadBuffer = new Float32Array(readBuffer);
a.setAttribute("download", "framebuffer.tga"); for (let i = 0; i < 2; i++) {
a.click(); const a = f32ReadBuffer[((y + i) * canvasTexture.width + x) * 4 + 0];
tempBuffer.unmap(); const b = f32ReadBuffer[((y + i) * canvasTexture.width + x) * 4 + 1];
requestAnimationFrame(render2); const c = f32ReadBuffer[((y + i) * canvasTexture.width + x) * 4 + 2];
}); const d = f32ReadBuffer[((y + i) * canvasTexture.width + x) * 4 + 3];
downloadRenderBufferPending = false; //console.log(a, b, c, d);
} else { }
tempBuffer.unmap();
requestAnimationFrame(render2); requestAnimationFrame(render2);
} });
*/
requestAnimationFrame(render2);
} else { } else {
requestAnimationFrame(render2); requestAnimationFrame(render2);
} }

View File

@ -8,34 +8,34 @@ class Select {
const labelE = document.createElement("label"); const labelE = document.createElement("label");
labelE.innerHTML = label; labelE.innerHTML = label;
const inputE = document.createElement("select"); const selectE = document.createElement("select");
inputE.className = "span-2"; selectE.className = "span-2";
for (let i = 0; i < options.length; i++) { for (let i = 0; i < options.length; i++) {
const option = options[i]; const option = options[i];
const optionE = document.createElement("option"); const optionE = document.createElement("option");
optionE.setAttribute("value", i); optionE.setAttribute("value", i);
optionE.innerHTML = option; optionE.innerHTML = option;
inputE.appendChild(optionE); selectE.appendChild(optionE);
} }
const rowE = document.createElement("row"); const rowE = document.createElement("row");
const sepE = document.createElement("row-separator"); const sepE = document.createElement("row-separator");
rowE.appendChild(labelE); rowE.appendChild(labelE);
rowE.appendChild(inputE); rowE.appendChild(selectE);
parent.appendChild(rowE); parent.appendChild(rowE);
parent.appendChild(sepE); parent.appendChild(sepE);
this.input = inputE; this.select = selectE;
this.options = options; this.options = options;
this.lastValue = undefined; this.lastValue = undefined;
const storageValue = localStorage.getItem(this.label); const storageValue = localStorage.getItem(this.label);
if (storageValue !== null) { if (storageValue !== null) {
this.input.value = storageValue; this.select.value = storageValue;
} }
this.update(); this.update();
@ -43,7 +43,7 @@ class Select {
update() update()
{ {
const rawValue = parseInt(this.input.value); const rawValue = parseInt(this.select.value);
if (rawValue !== this.lastValue) { if (rawValue !== this.lastValue) {
this.lastValue = rawValue; this.lastValue = rawValue;
localStorage.setItem(this.label, rawValue); localStorage.setItem(this.label, rawValue);

View File

@ -49,9 +49,8 @@ extern "C" {
return font_layout->layout_buffer_index; return font_layout->layout_buffer_index;
} }
void font_layout__draw(FontLayout * font_layout, char const * s) void font_layout__draw(FontLayout * font_layout)
{ {
font_layout->layout_buffer_index = 0; font_layout->draw_string("hexagon grid");
font_layout->draw_string(s);
} }
}; };

View File

@ -1,50 +0,0 @@
const controlGrid = document.getElementById("control-parent");
class TextInput {
constructor(label)
{
const parent = controlGrid;
const labelE = document.createElement("label");
labelE.innerHTML = label;
const inputE = document.createElement("input");
inputE.type = "text";
inputE.className = "span-2";
const rowE = document.createElement("row");
const sepE = document.createElement("row-separator");
rowE.appendChild(labelE);
rowE.appendChild(inputE);
parent.appendChild(rowE);
parent.appendChild(sepE);
this.label = label;
this.input = inputE;
this.lastValue = undefined;
const storageValue = localStorage.getItem(this.label);
if (storageValue !== null) {
this.input.value = storageValue;
} else {
this.input.value = "hexagon grid";
}
this.update();
}
update()
{
const rawValue = this.input.value;
if (rawValue !== this.lastValue) {
this.lastValue = rawValue;
localStorage.setItem(this.label, rawValue);
}
return rawValue;
}
};
export { TextInput };