screen-space derivatives, 4x multi-sampling
This commit is contained in:
parent
53cbbebdc7
commit
a3d5b6650e
9
font.js
9
font.js
@ -63,7 +63,7 @@ class FontRenderer {
|
||||
resource: sampler,
|
||||
}, {
|
||||
binding: 1,
|
||||
resource: texture,
|
||||
resource: texture.createView(),
|
||||
}, {
|
||||
binding: 2,
|
||||
resource: { buffer: glyphBuffer },
|
||||
@ -244,6 +244,9 @@ class FontRenderer {
|
||||
depthCompare: "always",
|
||||
format: "depth24plus",
|
||||
},
|
||||
multisample: {
|
||||
count: 4,
|
||||
}
|
||||
});
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -292,11 +295,11 @@ class FontRenderer {
|
||||
|
||||
this.sliderArray[4] = configuration.distanceThreshold;
|
||||
this.sliderArray[5] = configuration.distanceScale;
|
||||
this.sliderArray[6] = configuration.distanceOffset;
|
||||
//this.sliderArray[6] = configuration.distanceOffset;
|
||||
|
||||
this.sliderArray[8] = configuration.outlineThreshold;
|
||||
this.sliderArray[9] = configuration.outlineScale;
|
||||
this.sliderArray[10] = configuration.outlineOffset;
|
||||
//this.sliderArray[10] = configuration.outlineOffset;
|
||||
|
||||
this.sliderArray[12] = configuration.colorMix;
|
||||
this.sliderArray[13] = configuration.colorScale;
|
||||
|
||||
31
font.wgsl
31
font.wgsl
@ -52,7 +52,8 @@ struct VertexInput {
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) position: vec4f,
|
||||
@location(0) texture: vec2f,
|
||||
@location(0) @interpolate(linear, sample) texture: vec2f,
|
||||
//@location(0) texture: vec2f,
|
||||
@location(1) @interpolate(flat) glyphIndex: u32,
|
||||
@location(2) foo: vec4f,
|
||||
};
|
||||
@ -102,6 +103,17 @@ fn palette(t: f32) -> vec4f
|
||||
return vec4f(color, 1);
|
||||
}
|
||||
|
||||
fn aliasedLinearSaturation(distance: f32, threshold: f32, scale: f32) -> f32
|
||||
{
|
||||
let distanceFromEdge = threshold - distance;
|
||||
let dx = dpdx(distanceFromEdge);
|
||||
let dy = dpdy(distanceFromEdge);
|
||||
let gradientLength = length(vec2f(dx, dy));
|
||||
let thresholdWidth = scale * gradientLength;
|
||||
let aliased = saturate((distanceFromEdge / thresholdWidth) + 0.5);
|
||||
return aliased;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fragmentMain(input: VertexOutput) -> @location(0) vec4f
|
||||
{
|
||||
@ -111,6 +123,22 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4f
|
||||
let base = textureSample(fontTexture, linearSampler, input.texture * s + p);
|
||||
let distance = base.x;
|
||||
|
||||
let insideT = aliasedLinearSaturation(distance,
|
||||
config.distanceThreshold,
|
||||
config.distanceScale);
|
||||
|
||||
let outlineT = aliasedLinearSaturation(distance,
|
||||
config.outlineThreshold,
|
||||
config.outlineScale);
|
||||
|
||||
let insideColor = vec4f(1, 1, 1, 1);
|
||||
let outlineColor = vec4f(0, 0, 0, 1);
|
||||
let outsideColor = vec4f(0, 0, 0, 0);
|
||||
|
||||
let outline = mix(outlineColor, outsideColor, outlineT);
|
||||
return mix(insideColor, outline, insideT);
|
||||
|
||||
/*
|
||||
let insideColorW = vec4f(1, 1, 1, 1);
|
||||
let insideColorP = palette(distance * config.colorScale + config.colorOffset);
|
||||
let insideColor = mix(insideColorW, insideColorP, config.colorMix);
|
||||
@ -124,4 +152,5 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4f
|
||||
config.distanceThreshold - config.outlineThreshold,
|
||||
config.outlineScale, config.outlineOffset);
|
||||
return color;
|
||||
*/
|
||||
}
|
||||
|
||||
@ -2,23 +2,34 @@ import { Slider } from "./slider.js"
|
||||
|
||||
function makeSliders()
|
||||
{
|
||||
return {
|
||||
scale: new Slider("scale", 0.0, 0.05),
|
||||
translateX: new Slider("translate x", -10, 10),
|
||||
translateY: new Slider("translate y", -10, 10),
|
||||
const sliders = {
|
||||
scale: new Slider("scale", 0.0, 0.01),
|
||||
translateX: new Slider("translate x", -1, 1),
|
||||
translateY: new Slider("translate y", -1, 1),
|
||||
|
||||
distanceThreshold: new Slider("dist. threshold", 0.0, 1.0),
|
||||
distanceScale: new Slider("distance scale", 0.0, 200.0),
|
||||
distanceOffset: new Slider("distance offset", -20.0, 20.0),
|
||||
distanceThreshold: new Slider("dist. threshold", 0.25, 0.75),
|
||||
distanceScale: new Slider("distance scale", 0.0, 2.0),
|
||||
//distanceOffset: new Slider("distance offset", -20.0, 20.0),
|
||||
|
||||
outlineThreshold: new Slider("outline threshold", 0.0, 1.0),
|
||||
outlineScale: new Slider("outline scale", 0.0, 200.0),
|
||||
outlineOffset: new Slider("outline offset", -20.0, 20.0),
|
||||
outlineScale: new Slider("outline scale", 0.0, 50.0),
|
||||
//outlineOffset: new Slider("outline offset", -20.0, 20.0),
|
||||
|
||||
colorMix: new Slider("color mix", 0.0, 1.0),
|
||||
colorScale: new Slider("color scale", 0.0, 10.0),
|
||||
colorOffset: new Slider("color offset", 0.0, 3.1415),
|
||||
};
|
||||
|
||||
/*
|
||||
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)) {
|
||||
if (slider.label in defaults) {
|
||||
slider.input.value = defaults[slider.label];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return sliders;
|
||||
}
|
||||
|
||||
export { makeSliders };
|
||||
|
||||
25
index.js
25
index.js
@ -59,6 +59,7 @@ function createDepthTexture() {
|
||||
size: [canvas.width, canvas.height],
|
||||
format: 'depth24plus',
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
||||
sampleCount: 4,
|
||||
});
|
||||
}
|
||||
|
||||
@ -73,7 +74,7 @@ const pitchValue = document.getElementById("pitch");
|
||||
|
||||
function recreateDepth(force)
|
||||
{
|
||||
if (canvas.clientWidth !== canvas.width || canvas.clientWidth !== canvas.height || force === true) {
|
||||
if (force === true || canvas.clientWidth !== canvas.width || canvas.clientWidth !== canvas.height) {
|
||||
canvas.width = canvas.clientWidth;
|
||||
canvas.height = canvas.clientHeight;
|
||||
|
||||
@ -244,6 +245,8 @@ canvas.addEventListener("mousemove", onMouseMove);
|
||||
|
||||
var canRender = false;
|
||||
var frameNumber = 0;
|
||||
var multisampleTexture = undefined;
|
||||
|
||||
function render2()
|
||||
{
|
||||
if (canRender === true) {
|
||||
@ -252,14 +255,30 @@ function render2()
|
||||
|
||||
canRender = false;
|
||||
recreateDepth(false);
|
||||
const colorView = context.getCurrentTexture().createView();
|
||||
const canvasTexture = context.getCurrentTexture();
|
||||
if ((multisampleTexture === undefined) ||
|
||||
(multisampleTexture.width !== canvasTexture.width) ||
|
||||
(multisampleTexture.height !== canvasTexture.height)) {
|
||||
if ((multisampleTexture !== undefined)) {
|
||||
multisampleTexture.destroy();
|
||||
}
|
||||
|
||||
multisampleTexture = device.createTexture({
|
||||
format: canvasTexture.format,
|
||||
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
||||
size: [canvasTexture.width, canvasTexture.height],
|
||||
sampleCount: 4,
|
||||
});
|
||||
}
|
||||
|
||||
updateView();
|
||||
|
||||
const encoder = device.createCommandEncoder();
|
||||
const renderPass = encoder.beginRenderPass({
|
||||
colorAttachments: [{
|
||||
view: colorView,
|
||||
view: multisampleTexture.createView(),
|
||||
//view: canvasTexture.createView(),
|
||||
resolveTarget: canvasTexture.createView(),
|
||||
loadOp: "clear",
|
||||
clearValue: { r: 0.2, g: 0.2, b: 0.4, a: 1 },
|
||||
storeOp: "store",
|
||||
|
||||
@ -5,8 +5,6 @@ function remap(low1, high1, low2, high2, value)
|
||||
return low2 + (value - low1) * (high2 - low2) / (high1 - low1);
|
||||
}
|
||||
|
||||
const sliderDefaults = {"bone length":"32","velocity acc.":"385","velocity damp.":"796","bone count":"40"};
|
||||
|
||||
class Slider {
|
||||
constructor(label, low, high, max = 1024)
|
||||
{
|
||||
@ -41,8 +39,6 @@ class Slider {
|
||||
const storageValue = localStorage.getItem(this.label);
|
||||
if (storageValue !== null) {
|
||||
this.input.value = storageValue;
|
||||
} else if (this.label in sliderDefaults) {
|
||||
this.input.value = sliderDefaults[this.label];
|
||||
}
|
||||
|
||||
this.update();
|
||||
|
||||
@ -6,6 +6,8 @@ static inline size_t texture_offset(font * font)
|
||||
return (sizeof (struct font)) + (sizeof (struct glyph)) * font->glyph_count;
|
||||
}
|
||||
|
||||
extern "C" void log(int);
|
||||
|
||||
void FontLayout::init(size_t buffer, int layout_buffer_length)
|
||||
{
|
||||
this->font = reinterpret_cast<struct font *>(buffer + 0);
|
||||
@ -18,12 +20,14 @@ void FontLayout::init(size_t buffer, int layout_buffer_length)
|
||||
this->layout_buffer = New<LayoutBuffer>(layout_buffer_length);
|
||||
|
||||
this->glyph_buffer = New<GlyphBuffer>(this->font->glyph_count);
|
||||
int o = 0;
|
||||
log(o);
|
||||
for (uint16_t i = 0; i < this->font->glyph_count; i++) {
|
||||
glyph_texture const & texture = this->glyphs[i].texture;
|
||||
this->glyph_buffer[i].texPosition.x = float(texture.x) / float(this->font->texture_width);
|
||||
this->glyph_buffer[i].texPosition.y = float(texture.y) / float(this->font->texture_height);
|
||||
this->glyph_buffer[i].texSize.x = float(texture.width) / float(this->font->texture_width);
|
||||
this->glyph_buffer[i].texSize.y = float(texture.height) / float(this->font->texture_height);
|
||||
this->glyph_buffer[i].texPosition.x = float(texture.x - o) / float(this->font->texture_width);
|
||||
this->glyph_buffer[i].texPosition.y = float(texture.y - o) / float(this->font->texture_height);
|
||||
this->glyph_buffer[i].texSize.x = float(texture.width - o) / float(this->font->texture_width);
|
||||
this->glyph_buffer[i].texSize.y = float(texture.height - o) / float(this->font->texture_height);
|
||||
this->glyph_buffer[i].size.x = float(texture.width);
|
||||
this->glyph_buffer[i].size.y = float(texture.height);
|
||||
}
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
CFLAGS = -Og -g -gdwarf-4 -Wall -Wextra -Wno-error -Wfatal-errors
|
||||
OPT = -flto -O3 -fno-stack-protector
|
||||
|
||||
CFLAGS = -g -gdwarf-4 -Wall -Wextra -Wno-error -Wfatal-errors
|
||||
CFLAGS += -Wno-error=unused-parameter
|
||||
CFLAGS += -Wno-error=unused-variable
|
||||
CFLAGS += -Wno-error=unused-but-set-variable
|
||||
CFLAGS += -I../../include
|
||||
CFLAGS += $(OPT)
|
||||
|
||||
LDFLAGS += $(OPT)
|
||||
|
||||
CXXFLAGS = -std=c++23
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <array>
|
||||
|
||||
#include "ttf_2d_pack.h"
|
||||
@ -9,9 +11,9 @@ struct size {
|
||||
uint16_t height;
|
||||
};
|
||||
|
||||
constexpr struct size max_texture = {1024, 1024};
|
||||
constexpr struct size max_texture = {4096, 4096};
|
||||
|
||||
inline bool area_valid(const uint8_t texture[max_texture.height][max_texture.width],
|
||||
inline bool area_valid(const uint8_t * texture,
|
||||
const uint32_t x_offset,
|
||||
const uint32_t y_offset,
|
||||
const struct rect& rect,
|
||||
@ -22,7 +24,7 @@ inline bool area_valid(const uint8_t texture[max_texture.height][max_texture.wid
|
||||
uint32_t x = x_offset + xi;
|
||||
uint32_t y = y_offset + yi;
|
||||
|
||||
if (texture[y][x] != 0)
|
||||
if (texture[y * max_texture.width + x] != 0)
|
||||
return false;
|
||||
|
||||
if (x >= window.width || y >= window.height)
|
||||
@ -77,10 +79,12 @@ constexpr inline int log2(uint32_t n)
|
||||
case 256: return 8;
|
||||
case 512: return 9;
|
||||
case 1024: return 10;
|
||||
case 2048: return 11;
|
||||
case 4096: return 12;
|
||||
}
|
||||
}
|
||||
|
||||
static void pack_into(uint8_t texture[max_texture.height][max_texture.width],
|
||||
static void pack_into(uint8_t * texture,
|
||||
size & window,
|
||||
rect & rect)
|
||||
{
|
||||
@ -112,7 +116,7 @@ static void pack_into(uint8_t texture[max_texture.height][max_texture.width],
|
||||
uint32_t x = x_offset + xi;
|
||||
uint32_t y = y_offset + yi;
|
||||
|
||||
texture[y][x] = 1;
|
||||
texture[y * max_texture.width + x] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +149,8 @@ void insertion_sort(T * arr, int len)
|
||||
|
||||
window_curve_ix pack_all(struct rect * rects, const uint32_t num_rects)
|
||||
{
|
||||
uint8_t texture[max_texture.height][max_texture.width] = { 0 };
|
||||
uint8_t * texture = (uint8_t *)malloc(max_texture.height * max_texture.width);
|
||||
memset(texture, 0x00, max_texture.height * max_texture.width);
|
||||
size window = {1, 1};
|
||||
|
||||
// sort all rectangles by size
|
||||
@ -155,5 +160,7 @@ window_curve_ix pack_all(struct rect * rects, const uint32_t num_rects)
|
||||
pack_into(texture, window, rects[i]);
|
||||
}
|
||||
|
||||
free(texture);
|
||||
|
||||
return {window.width, window.height};
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
std::endian _target_endian;
|
||||
|
||||
constexpr uint32_t max_texture_dim = 1024;
|
||||
constexpr uint32_t max_texture_dim = 4096;
|
||||
constexpr uint32_t max_texture_size = max_texture_dim * max_texture_dim;
|
||||
|
||||
template< class T >
|
||||
@ -287,7 +287,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
uint32_t num_glyphs = (end - start) + 1;
|
||||
glyph glyphs[num_glyphs];
|
||||
uint8_t texture[max_texture_size];
|
||||
uint8_t * texture = (uint8_t *)malloc(max_texture_size);
|
||||
memset(texture, 0x00, max_texture_size);
|
||||
|
||||
auto window_curve_ix = load_all_positions(face, start, end, glyphs, texture);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user