color picker, text entry
This commit is contained in:
parent
b1122bdbf5
commit
c9a65e3bcf
60
color-input.js
Normal file
60
color-input.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
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
47
font.js
@ -110,6 +110,18 @@ 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";
|
||||||
@ -127,6 +139,12 @@ 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
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
@ -257,7 +275,7 @@ class FontRenderer {
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
this.sliders = makeSliders();
|
this.sliders = makeSliders();
|
||||||
this.sliderArray = new Float32Array(4 * 4);
|
this.sliderArray = new Float32Array(4 * 6);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// buffers
|
// buffers
|
||||||
@ -281,6 +299,21 @@ 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;
|
||||||
|
|
||||||
@ -291,8 +324,6 @@ 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;
|
||||||
@ -313,6 +344,14 @@ 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);
|
||||||
|
|
||||||
@ -342,8 +381,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,9 @@ struct Config {
|
|||||||
supersampleOffset: f32,
|
supersampleOffset: f32,
|
||||||
outlineThreshold: f32,
|
outlineThreshold: f32,
|
||||||
outlineScale: f32,
|
outlineScale: f32,
|
||||||
|
|
||||||
|
insideColor: vec4f,
|
||||||
|
outlineColor: vec4f,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GlyphBuffer {
|
struct GlyphBuffer {
|
||||||
@ -154,8 +157,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(1, 1, 1, 1);
|
let insideColor = vec4f(config.insideColor.xyz, 1);
|
||||||
let outlineColor = vec4f(0, 0, 0, 1);
|
let outlineColor = vec4f(config.outlineColor.xyz, 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);
|
||||||
@ -223,7 +226,7 @@ fn fragmentMain(input: VertexOutput) -> FragmentOutput
|
|||||||
|
|
||||||
var output: FragmentOutput;
|
var output: FragmentOutput;
|
||||||
|
|
||||||
if (config.mode == 0) {
|
if (config.mode == 1) {
|
||||||
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);
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
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", ["subpixel", "supersampling"]),
|
mode: new Select("mode", ["supersampling", "subpixel"]),
|
||||||
scale: new Slider("scale", 0.0, 0.01),
|
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),
|
||||||
@ -15,8 +17,10 @@ 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),
|
|
||||||
//rampMax: new Slider("ramp max", 0, 1.0),
|
text: new TextInput("text"),
|
||||||
|
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),
|
||||||
|
|||||||
13
index.html
13
index.html
@ -61,13 +61,22 @@
|
|||||||
border-bottom: 2px solid #888 !important;
|
border-bottom: 2px solid #888 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
select, option {
|
select, option, input[type="text"] {
|
||||||
font: 0.8rem sans-serif;
|
font: 0.8rem sans-serif;
|
||||||
}
|
}
|
||||||
input[type="range"] {
|
|
||||||
|
input[type="range"], input[type="text"] {
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
|
}
|
||||||
|
input[type="color"] {
|
||||||
|
height: 1.25rem;
|
||||||
|
}
|
||||||
|
input[type="range"] {
|
||||||
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);
|
||||||
|
|||||||
@ -49,8 +49,9 @@ extern "C" {
|
|||||||
return font_layout->layout_buffer_index;
|
return font_layout->layout_buffer_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void font_layout__draw(FontLayout * font_layout)
|
void font_layout__draw(FontLayout * font_layout, char const * s)
|
||||||
{
|
{
|
||||||
font_layout->draw_string("hexagon grid");
|
font_layout->layout_buffer_index = 0;
|
||||||
|
font_layout->draw_string(s);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
50
text-input.js
Normal file
50
text-input.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
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 };
|
||||||
Loading…
x
Reference in New Issue
Block a user