aboutsummaryrefslogtreecommitdiff
path: root/web/pw-visualizer
diff options
context:
space:
mode:
Diffstat (limited to 'web/pw-visualizer')
-rw-r--r--web/pw-visualizer/assets/res/fonts/roboto.json1
-rw-r--r--web/pw-visualizer/assets/res/fonts/roboto.pngbin0 -> 54869 bytes
-rw-r--r--web/pw-visualizer/assets/shaders/frag/msdf.glsl29
-rw-r--r--web/pw-visualizer/src/assets.ts5
-rw-r--r--web/pw-visualizer/src/index.ts37
-rw-r--r--web/pw-visualizer/src/webgl/msdf_text.ts181
-rw-r--r--web/pw-visualizer/src/webgl/texture.ts10
-rw-r--r--web/pw-visualizer/src/webgl/util.ts1
8 files changed, 253 insertions, 11 deletions
diff --git a/web/pw-visualizer/assets/res/fonts/roboto.json b/web/pw-visualizer/assets/res/fonts/roboto.json
new file mode 100644
index 0000000..c84b33d
--- /dev/null
+++ b/web/pw-visualizer/assets/res/fonts/roboto.json
@@ -0,0 +1 @@
+{"atlas":{"type":"msdf","distanceRange":8,"size":24,"width":232,"height":232,"yOrigin":"top"},"metrics":{"emSize":1,"lineHeight":1.171875,"ascender":-0.927734375,"descender":0.244140625,"underlineY":0.09765625,"underlineThickness":0.048828125},"glyphs":[{"unicode":32,"advance":0.2490234375},{"unicode":33,"advance":0.26806640625,"planeBounds":{"left":-0.11254882812500004,"top":-0.89371744791666652,"right":0.38745117187499989,"bottom":0.18961588541666666},"atlasBounds":{"left":78.5,"top":34.5,"right":90.5,"bottom":60.5}},{"unicode":34,"advance":0.32421875,"planeBounds":{"left":-0.12613932291666669,"top":-0.934814453125,"right":0.45719401041666663,"bottom":-0.309814453125},"atlasBounds":{"left":172.5,"top":195.5,"right":186.5,"bottom":210.5}},{"unicode":35,"advance":0.6103515625,"planeBounds":{"left":-0.13850911458333331,"top":-0.89713541666666652,"right":0.77815755208333337,"bottom":0.18619791666666666},"atlasBounds":{"left":91.5,"top":34.5,"right":113.5,"bottom":60.5}},{"unicode":36,"advance":0.568359375,"planeBounds":{"left":-0.13273111979166666,"top":-1.0071614583333335,"right":0.70060221354166663,"bottom":0.28450520833333331},"atlasBounds":{"left":60.5,"top":0.5,"right":80.5,"bottom":31.5}},{"unicode":37,"advance":0.734375,"planeBounds":{"left":-0.12963867187499997,"top":-0.89713541666666652,"right":0.870361328125,"bottom":0.18619791666666666},"atlasBounds":{"left":147.5,"top":34.5,"right":171.5,"bottom":60.5}},{"unicode":38,"advance":0.63916015625,"planeBounds":{"left":-0.14152018229166666,"top":-0.89713541666666652,"right":0.81681315104166663,"bottom":0.18619791666666666},"atlasBounds":{"left":21.5,"top":62.5,"right":44.5,"bottom":88.5}},{"unicode":39,"advance":0.1689453125,"planeBounds":{"left":-0.14371744791666669,"top":-0.9365234375,"right":0.31461588541666663,"bottom":-0.3115234375},"atlasBounds":{"left":160.5,"top":195.5,"right":171.5,"bottom":210.5}},{"unicode":40,"advance":0.34912109375,"planeBounds":{"left":-0.11621093750000004,"top":-0.97265625,"right":0.50878906249999989,"bottom":0.40234375},"atlasBounds":{"left":0.5,"top":0.5,"right":15.5,"bottom":33.5}},{"unicode":41,"advance":0.35302734375,"planeBounds":{"left":-0.15771484375000003,"top":-0.97265625,"right":0.46728515624999989,"bottom":0.40234375},"atlasBounds":{"left":16.5,"top":0.5,"right":31.5,"bottom":33.5}},{"unicode":42,"advance":0.4423828125,"planeBounds":{"left":-0.17293294270833331,"top":-0.89558919270833337,"right":0.61873372395833337,"bottom":-0.10392252604166667},"atlasBounds":{"left":87.5,"top":195.5,"right":106.5,"bottom":214.5}},{"unicode":43,"advance":0.5576171875,"planeBounds":{"left":-0.13932291666666666,"top":-0.767578125,"right":0.69401041666666663,"bottom":0.10742187499999999},"atlasBounds":{"left":47.5,"top":195.5,"right":67.5,"bottom":216.5}},{"unicode":44,"advance":0.22021484375,"planeBounds":{"left":-0.15771484375000003,"top":-0.28979492187499994,"right":0.34228515624999989,"bottom":0.335205078125},"atlasBounds":{"left":147.5,"top":195.5,"right":159.5,"bottom":210.5}},{"unicode":45,"advance":0.32861328125,"planeBounds":{"left":-0.14965820312500003,"top":-0.53165690104166663,"right":0.47534179687499989,"bottom":-0.073323567708333301},"atlasBounds":{"left":216.5,"top":170.5,"right":231.5,"bottom":181.5}},{"unicode":46,"advance":0.279296875,"planeBounds":{"left":-0.11450195312500004,"top":-0.30981445312499989,"right":0.38549804687499989,"bottom":0.19018554687500003},"atlasBounds":{"left":38.5,"top":217.5,"right":50.5,"bottom":229.5}},{"unicode":47,"advance":0.39599609375,"planeBounds":{"left":-0.16642252604166666,"top":-0.887451171875,"right":0.54191080729166663,"bottom":0.23754882812499997},"atlasBounds":{"left":194.5,"top":0.5,"right":211.5,"bottom":27.5}},{"unicode":48,"advance":0.568359375,"planeBounds":{"left":-0.13273111979166666,"top":-0.89713541666666652,"right":0.70060221354166663,"bottom":0.18619791666666666},"atlasBounds":{"left":66.5,"top":62.5,"right":86.5,"bottom":88.5}},{"unicode":49,"advance":0.568359375,"planeBounds":{"left":-0.10481770833333336,"top":-0.89835611979166652,"right":0.56184895833333326,"bottom":0.18497721354166666},"atlasBounds":{"left":108.5,"top":62.5,"right":124.5,"bottom":88.5}},{"unicode":50,"advance":0.568359375,"planeBounds":{"left":-0.13102213541666666,"top":-0.90201822916666652,"right":0.70231119791666663,"bottom":0.18131510416666666},"atlasBounds":{"left":125.5,"top":62.5,"right":145.5,"bottom":88.5}},{"unicode":51,"advance":0.568359375,"planeBounds":{"left":-0.14176432291666666,"top":-0.89713541666666652,"right":0.69156901041666663,"bottom":0.18619791666666666},"atlasBounds":{"left":146.5,"top":62.5,"right":166.5,"bottom":88.5}},{"unicode":52,"advance":0.568359375,"planeBounds":{"left":-0.15283203124999997,"top":-0.89713541666666652,"right":0.72216796875,"bottom":0.18619791666666666},"atlasBounds":{"left":167.5,"top":62.5,"right":188.5,"bottom":88.5}},{"unicode":53,"advance":0.568359375,"planeBounds":{"left":-0.12101236979166667,"top":-0.89225260416666652,"right":0.71232096354166663,"bottom":0.19108072916666666},"atlasBounds":{"left":189.5,"top":62.5,"right":209.5,"bottom":88.5}},{"unicode":54,"advance":0.568359375,"planeBounds":{"left":-0.12443033854166667,"top":-0.89396158854166652,"right":0.70890299479166663,"bottom":0.18937174479166666},"atlasBounds":{"left":91.5,"top":116.5,"right":111.5,"bottom":142.5}},{"unicode":55,"advance":0.568359375,"planeBounds":{"left":-0.13614908854166666,"top":-0.89713541666666652,"right":0.69718424479166663,"bottom":0.18619791666666666},"atlasBounds":{"left":211.5,"top":116.5,"right":231.5,"bottom":142.5}},{"unicode":56,"advance":0.568359375,"planeBounds":{"left":-0.13297526041666666,"top":-0.89713541666666652,"right":0.70035807291666663,"bottom":0.18619791666666666},"atlasBounds":{"left":134.5,"top":143.5,"right":154.5,"bottom":169.5}},{"unicode":57,"advance":0.568359375,"planeBounds":{"left":-0.13907877604166666,"top":-0.90030924479166652,"right":0.69425455729166663,"bottom":0.18302408854166666},"atlasBounds":{"left":175.5,"top":143.5,"right":195.5,"bottom":169.5}},{"unicode":58,"advance":0.26513671875,"planeBounds":{"left":-0.11743164062500004,"top":-0.72542317708333337,"right":0.38256835937499989,"bottom":0.19124348958333331},"atlasBounds":{"left":99.5,"top":170.5,"right":111.5,"bottom":192.5}},{"unicode":59,"advance":0.23779296875,"planeBounds":{"left":-0.16365559895833334,"top":-0.71077473958333337,"right":0.37801106770833331,"bottom":0.33089192708333331},"atlasBounds":{"left":196.5,"top":143.5,"right":209.5,"bottom":168.5}},{"unicode":60,"advance":0.50830078125,"planeBounds":{"left":-0.13964843749999997,"top":-0.70515950520833337,"right":0.6103515625,"bottom":0.086507161458333329},"atlasBounds":{"left":68.5,"top":195.5,"right":86.5,"bottom":214.5}},{"unicode":61,"advance":0.5595703125,"planeBounds":{"left":-0.11433919270833333,"top":-0.65999348958333326,"right":0.67732747395833337,"bottom":0.0066731770833333599},"atlasBounds":{"left":127.5,"top":195.5,"right":146.5,"bottom":211.5}},{"unicode":62,"advance":0.5205078125,"planeBounds":{"left":-0.12215169270833333,"top":-0.70515950520833337,"right":0.66951497395833337,"bottom":0.086507161458333329},"atlasBounds":{"left":107.5,"top":195.5,"right":126.5,"bottom":214.5}},{"unicode":63,"advance":0.48681640625,"planeBounds":{"left":-0.15657552083333331,"top":-0.89908854166666652,"right":0.63509114583333337,"bottom":0.18424479166666666},"atlasBounds":{"left":155.5,"top":143.5,"right":174.5,"bottom":169.5}},{"unicode":64,"advance":0.89501953125,"planeBounds":{"left":-0.1348371154108888,"top":-0.88313802083333337,"right":1.0318295512557778,"bottom":0.40852864583333331},"atlasBounds":{"left":98.5,"top":0.5,"right":126.5,"bottom":31.5}},{"unicode":65,"advance":0.66552734375,"planeBounds":{"left":-0.16674804687499997,"top":-0.89713541666666652,"right":0.833251953125,"bottom":0.18619791666666666},"atlasBounds":{"left":109.5,"top":143.5,"right":133.5,"bottom":169.5}},{"unicode":66,"advance":0.63134765625,"planeBounds":{"left":-0.11132812499999999,"top":-0.89713541666666652,"right":0.763671875,"bottom":0.18619791666666666},"atlasBounds":{"left":210.5,"top":62.5,"right":231.5,"bottom":88.5}},{"unicode":67,"advance":0.65283203125,"planeBounds":{"left":-0.12581380208333331,"top":-0.89713541666666652,"right":0.79085286458333337,"bottom":0.18619791666666666},"atlasBounds":{"left":66.5,"top":143.5,"right":88.5,"bottom":169.5}},{"unicode":68,"advance":0.6533203125,"planeBounds":{"left":-0.099853515625,"top":-0.89713541666666652,"right":0.77514648437499989,"bottom":0.18619791666666666},"atlasBounds":{"left":44.5,"top":143.5,"right":65.5,"bottom":169.5}},{"unicode":69,"advance":0.5654296875,"planeBounds":{"left":-0.11149088541666667,"top":-0.89713541666666652,"right":0.72184244791666663,"bottom":0.18619791666666666},"atlasBounds":{"left":23.5,"top":143.5,"right":43.5,"bottom":169.5}},{"unicode":70,"advance":0.5498046875,"planeBounds":{"left":-0.097493489583333329,"top":-0.89713541666666652,"right":0.69417317708333337,"bottom":0.18619791666666666},"atlasBounds":{"left":89.5,"top":143.5,"right":108.5,"bottom":169.5}},{"unicode":71,"advance":0.68115234375,"planeBounds":{"left":-0.12386067708333333,"top":-0.89713541666666652,"right":0.79280598958333337,"bottom":0.18619791666666666},"atlasBounds":{"left":0.5,"top":143.5,"right":22.5,"bottom":169.5}},{"unicode":72,"advance":0.7109375,"planeBounds":{"left":-0.10335286458333333,"top":-0.89713541666666652,"right":0.81331380208333337,"bottom":0.18619791666666666},"atlasBounds":{"left":188.5,"top":116.5,"right":210.5,"bottom":142.5}},{"unicode":73,"advance":0.2822265625,"planeBounds":{"left":-0.087565104166666699,"top":-0.89713541666666652,"right":0.37076822916666663,"bottom":0.18619791666666666},"atlasBounds":{"left":176.5,"top":116.5,"right":187.5,"bottom":142.5}},{"unicode":74,"advance":0.55517578125,"planeBounds":{"left":-0.16227213541666666,"top":-0.89225260416666652,"right":0.67106119791666663,"bottom":0.19108072916666666},"atlasBounds":{"left":155.5,"top":116.5,"right":175.5,"bottom":142.5}},{"unicode":75,"advance":0.63037109375,"planeBounds":{"left":-0.10359700520833333,"top":-0.89713541666666652,"right":0.81306966145833337,"bottom":0.18619791666666666},"atlasBounds":{"left":132.5,"top":116.5,"right":154.5,"bottom":142.5}},{"unicode":76,"advance":0.54150390625,"planeBounds":{"left":-0.099934895833333329,"top":-0.89713541666666652,"right":0.69173177083333337,"bottom":0.18619791666666666},"atlasBounds":{"left":112.5,"top":116.5,"right":131.5,"bottom":142.5}},{"unicode":77,"advance":0.87548828125,"planeBounds":{"left":-0.10416666666666666,"top":-0.89713541666666652,"right":0.97916666666666652,"bottom":0.18619791666666666},"atlasBounds":{"left":205.5,"top":34.5,"right":231.5,"bottom":60.5}},{"unicode":78,"advance":0.71044921875,"planeBounds":{"left":-0.10359700520833333,"top":-0.89713541666666652,"right":0.81306966145833337,"bottom":0.18619791666666666},"atlasBounds":{"left":68.5,"top":116.5,"right":90.5,"bottom":142.5}},{"unicode":79,"advance":0.6904296875,"planeBounds":{"left":-0.13419596354166666,"top":-0.89713541666666652,"right":0.82413736979166663,"bottom":0.18619791666666666},"atlasBounds":{"left":44.5,"top":116.5,"right":67.5,"bottom":142.5}},{"unicode":80,"advance":0.6396484375,"planeBounds":{"left":-0.099365234375,"top":-0.89713541666666652,"right":0.77563476562499989,"bottom":0.18619791666666666},"atlasBounds":{"left":22.5,"top":116.5,"right":43.5,"bottom":142.5}},{"unicode":81,"advance":0.6904296875,"planeBounds":{"left":-0.13663736979166666,"top":-0.90299479166666652,"right":0.82169596354166663,"bottom":0.30533854166666663},"atlasBounds":{"left":159.5,"top":0.5,"right":182.5,"bottom":29.5}},{"unicode":82,"advance":0.62451171875,"planeBounds":{"left":-0.096923828125,"top":-0.89713541666666652,"right":0.77807617187499989,"bottom":0.18619791666666666},"atlasBounds":{"left":0.5,"top":116.5,"right":21.5,"bottom":142.5}},{"unicode":83,"advance":0.60400390625,"planeBounds":{"left":-0.13574218749999997,"top":-0.89713541666666652,"right":0.7392578125,"bottom":0.18619791666666666},"atlasBounds":{"left":191.5,"top":89.5,"right":212.5,"bottom":115.5}},{"unicode":84,"advance":0.607421875,"planeBounds":{"left":-0.15437825520833331,"top":-0.89713541666666652,"right":0.76228841145833337,"bottom":0.18619791666666666},"atlasBounds":{"left":168.5,"top":89.5,"right":190.5,"bottom":115.5}},{"unicode":85,"advance":0.65234375,"planeBounds":{"left":-0.11035156249999999,"top":-0.89225260416666652,"right":0.7646484375,"bottom":0.19108072916666666},"atlasBounds":{"left":146.5,"top":89.5,"right":167.5,"bottom":115.5}},{"unicode":86,"advance":0.6474609375,"planeBounds":{"left":-0.17602539062499997,"top":-0.89713541666666652,"right":0.823974609375,"bottom":0.18619791666666666},"atlasBounds":{"left":121.5,"top":89.5,"right":145.5,"bottom":115.5}},{"unicode":87,"advance":0.88037109375,"planeBounds":{"left":-0.16129557291666657,"top":-0.89713541666666652,"right":1.0470377604166665,"bottom":0.18619791666666666},"atlasBounds":{"left":91.5,"top":89.5,"right":120.5,"bottom":115.5}},{"unicode":88,"advance":0.6328125,"planeBounds":{"left":-0.16202799479166666,"top":-0.89713541666666652,"right":0.79630533854166663,"bottom":0.18619791666666666},"atlasBounds":{"left":67.5,"top":89.5,"right":90.5,"bottom":115.5}},{"unicode":89,"advance":0.609375,"planeBounds":{"left":-0.17496744791666666,"top":-0.89713541666666652,"right":0.78336588541666663,"bottom":0.18619791666666666},"atlasBounds":{"left":43.5,"top":89.5,"right":66.5,"bottom":115.5}},{"unicode":90,"advance":0.6025390625,"planeBounds":{"left":-0.13378906249999997,"top":-0.89713541666666652,"right":0.7412109375,"bottom":0.18619791666666666},"atlasBounds":{"left":21.5,"top":89.5,"right":42.5,"bottom":115.5}},{"unicode":91,"advance":0.2744140625,"planeBounds":{"left":-0.10652669270833336,"top":-0.99723307291666652,"right":0.43513997395833331,"bottom":0.33610026041666663},"atlasBounds":{"left":32.5,"top":0.5,"right":45.5,"bottom":32.5}},{"unicode":92,"advance":0.41796875,"planeBounds":{"left":-0.15820312499999997,"top":-0.887451171875,"right":0.591796875,"bottom":0.23754882812499997},"atlasBounds":{"left":0.5,"top":34.5,"right":18.5,"bottom":61.5}},{"unicode":93,"advance":0.2744140625,"planeBounds":{"left":-0.16463216145833334,"top":-0.99723307291666652,"right":0.37703450520833331,"bottom":0.33610026041666663},"atlasBounds":{"left":46.5,"top":0.5,"right":59.5,"bottom":32.5}},{"unicode":94,"advance":0.427734375,"planeBounds":{"left":-0.16137695312499997,"top":-0.88761393229166663,"right":0.588623046875,"bottom":-0.17928059895833334},"atlasBounds":{"left":213.5,"top":89.5,"right":231.5,"bottom":106.5}},{"unicode":95,"advance":0.451171875,"planeBounds":{"left":-0.17024739583333331,"top":-0.18229166666666663,"right":0.62141927083333337,"bottom":0.27604166666666669},"atlasBounds":{"left":51.5,"top":217.5,"right":70.5,"bottom":228.5}},{"unicode":96,"advance":0.322265625,"planeBounds":{"left":-0.15226236979166669,"top":-0.92626953125,"right":0.43107096354166663,"bottom":-0.42626953125},"atlasBounds":{"left":23.5,"top":217.5,"right":37.5,"bottom":229.5}},{"unicode":97,"advance":0.54150390625,"planeBounds":{"left":-0.12459309895833333,"top":-0.72249348958333337,"right":0.66707356770833337,"bottom":0.19417317708333331},"atlasBounds":{"left":112.5,"top":170.5,"right":131.5,"bottom":192.5}},{"unicode":98,"advance":0.56298828125,"planeBounds":{"left":-0.12394205729166667,"top":-0.9326171875,"right":0.70939127604166663,"bottom":0.19238281249999997},"atlasBounds":{"left":19.5,"top":34.5,"right":39.5,"bottom":61.5}},{"unicode":99,"advance":0.52392578125,"planeBounds":{"left":-0.12898763020833331,"top":-0.72249348958333337,"right":0.66267903645833337,"bottom":0.19417317708333331},"atlasBounds":{"left":59.5,"top":170.5,"right":78.5,"bottom":192.5}},{"unicode":100,"advance":0.56494140625,"planeBounds":{"left":-0.14615885416666666,"top":-0.9326171875,"right":0.68717447916666663,"bottom":0.19238281249999997},"atlasBounds":{"left":40.5,"top":34.5,"right":60.5,"bottom":61.5}},{"unicode":101,"advance":0.53662109375,"planeBounds":{"left":-0.14322916666666666,"top":-0.72249348958333337,"right":0.69010416666666663,"bottom":0.19417317708333331},"atlasBounds":{"left":17.5,"top":170.5,"right":37.5,"bottom":192.5}},{"unicode":102,"advance":0.3544921875,"planeBounds":{"left":-0.14485677083333334,"top":-0.942626953125,"right":0.52180989583333326,"bottom":0.18237304687499997},"atlasBounds":{"left":61.5,"top":34.5,"right":77.5,"bottom":61.5}},{"unicode":103,"advance":0.56689453125,"planeBounds":{"left":-0.14347330729166666,"top":-0.70670572916666652,"right":0.68986002604166663,"bottom":0.37662760416666663},"atlasBounds":{"left":0.5,"top":62.5,"right":20.5,"bottom":88.5}},{"unicode":104,"advance":0.55517578125,"planeBounds":{"left":-0.11775716145833333,"top":-0.91666666666666652,"right":0.67390950520833337,"bottom":0.16666666666666666},"atlasBounds":{"left":185.5,"top":34.5,"right":204.5,"bottom":60.5}},{"unicode":105,"advance":0.255859375,"planeBounds":{"left":-0.12158203125000004,"top":-0.90616861979166652,"right":0.37841796874999989,"bottom":0.17716471354166666},"atlasBounds":{"left":172.5,"top":34.5,"right":184.5,"bottom":60.5}},{"unicode":106,"advance":0.25048828125,"planeBounds":{"left":-0.21500651041666669,"top":-0.90364583333333337,"right":0.36832682291666663,"bottom":0.38802083333333331},"atlasBounds":{"left":144.5,"top":0.5,"right":158.5,"bottom":31.5}},{"unicode":107,"advance":0.52197265625,"planeBounds":{"left":-0.12272135416666667,"top":-0.91666666666666652,"right":0.71061197916666663,"bottom":0.16666666666666666},"atlasBounds":{"left":126.5,"top":34.5,"right":146.5,"bottom":60.5}},{"unicode":108,"advance":0.255859375,"planeBounds":{"left":-0.1014811197916667,"top":-0.91666666666666652,"right":0.35685221354166663,"bottom":0.16666666666666666},"atlasBounds":{"left":114.5,"top":34.5,"right":125.5,"bottom":60.5}},{"unicode":109,"advance":0.87060546875,"planeBounds":{"left":-0.10636393229166667,"top":-0.70654296875,"right":0.97696940104166652,"bottom":0.16845703124999997},"atlasBounds":{"left":132.5,"top":170.5,"right":158.5,"bottom":191.5}},{"unicode":110,"advance":0.55615234375,"planeBounds":{"left":-0.11775716145833333,"top":-0.70654296875,"right":0.67390950520833337,"bottom":0.16845703124999997},"atlasBounds":{"left":27.5,"top":195.5,"right":46.5,"bottom":216.5}},{"unicode":111,"advance":0.5693359375,"planeBounds":{"left":-0.13199869791666666,"top":-0.72249348958333337,"right":0.70133463541666663,"bottom":0.19417317708333331},"atlasBounds":{"left":38.5,"top":170.5,"right":58.5,"bottom":192.5}},{"unicode":112,"advance":0.56298828125,"planeBounds":{"left":-0.12418619791666667,"top":-0.70914713541666652,"right":0.70914713541666663,"bottom":0.37418619791666663},"atlasBounds":{"left":87.5,"top":62.5,"right":107.5,"bottom":88.5}},{"unicode":113,"advance":0.56787109375,"planeBounds":{"left":-0.14640299479166666,"top":-0.70914713541666652,"right":0.68693033854166663,"bottom":0.37418619791666663},"atlasBounds":{"left":0.5,"top":89.5,"right":20.5,"bottom":115.5}},{"unicode":114,"advance":0.3515625,"planeBounds":{"left":-0.11279296875000004,"top":-0.70654296875,"right":0.51220703124999989,"bottom":0.16845703124999997},"atlasBounds":{"left":179.5,"top":170.5,"right":194.5,"bottom":191.5}},{"unicode":115,"advance":0.5166015625,"planeBounds":{"left":-0.14046223958333331,"top":-0.72249348958333337,"right":0.65120442708333337,"bottom":0.19417317708333331},"atlasBounds":{"left":79.5,"top":170.5,"right":98.5,"bottom":192.5}},{"unicode":116,"advance":0.3330078125,"planeBounds":{"left":-0.17830403645833334,"top":-0.823486328125,"right":0.48836263020833331,"bottom":0.17651367187499997},"atlasBounds":{"left":0.5,"top":170.5,"right":16.5,"bottom":194.5}},{"unicode":117,"advance":0.5556640625,"planeBounds":{"left":-0.11897786458333333,"top":-0.69677734375,"right":0.67268880208333337,"bottom":0.17822265624999997},"atlasBounds":{"left":159.5,"top":170.5,"right":178.5,"bottom":191.5}},{"unicode":118,"advance":0.4951171875,"planeBounds":{"left":-0.17008463541666666,"top":-0.70166015625,"right":0.66324869791666663,"bottom":0.17333984374999997},"atlasBounds":{"left":210.5,"top":143.5,"right":230.5,"bottom":164.5}},{"unicode":119,"advance":0.7431640625,"planeBounds":{"left":-0.17081705729166666,"top":-0.70166015625,"right":0.91251627604166652,"bottom":0.17333984374999997},"atlasBounds":{"left":0.5,"top":195.5,"right":26.5,"bottom":216.5}},{"unicode":120,"advance":0.50341796875,"planeBounds":{"left":-0.16471354166666666,"top":-0.70166015625,"right":0.66861979166666663,"bottom":0.17333984374999997},"atlasBounds":{"left":195.5,"top":170.5,"right":215.5,"bottom":191.5}},{"unicode":121,"advance":0.48681640625,"planeBounds":{"left":-0.17374674479166666,"top":-0.69913736979166652,"right":0.65958658854166663,"bottom":0.38419596354166663},"atlasBounds":{"left":45.5,"top":62.5,"right":65.5,"bottom":88.5}},{"unicode":122,"advance":0.50341796875,"planeBounds":{"left":-0.14143880208333331,"top":-0.70166015625,"right":0.65022786458333337,"bottom":0.17333984374999997},"atlasBounds":{"left":212.5,"top":0.5,"right":231.5,"bottom":21.5}},{"unicode":123,"advance":0.33544921875,"planeBounds":{"left":-0.15901692708333334,"top":-0.94783528645833337,"right":0.50764973958333326,"bottom":0.34383138020833331},"atlasBounds":{"left":127.5,"top":0.5,"right":143.5,"bottom":31.5}},{"unicode":124,"advance":0.2509765625,"planeBounds":{"left":-0.08235677083333337,"top":-0.89371744791666652,"right":0.33430989583333331,"bottom":0.31461588541666663},"atlasBounds":{"left":183.5,"top":0.5,"right":193.5,"bottom":29.5}},{"unicode":125,"advance":0.33544921875,"planeBounds":{"left":-0.17268880208333334,"top":-0.94783528645833337,"right":0.49397786458333331,"bottom":0.34383138020833331},"atlasBounds":{"left":81.5,"top":0.5,"right":97.5,"bottom":31.5}},{"unicode":126,"advance":0.66455078125,"planeBounds":{"left":-0.12581380208333331,"top":-0.58561197916666663,"right":0.79085286458333337,"bottom":-0.0022786458333333044},"atlasBounds":{"left":0.5,"top":217.5,"right":22.5,"bottom":231.5}}],"kerning":[]}
diff --git a/web/pw-visualizer/assets/res/fonts/roboto.png b/web/pw-visualizer/assets/res/fonts/roboto.png
new file mode 100644
index 0000000..3723e70
--- /dev/null
+++ b/web/pw-visualizer/assets/res/fonts/roboto.png
Binary files differ
diff --git a/web/pw-visualizer/assets/shaders/frag/msdf.glsl b/web/pw-visualizer/assets/shaders/frag/msdf.glsl
new file mode 100644
index 0000000..5d2325b
--- /dev/null
+++ b/web/pw-visualizer/assets/shaders/frag/msdf.glsl
@@ -0,0 +1,29 @@
+#extension GL_OES_standard_derivatives : enable
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+varying vec2 v_texCoord;
+uniform sampler2D msdf;
+uniform vec4 u_bgColor;
+uniform vec4 u_fgColor;
+
+uniform float u_distanceRange;
+uniform float u_glyphSize;
+uniform vec2 u_resolution;
+uniform vec4 u_viewbox;
+
+float median(float r, float g, float b) {
+ return max(min(r, g), min(max(r, g), b));
+}
+
+void main() {
+ float scale = u_distanceRange / u_glyphSize * u_resolution.y / u_viewbox.w;
+
+ vec3 msd = texture2D(msdf, v_texCoord).rgb;
+ float sd = median(msd.r, msd.g, msd.b);
+ float screenPxRange = max(u_distanceRange, scale);
+ float screenPxDistance = screenPxRange*(sd - 0.5);
+ float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
+ gl_FragColor = vec4(u_fgColor.rgb, u_fgColor.a * opacity);
+} \ No newline at end of file
diff --git a/web/pw-visualizer/src/assets.ts b/web/pw-visualizer/src/assets.ts
index 5fa5215..abd17e4 100644
--- a/web/pw-visualizer/src/assets.ts
+++ b/web/pw-visualizer/src/assets.ts
@@ -9,11 +9,16 @@ export {default as shipPng} from "../assets/res/ship.png";
export {default as fontPng} from "../assets/res/font.png";
+export {default as robotoMsdfPng} from "../assets/res/fonts/roboto.png";
+export {default as robotoMsdfJson} from "../assets/res/fonts/roboto.json";
+
export {default as imageFragmentShader} from "../assets/shaders/frag/image.glsl?url";
export {default as maskedImageFragmentShader} from "../assets/shaders/frag/masked_image.glsl?url";
export {default as simpleFragmentShader} from "../assets/shaders/frag/simple.glsl?url";
export {default as vorFragmentShader} from "../assets/shaders/frag/vor.glsl?url";
+export {default as msdfFragmentShader} from "../assets/shaders/frag/msdf.glsl?url";
+
export {default as imageVertexShader} from "../assets/shaders/vert/image.glsl?url";
export {default as simpleVertexShader} from "../assets/shaders/vert/simple.glsl?url";
diff --git a/web/pw-visualizer/src/index.ts b/web/pw-visualizer/src/index.ts
index 4231707..97bdb3d 100644
--- a/web/pw-visualizer/src/index.ts
+++ b/web/pw-visualizer/src/index.ts
@@ -25,6 +25,7 @@ import { defaultLabelFactory, LabelFactory, Align, Label } from "./webgl/text";
import { VoronoiBuilder } from "./voronoi/voronoi";
import * as assets from "./assets";
import { loadImage, Texture } from "./webgl/texture";
+import { defaultMsdfLabelFactory, MsdfLabelFactory, Label as MsdfLabel } from "./webgl/msdf_text";
function to_bbox(box: number[]): BBox {
@@ -84,7 +85,7 @@ export function init() {
ms_per_frame = parseInt(ELEMENTS["speed"].value);
- GL = CANVAS.getContext("webgl");
+ GL = CANVAS.getContext("webgl", { antialias: true });
GL.clearColor(0, 0, 0, 1);
GL.clear(GL.COLOR_BUFFER_BIT);
@@ -124,9 +125,12 @@ export class GameInstance {
image_shader: Shader;
masked_image_shader: Shader;
+ msdf_shader: Shader;
+
text_factory: LabelFactory;
- planet_labels: Label[];
- ship_labels: Label[];
+ msdf_text_factory: MsdfLabelFactory;
+ planet_labels: MsdfLabel[];
+ ship_labels: MsdfLabel[];
ship_ibo: IndexBuffer;
ship_vao: VertexArray;
@@ -153,6 +157,7 @@ export class GameInstance {
planets_textures: Texture[],
ship_texture: Texture,
font_texture: Texture,
+ robotoMsdfTexture: Texture,
shaders: Dictionary<ShaderFactory>
) {
this.game = game;
@@ -168,7 +173,9 @@ export class GameInstance {
});
this.masked_image_shader = shaders["masked_image"].create_shader(GL);
+ this.msdf_shader = shaders["msdf"].create_shader(GL);
this.text_factory = defaultLabelFactory(GL, font_texture, this.image_shader);
+ this.msdf_text_factory = defaultMsdfLabelFactory(GL, robotoMsdfTexture, this.msdf_shader);
this.planet_labels = [];
this.ship_labels = [];
@@ -278,11 +285,11 @@ export class GameInstance {
1,
0,
-planets[i * 3],
- -planets[i * 3 + 1] - 1.2,
+ -planets[i * 3 + 1] - 1.171875,
1,
]);
- const label = this.text_factory.build(GL, transform);
+ const label = this.msdf_text_factory.build(GL, transform);
this.planet_labels.push(label);
this.renderer.addRenderable(label.getRenderable(), LAYERS.planet_label);
}
@@ -330,7 +337,7 @@ export class GameInstance {
this.planet_labels[i].setText(
GL,
- "*" + planet_ships[i],
+ "" + planet_ships[i],
Align.Middle,
Align.Begin
);
@@ -375,7 +382,7 @@ export class GameInstance {
const renderable = new DefaultRenderable(ib, vao, this.masked_image_shader, [this.ship_texture], {});
this.renderer.addRenderable(renderable, LAYERS.ship);
- const label = this.text_factory.build(GL);
+ const label = this.msdf_text_factory.build(GL);
this.ship_labels.push(label);
this.renderer.addRenderable(label.getRenderable(), LAYERS.ship_label);
@@ -451,10 +458,11 @@ export class GameInstance {
this.shader,
this.image_shader,
this.masked_image_shader,
+ this.msdf_shader,
];
- // If not playing, still reder with different viewbox, so people can still pan etc.
+ // If not playing, still render with different viewbox, so that panning is still possible
if (!this.playing) {
this.last_time = time;
@@ -595,6 +603,7 @@ export async function set_instance(source: string): Promise<GameInstance> {
loadImage(assets.fontPng),
loadImage(assets.shipPng),
loadImage(assets.earthPng),
+ loadImage(assets.robotoMsdfPng),
];
const shader_promies = [
@@ -630,7 +639,14 @@ export async function set_instance(source: string): Promise<GameInstance> {
assets.simpleVertexShader,
),
])(),
-
+ (async () =>
+ <[string, ShaderFactory]>[
+ "msdf",
+ await ShaderFactory.create_factory(
+ assets.msdfFragmentShader,
+ assets.simpleVertexShader,
+ ),
+ ])(),
];
let shaders_array: [string, ShaderFactory][];
[texture_images, shaders_array] = await Promise.all([
@@ -646,12 +662,15 @@ export async function set_instance(source: string): Promise<GameInstance> {
const fontTexture = Texture.fromImage(GL, texture_images[0], "font");
const shipTexture = Texture.fromImage(GL, texture_images[1], "ship");
const earthTexture = Texture.fromImage(GL, texture_images[2], "earth");
+ const robotoMsdfTexture = Texture.fromImage(GL, texture_images[3], "robotoMsdf");
+
game_instance = new GameInstance(
Game.new(source),
[earthTexture],
shipTexture,
fontTexture,
+ robotoMsdfTexture,
shaders
);
diff --git a/web/pw-visualizer/src/webgl/msdf_text.ts b/web/pw-visualizer/src/webgl/msdf_text.ts
new file mode 100644
index 0000000..5bbac20
--- /dev/null
+++ b/web/pw-visualizer/src/webgl/msdf_text.ts
@@ -0,0 +1,181 @@
+import { Shader, Uniform1f, Uniform4f, UniformMatrix3fv } from "./shader";
+import { Texture } from "./texture";
+import { DefaultRenderable } from "./renderer";
+import { IndexBuffer, VertexBuffer } from "./buffer";
+import { VertexBufferLayout, VertexArray } from "./vertexBufferLayout";
+import { robotoMsdfJson } from "../assets";
+import { GlypInfo } from "./text";
+
+
+export enum Align {
+ Begin,
+ End,
+ Middle,
+}
+
+export type FontAtlas = {
+ atlas: AtlasMeta,
+ metrics: Metrics,
+ glyphs: Glyph[],
+}
+
+export type AtlasMeta = {
+ type: string,
+ distanceRange: number,
+ size: number,
+ width: number,
+ height: number,
+ yOrigin: string,
+}
+
+export type Metrics = {
+ emSize: number,
+ lineHeight: number,
+ ascender: number,
+ descender: number,
+ underlineY: number,
+ underlineThickness: number,
+}
+
+
+export type Glyph = {
+ unicode: number,
+ advance: number,
+ planeBounds?: Bounds,
+ atlasBounds?: Bounds,
+}
+
+export type Bounds = {
+ left: number,
+ bottom: number,
+ right: number,
+ top: number,
+}
+
+
+export class MsdfLabelFactory {
+ texture: Texture;
+ font: FontAtlas;
+ shader: Shader;
+
+ constructor(gl: WebGLRenderingContext, fontTexture: Texture, font: FontAtlas, shader: Shader) {
+ this.texture = fontTexture;
+ this.font = font;
+ this.shader = shader;
+ }
+
+ build(gl: WebGLRenderingContext, transform?: UniformMatrix3fv): Label {
+ return new Label(gl, this.shader, this.texture, this.font, transform);
+ }
+}
+
+export class Label {
+ inner: DefaultRenderable;
+
+ font: FontAtlas;
+ charAtlas: {[unicodeNumber: number]: Glyph};
+
+ constructor(gl: WebGLRenderingContext, shader: Shader, tex: Texture, font: FontAtlas, transform: UniformMatrix3fv) {
+ this.font = font;
+ this.charAtlas = {}
+ this.font.glyphs.forEach((glyph) => {
+ this.charAtlas[glyph.unicode] = glyph;
+ });
+
+ const uniforms = {
+ "u_trans": transform,
+ "u_trans_next": transform,
+ "u_fgColor": new Uniform4f([1.0, 1.0, 1.0, 1.0]),
+ "u_bgColor": new Uniform4f([0.0, 0.0, 0.0, 1.0]),
+ "u_distanceRange": new Uniform1f(font.atlas.distanceRange),
+ "u_glyphSize": new Uniform1f(font.atlas.size),
+ };
+ const ib = new IndexBuffer(gl, []);
+ const vb_pos = new VertexBuffer(gl, []);
+ const vb_tex = new VertexBuffer(gl, []);
+
+ const layout_pos = new VertexBufferLayout();
+ layout_pos.push(gl.FLOAT, 2, 4, "a_position");
+
+ const layout_tex = new VertexBufferLayout();
+ layout_tex.push(gl.FLOAT, 2, 4, "a_texCoord");
+
+ const vao = new VertexArray();
+ vao.addBuffer(vb_pos, layout_pos);
+ vao.addBuffer(vb_tex, layout_tex);
+
+ this.inner = new DefaultRenderable(ib, vao, shader, [tex], uniforms);
+ }
+
+ getRenderable(): DefaultRenderable {
+ return this.inner;
+ }
+
+ setText(gl: WebGLRenderingContext, text: string, h_align = Align.Begin, v_align = Align.Begin) {
+ const idxs = [];
+ const verts_pos = [];
+ const verts_tex = [];
+
+ let xPos = 0;
+ let yPos = 0;
+ switch (v_align) {
+ case Align.Begin:
+ yPos = -1;
+ break;
+ case Align.End:
+ yPos = 0;
+ break;
+ case Align.Middle:
+ yPos = -0.5;
+ break;
+ }
+
+ // track position in the index buffer
+ let bufPos = 0;
+ for (let charIndex = 0; charIndex < text.length; charIndex++) {
+ let char = this.charAtlas[text.charCodeAt(charIndex)]
+ if (char.atlasBounds && char.planeBounds) {
+ verts_pos.push(xPos + char.planeBounds.left, yPos-char.planeBounds.top);
+ verts_pos.push(xPos + char.planeBounds.right, yPos-char.planeBounds.top);
+ verts_pos.push(xPos + char.planeBounds.left, yPos-char.planeBounds.bottom);
+ verts_pos.push(xPos + char.planeBounds.right, yPos-char.planeBounds.bottom);
+
+ const atlasWidth = this.font.atlas.width;
+ const atlasHeight = this.font.atlas.height;
+
+ verts_tex.push(char.atlasBounds.left / atlasWidth, char.atlasBounds.top / atlasHeight);
+ verts_tex.push(char.atlasBounds.right / atlasWidth, char.atlasBounds.top / atlasHeight);
+ verts_tex.push(char.atlasBounds.left / atlasWidth, char.atlasBounds.bottom / atlasHeight);
+ verts_tex.push(char.atlasBounds.right / atlasWidth, char.atlasBounds.bottom / atlasHeight);
+
+ idxs.push(bufPos+0, bufPos+1, bufPos+2);
+ idxs.push(bufPos+1, bufPos+2, bufPos+3);
+ bufPos += 4;
+ }
+ xPos += char.advance;
+ }
+
+ let shift = 0;
+ switch (h_align) {
+ case Align.End:
+ shift = xPos;
+ break;
+ case Align.Middle:
+ shift = xPos / 2;
+ break;
+ }
+
+ for (let i = 0; i < verts_pos.length; i += 2) {
+ verts_pos[i] -= shift;
+ }
+
+
+ this.inner.updateIndexBuffer(gl, idxs);
+ this.inner.updateVAOBuffer(gl, 0, verts_pos);
+ this.inner.updateVAOBuffer(gl, 1, verts_tex);
+ }
+}
+
+export function defaultMsdfLabelFactory(gl: WebGLRenderingContext, fontTexture: Texture, shader: Shader): MsdfLabelFactory {
+ return new MsdfLabelFactory(gl, fontTexture, robotoMsdfJson, shader);
+}
diff --git a/web/pw-visualizer/src/webgl/texture.ts b/web/pw-visualizer/src/webgl/texture.ts
index 9624489..9ebd5c0 100644
--- a/web/pw-visualizer/src/webgl/texture.ts
+++ b/web/pw-visualizer/src/webgl/texture.ts
@@ -67,8 +67,14 @@ export class Texture {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ if (name == "font") {
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ } else {
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+
+ }
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA,
gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));
diff --git a/web/pw-visualizer/src/webgl/util.ts b/web/pw-visualizer/src/webgl/util.ts
index 7b55d19..922b016 100644
--- a/web/pw-visualizer/src/webgl/util.ts
+++ b/web/pw-visualizer/src/webgl/util.ts
@@ -74,6 +74,7 @@ export class Resizer {
mouse_pos = [0, 0];
last_drag = [0, 0];
+ // x, y, w, h
viewbox: number[];
orig_viewbox: number[];