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)
|
||||
{
|
||||
const label = "font";
|
||||
@ -127,6 +139,12 @@ class FontRenderer {
|
||||
this.maxGlyphs = 1024;
|
||||
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
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -257,7 +275,7 @@ class FontRenderer {
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
this.sliders = makeSliders();
|
||||
this.sliderArray = new Float32Array(4 * 4);
|
||||
this.sliderArray = new Float32Array(4 * 6);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// buffers
|
||||
@ -281,6 +299,21 @@ class FontRenderer {
|
||||
|
||||
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);
|
||||
const layoutBufferSize = this.instanceCount * 4 * 4;
|
||||
|
||||
@ -291,8 +324,6 @@ class FontRenderer {
|
||||
// sliders
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
const configuration = updateSliders(this.sliders);
|
||||
|
||||
this.sliderArray[0] = configuration.mode;
|
||||
this.sliderArray[1] = configuration.scale;
|
||||
this.sliderArray[2] = configuration.translateX;
|
||||
@ -313,6 +344,14 @@ class FontRenderer {
|
||||
this.sliderArray[14] = configuration.outlineThreshold;
|
||||
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,
|
||||
this.sliderArray);
|
||||
|
||||
@ -342,8 +381,6 @@ async function loadFont(device, canvasFormat, viewUniformBuffer, module)
|
||||
|
||||
const renderer = new FontRenderer(device, canvasFormat, viewUniformBuffer, fontWgsl, module, liberationBuffer);
|
||||
|
||||
module.instance.exports.font_layout__draw(renderer.fontLayoutAddress);
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,9 @@ struct Config {
|
||||
supersampleOffset: f32,
|
||||
outlineThreshold: f32,
|
||||
outlineScale: f32,
|
||||
|
||||
insideColor: vec4f,
|
||||
outlineColor: vec4f,
|
||||
};
|
||||
|
||||
struct GlyphBuffer {
|
||||
@ -154,8 +157,8 @@ const offsets = array(
|
||||
|
||||
fn supersampleColor(texture: vec2f, s: vec2f, p: vec2f) -> vec4f
|
||||
{
|
||||
let insideColor = vec4f(1, 1, 1, 1);
|
||||
let outlineColor = vec4f(0, 0, 0, 1);
|
||||
let insideColor = vec4f(config.insideColor.xyz, 1);
|
||||
let outlineColor = vec4f(config.outlineColor.xyz, 1);
|
||||
let outsideColor = vec4f(0, 0, 0, 0);
|
||||
|
||||
let dx = dpdx(texture.x * s.x);
|
||||
@ -223,7 +226,7 @@ fn fragmentMain(input: VertexOutput) -> FragmentOutput
|
||||
|
||||
var output: FragmentOutput;
|
||||
|
||||
if (config.mode == 0) {
|
||||
if (config.mode == 1) {
|
||||
output.color = subpixelColor(input.texture, s, p);
|
||||
} else {
|
||||
output.color = supersampleColor(input.texture, s, p);
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import { Slider } from "./slider.js"
|
||||
import { Select } from "./select.js"
|
||||
import { RowHeader } from "./row-header.js"
|
||||
import { TextInput } from "./text-input.js"
|
||||
import { ColorInput } from "./color-input.js"
|
||||
|
||||
function makeSliders()
|
||||
{
|
||||
const sliders = {
|
||||
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),
|
||||
translateX: new Slider("translate x", -1, 1),
|
||||
translateY: new Slider("translate y", -1, 1),
|
||||
@ -15,8 +17,10 @@ function makeSliders()
|
||||
distanceThreshold: new Slider("distance threshold", 0.25, 0.75),
|
||||
distanceScale: new Slider("distance scale", 0.0, 20.0),
|
||||
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"),
|
||||
subpixelEnable: new Slider("subpixel enable", 0, 1, 1),
|
||||
|
||||
13
index.html
13
index.html
@ -61,13 +61,22 @@
|
||||
border-bottom: 2px solid #888 !important;
|
||||
}
|
||||
|
||||
select, option {
|
||||
select, option, input[type="text"] {
|
||||
font: 0.8rem sans-serif;
|
||||
}
|
||||
input[type="range"] {
|
||||
|
||||
input[type="range"], input[type="text"] {
|
||||
height: 1rem;
|
||||
}
|
||||
input[type="color"] {
|
||||
height: 1.25rem;
|
||||
}
|
||||
input[type="range"] {
|
||||
width: calc(100% - 0.5em);
|
||||
}
|
||||
input[type="text"] {
|
||||
width: calc(100% - 1em);
|
||||
}
|
||||
.span-2 {
|
||||
grid-column: span 2;
|
||||
width: calc(100% - 0.5em);
|
||||
|
||||
@ -49,8 +49,9 @@ extern "C" {
|
||||
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