Add font rendering
This commit is contained in:
parent
4ffd8e333f
commit
e103fa6e3b
198
assets/fonts/arial.fnt
Normal file
198
assets/fonts/arial.fnt
Normal file
@ -0,0 +1,198 @@
|
||||
info face="Arial" size=82 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=3,3,3,3 spacing=-2,-2
|
||||
common lineHeight=100 base=75 scaleW=512 scaleH=512 pages=1 packed=0
|
||||
page id=0 file="arial.png"
|
||||
chars count=97
|
||||
char id=0 x=344 y=346 width=48 height=58 xoffset=7 yoffset=20 xadvance=66 page=0 chnl=0
|
||||
char id=10 x=0 y=0 width=0 height=0 xoffset=-3 yoffset=0 xadvance=4 page=0 chnl=0
|
||||
char id=32 x=0 y=0 width=0 height=0 xoffset=-3 yoffset=0 xadvance=27 page=0 chnl=0
|
||||
char id=33 x=118 y=346 width=13 height=65 xoffset=6 yoffset=13 xadvance=29 page=0 chnl=0
|
||||
char id=34 x=250 y=462 width=28 height=27 xoffset=0 yoffset=13 xadvance=33 page=0 chnl=0
|
||||
char id=35 x=191 y=346 width=49 height=65 xoffset=-2 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=36 x=269 y=0 width=44 height=76 xoffset=0 yoffset=10 xadvance=50 page=0 chnl=0
|
||||
char id=37 x=158 y=83 width=69 height=67 xoffset=2 yoffset=12 xadvance=77 page=0 chnl=0
|
||||
char id=38 x=227 y=83 width=55 height=67 xoffset=1 yoffset=12 xadvance=59 page=0 chnl=0
|
||||
char id=39 x=489 y=411 width=13 height=27 xoffset=1 yoffset=13 xadvance=20 page=0 chnl=0
|
||||
char id=40 x=177 y=0 width=25 height=81 xoffset=2 yoffset=13 xadvance=31 page=0 chnl=0
|
||||
char id=41 x=202 y=0 width=25 height=81 xoffset=0 yoffset=13 xadvance=31 page=0 chnl=0
|
||||
char id=42 x=216 y=462 width=34 height=31 xoffset=0 yoffset=13 xadvance=36 page=0 chnl=0
|
||||
char id=43 x=88 y=462 width=45 height=45 xoffset=1 yoffset=24 xadvance=52 page=0 chnl=0
|
||||
char id=44 x=278 y=462 width=13 height=26 xoffset=4 yoffset=65 xadvance=27 page=0 chnl=0
|
||||
char id=45 x=371 y=462 width=28 height=13 xoffset=0 yoffset=47 xadvance=31 page=0 chnl=0
|
||||
char id=46 x=358 y=462 width=13 height=13 xoffset=4 yoffset=65 xadvance=27 page=0 chnl=0
|
||||
char id=47 x=131 y=346 width=30 height=65 xoffset=-3 yoffset=13 xadvance=27 page=0 chnl=0
|
||||
char id=48 x=309 y=150 width=44 height=66 xoffset=1 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=49 x=0 y=346 width=28 height=65 xoffset=6 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=50 x=28 y=346 width=46 height=65 xoffset=-2 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=51 x=131 y=150 width=44 height=66 xoffset=1 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=52 x=240 y=346 width=47 height=64 xoffset=-2 yoffset=14 xadvance=50 page=0 chnl=0
|
||||
char id=53 x=74 y=346 width=44 height=65 xoffset=1 yoffset=14 xadvance=50 page=0 chnl=0
|
||||
char id=54 x=175 y=150 width=46 height=66 xoffset=-1 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=55 x=287 y=346 width=44 height=64 xoffset=1 yoffset=14 xadvance=50 page=0 chnl=0
|
||||
char id=56 x=221 y=150 width=44 height=66 xoffset=1 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=57 x=265 y=150 width=44 height=66 xoffset=1 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=58 x=476 y=411 width=13 height=49 xoffset=4 yoffset=29 xadvance=27 page=0 chnl=0
|
||||
char id=59 x=331 y=346 width=13 height=62 xoffset=4 yoffset=29 xadvance=27 page=0 chnl=0
|
||||
char id=60 x=0 y=462 width=44 height=45 xoffset=2 yoffset=24 xadvance=52 page=0 chnl=0
|
||||
char id=61 x=171 y=462 width=45 height=31 xoffset=1 yoffset=30 xadvance=52 page=0 chnl=0
|
||||
char id=62 x=44 y=462 width=44 height=45 xoffset=2 yoffset=24 xadvance=52 page=0 chnl=0
|
||||
char id=63 x=353 y=150 width=44 height=66 xoffset=1 yoffset=12 xadvance=50 page=0 chnl=0
|
||||
char id=64 x=70 y=0 width=82 height=83 xoffset=1 yoffset=12 xadvance=87 page=0 chnl=0
|
||||
char id=65 x=397 y=150 width=63 height=65 xoffset=-5 yoffset=13 xadvance=59 page=0 chnl=0
|
||||
char id=66 x=460 y=150 width=50 height=65 xoffset=4 yoffset=13 xadvance=59 page=0 chnl=0
|
||||
char id=67 x=375 y=0 width=57 height=67 xoffset=1 yoffset=12 xadvance=63 page=0 chnl=0
|
||||
char id=68 x=0 y=216 width=54 height=65 xoffset=4 yoffset=13 xadvance=63 page=0 chnl=0
|
||||
char id=69 x=54 y=216 width=50 height=65 xoffset=4 yoffset=13 xadvance=59 page=0 chnl=0
|
||||
char id=70 x=104 y=216 width=45 height=65 xoffset=4 yoffset=13 xadvance=54 page=0 chnl=0
|
||||
char id=71 x=432 y=0 width=61 height=67 xoffset=1 yoffset=12 xadvance=68 page=0 chnl=0
|
||||
char id=72 x=149 y=216 width=51 height=65 xoffset=4 yoffset=13 xadvance=63 page=0 chnl=0
|
||||
char id=73 x=489 y=83 width=14 height=65 xoffset=4 yoffset=13 xadvance=27 page=0 chnl=0
|
||||
char id=74 x=282 y=83 width=38 height=66 xoffset=-1 yoffset=13 xadvance=45 page=0 chnl=0
|
||||
char id=75 x=200 y=216 width=55 height=65 xoffset=4 yoffset=13 xadvance=59 page=0 chnl=0
|
||||
char id=76 x=255 y=216 width=42 height=65 xoffset=4 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=77 x=297 y=216 width=63 height=65 xoffset=2 yoffset=13 xadvance=71 page=0 chnl=0
|
||||
char id=78 x=360 y=216 width=51 height=65 xoffset=4 yoffset=13 xadvance=63 page=0 chnl=0
|
||||
char id=79 x=0 y=83 width=62 height=67 xoffset=1 yoffset=12 xadvance=68 page=0 chnl=0
|
||||
char id=80 x=411 y=216 width=50 height=65 xoffset=4 yoffset=13 xadvance=59 page=0 chnl=0
|
||||
char id=81 x=313 y=0 width=62 height=71 xoffset=1 yoffset=12 xadvance=68 page=0 chnl=0
|
||||
char id=82 x=0 y=281 width=56 height=65 xoffset=4 yoffset=13 xadvance=63 page=0 chnl=0
|
||||
char id=83 x=62 y=83 width=53 height=67 xoffset=1 yoffset=12 xadvance=59 page=0 chnl=0
|
||||
char id=84 x=56 y=281 width=52 height=65 xoffset=-1 yoffset=13 xadvance=54 page=0 chnl=0
|
||||
char id=85 x=320 y=83 width=51 height=66 xoffset=4 yoffset=13 xadvance=63 page=0 chnl=0
|
||||
char id=86 x=108 y=281 width=63 height=65 xoffset=-4 yoffset=13 xadvance=59 page=0 chnl=0
|
||||
char id=87 x=171 y=281 width=85 height=65 xoffset=-2 yoffset=13 xadvance=85 page=0 chnl=0
|
||||
char id=88 x=256 y=281 width=59 height=65 xoffset=-3 yoffset=13 xadvance=58 page=0 chnl=0
|
||||
char id=89 x=315 y=281 width=60 height=65 xoffset=-3 yoffset=13 xadvance=58 page=0 chnl=0
|
||||
char id=90 x=375 y=281 width=52 height=65 xoffset=-1 yoffset=13 xadvance=54 page=0 chnl=0
|
||||
char id=91 x=227 y=0 width=21 height=81 xoffset=2 yoffset=13 xadvance=27 page=0 chnl=0
|
||||
char id=92 x=161 y=346 width=30 height=65 xoffset=-3 yoffset=13 xadvance=27 page=0 chnl=0
|
||||
char id=93 x=248 y=0 width=21 height=81 xoffset=0 yoffset=13 xadvance=27 page=0 chnl=0
|
||||
char id=94 x=133 y=462 width=38 height=38 xoffset=-1 yoffset=12 xadvance=40 page=0 chnl=0
|
||||
char id=95 x=399 y=462 width=55 height=13 xoffset=-4 yoffset=81 xadvance=50 page=0 chnl=0
|
||||
char id=96 x=338 y=462 width=20 height=17 xoffset=0 yoffset=13 xadvance=31 page=0 chnl=0
|
||||
char id=97 x=392 y=346 width=46 height=51 xoffset=0 yoffset=28 xadvance=50 page=0 chnl=0
|
||||
char id=98 x=371 y=83 width=43 height=66 xoffset=2 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=99 x=438 y=346 width=43 height=51 xoffset=0 yoffset=28 xadvance=45 page=0 chnl=0
|
||||
char id=100 x=414 y=83 width=43 height=66 xoffset=0 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=101 x=0 y=411 width=46 height=51 xoffset=0 yoffset=28 xadvance=50 page=0 chnl=0
|
||||
char id=102 x=457 y=83 width=32 height=66 xoffset=-1 yoffset=12 xadvance=28 page=0 chnl=0
|
||||
char id=103 x=115 y=83 width=43 height=67 xoffset=0 yoffset=28 xadvance=49 page=0 chnl=0
|
||||
char id=104 x=461 y=216 width=40 height=65 xoffset=3 yoffset=13 xadvance=50 page=0 chnl=0
|
||||
char id=105 x=493 y=0 width=13 height=65 xoffset=3 yoffset=13 xadvance=22 page=0 chnl=0
|
||||
char id=106 x=152 y=0 width=25 height=82 xoffset=-7 yoffset=13 xadvance=21 page=0 chnl=0
|
||||
char id=107 x=427 y=281 width=41 height=65 xoffset=2 yoffset=13 xadvance=45 page=0 chnl=0
|
||||
char id=108 x=468 y=281 width=13 height=65 xoffset=3 yoffset=13 xadvance=22 page=0 chnl=0
|
||||
char id=109 x=133 y=411 width=63 height=50 xoffset=2 yoffset=28 xadvance=71 page=0 chnl=0
|
||||
char id=110 x=196 y=411 width=40 height=50 xoffset=3 yoffset=28 xadvance=50 page=0 chnl=0
|
||||
char id=111 x=46 y=411 width=46 height=51 xoffset=0 yoffset=28 xadvance=50 page=0 chnl=0
|
||||
char id=112 x=0 y=150 width=43 height=66 xoffset=2 yoffset=28 xadvance=50 page=0 chnl=0
|
||||
char id=113 x=43 y=150 width=43 height=66 xoffset=0 yoffset=28 xadvance=49 page=0 chnl=0
|
||||
char id=114 x=481 y=346 width=29 height=50 xoffset=3 yoffset=28 xadvance=31 page=0 chnl=0
|
||||
char id=115 x=92 y=411 width=41 height=51 xoffset=0 yoffset=28 xadvance=45 page=0 chnl=0
|
||||
char id=116 x=481 y=281 width=26 height=65 xoffset=-1 yoffset=14 xadvance=27 page=0 chnl=0
|
||||
char id=117 x=236 y=411 width=40 height=50 xoffset=3 yoffset=29 xadvance=50 page=0 chnl=0
|
||||
char id=118 x=276 y=411 width=45 height=49 xoffset=-2 yoffset=29 xadvance=45 page=0 chnl=0
|
||||
char id=119 x=321 y=411 width=66 height=49 xoffset=-4 yoffset=29 xadvance=61 page=0 chnl=0
|
||||
char id=120 x=387 y=411 width=46 height=49 xoffset=-2 yoffset=29 xadvance=45 page=0 chnl=0
|
||||
char id=121 x=86 y=150 width=45 height=66 xoffset=-2 yoffset=29 xadvance=43 page=0 chnl=0
|
||||
char id=122 x=433 y=411 width=43 height=49 xoffset=-2 yoffset=29 xadvance=44 page=0 chnl=0
|
||||
char id=123 x=0 y=0 width=29 height=83 xoffset=-1 yoffset=12 xadvance=31 page=0 chnl=0
|
||||
char id=124 x=58 y=0 width=12 height=83 xoffset=4 yoffset=13 xadvance=24 page=0 chnl=0
|
||||
char id=125 x=29 y=0 width=29 height=83 xoffset=-1 yoffset=12 xadvance=31 page=0 chnl=0
|
||||
char id=126 x=291 y=462 width=47 height=21 xoffset=0 yoffset=37 xadvance=52 page=0 chnl=0
|
||||
kernings count=96
|
||||
kerning first=121 second=46 amount=-6
|
||||
kerning first=84 second=45 amount=-5
|
||||
kerning first=86 second=44 amount=-8
|
||||
kerning first=114 second=46 amount=-5
|
||||
kerning first=114 second=44 amount=-5
|
||||
kerning first=49 second=49 amount=-6
|
||||
kerning first=89 second=65 amount=-6
|
||||
kerning first=84 second=79 amount=-1
|
||||
kerning first=65 second=84 amount=-6
|
||||
kerning first=76 second=86 amount=-6
|
||||
kerning first=65 second=87 amount=-3
|
||||
kerning first=76 second=89 amount=-6
|
||||
kerning first=84 second=99 amount=-9
|
||||
kerning first=86 second=101 amount=-5
|
||||
kerning first=102 second=102 amount=-1
|
||||
kerning first=89 second=105 amount=-3
|
||||
kerning first=86 second=58 amount=-3
|
||||
kerning first=86 second=111 amount=-5
|
||||
kerning first=89 second=112 amount=-6
|
||||
kerning first=89 second=113 amount=-8
|
||||
kerning first=86 second=114 amount=-3
|
||||
kerning first=89 second=117 amount=-5
|
||||
kerning first=65 second=118 amount=-1
|
||||
kerning first=84 second=119 amount=-5
|
||||
kerning first=76 second=121 amount=-3
|
||||
kerning first=82 second=84 amount=-1
|
||||
kerning first=89 second=58 amount=-5
|
||||
kerning first=87 second=65 amount=-3
|
||||
kerning first=87 second=97 amount=-3
|
||||
kerning first=87 second=59 amount=-1
|
||||
kerning first=82 second=87 amount=-1
|
||||
kerning first=118 second=46 amount=-6
|
||||
kerning first=65 second=89 amount=-6
|
||||
kerning first=65 second=86 amount=-6
|
||||
kerning first=80 second=44 amount=-11
|
||||
kerning first=86 second=46 amount=-8
|
||||
kerning first=84 second=105 amount=-3
|
||||
kerning first=84 second=97 amount=-9
|
||||
kerning first=84 second=114 amount=-3
|
||||
kerning first=80 second=65 amount=-6
|
||||
kerning first=84 second=58 amount=-9
|
||||
kerning first=86 second=97 amount=-6
|
||||
kerning first=76 second=84 amount=-6
|
||||
kerning first=89 second=59 amount=-5
|
||||
kerning first=70 second=44 amount=-9
|
||||
kerning first=80 second=46 amount=-11
|
||||
kerning first=89 second=101 amount=-8
|
||||
kerning first=65 second=119 amount=-1
|
||||
kerning first=87 second=121 amount=-1
|
||||
kerning first=76 second=87 amount=-6
|
||||
kerning first=86 second=45 amount=-5
|
||||
kerning first=32 second=89 amount=-1
|
||||
kerning first=84 second=117 amount=-3
|
||||
kerning first=89 second=118 amount=-5
|
||||
kerning first=65 second=32 amount=-5
|
||||
kerning first=86 second=65 amount=-6
|
||||
kerning first=84 second=111 amount=-9
|
||||
kerning first=89 second=45 amount=-8
|
||||
kerning first=65 second=121 amount=-1
|
||||
kerning first=87 second=58 amount=-1
|
||||
kerning first=82 second=89 amount=-1
|
||||
kerning first=89 second=44 amount=-11
|
||||
kerning first=32 second=84 amount=-1
|
||||
kerning first=87 second=111 amount=-1
|
||||
kerning first=84 second=59 amount=-9
|
||||
kerning first=84 second=101 amount=-9
|
||||
kerning first=84 second=32 amount=-1
|
||||
kerning first=86 second=59 amount=-3
|
||||
kerning first=89 second=46 amount=-11
|
||||
kerning first=87 second=101 amount=-1
|
||||
kerning first=32 second=65 amount=-5
|
||||
kerning first=84 second=44 amount=-9
|
||||
kerning first=70 second=65 amount=-5
|
||||
kerning first=86 second=117 amount=-3
|
||||
kerning first=84 second=115 amount=-9
|
||||
kerning first=84 second=65 amount=-6
|
||||
kerning first=89 second=32 amount=-1
|
||||
kerning first=87 second=44 amount=-5
|
||||
kerning first=89 second=111 amount=-8
|
||||
kerning first=89 second=97 amount=-6
|
||||
kerning first=119 second=46 amount=-5
|
||||
kerning first=87 second=46 amount=-5
|
||||
kerning first=82 second=86 amount=-1
|
||||
kerning first=121 second=44 amount=-6
|
||||
kerning first=84 second=46 amount=-9
|
||||
kerning first=80 second=32 amount=-1
|
||||
kerning first=87 second=114 amount=-1
|
||||
kerning first=119 second=44 amount=-5
|
||||
kerning first=76 second=32 amount=-3
|
||||
kerning first=84 second=121 amount=-5
|
||||
kerning first=86 second=121 amount=-3
|
||||
kerning first=70 second=46 amount=-9
|
||||
kerning first=87 second=45 amount=-1
|
||||
kerning first=118 second=44 amount=-6
|
||||
kerning first=87 second=117 amount=-1
|
||||
kerning first=86 second=105 amount=-1
|
BIN
assets/fonts/arial.png
Normal file
BIN
assets/fonts/arial.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
10
assets/shaders/font.fs
Normal file
10
assets/shaders/font.fs
Normal file
@ -0,0 +1,10 @@
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 uv;
|
||||
|
||||
uniform vec3 uColor;
|
||||
uniform sampler2D texture0;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(uColor, texture2D(texture0, uv).a);
|
||||
}
|
12
assets/shaders/font.vs
Normal file
12
assets/shaders/font.vs
Normal file
@ -0,0 +1,12 @@
|
||||
precision mediump float;
|
||||
|
||||
attribute vec2 aVertexPosition;
|
||||
attribute vec2 aTexCoords;
|
||||
|
||||
varying vec2 uv;
|
||||
uniform mat4 uTransformation;
|
||||
|
||||
void main() {
|
||||
gl_Position = uTransformation * vec4(aVertexPosition, 0.0, 1.0);
|
||||
uv = aTexCoords;
|
||||
}
|
425
src/engine/gui/font.js
Normal file
425
src/engine/gui/font.js
Normal file
@ -0,0 +1,425 @@
|
||||
import Resource from '../resource'
|
||||
import Screen from '../screen'
|
||||
import { Mesh } from '../mesh'
|
||||
import { Texture } from '../mesh/material'
|
||||
import { Node2D } from './'
|
||||
|
||||
import { mat4 } from 'gl-matrix'
|
||||
|
||||
const aspectRatio = Screen.width / Screen.height
|
||||
const PAD_TOP = 0
|
||||
const PAD_LEFT = 1
|
||||
const PAD_BOTTOM = 2
|
||||
const PAD_RIGHT = 3
|
||||
const DESIRED_PADDING = 3
|
||||
|
||||
const SPLITTER = ' '
|
||||
const NUMBER_SEPARATOR = ','
|
||||
|
||||
const LINE_HEIGHT = 0.03
|
||||
const SPACE_ASCII = 32
|
||||
const NL_ASCII = 10
|
||||
|
||||
class Character {
|
||||
constructor (id, xTexCoord, yTexCoord, xTexSize, yTexSize,
|
||||
xOffset, yOffset, sizeX, sizeY, xAdvance) {
|
||||
this.id = id
|
||||
this.xTexCoord = xTexCoord
|
||||
this.yTexCoord = yTexCoord
|
||||
this.xTexSize = xTexSize
|
||||
this.yTexSize = yTexSize
|
||||
this.xOffset = xOffset
|
||||
this.yOffset = yOffset
|
||||
this.sizeX = sizeX
|
||||
this.sizeY = sizeY
|
||||
this.xMaxTexCoord = xTexSize + xTexCoord
|
||||
this.yMaxTexCoord = yTexSize + yTexCoord
|
||||
this.xAdvance = xAdvance
|
||||
}
|
||||
}
|
||||
|
||||
class Word {
|
||||
constructor (fontSize) {
|
||||
this.fontSize = fontSize
|
||||
this.characters = []
|
||||
this.width = 0
|
||||
}
|
||||
|
||||
addCharacter (char) {
|
||||
this.characters.push(char)
|
||||
this.width += char.xAdvance * this.fontSize
|
||||
}
|
||||
}
|
||||
|
||||
class Line {
|
||||
constructor (spaceWidth, fontSize, maxLength) {
|
||||
this.spaceSize = spaceWidth * fontSize
|
||||
this.maxLength = maxLength
|
||||
this.words = []
|
||||
this.lineLength = 0
|
||||
}
|
||||
|
||||
attemptToAddWord (word) {
|
||||
let additionalLength = word.width
|
||||
additionalLength += this.words.length ? this.spaceSize : 0
|
||||
if (this.lineLength + additionalLength <= this.maxLength) {
|
||||
this.words.push(word)
|
||||
this.lineLength += additionalLength
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
class FontFile {
|
||||
constructor (name) {
|
||||
this.name = name
|
||||
this.values = {}
|
||||
this.metadata = {}
|
||||
}
|
||||
|
||||
getValue (vals, key) {
|
||||
return parseInt(vals[key])
|
||||
}
|
||||
|
||||
getValues (vals, key) {
|
||||
let nums = vals[key].split(NUMBER_SEPARATOR)
|
||||
let result = []
|
||||
for (let i in nums) {
|
||||
result.push(parseInt(nums[i]))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
readValues (data) {
|
||||
let lines = data.split('\n')
|
||||
for (let i in lines) {
|
||||
let line = lines[i]
|
||||
let lineSplit = line.split(SPLITTER)
|
||||
let lineValues = {}
|
||||
|
||||
for (let j in lineSplit) {
|
||||
let valuePairs = lineSplit[j].split('=')
|
||||
if (valuePairs.length === 2) {
|
||||
let key = valuePairs[0]
|
||||
let val = valuePairs[1]
|
||||
lineValues[key] = val
|
||||
}
|
||||
}
|
||||
|
||||
if (lineSplit[0] === 'info') {
|
||||
this.padding = this.getValues(lineValues, 'padding')
|
||||
this.paddingWidth = this.padding[PAD_LEFT] + this.padding[PAD_RIGHT]
|
||||
this.paddingHeight = this.padding[PAD_TOP] + this.padding[PAD_BOTTOM]
|
||||
} else if (lineSplit[0] === 'common') {
|
||||
let lineHeightPixels = this.getValue(lineValues, 'lineHeight') - this.paddingHeight
|
||||
this.vertPerPixelSize = LINE_HEIGHT / lineHeightPixels
|
||||
this.horizPixelSize = this.vertPerPixelSize / aspectRatio
|
||||
} else if (lineSplit[0] === 'char') {
|
||||
let c = this.loadCharacter(lineValues, this.getValue(this.values, 'scaleW'))
|
||||
if (c) this.metadata[c.id] = c
|
||||
continue
|
||||
} else if (lineSplit[0] === 'kernings' || lineSplit[0] === 'kerning' || lineSplit[0] === 'chars') {
|
||||
continue
|
||||
}
|
||||
for (let j in lineValues) {
|
||||
this.values[j] = lineValues[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadCharacter (values, imageSize) {
|
||||
let id = this.getValue(values, 'id')
|
||||
if (id === SPACE_ASCII) {
|
||||
this.spaceWidth = (this.getValue(values, 'xadvance') - this.paddingWidth) * this.horizPixelSize
|
||||
return null
|
||||
}
|
||||
let xTex = (this.getValue(values, 'x') + (this.padding[PAD_LEFT] - DESIRED_PADDING)) / imageSize
|
||||
let yTex = (this.getValue(values, 'y') + (this.padding[PAD_TOP] - DESIRED_PADDING)) / imageSize
|
||||
let width = this.getValue(values, 'width') - (this.paddingWidth - (2 * DESIRED_PADDING))
|
||||
let height = this.getValue(values, 'height') - ((this.paddingHeight) - (2 * DESIRED_PADDING))
|
||||
let quadWidth = width * this.horizPixelSize
|
||||
let quadHeight = height * this.vertPerPixelSize
|
||||
let xTexSize = width / imageSize
|
||||
let yTexSize = height / imageSize
|
||||
let xOff = (this.getValue(values, 'xoffset') + this.padding[PAD_LEFT] - DESIRED_PADDING) * this.horizPixelSize
|
||||
let yOff = (this.getValue(values, 'yoffset') + (this.padding[PAD_TOP] - DESIRED_PADDING)) * this.vertPerPixelSize
|
||||
let xAdvance = (this.getValue(values, 'xadvance') - this.paddingWidth) * this.horizPixelSize
|
||||
return new Character(id, xTex, yTex, xTexSize, yTexSize, xOff, yOff, quadWidth, quadHeight, xAdvance)
|
||||
}
|
||||
|
||||
getCharacter (ascii) {
|
||||
return this.metadata[ascii]
|
||||
}
|
||||
|
||||
static async fromFile (fontName) {
|
||||
let load = await Resource.GET('/assets/fonts/' + fontName + '.fnt')
|
||||
let file = new FontFile(fontName)
|
||||
file.readValues(load)
|
||||
console.log(file)
|
||||
return file
|
||||
}
|
||||
}
|
||||
|
||||
class Font {
|
||||
constructor (name, metadata) {
|
||||
this.name = name
|
||||
this.metadata = metadata
|
||||
this.texture = null
|
||||
}
|
||||
|
||||
static async fromFile (name) {
|
||||
let meta = await FontFile.fromFile(name)
|
||||
return new Font(name, meta)
|
||||
}
|
||||
|
||||
async loadTextures (gl) {
|
||||
this.texture = await Texture.createTexture2D(gl, await Resource.loadImage('/assets/fonts/' + this.name + '.png'), false, gl.LINEAR)
|
||||
}
|
||||
|
||||
createTextMesh (gl, text) {
|
||||
let lines = this.createStructure(text)
|
||||
let data = this.createQuadVertices(text, lines)
|
||||
return Mesh.constructFromVerticesUVs(gl, data.vertices, data.textureCoords)
|
||||
}
|
||||
|
||||
createStructure (text) {
|
||||
let chars = text.asCharacters
|
||||
let lines = []
|
||||
let currentLine = new Line(this.metadata.spaceWidth, text.fontSize, text.lineLength)
|
||||
let currentWord = new Word(text.fontSize)
|
||||
for (let c in chars) {
|
||||
let ascii = parseInt(chars[c])
|
||||
if (ascii === SPACE_ASCII) {
|
||||
let added = currentLine.attemptToAddWord(currentWord)
|
||||
if (!added) {
|
||||
lines.push(currentLine)
|
||||
currentLine = new Line(this.metadata.spaceWidth, text.fontSize, text.lineLength)
|
||||
currentLine.attemptToAddWord(currentWord)
|
||||
}
|
||||
currentWord = new Word(text.fontSize)
|
||||
continue
|
||||
}
|
||||
|
||||
if (ascii === NL_ASCII) {
|
||||
let added = currentLine.attemptToAddWord(currentWord)
|
||||
if (!added) {
|
||||
lines.push(currentLine)
|
||||
currentLine = new Line(this.metadata.spaceWidth, text.fontSize, text.lineLength)
|
||||
currentLine.attemptToAddWord(currentWord)
|
||||
}
|
||||
lines.push(currentLine)
|
||||
currentLine = new Line(this.metadata.spaceWidth, text.fontSize, text.lineLength)
|
||||
currentWord = new Word(text.fontSize)
|
||||
continue
|
||||
}
|
||||
|
||||
let character = this.metadata.getCharacter(ascii)
|
||||
currentWord.addCharacter(character)
|
||||
}
|
||||
this.completeStructure(lines, currentLine, currentWord, text)
|
||||
return lines
|
||||
}
|
||||
|
||||
completeStructure (lines, currentLine, currentWord, text) {
|
||||
let added = currentLine.attemptToAddWord(currentWord)
|
||||
if (!added) {
|
||||
lines.push(currentLine)
|
||||
currentLine = new Line(this.metadata.spaceWidth, text.fontSize, text.lineLength)
|
||||
currentLine.attemptToAddWord(currentWord)
|
||||
}
|
||||
lines.push(currentLine)
|
||||
return lines
|
||||
}
|
||||
|
||||
createQuadVertices (text, lines) {
|
||||
text.lines = lines.length
|
||||
let cursorX = 0
|
||||
let cursorY = 0
|
||||
let vertices = []
|
||||
let textureCoords = []
|
||||
for (let i in lines) {
|
||||
let line = lines[i]
|
||||
if (text.centered) {
|
||||
cursorX = (line.maxLength - line.lineLength) / 2
|
||||
}
|
||||
for (let j in line.words) {
|
||||
let word = line.words[j]
|
||||
for (let k in word.characters) {
|
||||
let letter = word.characters[k]
|
||||
this.addVerticesForCharacter(cursorX, cursorY, letter, text.fontSize, vertices)
|
||||
this.addTexCoords(textureCoords, letter.xTexCoord, letter.yTexCoord, letter.xMaxTexCoord, letter.yMaxTexCoord)
|
||||
cursorX += letter.xAdvance * text.fontSize
|
||||
}
|
||||
cursorX += this.metadata.spaceWidth * text.fontSize
|
||||
}
|
||||
cursorX = 0
|
||||
cursorY += LINE_HEIGHT * text.fontSize
|
||||
}
|
||||
return { vertices, textureCoords }
|
||||
}
|
||||
|
||||
addVerticesForCharacter (cursorX, cursorY, character, fontSize, vertices) {
|
||||
let x = cursorX + (character.xOffset * fontSize)
|
||||
let y = cursorY + (character.yOffset * fontSize)
|
||||
let maxX = x + (character.sizeX * fontSize)
|
||||
let maxY = y + (character.sizeY * fontSize)
|
||||
let properX = (2 * x) - 1
|
||||
let properY = (-2 * y) + 1
|
||||
let properMaxX = (2 * maxX) - 1
|
||||
let properMaxY = (-2 * maxY) + 1
|
||||
this.addVertices(vertices, properX, properY, properMaxX, properMaxY)
|
||||
}
|
||||
|
||||
addVertices (vertices, x, y, maxX, maxY) {
|
||||
vertices.push(x)
|
||||
vertices.push(y)
|
||||
vertices.push(x)
|
||||
vertices.push(maxY)
|
||||
vertices.push(maxX)
|
||||
vertices.push(maxY)
|
||||
vertices.push(maxX)
|
||||
vertices.push(maxY)
|
||||
vertices.push(maxX)
|
||||
vertices.push(y)
|
||||
vertices.push(x)
|
||||
vertices.push(y)
|
||||
}
|
||||
|
||||
addTexCoords (texCoords, x, y, maxX, maxY) {
|
||||
texCoords.push(x)
|
||||
texCoords.push(y)
|
||||
texCoords.push(x)
|
||||
texCoords.push(maxY)
|
||||
texCoords.push(maxX)
|
||||
texCoords.push(maxY)
|
||||
texCoords.push(maxX)
|
||||
texCoords.push(maxY)
|
||||
texCoords.push(maxX)
|
||||
texCoords.push(y)
|
||||
texCoords.push(x)
|
||||
texCoords.push(y)
|
||||
}
|
||||
}
|
||||
|
||||
class GUIText extends Node2D {
|
||||
constructor (text, font, fontSize, pos, size, centered = false) {
|
||||
super(pos, size)
|
||||
this.text = text
|
||||
this.fontSize = fontSize
|
||||
this.font = font
|
||||
this.centered = centered
|
||||
this.color = [0.0, 0.0, 0.0]
|
||||
}
|
||||
|
||||
updateTransform () {
|
||||
let matrix = mat4.create()
|
||||
mat4.translate(matrix, matrix, [this.pos[0], this.pos[2], 0.0])
|
||||
if (this.rotation !== 0.0) {
|
||||
mat4.rotate(matrix, matrix, this.rotation * Math.PI / 180, [0.0, 0.0, 1.0])
|
||||
}
|
||||
|
||||
// Add parent's transform to this
|
||||
if (this.parent) {
|
||||
mat4.mul(matrix, this.parent.transform, matrix)
|
||||
}
|
||||
|
||||
// Set the matrix
|
||||
this.transform = matrix
|
||||
|
||||
// Update children's transforms
|
||||
for (let i in this.children) {
|
||||
let child = this.children[i]
|
||||
if (!(child instanceof Node2D)) continue
|
||||
child.updateTransform()
|
||||
}
|
||||
}
|
||||
|
||||
createMesh (gl) {
|
||||
this.mesh = this.font.createTextMesh(gl, this)
|
||||
}
|
||||
|
||||
get lineLength () {
|
||||
return this.size[2]
|
||||
}
|
||||
|
||||
get asCharacters () {
|
||||
let chars = []
|
||||
for (let i = 0; i < this.text.length; i++) {
|
||||
chars.push(this.text.charCodeAt(i))
|
||||
}
|
||||
return chars
|
||||
}
|
||||
|
||||
draw (gl, shader) {
|
||||
const transformLocation = shader.getUniformLocation(gl, 'uTransformation')
|
||||
const colorLocation = shader.getUniformLocation(gl, 'uColor')
|
||||
gl.uniformMatrix4fv(transformLocation, false, this.transform)
|
||||
gl.uniform3fv(colorLocation, this.color)
|
||||
if (!this.mesh) this.createMesh(gl)
|
||||
this.mesh.prepare(gl, shader)
|
||||
this.mesh.draw(gl, shader)
|
||||
this.mesh.postdraw(gl, shader)
|
||||
}
|
||||
}
|
||||
|
||||
class FontRenderer {
|
||||
discoverTextNodes (nodes) {
|
||||
let textNodes = []
|
||||
for (let i in nodes) {
|
||||
let node = nodes[i]
|
||||
if (!(node instanceof GUIText)) {
|
||||
if (node.children) {
|
||||
textNodes.concat(this.discoverTextNodes(node.children))
|
||||
}
|
||||
continue
|
||||
}
|
||||
textNodes.push(node)
|
||||
}
|
||||
return textNodes
|
||||
}
|
||||
|
||||
draw (gl, nodes) {
|
||||
let fontPairs = {}
|
||||
let textNodes = this.discoverTextNodes(nodes)
|
||||
for (let i in textNodes) {
|
||||
let node = textNodes[i]
|
||||
if (!this.fonts) {
|
||||
this.fonts = {}
|
||||
}
|
||||
|
||||
if (!this.fonts[node.font.name]) {
|
||||
this.fonts[node.font.name] = node.font
|
||||
}
|
||||
|
||||
if (fontPairs[node.font.name]) {
|
||||
fontPairs[node.font.name].push(node)
|
||||
} else {
|
||||
fontPairs[node.font.name] = [node]
|
||||
}
|
||||
}
|
||||
|
||||
this.shader.use(gl)
|
||||
gl.enable(gl.BLEND)
|
||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||
gl.disable(gl.DEPTH_TEST)
|
||||
for (let i in fontPairs) {
|
||||
let texts = fontPairs[i]
|
||||
let font = this.fonts[i]
|
||||
gl.activeTexture(gl.TEXTURE0)
|
||||
gl.bindTexture(font.texture.type, font.texture.id)
|
||||
for (let j in texts) {
|
||||
let text = texts[j]
|
||||
text.draw(gl, this.shader)
|
||||
}
|
||||
}
|
||||
gl.enable(gl.DEPTH_TEST)
|
||||
gl.disable(gl.BLEND)
|
||||
}
|
||||
|
||||
async initialize (game) {
|
||||
this.shader = await game.shaders.createShaderFromFiles(game.gl, 'font', false)
|
||||
}
|
||||
}
|
||||
|
||||
export { FontRenderer, GUIText, Font }
|
@ -81,7 +81,7 @@ class Node2D {
|
||||
|
||||
// Scaling
|
||||
this.gscale = [1.0, 1.0]
|
||||
this.size = size || new Dim4(0.0, 0.0, 0.0, 0.0)
|
||||
this.size = size || new Dim4(1.0, 0.0, 1.0, 0.0)
|
||||
|
||||
// Rotation in degrees
|
||||
this.rotation = rotation || 0.0
|
||||
@ -214,4 +214,4 @@ class GUIRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
export { Dim4, GUIRenderer, GUIImage }
|
||||
export { Node2D, Dim4, GUIRenderer, GUIImage }
|
||||
|
@ -7,7 +7,7 @@ let gl
|
||||
|
||||
class Engine {
|
||||
constructor () {
|
||||
this.screen = new Screen()
|
||||
this.screen = Screen
|
||||
this.input = new Input(this.screen.gl.canvas)
|
||||
this.shaders = new ShaderManager()
|
||||
this.running = false
|
||||
|
@ -50,6 +50,20 @@ class Mesh {
|
||||
return mesh
|
||||
}
|
||||
|
||||
static constructFromVerticesUVs (gl, vertices, uvs, dimensions = 2) {
|
||||
let pos = Mesh.loadToBuffer(gl, gl.ARRAY_BUFFER, new Float32Array(vertices))
|
||||
let mesh = new Mesh()
|
||||
mesh.uv = uvs
|
||||
mesh.posBuffer = pos
|
||||
mesh.vertices = vertices
|
||||
mesh.vertexCount = vertices.length / dimensions
|
||||
mesh.vertexLayout = dimensions
|
||||
mesh.uvs = Mesh.loadToBuffer(gl, gl.ARRAY_BUFFER, new Float32Array(uvs))
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null)
|
||||
|
||||
return mesh
|
||||
}
|
||||
|
||||
bindBuffers (gl, shader) {
|
||||
this._bufferCount = 1
|
||||
|
||||
|
@ -53,7 +53,7 @@ function smartGET (data) {
|
||||
}
|
||||
|
||||
function loadImage (url) {
|
||||
url = '/assets/textures/' + url
|
||||
if (url.indexOf('/') !== 0) url = '/assets/textures/' + url
|
||||
|
||||
// Ensure we don't load a texture multiple times
|
||||
if (imgCache[url]) return imgCache[url]
|
||||
|
@ -30,6 +30,14 @@ class Screen {
|
||||
this._el.width = window.innerWidth
|
||||
this._el.height = window.innerHeight
|
||||
}
|
||||
|
||||
get width () {
|
||||
return this._el.width
|
||||
}
|
||||
|
||||
get height () {
|
||||
return this._el.height
|
||||
}
|
||||
}
|
||||
|
||||
export default Screen
|
||||
export default new Screen()
|
||||
|
12
src/index.js
12
src/index.js
@ -9,10 +9,12 @@ import { Skybox } from './engine/components/skybox'
|
||||
import { SimplexHeightMap } from './engine/components/terrain/heightmap'
|
||||
import { Material, Texture } from './engine/mesh/material'
|
||||
import { GUIRenderer, GUIImage, Dim4 } from './engine/gui'
|
||||
import { FontRenderer, GUIText, Font } from './engine/gui/font'
|
||||
|
||||
let game = new Engine()
|
||||
let env = new Environment()
|
||||
let gui = new GUIRenderer()
|
||||
let fnt = new FontRenderer()
|
||||
|
||||
async function pipeline () {
|
||||
let entity = await loadMesh(game.gl, 'test')
|
||||
@ -22,12 +24,19 @@ async function pipeline () {
|
||||
|
||||
entity.setRotation([0.0, 0.0, -90.0])
|
||||
|
||||
let arialFont = await Font.fromFile('arial')
|
||||
await arialFont.loadTextures(game.gl)
|
||||
|
||||
// Initialize GUI
|
||||
await gui.initialize(game)
|
||||
await fnt.initialize(game)
|
||||
|
||||
let itms = [
|
||||
new GUIImage(await Texture.createTexture2D(game.gl, await Resource.loadImage('noisy.png'), false, game.gl.LINEAR),
|
||||
new Dim4(-0.9, 0.0, 0.9, 0.0), new Dim4(0.1, 0.0, 0.1, 0.0))
|
||||
new Dim4(-0.9, 0.0, 0.9, 0.0), new Dim4(0.1, 0.0, 0.1, 0.0)),
|
||||
new GUIText('this is example text!\nmulti line!', arialFont, 2, new Dim4(0.1, 0.0, -0.2, 0.0), new Dim4(1.0, 0.0, 0.3, 0.0), true)
|
||||
]
|
||||
itms[1].color = [1.0, 0.0, 0.2]
|
||||
|
||||
// Create a height map based on OpenSimplex noise
|
||||
let hmap = new SimplexHeightMap(1, 1, 256, 50)
|
||||
@ -106,6 +115,7 @@ async function pipeline () {
|
||||
|
||||
game.addRenderFunction(function (gl) {
|
||||
gui.draw(gl, itms)
|
||||
fnt.draw(gl, itms)
|
||||
})
|
||||
|
||||
game.startGameLoop()
|
||||
|
Loading…
Reference in New Issue
Block a user