commit cc18e2c5e4cdad037d1437b245531c457a786cbb Author: fgnm Date: Fri Jun 26 16:49:10 2020 +0200 Push to BitBucket diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..215bc768 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +.idea/ +/build/ +.gradle/ +h2d-libgdx-spine-extension/build/ +hyperlap2d-common-api/build/ +hyperlap2d-runtime-libgdx/build/ +plugin-9patch/build/ +plugin-performance/build/ +plugin-tiled/build/ diff --git a/art/font/myriad-medium-big.fnt b/art/font/myriad-medium-big.fnt new file mode 100644 index 00000000..52bdba57 --- /dev/null +++ b/art/font/myriad-medium-big.fnt @@ -0,0 +1,4827 @@ +info face="MyriadPro-Regular" size=16 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=20 base=12 scaleW=256 scaleH=512 pages=1 packed=0 +page id=0 file="myriad-medium-big.png" +chars count=506 +char id=0 x=210 y=127 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=13 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=0 page=0 chnl=0 +char id=33 x=250 y=113 width=5 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=34 x=205 y=253 width=7 height=6 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=35 x=220 y=127 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=36 x=102 y=19 width=9 height=16 xoffset=0 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=37 x=110 y=84 width=15 height=14 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=0 +char id=38 x=230 y=127 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=39 x=212 y=253 width=5 height=6 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=40 x=111 y=19 width=6 height=16 xoffset=0 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=41 x=117 y=19 width=6 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=42 x=88 y=253 width=9 height=8 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=43 x=185 y=219 width=11 height=11 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=44 x=148 y=253 width=5 height=7 xoffset=-1 yoffset=9 xadvance=3 page=0 chnl=0 +char id=45 x=68 y=263 width=7 height=4 xoffset=-1 yoffset=6 xadvance=5 page=0 chnl=0 +char id=46 x=6 y=263 width=5 height=5 xoffset=-1 yoffset=8 xadvance=3 page=0 chnl=0 +char id=47 x=125 y=84 width=9 height=14 xoffset=-2 yoffset=0 xadvance=5 page=0 chnl=0 +char id=48 x=242 y=127 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=49 x=0 y=141 width=7 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=50 x=7 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=51 x=17 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=52 x=27 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=53 x=37 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=54 x=47 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=55 x=57 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=56 x=67 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=57 x=134 y=84 width=10 height=14 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=58 x=248 y=219 width=5 height=10 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=59 x=98 y=219 width=5 height=12 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=0 +char id=60 x=196 y=219 width=10 height=11 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=0 +char id=61 x=217 y=253 width=11 height=6 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=0 +char id=62 x=206 y=219 width=10 height=11 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=0 +char id=63 x=77 y=141 width=8 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=64 x=144 y=84 width=14 height=14 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=0 +char id=65 x=85 y=141 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=66 x=97 y=141 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=67 x=107 y=141 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=68 x=118 y=141 width=12 height=13 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=69 x=130 y=141 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=70 x=139 y=141 width=8 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=71 x=147 y=141 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=72 x=159 y=141 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=73 x=251 y=84 width=4 height=13 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=74 x=170 y=141 width=7 height=13 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=75 x=177 y=141 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=76 x=187 y=141 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=77 x=196 y=141 width=14 height=13 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=0 +char id=78 x=210 y=141 width=11 height=13 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=79 x=221 y=141 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=80 x=234 y=141 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=81 x=179 y=68 width=13 height=15 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=82 x=243 y=141 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=83 x=0 y=154 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=84 x=10 y=154 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=85 x=21 y=154 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=86 x=32 y=154 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=87 x=43 y=154 width=16 height=13 xoffset=-1 yoffset=0 xadvance=14 page=0 chnl=0 +char id=88 x=59 y=154 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=89 x=70 y=154 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=90 x=81 y=154 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=91 x=192 y=68 width=6 height=15 xoffset=0 yoffset=0 xadvance=5 page=0 chnl=0 +char id=92 x=158 y=84 width=8 height=14 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=93 x=198 y=68 width=6 height=15 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=94 x=14 y=232 width=11 height=10 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=95 x=94 y=263 width=10 height=3 xoffset=-1 yoffset=12 xadvance=8 page=0 chnl=0 +char id=96 x=11 y=263 width=6 height=5 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=97 x=25 y=232 width=9 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=98 x=166 y=84 width=10 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=99 x=34 y=232 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=100 x=176 y=84 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=101 x=43 y=232 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=102 x=186 y=84 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=103 x=194 y=84 width=10 height=14 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=104 x=204 y=84 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=105 x=250 y=68 width=5 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=106 x=100 y=0 width=6 height=17 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=107 x=213 y=84 width=9 height=14 xoffset=0 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=108 x=251 y=52 width=4 height=14 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=109 x=53 y=232 width=14 height=10 xoffset=0 yoffset=3 xadvance=13 page=0 chnl=0 +char id=110 x=67 y=232 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=111 x=76 y=232 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=112 x=222 y=84 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=113 x=232 y=84 width=10 height=14 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=114 x=87 y=232 width=6 height=10 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=0 +char id=115 x=93 y=232 width=8 height=10 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=116 x=103 y=219 width=7 height=12 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=117 x=101 y=232 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=118 x=110 y=232 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=119 x=120 y=232 width=14 height=10 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=120 x=134 y=232 width=10 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=121 x=204 y=68 width=10 height=15 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=122 x=144 y=232 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=123 x=214 y=68 width=7 height=15 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=124 x=20 y=0 width=4 height=18 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=125 x=221 y=68 width=7 height=15 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=126 x=17 y=263 width=11 height=5 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=0 +char id=160 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=161 x=92 y=154 width=5 height=13 xoffset=-1 yoffset=3 xadvance=4 page=0 chnl=0 +char id=162 x=242 y=84 width=9 height=14 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=163 x=97 y=154 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=164 x=216 y=219 width=10 height=11 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=165 x=107 y=154 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=166 x=123 y=19 width=4 height=16 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=167 x=0 y=99 width=10 height=14 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=168 x=75 y=263 width=7 height=4 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=169 x=117 y=154 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=170 x=153 y=253 width=7 height=7 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=171 x=97 y=253 width=9 height=8 xoffset=-1 yoffset=4 xadvance=7 page=0 chnl=0 +char id=172 x=160 y=253 width=11 height=7 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=0 +char id=173 x=82 y=263 width=7 height=4 xoffset=-1 yoffset=6 xadvance=5 page=0 chnl=0 +char id=174 x=106 y=253 width=9 height=8 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=175 x=104 y=263 width=7 height=3 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=176 x=228 y=253 width=7 height=6 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=177 x=110 y=219 width=11 height=12 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=0 +char id=178 x=115 y=253 width=7 height=8 xoffset=-1 yoffset=-2 xadvance=5 page=0 chnl=0 +char id=179 x=81 y=253 width=7 height=9 xoffset=-1 yoffset=-3 xadvance=5 page=0 chnl=0 +char id=180 x=28 y=263 width=6 height=5 xoffset=0 yoffset=0 xadvance=5 page=0 chnl=0 +char id=181 x=10 y=99 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=182 x=228 y=68 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=183 x=89 y=263 width=5 height=4 xoffset=-1 yoffset=6 xadvance=3 page=0 chnl=0 +char id=184 x=235 y=253 width=6 height=6 xoffset=-1 yoffset=11 xadvance=5 page=0 chnl=0 +char id=185 x=122 y=253 width=5 height=8 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=186 x=171 y=253 width=8 height=7 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=187 x=127 y=253 width=9 height=8 xoffset=-1 yoffset=4 xadvance=7 page=0 chnl=0 +char id=188 x=130 y=154 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=189 x=144 y=154 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=190 x=158 y=154 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=191 x=20 y=99 width=8 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=192 x=127 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=193 x=139 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=194 x=151 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=195 x=163 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=196 x=175 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=197 x=187 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=198 x=172 y=154 width=16 height=13 xoffset=-2 yoffset=0 xadvance=13 page=0 chnl=0 +char id=199 x=106 y=0 width=11 height=17 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=200 x=199 y=19 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=201 x=208 y=19 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=202 x=217 y=19 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=203 x=226 y=19 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=204 x=235 y=19 width=6 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=205 x=241 y=19 width=6 height=16 xoffset=0 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=206 x=247 y=19 width=8 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=207 x=0 y=36 width=8 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=208 x=188 y=154 width=14 height=13 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=209 x=8 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=210 x=19 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=211 x=32 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=212 x=45 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=213 x=58 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=214 x=71 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=215 x=226 y=219 width=11 height=11 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=216 x=237 y=68 width=13 height=15 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=0 +char id=217 x=84 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=218 x=95 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=219 x=106 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=220 x=117 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=221 x=128 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=222 x=202 y=154 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=223 x=28 y=99 width=10 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=224 x=38 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=225 x=47 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=226 x=56 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=227 x=211 y=154 width=9 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=228 x=220 y=154 width=9 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=229 x=65 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=230 x=153 y=232 width=14 height=10 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=231 x=74 y=99 width=9 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=232 x=83 y=99 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=233 x=93 y=99 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=234 x=103 y=99 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=235 x=229 y=154 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=236 x=113 y=99 width=6 height=14 xoffset=-2 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=237 x=119 y=99 width=6 height=14 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=238 x=125 y=99 width=7 height=14 xoffset=-2 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=239 x=239 y=154 width=8 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=240 x=132 y=99 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=241 x=0 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=242 x=143 y=99 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=243 x=154 y=99 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=244 x=165 y=99 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=245 x=9 y=167 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=246 x=20 y=167 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=247 x=167 y=232 width=11 height=10 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=248 x=121 y=219 width=11 height=12 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=249 x=176 y=99 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=250 x=185 y=99 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=251 x=194 y=99 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=252 x=31 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=253 x=0 y=0 width=10 height=19 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=254 x=117 y=0 width=10 height=17 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=255 x=24 y=0 width=10 height=18 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=256 x=0 y=84 width=12 height=15 xoffset=-1 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=257 x=132 y=219 width=9 height=12 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=258 x=139 y=36 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=259 x=40 y=167 width=9 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=260 x=127 y=0 width=12 height=17 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=261 x=203 y=99 width=10 height=14 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=262 x=151 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=263 x=213 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=264 x=162 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=265 x=222 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=266 x=173 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=267 x=49 y=167 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=268 x=184 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=269 x=231 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=270 x=195 y=36 width=12 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=271 x=240 y=99 width=14 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=272 x=58 y=167 width=14 height=13 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=273 x=0 y=113 width=12 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=274 x=12 y=84 width=9 height=15 xoffset=0 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=275 x=141 y=219 width=10 height=12 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=276 x=207 y=36 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=277 x=72 y=167 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=278 x=216 y=36 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=279 x=82 y=167 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=280 x=139 y=0 width=9 height=17 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=281 x=12 y=113 width=10 height=14 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=282 x=225 y=36 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=283 x=22 y=113 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=284 x=234 y=36 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=285 x=34 y=0 width=10 height=18 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=286 x=0 y=52 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=287 x=148 y=0 width=10 height=17 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=288 x=12 y=52 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=289 x=158 y=0 width=10 height=17 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=290 x=168 y=0 width=12 height=17 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=291 x=44 y=0 width=10 height=18 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=292 x=24 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=293 x=180 y=0 width=11 height=17 xoffset=-2 yoffset=-4 xadvance=9 page=0 chnl=0 +char id=294 x=92 y=167 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=295 x=32 y=113 width=11 height=14 xoffset=-2 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=296 x=246 y=36 width=7 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=297 x=247 y=154 width=7 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=298 x=21 y=84 width=6 height=15 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=299 x=105 y=167 width=6 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=300 x=35 y=52 width=7 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=301 x=111 y=167 width=7 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=302 x=191 y=0 width=6 height=17 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=303 x=197 y=0 width=6 height=17 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=304 x=42 y=52 width=4 height=16 xoffset=0 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=305 x=178 y=232 width=4 height=10 xoffset=0 yoffset=3 xadvance=4 page=0 chnl=0 +char id=306 x=118 y=167 width=10 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=307 x=203 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=308 x=46 y=52 width=9 height=16 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=309 x=212 y=0 width=7 height=17 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=310 x=219 y=0 width=10 height=17 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=311 x=54 y=0 width=9 height=18 xoffset=0 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=312 x=182 y=232 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=313 x=55 y=52 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=314 x=229 y=0 width=7 height=17 xoffset=-1 yoffset=-4 xadvance=4 page=0 chnl=0 +char id=315 x=236 y=0 width=9 height=17 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=316 x=63 y=0 width=5 height=18 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=317 x=128 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=318 x=43 y=113 width=6 height=14 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=319 x=137 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=320 x=49 y=113 width=6 height=14 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=321 x=146 y=167 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=322 x=55 y=113 width=6 height=14 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=323 x=64 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=324 x=61 y=113 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=325 x=0 y=19 width=11 height=17 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=326 x=70 y=113 width=9 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=327 x=75 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=328 x=79 y=113 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=329 x=88 y=113 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=330 x=11 y=19 width=11 height=17 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=331 x=157 y=167 width=9 height=13 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=332 x=27 y=84 width=13 height=15 xoffset=-1 yoffset=-2 xadvance=11 page=0 chnl=0 +char id=333 x=151 y=219 width=11 height=12 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=0 +char id=334 x=86 y=52 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=335 x=166 y=167 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=336 x=99 y=52 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=337 x=98 y=113 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=338 x=40 y=84 width=16 height=15 xoffset=-1 yoffset=-1 xadvance=14 page=0 chnl=0 +char id=339 x=191 y=232 width=16 height=10 xoffset=-1 yoffset=3 xadvance=14 page=0 chnl=0 +char id=340 x=112 y=52 width=10 height=16 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=341 x=109 y=113 width=6 height=14 xoffset=0 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=342 x=245 y=0 width=10 height=17 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=343 x=115 y=113 width=7 height=14 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=344 x=122 y=52 width=10 height=16 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=345 x=122 y=113 width=7 height=14 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=346 x=132 y=52 width=10 height=16 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=347 x=129 y=113 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=348 x=142 y=52 width=10 height=16 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=349 x=137 y=113 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=350 x=22 y=19 width=10 height=17 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=351 x=145 y=113 width=8 height=14 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=352 x=152 y=52 width=10 height=16 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=353 x=153 y=113 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=354 x=32 y=19 width=11 height=17 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=355 x=162 y=52 width=7 height=16 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=356 x=169 y=52 width=11 height=16 xoffset=-2 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=357 x=161 y=113 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=358 x=177 y=167 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=359 x=162 y=219 width=7 height=12 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=360 x=180 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=361 x=188 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=362 x=56 y=84 width=11 height=15 xoffset=0 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=363 x=197 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=364 x=191 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=365 x=206 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=366 x=202 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=367 x=169 y=113 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=368 x=213 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=369 x=178 y=113 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=370 x=43 y=19 width=11 height=17 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=371 x=187 y=113 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=372 x=224 y=52 width=16 height=16 xoffset=-1 yoffset=-3 xadvance=14 page=0 chnl=0 +char id=373 x=197 y=113 width=14 height=14 xoffset=-1 yoffset=-1 xadvance=12 page=0 chnl=0 +char id=374 x=240 y=52 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=375 x=10 y=0 width=10 height=19 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=376 x=0 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=377 x=11 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=378 x=211 y=113 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=379 x=22 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=380 x=215 y=167 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=381 x=33 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=382 x=220 y=113 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=894 x=224 y=167 width=5 height=13 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=900 x=34 y=263 width=5 height=5 xoffset=0 yoffset=0 xadvance=5 page=0 chnl=0 +char id=901 x=39 y=263 width=8 height=5 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=902 x=229 y=167 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=903 x=47 y=263 width=5 height=5 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=0 +char id=904 x=241 y=167 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=905 x=0 y=180 width=13 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=906 x=13 y=180 width=6 height=13 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=908 x=19 y=180 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=910 x=33 y=180 width=14 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=911 x=47 y=180 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=912 x=229 y=113 width=8 height=14 xoffset=-2 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=913 x=61 y=180 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=914 x=73 y=180 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=915 x=83 y=180 width=8 height=13 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=916 x=91 y=180 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=917 x=103 y=180 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=918 x=112 y=180 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=919 x=123 y=180 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=920 x=134 y=180 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=921 x=147 y=180 width=4 height=13 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=922 x=151 y=180 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=923 x=161 y=180 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=924 x=173 y=180 width=14 height=13 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=0 +char id=925 x=187 y=180 width=11 height=13 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=926 x=198 y=180 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=927 x=209 y=180 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=928 x=222 y=180 width=10 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=929 x=232 y=180 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=931 x=241 y=180 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=932 x=0 y=193 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=933 x=11 y=193 width=12 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=934 x=237 y=113 width=13 height=14 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=0 +char id=935 x=23 y=193 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=936 x=34 y=193 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=937 x=47 y=193 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=938 x=44 y=68 width=8 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=939 x=67 y=84 width=12 height=15 xoffset=-1 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=940 x=60 y=193 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=941 x=71 y=193 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=942 x=54 y=19 width=10 height=17 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=943 x=80 y=193 width=5 height=13 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=944 x=0 y=127 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=945 x=207 y=232 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=946 x=68 y=0 width=10 height=18 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=947 x=10 y=127 width=11 height=14 xoffset=-2 yoffset=3 xadvance=7 page=0 chnl=0 +char id=948 x=21 y=127 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=949 x=218 y=232 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=950 x=52 y=68 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=951 x=32 y=127 width=10 height=14 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=952 x=42 y=127 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=953 x=227 y=232 width=5 height=10 xoffset=0 yoffset=3 xadvance=4 page=0 chnl=0 +char id=954 x=232 y=232 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=955 x=52 y=127 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=956 x=62 y=127 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=957 x=241 y=232 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=958 x=64 y=19 width=9 height=17 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=959 x=0 y=243 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=960 x=11 y=243 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=961 x=72 y=127 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=962 x=85 y=193 width=9 height=13 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=963 x=237 y=219 width=11 height=11 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=964 x=22 y=243 width=10 height=10 xoffset=-2 yoffset=3 xadvance=7 page=0 chnl=0 +char id=965 x=32 y=243 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=966 x=79 y=84 width=12 height=15 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=967 x=82 y=127 width=10 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=968 x=73 y=19 width=12 height=17 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=969 x=42 y=243 width=13 height=10 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=970 x=94 y=193 width=8 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=971 x=102 y=193 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=972 x=112 y=193 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=973 x=123 y=193 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=974 x=133 y=193 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1025 x=61 y=68 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=1026 x=70 y=68 width=13 height=16 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1027 x=83 y=68 width=8 height=16 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=1028 x=146 y=193 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1029 x=157 y=193 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1030 x=167 y=193 width=4 height=13 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=1031 x=91 y=68 width=8 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=1032 x=171 y=193 width=7 height=13 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=1033 x=92 y=127 width=17 height=14 xoffset=-2 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1034 x=178 y=193 width=15 height=13 xoffset=0 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1035 x=193 y=193 width=13 height=13 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1036 x=99 y=68 width=10 height=16 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=1038 x=109 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=1039 x=120 y=68 width=10 height=16 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1040 x=206 y=193 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1041 x=218 y=193 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1042 x=228 y=193 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1043 x=238 y=193 width=8 height=13 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1044 x=130 y=68 width=12 height=16 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1045 x=246 y=193 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1046 x=0 y=206 width=15 height=13 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=0 +char id=1047 x=15 y=206 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1048 x=25 y=206 width=11 height=13 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1049 x=142 y=68 width=11 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=1050 x=36 y=206 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1051 x=46 y=206 width=12 height=13 xoffset=-2 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1052 x=58 y=206 width=14 height=13 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=0 +char id=1053 x=72 y=206 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1054 x=83 y=206 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1055 x=96 y=206 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1056 x=107 y=206 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1057 x=116 y=206 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1058 x=127 y=206 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1059 x=138 y=206 width=11 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1060 x=109 y=127 width=13 height=14 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1061 x=149 y=206 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1062 x=153 y=68 width=11 height=16 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1063 x=160 y=206 width=10 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1064 x=170 y=206 width=14 height=13 xoffset=0 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1065 x=164 y=68 width=15 height=16 xoffset=0 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1066 x=184 y=206 width=13 height=13 xoffset=-2 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1067 x=197 y=206 width=12 height=13 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1068 x=209 y=206 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1069 x=219 y=206 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1070 x=230 y=206 width=15 height=13 xoffset=0 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1071 x=245 y=206 width=10 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1072 x=55 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1073 x=122 y=127 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1074 x=64 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1075 x=73 y=243 width=7 height=10 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1076 x=0 y=219 width=10 height=13 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1077 x=80 y=243 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1078 x=90 y=243 width=13 height=10 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1079 x=103 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1080 x=112 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1081 x=10 y=219 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1082 x=121 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1083 x=130 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1084 x=139 y=243 width=12 height=10 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=1085 x=151 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1086 x=160 y=243 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1087 x=171 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1088 x=132 y=127 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1089 x=180 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1090 x=189 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1091 x=91 y=84 width=10 height=15 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1092 x=78 y=0 width=12 height=18 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1093 x=198 y=243 width=10 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1094 x=19 y=219 width=10 height=13 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1095 x=208 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1096 x=217 y=243 width=12 height=10 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0 +char id=1097 x=29 y=219 width=13 height=13 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0 +char id=1098 x=229 y=243 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1099 x=240 y=243 width=11 height=10 xoffset=0 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1100 x=0 y=253 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1101 x=9 y=253 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1102 x=18 y=253 width=12 height=10 xoffset=0 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1103 x=30 y=253 width=9 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1105 x=42 y=219 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1106 x=85 y=19 width=11 height=17 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=1107 x=142 y=127 width=7 height=14 xoffset=0 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1108 x=39 y=253 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1109 x=48 y=253 width=8 height=10 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1110 x=52 y=219 width=5 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=1111 x=57 y=219 width=8 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=1112 x=96 y=19 width=6 height=17 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=1113 x=0 y=232 width=14 height=11 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=1114 x=56 y=253 width=13 height=10 xoffset=0 yoffset=3 xadvance=13 page=0 chnl=0 +char id=1115 x=149 y=127 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=1116 x=160 y=127 width=9 height=14 xoffset=0 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1118 x=90 y=0 width=10 height=18 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1119 x=65 y=219 width=9 height=13 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1168 x=101 y=84 width=9 height=15 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=1169 x=169 y=219 width=7 height=12 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=0 +char id=1241 x=69 y=253 width=12 height=10 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=8204 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=8211 x=111 y=263 width=10 height=3 xoffset=-1 yoffset=6 xadvance=8 page=0 chnl=0 +char id=8212 x=121 y=263 width=18 height=3 xoffset=-1 yoffset=6 xadvance=16 page=0 chnl=0 +char id=8216 x=179 y=253 width=5 height=7 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=8217 x=184 y=253 width=5 height=7 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=8218 x=241 y=253 width=5 height=6 xoffset=-1 yoffset=9 xadvance=3 page=0 chnl=0 +char id=8220 x=189 y=253 width=8 height=7 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8221 x=197 y=253 width=8 height=7 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8222 x=246 y=253 width=8 height=6 xoffset=-1 yoffset=9 xadvance=6 page=0 chnl=0 +char id=8224 x=169 y=127 width=10 height=14 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=8225 x=179 y=127 width=10 height=14 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=8226 x=0 y=263 width=6 height=6 xoffset=-1 yoffset=5 xadvance=5 page=0 chnl=0 +char id=8230 x=52 y=263 width=16 height=5 xoffset=0 yoffset=8 xadvance=16 page=0 chnl=0 +char id=8240 x=189 y=127 width=21 height=14 xoffset=-1 yoffset=-1 xadvance=19 page=0 chnl=0 +char id=8249 x=136 y=253 width=6 height=8 xoffset=-1 yoffset=4 xadvance=4 page=0 chnl=0 +char id=8250 x=142 y=253 width=6 height=8 xoffset=-1 yoffset=4 xadvance=4 page=0 chnl=0 +char id=8260 x=74 y=219 width=14 height=13 xoffset=-4 yoffset=0 xadvance=2 page=0 chnl=0 +char id=8363 x=176 y=219 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=8364 x=88 y=219 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +kernings count=4316 +kerning first=362 second=913 amount=-1 +kerning first=8216 second=281 amount=-1 +kerning first=221 second=285 amount=-1 +kerning first=39 second=961 amount=-1 +kerning first=356 second=232 amount=-1 +kerning first=1090 second=8212 amount=-1 +kerning first=34 second=74 amount=-1 +kerning first=1027 second=1107 amount=-1 +kerning first=8218 second=376 amount=-2 +kerning first=86 second=248 amount=-1 +kerning first=8221 second=301 amount=-1 +kerning first=362 second=258 amount=-1 +kerning first=358 second=335 amount=-1 +kerning first=957 second=46 amount=-1 +kerning first=257 second=84 amount=-1 +kerning first=376 second=279 amount=-1 +kerning first=356 second=97 amount=-1 +kerning first=354 second=231 amount=-1 +kerning first=89 second=210 amount=-1 +kerning first=70 second=224 amount=-1 +kerning first=1058 second=1035 amount=1 +kerning first=910 second=965 amount=-1 +kerning first=8220 second=229 amount=-1 +kerning first=8216 second=937 amount=-1 +kerning first=1168 second=1040 amount=-1 +kerning first=76 second=87 amount=-1 +kerning first=208 second=8230 amount=-1 +kerning first=932 second=940 amount=-1 +kerning first=354 second=93 amount=1 +kerning first=229 second=932 amount=-1 +kerning first=939 second=959 amount=-1 +kerning first=321 second=173 amount=-1 +kerning first=932 second=244 amount=-1 +kerning first=220 second=198 amount=-1 +kerning first=915 second=71 amount=-1 +kerning first=929 second=923 amount=-1 +kerning first=221 second=308 amount=-1 +kerning first=86 second=279 amount=-1 +kerning first=358 second=227 amount=-1 +kerning first=192 second=39 amount=-1 +kerning first=8217 second=109 amount=-1 +kerning first=1043 second=1088 amount=-1 +kerning first=87 second=358 amount=1 +kerning first=196 second=221 amount=-1 +kerning first=279 second=932 amount=-1 +kerning first=65 second=89 amount=-1 +kerning first=947 second=44 amount=-1 +kerning first=87 second=267 amount=-1 +kerning first=221 second=369 amount=-1 +kerning first=315 second=262 amount=-1 +kerning first=196 second=84 amount=-1 +kerning first=1027 second=187 amount=-1 +kerning first=931 second=264 amount=-1 +kerning first=91 second=1058 amount=1 +kerning first=8218 second=358 amount=-1 +kerning first=1098 second=1091 amount=-1 +kerning first=84 second=361 amount=-1 +kerning first=915 second=941 amount=-1 +kerning first=939 second=181 amount=-1 +kerning first=1043 second=44 amount=-1 +kerning first=89 second=252 amount=-1 +kerning first=334 second=44 amount=-1 +kerning first=1043 second=1032 amount=-1 +kerning first=219 second=195 amount=-1 +kerning first=932 second=260 amount=-1 +kerning first=89 second=173 amount=-1 +kerning first=8216 second=940 amount=-1 +kerning first=1168 second=1074 amount=-1 +kerning first=354 second=285 amount=-1 +kerning first=8216 second=244 amount=-1 +kerning first=8220 second=281 amount=-1 +kerning first=221 second=242 amount=-1 +kerning first=65 second=34 amount=-1 +kerning first=227 second=8221 amount=-1 +kerning first=89 second=111 amount=-1 +kerning first=1059 second=1066 amount=1 +kerning first=84 second=973 amount=-1 +kerning first=931 second=8211 amount=-1 +kerning first=220 second=194 amount=-1 +kerning first=84 second=251 amount=-1 +kerning first=8217 second=324 amount=-1 +kerning first=109 second=356 amount=-1 +kerning first=230 second=354 amount=-1 +kerning first=933 second=45 amount=-1 +kerning first=160 second=86 amount=-1 +kerning first=1066 second=1059 amount=-1 +kerning first=902 second=39 amount=-1 +kerning first=1027 second=1085 amount=-1 +kerning first=319 second=8220 amount=-2 +kerning first=932 second=8249 amount=-1 +kerning first=358 second=287 amount=-1 +kerning first=8220 second=937 amount=-1 +kerning first=372 second=263 amount=-1 +kerning first=84 second=110 amount=-1 +kerning first=8221 second=111 amount=-1 +kerning first=915 second=916 amount=-2 +kerning first=317 second=89 amount=-1 +kerning first=46 second=8220 amount=-2 +kerning first=315 second=376 amount=-1 +kerning first=39 second=74 amount=-1 +kerning first=923 second=356 amount=-1 +kerning first=91 second=372 amount=1 +kerning first=910 second=210 amount=-1 +kerning first=45 second=376 amount=-1 +kerning first=927 second=44 amount=-1 +kerning first=227 second=354 amount=-1 +kerning first=354 second=308 amount=-1 +kerning first=315 second=332 amount=-1 +kerning first=8204 second=354 amount=-1 +kerning first=171 second=933 amount=-1 +kerning first=932 second=948 amount=-1 +kerning first=315 second=85 amount=-1 +kerning first=319 second=219 amount=-1 +kerning first=356 second=361 amount=-1 +kerning first=102 second=46 amount=-1 +kerning first=8216 second=260 amount=-1 +kerning first=1100 second=8217 amount=-1 +kerning first=221 second=262 amount=-1 +kerning first=376 second=913 amount=-1 +kerning first=1033 second=1026 amount=-1 +kerning first=1058 second=1105 amount=-1 +kerning first=8212 second=1035 amount=-1 +kerning first=1059 second=173 amount=-1 +kerning first=372 second=192 amount=-1 +kerning first=275 second=354 amount=-1 +kerning first=40 second=221 amount=1 +kerning first=109 second=8217 amount=-1 +kerning first=912 second=958 amount=1 +kerning first=225 second=356 amount=-1 +kerning first=1168 second=1109 amount=-1 +kerning first=319 second=81 amount=-1 +kerning first=354 second=369 amount=-1 +kerning first=376 second=258 amount=-1 +kerning first=317 second=34 amount=-2 +kerning first=356 second=973 amount=-1 +kerning first=102 second=39 amount=1 +kerning first=915 second=8250 amount=-1 +kerning first=40 second=84 amount=1 +kerning first=44 second=34 amount=-2 +kerning first=923 second=8217 amount=-1 +kerning first=356 second=251 amount=-1 +kerning first=362 second=196 amount=-1 +kerning first=86 second=913 amount=-1 +kerning first=1038 second=1066 amount=1 +kerning first=933 second=79 amount=-1 +kerning first=1027 second=1169 amount=-1 +kerning first=80 second=916 amount=-1 +kerning first=84 second=328 amount=-1 +kerning first=354 second=942 amount=-1 +kerning first=358 second=365 amount=-1 +kerning first=8220 second=940 amount=-1 +kerning first=258 second=8216 amount=-1 +kerning first=916 second=39 amount=-1 +kerning first=356 second=110 amount=-1 +kerning first=915 second=949 amount=-1 +kerning first=354 second=242 amount=-1 +kerning first=86 second=258 amount=-1 +kerning first=89 second=224 amount=-1 +kerning first=315 second=358 amount=-1 +kerning first=8220 second=244 amount=-1 +kerning first=910 second=971 amount=-1 +kerning first=101 second=84 amount=-1 +kerning first=246 second=358 amount=-1 +kerning first=76 second=366 amount=-1 +kerning first=8216 second=948 amount=-1 +kerning first=160 second=932 amount=-1 +kerning first=45 second=358 amount=-1 +kerning first=933 second=8212 amount=-1 +kerning first=910 second=173 amount=-1 +kerning first=225 second=8217 amount=-1 +kerning first=8217 second=331 amount=-1 +kerning first=915 second=336 amount=-1 +kerning first=173 second=1058 amount=-1 +kerning first=8222 second=356 amount=-1 +kerning first=84 second=954 amount=-1 +kerning first=1040 second=1058 amount=-1 +kerning first=939 second=943 amount=-1 +kerning first=971 second=39 amount=-1 +kerning first=358 second=941 amount=-1 +kerning first=221 second=332 amount=-1 +kerning first=84 second=228 amount=-1 +kerning first=8217 second=283 amount=-1 +kerning first=358 second=246 amount=-1 +kerning first=372 second=234 amount=-1 +kerning first=81 second=46 amount=-1 +kerning first=932 second=269 amount=-1 +kerning first=1043 second=1101 amount=-1 +kerning first=933 second=912 amount=-1 +kerning first=1066 second=1038 amount=-1 +kerning first=1038 second=173 amount=-1 +kerning first=932 second=117 amount=-1 +kerning first=372 second=354 amount=1 +kerning first=89 second=339 amount=-1 +kerning first=315 second=199 amount=-1 +kerning first=358 second=105 amount=-1 +kerning first=87 second=301 amount=1 +kerning first=111 second=932 amount=-1 +kerning first=360 second=256 amount=-1 +kerning first=376 second=81 amount=-1 +kerning first=915 second=338 amount=-1 +kerning first=944 second=34 amount=-1 +kerning first=70 second=256 amount=-1 +kerning first=315 second=288 amount=-1 +kerning first=76 second=45 amount=-1 +kerning first=364 second=913 amount=-1 +kerning first=8220 second=260 amount=-1 +kerning first=343 second=8230 amount=-1 +kerning first=356 second=328 amount=-1 +kerning first=932 second=197 amount=-1 +kerning first=358 second=916 amount=-1 +kerning first=84 second=248 amount=-1 +kerning first=8221 second=339 amount=-1 +kerning first=1058 second=1083 amount=-1 +kerning first=364 second=258 amount=-1 +kerning first=1168 second=1087 amount=-1 +kerning first=939 second=268 amount=-1 +kerning first=89 second=275 amount=-1 +kerning first=933 second=193 amount=-2 +kerning first=221 second=358 amount=1 +kerning first=1113 second=1090 amount=-1 +kerning first=356 second=954 amount=-1 +kerning first=197 second=89 amount=-1 +kerning first=195 second=376 amount=-1 +kerning first=8216 second=269 amount=-1 +kerning first=221 second=267 amount=-1 +kerning first=8221 second=312 amount=-1 +kerning first=356 second=228 amount=-1 +kerning first=228 second=932 amount=-1 +kerning first=8217 second=349 amount=-1 +kerning first=218 second=198 amount=-1 +kerning first=933 second=58 amount=-1 +kerning first=955 second=39 amount=-1 +kerning first=932 second=341 amount=-1 +kerning first=1027 second=1098 amount=-1 +kerning first=84 second=279 amount=-1 +kerning first=8221 second=275 amount=-1 +kerning first=324 second=8221 amount=-1 +kerning first=194 second=39 amount=-1 +kerning first=932 second=187 amount=-1 +kerning first=8220 second=948 amount=-1 +kerning first=65 second=8220 amount=-1 +kerning first=112 second=8221 amount=-1 +kerning first=358 second=8250 amount=-1 +kerning first=193 second=221 amount=-1 +kerning first=277 second=932 amount=-1 +kerning first=376 second=115 amount=-1 +kerning first=915 second=195 amount=-2 +kerning first=315 second=362 amount=-1 +kerning first=76 second=79 amount=-1 +kerning first=8216 second=197 amount=-1 +kerning first=1046 second=1033 amount=1 +kerning first=345 second=46 amount=-1 +kerning first=221 second=199 amount=-1 +kerning first=8217 second=236 amount=-1 +kerning first=932 second=963 amount=-1 +kerning first=915 second=290 amount=-1 +kerning first=313 second=262 amount=-1 +kerning first=193 second=84 amount=-1 +kerning first=939 second=951 amount=-1 +kerning first=932 second=235 amount=-1 +kerning first=121 second=46 amount=-1 +kerning first=197 second=34 amount=-1 +kerning first=102 second=59 amount=1 +kerning first=358 second=949 amount=-1 +kerning first=221 second=288 amount=-1 +kerning first=356 second=248 amount=-1 +kerning first=321 second=372 amount=-1 +kerning first=1058 second=1119 amount=-1 +kerning first=319 second=356 amount=-1 +kerning first=324 second=354 amount=-1 +kerning first=1043 second=1080 amount=-1 +kerning first=376 second=196 amount=-1 +kerning first=8217 second=101 amount=-1 +kerning first=242 second=356 amount=-1 +kerning first=354 second=380 amount=-1 +kerning first=187 second=932 amount=-1 +kerning first=112 second=354 amount=-1 +kerning first=76 second=8212 amount=-1 +kerning first=929 second=260 amount=-1 +kerning first=936 second=46 amount=-1 +kerning first=1034 second=1035 amount=-1 +kerning first=358 second=84 amount=1 +kerning first=915 second=8230 amount=-2 +kerning first=195 second=358 amount=-1 +kerning first=224 second=8221 amount=-1 +kerning first=87 second=111 amount=-1 +kerning first=1057 second=1066 amount=1 +kerning first=218 second=194 amount=-1 +kerning first=308 second=93 amount=1 +kerning first=86 second=196 amount=-1 +kerning first=123 second=1026 amount=1 +kerning first=356 second=279 amount=-1 +kerning first=931 second=45 amount=-1 +kerning first=358 second=378 amount=-1 +kerning first=80 second=195 amount=-1 +kerning first=376 second=333 amount=-1 +kerning first=317 second=8220 amount=-2 +kerning first=354 second=358 amount=1 +kerning first=89 second=243 amount=-1 +kerning first=934 second=88 amount=-1 +kerning first=8217 second=46 amount=-2 +kerning first=8216 second=963 amount=-1 +kerning first=1168 second=1066 amount=1 +kerning first=44 second=8220 amount=-2 +kerning first=313 second=376 amount=-1 +kerning first=319 second=8217 amount=-2 +kerning first=354 second=267 amount=-1 +kerning first=932 second=41 amount=1 +kerning first=8216 second=235 amount=-1 +kerning first=242 second=8217 amount=-1 +kerning first=8220 second=269 amount=-1 +kerning first=46 second=8217 amount=-2 +kerning first=354 second=119 amount=-1 +kerning first=89 second=103 amount=-1 +kerning first=224 second=354 amount=-1 +kerning first=8212 second=356 amount=-1 +kerning first=84 second=969 amount=-1 +kerning first=313 second=332 amount=-1 +kerning first=1059 second=1058 amount=1 +kerning first=1091 second=46 amount=-1 +kerning first=102 second=93 amount=2 +kerning first=216 second=44 amount=-1 +kerning first=84 second=241 amount=-1 +kerning first=8217 second=297 amount=-1 +kerning first=313 second=85 amount=-1 +kerning first=8221 second=243 amount=-1 +kerning first=317 second=219 amount=-1 +kerning first=86 second=333 amount=-1 +kerning first=8216 second=8216 amount=-1 +kerning first=1043 second=1115 amount=1 +kerning first=1098 second=8217 amount=-1 +kerning first=376 second=233 amount=-1 +kerning first=1027 second=1077 amount=-1 +kerning first=217 second=913 amount=-1 +kerning first=321 second=171 amount=-1 +kerning first=8230 second=8221 amount=-2 +kerning first=366 second=65 amount=-1 +kerning first=360 second=192 amount=-1 +kerning first=358 second=265 amount=-1 +kerning first=283 second=354 amount=-1 +kerning first=80 second=8230 amount=-2 +kerning first=376 second=356 amount=1 +kerning first=8221 second=103 amount=-1 +kerning first=317 second=81 amount=-1 +kerning first=70 second=192 amount=-1 +kerning first=315 second=210 amount=-1 +kerning first=358 second=118 amount=-1 +kerning first=8220 second=197 amount=-1 +kerning first=91 second=354 amount=1 +kerning first=45 second=910 amount=-1 +kerning first=217 second=258 amount=-1 +kerning first=923 second=86 amount=-1 +kerning first=89 second=256 amount=-1 +kerning first=321 second=220 amount=-1 +kerning first=86 second=233 amount=-1 +kerning first=364 second=196 amount=-1 +kerning first=84 second=913 amount=-1 +kerning first=1168 second=173 amount=-1 +kerning first=931 second=79 amount=-1 +kerning first=8204 second=87 amount=-1 +kerning first=1035 second=1066 amount=-1 +kerning first=936 second=198 amount=-1 +kerning first=86 second=356 amount=1 +kerning first=1058 second=1096 amount=-1 +kerning first=358 second=195 amount=-1 +kerning first=1043 second=1059 amount=1 +kerning first=45 second=1066 amount=-1 +kerning first=271 second=311 amount=1 +kerning first=912 second=950 amount=1 +kerning first=1168 second=1100 amount=-1 +kerning first=84 second=258 amount=-1 +kerning first=87 second=224 amount=-1 +kerning first=313 second=358 amount=-1 +kerning first=8221 second=256 amount=-1 +kerning first=213 second=46 amount=-1 +kerning first=354 second=343 amount=-1 +kerning first=243 second=358 amount=-1 +kerning first=913 second=221 amount=-1 +kerning first=939 second=65 amount=-2 +kerning first=89 second=171 amount=-1 +kerning first=1059 second=1092 amount=-1 +kerning first=931 second=8212 amount=-1 +kerning first=356 second=969 amount=-1 +kerning first=84 second=307 amount=-1 +kerning first=356 second=241 amount=-1 +kerning first=1038 second=1058 amount=1 +kerning first=933 second=71 amount=-1 +kerning first=913 second=84 amount=-1 +kerning first=932 second=367 amount=-1 +kerning first=8217 second=198 amount=-1 +kerning first=260 second=39 amount=-1 +kerning first=354 second=965 amount=-1 +kerning first=79 second=46 amount=-1 +kerning first=358 second=345 amount=-1 +kerning first=8220 second=963 amount=-1 +kerning first=931 second=912 amount=1 +kerning first=104 second=358 amount=-1 +kerning first=256 second=221 amount=-1 +kerning first=376 second=291 amount=-1 +kerning first=354 second=237 amount=-1 +kerning first=358 second=8230 amount=-1 +kerning first=910 second=962 amount=-1 +kerning first=8220 second=235 amount=-1 +kerning first=315 second=173 amount=-1 +kerning first=915 second=214 amount=-1 +kerning first=87 second=339 amount=-1 +kerning first=313 second=199 amount=-1 +kerning first=109 second=932 amount=-1 +kerning first=370 second=256 amount=-1 +kerning first=974 second=34 amount=-1 +kerning first=221 second=210 amount=-1 +kerning first=123 second=106 amount=1 +kerning first=932 second=972 amount=-1 +kerning first=256 second=84 amount=-1 +kerning first=123 second=1095 amount=-1 +kerning first=8220 second=8216 amount=-1 +kerning first=313 second=288 amount=-1 +kerning first=356 second=913 amount=-1 +kerning first=932 second=250 amount=-1 +kerning first=84 second=946 amount=-1 +kerning first=939 second=966 amount=-1 +kerning first=936 second=194 amount=-1 +kerning first=341 second=8230 amount=-1 +kerning first=8222 second=86 amount=-1 +kerning first=358 second=232 amount=-1 +kerning first=923 second=932 amount=-1 +kerning first=929 second=197 amount=-1 +kerning first=372 second=225 amount=-1 +kerning first=1043 second=1093 amount=-1 +kerning first=329 second=356 amount=-1 +kerning first=8217 second=114 amount=-1 +kerning first=933 second=941 amount=-1 +kerning first=65 second=356 amount=-1 +kerning first=356 second=258 amount=-1 +kerning first=932 second=109 amount=-1 +kerning first=926 second=970 amount=1 +kerning first=358 second=97 amount=-1 +kerning first=87 second=275 amount=-1 +kerning first=197 second=8220 amount=-1 +kerning first=356 second=307 amount=-1 +kerning first=1038 second=1092 amount=-1 +kerning first=321 second=927 amount=-1 +kerning first=196 second=89 amount=-1 +kerning first=8250 second=221 amount=-1 +kerning first=192 second=376 amount=-1 +kerning first=8217 second=194 amount=-1 +kerning first=8211 second=1026 amount=-1 +kerning first=225 second=932 amount=-1 +kerning first=910 second=256 amount=-2 +kerning first=376 second=363 amount=-1 +kerning first=261 second=358 amount=-1 +kerning first=915 second=973 amount=-1 +kerning first=321 second=286 amount=-1 +kerning first=1058 second=1075 amount=-1 +kerning first=8250 second=84 amount=-1 +kerning first=319 second=268 amount=-1 +kerning first=1043 second=1038 amount=1 +kerning first=173 second=354 amount=-1 +kerning first=933 second=916 amount=-2 +kerning first=8216 second=972 amount=-1 +kerning first=1168 second=1079 amount=-1 +kerning first=110 second=8221 amount=-1 +kerning first=354 second=301 amount=-1 +kerning first=89 second=263 amount=-1 +kerning first=329 second=8217 amount=-1 +kerning first=34 second=193 amount=-1 +kerning first=221 second=252 amount=-1 +kerning first=65 second=8217 amount=-1 +kerning first=221 second=173 amount=-1 +kerning first=939 second=44 amount=-2 +kerning first=313 second=362 amount=-1 +kerning first=356 second=946 amount=-1 +kerning first=84 second=382 amount=-1 +kerning first=8217 second=337 amount=-1 +kerning first=1043 second=8249 amount=-1 +kerning first=1090 second=8230 amount=-1 +kerning first=119 second=46 amount=-1 +kerning first=196 second=34 amount=-1 +kerning first=372 second=273 amount=-1 +kerning first=221 second=111 amount=-1 +kerning first=932 second=324 amount=-1 +kerning first=376 second=245 amount=-1 +kerning first=1027 second=1090 amount=-1 +kerning first=321 second=8221 amount=-2 +kerning first=8221 second=263 amount=-1 +kerning first=317 second=356 amount=-1 +kerning first=89 second=927 amount=-1 +kerning first=217 second=196 amount=-1 +kerning first=372 second=277 amount=-1 +kerning first=123 second=376 amount=1 +kerning first=244 second=356 amount=-1 +kerning first=84 second=115 amount=-1 +kerning first=89 second=192 amount=-1 +kerning first=8222 second=932 amount=-1 +kerning first=110 second=354 amount=-1 +kerning first=934 second=46 amount=-1 +kerning first=89 second=286 amount=-1 +kerning first=76 second=71 amount=-1 +kerning first=933 second=8250 amount=-1 +kerning first=192 second=358 amount=-1 +kerning first=902 second=376 amount=-1 +kerning first=226 second=8221 amount=-1 +kerning first=8217 second=231 amount=-1 +kerning first=86 second=245 amount=-1 +kerning first=932 second=953 amount=-1 +kerning first=70 second=74 amount=-1 +kerning first=932 second=226 amount=-1 +kerning first=84 second=196 amount=-1 +kerning first=8221 second=192 amount=-1 +kerning first=939 second=213 amount=-1 +kerning first=321 second=354 amount=-1 +kerning first=1027 second=46 amount=-1 +kerning first=333 second=84 amount=-1 +kerning first=1043 second=1072 amount=-1 +kerning first=933 second=949 amount=-1 +kerning first=1168 second=1114 amount=-1 +kerning first=87 second=243 amount=-1 +kerning first=319 second=86 amount=-1 +kerning first=271 second=8221 amount=1 +kerning first=331 second=358 amount=-1 +kerning first=70 second=371 amount=-1 +kerning first=1034 second=8217 amount=-1 +kerning first=1113 second=1118 amount=-1 +kerning first=376 second=268 amount=-1 +kerning first=317 second=8217 amount=-2 +kerning first=1059 second=1106 amount=1 +kerning first=210 second=8230 amount=-1 +kerning first=244 second=8217 amount=-1 +kerning first=933 second=336 amount=-1 +kerning first=40 second=89 amount=1 +kerning first=44 second=8217 amount=-2 +kerning first=226 second=354 amount=-1 +kerning first=356 second=382 amount=-1 +kerning first=1057 second=1058 amount=1 +kerning first=84 second=333 amount=-1 +kerning first=339 second=84 amount=-1 +kerning first=354 second=971 amount=-1 +kerning first=358 second=361 amount=-1 +kerning first=8220 second=972 amount=-1 +kerning first=219 second=913 amount=-1 +kerning first=123 second=358 amount=1 +kerning first=356 second=115 amount=-1 +kerning first=8221 second=8221 amount=-1 +kerning first=8218 second=372 amount=-1 +kerning first=354 second=252 amount=-1 +kerning first=362 second=65 amount=-1 +kerning first=89 second=234 amount=-1 +kerning first=370 second=192 amount=-1 +kerning first=915 second=954 amount=-1 +kerning first=1058 second=1054 amount=-1 +kerning first=354 second=173 amount=-1 +kerning first=1168 second=1058 amount=1 +kerning first=313 second=210 amount=-1 +kerning first=89 second=354 amount=1 +kerning first=366 second=923 amount=-1 +kerning first=8216 second=226 amount=-1 +kerning first=219 second=258 amount=-1 +kerning first=221 second=224 amount=-1 +kerning first=902 second=358 amount=-1 +kerning first=933 second=338 amount=-1 +kerning first=354 second=111 amount=-1 +kerning first=235 second=84 amount=-1 +kerning first=87 second=256 amount=-1 +kerning first=84 second=959 amount=-1 +kerning first=932 second=331 amount=-1 +kerning first=358 second=973 amount=-1 +kerning first=84 second=233 amount=-1 +kerning first=8217 second=285 amount=-1 +kerning first=8221 second=234 amount=-1 +kerning first=356 second=196 amount=-1 +kerning first=1033 second=1066 amount=-1 +kerning first=39 second=193 amount=-1 +kerning first=358 second=251 amount=-1 +kerning first=923 second=939 amount=-2 +kerning first=1043 second=1107 amount=-1 +kerning first=372 second=239 amount=1 +kerning first=932 second=283 amount=-1 +kerning first=84 second=356 amount=1 +kerning first=8221 second=354 amount=1 +kerning first=932 second=122 amount=-1 +kerning first=291 second=84 amount=-1 +kerning first=214 second=46 amount=-1 +kerning first=358 second=110 amount=-1 +kerning first=910 second=927 amount=-1 +kerning first=97 second=84 amount=-1 +kerning first=372 second=100 amount=-1 +kerning first=952 second=8230 amount=-1 +kerning first=910 second=192 amount=-2 +kerning first=91 second=87 amount=1 +kerning first=1038 second=1106 amount=1 +kerning first=319 second=932 amount=-1 +kerning first=221 second=339 amount=-1 +kerning first=932 second=934 amount=-1 +kerning first=242 second=932 amount=-1 +kerning first=321 second=211 amount=-1 +kerning first=910 second=286 amount=-1 +kerning first=1035 second=1058 amount=-1 +kerning first=356 second=333 amount=-1 +kerning first=931 second=71 amount=-1 +kerning first=939 second=923 amount=-2 +kerning first=258 second=39 amount=-1 +kerning first=84 second=181 amount=-1 +kerning first=8217 second=308 amount=-1 +kerning first=1058 second=1088 amount=-1 +kerning first=45 second=1058 amount=-1 +kerning first=376 second=230 amount=-1 +kerning first=1168 second=1092 amount=-1 +kerning first=89 second=289 amount=-1 +kerning first=933 second=195 amount=-2 +kerning first=313 second=173 amount=-1 +kerning first=1113 second=1095 amount=-1 +kerning first=84 second=8217 amount=1 +kerning first=197 second=356 amount=-1 +kerning first=1059 second=1084 amount=-1 +kerning first=368 second=256 amount=-1 +kerning first=356 second=959 amount=-1 +kerning first=973 second=34 amount=-1 +kerning first=8216 second=283 amount=-1 +kerning first=221 second=275 amount=-1 +kerning first=916 second=358 amount=-1 +kerning first=933 second=290 amount=-1 +kerning first=356 second=233 amount=-1 +kerning first=1043 second=187 amount=-1 +kerning first=932 second=349 amount=-1 +kerning first=1114 second=1091 amount=-1 +kerning first=1027 second=1103 amount=-1 +kerning first=86 second=230 amount=-1 +kerning first=84 second=291 amount=-1 +kerning first=356 second=356 amount=1 +kerning first=8221 second=289 amount=-1 +kerning first=118 second=8230 amount=-1 +kerning first=358 second=328 amount=-1 +kerning first=76 second=221 amount=-1 +kerning first=8211 second=376 amount=-1 +kerning first=295 second=356 amount=-1 +kerning first=1058 second=44 amount=-1 +kerning first=376 second=271 amount=-1 +kerning first=354 second=224 amount=-1 +kerning first=89 second=211 amount=-1 +kerning first=8212 second=932 amount=-1 +kerning first=1058 second=1032 amount=-1 +kerning first=70 second=225 amount=-1 +kerning first=910 second=961 amount=-1 +kerning first=8220 second=226 amount=-1 +kerning first=76 second=336 amount=-1 +kerning first=76 second=84 amount=-1 +kerning first=196 second=8220 amount=-1 +kerning first=315 second=372 amount=-1 +kerning first=933 second=8230 amount=-2 +kerning first=245 second=8221 amount=-1 +kerning first=932 second=968 amount=-1 +kerning first=8217 second=242 amount=-1 +kerning first=89 second=74 amount=-1 +kerning first=193 second=89 amount=-1 +kerning first=171 second=221 amount=-1 +kerning first=932 second=236 amount=-1 +kerning first=194 second=376 amount=-1 +kerning first=197 second=8217 amount=-1 +kerning first=358 second=954 amount=-1 +kerning first=1169 second=44 amount=-1 +kerning first=376 second=932 amount=1 +kerning first=356 second=181 amount=-1 +kerning first=86 second=271 amount=-1 +kerning first=1027 second=59 amount=-1 +kerning first=358 second=228 amount=-1 +kerning first=319 second=370 amount=-1 +kerning first=1043 second=1085 amount=-1 +kerning first=1168 second=171 amount=-1 +kerning first=34 second=941 amount=-1 +kerning first=259 second=358 amount=-1 +kerning first=272 second=46 amount=-1 +kerning first=171 second=84 amount=-1 +kerning first=317 second=268 amount=-1 +kerning first=932 second=101 amount=-1 +kerning first=89 second=371 amount=-1 +kerning first=76 second=338 amount=-1 +kerning first=65 second=86 amount=-1 +kerning first=356 second=8217 amount=1 +kerning first=354 second=339 amount=-1 +kerning first=8221 second=74 amount=-1 +kerning first=87 second=263 amount=-1 +kerning first=295 second=8217 amount=-1 +kerning first=376 second=65 amount=-1 +kerning first=8216 second=349 amount=-1 +kerning first=908 second=44 amount=-1 +kerning first=245 second=354 amount=-1 +kerning first=1038 second=1084 amount=-1 +kerning first=86 second=932 amount=1 +kerning first=8230 second=933 amount=-1 +kerning first=84 second=363 amount=-1 +kerning first=356 second=291 amount=-1 +kerning first=193 second=34 amount=-1 +kerning first=8211 second=358 amount=-1 +kerning first=376 second=347 amount=-1 +kerning first=354 second=312 amount=-1 +kerning first=321 second=264 amount=-1 +kerning first=89 second=353 amount=-1 +kerning first=358 second=248 amount=-1 +kerning first=219 second=196 amount=-1 +kerning first=241 second=356 amount=-1 +kerning first=34 second=916 amount=-1 +kerning first=86 second=65 amount=-1 +kerning first=87 second=192 amount=-1 +kerning first=271 second=108 amount=1 +kerning first=354 second=275 amount=-1 +kerning first=932 second=46 amount=-1 +kerning first=8220 second=283 amount=-1 +kerning first=221 second=243 amount=-1 +kerning first=195 second=936 amount=-1 +kerning first=315 second=171 amount=-1 +kerning first=84 second=943 amount=-1 +kerning first=194 second=358 amount=-1 +kerning first=84 second=245 amount=-1 +kerning first=8221 second=353 amount=-1 +kerning first=40 second=1035 amount=1 +kerning first=8216 second=101 amount=-1 +kerning first=1043 second=1169 amount=-1 +kerning first=221 second=103 amount=-1 +kerning first=932 second=297 amount=-1 +kerning first=1027 second=1082 amount=-1 +kerning first=321 second=8211 amount=-1 +kerning first=103 second=356 amount=-1 +kerning first=335 second=84 amount=-1 +kerning first=358 second=279 amount=-1 +kerning first=372 second=257 amount=-1 +kerning first=915 second=913 amount=-2 +kerning first=317 second=86 amount=-1 +kerning first=40 second=309 amount=1 +kerning first=315 second=220 amount=-1 +kerning first=372 second=113 amount=-1 +kerning first=376 second=99 amount=-1 +kerning first=76 second=290 amount=-1 +kerning first=910 second=211 amount=-1 +kerning first=212 second=8230 amount=-1 +kerning first=89 second=264 amount=-1 +kerning first=241 second=8217 amount=-1 +kerning first=931 second=336 amount=-1 +kerning first=932 second=945 amount=-1 +kerning first=329 second=932 amount=-1 +kerning first=915 second=258 amount=-2 +kerning first=1168 second=1241 amount=-1 +kerning first=123 second=1066 amount=1 +kerning first=319 second=213 amount=-1 +kerning first=65 second=932 amount=-1 +kerning first=356 second=363 amount=-1 +kerning first=46 second=939 amount=-1 +kerning first=221 second=256 amount=-1 +kerning first=1058 second=1101 amount=-1 +kerning first=8216 second=46 amount=-2 +kerning first=372 second=193 amount=-1 +kerning first=1027 second=1026 amount=1 +kerning first=34 second=949 amount=-1 +kerning first=321 second=87 amount=-1 +kerning first=86 second=99 amount=-1 +kerning first=912 second=955 amount=1 +kerning first=364 second=65 amount=-1 +kerning first=87 second=234 amount=-1 +kerning first=368 second=192 amount=-1 +kerning first=1168 second=1106 amount=1 +kerning first=933 second=214 amount=-1 +kerning first=8220 second=349 amount=-1 +kerning first=89 second=8211 amount=-1 +kerning first=87 second=354 amount=1 +kerning first=931 second=338 amount=-1 +kerning first=356 second=943 amount=-1 +kerning first=362 second=923 amount=-1 +kerning first=376 second=44 amount=-2 +kerning first=39 second=941 amount=-1 +kerning first=233 second=84 amount=-1 +kerning first=356 second=245 amount=-1 +kerning first=85 second=256 amount=-1 +kerning first=913 second=89 amount=-1 +kerning first=221 second=171 amount=-1 +kerning first=195 second=372 amount=-1 +kerning first=173 second=933 amount=-1 +kerning first=80 second=913 amount=-1 +kerning first=1027 second=1118 amount=-1 +kerning first=257 second=356 amount=-1 +kerning first=932 second=198 amount=-1 +kerning first=354 second=962 amount=-1 +kerning first=372 second=335 amount=-1 +kerning first=915 second=946 amount=-1 +kerning first=8218 second=354 amount=-1 +kerning first=354 second=243 amount=-1 +kerning first=89 second=225 amount=-1 +kerning first=8212 second=939 amount=-1 +kerning first=910 second=970 amount=-1 +kerning first=287 second=84 amount=-1 +kerning first=76 second=368 amount=-1 +kerning first=8216 second=945 amount=-1 +kerning first=80 second=258 amount=-1 +kerning first=86 second=44 amount=-1 +kerning first=211 second=46 amount=-1 +kerning first=354 second=372 amount=1 +kerning first=932 second=944 amount=-1 +kerning first=256 second=89 amount=-1 +kerning first=8217 second=358 amount=1 +kerning first=260 second=376 amount=-1 +kerning first=354 second=103 amount=-1 +kerning first=84 second=951 amount=-1 +kerning first=8220 second=101 amount=-1 +kerning first=939 second=940 amount=-1 +kerning first=317 second=932 amount=-1 +kerning first=932 second=255 amount=-1 +kerning first=39 second=916 amount=-1 +kerning first=915 second=81 amount=-1 +kerning first=358 second=969 amount=-1 +kerning first=244 second=932 amount=-1 +kerning first=8217 second=267 amount=-1 +kerning first=1033 second=1058 amount=-1 +kerning first=358 second=241 amount=-1 +kerning first=913 second=34 amount=-1 +kerning first=366 second=260 amount=-1 +kerning first=932 second=261 amount=-1 +kerning first=372 second=227 amount=-1 +kerning first=376 second=213 amount=-1 +kerning first=933 second=973 amount=-1 +kerning first=293 second=358 amount=-1 +kerning first=1043 second=1098 amount=-1 +kerning first=922 second=74 amount=1 +kerning first=357 second=8221 amount=1 +kerning first=932 second=114 amount=-1 +kerning first=315 second=927 amount=-1 +kerning first=926 second=912 amount=1 +kerning first=8204 second=902 amount=-1 +kerning first=257 second=8217 amount=-1 +kerning first=84 second=86 amount=1 +kerning first=1059 second=8211 amount=-1 +kerning first=196 second=356 amount=-1 +kerning first=354 second=256 amount=-1 +kerning first=373 second=46 amount=-1 +kerning first=315 second=286 amount=-1 +kerning first=8216 second=198 amount=-1 +kerning first=931 second=290 amount=-1 +kerning first=256 second=34 amount=-1 +kerning first=910 second=264 amount=-1 +kerning first=8220 second=46 amount=-2 +kerning first=932 second=194 amount=-1 +kerning first=358 second=913 amount=-1 +kerning first=1068 second=1026 amount=-1 +kerning first=84 second=230 amount=-1 +kerning first=8221 second=305 amount=-1 +kerning first=1058 second=1080 amount=-1 +kerning first=89 second=273 amount=-1 +kerning first=8250 second=89 amount=-1 +kerning first=1056 second=44 amount=-2 +kerning first=1168 second=1084 amount=-1 +kerning first=1056 second=1032 amount=-1 +kerning first=939 second=260 amount=-2 +kerning first=922 second=970 amount=1 +kerning first=89 second=277 amount=-1 +kerning first=358 second=258 amount=-1 +kerning first=34 second=195 amount=-1 +kerning first=260 second=358 amount=-1 +kerning first=8221 second=8204 amount=-1 +kerning first=354 second=171 amount=-1 +kerning first=315 second=8221 amount=-2 +kerning first=1059 second=1076 amount=-1 +kerning first=313 second=372 amount=-1 +kerning first=193 second=8220 amount=-1 +kerning first=356 second=951 amount=-1 +kerning first=197 second=86 amount=-1 +kerning first=246 second=8221 amount=-1 +kerning first=39 second=949 amount=-1 +kerning first=8216 second=261 amount=-1 +kerning first=221 second=263 amount=-1 +kerning first=910 second=8211 amount=-1 +kerning first=8217 second=343 amount=-1 +kerning first=8221 second=273 amount=-1 +kerning first=358 second=307 amount=-1 +kerning first=196 second=8217 amount=-1 +kerning first=160 second=8216 amount=-1 +kerning first=932 second=337 amount=-1 +kerning first=376 second=249 amount=-1 +kerning first=1027 second=1095 amount=-1 +kerning first=8216 second=1103 amount=-1 +kerning first=8211 second=910 amount=-1 +kerning first=84 second=271 amount=-1 +kerning first=8221 second=277 amount=-1 +kerning first=317 second=370 amount=-1 +kerning first=332 second=46 amount=-1 +kerning first=76 second=214 amount=-1 +kerning first=8220 second=945 amount=-1 +kerning first=84 second=120 amount=-1 +kerning first=376 second=259 amount=-1 +kerning first=255 second=46 amount=-1 +kerning first=356 second=86 amount=1 +kerning first=915 second=196 amount=-2 +kerning first=1038 second=8211 amount=-1 +kerning first=221 second=927 amount=-1 +kerning first=1168 second=1028 amount=-1 +kerning first=8218 second=1063 amount=-1 +kerning first=315 second=354 amount=-1 +kerning first=217 second=65 amount=-1 +kerning first=34 second=8230 amount=-2 +kerning first=8216 second=194 amount=-1 +kerning first=221 second=192 amount=-1 +kerning first=8217 second=237 amount=-1 +kerning first=246 second=354 amount=-1 +kerning first=1107 second=46 amount=-1 +kerning first=8211 second=1066 amount=-1 +kerning first=84 second=932 amount=1 +kerning first=45 second=354 amount=-1 +kerning first=65 second=939 amount=-2 +kerning first=939 second=948 amount=-1 +kerning first=932 second=231 amount=-1 +kerning first=1040 second=1033 amount=1 +kerning first=358 second=946 amount=-1 +kerning first=221 second=286 amount=-1 +kerning first=376 second=923 amount=-1 +kerning first=356 second=230 amount=-1 +kerning first=321 second=366 amount=-1 +kerning first=86 second=259 amount=-1 +kerning first=1058 second=1115 amount=1 +kerning first=1114 second=8217 amount=-1 +kerning first=1043 second=1077 amount=-1 +kerning first=933 second=954 amount=-1 +kerning first=1027 second=1040 amount=-1 +kerning first=939 second=334 amount=-1 +kerning first=932 second=93 amount=1 +kerning first=89 second=351 amount=-1 +kerning first=84 second=65 amount=-1 +kerning first=85 second=192 amount=-1 +kerning first=40 second=356 amount=1 +kerning first=929 second=46 amount=-2 +kerning first=8220 second=198 amount=-1 +kerning first=8216 second=337 amount=-1 +kerning first=1028 second=1035 amount=1 +kerning first=192 second=936 amount=-1 +kerning first=313 second=171 amount=-1 +kerning first=1038 second=1076 amount=-1 +kerning first=86 second=923 amount=-1 +kerning first=84 second=347 amount=-1 +kerning first=8221 second=351 amount=-1 +kerning first=356 second=271 amount=-1 +kerning first=80 second=196 amount=-1 +kerning first=101 second=356 amount=-1 +kerning first=197 second=932 amount=-1 +kerning first=356 second=120 amount=-1 +kerning first=915 second=959 amount=-1 +kerning first=89 second=239 amount=1 +kerning first=939 second=216 amount=-1 +kerning first=1058 second=1059 amount=1 +kerning first=321 second=45 amount=-1 +kerning first=313 second=220 amount=-1 +kerning first=354 second=263 amount=-1 +kerning first=70 second=257 amount=-1 +kerning first=8220 second=261 amount=-1 +kerning first=8216 second=231 amount=-1 +kerning first=221 second=234 amount=-1 +kerning first=89 second=100 amount=-1 +kerning first=84 second=966 amount=-1 +kerning first=356 second=932 amount=1 +kerning first=366 second=197 amount=-1 +kerning first=8220 second=1103 amount=-1 +kerning first=295 second=932 amount=-1 +kerning first=221 second=354 amount=1 +kerning first=84 second=238 amount=-1 +kerning first=8217 second=301 amount=-1 +kerning first=8221 second=239 amount=-1 +kerning first=317 second=213 amount=-1 +kerning first=39 second=195 amount=-1 +kerning first=358 second=382 amount=-1 +kerning first=44 second=939 amount=-1 +kerning first=372 second=246 amount=-1 +kerning first=932 second=285 amount=-1 +kerning first=220 second=256 amount=-1 +kerning first=376 second=229 amount=-1 +kerning first=1027 second=1074 amount=-1 +kerning first=230 second=84 amount=-1 +kerning first=360 second=193 amount=-1 +kerning first=84 second=99 amount=-1 +kerning first=8221 second=100 amount=-1 +kerning first=356 second=65 amount=-1 +kerning first=354 second=192 amount=-1 +kerning first=315 second=211 amount=-1 +kerning first=70 second=193 amount=-1 +kerning first=358 second=115 amount=-1 +kerning first=8220 second=194 amount=-1 +kerning first=931 second=214 amount=-1 +kerning first=8204 second=221 amount=-1 +kerning first=915 second=181 amount=-1 +kerning first=902 second=936 amount=-1 +kerning first=364 second=923 amount=-1 +kerning first=913 second=8220 amount=-1 +kerning first=227 second=84 amount=-1 +kerning first=86 second=229 amount=-1 +kerning first=89 second=45 amount=-1 +kerning first=123 second=1058 amount=1 +kerning first=1035 second=1063 amount=-1 +kerning first=356 second=347 amount=-1 +kerning first=8204 second=84 amount=-1 +kerning first=195 second=8221 amount=-1 +kerning first=192 second=372 amount=-1 +kerning first=939 second=197 amount=-2 +kerning first=1058 second=1093 amount=-1 +kerning first=39 second=8230 amount=-2 +kerning first=929 second=198 amount=-1 +kerning first=358 second=196 amount=-1 +kerning first=1075 second=44 amount=-1 +kerning first=932 second=308 amount=-1 +kerning first=8216 second=1026 amount=1 +kerning first=321 second=79 amount=-1 +kerning first=1168 second=1097 amount=-1 +kerning first=87 second=225 amount=-1 +kerning first=939 second=284 amount=-1 +kerning first=275 second=84 amount=-1 +kerning first=8220 second=337 amount=-1 +kerning first=84 second=44 amount=-1 +kerning first=256 second=8220 amount=-1 +kerning first=354 second=8221 amount=1 +kerning first=1059 second=1089 amount=-1 +kerning first=232 second=358 amount=-1 +kerning first=356 second=966 amount=-1 +kerning first=8216 second=285 amount=-1 +kerning first=258 second=376 amount=-1 +kerning first=221 second=289 amount=-1 +kerning first=356 second=238 amount=-1 +kerning first=932 second=369 amount=-1 +kerning first=241 second=932 amount=-1 +kerning first=195 second=354 amount=-1 +kerning first=321 second=8212 amount=-1 +kerning first=1027 second=1109 amount=-1 +kerning first=84 second=299 amount=-1 +kerning first=8221 second=303 amount=-1 +kerning first=1041 second=1098 amount=-1 +kerning first=362 second=260 amount=-1 +kerning first=358 second=333 amount=-1 +kerning first=354 second=961 amount=-1 +kerning first=289 second=358 amount=-1 +kerning first=376 second=281 amount=-1 +kerning first=356 second=99 amount=-1 +kerning first=939 second=187 amount=-1 +kerning first=354 second=234 amount=-1 +kerning first=1058 second=1038 amount=1 +kerning first=70 second=227 amount=-1 +kerning first=313 second=927 amount=-1 +kerning first=8220 second=231 amount=-1 +kerning first=336 second=8230 amount=-1 +kerning first=98 second=358 amount=-1 +kerning first=376 second=125 amount=1 +kerning first=8218 second=87 amount=-1 +kerning first=123 second=372 amount=1 +kerning first=253 second=8230 amount=-1 +kerning first=354 second=354 amount=1 +kerning first=76 second=89 amount=-1 +kerning first=193 second=356 amount=-1 +kerning first=221 second=211 amount=-1 +kerning first=932 second=942 amount=-1 +kerning first=1059 second=45 amount=-1 +kerning first=916 second=936 amount=-1 +kerning first=89 second=79 amount=-1 +kerning first=103 second=932 amount=-1 +kerning first=313 second=286 amount=-1 +kerning first=939 second=963 amount=-1 +kerning first=932 second=242 amount=-1 +kerning first=358 second=959 amount=-1 +kerning first=8216 second=308 amount=-1 +kerning first=1058 second=8249 amount=-1 +kerning first=902 second=372 amount=-1 +kerning first=86 second=281 amount=-1 +kerning first=8212 second=1059 amount=-1 +kerning first=358 second=233 amount=-1 +kerning first=929 second=194 amount=-1 +kerning first=221 second=74 amount=-1 +kerning first=1043 second=1090 amount=-1 +kerning first=1168 second=8211 amount=-1 +kerning first=8217 second=111 amount=-1 +kerning first=1066 second=1026 amount=-1 +kerning first=86 second=125 amount=1 +kerning first=87 second=273 amount=-1 +kerning first=114 second=8230 amount=-1 +kerning first=171 second=89 amount=-1 +kerning first=8249 second=376 amount=-1 +kerning first=358 second=356 amount=1 +kerning first=356 second=44 amount=-1 +kerning first=89 second=8212 amount=-1 +kerning first=947 second=46 amount=-1 +kerning first=87 second=277 amount=-1 +kerning first=372 second=84 amount=1 +kerning first=1033 second=8221 amount=-1 +kerning first=258 second=358 amount=-1 +kerning first=221 second=371 amount=-1 +kerning first=313 second=8221 amount=-2 +kerning first=1038 second=1089 amount=-1 +kerning first=315 second=264 amount=-1 +kerning first=76 second=34 amount=-2 +kerning first=196 second=86 amount=-1 +kerning first=243 second=8221 amount=-1 +kerning first=84 second=373 amount=-1 +kerning first=356 second=299 amount=-1 +kerning first=193 second=8217 amount=-1 +kerning first=8220 second=1026 amount=1 +kerning first=197 second=939 amount=-2 +kerning first=915 second=943 amount=-1 +kerning first=910 second=45 amount=-1 +kerning first=1043 second=46 amount=-1 +kerning first=1058 second=1072 amount=-1 +kerning first=358 second=181 amount=-1 +kerning first=334 second=46 amount=-1 +kerning first=933 second=913 amount=-2 +kerning first=1168 second=1076 amount=-2 +kerning first=354 second=289 amount=-1 +kerning first=89 second=257 amount=-1 +kerning first=8216 second=242 amount=-1 +kerning first=8220 second=285 amount=-1 +kerning first=221 second=353 amount=-1 +kerning first=104 second=8221 amount=-1 +kerning first=89 second=113 amount=-1 +kerning first=315 second=8211 amount=-1 +kerning first=358 second=8217 amount=1 +kerning first=257 second=932 amount=-1 +kerning first=313 second=354 amount=-1 +kerning first=219 second=65 amount=-1 +kerning first=84 second=974 amount=-1 +kerning first=220 second=192 amount=-1 +kerning first=933 second=258 amount=-2 +kerning first=243 second=354 amount=-1 +kerning first=1038 second=45 amount=-1 +kerning first=84 second=249 amount=-1 +kerning first=1062 second=1112 amount=1 +kerning first=208 second=44 amount=-1 +kerning first=75 second=308 amount=1 +kerning first=376 second=244 amount=-1 +kerning first=1027 second=1087 amount=-1 +kerning first=217 second=923 amount=-1 +kerning first=84 second=259 amount=-1 +kerning first=319 second=8249 amount=-1 +kerning first=8249 second=358 amount=-1 +kerning first=358 second=291 amount=-1 +kerning first=372 second=265 amount=-1 +kerning first=1059 second=8212 amount=-1 +kerning first=84 second=112 amount=-1 +kerning first=8221 second=113 amount=-1 +kerning first=89 second=193 amount=-1 +kerning first=923 second=8216 amount=-1 +kerning first=104 second=354 amount=-1 +kerning first=927 second=46 amount=-1 +kerning first=1061 second=1060 amount=-1 +kerning first=8220 second=308 amount=-1 +kerning first=1026 second=1035 amount=-1 +kerning first=194 second=936 amount=-1 +kerning first=915 second=268 amount=-1 +kerning first=354 second=74 amount=-1 +kerning first=86 second=244 amount=-1 +kerning first=315 second=87 amount=-1 +kerning first=84 second=923 amount=-1 +kerning first=319 second=217 amount=-1 +kerning first=356 second=373 amount=-1 +kerning first=89 second=58 amount=-1 +kerning first=8211 second=1058 amount=-1 +kerning first=221 second=264 amount=-1 +kerning first=8221 second=193 amount=-1 +kerning first=910 second=79 amount=-1 +kerning first=939 second=212 amount=-1 +kerning first=8212 second=1038 amount=-1 +kerning first=1058 second=1107 amount=-1 +kerning first=319 second=334 amount=-1 +kerning first=372 second=195 amount=-1 +kerning first=196 second=932 amount=-1 +kerning first=933 second=946 amount=-1 +kerning first=8216 second=1040 amount=-1 +kerning first=1168 second=1111 amount=-1 +kerning first=87 second=239 amount=1 +kerning first=324 second=84 amount=-1 +kerning first=354 second=371 amount=-1 +kerning first=89 second=335 amount=-1 +kerning first=70 second=365 amount=-1 +kerning first=376 second=260 amount=-1 +kerning first=261 second=8221 amount=-1 +kerning first=112 second=84 amount=-1 +kerning first=356 second=974 amount=-1 +kerning first=40 second=86 amount=1 +kerning first=913 second=356 amount=-1 +kerning first=87 second=100 amount=-1 +kerning first=910 second=8212 amount=-1 +kerning first=356 second=249 amount=-1 +kerning first=362 second=197 amount=-1 +kerning first=933 second=81 amount=-1 +kerning first=221 second=8211 amount=-1 +kerning first=932 second=380 amount=-1 +kerning first=8217 second=339 amount=-1 +kerning first=84 second=326 amount=-1 +kerning first=319 second=216 amount=-1 +kerning first=356 second=259 amount=-1 +kerning first=8221 second=335 amount=-1 +kerning first=354 second=970 amount=-1 +kerning first=358 second=363 amount=-1 +kerning first=337 second=358 amount=-1 +kerning first=218 second=256 amount=-1 +kerning first=356 second=112 amount=-1 +kerning first=915 second=951 amount=-1 +kerning first=354 second=353 amount=-1 +kerning first=86 second=260 amount=-1 +kerning first=89 second=227 amount=-1 +kerning first=910 second=912 amount=-1 +kerning first=370 second=193 amount=-1 +kerning first=372 second=8230 amount=-1 +kerning first=8220 second=242 amount=-1 +kerning first=376 second=8249 amount=-1 +kerning first=1038 second=8212 amount=-1 +kerning first=256 second=356 amount=-1 +kerning first=313 second=211 amount=-1 +kerning first=261 second=354 amount=-1 +kerning first=221 second=225 amount=-1 +kerning first=1059 second=58 amount=-1 +kerning first=8217 second=312 amount=-1 +kerning first=356 second=923 amount=-1 +kerning first=939 second=972 amount=-1 +kerning first=932 second=358 amount=1 +kerning first=358 second=943 amount=-1 +kerning first=1058 second=187 amount=-1 +kerning first=224 second=84 amount=-1 +kerning first=84 second=229 amount=-1 +kerning first=8217 second=275 amount=-1 +kerning first=1033 second=1063 amount=-1 +kerning first=358 second=245 amount=-1 +kerning first=248 second=358 amount=-1 +kerning first=913 second=8217 amount=-1 +kerning first=192 second=8221 amount=-1 +kerning first=932 second=267 amount=-1 +kerning first=194 second=372 amount=-1 +kerning first=372 second=232 amount=-1 +kerning first=1027 second=1066 amount=1 +kerning first=1043 second=1103 amount=-1 +kerning first=91 second=221 amount=1 +kerning first=932 second=119 amount=-1 +kerning first=929 second=308 amount=-1 +kerning first=376 second=334 amount=-1 +kerning first=1034 second=1059 amount=-1 +kerning first=283 second=84 amount=-1 +kerning first=372 second=97 amount=-1 +kerning first=45 second=933 amount=-1 +kerning first=910 second=193 amount=-2 +kerning first=234 second=358 amount=-1 +kerning first=91 second=84 amount=1 +kerning first=331 second=8221 amount=-1 +kerning first=256 second=8217 amount=-1 +kerning first=356 second=326 amount=-1 +kerning first=939 second=920 amount=-1 +kerning first=8250 second=356 amount=-1 +kerning first=8220 second=1040 amount=-1 +kerning first=192 second=354 amount=-1 +kerning first=910 second=58 amount=-1 +kerning first=1043 second=59 amount=-1 +kerning first=968 second=39 amount=-1 +kerning first=40 second=932 amount=1 +kerning first=1058 second=1085 amount=-1 +kerning first=364 second=260 amount=-1 +kerning first=319 second=284 amount=-1 +kerning first=285 second=358 amount=-1 +kerning first=376 second=216 amount=-1 +kerning first=321 second=71 amount=-1 +kerning first=1168 second=1089 amount=-1 +kerning first=1036 second=1051 amount=1 +kerning first=939 second=266 amount=-1 +kerning first=922 second=912 amount=1 +kerning first=89 second=287 amount=-1 +kerning first=76 second=8220 amount=-2 +kerning first=8216 second=358 amount=1 +kerning first=933 second=196 amount=-2 +kerning first=221 second=273 amount=-1 +kerning first=1027 second=173 amount=-1 +kerning first=354 second=8211 amount=-1 +kerning first=331 second=354 amount=-1 +kerning first=8216 second=267 amount=-1 +kerning first=1038 second=58 amount=-1 +kerning first=221 second=277 amount=-1 +kerning first=101 second=932 amount=-1 +kerning first=356 second=229 amount=-1 +kerning first=1057 second=1033 amount=1 +kerning first=1100 second=1098 amount=-1 +kerning first=902 second=8221 amount=-1 +kerning first=932 second=343 amount=-1 +kerning first=1027 second=1100 amount=-1 +kerning first=84 second=281 amount=-1 +kerning first=8221 second=287 amount=-1 +kerning first=1041 second=1090 amount=-1 +kerning first=195 second=87 amount=-1 +kerning first=76 second=219 amount=-1 +kerning first=84 second=125 amount=1 +kerning first=376 second=269 amount=-1 +kerning first=354 second=225 amount=-1 +kerning first=1168 second=45 amount=-1 +kerning first=376 second=117 amount=-1 +kerning first=123 second=354 amount=1 +kerning first=955 second=947 amount=-1 +kerning first=260 second=936 amount=-1 +kerning first=315 second=366 amount=-1 +kerning first=76 second=81 amount=-1 +kerning first=932 second=965 amount=-1 +kerning first=8217 second=243 amount=-1 +kerning first=354 second=87 amount=1 +kerning first=89 second=71 amount=-1 +kerning first=313 second=264 amount=-1 +kerning first=193 second=86 amount=-1 +kerning first=939 second=953 amount=-1 +kerning first=932 second=237 amount=-1 +kerning first=915 second=65 amount=-2 +kerning first=358 second=951 amount=-1 +kerning first=1068 second=1066 amount=-1 +kerning first=333 second=356 amount=-1 +kerning first=902 second=354 amount=-1 +kerning first=86 second=269 amount=-1 +kerning first=1058 second=1169 amount=-1 +kerning first=319 second=364 amount=-1 +kerning first=1043 second=1082 amount=-1 +kerning first=343 second=44 amount=-1 +kerning first=376 second=197 amount=-1 +kerning first=8217 second=103 amount=-1 +kerning first=196 second=939 amount=-2 +kerning first=936 second=256 amount=-1 +kerning first=933 second=959 amount=-1 +kerning first=8249 second=910 amount=-1 +kerning first=34 second=969 amount=-1 +kerning first=319 second=8216 amount=-2 +kerning first=89 second=365 amount=-1 +kerning first=958 second=125 amount=1 +kerning first=376 second=284 amount=-1 +kerning first=46 second=8216 amount=-2 +kerning first=354 second=305 amount=-1 +kerning first=1034 second=1038 amount=-1 +kerning first=358 second=86 amount=1 +kerning first=87 second=257 amount=-1 +kerning first=102 second=8221 amount=1 +kerning first=221 second=351 amount=-1 +kerning first=87 second=113 amount=-1 +kerning first=313 second=8211 amount=-1 +kerning first=218 second=192 amount=-1 +kerning first=339 second=356 amount=-1 +kerning first=86 second=197 amount=-1 +kerning first=315 second=45 amount=-1 +kerning first=356 second=281 amount=-1 +kerning first=173 second=221 amount=-1 +kerning first=916 second=8221 amount=-1 +kerning first=219 second=923 amount=-1 +kerning first=8217 second=256 amount=-1 +kerning first=356 second=125 amount=1 +kerning first=915 second=966 amount=-1 +kerning first=317 second=8249 amount=-1 +kerning first=89 second=246 amount=-1 +kerning first=963 second=912 amount=1 +kerning first=358 second=230 amount=-1 +kerning first=354 second=273 amount=-1 +kerning first=8220 second=358 amount=1 +kerning first=1043 second=1026 amount=1 +kerning first=333 second=8217 amount=-1 +kerning first=34 second=913 amount=-1 +kerning first=87 second=193 amount=-1 +kerning first=354 second=277 amount=-1 +kerning first=235 second=356 amount=-1 +kerning first=173 second=84 amount=-1 +kerning first=8220 second=267 amount=-1 +kerning first=80 second=65 amount=-1 +kerning first=221 second=239 amount=1 +kerning first=933 second=181 amount=-1 +kerning first=195 second=933 amount=-2 +kerning first=354 second=121 amount=-1 +kerning first=84 second=940 amount=-1 +kerning first=34 second=258 amount=-1 +kerning first=216 second=46 amount=-1 +kerning first=313 second=87 amount=-1 +kerning first=84 second=244 amount=-1 +kerning first=260 second=372 amount=-1 +kerning first=317 second=217 amount=-1 +kerning first=8221 second=246 amount=-1 +kerning first=1043 second=1118 amount=-1 +kerning first=221 second=100 amount=-1 +kerning first=932 second=301 amount=-1 +kerning first=376 second=235 amount=-1 +kerning first=1027 second=1079 amount=-1 +kerning first=1168 second=8212 amount=-1 +kerning first=291 second=356 amount=-1 +kerning first=916 second=354 amount=-1 +kerning first=317 second=334 amount=-1 +kerning first=360 second=195 amount=-1 +kerning first=358 second=271 amount=-1 +kerning first=97 second=356 amount=-1 +kerning first=193 second=932 amount=-1 +kerning first=8221 second=105 amount=-1 +kerning first=70 second=195 amount=-1 +kerning first=358 second=120 amount=-1 +kerning first=87 second=335 amount=-1 +kerning first=217 second=260 amount=-1 +kerning first=259 second=8221 amount=-1 +kerning first=110 second=84 amount=-1 +kerning first=321 second=221 amount=-1 +kerning first=86 second=235 amount=-1 +kerning first=315 second=79 amount=-1 +kerning first=364 second=197 amount=-1 +kerning first=319 second=212 amount=-1 +kerning first=931 second=81 amount=-1 +kerning first=8204 second=89 amount=-1 +kerning first=939 second=934 amount=-1 +kerning first=358 second=932 amount=1 +kerning first=915 second=44 amount=-2 +kerning first=910 second=71 amount=-1 +kerning first=317 second=216 amount=-1 +kerning first=321 second=336 amount=-1 +kerning first=1058 second=1098 amount=-1 +kerning first=271 second=318 amount=1 +kerning first=326 second=358 amount=-1 +kerning first=221 second=45 amount=-1 +kerning first=321 second=84 amount=-1 +kerning first=912 second=952 amount=1 +kerning first=1168 second=1102 amount=-1 +kerning first=84 second=260 amount=-1 +kerning first=87 second=227 amount=-1 +kerning first=368 second=193 amount=-1 +kerning first=354 second=351 amount=-1 +kerning first=939 second=67 amount=-1 +kerning first=259 second=354 amount=-1 +kerning first=315 second=8212 amount=-1 +kerning first=70 second=8230 amount=-2 +kerning first=358 second=65 amount=-1 +kerning first=356 second=940 amount=-1 +kerning first=97 second=8217 amount=-1 +kerning first=376 second=41 amount=1 +kerning first=39 second=969 amount=-1 +kerning first=356 second=244 amount=-1 +kerning first=913 second=86 amount=-1 +kerning first=955 second=8221 amount=-1 +kerning first=226 second=84 amount=-1 +kerning first=1027 second=1114 amount=-1 +kerning first=321 second=338 amount=-1 +kerning first=194 second=8221 amount=-1 +kerning first=358 second=347 amount=-1 +kerning first=84 second=8249 amount=-1 +kerning first=354 second=239 amount=-1 +kerning first=910 second=941 amount=-1 +kerning first=1168 second=58 amount=-1 +kerning first=915 second=213 amount=-1 +kerning first=76 second=356 amount=-1 +kerning first=8211 second=354 amount=-1 +kerning first=86 second=41 amount=1 +kerning first=89 second=336 amount=-1 +kerning first=80 second=44 amount=-2 +kerning first=932 second=971 amount=-1 +kerning first=256 second=86 amount=-1 +kerning first=354 second=100 amount=-1 +kerning first=89 second=84 amount=1 +kerning first=70 second=97 amount=-1 +kerning first=84 second=948 amount=-1 +kerning first=942 second=8217 amount=-1 +kerning first=939 second=968 amount=-1 +kerning first=932 second=252 amount=-1 +kerning first=39 second=913 amount=-1 +kerning first=358 second=966 amount=-1 +kerning first=936 second=192 amount=-1 +kerning first=932 second=173 amount=-1 +kerning first=8217 second=263 amount=-1 +kerning first=358 second=238 amount=-1 +kerning first=372 second=228 amount=-1 +kerning first=194 second=354 amount=-1 +kerning first=221 second=79 amount=-1 +kerning first=376 second=212 amount=-1 +kerning first=171 second=356 amount=-1 +kerning first=933 second=943 amount=-1 +kerning first=1027 second=1058 amount=1 +kerning first=1043 second=1095 amount=-1 +kerning first=8216 second=1066 amount=1 +kerning first=356 second=260 amount=-1 +kerning first=1113 second=8221 amount=-1 +kerning first=317 second=284 amount=-1 +kerning first=932 second=111 amount=-1 +kerning first=39 second=258 amount=-1 +kerning first=281 second=358 amount=-1 +kerning first=8221 second=84 amount=1 +kerning first=65 second=8216 amount=-1 +kerning first=89 second=338 amount=-1 +kerning first=358 second=99 amount=-1 +kerning first=910 second=916 amount=-2 +kerning first=76 second=8217 amount=-2 +kerning first=319 second=920 amount=-1 +kerning first=160 second=8218 amount=-2 +kerning first=221 second=8212 amount=-1 +kerning first=8217 second=192 amount=-1 +kerning first=354 second=45 amount=-1 +kerning first=969 second=34 amount=-1 +kerning first=1098 second=1098 amount=-1 +kerning first=356 second=8249 amount=-1 +kerning first=376 second=367 amount=-1 +kerning first=321 second=290 amount=-1 +kerning first=1058 second=1077 amount=-1 +kerning first=319 second=266 amount=-1 +kerning first=192 second=87 amount=-1 +kerning first=372 second=248 amount=-1 +kerning first=1043 second=1040 amount=-1 +kerning first=913 second=932 amount=-1 +kerning first=1168 second=1081 amount=-1 +kerning first=354 second=303 amount=-1 +kerning first=89 second=265 amount=-1 +kerning first=34 second=196 amount=-1 +kerning first=936 second=961 amount=-1 +kerning first=939 second=46 amount=-2 +kerning first=258 second=936 amount=-1 +kerning first=358 second=44 amount=-1 +kerning first=313 second=366 amount=-1 +kerning first=356 second=948 amount=-1 +kerning first=88 second=934 amount=-1 +kerning first=933 second=268 amount=-1 +kerning first=221 second=257 amount=-1 +kerning first=910 second=8250 amount=-1 +kerning first=1100 second=1090 amount=-1 +kerning first=8216 second=111 amount=-1 +kerning first=221 second=113 amount=-1 +kerning first=1066 second=1066 amount=-1 +kerning first=335 second=356 amount=-1 +kerning first=376 second=250 amount=-1 +kerning first=8217 second=8221 amount=-1 +kerning first=1027 second=1092 amount=-1 +kerning first=84 second=269 amount=-1 +kerning first=256 second=932 amount=-1 +kerning first=317 second=364 amount=-1 +kerning first=8221 second=265 amount=-1 +kerning first=358 second=299 amount=-1 +kerning first=341 second=44 amount=-1 +kerning first=217 second=197 amount=-1 +kerning first=372 second=279 amount=-1 +kerning first=193 second=939 amount=-2 +kerning first=84 second=117 amount=-1 +kerning first=915 second=923 amount=-2 +kerning first=317 second=8216 amount=-2 +kerning first=89 second=195 amount=-1 +kerning first=910 second=949 amount=-1 +kerning first=293 second=8221 amount=-1 +kerning first=44 second=8216 amount=-2 +kerning first=89 second=290 amount=-1 +kerning first=221 second=193 amount=-1 +kerning first=123 second=87 amount=1 +kerning first=8217 second=234 amount=-1 +kerning first=910 second=336 amount=-1 +kerning first=366 second=198 amount=-1 +kerning first=939 second=945 amount=-1 +kerning first=932 second=224 amount=-1 +kerning first=1068 second=1058 amount=-1 +kerning first=8220 second=1066 amount=1 +kerning first=84 second=197 amount=-1 +kerning first=376 second=920 amount=-1 +kerning first=313 second=45 amount=-1 +kerning first=8217 second=354 amount=1 +kerning first=8221 second=195 amount=-1 +kerning first=946 second=34 amount=-1 +kerning first=321 second=368 amount=-1 +kerning first=1043 second=1074 amount=-1 +kerning first=221 second=58 amount=-1 +kerning first=902 second=87 amount=-1 +kerning first=933 second=951 amount=-1 +kerning first=1168 second=1116 amount=-1 +kerning first=87 second=246 amount=-1 +kerning first=1041 second=1026 amount=-1 +kerning first=335 second=8217 amount=-1 +kerning first=70 second=361 amount=-1 +kerning first=376 second=266 amount=-1 +kerning first=85 second=193 amount=-1 +kerning first=293 second=354 amount=-1 +kerning first=354 second=8212 amount=-1 +kerning first=89 second=8230 amount=-2 +kerning first=1059 second=1108 amount=-1 +kerning first=233 second=356 amount=-1 +kerning first=8250 second=932 amount=-1 +kerning first=221 second=335 amount=-1 +kerning first=192 second=933 amount=-2 +kerning first=910 second=338 amount=-1 +kerning first=1027 second=171 amount=-1 +kerning first=245 second=84 amount=-1 +kerning first=260 second=8221 amount=-1 +kerning first=80 second=923 amount=-1 +kerning first=258 second=372 amount=-1 +kerning first=84 second=341 amount=-1 +kerning first=356 second=269 amount=-1 +kerning first=8221 second=345 amount=-1 +kerning first=931 second=8217 amount=-1 +kerning first=354 second=912 amount=-1 +kerning first=932 second=339 amount=-1 +kerning first=358 second=373 amount=-1 +kerning first=287 second=356 amount=-1 +kerning first=84 second=187 amount=-1 +kerning first=8221 second=8230 amount=-2 +kerning first=356 second=117 amount=-1 +kerning first=939 second=198 amount=-2 +kerning first=354 second=253 amount=-1 +kerning first=89 second=232 amount=-1 +kerning first=1090 second=44 amount=-1 +kerning first=70 second=251 amount=-1 +kerning first=370 second=195 amount=-1 +kerning first=1168 second=1060 amount=-1 +kerning first=923 second=39 amount=-1 +kerning first=354 second=257 amount=-1 +kerning first=8216 second=224 amount=-1 +kerning first=219 second=260 amount=-1 +kerning first=221 second=227 amount=-1 +kerning first=354 second=113 amount=-1 +kerning first=89 second=97 amount=-1 +kerning first=8220 second=111 amount=-1 +kerning first=84 second=963 amount=-1 +kerning first=366 second=194 amount=-1 +kerning first=8204 second=8220 amount=-1 +kerning first=939 second=944 amount=-1 +kerning first=932 second=312 amount=-1 +kerning first=358 second=974 amount=-1 +kerning first=84 second=235 amount=-1 +kerning first=313 second=79 amount=-1 +kerning first=356 second=197 amount=-1 +kerning first=8217 second=289 amount=-1 +kerning first=260 second=354 amount=-1 +kerning first=317 second=212 amount=-1 +kerning first=8221 second=232 amount=-1 +kerning first=39 second=196 amount=-1 +kerning first=358 second=249 amount=-1 +kerning first=1043 second=1109 amount=-1 +kerning first=932 second=275 amount=-1 +kerning first=376 second=226 amount=-1 +kerning first=328 second=358 amount=-1 +kerning first=358 second=259 amount=-1 +kerning first=1059 second=8230 amount=-2 +kerning first=354 second=193 amount=-1 +kerning first=358 second=112 amount=-1 +kerning first=1111 second=1106 amount=1 +kerning first=76 second=268 amount=-1 +kerning first=333 second=932 amount=-1 +kerning first=902 second=933 amount=-2 +kerning first=910 second=195 amount=-2 +kerning first=313 second=8212 amount=-1 +kerning first=68 second=8230 amount=-1 +kerning first=91 second=89 amount=1 +kerning first=1038 second=1108 amount=-1 +kerning first=8216 second=339 amount=-1 +kerning first=321 second=214 amount=-1 +kerning first=86 second=226 amount=-1 +kerning first=315 second=71 amount=-1 +kerning first=910 second=290 amount=-1 +kerning first=210 second=44 amount=-1 +kerning first=356 second=341 amount=-1 +kerning first=358 second=923 amount=-1 +kerning first=372 second=913 amount=-1 +kerning first=356 second=187 amount=-1 +kerning first=939 second=194 amount=-2 +kerning first=1058 second=1090 amount=-1 +kerning first=271 second=293 amount=1 +kerning first=1107 second=173 amount=-1 +kerning first=8217 second=74 amount=-1 +kerning first=913 second=939 amount=-2 +kerning first=1168 second=1094 amount=-1 +kerning first=319 second=67 amount=-1 +kerning first=354 second=335 amount=-1 +kerning first=339 second=932 amount=-1 +kerning first=372 second=258 amount=-1 +kerning first=84 second=41 amount=1 +kerning first=1027 second=1241 amount=-1 +kerning first=939 second=59 amount=-1 +kerning first=1059 second=1086 amount=-1 +kerning first=356 second=963 amount=-1 +kerning first=197 second=8216 amount=-1 +kerning first=221 second=287 amount=-1 +kerning first=8216 second=275 amount=-1 +kerning first=229 second=358 amount=-1 +kerning first=87 second=84 amount=1 +kerning first=356 second=235 amount=-1 +kerning first=910 second=8230 amount=-2 +kerning first=933 second=65 amount=-2 +kerning first=1027 second=1106 amount=1 +kerning first=8218 second=221 amount=-2 +kerning first=256 second=939 amount=-2 +kerning first=187 second=1026 amount=-1 +kerning first=235 second=932 amount=-1 +kerning first=358 second=326 amount=-1 +kerning first=1058 second=46 amount=-1 +kerning first=376 second=283 amount=-1 +kerning first=354 second=227 amount=-1 +kerning first=89 second=214 amount=-1 +kerning first=70 second=228 amount=-1 +kerning first=8220 second=224 amount=-1 +kerning first=279 second=358 amount=-1 +kerning first=8218 second=84 amount=-1 +kerning first=1038 second=8230 amount=-2 +kerning first=8230 second=34 amount=-2 +kerning first=76 second=86 amount=-1 +kerning first=958 second=41 amount=1 +kerning first=932 second=962 amount=-1 +kerning first=8217 second=353 amount=-1 +kerning first=291 second=932 amount=-1 +kerning first=916 second=933 amount=-1 +kerning first=952 second=44 amount=-1 +kerning first=317 second=920 amount=-1 +kerning first=932 second=243 amount=-1 +kerning first=1169 second=46 amount=-1 +kerning first=97 second=932 amount=-1 +kerning first=86 second=283 amount=-1 +kerning first=358 second=229 amount=-1 +kerning first=319 second=360 amount=-1 +kerning first=221 second=71 amount=-1 +kerning first=932 second=372 amount=1 +kerning first=1043 second=1087 amount=-1 +kerning first=1168 second=8250 amount=-1 +kerning first=933 second=966 amount=-1 +kerning first=8216 second=1058 amount=1 +kerning first=317 second=266 amount=-1 +kerning first=932 second=103 amount=-1 +kerning first=194 second=87 amount=-1 +kerning first=89 second=361 amount=-1 +kerning first=356 second=41 amount=1 +kerning first=87 second=265 amount=-1 +kerning first=8220 second=339 amount=-1 +kerning first=376 second=67 amount=-1 +kerning first=908 second=46 amount=-1 +kerning first=221 second=365 amount=-1 +kerning first=1038 second=1086 amount=-1 +kerning first=931 second=268 amount=-1 +kerning first=1098 second=1090 amount=-1 +kerning first=84 second=367 amount=-1 +kerning first=376 second=349 amount=-1 +kerning first=915 second=940 amount=-1 +kerning first=89 second=251 amount=-1 +kerning first=219 second=197 amount=-1 +kerning first=932 second=256 amount=-1 +kerning first=8216 second=962 amount=-1 +kerning first=87 second=195 amount=-1 +kerning first=354 second=287 amount=-1 +kerning first=118 second=44 amount=-1 +kerning first=173 second=89 amount=-1 +kerning first=8216 second=243 amount=-1 +kerning first=8220 second=275 amount=-1 +kerning first=160 second=376 amount=-1 +kerning first=221 second=246 amount=-1 +kerning first=84 second=972 amount=-1 +kerning first=8204 second=8222 amount=-2 +kerning first=98 second=8221 amount=-1 +kerning first=220 second=193 amount=-1 +kerning first=84 second=250 amount=-1 +kerning first=362 second=198 amount=-1 +kerning first=230 second=356 amount=-1 +kerning first=232 second=354 amount=-1 +kerning first=8216 second=103 amount=-1 +kerning first=933 second=44 amount=-2 +kerning first=1066 second=1058 amount=-1 +kerning first=1027 second=1084 amount=-1 +kerning first=76 second=932 amount=-1 +kerning first=8211 second=933 amount=-1 +kerning first=319 second=39 amount=-2 +kerning first=1060 second=1061 amount=-1 +kerning first=932 second=171 amount=-1 +kerning first=358 second=281 amount=-1 +kerning first=84 second=109 amount=-1 +kerning first=8221 second=110 amount=-1 +kerning first=46 second=39 amount=-2 +kerning first=315 second=221 amount=-1 +kerning first=358 second=125 amount=1 +kerning first=376 second=101 amount=-1 +kerning first=289 second=354 amount=-1 +kerning first=87 second=8230 amount=-1 +kerning first=910 second=214 amount=-1 +kerning first=45 second=221 amount=-1 +kerning first=227 second=356 amount=-1 +kerning first=315 second=336 amount=-1 +kerning first=171 second=932 amount=-1 +kerning first=8204 second=356 amount=-1 +kerning first=98 second=354 amount=-1 +kerning first=194 second=933 amount=-2 +kerning first=915 second=260 amount=-2 +kerning first=315 second=84 amount=-1 +kerning first=319 second=218 amount=-1 +kerning first=356 second=367 amount=-1 +kerning first=246 second=84 amount=-1 +kerning first=8216 second=256 amount=-1 +kerning first=8220 second=1058 amount=1 +kerning first=258 second=8221 amount=-1 +kerning first=45 second=84 amount=-1 +kerning first=1058 second=1103 amount=-1 +kerning first=372 second=196 amount=-1 +kerning first=1043 second=1066 amount=1 +kerning first=275 second=356 amount=-1 +kerning first=1027 second=1028 amount=-1 +kerning first=321 second=89 amount=-1 +kerning first=86 second=101 amount=-1 +kerning first=1168 second=1108 amount=-1 +kerning first=87 second=232 amount=-1 +kerning first=368 second=195 amount=-1 +kerning first=354 second=365 amount=-1 +kerning first=933 second=213 amount=-1 +kerning first=160 second=358 amount=-1 +kerning first=315 second=338 amount=-1 +kerning first=1068 second=8221 amount=-1 +kerning first=356 second=972 amount=-1 +kerning first=376 second=46 amount=-2 +kerning first=87 second=97 amount=-1 +kerning first=356 second=250 amount=-1 +kerning first=1100 second=1118 amount=-1 +kerning first=362 second=194 amount=-1 +kerning first=91 second=1035 amount=1 +kerning first=8217 second=305 amount=-1 +kerning first=227 second=8217 amount=-1 +kerning first=258 second=354 amount=-1 +kerning first=84 second=324 amount=-1 +kerning first=8221 second=328 amount=-1 +kerning first=354 second=941 amount=-1 +kerning first=8220 second=962 amount=-1 +kerning first=372 second=333 amount=-1 +kerning first=1058 second=59 amount=-1 +kerning first=915 second=948 amount=-1 +kerning first=356 second=109 amount=-1 +kerning first=354 second=246 amount=-1 +kerning first=89 second=228 amount=-1 +kerning first=8220 second=243 amount=-1 +kerning first=91 second=309 amount=1 +kerning first=910 second=973 amount=-1 +kerning first=8217 second=8204 amount=-1 +kerning first=76 second=370 amount=-1 +kerning first=321 second=34 amount=-2 +kerning first=80 second=260 amount=-1 +kerning first=86 second=46 amount=-1 +kerning first=955 second=967 amount=-1 +kerning first=111 second=358 amount=-1 +kerning first=1043 second=173 amount=-1 +kerning first=335 second=932 amount=-1 +kerning first=8217 second=273 amount=-1 +kerning first=915 second=334 amount=-1 +kerning first=354 second=105 amount=-1 +kerning first=1059 second=1044 amount=-1 +kerning first=84 second=953 amount=-1 +kerning first=8220 second=103 amount=-1 +kerning first=939 second=942 amount=-1 +kerning first=358 second=940 amount=-1 +kerning first=221 second=336 amount=-1 +kerning first=84 second=226 amount=-1 +kerning first=313 second=71 amount=-1 +kerning first=8217 second=277 amount=-1 +kerning first=212 second=44 amount=-1 +kerning first=358 second=244 amount=-1 +kerning first=951 second=8221 amount=-1 +kerning first=372 second=233 amount=-1 +kerning first=221 second=84 amount=1 +kerning first=932 second=263 amount=-1 +kerning first=360 second=913 amount=-1 +kerning first=260 second=87 amount=-1 +kerning first=1043 second=1100 amount=-1 +kerning first=1168 second=8230 amount=-1 +kerning first=8230 second=8220 amount=-2 +kerning first=354 second=916 amount=-1 +kerning first=70 second=913 amount=-1 +kerning first=372 second=356 amount=1 +kerning first=317 second=67 amount=-1 +kerning first=89 second=248 amount=-1 +kerning first=187 second=376 amount=-1 +kerning first=360 second=258 amount=-1 +kerning first=8249 second=354 amount=-1 +kerning first=915 second=216 amount=-1 +kerning first=315 second=290 amount=-1 +kerning first=70 second=258 amount=-1 +kerning first=196 second=8216 amount=-1 +kerning first=221 second=338 amount=-1 +kerning first=8220 second=256 amount=-1 +kerning first=228 second=358 amount=-1 +kerning first=356 second=324 amount=-1 +kerning first=271 second=295 amount=1 +kerning first=932 second=192 amount=-1 +kerning first=8221 second=248 amount=-1 +kerning first=1058 second=1082 amount=-1 +kerning first=233 second=932 amount=-1 +kerning first=1056 second=46 amount=-2 +kerning first=376 second=198 amount=-1 +kerning first=933 second=923 amount=-2 +kerning first=1168 second=1086 amount=-1 +kerning first=939 second=262 amount=-1 +kerning first=277 second=358 amount=-1 +kerning first=89 second=279 amount=-1 +kerning first=358 second=260 amount=-1 +kerning first=337 second=8221 amount=-1 +kerning first=354 second=8250 amount=-1 +kerning first=356 second=953 amount=-1 +kerning first=195 second=221 amount=-1 +kerning first=8216 second=263 amount=-1 +kerning first=287 second=932 amount=-1 +kerning first=221 second=265 amount=-1 +kerning first=84 second=331 amount=-1 +kerning first=8217 second=351 amount=-1 +kerning first=356 second=226 amount=-1 +kerning first=1100 second=1095 amount=-1 +kerning first=1038 second=1044 amount=-1 +kerning first=34 second=65 amount=-1 +kerning first=1027 second=1097 amount=-1 +kerning first=965 second=34 amount=-1 +kerning first=86 second=198 amount=-1 +kerning first=84 second=283 amount=-1 +kerning first=8221 second=279 amount=-1 +kerning first=317 second=360 amount=-1 +kerning first=354 second=949 amount=-1 +kerning first=932 second=8221 amount=1 +kerning first=76 second=213 amount=-1 +kerning first=195 second=84 amount=-1 +kerning first=84 second=122 amount=-1 +kerning first=376 second=261 amount=-1 +kerning first=65 second=39 amount=-1 +kerning first=187 second=358 amount=-1 +kerning first=1058 second=1026 amount=1 +kerning first=358 second=8249 amount=-1 +kerning first=248 second=8221 amount=-1 +kerning first=910 second=954 amount=-1 +kerning first=337 second=354 amount=-1 +kerning first=915 second=197 amount=-2 +kerning first=260 second=933 amount=-2 +kerning first=315 second=368 amount=-1 +kerning first=8216 second=192 amount=-1 +kerning first=221 second=195 amount=-1 +kerning first=932 second=961 amount=-1 +kerning first=8217 second=239 amount=-1 +kerning first=915 second=284 amount=-1 +kerning first=171 second=939 amount=-1 +kerning first=173 second=1035 amount=-1 +kerning first=354 second=84 amount=1 +kerning first=84 second=934 amount=-1 +kerning first=1040 second=1035 amount=-1 +kerning first=932 second=234 amount=-1 +kerning first=358 second=948 amount=-1 +kerning first=102 second=58 amount=1 +kerning first=1068 second=1063 amount=-1 +kerning first=221 second=290 amount=-1 +kerning first=920 second=8230 amount=-1 +kerning first=86 second=261 amount=-1 +kerning first=1058 second=1118 amount=-1 +kerning first=324 second=356 amount=-1 +kerning first=1043 second=1079 amount=-1 +kerning first=932 second=354 amount=1 +kerning first=376 second=194 amount=-1 +kerning first=8217 second=100 amount=-1 +kerning first=939 second=332 amount=-1 +kerning first=354 second=378 amount=-1 +kerning first=112 second=356 amount=-1 +kerning first=248 second=354 amount=-1 +kerning first=929 second=256 amount=-1 +kerning first=85 second=195 amount=-1 +kerning first=1059 second=1113 amount=-1 +kerning first=376 second=59 amount=-1 +kerning first=915 second=187 amount=-1 +kerning first=356 second=331 amount=-1 +kerning first=270 second=8230 amount=-1 +kerning first=1027 second=8211 amount=-1 +kerning first=218 second=193 amount=-1 +kerning first=221 second=8230 amount=-2 +kerning first=86 second=194 amount=-1 +kerning first=364 second=198 amount=-1 +kerning first=84 second=349 amount=-1 +kerning first=356 second=283 amount=-1 +kerning first=234 second=354 amount=-1 +kerning first=80 second=197 amount=-1 +kerning first=376 second=337 amount=-1 +kerning first=356 second=122 amount=-1 +kerning first=915 second=963 amount=-1 +kerning first=317 second=39 amount=-2 +kerning first=8216 second=961 amount=-2 +kerning first=44 second=39 amount=-2 +kerning first=313 second=221 amount=-1 +kerning first=324 second=8217 amount=-1 +kerning first=354 second=265 amount=-1 +kerning first=8216 second=234 amount=-1 +kerning first=8220 second=263 amount=-1 +kerning first=221 second=232 amount=-1 +kerning first=285 second=354 amount=-1 +kerning first=354 second=118 amount=-1 +kerning first=112 second=8217 amount=-1 +kerning first=224 second=356 amount=-1 +kerning first=84 second=968 amount=-1 +kerning first=313 second=336 amount=-1 +kerning first=356 second=934 amount=-1 +kerning first=8216 second=354 amount=1 +kerning first=84 second=236 amount=-1 +kerning first=8217 second=303 amount=-1 +kerning first=313 second=84 amount=-1 +kerning first=8221 second=241 amount=-1 +kerning first=317 second=218 amount=-1 +kerning first=86 second=337 amount=-1 +kerning first=243 second=84 amount=-1 +kerning first=34 second=44 amount=-2 +kerning first=372 second=245 amount=-1 +kerning first=221 second=97 amount=-1 +kerning first=932 second=289 amount=-1 +kerning first=1043 second=1114 amount=-1 +kerning first=376 second=231 amount=-1 +kerning first=1027 second=1076 amount=-2 +kerning first=321 second=8220 amount=-2 +kerning first=923 second=376 amount=-1 +kerning first=360 second=196 amount=-1 +kerning first=89 second=913 amount=-1 +kerning first=358 second=269 amount=-1 +kerning first=283 second=356 amount=-1 +kerning first=1041 second=1066 amount=-1 +kerning first=84 second=101 amount=-1 +kerning first=354 second=195 amount=-1 +kerning first=39 second=65 amount=-1 +kerning first=70 second=196 amount=-1 +kerning first=315 second=214 amount=-1 +kerning first=358 second=117 amount=-1 +kerning first=8220 second=192 amount=-1 +kerning first=91 second=356 amount=1 +kerning first=931 second=213 amount=-1 +kerning first=376 second=93 amount=1 +kerning first=313 second=338 amount=-1 +kerning first=1066 second=8221 amount=-1 +kerning first=89 second=258 amount=-1 +kerning first=1038 second=1113 amount=-1 +kerning first=104 second=84 amount=-1 +kerning first=321 second=219 amount=-1 +kerning first=86 second=231 amount=-1 +kerning first=1098 second=1118 amount=-1 +kerning first=364 second=194 amount=-1 +kerning first=356 second=349 amount=-1 +kerning first=8221 second=913 amount=-1 +kerning first=8204 second=86 amount=-1 +kerning first=224 second=8217 amount=-1 +kerning first=939 second=199 amount=-1 +kerning first=1058 second=1095 amount=-1 +kerning first=8212 second=1026 amount=-1 +kerning first=358 second=197 amount=-1 +kerning first=1043 second=1058 amount=1 +kerning first=1075 second=46 amount=-1 +kerning first=944 second=39 amount=-1 +kerning first=321 second=81 amount=-1 +kerning first=86 second=93 amount=1 +kerning first=1168 second=1099 amount=-1 +kerning first=87 second=228 amount=-1 +kerning first=8221 second=258 amount=-1 +kerning first=939 second=288 amount=-1 +kerning first=354 second=345 amount=-1 +kerning first=932 second=74 amount=-1 +kerning first=84 second=46 amount=-1 +kerning first=1050 second=1051 amount=1 +kerning first=354 second=8230 amount=-1 +kerning first=109 second=358 amount=-1 +kerning first=356 second=968 amount=-1 +kerning first=8216 second=289 amount=-1 +kerning first=934 second=933 amount=-1 +kerning first=8221 second=307 amount=-1 +kerning first=356 second=236 amount=-1 +kerning first=932 second=371 amount=-1 +kerning first=1027 second=1111 amount=-1 +kerning first=1114 second=1098 amount=-1 +kerning first=923 second=358 amount=-1 +kerning first=84 second=297 amount=-1 +kerning first=1118 second=8230 amount=-1 +kerning first=358 second=341 amount=-1 +kerning first=370 second=913 amount=-1 +kerning first=258 second=87 amount=-1 +kerning first=8220 second=961 amount=-2 +kerning first=376 second=285 amount=-1 +kerning first=356 second=101 amount=-1 +kerning first=354 second=232 amount=-1 +kerning first=1058 second=1040 amount=-1 +kerning first=358 second=187 amount=-1 +kerning first=8220 second=234 amount=-1 +kerning first=915 second=212 amount=-1 +kerning first=8218 second=89 amount=-2 +kerning first=955 second=957 amount=-1 +kerning first=87 second=248 amount=-1 +kerning first=8230 second=8217 amount=-2 +kerning first=8222 second=376 amount=-2 +kerning first=1168 second=1044 amount=-1 +kerning first=230 second=932 amount=-1 +kerning first=370 second=258 amount=-1 +kerning first=221 second=214 amount=-1 +kerning first=8220 second=354 amount=1 +kerning first=932 second=970 amount=-1 +kerning first=261 second=84 amount=-1 +kerning first=354 second=97 amount=-1 +kerning first=89 second=81 amount=-1 +kerning first=1059 second=1035 amount=1 +kerning first=84 second=945 amount=-1 +kerning first=313 second=290 amount=-1 +kerning first=193 second=8216 amount=-1 +kerning first=932 second=353 amount=-1 +kerning first=939 second=965 amount=-1 +kerning first=358 second=963 amount=-1 +kerning first=936 second=193 amount=-1 +kerning first=225 second=358 amount=-1 +kerning first=358 second=235 amount=-1 +kerning first=929 second=192 amount=-1 +kerning first=8216 second=74 amount=-1 +kerning first=1043 second=1092 amount=-1 +kerning first=8217 second=113 amount=-1 +kerning first=933 second=940 amount=-1 +kerning first=34 second=974 amount=-1 +kerning first=1036 second=1095 amount=-1 +kerning first=227 second=932 amount=-1 +kerning first=217 second=198 amount=-1 +kerning first=8204 second=932 amount=-1 +kerning first=376 second=308 amount=-1 +kerning first=356 second=46 amount=-1 +kerning first=39 second=44 amount=-2 +kerning first=87 second=279 amount=-1 +kerning first=910 second=913 amount=-2 +kerning first=326 second=8221 amount=-1 +kerning first=197 second=39 amount=-1 +kerning first=1028 second=1051 amount=1 +kerning first=221 second=361 amount=-1 +kerning first=192 second=221 amount=-1 +kerning first=275 second=932 amount=-1 +kerning first=8217 second=193 amount=-1 +kerning first=1098 second=1095 amount=-1 +kerning first=356 second=297 amount=-1 +kerning first=910 second=258 amount=-2 +kerning first=84 second=198 amount=-1 +kerning first=376 second=369 amount=-1 +kerning first=915 second=972 amount=-1 +kerning first=1058 second=1074 amount=-1 +kerning first=319 second=262 amount=-1 +kerning first=192 second=84 amount=-1 +kerning first=372 second=230 amount=-1 +kerning first=173 second=356 amount=-1 +kerning first=34 second=923 amount=-1 +kerning first=8222 second=358 amount=-1 +kerning first=1168 second=1078 amount=-1 +kerning first=8216 second=353 amount=-1 +kerning first=8220 second=289 amount=-1 +kerning first=326 second=354 amount=-1 +kerning first=221 second=251 amount=-1 +kerning first=89 second=115 amount=-1 +kerning first=258 second=933 amount=-2 +kerning first=358 second=41 amount=1 +kerning first=84 second=944 amount=-1 +kerning first=313 second=368 amount=-1 +kerning first=356 second=945 amount=-1 +kerning first=336 second=44 amount=-1 +kerning first=220 second=195 amount=-1 +kerning first=933 second=260 amount=-2 +kerning first=253 second=44 amount=-1 +kerning first=84 second=255 amount=-1 +kerning first=8217 second=335 amount=-1 +kerning first=1043 second=171 amount=-1 +kerning first=1038 second=1035 amount=1 +kerning first=331 second=84 amount=-1 +kerning first=208 second=46 amount=-1 +kerning first=1066 second=1063 amount=-1 +kerning first=376 second=242 amount=-1 +kerning first=1027 second=1089 amount=-1 +kerning first=84 second=261 amount=-1 +kerning first=75 second=74 amount=1 +kerning first=932 second=8211 amount=-1 +kerning first=217 second=194 amount=-1 +kerning first=372 second=271 amount=-1 +kerning first=123 second=221 amount=1 +kerning first=84 second=114 amount=-1 +kerning first=8221 second=115 amount=-1 +kerning first=915 second=920 amount=-1 +kerning first=89 second=196 amount=-1 +kerning first=110 second=356 amount=-1 +kerning first=910 second=946 amount=-1 +kerning first=114 second=44 amount=-1 +kerning first=950 second=125 amount=1 +kerning first=123 second=84 amount=1 +kerning first=902 second=221 amount=-1 +kerning first=915 second=266 amount=-1 +kerning first=86 second=242 amount=-1 +kerning first=315 second=89 amount=-1 +kerning first=8220 second=74 amount=-1 +kerning first=319 second=376 amount=-1 +kerning first=932 second=225 amount=-1 +kerning first=372 second=932 amount=1 +kerning first=84 second=194 amount=-1 +kerning first=910 second=81 amount=-1 +kerning first=356 second=198 amount=-1 +kerning first=45 second=89 amount=-1 +kerning first=8221 second=196 amount=-1 +kerning first=939 second=210 amount=-1 +kerning first=321 second=356 amount=-1 +kerning first=1058 second=1109 amount=-1 +kerning first=1027 second=45 amount=-1 +kerning first=319 second=332 amount=-1 +kerning first=902 second=84 amount=-1 +kerning first=8249 second=933 amount=-1 +kerning first=933 second=948 amount=-1 +kerning first=1168 second=1113 amount=-1 +kerning first=319 second=85 amount=-1 +kerning first=932 second=87 amount=1 +kerning first=354 second=361 amount=-1 +kerning first=70 second=363 amount=-1 +kerning first=89 second=333 amount=-1 +kerning first=376 second=262 amount=-1 +kerning first=1034 second=1026 amount=-1 +kerning first=1059 second=1105 amount=-1 +kerning first=372 second=65 amount=-1 +kerning first=356 second=944 amount=-1 +kerning first=39 second=974 amount=-1 +kerning first=933 second=334 amount=-1 +kerning first=281 second=354 amount=-1 +kerning first=110 second=8217 amount=-1 +kerning first=226 second=356 amount=-1 +kerning first=356 second=255 amount=-1 +kerning first=913 second=8216 amount=-1 +kerning first=315 second=34 amount=-2 +kerning first=84 second=337 amount=-1 +kerning first=8221 second=333 amount=-1 +kerning first=356 second=261 amount=-1 +kerning first=932 second=305 amount=-1 +kerning first=358 second=367 amount=-1 +kerning first=354 second=973 amount=-1 +kerning first=356 second=114 amount=-1 +kerning first=354 second=251 amount=-1 +kerning first=89 second=233 amount=-1 +kerning first=370 second=196 amount=-1 +kerning first=87 second=913 amount=-1 +kerning first=8220 second=353 amount=-1 +kerning first=915 second=953 amount=-1 +kerning first=321 second=8217 amount=-2 +kerning first=8212 second=376 amount=-1 +kerning first=1168 second=1057 amount=-1 +kerning first=313 second=214 amount=-1 +kerning first=89 second=356 amount=1 +kerning first=8216 second=225 amount=-1 +kerning first=933 second=216 amount=-1 +kerning first=1043 second=1241 amount=-1 +kerning first=221 second=228 amount=-1 +kerning first=256 second=8216 amount=-1 +kerning first=354 second=110 amount=-1 +kerning first=87 second=258 amount=-1 +kerning first=319 second=358 amount=-1 +kerning first=939 second=971 amount=-1 +kerning first=932 second=273 amount=-1 +kerning first=39 second=923 amount=-1 +kerning first=358 second=972 amount=-1 +kerning first=242 second=358 amount=-1 +kerning first=957 second=8230 amount=-1 +kerning first=84 second=231 amount=-1 +kerning first=8217 second=287 amount=-1 +kerning first=356 second=194 amount=-1 +kerning first=8221 second=233 amount=-1 +kerning first=358 second=250 amount=-1 +kerning first=939 second=173 amount=-1 +kerning first=1043 second=1106 amount=1 +kerning first=932 second=277 amount=-1 +kerning first=226 second=8217 amount=-1 +kerning first=8216 second=1076 amount=-1 +kerning first=8221 second=356 amount=1 +kerning first=932 second=121 amount=-1 +kerning first=1041 second=1058 amount=-1 +kerning first=974 second=39 amount=-1 +kerning first=916 second=84 amount=-1 +kerning first=84 second=93 amount=1 +kerning first=376 second=332 amount=-1 +kerning first=358 second=109 amount=-1 +kerning first=929 second=74 amount=-1 +kerning first=372 second=99 amount=-1 +kerning first=910 second=196 amount=-2 +kerning first=271 second=8217 amount=1 +kerning first=91 second=86 amount=1 +kerning first=1038 second=1105 amount=-1 +kerning first=1027 second=8212 amount=-1 +kerning first=324 second=932 amount=-1 +kerning first=221 second=248 amount=-1 +kerning first=319 second=199 amount=-1 +kerning first=356 second=337 amount=-1 +kerning first=112 second=932 amount=-1 +kerning first=1058 second=1087 amount=-1 +kerning first=319 second=288 amount=-1 +kerning first=368 second=913 amount=-1 +kerning first=8212 second=358 amount=-1 +kerning first=1168 second=1091 amount=-1 +kerning first=1056 second=1040 amount=-1 +kerning first=354 second=328 amount=-1 +kerning first=89 second=291 amount=-1 +kerning first=76 second=8249 amount=-1 +kerning first=8216 second=273 amount=-1 +kerning first=933 second=197 amount=-2 +kerning first=958 second=93 amount=1 +kerning first=8221 second=8217 amount=-1 +kerning first=1059 second=1083 amount=-1 +kerning first=368 second=258 amount=-1 +kerning first=372 second=44 amount=-1 +kerning first=8216 second=277 amount=-1 +kerning first=160 second=372 amount=-1 +kerning first=259 second=84 amount=-1 +kerning first=933 second=284 amount=-1 +kerning first=221 second=279 amount=-1 +kerning first=356 second=231 amount=-1 +kerning first=1057 second=1035 amount=1 +kerning first=932 second=351 amount=-1 +kerning first=376 second=358 amount=1 +kerning first=1027 second=1102 amount=-1 +kerning first=1114 second=1090 amount=-1 +kerning first=84 second=285 amount=-1 +kerning first=8221 second=291 amount=-1 +kerning first=354 second=954 amount=-1 +kerning first=358 second=324 amount=-1 +kerning first=76 second=217 amount=-1 +kerning first=195 second=89 amount=-1 +kerning first=8211 second=221 amount=-1 +kerning first=376 second=267 amount=-1 +kerning first=356 second=93 amount=1 +kerning first=915 second=934 amount=-1 +kerning first=354 second=228 amount=-1 +kerning first=224 second=932 amount=-1 +kerning first=910 second=959 amount=-1 +kerning first=8220 second=225 amount=-1 +kerning first=219 second=198 amount=-1 +kerning first=76 second=334 amount=-1 +kerning first=1028 second=1098 amount=-1 +kerning first=1168 second=1035 amount=1 +kerning first=328 second=8221 amount=-1 +kerning first=196 second=39 amount=-1 +kerning first=8211 second=84 amount=-1 +kerning first=933 second=187 amount=-1 +kerning first=8217 second=246 amount=-1 +kerning first=936 second=916 amount=-1 +kerning first=86 second=358 amount=1 +kerning first=932 second=239 amount=-1 +kerning first=194 second=221 amount=-1 +kerning first=283 second=932 amount=-1 +kerning first=915 second=67 amount=-1 +kerning first=358 second=953 amount=-1 +kerning first=8220 second=1076 amount=-1 +kerning first=65 second=376 amount=-1 +kerning first=86 second=267 amount=-1 +kerning first=1027 second=58 amount=-1 +kerning first=358 second=226 amount=-1 +kerning first=319 second=362 amount=-1 +kerning first=91 second=932 amount=1 +kerning first=343 second=46 amount=-1 +kerning first=8217 second=105 amount=-1 +kerning first=376 second=199 amount=-1 +kerning first=933 second=963 amount=-1 +kerning first=1043 second=1084 amount=-1 +kerning first=84 second=308 amount=-1 +kerning first=317 second=262 amount=-1 +kerning first=932 second=100 amount=-1 +kerning first=194 second=84 amount=-1 +kerning first=89 second=363 amount=-1 +kerning first=76 second=216 amount=-1 +kerning first=195 second=34 amount=-1 +kerning first=376 second=288 amount=-1 +kerning first=1107 second=8211 amount=-1 +kerning first=354 second=248 amount=-1 +kerning first=70 second=230 amount=-1 +kerning first=74 second=125 amount=1 +kerning first=328 second=354 amount=-1 +kerning first=102 second=8230 amount=-1 +kerning first=8216 second=351 amount=-1 +kerning first=245 second=356 amount=-1 +kerning first=910 second=181 amount=-1 +kerning first=1038 second=1083 amount=-1 +kerning first=218 second=195 amount=-1 +kerning first=1035 second=1035 amount=-1 +kerning first=84 second=369 amount=-1 +kerning first=356 second=285 amount=-1 +kerning first=229 second=8221 amount=-1 +kerning first=915 second=968 amount=-1 +kerning first=321 second=268 amount=-1 +kerning first=89 second=245 amount=-1 +kerning first=1058 second=1066 amount=1 +kerning first=8220 second=273 amount=-1 +kerning first=1043 second=1028 amount=-1 +kerning first=219 second=194 amount=-1 +kerning first=45 second=1035 amount=-1 +kerning first=87 second=196 amount=-1 +kerning first=271 second=107 amount=1 +kerning first=354 second=279 amount=-1 +kerning first=932 second=45 amount=-1 +kerning first=8220 second=277 amount=-1 +kerning first=315 second=8220 amount=-2 +kerning first=84 second=942 amount=-1 +kerning first=1107 second=1076 amount=-1 +kerning first=329 second=358 amount=-1 +kerning first=34 second=260 amount=-1 +kerning first=84 second=242 amount=-1 +kerning first=313 second=89 amount=-1 +kerning first=65 second=358 amount=-1 +kerning first=8221 second=245 amount=-1 +kerning first=317 second=376 amount=-1 +kerning first=358 second=331 amount=-1 +kerning first=8216 second=100 amount=-1 +kerning first=245 second=8217 amount=-1 +kerning first=932 second=303 amount=-1 +kerning first=1027 second=1081 amount=-1 +kerning first=229 second=354 amount=-1 +kerning first=356 second=308 amount=-1 +kerning first=317 second=332 amount=-1 +kerning first=358 second=283 amount=-1 +kerning first=372 second=259 amount=-1 +kerning first=317 second=85 amount=-1 +kerning first=315 second=219 amount=-1 +kerning first=358 second=122 amount=-1 +kerning first=87 second=333 amount=-1 +kerning first=76 second=284 amount=-1 +kerning first=221 second=913 amount=-1 +kerning first=360 second=65 amount=-1 +kerning first=89 second=268 amount=-1 +kerning first=1058 second=173 amount=-1 +kerning first=279 second=354 amount=-1 +kerning first=931 second=334 amount=-1 +kerning first=81 second=8230 amount=-1 +kerning first=315 second=81 amount=-1 +kerning first=70 second=65 amount=-1 +kerning first=319 second=210 amount=-1 +kerning first=356 second=369 amount=-1 +kerning first=915 second=46 amount=-2 +kerning first=372 second=923 amount=-1 +kerning first=221 second=258 amount=-1 +kerning first=358 second=934 amount=-1 +kerning first=313 second=34 amount=-2 +kerning first=1058 second=1100 amount=-1 +kerning first=271 second=320 amount=1 +kerning first=8217 second=84 amount=1 +kerning first=321 second=86 amount=-1 +kerning first=87 second=233 amount=-1 +kerning first=1168 second=1105 amount=-1 +kerning first=85 second=913 amount=-1 +kerning first=368 second=196 amount=-1 +kerning first=1169 second=173 amount=-1 +kerning first=933 second=212 amount=-1 +kerning first=8220 second=351 amount=-1 +kerning first=87 second=356 amount=1 +kerning first=931 second=216 amount=-1 +kerning first=356 second=942 amount=-1 +kerning first=293 second=84 amount=-1 +kerning first=356 second=242 amount=-1 +kerning first=85 second=258 amount=-1 +kerning first=317 second=358 amount=-1 +kerning first=244 second=358 amount=-1 +kerning first=1027 second=1116 amount=-1 +kerning first=173 second=932 amount=-1 +kerning first=932 second=8212 amount=-1 +kerning first=354 second=969 amount=-1 +kerning first=358 second=349 amount=-1 +kerning first=935 second=934 amount=-1 +kerning first=915 second=945 amount=-1 +kerning first=354 second=241 amount=-1 +kerning first=8218 second=356 amount=-1 +kerning first=8212 second=910 amount=-1 +kerning first=310 second=308 amount=1 +kerning first=910 second=943 amount=-1 +kerning first=973 second=39 amount=-1 +kerning first=76 second=364 amount=-1 +kerning first=76 second=8216 amount=-2 +kerning first=80 second=46 amount=-2 +kerning first=1046 second=1051 amount=1 +kerning first=932 second=912 amount=-1 +kerning first=260 second=221 amount=-1 +kerning first=8220 second=100 amount=-1 +kerning first=939 second=962 amount=-1 +kerning first=932 second=253 amount=-1 +kerning first=936 second=195 amount=-1 +kerning first=319 second=173 amount=-1 +kerning first=358 second=968 amount=-1 +kerning first=8217 second=265 amount=-1 +kerning first=317 second=199 amount=-1 +kerning first=86 second=301 amount=1 +kerning first=8212 second=1066 amount=-1 +kerning first=358 second=236 amount=-1 +kerning first=110 second=932 amount=-1 +kerning first=923 second=936 amount=-1 +kerning first=932 second=257 amount=-1 +kerning first=366 second=256 amount=-1 +kerning first=372 second=229 amount=-1 +kerning first=260 second=84 amount=-1 +kerning first=221 second=81 amount=-1 +kerning first=376 second=210 amount=-1 +kerning first=933 second=972 amount=-1 +kerning first=1027 second=1060 amount=-1 +kerning first=1043 second=1097 amount=-1 +kerning first=317 second=288 amount=-1 +kerning first=354 second=913 amount=-1 +kerning first=932 second=113 amount=-1 +kerning first=39 second=260 amount=-1 +kerning first=345 second=8230 amount=-1 +kerning first=89 second=230 amount=-1 +kerning first=358 second=101 amount=-1 +kerning first=121 second=8230 amount=-1 +kerning first=915 second=198 amount=-2 +kerning first=321 second=932 amount=-1 +kerning first=354 second=258 amount=-1 +kerning first=8230 second=939 amount=-1 +kerning first=931 second=284 amount=-1 +kerning first=8217 second=195 amount=-1 +kerning first=70 second=44 amount=-2 +kerning first=84 second=380 amount=-1 +kerning first=910 second=268 amount=-1 +kerning first=932 second=193 amount=-1 +kerning first=195 second=8220 amount=-1 +kerning first=936 second=8230 amount=-1 +kerning first=915 second=944 amount=-1 +kerning first=354 second=307 amount=-1 +kerning first=1058 second=1079 amount=-1 +kerning first=192 second=89 amount=-1 +kerning first=197 second=376 amount=-1 +kerning first=933 second=920 amount=-1 +kerning first=1168 second=1083 amount=-1 +kerning first=226 second=932 amount=-1 +kerning first=939 second=256 amount=-2 +kerning first=89 second=271 amount=-1 +kerning first=34 second=197 amount=-1 +kerning first=358 second=46 amount=-1 +kerning first=193 second=39 amount=-1 +kerning first=933 second=266 amount=-1 +kerning first=8216 second=257 amount=-1 +kerning first=160 second=354 amount=-1 +kerning first=84 second=358 amount=1 +kerning first=8217 second=345 amount=-1 +kerning first=1043 second=8211 amount=-1 +kerning first=111 second=8221 amount=-1 +kerning first=950 second=41 amount=1 +kerning first=8216 second=113 amount=-1 +kerning first=221 second=115 amount=-1 +kerning first=932 second=335 amount=-1 +kerning first=376 second=252 amount=-1 +kerning first=8217 second=8230 amount=-2 +kerning first=1027 second=1094 amount=-1 +kerning first=84 second=267 amount=-1 +kerning first=376 second=173 amount=-1 +kerning first=8221 second=271 amount=-1 +kerning first=317 second=362 amount=-1 +kerning first=89 second=932 amount=1 +kerning first=354 second=946 amount=-1 +kerning first=76 second=212 amount=-1 +kerning first=358 second=297 amount=-1 +kerning first=341 second=46 amount=-1 +kerning first=80 second=198 amount=-1 +kerning first=372 second=281 amount=-1 +kerning first=84 second=119 amount=-1 +kerning first=923 second=372 amount=-1 +kerning first=910 second=951 amount=-1 +kerning first=1091 second=8230 amount=-1 +kerning first=372 second=125 amount=1 +kerning first=192 second=34 amount=-1 +kerning first=941 second=912 amount=1 +kerning first=376 second=111 amount=-1 +kerning first=915 second=194 amount=-2 +kerning first=1028 second=1090 amount=-1 +kerning first=357 second=8217 amount=1 +kerning first=315 second=356 amount=-1 +kerning first=8216 second=193 amount=-1 +kerning first=123 second=89 amount=1 +kerning first=221 second=196 amount=-1 +kerning first=246 second=356 amount=-1 +kerning first=8217 second=232 amount=-1 +kerning first=89 second=65 amount=-1 +kerning first=45 second=356 amount=-1 +kerning first=356 second=380 amount=-1 +kerning first=8221 second=932 amount=1 +kerning first=111 second=354 amount=-1 +kerning first=932 second=227 amount=-1 +kerning first=1107 second=45 amount=-1 +kerning first=915 second=59 amount=-1 +kerning first=358 second=945 amount=-1 +kerning first=1033 second=1035 amount=-1 +kerning first=321 second=370 amount=-1 +kerning first=1058 second=1114 amount=-1 +kerning first=1043 second=1076 amount=-2 +kerning first=902 second=89 amount=-1 +kerning first=197 second=358 amount=-1 +kerning first=228 second=8221 amount=-1 +kerning first=933 second=953 amount=-1 +kerning first=86 second=111 amount=-1 +kerning first=1168 second=1119 amount=-1 +kerning first=87 second=245 amount=-1 +kerning first=89 second=347 amount=-1 +kerning first=8221 second=65 amount=-1 +kerning first=85 second=196 amount=-1 +kerning first=8216 second=335 amount=-1 +kerning first=221 second=333 amount=-1 +kerning first=313 second=8220 amount=-2 +kerning first=356 second=358 amount=1 +kerning first=1027 second=8250 amount=-1 +kerning first=295 second=358 amount=-1 +kerning first=1114 second=1118 amount=-1 +kerning first=173 second=939 amount=-1 +kerning first=315 second=8217 amount=-2 +kerning first=84 second=343 amount=-1 +kerning first=8221 second=347 amount=-1 +kerning first=356 second=267 amount=-1 +kerning first=213 second=8230 amount=-1 +kerning first=246 second=8217 amount=-1 +kerning first=80 second=194 amount=-1 +kerning first=356 second=119 amount=-1 +kerning first=228 second=354 amount=-1 +kerning first=354 second=382 amount=-1 +kerning first=1058 second=1058 amount=1 +kerning first=358 second=198 amount=-1 +kerning first=70 second=249 amount=-1 +kerning first=1090 second=46 amount=-1 +kerning first=902 second=34 amount=-1 +kerning first=313 second=219 amount=-1 +kerning first=70 second=259 amount=-1 +kerning first=8216 second=227 amount=-1 +kerning first=8220 second=257 amount=-1 +kerning first=221 second=233 amount=-1 +kerning first=220 second=913 amount=-1 +kerning first=354 second=115 amount=-1 +kerning first=89 second=99 amount=-1 +kerning first=8222 second=372 amount=-1 +kerning first=370 second=65 amount=-1 +kerning first=8220 second=113 amount=-1 +kerning first=84 second=965 amount=-1 +kerning first=366 second=192 amount=-1 +kerning first=277 second=354 amount=-1 +kerning first=358 second=944 amount=-1 +kerning first=79 second=8230 amount=-1 +kerning first=221 second=356 amount=1 +kerning first=84 second=237 amount=-1 +kerning first=8221 second=238 amount=-1 +kerning first=313 second=81 amount=-1 +kerning first=317 second=210 amount=-1 +kerning first=40 second=1026 amount=1 +kerning first=39 second=197 amount=-1 +kerning first=358 second=255 amount=-1 +kerning first=372 second=244 amount=-1 +kerning first=932 second=287 amount=-1 +kerning first=360 second=923 amount=-1 +kerning first=220 second=258 amount=-1 +kerning first=76 second=920 amount=-1 +kerning first=376 second=224 amount=-1 +kerning first=1043 second=1111 amount=-1 +kerning first=232 second=84 amount=-1 +kerning first=1041 second=1063 amount=-1 +kerning first=70 second=923 amount=-1 +kerning first=358 second=261 amount=-1 +kerning first=8221 second=99 amount=-1 +kerning first=1107 second=8212 amount=-1 +kerning first=1034 second=1066 amount=-1 +kerning first=354 second=196 amount=-1 +kerning first=358 second=114 amount=-1 +kerning first=8220 second=193 amount=-1 +kerning first=931 second=212 amount=-1 +kerning first=76 second=266 amount=-1 +kerning first=187 second=354 amount=-1 +kerning first=913 second=39 amount=-1 +kerning first=289 second=84 amount=-1 +kerning first=321 second=213 amount=-1 +kerning first=86 second=224 amount=-1 +kerning first=89 second=44 amount=-2 +kerning first=210 second=46 amount=-1 +kerning first=356 second=343 amount=-1 +kerning first=939 second=927 amount=-1 +kerning first=98 second=84 amount=-1 +kerning first=241 second=358 amount=-1 +kerning first=102 second=34 amount=1 +kerning first=910 second=65 amount=-2 +kerning first=939 second=192 amount=-2 +kerning first=1058 second=1092 amount=-1 +kerning first=358 second=194 amount=-1 +kerning first=376 second=339 amount=-1 +kerning first=933 second=934 amount=-1 +kerning first=912 second=946 amount=1 +kerning first=245 second=932 amount=-1 +kerning first=1168 second=1096 amount=-1 +kerning first=939 second=286 amount=-1 +kerning first=354 second=333 amount=-1 +kerning first=8220 second=335 amount=-1 +kerning first=916 second=34 amount=-1 +kerning first=372 second=260 amount=-1 +kerning first=256 second=39 amount=-1 +kerning first=8221 second=44 amount=-2 +kerning first=356 second=965 amount=-1 +kerning first=929 second=912 amount=1 +kerning first=8216 second=287 amount=-1 +kerning first=103 second=358 amount=-1 +kerning first=258 second=221 amount=-1 +kerning first=221 second=291 amount=-1 +kerning first=356 second=237 amount=-1 +kerning first=933 second=67 amount=-1 +kerning first=317 second=173 amount=-1 +kerning first=932 second=365 amount=-1 +kerning first=1027 second=1108 amount=-1 +kerning first=1114 second=1095 amount=-1 +kerning first=195 second=356 amount=-1 +kerning first=86 second=339 amount=-1 +kerning first=84 second=301 amount=-1 +kerning first=8221 second=299 amount=-1 +kerning first=362 second=256 amount=-1 +kerning first=354 second=959 amount=-1 +kerning first=358 second=337 amount=-1 +kerning first=971 second=34 amount=-1 +kerning first=258 second=84 amount=-1 +kerning first=376 second=275 amount=-1 +kerning first=354 second=233 amount=-1 +kerning first=89 second=213 amount=-1 +kerning first=70 second=229 amount=-1 +kerning first=8220 second=227 amount=-1 +kerning first=910 second=966 amount=-1 +kerning first=8218 second=86 amount=-1 +kerning first=87 second=230 amount=-1 +kerning first=354 second=356 amount=1 +kerning first=119 second=8230 amount=-1 +kerning first=8211 second=89 amount=-1 +kerning first=932 second=941 amount=-1 +kerning first=1059 second=44 amount=-2 +kerning first=1059 second=1032 amount=-1 +kerning first=74 second=41 amount=1 +kerning first=939 second=961 amount=-1 +kerning first=952 second=46 amount=-1 +kerning first=932 second=246 amount=-1 +kerning first=1058 second=171 amount=-1 +kerning first=68 second=44 amount=-1 +kerning first=86 second=275 amount=-1 +kerning first=8212 second=1058 amount=-1 +kerning first=358 second=231 amount=-1 +kerning first=929 second=193 amount=-1 +kerning first=319 second=372 amount=-1 +kerning first=192 second=8220 amount=-1 +kerning first=934 second=8230 amount=-1 +kerning first=8217 second=110 amount=-1 +kerning first=1043 second=1089 amount=-1 +kerning first=933 second=968 amount=-1 +kerning first=194 second=89 amount=-1 +kerning first=932 second=105 amount=-1 +kerning first=8249 second=221 amount=-1 +kerning first=196 second=376 amount=-1 +kerning first=195 second=8217 amount=-1 +kerning first=931 second=920 amount=-1 +kerning first=354 second=181 amount=-1 +kerning first=358 second=93 amount=1 +kerning first=87 second=271 amount=-1 +kerning first=1100 second=8221 amount=-1 +kerning first=40 second=106 amount=1 +kerning first=221 second=363 amount=-1 +kerning first=257 second=358 amount=-1 +kerning first=40 second=1095 amount=-1 +kerning first=315 second=268 amount=-1 +kerning first=8249 second=84 amount=-1 +kerning first=1027 second=8230 amount=-1 +kerning first=931 second=266 amount=-1 +kerning first=932 second=916 amount=-1 +kerning first=354 second=8217 amount=1 +kerning first=109 second=8221 amount=-1 +kerning first=123 second=1035 amount=1 +kerning first=356 second=301 amount=-1 +kerning first=915 second=942 amount=-1 +kerning first=910 second=44 amount=-2 +kerning first=1043 second=45 amount=-1 +kerning first=89 second=249 amount=-1 +kerning first=87 second=932 amount=1 +kerning first=955 second=34 amount=-1 +kerning first=8216 second=941 amount=-1 +kerning first=80 second=308 amount=-1 +kerning first=123 second=309 amount=1 +kerning first=1168 second=1075 amount=-1 +kerning first=923 second=8221 amount=-1 +kerning first=354 second=291 amount=-1 +kerning first=194 second=34 amount=-1 +kerning first=118 second=46 amount=-1 +kerning first=89 second=259 amount=-1 +kerning first=8220 second=287 amount=-1 +kerning first=8216 second=246 amount=-1 +kerning first=221 second=245 amount=-1 +kerning first=1075 second=173 amount=-1 +kerning first=84 second=971 amount=-1 +kerning first=313 second=356 amount=-1 +kerning first=220 second=196 amount=-1 +kerning first=243 second=356 amount=-1 +kerning first=1038 second=44 amount=-2 +kerning first=84 second=252 amount=-1 +kerning first=87 second=65 amount=-1 +kerning first=8217 second=328 amount=-1 +kerning first=8218 second=932 amount=-1 +kerning first=1038 second=1032 amount=-1 +kerning first=109 second=354 amount=-1 +kerning first=84 second=173 amount=-1 +kerning first=933 second=46 amount=-2 +kerning first=8221 second=160 amount=-1 +kerning first=160 second=87 amount=-1 +kerning first=902 second=8220 amount=-1 +kerning first=376 second=243 amount=-1 +kerning first=1027 second=1086 amount=-1 +kerning first=319 second=171 amount=-1 +kerning first=932 second=8250 amount=-1 +kerning first=89 second=923 amount=-1 +kerning first=358 second=285 amount=-1 +kerning first=196 second=358 amount=-1 +kerning first=372 second=269 amount=-1 +kerning first=225 second=8221 amount=-1 +kerning first=84 second=111 amount=-1 +kerning first=8221 second=112 amount=-1 +kerning first=923 second=354 amount=-1 +kerning first=376 second=103 amount=-1 +kerning first=8216 second=916 amount=-1 +kerning first=104 second=356 amount=-1 +kerning first=910 second=213 amount=-1 +kerning first=1058 second=1241 amount=-1 +kerning first=76 second=67 amount=-1 +kerning first=337 second=84 amount=-1 +kerning first=932 second=949 amount=-1 +kerning first=915 second=262 amount=-1 +kerning first=86 second=243 amount=-1 +kerning first=315 second=86 amount=-1 +kerning first=319 second=220 amount=-1 +kerning first=8221 second=923 amount=-1 +kerning first=8204 second=8216 amount=-1 +kerning first=65 second=936 amount=-1 +kerning first=1033 second=8217 amount=-1 +kerning first=221 second=268 amount=-1 +kerning first=313 second=8217 amount=-2 +kerning first=939 second=211 amount=-1 +kerning first=1058 second=1106 amount=1 +kerning first=214 second=8230 amount=-1 +kerning first=243 second=8217 amount=-1 +kerning first=372 second=197 amount=-1 +kerning first=933 second=945 amount=-1 +kerning first=40 second=376 amount=1 +kerning first=225 second=354 amount=-1 +kerning first=932 second=84 amount=1 +kerning first=354 second=363 amount=-1 +kerning first=358 second=308 amount=-1 +kerning first=376 second=256 amount=-1 +kerning first=248 second=84 amount=-1 +kerning first=356 second=971 amount=-1 +kerning first=218 second=913 amount=-1 +kerning first=102 second=8220 amount=1 +kerning first=1028 second=1026 amount=1 +kerning first=87 second=99 amount=-1 +kerning first=1043 second=8212 amount=-1 +kerning first=356 second=252 amount=-1 +kerning first=368 second=65 amount=-1 +kerning first=362 second=192 amount=-1 +kerning first=356 second=173 amount=-1 +kerning first=932 second=378 amount=-1 +kerning first=104 second=8217 amount=-1 +kerning first=8217 second=248 amount=-1 +kerning first=8221 second=326 amount=-1 +kerning first=358 second=369 amount=-1 +kerning first=370 second=923 amount=-1 +kerning first=218 second=258 amount=-1 +kerning first=354 second=943 amount=-1 +kerning first=8220 second=941 amount=-1 +kerning first=356 second=111 amount=-1 +kerning first=234 second=84 amount=-1 +kerning first=354 second=245 amount=-1 +kerning first=86 second=256 amount=-1 +kerning first=89 second=229 amount=-1 +kerning first=8220 second=246 amount=-1 +kerning first=376 second=171 amount=-1 +kerning first=76 second=360 amount=-1 +kerning first=8216 second=949 amount=-1 +kerning first=1168 second=1054 amount=-1 +kerning first=261 second=356 amount=-1 +kerning first=933 second=198 amount=-2 +kerning first=915 second=332 amount=-1 +kerning first=173 second=1059 amount=-1 +kerning first=8222 second=354 amount=-1 +kerning first=939 second=970 amount=-1 +kerning first=285 second=84 amount=-1 +kerning first=358 second=942 amount=-1 +kerning first=84 second=224 amount=-1 +kerning first=87 second=44 amount=-1 +kerning first=8217 second=279 amount=-1 +kerning first=212 second=46 amount=-1 +kerning first=358 second=242 amount=-1 +kerning first=8216 second=84 amount=1 +kerning first=372 second=235 amount=-1 +kerning first=932 second=265 amount=-1 +kerning first=933 second=944 amount=-1 +kerning first=1043 second=1102 amount=-1 +kerning first=260 second=89 amount=-1 +kerning first=40 second=358 amount=1 +kerning first=65 second=372 amount=-1 +kerning first=932 second=118 amount=-1 +kerning first=315 second=932 amount=-1 +kerning first=8220 second=916 amount=-1 +kerning first=1050 second=1095 amount=-1 +kerning first=246 second=932 amount=-1 +kerning first=1034 second=1058 amount=-1 +kerning first=910 second=923 amount=-2 +kerning first=45 second=932 amount=-1 +kerning first=360 second=260 amount=-1 +kerning first=70 second=260 amount=-1 +kerning first=319 second=927 amount=-1 +kerning first=221 second=230 amount=-1 +kerning first=101 second=358 amount=-1 +kerning first=261 second=8217 amount=-1 +kerning first=8211 second=1035 amount=-1 +kerning first=958 second=955 amount=1 +kerning first=272 second=8230 amount=-1 +kerning first=931 second=67 amount=-1 +kerning first=932 second=195 amount=-1 +kerning first=192 second=356 amount=-1 +kerning first=84 second=339 amount=-1 +kerning first=1043 second=58 amount=-1 +kerning first=1058 second=1084 amount=-1 +kerning first=364 second=256 amount=-1 +kerning first=319 second=286 amount=-1 +kerning first=260 second=34 amount=-1 +kerning first=1168 second=1088 amount=-1 +kerning first=939 second=264 amount=-1 +kerning first=89 second=281 amount=-1 +kerning first=76 second=39 amount=-2 +kerning first=933 second=194 amount=-2 +kerning first=1113 second=1091 amount=-1 +kerning first=89 second=125 amount=1 +kerning first=372 second=41 amount=1 +kerning first=331 second=356 amount=-1 +kerning first=8216 second=265 amount=-1 +kerning first=221 second=271 amount=-1 +kerning first=84 second=312 amount=-1 +kerning first=356 second=224 amount=-1 +kerning first=933 second=59 amount=-1 +kerning first=932 second=345 amount=-1 +kerning first=1027 second=1099 amount=-1 +kerning first=84 second=275 amount=-1 +kerning first=319 second=8221 amount=-2 +kerning first=8221 second=281 amount=-1 +kerning first=317 second=372 amount=-1 +kerning first=932 second=8230 amount=-1 +kerning first=194 second=8220 amount=-1 +kerning first=354 second=951 amount=-1 +kerning first=76 second=218 amount=-1 +kerning first=195 second=86 amount=-1 +kerning first=242 second=8221 amount=-1 +kerning first=8220 second=949 amount=-1 +kerning first=376 second=263 amount=-1 +kerning first=939 second=8211 amount=-1 +kerning first=46 second=8221 amount=-2 +kerning first=1058 second=1028 amount=-1 +kerning first=193 second=376 amount=-1 +kerning first=192 second=8217 amount=-1 +kerning first=915 second=199 amount=-1 +kerning first=1168 second=44 amount=-1 +kerning first=1028 second=1095 amount=-1 +kerning first=8250 second=1026 amount=-1 +kerning first=221 second=932 amount=1 +kerning first=123 second=356 amount=1 +kerning first=1168 second=1032 amount=-1 +kerning first=315 second=370 amount=-1 +kerning first=8216 second=195 amount=-1 +kerning first=1098 second=8221 amount=-1 +kerning first=8217 second=241 amount=-1 +kerning first=915 second=288 amount=-1 +kerning first=936 second=913 amount=-1 +kerning first=354 second=86 amount=1 +kerning first=173 second=1038 amount=-1 +kerning first=8220 second=84 amount=1 +kerning first=313 second=268 amount=-1 +kerning first=932 second=232 amount=-1 +kerning first=929 second=916 amount=-1 +kerning first=902 second=356 amount=-1 +kerning first=376 second=927 amount=-1 +kerning first=356 second=339 amount=-1 +kerning first=86 second=263 amount=-1 +kerning first=331 second=8217 amount=-1 +kerning first=8222 second=1063 amount=-1 +kerning first=319 second=354 amount=-1 +kerning first=221 second=65 amount=-1 +kerning first=1043 second=1081 amount=-1 +kerning first=376 second=192 amount=-1 +kerning first=936 second=258 amount=-1 +kerning first=242 second=354 amount=-1 +kerning first=1027 second=1044 amount=-1 +kerning first=932 second=97 amount=-1 +kerning first=1065 second=1112 amount=1 +kerning first=376 second=286 amount=-1 +kerning first=354 second=230 amount=-1 +kerning first=87 second=259 amount=-1 +kerning first=1059 second=1115 amount=1 +kerning first=306 second=125 amount=1 +kerning first=221 second=347 amount=-1 +kerning first=8217 second=913 amount=-1 +kerning first=356 second=312 amount=-1 +kerning first=8216 second=8230 amount=-2 +kerning first=218 second=196 amount=-1 +kerning first=85 second=65 amount=-1 +kerning first=86 second=192 amount=-1 +kerning first=356 second=275 amount=-1 +kerning first=358 second=380 amount=-1 +kerning first=8217 second=258 amount=-1 +kerning first=197 second=936 amount=-1 +kerning first=317 second=171 amount=-1 +kerning first=915 second=965 amount=-1 +kerning first=89 second=244 amount=-1 +kerning first=87 second=923 amount=-1 +kerning first=193 second=358 amount=-1 +kerning first=902 second=8217 amount=-1 +kerning first=271 second=104 amount=1 +kerning first=354 second=271 amount=-1 +kerning first=8216 second=232 amount=-1 +kerning first=8220 second=265 amount=-1 +kerning first=8217 second=307 amount=-1 +kerning first=195 second=932 amount=-1 +kerning first=354 second=120 amount=-1 +kerning first=8212 second=354 amount=-1 +kerning first=70 second=117 amount=-1 +kerning first=84 second=962 amount=-1 +kerning first=326 second=84 amount=-1 +kerning first=84 second=243 amount=-1 +kerning first=313 second=86 amount=-1 +kerning first=8221 second=244 amount=-1 +kerning first=317 second=220 amount=-1 +kerning first=358 second=358 amount=1 +kerning first=8216 second=97 amount=-1 +kerning first=34 second=46 amount=-2 +kerning first=1043 second=1116 amount=-1 +kerning first=221 second=99 amount=-1 +kerning first=376 second=234 amount=-1 +kerning first=1027 second=1078 amount=-1 +kerning first=321 second=8249 amount=-1 +kerning first=916 second=356 amount=-1 +kerning first=84 second=372 amount=1 +kerning first=211 second=8230 amount=-1 +kerning first=354 second=932 amount=1 +kerning first=360 second=197 amount=-1 +kerning first=358 second=267 amount=-1 +kerning first=920 second=44 amount=-1 +kerning first=84 second=103 amount=-1 +kerning first=376 second=354 amount=1 +kerning first=315 second=213 amount=-1 +kerning first=70 second=197 amount=-1 +kerning first=358 second=119 amount=-1 +kerning first=8220 second=195 amount=-1 +kerning first=45 second=939 amount=-1 +kerning first=217 second=256 amount=-1 +kerning first=1044 second=1112 amount=1 +kerning first=923 second=87 amount=-1 +kerning first=1038 second=1115 amount=1 +kerning first=89 second=260 amount=-1 +kerning first=1026 second=1026 amount=-1 +kerning first=321 second=217 amount=-1 +kerning first=354 second=65 amount=-1 +kerning first=86 second=234 amount=-1 +kerning first=364 second=192 amount=-1 +kerning first=319 second=211 amount=-1 +kerning first=102 second=8217 amount=1 +kerning first=270 second=44 amount=-1 +kerning first=321 second=334 amount=-1 +kerning first=86 second=354 amount=1 +kerning first=1058 second=1097 amount=-1 +kerning first=271 second=314 amount=1 +kerning first=368 second=923 amount=-1 +kerning first=221 second=44 amount=-2 +kerning first=1043 second=1060 amount=-1 +kerning first=8230 second=8216 amount=-2 +kerning first=1168 second=1101 amount=-1 +kerning first=84 second=256 amount=-1 +kerning first=87 second=229 amount=-1 +kerning first=8221 second=260 amount=-1 +kerning first=354 second=347 amount=-1 +kerning first=373 second=8230 amount=-1 +kerning first=913 second=376 amount=-1 +kerning first=916 second=8217 amount=-1 +kerning first=197 second=372 amount=-1 +kerning first=259 second=356 amount=-1 +kerning first=89 second=8249 amount=-1 +kerning first=8220 second=8230 amount=-2 +kerning first=356 second=962 amount=-1 +kerning first=934 second=935 amount=-1 +kerning first=356 second=243 amount=-1 +kerning first=40 second=1066 amount=1 +kerning first=281 second=84 amount=-1 +kerning first=932 second=361 amount=-1 +kerning first=1027 second=1113 amount=-1 +kerning first=260 second=8220 amount=-1 +kerning first=321 second=216 amount=-1 +kerning first=356 second=372 amount=1 +kerning first=354 second=966 amount=-1 +kerning first=329 second=8221 amount=-1 +kerning first=358 second=343 amount=-1 +kerning first=258 second=89 amount=-1 +kerning first=84 second=171 amount=-1 +kerning first=256 second=376 amount=-1 +kerning first=376 second=289 amount=-1 +kerning first=65 second=8221 amount=-1 +kerning first=356 second=103 amount=-1 +kerning first=354 second=238 amount=-1 +kerning first=910 second=940 amount=-1 +kerning first=8220 second=232 amount=-1 +kerning first=313 second=932 amount=-1 +kerning first=915 second=210 amount=-1 +kerning first=8211 second=356 amount=-1 +kerning first=243 second=932 amount=-1 +kerning first=89 second=334 amount=-1 +kerning first=370 second=260 amount=-1 +kerning first=34 second=198 amount=-1 +kerning first=221 second=213 amount=-1 +kerning first=932 second=973 amount=-1 +kerning first=354 second=99 amount=-1 +kerning first=8220 second=97 amount=-1 +kerning first=1040 second=1051 amount=1 +kerning first=317 second=927 amount=-1 +kerning first=932 second=251 amount=-1 +kerning first=332 second=8230 amount=-1 +kerning first=936 second=196 amount=-1 +kerning first=358 second=965 amount=-1 +kerning first=259 second=8217 amount=-1 +kerning first=8222 second=87 amount=-1 +kerning first=1058 second=8211 amount=-1 +kerning first=255 second=8230 amount=-1 +kerning first=929 second=195 amount=-1 +kerning first=358 second=237 amount=-1 +kerning first=372 second=226 amount=-1 +kerning first=923 second=933 amount=-2 +kerning first=194 second=356 amount=-1 +kerning first=329 second=354 amount=-1 +kerning first=376 second=211 amount=-1 +kerning first=8217 second=115 amount=-1 +kerning first=933 second=942 amount=-1 +kerning first=1027 second=1057 amount=-1 +kerning first=1043 second=1094 amount=-1 +kerning first=104 second=932 amount=-1 +kerning first=65 second=354 amount=-1 +kerning first=356 second=256 amount=-1 +kerning first=317 second=286 amount=-1 +kerning first=932 second=110 amount=-1 +kerning first=913 second=358 amount=-1 +kerning first=258 second=34 amount=-1 +kerning first=1107 second=8230 amount=-1 +kerning first=89 second=216 amount=-1 +kerning first=39 second=46 amount=-2 +kerning first=87 second=281 amount=-1 +kerning first=376 second=74 amount=-1 +kerning first=1169 second=8211 amount=-1 +kerning first=87 second=125 amount=1 +kerning first=950 second=93 amount=1 +kerning first=8249 second=89 amount=-1 +kerning first=8250 second=376 amount=-1 +kerning first=8217 second=196 amount=-1 +kerning first=354 second=44 amount=-1 +kerning first=910 second=260 amount=-2 +kerning first=1034 second=8221 amount=-1 +kerning first=256 second=358 amount=-1 +kerning first=915 second=971 amount=-1 +kerning first=356 second=171 amount=-1 +kerning first=317 second=8221 amount=-2 +kerning first=321 second=284 amount=-1 +kerning first=376 second=371 amount=-1 +kerning first=1058 second=1076 amount=-2 +kerning first=929 second=8230 amount=-2 +kerning first=319 second=264 amount=-1 +kerning first=192 second=86 amount=-1 +kerning first=244 second=8221 amount=-1 +kerning first=955 second=8217 amount=-1 +kerning first=44 second=8221 amount=-2 +kerning first=1168 second=1080 amount=-1 +kerning first=915 second=173 amount=-1 +kerning first=354 second=299 amount=-1 +kerning first=194 second=8217 amount=-1 +kerning first=89 second=269 amount=-1 +kerning first=1118 second=44 amount=-1 +kerning first=34 second=194 amount=-1 +kerning first=221 second=249 amount=-1 +kerning first=195 second=939 amount=-2 +kerning first=939 second=45 amount=-1 +kerning first=89 second=117 amount=-1 +kerning first=1059 second=1072 amount=-1 +kerning first=313 second=370 amount=-1 +kerning first=336 second=46 amount=-1 +kerning first=933 second=262 amount=-1 +kerning first=221 second=259 amount=-1 +kerning first=253 second=46 amount=-1 +kerning first=8217 second=333 amount=-1 +kerning first=1043 second=8250 amount=-1 +kerning first=1169 second=1076 amount=-1 +kerning first=932 second=328 amount=-1 +kerning first=376 second=353 amount=-1 +kerning first=1027 second=1091 amount=-1 +kerning first=84 second=263 amount=-1 +kerning first=319 second=8211 amount=-1 +kerning first=261 second=932 amount=-1 +kerning first=317 second=354 amount=-1 +kerning first=220 second=65 amount=-1 +kerning first=8221 second=269 amount=-1 +kerning first=358 second=301 amount=-1 +kerning first=217 second=192 amount=-1 +kerning first=372 second=283 amount=-1 +kerning first=244 second=354 amount=-1 +kerning first=89 second=197 amount=-1 +kerning first=910 second=948 amount=-1 +kerning first=221 second=923 amount=-1 +kerning first=114 second=46 amount=-1 +kerning first=1113 second=8217 amount=-1 +kerning first=89 second=284 amount=-1 +kerning first=8250 second=358 amount=-1 +kerning first=123 second=86 amount=1 +kerning first=932 second=954 amount=-1 +kerning first=8217 second=233 amount=-1 +kerning first=910 second=334 amount=-1 +kerning first=932 second=228 amount=-1 +kerning first=84 second=192 amount=-1 +kerning first=8217 second=356 amount=1 +kerning first=8221 second=197 amount=-1 +kerning first=321 second=364 amount=-1 +kerning first=1058 second=1111 amount=-1 +kerning first=39 second=198 amount=-1 +kerning first=902 second=86 amount=-1 +kerning first=196 second=936 amount=-1 +kerning first=1027 second=1035 amount=1 +kerning first=321 second=8216 amount=-2 +kerning first=1168 second=1115 amount=1 +kerning first=87 second=244 amount=-1 +kerning first=319 second=87 amount=-1 +kerning first=85 second=923 amount=-1 +kerning first=354 second=373 amount=-1 +kerning first=70 second=367 amount=-1 +kerning first=376 second=264 amount=-1 +kerning first=293 second=356 amount=-1 +kerning first=939 second=79 amount=-1 +kerning first=933 second=332 amount=-1 +kerning first=192 second=932 amount=-1 +kerning first=910 second=216 amount=-1 +kerning first=1038 second=1072 amount=-1 +kerning first=328 second=84 amount=-1 +kerning first=8221 second=341 amount=-1 +kerning first=356 second=263 amount=-1 +kerning first=932 second=248 amount=-1 +kerning first=354 second=974 amount=-1 +kerning first=84 second=8221 amount=1 +kerning first=354 second=249 amount=-1 +kerning first=89 second=235 amount=-1 +kerning first=939 second=8212 amount=-1 +kerning first=70 second=250 amount=-1 +kerning first=370 second=197 amount=-1 +kerning first=376 second=8211 amount=-1 +kerning first=8217 second=8217 amount=-1 +kerning first=331 second=932 amount=-1 +kerning first=160 second=902 amount=-1 +kerning first=1168 second=1059 amount=1 +kerning first=313 second=213 amount=-1 +kerning first=354 second=259 amount=-1 +kerning first=8216 second=228 amount=-1 +kerning first=333 second=358 amount=-1 +kerning first=219 second=256 amount=-1 +kerning first=221 second=229 amount=-1 +kerning first=354 second=112 amount=-1 +kerning first=87 second=260 amount=-1 +kerning first=84 second=961 amount=-1 +kerning first=366 second=193 amount=-1 +kerning first=939 second=912 amount=-1 +kerning first=358 second=971 amount=-1 +kerning first=293 second=8217 amount=-1 +kerning first=84 second=234 amount=-1 +kerning first=8217 second=291 amount=-1 +kerning first=356 second=192 amount=-1 +kerning first=8221 second=235 amount=-1 +kerning first=260 second=356 amount=-1 +kerning first=317 second=211 amount=-1 +kerning first=39 second=194 amount=-1 +kerning first=358 second=252 amount=-1 +kerning first=1043 second=1108 amount=-1 +kerning first=932 second=279 amount=-1 +kerning first=376 second=225 amount=-1 +kerning first=358 second=173 amount=-1 +kerning first=123 second=932 amount=1 +kerning first=84 second=354 amount=1 +kerning first=354 second=923 amount=-1 +kerning first=229 second=84 amount=-1 +kerning first=1034 second=1063 amount=-1 +kerning first=358 second=111 amount=-1 +kerning first=339 second=358 amount=-1 +kerning first=372 second=101 amount=-1 +kerning first=197 second=8221 amount=-1 +kerning first=76 second=262 amount=-1 +kerning first=196 second=372 amount=-1 +kerning first=1028 second=1066 amount=1 +kerning first=902 second=932 amount=-1 +kerning first=910 second=197 amount=-2 +kerning first=8216 second=248 amount=-1 +kerning first=321 second=212 amount=-1 +kerning first=86 second=225 amount=-1 +kerning first=89 second=41 amount=1 +kerning first=910 second=284 amount=-1 +kerning first=279 second=84 amount=-1 +kerning first=46 second=933 amount=-1 +kerning first=1068 second=1035 amount=-1 +kerning first=258 second=8220 amount=-1 +kerning first=356 second=8221 amount=1 +kerning first=939 second=193 amount=-2 +kerning first=947 second=8230 amount=-1 +kerning first=235 second=358 amount=-1 +kerning first=1058 second=1089 amount=-1 +kerning first=295 second=8221 amount=-1 +kerning first=45 second=1059 amount=-1 +kerning first=260 second=8217 amount=-1 +kerning first=1168 second=1093 amount=-1 +kerning first=354 second=326 amount=-1 +kerning first=933 second=199 amount=-1 +kerning first=1046 second=1095 amount=-1 +kerning first=197 second=354 amount=-1 +kerning first=939 second=58 amount=-1 +kerning first=969 second=39 amount=-1 +kerning first=74 second=93 amount=1 +kerning first=368 second=260 amount=-1 +kerning first=372 second=46 amount=-1 +kerning first=356 second=961 amount=-1 +kerning first=1040 second=1098 amount=-1 +kerning first=291 second=358 amount=-1 +kerning first=34 second=308 amount=-1 +kerning first=8216 second=279 amount=-1 +kerning first=221 second=281 amount=-1 +kerning first=933 second=288 amount=-1 +kerning first=910 second=187 amount=-1 +kerning first=356 second=234 amount=-1 +kerning first=1043 second=8230 amount=-1 +kerning first=40 second=1058 amount=1 +kerning first=334 second=8230 amount=-1 +kerning first=97 second=358 amount=-1 +kerning first=221 second=125 amount=1 +kerning first=376 second=273 amount=-1 +kerning first=1027 second=1105 amount=-1 +kerning first=8216 second=1113 amount=-1 +kerning first=84 second=289 amount=-1 +kerning first=356 second=354 amount=1 +kerning first=76 second=376 amount=-1 +kerning first=295 second=354 amount=-1 +kerning first=376 second=277 amount=-1 +kerning first=957 second=44 amount=-1 +kerning first=1058 second=45 amount=-1 +kerning first=354 second=229 amount=-1 +kerning first=89 second=212 amount=-1 +kerning first=8212 second=933 amount=-1 +kerning first=70 second=226 amount=-1 +kerning first=8220 second=228 amount=-1 +kerning first=910 second=963 amount=-1 +kerning first=76 second=332 amount=-1 +kerning first=1168 second=1038 amount=1 +kerning first=76 second=85 amount=-1 +kerning first=932 second=969 amount=-1 +kerning first=1090 second=173 amount=-1 +kerning first=8217 second=245 amount=-1 +kerning first=86 second=273 amount=-1 +kerning first=916 second=932 amount=-1 +kerning first=171 second=376 amount=-1 +kerning first=932 second=241 amount=-1 +kerning first=1169 second=45 amount=-1 +kerning first=306 second=41 amount=1 +kerning first=86 second=277 amount=-1 +kerning first=358 second=224 amount=-1 +kerning first=319 second=366 amount=-1 +kerning first=1043 second=1086 amount=-1 +kerning first=1168 second=8249 amount=-1 +kerning first=933 second=965 amount=-1 +kerning first=1056 second=1076 amount=-1 +kerning first=927 second=8230 amount=-1 +kerning first=317 second=264 amount=-1 +kerning first=89 second=367 amount=-1 +kerning first=194 second=86 amount=-1 +kerning first=241 second=8221 amount=-1 +kerning first=84 second=74 amount=-1 +kerning first=65 second=87 amount=-1 +kerning first=40 second=372 amount=1 +kerning first=87 second=269 amount=-1 +kerning first=8220 second=248 amount=-1 +kerning first=192 second=939 amount=-2 +kerning first=946 second=39 amount=-1 +kerning first=321 second=920 amount=-1 +kerning first=931 second=262 amount=-1 +kerning first=932 second=913 amount=-1 +kerning first=84 second=371 amount=-1 +kerning first=356 second=289 amount=-1 +kerning first=76 second=358 amount=-1 +kerning first=376 second=351 amount=-1 +kerning first=915 second=962 amount=-1 +kerning first=321 second=266 amount=-1 +kerning first=259 second=932 amount=-1 +kerning first=317 second=8211 amount=-1 +kerning first=358 second=339 amount=-1 +kerning first=218 second=65 amount=-1 +kerning first=372 second=198 amount=-1 +kerning first=89 second=250 amount=-1 +kerning first=219 second=192 amount=-1 +kerning first=45 second=1038 amount=-1 +kerning first=932 second=258 amount=-1 +kerning first=241 second=354 amount=-1 +kerning first=8216 second=969 amount=-1 +kerning first=1168 second=1072 amount=-1 +kerning first=87 second=197 amount=-1 +kerning first=319 second=45 amount=-1 +kerning first=1036 second=1033 amount=1 +kerning first=354 second=281 amount=-1 +kerning first=8220 second=279 amount=-1 +kerning first=160 second=221 amount=-1 +kerning first=221 second=244 amount=-1 +kerning first=220 second=923 amount=-1 +kerning first=354 second=125 amount=1 +kerning first=315 second=8249 amount=-1 +kerning first=84 second=970 amount=-1 +kerning first=171 second=358 amount=-1 +kerning first=8204 second=8218 amount=-2 +kerning first=932 second=307 amount=-1 +kerning first=8220 second=1113 amount=-1 +kerning first=1058 second=8212 amount=-1 +kerning first=84 second=353 amount=-1 +kerning first=358 second=312 amount=-1 +kerning first=232 second=356 amount=-1 +kerning first=160 second=84 amount=-1 +kerning first=376 second=239 amount=1 +kerning first=1027 second=1083 amount=-1 +kerning first=8211 second=932 amount=-1 +kerning first=103 second=354 amount=-1 +kerning first=89 second=920 amount=-1 +kerning first=39 second=308 amount=-1 +kerning first=76 second=199 amount=-1 +kerning first=358 second=275 amount=-1 +kerning first=372 second=261 amount=-1 +kerning first=193 second=936 amount=-1 +kerning first=8221 second=109 amount=-1 +kerning first=356 second=74 amount=-1 +kerning first=317 second=87 amount=-1 +kerning first=315 second=217 amount=-1 +kerning first=376 second=100 amount=-1 +kerning first=76 second=288 amount=-1 +kerning first=8216 second=913 amount=-1 +kerning first=1169 second=8212 amount=-1 +kerning first=289 second=356 amount=-1 +kerning first=902 second=939 amount=-2 +kerning first=910 second=212 amount=-1 +kerning first=89 second=266 amount=-1 +kerning first=315 second=334 amount=-1 +kerning first=931 second=332 amount=-1 +kerning first=932 second=946 amount=-1 +kerning first=98 second=356 amount=-1 +kerning first=194 second=932 amount=-1 +kerning first=915 second=256 amount=-2 +kerning first=86 second=239 amount=1 +kerning first=356 second=371 amount=-1 +kerning first=65 second=933 amount=-2 +kerning first=102 second=44 amount=-1 +kerning first=8216 second=258 amount=-1 +kerning first=221 second=260 amount=-1 +kerning first=257 second=8221 amount=-1 +kerning first=111 second=84 amount=-1 +kerning first=1058 second=1102 amount=-1 +kerning first=372 second=194 amount=-1 +kerning first=8216 second=1035 amount=1 +kerning first=86 second=100 amount=-1 +kerning first=1168 second=1107 amount=-1 +kerning first=87 second=235 amount=-1 +kerning first=319 second=79 amount=-1 +kerning first=368 second=197 amount=-1 +kerning first=933 second=210 amount=-1 +kerning first=939 second=71 amount=-1 +kerning first=315 second=216 amount=-1 +kerning first=356 second=970 amount=-1 +kerning first=335 second=358 amount=-1 +kerning first=376 second=45 amount=-1 +kerning first=356 second=353 amount=-1 +kerning first=85 second=260 amount=-1 +kerning first=1057 second=1051 amount=1 +kerning first=362 second=193 amount=-1 +kerning first=8216 second=8220 amount=-1 +kerning first=221 second=8249 amount=-1 +kerning first=1075 second=8211 amount=-1 +kerning first=1027 second=1119 amount=-1 +kerning first=258 second=356 amount=-1 +kerning first=257 second=354 amount=-1 +kerning first=319 second=8212 amount=-1 +kerning first=8221 second=324 amount=-1 +kerning first=98 second=8217 amount=-1 +kerning first=354 second=940 amount=-1 +kerning first=8220 second=969 amount=-1 +kerning first=372 second=337 amount=-1 +kerning first=1058 second=58 amount=-1 +kerning first=84 second=8211 amount=-1 +kerning first=915 second=947 amount=-1 +kerning first=354 second=244 amount=-1 +kerning first=89 second=226 amount=-1 +kerning first=910 second=972 amount=-1 +kerning first=76 second=362 amount=-1 +kerning first=228 second=84 amount=-1 +kerning first=80 second=256 amount=-1 +kerning first=310 second=74 amount=1 +kerning first=196 second=8221 amount=-1 +kerning first=193 second=372 amount=-1 +kerning first=1026 second=1066 amount=-1 +kerning first=916 second=939 amount=-1 +kerning first=939 second=941 amount=-1 +kerning first=932 second=382 amount=-1 +kerning first=358 second=962 amount=-1 +kerning first=221 second=334 amount=-1 +kerning first=84 second=225 amount=-1 +kerning first=87 second=41 amount=1 +kerning first=8217 second=271 amount=-1 +kerning first=1033 second=1059 amount=-1 +kerning first=277 second=84 amount=-1 +kerning first=358 second=243 amount=-1 +kerning first=44 second=933 amount=-1 +kerning first=372 second=231 amount=-1 +kerning first=1043 second=1099 amount=-1 +kerning first=81 second=44 amount=-1 +kerning first=1168 second=187 amount=-1 +kerning first=1066 second=1035 amount=-1 +kerning first=933 second=971 amount=-1 +kerning first=260 second=86 amount=-1 +kerning first=1075 second=1076 amount=-1 +kerning first=8230 second=39 amount=-2 +kerning first=233 second=358 amount=-1 +kerning first=271 second=322 amount=1 +kerning first=932 second=115 amount=-1 +kerning first=358 second=372 amount=1 +kerning first=936 second=65 amount=-1 +kerning first=8220 second=913 amount=-1 +kerning first=258 second=8217 amount=-1 +kerning first=84 second=87 amount=1 +kerning first=933 second=173 amount=-1 +kerning first=187 second=221 amount=-1 +kerning first=358 second=103 amount=-1 +kerning first=372 second=93 amount=1 +kerning first=931 second=199 amount=-1 +kerning first=376 second=79 amount=-1 +kerning first=8249 second=356 amount=-1 +kerning first=196 second=354 amount=-1 +kerning first=910 second=920 amount=-1 +kerning first=1028 second=1058 amount=1 +kerning first=8217 second=932 amount=1 +kerning first=354 second=260 amount=-1 +kerning first=1114 second=8221 amount=-1 +kerning first=315 second=284 amount=-1 +kerning first=8220 second=258 amount=-1 +kerning first=931 second=288 amount=-1 +kerning first=287 second=358 amount=-1 +kerning first=221 second=216 amount=-1 +kerning first=187 second=84 amount=-1 +kerning first=70 second=46 amount=-2 +kerning first=939 second=916 amount=-2 +kerning first=910 second=266 amount=-1 +kerning first=1068 second=8217 amount=-1 +kerning first=932 second=196 amount=-1 +kerning first=8220 second=1035 amount=1 +kerning first=84 second=305 amount=-1 +kerning first=356 second=8211 amount=-1 +kerning first=293 second=932 amount=-1 +kerning first=1058 second=1081 amount=-1 +kerning first=1043 second=1044 amount=-1 +kerning first=376 second=8212 amount=-1 +kerning first=8217 second=65 amount=-1 +kerning first=321 second=67 amount=-1 +kerning first=913 second=936 amount=-1 +kerning first=1168 second=1085 amount=-1 +kerning first=89 second=283 amount=-1 +kerning first=358 second=256 amount=-1 +kerning first=354 second=8249 amount=-1 +kerning first=1059 second=1077 amount=-1 +kerning first=8220 second=8220 amount=-1 +kerning first=1040 second=1090 amount=-1 +kerning first=197 second=87 amount=-1 +kerning first=221 second=269 amount=-1 +kerning first=84 second=273 amount=-1 +kerning first=8221 second=331 amount=-1 +kerning first=356 second=225 amount=-1 +kerning first=8217 second=347 amount=-1 +kerning first=8216 second=115 amount=-1 +kerning first=221 second=117 amount=-1 +kerning first=932 second=333 amount=-1 +kerning first=1027 second=1096 amount=-1 +kerning first=8211 second=939 amount=-1 +kerning first=84 second=277 amount=-1 +kerning first=8221 second=283 amount=-1 +kerning first=256 second=936 amount=-1 +kerning first=317 second=366 amount=-1 +kerning first=354 second=948 amount=-1 +kerning first=76 second=210 amount=-1 +kerning first=84 second=121 amount=-1 +kerning first=376 second=257 amount=-1 +kerning first=356 second=87 amount=1 +kerning first=915 second=927 amount=-1 +kerning first=939 second=8250 amount=-1 +kerning first=358 second=171 amount=-1 +kerning first=910 second=953 amount=-1 +kerning first=951 second=8217 amount=-1 +kerning first=376 second=113 amount=-1 +kerning first=337 second=356 amount=-1 +kerning first=915 second=192 amount=-2 +kerning first=216 second=8230 amount=-1 +kerning first=260 second=932 amount=-1 +kerning first=315 second=364 amount=-1 +kerning first=8216 second=196 amount=-1 +kerning first=345 second=44 amount=-1 +kerning first=221 second=197 amount=-1 +kerning first=194 second=939 amount=-2 +kerning first=932 second=959 amount=-1 +kerning first=8217 second=238 amount=-1 +kerning first=915 second=286 amount=-1 +kerning first=171 second=910 amount=-1 +kerning first=89 second=67 amount=-1 +kerning first=315 second=8216 amount=-2 +kerning first=939 second=949 amount=-1 +kerning first=932 second=233 amount=-1 +kerning first=121 second=44 amount=-1 +kerning first=929 second=913 amount=-1 +kerning first=221 second=284 amount=-1 +kerning first=356 second=305 amount=-1 +kerning first=1033 second=1038 amount=-1 +kerning first=321 second=360 amount=-1 +kerning first=86 second=257 amount=-1 +kerning first=1058 second=1116 amount=-1 +kerning first=1043 second=1078 amount=-1 +kerning first=932 second=356 amount=1 +kerning first=376 second=193 amount=-1 +kerning first=8217 second=99 amount=-1 +kerning first=86 second=113 amount=-1 +kerning first=1168 second=1169 amount=-1 +kerning first=939 second=336 amount=-1 +kerning first=360 second=198 amount=-1 +kerning first=89 second=349 amount=-1 +kerning first=248 second=356 amount=-1 +kerning first=929 second=258 amount=-1 +kerning first=936 second=44 amount=-1 +kerning first=85 second=197 amount=-1 +kerning first=317 second=45 amount=-1 +kerning first=40 second=354 amount=1 +kerning first=70 second=198 amount=-1 +kerning first=376 second=58 amount=-1 +kerning first=8216 second=333 amount=-1 +kerning first=218 second=923 amount=-1 +kerning first=913 second=372 amount=-1 +kerning first=313 second=8249 amount=-1 +kerning first=356 second=273 amount=-1 +kerning first=1038 second=1077 amount=-1 +kerning first=337 second=8217 amount=-1 +kerning first=86 second=193 amount=-1 +kerning first=84 second=351 amount=-1 +kerning first=8221 second=349 amount=-1 +kerning first=356 second=277 amount=-1 +kerning first=234 second=356 amount=-1 +kerning first=932 second=181 amount=-1 +kerning first=80 second=192 amount=-1 +kerning first=101 second=354 amount=-1 +kerning first=356 second=121 amount=-1 +kerning first=76 second=173 amount=-1 +kerning first=376 second=335 amount=-1 +kerning first=197 second=933 amount=-2 +kerning first=915 second=961 amount=-2 +kerning first=939 second=338 amount=-1 +kerning first=1058 second=1060 amount=-1 +kerning first=8217 second=44 amount=-2 +kerning first=8216 second=959 amount=-1 +kerning first=256 second=372 amount=-1 +kerning first=313 second=217 amount=-1 +kerning first=354 second=269 amount=-1 +kerning first=932 second=8217 amount=1 +kerning first=70 second=261 amount=-1 +kerning first=8216 second=233 amount=-1 +kerning first=221 second=235 amount=-1 +kerning first=285 second=356 amount=-1 +kerning first=354 second=117 amount=-1 +kerning first=89 second=101 amount=-1 +kerning first=248 second=8217 amount=-1 +kerning first=313 second=334 amount=-1 +kerning first=366 second=195 amount=-1 +kerning first=8220 second=115 amount=-1 +kerning first=1091 second=44 amount=-1 +kerning first=8216 second=356 amount=1 +kerning first=84 second=239 amount=-1 +kerning first=8217 second=299 amount=-1 +kerning first=8221 second=236 amount=-1 +kerning first=86 second=335 amount=-1 +kerning first=372 second=242 amount=-1 +kerning first=1043 second=1113 amount=-1 +kerning first=932 second=291 amount=-1 +kerning first=220 second=260 amount=-1 +kerning first=376 second=227 amount=-1 +kerning first=1027 second=1075 amount=-1 +kerning first=8216 second=1083 amount=-1 +kerning first=321 second=39 amount=-2 +kerning first=109 second=84 amount=-1 +kerning first=923 second=221 amount=-1 +kerning first=360 second=194 amount=-1 +kerning first=358 second=263 amount=-1 +kerning first=84 second=100 amount=-1 +kerning first=8221 second=101 amount=-1 +kerning first=317 second=79 amount=-1 +kerning first=354 second=197 amount=-1 +kerning first=315 second=212 amount=-1 +kerning first=70 second=194 amount=-1 +kerning first=910 second=934 amount=-1 +kerning first=8220 second=196 amount=-1 +kerning first=931 second=210 amount=-1 +kerning first=8204 second=376 amount=-1 +kerning first=923 second=84 amount=-1 +kerning first=313 second=216 amount=-1 +kerning first=1057 second=1098 amount=-1 +kerning first=308 second=125 amount=1 +kerning first=321 second=218 amount=-1 +kerning first=86 second=227 amount=-1 +kerning first=89 second=46 amount=-2 +kerning first=364 second=193 amount=-1 +kerning first=356 second=351 amount=-1 +kerning first=910 second=67 amount=-1 +kerning first=939 second=195 amount=-2 +kerning first=317 second=8212 amount=-1 +kerning first=1058 second=1094 amount=-1 +kerning first=358 second=192 amount=-1 +kerning first=1043 second=1057 amount=-1 +kerning first=1075 second=45 amount=-1 +kerning first=221 second=41 amount=1 +kerning first=1168 second=1098 amount=-1 +kerning first=87 second=226 amount=-1 +kerning first=319 second=71 amount=-1 +kerning first=939 second=290 amount=-1 +kerning first=213 second=44 amount=-1 +kerning first=354 second=341 amount=-1 +kerning first=8220 second=333 amount=-1 +kerning first=225 second=84 amount=-1 +kerning first=84 second=45 amount=-1 +kerning first=8221 second=46 amount=-2 +kerning first=354 second=187 amount=-1 +kerning first=230 second=358 amount=-1 +kerning first=193 second=8221 amount=-1 +kerning first=102 second=125 amount=2 +kerning first=8216 second=291 amount=-1 +kerning first=356 second=239 amount=-1 +kerning first=91 second=1026 amount=1 +kerning first=932 second=363 amount=-1 +kerning first=84 second=303 amount=-1 +kerning first=8221 second=297 amount=-1 +kerning first=354 second=963 amount=-1 +kerning first=79 second=44 amount=-1 +kerning first=195 second=8216 amount=-1 +kerning first=258 second=86 amount=-1 +kerning first=8220 second=959 amount=-1 +kerning first=376 second=287 amount=-1 +kerning first=356 second=100 amount=-1 +kerning first=227 second=358 amount=-1 +kerning first=354 second=235 amount=-1 +kerning first=939 second=8230 amount=-2 +kerning first=358 second=8221 amount=1 +kerning first=910 second=968 amount=-1 +kerning first=8220 second=233 amount=-1 +kerning first=8204 second=358 amount=-1 +kerning first=915 second=211 amount=-1 +kerning first=931 second=173 amount=-1 +kerning first=8222 second=221 amount=-2 +kerning first=260 second=939 amount=-2 +kerning first=232 second=932 amount=-1 +kerning first=193 second=354 amount=-1 +kerning first=221 second=212 amount=-1 +kerning first=8220 second=356 amount=1 +kerning first=932 second=943 amount=-1 +kerning first=936 second=923 amount=-1 +kerning first=965 second=39 amount=-1 +kerning first=1026 second=1058 amount=-1 +kerning first=1059 second=46 amount=-2 +kerning first=313 second=284 amount=-1 +kerning first=8217 second=160 amount=-1 +kerning first=932 second=245 amount=-1 +kerning first=275 second=358 amount=-1 +kerning first=358 second=961 amount=-1 +kerning first=1058 second=8250 amount=-1 +kerning first=8220 second=1083 amount=-1 +kerning first=8222 second=84 amount=-1 +kerning first=68 second=46 amount=-1 +kerning first=1066 second=8217 amount=-1 +kerning first=358 second=234 amount=-1 +kerning first=929 second=196 amount=-1 +kerning first=1043 second=1091 amount=-1 +kerning first=950 second=955 amount=1 +kerning first=8217 second=112 amount=-1 +kerning first=1027 second=1054 amount=-1 +kerning first=933 second=962 amount=-1 +kerning first=289 second=932 amount=-1 +kerning first=315 second=920 amount=-1 +kerning first=358 second=354 amount=1 +kerning first=98 second=932 amount=-1 +kerning first=356 second=45 amount=-1 +kerning first=968 second=34 amount=-1 +kerning first=89 second=198 amount=-1 +kerning first=87 second=283 amount=-1 +kerning first=376 second=71 amount=-1 +kerning first=221 second=367 amount=-1 +kerning first=8217 second=923 amount=-1 +kerning first=315 second=266 amount=-1 +kerning first=196 second=87 amount=-1 +kerning first=1075 second=8212 amount=-1 +kerning first=354 second=41 amount=1 +kerning first=356 second=303 amount=-1 +kerning first=84 second=8212 amount=-1 +kerning first=376 second=365 amount=-1 +kerning first=915 second=970 amount=-1 +kerning first=8221 second=198 amount=-1 +kerning first=910 second=46 amount=-2 +kerning first=1043 second=1035 amount=1 +kerning first=1168 second=1077 amount=-1 +kerning first=89 second=261 amount=-1 +kerning first=8216 second=245 amount=-1 +kerning first=8220 second=291 amount=-1 +kerning first=80 second=74 amount=-1 +kerning first=326 second=356 amount=-1 +kerning first=221 second=250 amount=-1 +kerning first=258 second=932 amount=-1 +kerning first=84 second=912 amount=-1 +kerning first=313 second=364 amount=-1 +kerning first=220 second=197 amount=-1 +kerning first=933 second=256 amount=-2 +kerning first=1038 second=46 amount=-2 +kerning first=84 second=253 amount=-1 +kerning first=313 second=8216 amount=-2 +kerning first=8217 second=326 amount=-1 +kerning first=119 second=44 amount=-1 +kerning first=160 second=89 amount=-1 +kerning first=372 second=358 amount=1 +kerning first=376 second=246 amount=-1 +kerning first=1027 second=1088 amount=-1 +kerning first=84 second=257 amount=-1 +kerning first=358 second=289 amount=-1 +kerning first=217 second=193 amount=-1 +kerning first=372 second=267 amount=-1 +kerning first=84 second=113 amount=-1 +kerning first=8221 second=114 amount=-1 +kerning first=89 second=194 amount=-1 +kerning first=370 second=198 amount=-1 +kerning first=910 second=945 amount=-1 +kerning first=934 second=44 amount=-1 +kerning first=221 second=920 amount=-1 +kerning first=91 second=106 amount=1 +kerning first=70 second=308 amount=-1 +kerning first=913 second=8221 amount=-1 +kerning first=91 second=1095 amount=-1 +kerning first=932 second=951 amount=-1 +kerning first=86 second=246 amount=-1 +kerning first=89 second=59 amount=-1 +kerning first=915 second=264 amount=-1 +kerning first=173 second=1026 amount=-1 +kerning first=8211 second=1059 amount=-1 +kerning first=319 second=221 amount=-1 +kerning first=1040 second=1026 amount=-1 +kerning first=326 second=8217 amount=-1 +kerning first=221 second=266 amount=-1 +kerning first=84 second=193 amount=-1 +kerning first=356 second=8212 amount=-1 +kerning first=8221 second=194 amount=-1 +kerning first=939 second=214 amount=-1 +kerning first=1058 second=1108 amount=-1 +kerning first=1027 second=44 amount=-1 +kerning first=319 second=336 amount=-1 +kerning first=8249 second=932 amount=-1 +kerning first=196 second=933 amount=-2 +kerning first=1027 second=1032 amount=-1 +kerning first=319 second=84 amount=-1 +kerning first=932 second=86 amount=1 +kerning first=354 second=367 amount=-1 +kerning first=89 second=337 amount=-1 +kerning first=70 second=369 amount=-1 +kerning first=242 second=84 amount=-1 +kerning first=256 second=8221 amount=-1 +kerning first=358 second=74 amount=-1 +kerning first=1059 second=1103 amount=-1 +kerning first=356 second=912 amount=-1 +kerning first=915 second=8211 amount=-1 +kerning first=281 second=356 amount=-1 +kerning first=40 second=87 amount=1 +kerning first=913 second=354 amount=-1 +kerning first=934 second=939 amount=-1 +kerning first=87 second=101 amount=-1 +kerning first=910 second=198 amount=-2 +kerning first=356 second=253 amount=-1 +kerning first=362 second=195 amount=-1 +kerning first=84 second=335 amount=-1 +kerning first=319 second=338 amount=-1 +kerning first=356 second=257 amount=-1 +kerning first=8221 second=337 amount=-1 +kerning first=932 second=230 amount=-1 +kerning first=358 second=371 amount=-1 +kerning first=218 second=260 amount=-1 +kerning first=354 second=972 amount=-1 +kerning first=356 second=113 amount=-1 +kerning first=354 second=250 amount=-1 +kerning first=89 second=231 amount=-1 +kerning first=370 second=194 amount=-1 +kerning first=8220 second=245 amount=-1 +kerning first=910 second=944 amount=-1 +kerning first=76 second=372 amount=-1 +kerning first=8212 second=221 amount=-1 +kerning first=256 second=354 amount=-1 +kerning first=313 second=212 amount=-1 +kerning first=1061 second=1095 amount=-1 +kerning first=221 second=226 amount=-1 +kerning first=1059 second=59 amount=-1 +kerning first=354 second=109 amount=-1 +kerning first=89 second=93 amount=1 +kerning first=324 second=358 amount=-1 +kerning first=939 second=973 amount=-1 +kerning first=358 second=970 amount=-1 +kerning first=8212 second=84 amount=-1 +kerning first=1058 second=8230 amount=-1 +kerning first=84 second=227 amount=-1 +kerning first=87 second=46 amount=-1 +kerning first=356 second=193 amount=-1 +kerning first=904 second=912 amount=1 +kerning first=8217 second=281 amount=-1 +kerning first=8221 second=231 amount=-1 +kerning first=112 second=358 amount=-1 +kerning first=358 second=353 amount=-1 +kerning first=1043 second=1105 amount=-1 +kerning first=932 second=271 amount=-1 +kerning first=337 second=932 amount=-1 +kerning first=91 second=376 amount=1 +kerning first=932 second=120 amount=-1 +kerning first=376 second=336 amount=-1 +kerning first=317 second=71 amount=-1 +kerning first=214 second=44 amount=-1 +kerning first=376 second=84 amount=1 +kerning first=1169 second=8230 amount=-1 +kerning first=910 second=194 amount=-2 +kerning first=1057 second=1090 amount=-1 +kerning first=1038 second=1103 amount=-1 +kerning first=8216 second=230 amount=-1 +kerning first=932 second=932 amount=1 +kerning first=187 second=89 amount=-1 +kerning first=8211 second=1038 amount=-1 +kerning first=315 second=67 amount=-1 +kerning first=356 second=335 amount=-1 +kerning first=248 second=932 amount=-1 +kerning first=8250 second=354 amount=-1 +kerning first=935 second=970 amount=1 +kerning first=910 second=59 amount=-1 +kerning first=1058 second=1086 amount=-1 +kerning first=319 second=290 amount=-1 +kerning first=192 second=8216 amount=-1 +kerning first=376 second=338 amount=-1 +kerning first=933 second=927 amount=-1 +kerning first=908 second=8230 amount=-1 +kerning first=224 second=358 amount=-1 +kerning first=86 second=84 amount=1 +kerning first=1168 second=1090 amount=-1 +kerning first=354 second=324 amount=-1 +kerning first=932 second=65 amount=-1 +kerning first=89 second=285 amount=-1 +kerning first=76 second=171 amount=-1 +kerning first=933 second=192 amount=-2 +kerning first=258 second=939 amount=-2 +kerning first=1040 second=1095 amount=-1 +kerning first=234 second=932 amount=-1 +kerning first=306 second=93 amount=1 +kerning first=8216 second=271 amount=-1 +kerning first=933 second=286 amount=-1 +kerning first=1038 second=59 amount=-1 +kerning first=221 second=283 amount=-1 +kerning first=356 second=227 amount=-1 +kerning first=283 second=358 amount=-1 +kerning first=333 second=8221 amount=-1 +kerning first=932 second=347 amount=-1 +kerning first=1027 second=1101 amount=-1 +kerning first=917 second=912 amount=1 +kerning first=84 second=287 amount=-1 +kerning first=8221 second=285 amount=-1 +kerning first=91 second=358 amount=1 +kerning first=354 second=953 amount=-1 +kerning first=76 second=220 amount=-1 +kerning first=372 second=301 amount=1 +kerning first=285 second=932 amount=-1 +kerning first=376 second=265 amount=-1 +kerning first=354 second=226 amount=-1 +kerning first=358 second=8211 amount=-1 +kerning first=313 second=920 amount=-1 +kerning first=1168 second=46 amount=-1 +kerning first=8216 second=932 amount=1 +kerning first=87 second=198 amount=-1 +kerning first=89 second=308 amount=-1 +kerning first=315 second=360 amount=-1 +kerning first=932 second=966 amount=-1 +kerning first=8217 second=244 amount=-1 +kerning first=1059 second=1026 amount=1 +kerning first=313 second=266 amount=-1 +kerning first=193 second=87 amount=-1 +kerning first=939 second=954 amount=-1 +kerning first=932 second=238 amount=-1 +kerning first=333 second=354 amount=-1 +kerning first=65 second=221 amount=-1 +kerning first=86 second=265 amount=-1 +kerning first=358 second=225 amount=-1 +kerning first=8216 second=65 amount=-1 +kerning first=319 second=368 amount=-1 +kerning first=221 second=67 amount=-1 +kerning first=902 second=8216 amount=-1 +kerning first=376 second=195 amount=-1 +kerning first=8249 second=939 amount=-1 +kerning first=936 second=260 amount=-1 +kerning first=933 second=961 amount=-1 +kerning first=1043 second=1083 amount=-1 +kerning first=272 second=44 amount=-1 +kerning first=8221 second=308 amount=-1 +kerning first=932 second=99 amount=-1 +kerning first=89 second=369 amount=-1 +kerning first=1041 second=1035 amount=-1 +kerning first=329 second=84 amount=-1 +kerning first=376 second=290 amount=-1 +kerning first=65 second=84 amount=-1 +kerning first=358 second=87 amount=1 +kerning first=87 second=261 amount=-1 +kerning first=8220 second=230 amount=-1 +kerning first=328 second=356 amount=-1 +kerning first=8216 second=347 amount=-1 +kerning first=221 second=349 amount=-1 +kerning first=218 second=197 amount=-1 +kerning first=160 second=8220 amount=-1 +kerning first=339 second=354 amount=-1 +kerning first=86 second=195 amount=-1 +kerning first=84 second=365 amount=-1 +kerning first=356 second=287 amount=-1 +kerning first=173 second=376 amount=-1 +kerning first=8217 second=260 amount=-1 +kerning first=321 second=262 amount=-1 +kerning first=354 second=331 amount=-1 +kerning first=358 second=305 amount=-1 +kerning first=89 second=242 amount=-1 +kerning first=97 second=8221 amount=-1 +kerning first=219 second=193 amount=-1 +kerning first=376 second=8230 amount=-2 +kerning first=8216 second=966 amount=-1 +kerning first=87 second=194 amount=-1 +kerning first=368 second=198 amount=-1 +kerning first=354 second=283 amount=-1 +kerning first=932 second=44 amount=-1 +kerning first=235 second=354 amount=-1 +kerning first=8220 second=271 amount=-1 +kerning first=354 second=122 amount=-1 +kerning first=315 second=39 amount=-2 +kerning first=84 second=941 amount=-1 +kerning first=102 second=8216 amount=1 +kerning first=34 second=256 amount=-1 +kerning first=84 second=246 amount=-1 +kerning first=8221 second=242 amount=-1 +kerning first=317 second=221 amount=-1 +kerning first=1038 second=1026 amount=1 +kerning first=1090 second=8211 amount=-1 +kerning first=328 second=8217 amount=-1 +kerning first=358 second=273 amount=-1 +kerning first=8216 second=99 amount=-1 +kerning first=1043 second=1119 amount=-1 +kerning first=221 second=101 amount=-1 +kerning first=932 second=299 amount=-1 +kerning first=376 second=232 amount=-1 +kerning first=1027 second=1080 amount=-1 +kerning first=76 second=927 amount=-1 +kerning first=291 second=354 amount=-1 +kerning first=308 second=41 amount=1 +kerning first=86 second=8230 amount=-1 +kerning first=229 second=356 amount=-1 +kerning first=317 second=336 amount=-1 +kerning first=354 second=934 amount=-1 +kerning first=358 second=277 amount=-1 +kerning first=8220 second=932 amount=1 +kerning first=97 second=354 amount=-1 +kerning first=920 second=46 amount=-1 +kerning first=84 second=105 amount=-1 +kerning first=193 second=933 amount=-2 +kerning first=317 second=84 amount=-1 +kerning first=315 second=218 amount=-1 +kerning first=358 second=121 amount=-1 +kerning first=87 second=337 amount=-1 +kerning first=942 second=8221 amount=-1 +kerning first=372 second=111 amount=-1 +kerning first=244 second=84 amount=-1 +kerning first=76 second=286 amount=-1 +kerning first=376 second=97 amount=-1 +kerning first=1111 second=1115 amount=1 +kerning first=923 second=89 amount=-1 +kerning first=89 second=262 amount=-1 +kerning first=279 second=356 amount=-1 +kerning first=321 second=376 amount=-1 +kerning first=86 second=232 amount=-1 +kerning first=364 second=195 amount=-1 +kerning first=8220 second=65 amount=-1 +kerning first=319 second=214 amount=-1 +kerning first=356 second=365 amount=-1 +kerning first=84 second=916 amount=-1 +kerning first=173 second=358 amount=-1 +kerning first=102 second=41 amount=2 +kerning first=915 second=45 amount=-1 +kerning first=317 second=338 amount=-1 +kerning first=321 second=332 amount=-1 +kerning first=270 second=46 amount=-1 +kerning first=1058 second=1099 amount=-1 +kerning first=8216 second=44 amount=-2 +kerning first=271 second=316 amount=1 +kerning first=221 second=46 amount=-2 +kerning first=1090 second=1076 amount=-1 +kerning first=8216 second=1032 amount=-1 +kerning first=321 second=85 amount=-1 +kerning first=86 second=97 amount=-1 +kerning first=87 second=231 amount=-1 +kerning first=368 second=194 amount=-1 +kerning first=1168 second=1103 amount=-1 +kerning first=354 second=349 amount=-1 +kerning first=76 second=8221 amount=-2 +kerning first=933 second=211 amount=-1 +kerning first=8220 second=347 amount=-1 +kerning first=229 second=8217 amount=-1 +kerning first=1059 second=1095 amount=-1 +kerning first=356 second=941 amount=-1 +kerning first=923 second=34 amount=-1 +kerning first=87 second=93 amount=1 +kerning first=356 second=246 amount=-1 +kerning first=913 second=87 amount=-1 +kerning first=1056 second=8230 amount=-2 +kerning first=932 second=373 amount=-1 +kerning first=1027 second=1115 amount=1 +kerning first=110 second=358 amount=-1 +kerning first=354 second=968 amount=-1 +kerning first=358 second=351 amount=-1 +kerning first=8220 second=966 amount=-1 +kerning first=326 second=932 amount=-1 +kerning first=84 second=8250 amount=-1 +kerning first=356 second=105 amount=-1 +kerning first=354 second=236 amount=-1 +kerning first=1058 second=1044 amount=-1 +kerning first=910 second=942 amount=-1 +kerning first=1168 second=59 amount=-1 +kerning first=76 second=354 amount=-1 +kerning first=211 second=44 amount=-1 +kerning first=89 second=332 amount=-1 +kerning first=366 second=913 amount=-1 +kerning first=932 second=974 amount=-1 +kerning first=256 second=87 amount=-1 +kerning first=1026 second=1063 amount=-1 +kerning first=321 second=358 amount=-1 +kerning first=354 second=101 amount=-1 +kerning first=8220 second=99 amount=-1 +kerning first=356 second=916 amount=-1 +kerning first=84 second=949 amount=-1 +kerning first=1059 second=1040 amount=-1 +kerning first=932 second=249 amount=-1 +kerning first=915 second=79 amount=-1 +kerning first=936 second=197 amount=-1 +kerning first=8222 second=89 amount=-2 +kerning first=313 second=67 amount=-1 +kerning first=8217 second=269 amount=-1 +kerning first=922 second=308 amount=1 +kerning first=358 second=239 amount=-1 +kerning first=366 second=258 amount=-1 +kerning first=372 second=224 amount=-1 +kerning first=932 second=259 amount=-1 +kerning first=376 second=214 amount=-1 +kerning first=171 second=354 amount=-1 +kerning first=933 second=970 amount=-1 +kerning first=1027 second=1059 amount=1 +kerning first=1043 second=1096 amount=-1 +kerning first=317 second=290 amount=-1 +kerning first=194 second=8216 amount=-1 +kerning first=932 second=112 amount=-1 +kerning first=39 second=256 amount=-1 +kerning first=931 second=927 amount=-1 +kerning first=84 second=84 amount=1 +kerning first=226 second=358 amount=-1 +kerning first=358 second=100 amount=-1 +kerning first=929 second=65 amount=-1 +kerning first=915 second=8212 amount=-1 +kerning first=1038 second=1095 amount=-1 +kerning first=373 second=44 amount=-1 +kerning first=160 second=8222 amount=-2 +kerning first=931 second=286 amount=-1 +kerning first=221 second=198 amount=-1 +kerning first=91 second=1066 amount=1 +kerning first=932 second=923 amount=-1 +kerning first=8217 second=197 amount=-1 +kerning first=321 second=199 amount=-1 +kerning first=354 second=46 amount=-1 +kerning first=84 second=378 amount=-1 +kerning first=910 second=262 amount=-1 +kerning first=8220 second=44 amount=-2 +kerning first=939 second=913 amount=-2 +kerning first=335 second=8221 amount=-1 +kerning first=195 second=39 amount=-1 +kerning first=8220 second=1032 amount=-1 +kerning first=915 second=912 amount=-1 +kerning first=356 second=8250 amount=-1 +kerning first=376 second=361 amount=-1 +kerning first=321 second=288 amount=-1 +kerning first=89 second=358 amount=1 +kerning first=1058 second=1078 amount=-1 +kerning first=372 second=339 amount=-1 +kerning first=197 second=221 amount=-1 +kerning first=281 second=932 amount=-1 +kerning first=8216 second=974 amount=-1 +kerning first=913 second=933 amount=-2 +kerning first=1168 second=1082 amount=-1 +kerning first=939 second=258 amount=-2 +kerning first=354 second=297 amount=-1 +kerning first=89 second=267 amount=-1 +kerning first=1118 second=46 amount=-1 +kerning first=34 second=192 amount=-1 +kerning first=1050 second=1033 amount=1 +kerning first=85 second=198 amount=-1 +kerning first=358 second=45 amount=-1 +kerning first=313 second=360 amount=-1 +kerning first=931 second=8221 amount=-1 +kerning first=356 second=949 amount=-1 +kerning first=197 second=84 amount=-1 +kerning first=8216 second=259 amount=-1 +kerning first=933 second=264 amount=-1 +kerning first=160 second=356 amount=-1 +kerning first=221 second=261 amount=-1 +kerning first=8217 second=341 amount=-1 +kerning first=8221 second=358 amount=1 +kerning first=1057 second=1026 amount=1 +kerning first=1100 second=1091 amount=-1 +kerning first=1038 second=1040 amount=-1 +kerning first=932 second=326 amount=-1 +kerning first=335 second=354 amount=-1 +kerning first=376 second=251 amount=-1 +kerning first=1027 second=1093 amount=-1 +kerning first=84 second=265 amount=-1 +kerning first=256 second=933 amount=-2 +kerning first=8221 second=267 amount=-1 +kerning first=317 second=368 amount=-1 +kerning first=354 second=945 amount=-1 +kerning first=332 second=44 amount=-1 +kerning first=76 second=211 amount=-1 +kerning first=358 second=303 amount=-1 +kerning first=217 second=195 amount=-1 +kerning first=372 second=275 amount=-1 +kerning first=84 second=118 amount=-1 +kerning first=255 second=44 amount=-1 +kerning first=356 second=84 amount=1 +kerning first=89 second=199 amount=-1 +kerning first=295 second=84 amount=-1 +kerning first=8216 second=923 amount=-1 +kerning first=915 second=193 amount=-2 +kerning first=1168 second=1026 amount=1 +kerning first=89 second=288 amount=-1 +kerning first=933 second=8211 amount=-1 +kerning first=221 second=194 amount=-1 +kerning first=8204 second=372 amount=-1 +kerning first=8217 second=235 amount=-1 +kerning first=910 second=332 amount=-1 +kerning first=1107 second=44 amount=-1 +kerning first=356 second=378 amount=-1 +kerning first=939 second=946 amount=-1 +kerning first=111 second=356 amount=-1 +kerning first=932 second=229 amount=-1 +kerning first=915 second=58 amount=-1 +kerning first=1068 second=1059 amount=-1 +kerning first=84 second=195 amount=-1 +kerning first=321 second=362 amount=-1 +kerning first=1058 second=1113 amount=-1 +kerning first=1043 second=1075 amount=-1 +kerning first=221 second=59 amount=-1 +kerning first=1027 second=1038 amount=1 +kerning first=34 second=961 amount=-1 +kerning first=1168 second=1118 amount=-1 +kerning first=87 second=242 amount=-1 +kerning first=319 second=89 amount=-1 +kerning first=85 second=194 amount=-1 +kerning first=354 second=198 amount=-1 +kerning first=939 second=81 amount=-1 +kerning first=929 second=44 amount=-2 +kerning first=233 second=354 amount=-1 +kerning first=1059 second=1109 amount=-1 +kerning first=1028 second=1033 amount=1 +kerning first=221 second=337 amount=-1 +kerning first=313 second=39 amount=-2 +kerning first=1027 second=8249 amount=-1 +kerning first=1075 second=8230 amount=-1 +kerning first=173 second=910 amount=-1 +kerning first=84 second=345 amount=-1 +kerning first=356 second=265 amount=-1 +kerning first=8221 second=343 amount=-1 +kerning first=1035 second=1026 amount=-1 +kerning first=354 second=944 amount=-1 +kerning first=8220 second=974 amount=-1 +kerning first=287 second=354 amount=-1 +kerning first=80 second=193 amount=-1 +kerning first=84 second=8230 amount=-1 +kerning first=356 second=118 amount=-1 +kerning first=111 second=8217 amount=-1 +kerning first=228 second=356 amount=-1 +kerning first=354 second=255 amount=-1 +kerning first=915 second=957 amount=-1 +kerning first=1058 second=1057 amount=-1 +kerning first=358 second=8212 amount=-1 +kerning first=70 second=252 amount=-1 +kerning first=1090 second=45 amount=-1 +kerning first=45 second=1026 amount=-1 +kerning first=923 second=8220 amount=-1 +kerning first=313 second=218 amount=-1 +kerning first=319 second=34 amount=-2 +kerning first=271 second=98 amount=1 +kerning first=354 second=261 amount=-1 +kerning first=241 second=84 amount=-1 +kerning first=8216 second=229 amount=-1 +kerning first=8220 second=259 amount=-1 +kerning first=221 second=231 amount=-1 +kerning first=173 second=1066 amount=-1 +kerning first=46 second=34 amount=-2 +kerning first=354 second=114 amount=-1 +kerning first=1040 second=1066 amount=-1 +kerning first=366 second=196 amount=-1 +kerning first=277 second=356 amount=-1 +kerning first=358 second=912 amount=-1 +kerning first=8212 second=89 amount=-1 +kerning first=84 second=232 amount=-1 +kerning first=8221 second=237 amount=-1 +kerning first=356 second=195 amount=-1 +kerning first=317 second=214 amount=-1 +kerning first=39 second=192 amount=-1 +kerning first=358 second=253 amount=-1 +kerning first=372 second=243 amount=-1 +kerning first=932 second=281 amount=-1 +kerning first=376 second=228 amount=-1 +kerning first=221 second=93 amount=1 +kerning first=260 second=8216 amount=-1 +kerning first=1027 second=1072 amount=-1 +kerning first=932 second=125 amount=1 +kerning first=358 second=257 amount=-1 +kerning first=8220 second=923 amount=-1 +kerning first=103 second=84 amount=-1 +kerning first=245 second=358 amount=-1 +kerning first=84 second=97 amount=-1 +kerning first=354 second=194 amount=-1 +kerning first=358 second=113 amount=-1 +kerning first=931 second=211 amount=-1 +kerning first=76 second=264 amount=-1 +kerning first=228 second=8217 amount=-1 +kerning first=910 second=199 amount=-1 +kerning first=1057 second=1095 amount=-1 +kerning first=187 second=356 amount=-1 +kerning first=1038 second=1109 amount=-1 +kerning first=321 second=210 amount=-1 +kerning first=86 second=228 amount=-1 +kerning first=910 second=288 amount=-1 +kerning first=356 second=345 amount=-1 +kerning first=1068 second=1038 amount=-1 +kerning first=935 second=912 amount=1 +kerning first=356 second=8230 amount=-1 +kerning first=939 second=196 amount=-2 +kerning first=1058 second=1091 amount=-1 +kerning first=358 second=193 amount=-1 +kerning first=1043 second=1054 amount=-1 +kerning first=328 second=932 amount=-1 +kerning first=376 second=248 amount=-1 +kerning first=1168 second=1095 amount=-1 +kerning first=1056 second=1044 amount=-1 +kerning first=354 second=337 amount=-1 +kerning first=76 second=8211 amount=-1 +kerning first=372 second=256 amount=-1 +kerning first=1113 second=1098 amount=-1 diff --git a/art/font/myriad-medium-big.png b/art/font/myriad-medium-big.png new file mode 100644 index 00000000..5a7df5c3 Binary files /dev/null and b/art/font/myriad-medium-big.png differ diff --git a/art/font/myriad-medium-small.fnt b/art/font/myriad-medium-small.fnt new file mode 100644 index 00000000..7c582e6b --- /dev/null +++ b/art/font/myriad-medium-small.fnt @@ -0,0 +1,3178 @@ +info face="MyriadPro-Regular" size=12 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=15 base=9 scaleW=128 scaleH=512 pages=1 packed=0 +page id=0 file="myriad-medium-small.png" +chars count=506 +char id=0 x=72 y=121 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=13 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=0 page=0 chnl=0 +char id=33 x=80 y=121 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=34 x=93 y=349 width=6 height=5 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=35 x=117 y=276 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=36 x=8 y=42 width=8 height=13 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=37 x=0 y=287 width=12 height=10 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=38 x=85 y=121 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=39 x=123 y=254 width=4 height=5 xoffset=-1 yoffset=0 xadvance=2 page=0 chnl=0 +char id=40 x=91 y=108 width=6 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=41 x=97 y=108 width=5 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=42 x=0 y=349 width=7 height=7 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=43 x=78 y=307 width=9 height=9 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=44 x=38 y=349 width=5 height=6 xoffset=-1 yoffset=7 xadvance=2 page=0 chnl=0 +char id=45 x=64 y=356 width=6 height=3 xoffset=-1 yoffset=4 xadvance=4 page=0 chnl=0 +char id=46 x=11 y=356 width=5 height=4 xoffset=-1 yoffset=6 xadvance=2 page=0 chnl=0 +char id=47 x=95 y=121 width=8 height=11 xoffset=-2 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=48 x=12 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=49 x=20 y=287 width=5 height=10 xoffset=0 yoffset=0 xadvance=6 page=0 chnl=0 +char id=50 x=25 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=51 x=33 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=52 x=41 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=53 x=49 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=54 x=57 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=55 x=65 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=56 x=73 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=57 x=103 y=121 width=8 height=11 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=58 x=122 y=297 width=5 height=8 xoffset=-1 yoffset=2 xadvance=2 page=0 chnl=0 +char id=59 x=111 y=121 width=5 height=11 xoffset=-1 yoffset=2 xadvance=2 page=0 chnl=0 +char id=60 x=87 y=307 width=9 height=9 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=61 x=99 y=349 width=9 height=5 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=62 x=96 y=307 width=9 height=9 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=63 x=116 y=121 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=64 x=81 y=287 width=11 height=10 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=0 +char id=65 x=0 y=133 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=66 x=10 y=133 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=67 x=18 y=133 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=68 x=27 y=133 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=69 x=37 y=133 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=70 x=45 y=133 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=71 x=53 y=133 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=72 x=63 y=133 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=73 x=123 y=121 width=4 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=74 x=72 y=133 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=75 x=78 y=133 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=76 x=87 y=133 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=77 x=95 y=133 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=78 x=106 y=133 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=79 x=115 y=133 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=80 x=0 y=144 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=81 x=16 y=42 width=10 height=13 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=82 x=8 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=83 x=17 y=144 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=84 x=25 y=144 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=85 x=34 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=86 x=43 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=87 x=52 y=144 width=13 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=88 x=65 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=89 x=74 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=90 x=83 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=91 x=26 y=42 width=6 height=13 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=92 x=92 y=144 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=93 x=122 y=28 width=5 height=13 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=94 x=0 y=317 width=9 height=8 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=95 x=70 y=356 width=8 height=3 xoffset=-1 yoffset=9 xadvance=6 page=0 chnl=0 +char id=96 x=16 y=356 width=5 height=4 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=97 x=9 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=98 x=99 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=99 x=17 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=100 x=108 y=144 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=101 x=25 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=102 x=116 y=144 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=103 x=0 y=155 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=104 x=8 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=105 x=122 y=144 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=106 x=0 y=0 width=6 height=14 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=107 x=16 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=108 x=123 y=82 width=4 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=109 x=33 y=317 width=12 height=8 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=110 x=45 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=111 x=53 y=317 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=112 x=24 y=155 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=113 x=33 y=155 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=114 x=62 y=317 width=6 height=8 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=0 +char id=115 x=68 y=317 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=116 x=92 y=287 width=6 height=10 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=117 x=75 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=118 x=83 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=119 x=91 y=317 width=11 height=8 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=120 x=102 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=121 x=41 y=155 width=8 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=122 x=110 y=317 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=123 x=32 y=42 width=6 height=13 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=124 x=6 y=0 width=3 height=14 xoffset=0 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=125 x=38 y=42 width=6 height=13 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=126 x=108 y=349 width=9 height=5 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=160 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=161 x=49 y=155 width=5 height=11 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=162 x=102 y=108 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=163 x=98 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=164 x=106 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=165 x=114 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=166 x=44 y=42 width=3 height=13 xoffset=0 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=167 x=110 y=108 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=168 x=21 y=356 width=6 height=4 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=169 x=0 y=297 width=10 height=10 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=170 x=43 y=349 width=6 height=6 xoffset=-1 yoffset=1 xadvance=4 page=0 chnl=0 +char id=171 x=7 y=349 width=7 height=7 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=172 x=49 y=349 width=9 height=6 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=173 x=78 y=356 width=6 height=3 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=0 +char id=174 x=14 y=349 width=7 height=7 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=175 x=84 y=356 width=6 height=3 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=176 x=58 y=349 width=6 height=6 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=177 x=10 y=297 width=9 height=10 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=178 x=121 y=325 width=6 height=7 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=179 x=117 y=317 width=6 height=8 xoffset=-1 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=180 x=27 y=356 width=5 height=4 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=181 x=54 y=155 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=182 x=118 y=108 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=183 x=32 y=356 width=4 height=4 xoffset=-1 yoffset=4 xadvance=2 page=0 chnl=0 +char id=184 x=117 y=349 width=5 height=5 xoffset=-1 yoffset=8 xadvance=4 page=0 chnl=0 +char id=185 x=121 y=341 width=5 height=7 xoffset=-1 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=186 x=64 y=349 width=7 height=6 xoffset=-1 yoffset=1 xadvance=4 page=0 chnl=0 +char id=187 x=21 y=349 width=7 height=7 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=188 x=19 y=297 width=11 height=10 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=189 x=30 y=297 width=11 height=10 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=190 x=41 y=297 width=11 height=10 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=191 x=63 y=155 width=7 height=11 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=192 x=47 y=42 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=193 x=57 y=42 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=194 x=67 y=42 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=195 x=9 y=0 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=7 page=0 chnl=0 +char id=196 x=77 y=42 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=197 x=19 y=0 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=7 page=0 chnl=0 +char id=198 x=70 y=155 width=13 height=11 xoffset=-2 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=199 x=29 y=0 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=200 x=87 y=42 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=201 x=95 y=42 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=202 x=103 y=42 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=203 x=111 y=42 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=204 x=119 y=42 width=6 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=205 x=0 y=56 width=6 height=13 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=206 x=6 y=56 width=7 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=207 x=13 y=56 width=7 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=208 x=83 y=155 width=11 height=11 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=209 x=38 y=0 width=9 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=210 x=20 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=211 x=30 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=212 x=40 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=213 x=47 y=0 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=214 x=50 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=215 x=105 y=307 width=9 height=9 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=216 x=0 y=121 width=10 height=12 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=217 x=60 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=218 x=69 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=219 x=78 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=220 x=87 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=221 x=96 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=222 x=94 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=223 x=102 y=155 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=224 x=111 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=225 x=119 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=226 x=0 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=227 x=8 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=228 x=16 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=229 x=24 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=230 x=0 y=325 width=11 height=8 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=231 x=32 y=166 width=8 height=11 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=232 x=40 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=233 x=48 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=234 x=56 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=235 x=64 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=236 x=72 y=166 width=5 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=237 x=77 y=166 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=238 x=83 y=166 width=6 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=239 x=89 y=166 width=7 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=240 x=96 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=241 x=104 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=242 x=112 y=166 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=243 x=0 y=177 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=244 x=9 y=177 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=245 x=18 y=177 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=246 x=27 y=177 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=247 x=11 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=248 x=52 y=297 width=9 height=10 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=249 x=36 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=250 x=44 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=251 x=52 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=252 x=60 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=253 x=57 y=0 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=254 x=65 y=0 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=255 x=74 y=0 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=256 x=105 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=257 x=61 y=297 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=258 x=82 y=0 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=7 page=0 chnl=0 +char id=259 x=68 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=260 x=92 y=0 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=261 x=76 y=177 width=8 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=262 x=115 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=263 x=84 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=264 x=0 y=69 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=265 x=92 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=266 x=9 y=69 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=267 x=100 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=268 x=18 y=69 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=269 x=108 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=270 x=27 y=69 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=271 x=116 y=177 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=272 x=0 y=188 width=11 height=11 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=273 x=11 y=188 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=274 x=37 y=69 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=275 x=69 y=297 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=276 x=102 y=0 width=8 height=14 xoffset=-1 yoffset=-4 xadvance=6 page=0 chnl=0 +char id=277 x=20 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=278 x=45 y=69 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=279 x=28 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=280 x=110 y=0 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=281 x=36 y=188 width=8 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=282 x=53 y=69 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=283 x=44 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=284 x=61 y=69 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=285 x=118 y=0 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=286 x=0 y=14 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=287 x=10 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=288 x=71 y=69 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=289 x=18 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=290 x=26 y=14 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=291 x=36 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=292 x=81 y=69 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=293 x=90 y=69 width=9 height=13 xoffset=-2 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=294 x=52 y=188 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=295 x=62 y=188 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=296 x=44 y=14 width=6 height=14 xoffset=-2 yoffset=-4 xadvance=3 page=0 chnl=0 +char id=297 x=121 y=166 width=6 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=298 x=99 y=69 width=5 height=13 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=299 x=122 y=287 width=5 height=10 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=300 x=50 y=14 width=6 height=14 xoffset=-2 yoffset=-4 xadvance=3 page=0 chnl=0 +char id=301 x=71 y=188 width=6 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=302 x=56 y=14 width=5 height=14 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=303 x=61 y=14 width=5 height=14 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=304 x=104 y=69 width=5 height=13 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=305 x=123 y=317 width=4 height=8 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=306 x=77 y=188 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=307 x=66 y=14 width=7 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=308 x=109 y=69 width=7 height=13 xoffset=-1 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=309 x=73 y=14 width=6 height=14 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=310 x=79 y=14 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=311 x=88 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=312 x=20 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=313 x=116 y=69 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=314 x=0 y=82 width=6 height=13 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=315 x=96 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=316 x=104 y=14 width=5 height=14 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=317 x=86 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=318 x=94 y=188 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=319 x=100 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=320 x=108 y=188 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=321 x=114 y=188 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=322 x=0 y=199 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=323 x=6 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=324 x=5 y=199 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=325 x=109 y=14 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=326 x=13 y=199 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=327 x=15 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=328 x=21 y=199 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=329 x=29 y=199 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=330 x=118 y=14 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=331 x=37 y=199 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=332 x=24 y=82 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=333 x=77 y=297 width=9 height=10 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=334 x=0 y=28 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=335 x=45 y=199 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=336 x=34 y=82 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=337 x=54 y=199 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=338 x=44 y=82 width=13 height=13 xoffset=-1 yoffset=-2 xadvance=11 page=0 chnl=0 +char id=339 x=28 y=325 width=12 height=8 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=340 x=57 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=341 x=63 y=199 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=342 x=10 y=28 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=343 x=69 y=199 width=6 height=11 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=0 +char id=344 x=66 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=345 x=75 y=199 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=346 x=75 y=82 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=347 x=81 y=199 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=348 x=83 y=82 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=349 x=88 y=199 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=350 x=19 y=28 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=351 x=95 y=199 width=7 height=11 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=352 x=91 y=82 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=353 x=102 y=199 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=354 x=27 y=28 width=9 height=14 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=355 x=99 y=82 width=6 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=356 x=105 y=82 width=9 height=13 xoffset=-2 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=357 x=109 y=199 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=358 x=116 y=199 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=359 x=86 y=297 width=6 height=10 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=360 x=36 y=28 width=9 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=361 x=0 y=210 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=362 x=114 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=363 x=92 y=297 width=8 height=10 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=364 x=45 y=28 width=9 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=365 x=8 y=210 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=366 x=54 y=28 width=9 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=367 x=16 y=210 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=368 x=0 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=369 x=24 y=210 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=370 x=63 y=28 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=371 x=32 y=210 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=372 x=9 y=95 width=13 height=13 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=373 x=41 y=210 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=374 x=22 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=375 x=72 y=28 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=376 x=31 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=377 x=40 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=378 x=52 y=210 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=379 x=49 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=380 x=59 y=210 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=381 x=58 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=382 x=66 y=210 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=894 x=73 y=210 width=5 height=11 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=900 x=36 y=356 width=4 height=4 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=901 x=40 y=356 width=7 height=4 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=902 x=78 y=210 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=903 x=47 y=356 width=5 height=4 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=904 x=88 y=210 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=905 x=97 y=210 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=906 x=107 y=210 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=908 x=112 y=210 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=910 x=0 y=221 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=911 x=11 y=221 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=912 x=22 y=221 width=7 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=913 x=29 y=221 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=914 x=39 y=221 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=915 x=47 y=221 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=916 x=55 y=221 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=917 x=65 y=221 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=918 x=73 y=221 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=919 x=82 y=221 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=920 x=91 y=221 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=921 x=123 y=188 width=4 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=922 x=101 y=221 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=923 x=110 y=221 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=924 x=0 y=232 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=925 x=11 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=926 x=20 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=927 x=29 y=232 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=928 x=39 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=929 x=48 y=232 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=931 x=56 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=932 x=65 y=232 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=933 x=74 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=934 x=10 y=121 width=11 height=12 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=935 x=83 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=936 x=92 y=232 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=937 x=102 y=232 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=938 x=67 y=95 width=7 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=939 x=74 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=940 x=113 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=941 x=0 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=942 x=80 y=28 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=943 x=120 y=221 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=944 x=8 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=945 x=40 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=946 x=88 y=28 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=947 x=16 y=243 width=9 height=11 xoffset=-2 yoffset=2 xadvance=6 page=0 chnl=0 +char id=948 x=25 y=243 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=949 x=49 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=950 x=83 y=95 width=7 height=13 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=951 x=34 y=243 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=952 x=42 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=953 x=57 y=325 width=5 height=8 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=954 x=62 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=955 x=50 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=956 x=58 y=243 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=957 x=70 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=958 x=90 y=95 width=8 height=13 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=959 x=78 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=960 x=87 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=961 x=67 y=243 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=962 x=100 y=297 width=7 height=10 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=963 x=96 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=964 x=105 y=325 width=8 height=8 xoffset=-2 yoffset=2 xadvance=5 page=0 chnl=0 +char id=965 x=113 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=966 x=21 y=121 width=10 height=12 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=967 x=76 y=243 width=8 height=11 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=968 x=98 y=95 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=969 x=0 y=333 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=970 x=107 y=297 width=7 height=10 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=971 x=114 y=297 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=972 x=84 y=243 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=973 x=93 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=974 x=101 y=243 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1025 x=108 y=95 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=1026 x=116 y=95 width=11 height=13 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1027 x=0 y=108 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=5 page=0 chnl=0 +char id=1028 x=111 y=243 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1029 x=0 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1030 x=123 y=210 width=4 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=1031 x=8 y=108 width=7 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=1032 x=120 y=243 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=1033 x=31 y=121 width=14 height=12 xoffset=-2 yoffset=-1 xadvance=11 page=0 chnl=0 +char id=1034 x=8 y=254 width=13 height=11 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=0 +char id=1035 x=21 y=254 width=11 height=11 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1036 x=15 y=108 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=1038 x=24 y=108 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=1039 x=97 y=28 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1040 x=32 y=254 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1041 x=42 y=254 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1042 x=51 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1043 x=59 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=1044 x=33 y=108 width=10 height=13 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1045 x=67 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1046 x=75 y=254 width=12 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1047 x=87 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1048 x=95 y=254 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1049 x=43 y=108 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=1050 x=104 y=254 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1051 x=113 y=254 width=10 height=11 xoffset=-2 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1052 x=0 y=265 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1053 x=11 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1054 x=20 y=265 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1055 x=30 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1056 x=39 y=265 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1057 x=47 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1058 x=56 y=265 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1059 x=65 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1060 x=45 y=121 width=11 height=12 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=1061 x=74 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1062 x=52 y=108 width=10 height=13 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1063 x=83 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1064 x=92 y=265 width=12 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1065 x=62 y=108 width=12 height=13 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1066 x=104 y=265 width=11 height=11 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1067 x=115 y=265 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=1068 x=0 y=276 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1069 x=9 y=276 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1070 x=18 y=276 width=12 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1071 x=30 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1072 x=10 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1073 x=38 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1074 x=18 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1075 x=26 y=333 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1076 x=0 y=307 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1077 x=33 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1078 x=41 y=333 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=1079 x=51 y=333 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1080 x=58 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1081 x=46 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1082 x=66 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1083 x=74 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1084 x=82 y=333 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=1085 x=92 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1086 x=100 y=333 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1087 x=109 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1088 x=54 y=276 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1089 x=117 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1090 x=0 y=341 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1091 x=63 y=276 width=8 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1092 x=106 y=28 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1093 x=7 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1094 x=8 y=307 width=9 height=10 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1095 x=15 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1096 x=23 y=341 width=10 height=8 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=1097 x=17 y=307 width=11 height=10 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=1098 x=33 y=341 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1099 x=42 y=341 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=1100 x=52 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1101 x=60 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1102 x=68 y=341 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=1103 x=78 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1105 x=71 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1106 x=74 y=108 width=9 height=13 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1107 x=79 y=276 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=1108 x=86 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1109 x=94 y=341 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1110 x=122 y=232 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=1111 x=86 y=276 width=7 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=1112 x=116 y=28 width=6 height=14 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=1113 x=114 y=307 width=11 height=9 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=1114 x=101 y=341 width=11 height=8 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=1115 x=93 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1116 x=101 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1118 x=0 y=42 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1119 x=28 y=307 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1168 x=83 y=108 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=5 page=0 chnl=0 +char id=1169 x=36 y=307 width=7 height=10 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=1241 x=112 y=341 width=9 height=8 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=0 +char id=8204 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=8211 x=90 y=356 width=8 height=3 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=0 +char id=8212 x=98 y=356 width=14 height=3 xoffset=-1 yoffset=4 xadvance=12 page=0 chnl=0 +char id=8216 x=71 y=349 width=5 height=6 xoffset=-1 yoffset=-2 xadvance=2 page=0 chnl=0 +char id=8217 x=76 y=349 width=5 height=6 xoffset=-1 yoffset=-2 xadvance=2 page=0 chnl=0 +char id=8218 x=122 y=349 width=5 height=5 xoffset=-1 yoffset=7 xadvance=2 page=0 chnl=0 +char id=8220 x=81 y=349 width=6 height=6 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=8221 x=87 y=349 width=6 height=6 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=8222 x=0 y=356 width=6 height=5 xoffset=-1 yoffset=7 xadvance=4 page=0 chnl=0 +char id=8224 x=56 y=121 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8225 x=64 y=121 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8226 x=6 y=356 width=5 height=5 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=8230 x=52 y=356 width=12 height=4 xoffset=0 yoffset=6 xadvance=12 page=0 chnl=0 +char id=8240 x=43 y=307 width=16 height=10 xoffset=-1 yoffset=0 xadvance=14 page=0 chnl=0 +char id=8249 x=28 y=349 width=5 height=7 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=8250 x=33 y=349 width=5 height=7 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=8260 x=59 y=307 width=11 height=10 xoffset=-3 yoffset=0 xadvance=1 page=0 chnl=0 +char id=8363 x=109 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8364 x=70 y=307 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +kernings count=2667 +kerning first=8216 second=281 amount=-1 +kerning first=356 second=232 amount=-1 +kerning first=39 second=961 amount=-1 +kerning first=34 second=74 amount=-1 +kerning first=8218 second=376 amount=-1 +kerning first=1027 second=1107 amount=-1 +kerning first=358 second=335 amount=-1 +kerning first=957 second=46 amount=-1 +kerning first=257 second=84 amount=-1 +kerning first=376 second=279 amount=-1 +kerning first=356 second=97 amount=-1 +kerning first=354 second=231 amount=-1 +kerning first=70 second=224 amount=-1 +kerning first=8216 second=937 amount=-1 +kerning first=1168 second=1040 amount=-1 +kerning first=76 second=87 amount=-1 +kerning first=932 second=940 amount=-1 +kerning first=354 second=93 amount=1 +kerning first=229 second=932 amount=-1 +kerning first=939 second=959 amount=-1 +kerning first=321 second=173 amount=-1 +kerning first=929 second=923 amount=-1 +kerning first=932 second=244 amount=-1 +kerning first=221 second=308 amount=-1 +kerning first=358 second=227 amount=-1 +kerning first=192 second=39 amount=-1 +kerning first=1043 second=1088 amount=-1 +kerning first=196 second=221 amount=-1 +kerning first=65 second=89 amount=-1 +kerning first=947 second=44 amount=-1 +kerning first=221 second=369 amount=-1 +kerning first=1027 second=187 amount=-1 +kerning first=196 second=84 amount=-1 +kerning first=8218 second=358 amount=-1 +kerning first=84 second=361 amount=-1 +kerning first=915 second=941 amount=-1 +kerning first=89 second=252 amount=-1 +kerning first=1043 second=1032 amount=-1 +kerning first=1043 second=44 amount=-1 +kerning first=932 second=260 amount=-1 +kerning first=89 second=173 amount=-1 +kerning first=8216 second=940 amount=-1 +kerning first=1168 second=1074 amount=-1 +kerning first=354 second=285 amount=-1 +kerning first=8216 second=244 amount=-1 +kerning first=8220 second=281 amount=-1 +kerning first=221 second=242 amount=-1 +kerning first=65 second=34 amount=-1 +kerning first=89 second=111 amount=-1 +kerning first=1059 second=1066 amount=1 +kerning first=84 second=251 amount=-1 +kerning first=109 second=356 amount=-1 +kerning first=933 second=45 amount=-1 +kerning first=1066 second=1059 amount=-1 +kerning first=902 second=39 amount=-1 +kerning first=1027 second=1085 amount=-1 +kerning first=319 second=8220 amount=-1 +kerning first=932 second=8249 amount=-1 +kerning first=358 second=287 amount=-1 +kerning first=8220 second=937 amount=-1 +kerning first=84 second=110 amount=-1 +kerning first=317 second=89 amount=-1 +kerning first=46 second=8220 amount=-1 +kerning first=315 second=376 amount=-1 +kerning first=923 second=356 amount=-1 +kerning first=39 second=74 amount=-1 +kerning first=91 second=372 amount=1 +kerning first=8221 second=111 amount=-1 +kerning first=915 second=916 amount=-1 +kerning first=45 second=376 amount=-1 +kerning first=227 second=354 amount=-1 +kerning first=354 second=308 amount=-1 +kerning first=171 second=933 amount=-1 +kerning first=932 second=948 amount=-1 +kerning first=356 second=361 amount=-1 +kerning first=8216 second=260 amount=-1 +kerning first=1100 second=8217 amount=-1 +kerning first=376 second=913 amount=-1 +kerning first=1033 second=1026 amount=-1 +kerning first=1058 second=1105 amount=-1 +kerning first=372 second=192 amount=-1 +kerning first=225 second=356 amount=-1 +kerning first=354 second=369 amount=-1 +kerning first=376 second=258 amount=-1 +kerning first=317 second=34 amount=-1 +kerning first=915 second=8250 amount=-1 +kerning first=102 second=39 amount=1 +kerning first=40 second=84 amount=1 +kerning first=923 second=8217 amount=-1 +kerning first=356 second=251 amount=-1 +kerning first=44 second=34 amount=-1 +kerning first=86 second=913 amount=-1 +kerning first=1038 second=1066 amount=1 +kerning first=1027 second=1169 amount=-1 +kerning first=80 second=916 amount=-1 +kerning first=84 second=328 amount=-1 +kerning first=358 second=365 amount=-1 +kerning first=8220 second=940 amount=-1 +kerning first=916 second=39 amount=-1 +kerning first=258 second=8216 amount=-1 +kerning first=356 second=110 amount=-1 +kerning first=915 second=949 amount=-1 +kerning first=354 second=242 amount=-1 +kerning first=315 second=358 amount=-1 +kerning first=86 second=258 amount=-1 +kerning first=89 second=224 amount=-1 +kerning first=8220 second=244 amount=-1 +kerning first=8216 second=948 amount=-1 +kerning first=45 second=358 amount=-1 +kerning first=933 second=8212 amount=-1 +kerning first=910 second=173 amount=-1 +kerning first=8222 second=356 amount=-1 +kerning first=1040 second=1058 amount=-1 +kerning first=971 second=39 amount=-1 +kerning first=358 second=941 amount=-1 +kerning first=84 second=228 amount=-1 +kerning first=8217 second=283 amount=-1 +kerning first=358 second=246 amount=-1 +kerning first=932 second=269 amount=-1 +kerning first=1043 second=1101 amount=-1 +kerning first=933 second=912 amount=1 +kerning first=1066 second=1038 amount=-1 +kerning first=932 second=117 amount=-1 +kerning first=89 second=339 amount=-1 +kerning first=358 second=105 amount=-1 +kerning first=87 second=301 amount=1 +kerning first=944 second=34 amount=-1 +kerning first=70 second=256 amount=-1 +kerning first=76 second=45 amount=-1 +kerning first=343 second=8230 amount=-1 +kerning first=8220 second=260 amount=-1 +kerning first=356 second=328 amount=-1 +kerning first=932 second=197 amount=-1 +kerning first=358 second=916 amount=-1 +kerning first=84 second=248 amount=-1 +kerning first=8221 second=339 amount=-1 +kerning first=1058 second=1083 amount=-1 +kerning first=1168 second=1087 amount=-1 +kerning first=89 second=275 amount=-1 +kerning first=933 second=193 amount=-1 +kerning first=1113 second=1090 amount=-1 +kerning first=197 second=89 amount=-1 +kerning first=195 second=376 amount=-1 +kerning first=8216 second=269 amount=-1 +kerning first=221 second=267 amount=-1 +kerning first=8217 second=349 amount=-1 +kerning first=356 second=228 amount=-1 +kerning first=228 second=932 amount=-1 +kerning first=955 second=39 amount=-1 +kerning first=932 second=341 amount=-1 +kerning first=1027 second=1098 amount=-1 +kerning first=84 second=279 amount=-1 +kerning first=194 second=39 amount=-1 +kerning first=8221 second=275 amount=-1 +kerning first=8220 second=948 amount=-1 +kerning first=65 second=8220 amount=-1 +kerning first=193 second=221 amount=-1 +kerning first=376 second=115 amount=-1 +kerning first=915 second=195 amount=-1 +kerning first=8216 second=197 amount=-1 +kerning first=345 second=46 amount=-1 +kerning first=932 second=963 amount=-1 +kerning first=193 second=84 amount=-1 +kerning first=197 second=34 amount=-1 +kerning first=932 second=235 amount=-1 +kerning first=358 second=949 amount=-1 +kerning first=356 second=248 amount=-1 +kerning first=321 second=372 amount=-1 +kerning first=1058 second=1119 amount=-1 +kerning first=319 second=356 amount=-1 +kerning first=324 second=354 amount=-1 +kerning first=376 second=196 amount=-1 +kerning first=8217 second=101 amount=-1 +kerning first=1043 second=1080 amount=-1 +kerning first=354 second=380 amount=-1 +kerning first=187 second=932 amount=-1 +kerning first=76 second=8212 amount=-1 +kerning first=929 second=260 amount=-1 +kerning first=936 second=46 amount=-1 +kerning first=1034 second=1035 amount=-1 +kerning first=915 second=8230 amount=-1 +kerning first=195 second=358 amount=-1 +kerning first=86 second=196 amount=-1 +kerning first=308 second=93 amount=1 +kerning first=356 second=279 amount=-1 +kerning first=358 second=378 amount=-1 +kerning first=80 second=195 amount=-1 +kerning first=376 second=333 amount=-1 +kerning first=317 second=8220 amount=-1 +kerning first=89 second=243 amount=-1 +kerning first=8217 second=46 amount=-2 +kerning first=8216 second=963 amount=-1 +kerning first=44 second=8220 amount=-1 +kerning first=313 second=376 amount=-1 +kerning first=319 second=8217 amount=-1 +kerning first=354 second=267 amount=-1 +kerning first=932 second=41 amount=1 +kerning first=8216 second=235 amount=-1 +kerning first=8220 second=269 amount=-1 +kerning first=8212 second=356 amount=-1 +kerning first=46 second=8217 amount=-1 +kerning first=224 second=354 amount=-1 +kerning first=84 second=969 amount=-1 +kerning first=1059 second=1058 amount=1 +kerning first=1091 second=46 amount=-1 +kerning first=102 second=93 amount=1 +kerning first=84 second=241 amount=-1 +kerning first=8221 second=243 amount=-1 +kerning first=8216 second=8216 amount=-1 +kerning first=376 second=233 amount=-1 +kerning first=1027 second=1077 amount=-1 +kerning first=1098 second=8217 amount=-1 +kerning first=8230 second=8221 amount=-1 +kerning first=358 second=265 amount=-1 +kerning first=80 second=8230 amount=-2 +kerning first=8221 second=103 amount=-1 +kerning first=70 second=192 amount=-1 +kerning first=8220 second=197 amount=-1 +kerning first=91 second=354 amount=1 +kerning first=45 second=910 amount=-1 +kerning first=923 second=86 amount=-1 +kerning first=89 second=256 amount=-1 +kerning first=84 second=913 amount=-1 +kerning first=1168 second=173 amount=-1 +kerning first=1035 second=1066 amount=-1 +kerning first=936 second=198 amount=-1 +kerning first=1058 second=1096 amount=-1 +kerning first=358 second=195 amount=-1 +kerning first=271 second=311 amount=1 +kerning first=912 second=950 amount=1 +kerning first=84 second=258 amount=-1 +kerning first=313 second=358 amount=-1 +kerning first=354 second=343 amount=-1 +kerning first=8221 second=256 amount=-1 +kerning first=1168 second=1100 amount=-1 +kerning first=913 second=221 amount=-1 +kerning first=939 second=65 amount=-1 +kerning first=89 second=171 amount=-1 +kerning first=1059 second=1092 amount=-1 +kerning first=356 second=969 amount=-1 +kerning first=84 second=307 amount=-1 +kerning first=356 second=241 amount=-1 +kerning first=1038 second=1058 amount=1 +kerning first=913 second=84 amount=-1 +kerning first=932 second=367 amount=-1 +kerning first=260 second=39 amount=-1 +kerning first=8217 second=198 amount=-1 +kerning first=358 second=345 amount=-1 +kerning first=8220 second=963 amount=-1 +kerning first=104 second=358 amount=-1 +kerning first=256 second=221 amount=-1 +kerning first=354 second=237 amount=-1 +kerning first=358 second=8230 amount=-1 +kerning first=8220 second=235 amount=-1 +kerning first=910 second=962 amount=-1 +kerning first=315 second=173 amount=-1 +kerning first=109 second=932 amount=-1 +kerning first=974 second=34 amount=-1 +kerning first=123 second=106 amount=1 +kerning first=932 second=972 amount=-1 +kerning first=256 second=84 amount=-1 +kerning first=356 second=913 amount=-1 +kerning first=932 second=250 amount=-1 +kerning first=341 second=8230 amount=-1 +kerning first=8220 second=8216 amount=-1 +kerning first=8222 second=86 amount=-1 +kerning first=936 second=194 amount=-1 +kerning first=939 second=966 amount=-1 +kerning first=358 second=232 amount=-1 +kerning first=923 second=932 amount=-1 +kerning first=929 second=197 amount=-1 +kerning first=329 second=356 amount=-1 +kerning first=933 second=941 amount=-1 +kerning first=1043 second=1093 amount=-1 +kerning first=65 second=356 amount=-1 +kerning first=356 second=258 amount=-1 +kerning first=932 second=109 amount=-1 +kerning first=123 second=1095 amount=-1 +kerning first=358 second=97 amount=-1 +kerning first=197 second=8220 amount=-1 +kerning first=356 second=307 amount=-1 +kerning first=1038 second=1092 amount=-1 +kerning first=196 second=89 amount=-1 +kerning first=192 second=376 amount=-1 +kerning first=8250 second=221 amount=-1 +kerning first=8217 second=194 amount=-1 +kerning first=225 second=932 amount=-1 +kerning first=910 second=256 amount=-1 +kerning first=261 second=358 amount=-1 +kerning first=376 second=363 amount=-1 +kerning first=915 second=973 amount=-1 +kerning first=8250 second=84 amount=-1 +kerning first=1058 second=1075 amount=-1 +kerning first=173 second=354 amount=-1 +kerning first=933 second=916 amount=-1 +kerning first=8216 second=972 amount=-1 +kerning first=1168 second=1079 amount=-1 +kerning first=354 second=301 amount=-1 +kerning first=89 second=263 amount=-1 +kerning first=34 second=193 amount=-1 +kerning first=221 second=252 amount=-1 +kerning first=65 second=8217 amount=-1 +kerning first=221 second=173 amount=-1 +kerning first=939 second=44 amount=-1 +kerning first=84 second=382 amount=-1 +kerning first=8217 second=337 amount=-1 +kerning first=1090 second=8230 amount=-1 +kerning first=196 second=34 amount=-1 +kerning first=932 second=324 amount=-1 +kerning first=221 second=111 amount=-1 +kerning first=376 second=245 amount=-1 +kerning first=1027 second=1090 amount=-1 +kerning first=321 second=8221 amount=-1 +kerning first=317 second=356 amount=-1 +kerning first=8221 second=263 amount=-1 +kerning first=84 second=115 amount=-1 +kerning first=89 second=192 amount=-1 +kerning first=8222 second=932 amount=-1 +kerning first=110 second=354 amount=-1 +kerning first=934 second=46 amount=-1 +kerning first=192 second=358 amount=-1 +kerning first=902 second=376 amount=-1 +kerning first=8217 second=231 amount=-1 +kerning first=70 second=74 amount=-1 +kerning first=932 second=226 amount=-1 +kerning first=84 second=196 amount=-1 +kerning first=8221 second=192 amount=-1 +kerning first=321 second=354 amount=-1 +kerning first=1027 second=46 amount=-1 +kerning first=1043 second=1072 amount=-1 +kerning first=933 second=949 amount=-1 +kerning first=1168 second=1114 amount=-1 +kerning first=319 second=86 amount=-1 +kerning first=271 second=8221 amount=1 +kerning first=331 second=358 amount=-1 +kerning first=1034 second=8217 amount=-1 +kerning first=317 second=8217 amount=-1 +kerning first=44 second=8217 amount=-1 +kerning first=226 second=354 amount=-1 +kerning first=356 second=382 amount=-1 +kerning first=84 second=333 amount=-1 +kerning first=358 second=361 amount=-1 +kerning first=8220 second=972 amount=-1 +kerning first=123 second=358 amount=1 +kerning first=356 second=115 amount=-1 +kerning first=8221 second=8221 amount=-1 +kerning first=354 second=252 amount=-1 +kerning first=89 second=234 amount=-1 +kerning first=8218 second=372 amount=-1 +kerning first=915 second=954 amount=-1 +kerning first=354 second=173 amount=-1 +kerning first=221 second=224 amount=-1 +kerning first=902 second=358 amount=-1 +kerning first=354 second=111 amount=-1 +kerning first=87 second=256 amount=-1 +kerning first=84 second=959 amount=-1 +kerning first=932 second=331 amount=-1 +kerning first=84 second=233 amount=-1 +kerning first=356 second=196 amount=-1 +kerning first=8217 second=285 amount=-1 +kerning first=358 second=251 amount=-1 +kerning first=39 second=193 amount=-1 +kerning first=372 second=239 amount=1 +kerning first=932 second=283 amount=-1 +kerning first=8221 second=234 amount=-1 +kerning first=923 second=939 amount=-1 +kerning first=1043 second=1107 amount=-1 +kerning first=1033 second=1066 amount=-1 +kerning first=932 second=122 amount=-1 +kerning first=358 second=110 amount=-1 +kerning first=97 second=84 amount=-1 +kerning first=910 second=192 amount=-1 +kerning first=91 second=87 amount=1 +kerning first=319 second=932 amount=-1 +kerning first=221 second=339 amount=-1 +kerning first=1035 second=1058 amount=-1 +kerning first=356 second=333 amount=-1 +kerning first=939 second=923 amount=-1 +kerning first=258 second=39 amount=-1 +kerning first=8217 second=308 amount=-1 +kerning first=1058 second=1088 amount=-1 +kerning first=376 second=230 amount=-1 +kerning first=1168 second=1092 amount=-1 +kerning first=933 second=195 amount=-1 +kerning first=313 second=173 amount=-1 +kerning first=197 second=356 amount=-1 +kerning first=356 second=959 amount=-1 +kerning first=973 second=34 amount=-1 +kerning first=221 second=275 amount=-1 +kerning first=356 second=233 amount=-1 +kerning first=8216 second=283 amount=-1 +kerning first=916 second=358 amount=-1 +kerning first=932 second=349 amount=-1 +kerning first=1027 second=1103 amount=-1 +kerning first=1043 second=187 amount=-1 +kerning first=84 second=291 amount=-1 +kerning first=8221 second=289 amount=-1 +kerning first=76 second=221 amount=-1 +kerning first=358 second=328 amount=-1 +kerning first=295 second=356 amount=-1 +kerning first=376 second=271 amount=-1 +kerning first=8211 second=376 amount=-1 +kerning first=1058 second=44 amount=-1 +kerning first=354 second=224 amount=-1 +kerning first=8212 second=932 amount=-1 +kerning first=70 second=225 amount=-1 +kerning first=910 second=961 amount=-1 +kerning first=1058 second=1032 amount=-1 +kerning first=76 second=84 amount=-1 +kerning first=196 second=8220 amount=-1 +kerning first=315 second=372 amount=-1 +kerning first=933 second=8230 amount=-1 +kerning first=8217 second=242 amount=-1 +kerning first=89 second=74 amount=-1 +kerning first=193 second=89 amount=-1 +kerning first=932 second=236 amount=-1 +kerning first=194 second=376 amount=-1 +kerning first=197 second=8217 amount=-1 +kerning first=1169 second=44 amount=-1 +kerning first=1027 second=59 amount=-1 +kerning first=358 second=228 amount=-1 +kerning first=1043 second=1085 amount=-1 +kerning first=34 second=941 amount=-1 +kerning first=259 second=358 amount=-1 +kerning first=932 second=101 amount=-1 +kerning first=89 second=371 amount=-1 +kerning first=65 second=86 amount=-1 +kerning first=8221 second=74 amount=-1 +kerning first=354 second=339 amount=-1 +kerning first=376 second=65 amount=-1 +kerning first=8230 second=933 amount=-1 +kerning first=84 second=363 amount=-1 +kerning first=193 second=34 amount=-1 +kerning first=356 second=291 amount=-1 +kerning first=8211 second=358 amount=-1 +kerning first=376 second=347 amount=-1 +kerning first=354 second=312 amount=-1 +kerning first=358 second=248 amount=-1 +kerning first=89 second=353 amount=-1 +kerning first=241 second=356 amount=-1 +kerning first=86 second=65 amount=-1 +kerning first=34 second=916 amount=-1 +kerning first=87 second=192 amount=-1 +kerning first=271 second=108 amount=1 +kerning first=354 second=275 amount=-1 +kerning first=932 second=46 amount=-1 +kerning first=8220 second=283 amount=-1 +kerning first=221 second=243 amount=-1 +kerning first=195 second=936 amount=-1 +kerning first=194 second=358 amount=-1 +kerning first=84 second=245 amount=-1 +kerning first=8221 second=353 amount=-1 +kerning first=8216 second=101 amount=-1 +kerning first=1043 second=1169 amount=-1 +kerning first=932 second=297 amount=-1 +kerning first=1027 second=1082 amount=-1 +kerning first=321 second=8211 amount=-1 +kerning first=358 second=279 amount=-1 +kerning first=915 second=913 amount=-1 +kerning first=317 second=86 amount=-1 +kerning first=40 second=309 amount=1 +kerning first=376 second=99 amount=-1 +kerning first=932 second=945 amount=-1 +kerning first=329 second=932 amount=-1 +kerning first=915 second=258 amount=-1 +kerning first=1168 second=1241 amount=-1 +kerning first=65 second=932 amount=-1 +kerning first=356 second=363 amount=-1 +kerning first=46 second=939 amount=-1 +kerning first=221 second=256 amount=-1 +kerning first=1058 second=1101 amount=-1 +kerning first=372 second=193 amount=-1 +kerning first=8216 second=46 amount=-1 +kerning first=34 second=949 amount=-1 +kerning first=321 second=87 amount=-1 +kerning first=912 second=955 amount=1 +kerning first=1027 second=1026 amount=1 +kerning first=89 second=8211 amount=-1 +kerning first=376 second=44 amount=-1 +kerning first=39 second=941 amount=-1 +kerning first=356 second=245 amount=-1 +kerning first=913 second=89 amount=-1 +kerning first=221 second=171 amount=-1 +kerning first=195 second=372 amount=-1 +kerning first=80 second=913 amount=-1 +kerning first=257 second=356 amount=-1 +kerning first=932 second=198 amount=-1 +kerning first=354 second=962 amount=-1 +kerning first=173 second=933 amount=-1 +kerning first=1027 second=1118 amount=-1 +kerning first=915 second=946 amount=-1 +kerning first=8218 second=354 amount=-1 +kerning first=354 second=243 amount=-1 +kerning first=89 second=225 amount=-1 +kerning first=910 second=970 amount=1 +kerning first=8212 second=939 amount=-1 +kerning first=8216 second=945 amount=-1 +kerning first=80 second=258 amount=-1 +kerning first=86 second=44 amount=-1 +kerning first=256 second=89 amount=-1 +kerning first=260 second=376 amount=-1 +kerning first=354 second=103 amount=-1 +kerning first=8220 second=101 amount=-1 +kerning first=317 second=932 amount=-1 +kerning first=939 second=940 amount=-1 +kerning first=358 second=969 amount=-1 +kerning first=39 second=916 amount=-1 +kerning first=8217 second=267 amount=-1 +kerning first=1033 second=1058 amount=-1 +kerning first=358 second=241 amount=-1 +kerning first=913 second=34 amount=-1 +kerning first=932 second=261 amount=-1 +kerning first=293 second=358 amount=-1 +kerning first=357 second=8221 amount=1 +kerning first=1043 second=1098 amount=-1 +kerning first=932 second=114 amount=-1 +kerning first=926 second=912 amount=1 +kerning first=8204 second=902 amount=-1 +kerning first=196 second=356 amount=-1 +kerning first=354 second=256 amount=-1 +kerning first=8216 second=198 amount=-1 +kerning first=256 second=34 amount=-1 +kerning first=8220 second=46 amount=-1 +kerning first=932 second=194 amount=-1 +kerning first=358 second=913 amount=-1 +kerning first=1068 second=1026 amount=-1 +kerning first=84 second=230 amount=-1 +kerning first=89 second=273 amount=-1 +kerning first=1058 second=1080 amount=-1 +kerning first=8250 second=89 amount=-1 +kerning first=1056 second=44 amount=-2 +kerning first=1168 second=1084 amount=-1 +kerning first=1056 second=1032 amount=-1 +kerning first=939 second=260 amount=-1 +kerning first=922 second=970 amount=1 +kerning first=89 second=277 amount=-1 +kerning first=358 second=258 amount=-1 +kerning first=34 second=195 amount=-1 +kerning first=8221 second=8204 amount=-1 +kerning first=260 second=358 amount=-1 +kerning first=354 second=171 amount=-1 +kerning first=315 second=8221 amount=-1 +kerning first=1059 second=1076 amount=-1 +kerning first=313 second=372 amount=-1 +kerning first=193 second=8220 amount=-1 +kerning first=197 second=86 amount=-1 +kerning first=39 second=949 amount=-1 +kerning first=221 second=263 amount=-1 +kerning first=910 second=8211 amount=-1 +kerning first=8221 second=273 amount=-1 +kerning first=196 second=8217 amount=-1 +kerning first=358 second=307 amount=-1 +kerning first=932 second=337 amount=-1 +kerning first=376 second=249 amount=-1 +kerning first=160 second=8216 amount=-1 +kerning first=8211 second=910 amount=-1 +kerning first=84 second=271 amount=-1 +kerning first=8221 second=277 amount=-1 +kerning first=1027 second=1095 amount=-1 +kerning first=8220 second=945 amount=-1 +kerning first=376 second=259 amount=-1 +kerning first=915 second=196 amount=-1 +kerning first=315 second=354 amount=-1 +kerning first=34 second=8230 amount=-1 +kerning first=8216 second=194 amount=-1 +kerning first=221 second=192 amount=-1 +kerning first=1107 second=46 amount=-1 +kerning first=45 second=354 amount=-1 +kerning first=932 second=231 amount=-1 +kerning first=65 second=939 amount=-1 +kerning first=939 second=948 amount=-1 +kerning first=356 second=230 amount=-1 +kerning first=376 second=923 amount=-1 +kerning first=1114 second=8217 amount=-1 +kerning first=1043 second=1077 amount=-1 +kerning first=1027 second=1040 amount=-1 +kerning first=932 second=93 amount=1 +kerning first=89 second=351 amount=-1 +kerning first=84 second=65 amount=-1 +kerning first=40 second=356 amount=1 +kerning first=929 second=46 amount=-2 +kerning first=8220 second=198 amount=-1 +kerning first=8216 second=337 amount=-1 +kerning first=192 second=936 amount=-1 +kerning first=1038 second=1076 amount=-1 +kerning first=86 second=923 amount=-1 +kerning first=84 second=347 amount=-1 +kerning first=356 second=271 amount=-1 +kerning first=8221 second=351 amount=-1 +kerning first=80 second=196 amount=-1 +kerning first=197 second=932 amount=-1 +kerning first=915 second=959 amount=-1 +kerning first=89 second=239 amount=1 +kerning first=321 second=45 amount=-1 +kerning first=354 second=263 amount=-1 +kerning first=70 second=257 amount=-1 +kerning first=8216 second=231 amount=-1 +kerning first=221 second=234 amount=-1 +kerning first=89 second=100 amount=-1 +kerning first=84 second=966 amount=-1 +kerning first=295 second=932 amount=-1 +kerning first=84 second=238 amount=-1 +kerning first=39 second=195 amount=-1 +kerning first=358 second=382 amount=-1 +kerning first=44 second=939 amount=-1 +kerning first=932 second=285 amount=-1 +kerning first=376 second=229 amount=-1 +kerning first=1027 second=1074 amount=-1 +kerning first=84 second=99 amount=-1 +kerning first=8221 second=100 amount=-1 +kerning first=356 second=65 amount=-1 +kerning first=354 second=192 amount=-1 +kerning first=70 second=193 amount=-1 +kerning first=358 second=115 amount=-1 +kerning first=8220 second=194 amount=-1 +kerning first=8204 second=221 amount=-1 +kerning first=915 second=181 amount=-1 +kerning first=902 second=936 amount=-1 +kerning first=913 second=8220 amount=-1 +kerning first=227 second=84 amount=-1 +kerning first=89 second=45 amount=-1 +kerning first=1035 second=1063 amount=-1 +kerning first=356 second=347 amount=-1 +kerning first=195 second=8221 amount=-1 +kerning first=192 second=372 amount=-1 +kerning first=939 second=197 amount=-1 +kerning first=1058 second=1093 amount=-1 +kerning first=39 second=8230 amount=-1 +kerning first=929 second=198 amount=-1 +kerning first=358 second=196 amount=-1 +kerning first=1075 second=44 amount=-1 +kerning first=932 second=308 amount=-1 +kerning first=8216 second=1026 amount=1 +kerning first=1168 second=1097 amount=-1 +kerning first=8220 second=337 amount=-1 +kerning first=256 second=8220 amount=-1 +kerning first=84 second=44 amount=-1 +kerning first=1059 second=1089 amount=-1 +kerning first=356 second=966 amount=-1 +kerning first=258 second=376 amount=-1 +kerning first=8216 second=285 amount=-1 +kerning first=356 second=238 amount=-1 +kerning first=241 second=932 amount=-1 +kerning first=932 second=369 amount=-1 +kerning first=195 second=354 amount=-1 +kerning first=321 second=8212 amount=-1 +kerning first=84 second=299 amount=-1 +kerning first=358 second=333 amount=-1 +kerning first=354 second=961 amount=-1 +kerning first=356 second=99 amount=-1 +kerning first=376 second=281 amount=-1 +kerning first=354 second=234 amount=-1 +kerning first=70 second=227 amount=-1 +kerning first=8220 second=231 amount=-1 +kerning first=376 second=125 amount=1 +kerning first=123 second=372 amount=1 +kerning first=8218 second=87 amount=-1 +kerning first=76 second=89 amount=-1 +kerning first=193 second=356 amount=-1 +kerning first=916 second=936 amount=-1 +kerning first=939 second=963 amount=-1 +kerning first=932 second=242 amount=-1 +kerning first=8216 second=308 amount=-1 +kerning first=358 second=959 amount=-1 +kerning first=902 second=372 amount=-1 +kerning first=358 second=233 amount=-1 +kerning first=929 second=194 amount=-1 +kerning first=221 second=74 amount=-1 +kerning first=8217 second=111 amount=-1 +kerning first=86 second=125 amount=1 +kerning first=1043 second=1090 amount=-1 +kerning first=114 second=8230 amount=-1 +kerning first=1168 second=8211 amount=-1 +kerning first=1066 second=1026 amount=-1 +kerning first=356 second=44 amount=-1 +kerning first=89 second=8212 amount=-1 +kerning first=947 second=46 amount=-1 +kerning first=1033 second=8221 amount=-1 +kerning first=258 second=358 amount=-1 +kerning first=313 second=8221 amount=-1 +kerning first=221 second=371 amount=-1 +kerning first=1038 second=1089 amount=-1 +kerning first=196 second=86 amount=-1 +kerning first=76 second=34 amount=-1 +kerning first=356 second=299 amount=-1 +kerning first=193 second=8217 amount=-1 +kerning first=8220 second=1026 amount=1 +kerning first=197 second=939 amount=-1 +kerning first=915 second=943 amount=-1 +kerning first=910 second=45 amount=-1 +kerning first=1058 second=1072 amount=-1 +kerning first=1043 second=46 amount=-1 +kerning first=933 second=913 amount=-1 +kerning first=1168 second=1076 amount=-1 +kerning first=354 second=289 amount=-1 +kerning first=89 second=257 amount=-1 +kerning first=8216 second=242 amount=-1 +kerning first=8220 second=285 amount=-1 +kerning first=221 second=353 amount=-1 +kerning first=89 second=113 amount=-1 +kerning first=315 second=8211 amount=-1 +kerning first=257 second=932 amount=-1 +kerning first=313 second=354 amount=-1 +kerning first=84 second=974 amount=-1 +kerning first=933 second=258 amount=-1 +kerning first=84 second=249 amount=-1 +kerning first=376 second=244 amount=-1 +kerning first=1027 second=1087 amount=-1 +kerning first=84 second=259 amount=-1 +kerning first=358 second=291 amount=-1 +kerning first=84 second=112 amount=-1 +kerning first=8221 second=113 amount=-1 +kerning first=89 second=193 amount=-1 +kerning first=104 second=354 amount=-1 +kerning first=923 second=8216 amount=-1 +kerning first=8220 second=308 amount=-1 +kerning first=1026 second=1035 amount=-1 +kerning first=194 second=936 amount=-1 +kerning first=354 second=74 amount=-1 +kerning first=315 second=87 amount=-1 +kerning first=84 second=923 amount=-1 +kerning first=8221 second=193 amount=-1 +kerning first=1058 second=1107 amount=-1 +kerning first=372 second=195 amount=-1 +kerning first=196 second=932 amount=-1 +kerning first=1168 second=1111 amount=-1 +kerning first=87 second=239 amount=1 +kerning first=8216 second=1040 amount=-1 +kerning first=324 second=84 amount=-1 +kerning first=354 second=371 amount=-1 +kerning first=89 second=335 amount=-1 +kerning first=376 second=260 amount=-1 +kerning first=356 second=974 amount=-1 +kerning first=913 second=356 amount=-1 +kerning first=40 second=86 amount=1 +kerning first=910 second=8212 amount=-1 +kerning first=356 second=249 amount=-1 +kerning first=221 second=8211 amount=-1 +kerning first=932 second=380 amount=-1 +kerning first=8217 second=339 amount=-1 +kerning first=84 second=326 amount=-1 +kerning first=8221 second=335 amount=-1 +kerning first=356 second=259 amount=-1 +kerning first=358 second=363 amount=-1 +kerning first=356 second=112 amount=-1 +kerning first=915 second=951 amount=-1 +kerning first=354 second=353 amount=-1 +kerning first=86 second=260 amount=-1 +kerning first=910 second=912 amount=1 +kerning first=372 second=8230 amount=-1 +kerning first=89 second=227 amount=-1 +kerning first=376 second=8249 amount=-1 +kerning first=256 second=356 amount=-1 +kerning first=261 second=354 amount=-1 +kerning first=8220 second=242 amount=-1 +kerning first=221 second=225 amount=-1 +kerning first=356 second=923 amount=-1 +kerning first=939 second=972 amount=-1 +kerning first=1058 second=187 amount=-1 +kerning first=224 second=84 amount=-1 +kerning first=84 second=229 amount=-1 +kerning first=8217 second=275 amount=-1 +kerning first=358 second=245 amount=-1 +kerning first=1033 second=1063 amount=-1 +kerning first=913 second=8217 amount=-1 +kerning first=194 second=372 amount=-1 +kerning first=192 second=8221 amount=-1 +kerning first=932 second=267 amount=-1 +kerning first=1043 second=1103 amount=-1 +kerning first=929 second=308 amount=-1 +kerning first=1034 second=1059 amount=-1 +kerning first=45 second=933 amount=-1 +kerning first=910 second=193 amount=-1 +kerning first=91 second=84 amount=1 +kerning first=256 second=8217 amount=-1 +kerning first=356 second=326 amount=-1 +kerning first=8250 second=356 amount=-1 +kerning first=192 second=354 amount=-1 +kerning first=1043 second=59 amount=-1 +kerning first=40 second=932 amount=1 +kerning first=968 second=39 amount=-1 +kerning first=1168 second=1089 amount=-1 +kerning first=1058 second=1085 amount=-1 +kerning first=8220 second=1040 amount=-1 +kerning first=922 second=912 amount=1 +kerning first=76 second=8220 amount=-1 +kerning first=933 second=196 amount=-1 +kerning first=221 second=273 amount=-1 +kerning first=1027 second=173 amount=-1 +kerning first=354 second=8211 amount=-1 +kerning first=331 second=354 amount=-1 +kerning first=8216 second=267 amount=-1 +kerning first=221 second=277 amount=-1 +kerning first=356 second=229 amount=-1 +kerning first=1100 second=1098 amount=-1 +kerning first=902 second=8221 amount=-1 +kerning first=932 second=343 amount=-1 +kerning first=1027 second=1100 amount=-1 +kerning first=84 second=281 amount=-1 +kerning first=8221 second=287 amount=-1 +kerning first=195 second=87 amount=-1 +kerning first=84 second=125 amount=1 +kerning first=376 second=269 amount=-1 +kerning first=354 second=225 amount=-1 +kerning first=1168 second=45 amount=-1 +kerning first=376 second=117 amount=-1 +kerning first=123 second=354 amount=1 +kerning first=260 second=936 amount=-1 +kerning first=8217 second=243 amount=-1 +kerning first=193 second=86 amount=-1 +kerning first=932 second=237 amount=-1 +kerning first=915 second=65 amount=-1 +kerning first=1068 second=1066 amount=-1 +kerning first=902 second=354 amount=-1 +kerning first=343 second=44 amount=-1 +kerning first=376 second=197 amount=-1 +kerning first=8217 second=103 amount=-1 +kerning first=196 second=939 amount=-1 +kerning first=936 second=256 amount=-1 +kerning first=933 second=959 amount=-1 +kerning first=319 second=8216 amount=-1 +kerning first=8249 second=910 amount=-1 +kerning first=34 second=969 amount=-1 +kerning first=89 second=365 amount=-1 +kerning first=1043 second=1082 amount=-1 +kerning first=1058 second=1169 amount=-1 +kerning first=46 second=8216 amount=-1 +kerning first=354 second=305 amount=-1 +kerning first=1034 second=1038 amount=-1 +kerning first=102 second=8221 amount=1 +kerning first=221 second=351 amount=-1 +kerning first=313 second=8211 amount=-1 +kerning first=86 second=197 amount=-1 +kerning first=315 second=45 amount=-1 +kerning first=356 second=281 amount=-1 +kerning first=173 second=221 amount=-1 +kerning first=916 second=8221 amount=-1 +kerning first=8217 second=256 amount=-1 +kerning first=356 second=125 amount=1 +kerning first=915 second=966 amount=-1 +kerning first=89 second=246 amount=-1 +kerning first=358 second=230 amount=-1 +kerning first=354 second=273 amount=-1 +kerning first=1043 second=1026 amount=1 +kerning first=34 second=913 amount=-1 +kerning first=87 second=193 amount=-1 +kerning first=354 second=277 amount=-1 +kerning first=173 second=84 amount=-1 +kerning first=80 second=65 amount=-1 +kerning first=221 second=239 amount=1 +kerning first=8220 second=267 amount=-1 +kerning first=195 second=933 amount=-1 +kerning first=84 second=940 amount=-1 +kerning first=34 second=258 amount=-1 +kerning first=313 second=87 amount=-1 +kerning first=84 second=244 amount=-1 +kerning first=260 second=372 amount=-1 +kerning first=8221 second=246 amount=-1 +kerning first=932 second=301 amount=-1 +kerning first=376 second=235 amount=-1 +kerning first=221 second=100 amount=-1 +kerning first=916 second=354 amount=-1 +kerning first=1027 second=1079 amount=-1 +kerning first=1043 second=1118 amount=-1 +kerning first=1168 second=8212 amount=-1 +kerning first=358 second=271 amount=-1 +kerning first=97 second=356 amount=-1 +kerning first=193 second=932 amount=-1 +kerning first=70 second=195 amount=-1 +kerning first=110 second=84 amount=-1 +kerning first=321 second=221 amount=-1 +kerning first=8204 second=89 amount=-1 +kerning first=915 second=44 amount=-1 +kerning first=271 second=318 amount=1 +kerning first=326 second=358 amount=-1 +kerning first=221 second=45 amount=-1 +kerning first=1058 second=1098 amount=-1 +kerning first=321 second=84 amount=-1 +kerning first=1168 second=1102 amount=-1 +kerning first=84 second=260 amount=-1 +kerning first=354 second=351 amount=-1 +kerning first=259 second=354 amount=-1 +kerning first=315 second=8212 amount=-1 +kerning first=70 second=8230 amount=-1 +kerning first=358 second=65 amount=-1 +kerning first=356 second=940 amount=-1 +kerning first=376 second=41 amount=1 +kerning first=39 second=969 amount=-1 +kerning first=356 second=244 amount=-1 +kerning first=913 second=86 amount=-1 +kerning first=955 second=8221 amount=-1 +kerning first=226 second=84 amount=-1 +kerning first=1027 second=1114 amount=-1 +kerning first=194 second=8221 amount=-1 +kerning first=358 second=347 amount=-1 +kerning first=84 second=8249 amount=-1 +kerning first=354 second=239 amount=-1 +kerning first=910 second=941 amount=-1 +kerning first=1168 second=58 amount=-1 +kerning first=76 second=356 amount=-1 +kerning first=86 second=41 amount=1 +kerning first=8211 second=354 amount=-1 +kerning first=80 second=44 amount=-2 +kerning first=256 second=86 amount=-1 +kerning first=354 second=100 amount=-1 +kerning first=70 second=97 amount=-1 +kerning first=84 second=948 amount=-1 +kerning first=932 second=252 amount=-1 +kerning first=39 second=913 amount=-1 +kerning first=936 second=192 amount=-1 +kerning first=358 second=966 amount=-1 +kerning first=932 second=173 amount=-1 +kerning first=8217 second=263 amount=-1 +kerning first=358 second=238 amount=-1 +kerning first=194 second=354 amount=-1 +kerning first=1043 second=1095 amount=-1 +kerning first=8216 second=1066 amount=1 +kerning first=356 second=260 amount=-1 +kerning first=1113 second=8221 amount=-1 +kerning first=932 second=111 amount=-1 +kerning first=39 second=258 amount=-1 +kerning first=65 second=8216 amount=-1 +kerning first=358 second=99 amount=-1 +kerning first=910 second=916 amount=-1 +kerning first=76 second=8217 amount=-1 +kerning first=160 second=8218 amount=-1 +kerning first=221 second=8212 amount=-1 +kerning first=8217 second=192 amount=-1 +kerning first=354 second=45 amount=-1 +kerning first=969 second=34 amount=-1 +kerning first=1098 second=1098 amount=-1 +kerning first=356 second=8249 amount=-1 +kerning first=376 second=367 amount=-1 +kerning first=1058 second=1077 amount=-1 +kerning first=192 second=87 amount=-1 +kerning first=1043 second=1040 amount=-1 +kerning first=913 second=932 amount=-1 +kerning first=1168 second=1081 amount=-1 +kerning first=354 second=303 amount=-1 +kerning first=89 second=265 amount=-1 +kerning first=34 second=196 amount=-1 +kerning first=936 second=961 amount=-1 +kerning first=358 second=44 amount=-1 +kerning first=258 second=936 amount=-1 +kerning first=356 second=948 amount=-1 +kerning first=939 second=46 amount=-1 +kerning first=221 second=257 amount=-1 +kerning first=1100 second=1090 amount=-1 +kerning first=8216 second=111 amount=-1 +kerning first=221 second=113 amount=-1 +kerning first=376 second=250 amount=-1 +kerning first=8217 second=8221 amount=-1 +kerning first=1027 second=1092 amount=-1 +kerning first=1066 second=1066 amount=-1 +kerning first=84 second=269 amount=-1 +kerning first=256 second=932 amount=-1 +kerning first=8221 second=265 amount=-1 +kerning first=358 second=299 amount=-1 +kerning first=341 second=44 amount=-1 +kerning first=193 second=939 amount=-1 +kerning first=84 second=117 amount=-1 +kerning first=915 second=923 amount=-1 +kerning first=317 second=8216 amount=-1 +kerning first=89 second=195 amount=-1 +kerning first=910 second=949 amount=-1 +kerning first=44 second=8216 amount=-1 +kerning first=221 second=193 amount=-1 +kerning first=123 second=87 amount=1 +kerning first=8217 second=234 amount=-1 +kerning first=939 second=945 amount=-1 +kerning first=932 second=224 amount=-1 +kerning first=1068 second=1058 amount=-1 +kerning first=8220 second=1066 amount=1 +kerning first=84 second=197 amount=-1 +kerning first=313 second=45 amount=-1 +kerning first=8221 second=195 amount=-1 +kerning first=1043 second=1074 amount=-1 +kerning first=902 second=87 amount=-1 +kerning first=1168 second=1116 amount=-1 +kerning first=1041 second=1026 amount=-1 +kerning first=293 second=354 amount=-1 +kerning first=354 second=8212 amount=-1 +kerning first=89 second=8230 amount=-1 +kerning first=1059 second=1108 amount=-1 +kerning first=8250 second=932 amount=-1 +kerning first=221 second=335 amount=-1 +kerning first=192 second=933 amount=-1 +kerning first=260 second=8221 amount=-1 +kerning first=80 second=923 amount=-1 +kerning first=258 second=372 amount=-1 +kerning first=84 second=341 amount=-1 +kerning first=356 second=269 amount=-1 +kerning first=932 second=339 amount=-1 +kerning first=356 second=117 amount=-1 +kerning first=8221 second=8230 amount=-2 +kerning first=89 second=232 amount=-1 +kerning first=939 second=198 amount=-1 +kerning first=1090 second=44 amount=-1 +kerning first=1168 second=1060 amount=-1 +kerning first=923 second=39 amount=-1 +kerning first=354 second=257 amount=-1 +kerning first=221 second=227 amount=-1 +kerning first=354 second=113 amount=-1 +kerning first=89 second=97 amount=-1 +kerning first=8220 second=111 amount=-1 +kerning first=84 second=963 amount=-1 +kerning first=8204 second=8220 amount=-1 +kerning first=932 second=312 amount=-1 +kerning first=358 second=974 amount=-1 +kerning first=84 second=235 amount=-1 +kerning first=356 second=197 amount=-1 +kerning first=260 second=354 amount=-1 +kerning first=8217 second=289 amount=-1 +kerning first=358 second=249 amount=-1 +kerning first=39 second=196 amount=-1 +kerning first=8221 second=232 amount=-1 +kerning first=932 second=275 amount=-1 +kerning first=376 second=226 amount=-1 +kerning first=328 second=358 amount=-1 +kerning first=358 second=259 amount=-1 +kerning first=1059 second=8230 amount=-1 +kerning first=354 second=193 amount=-1 +kerning first=358 second=112 amount=-1 +kerning first=1111 second=1106 amount=1 +kerning first=902 second=933 amount=-1 +kerning first=313 second=8212 amount=-1 +kerning first=910 second=195 amount=-1 +kerning first=1038 second=1108 amount=-1 +kerning first=8216 second=339 amount=-1 +kerning first=356 second=341 amount=-1 +kerning first=358 second=923 amount=-1 +kerning first=372 second=913 amount=-1 +kerning first=939 second=194 amount=-1 +kerning first=1058 second=1090 amount=-1 +kerning first=271 second=293 amount=1 +kerning first=8217 second=74 amount=-1 +kerning first=913 second=939 amount=-1 +kerning first=1168 second=1094 amount=-1 +kerning first=354 second=335 amount=-1 +kerning first=372 second=258 amount=-1 +kerning first=84 second=41 amount=1 +kerning first=1027 second=1241 amount=-1 +kerning first=356 second=963 amount=-1 +kerning first=1059 second=1086 amount=-1 +kerning first=197 second=8216 amount=-1 +kerning first=229 second=358 amount=-1 +kerning first=356 second=235 amount=-1 +kerning first=8216 second=275 amount=-1 +kerning first=933 second=65 amount=-1 +kerning first=910 second=8230 amount=-1 +kerning first=8218 second=221 amount=-1 +kerning first=256 second=939 amount=-1 +kerning first=358 second=326 amount=-1 +kerning first=376 second=283 amount=-1 +kerning first=1058 second=46 amount=-1 +kerning first=354 second=227 amount=-1 +kerning first=70 second=228 amount=-1 +kerning first=8218 second=84 amount=-1 +kerning first=8230 second=34 amount=-1 +kerning first=1038 second=8230 amount=-1 +kerning first=76 second=86 amount=-1 +kerning first=932 second=962 amount=-1 +kerning first=8217 second=353 amount=-1 +kerning first=916 second=933 amount=-1 +kerning first=932 second=243 amount=-1 +kerning first=1169 second=46 amount=-1 +kerning first=97 second=932 amount=-1 +kerning first=358 second=229 amount=-1 +kerning first=933 second=966 amount=-1 +kerning first=1043 second=1087 amount=-1 +kerning first=1168 second=8250 amount=-1 +kerning first=8216 second=1058 amount=1 +kerning first=194 second=87 amount=-1 +kerning first=932 second=103 amount=-1 +kerning first=89 second=361 amount=-1 +kerning first=356 second=41 amount=1 +kerning first=8220 second=339 amount=-1 +kerning first=221 second=365 amount=-1 +kerning first=1038 second=1086 amount=-1 +kerning first=1098 second=1090 amount=-1 +kerning first=84 second=367 amount=-1 +kerning first=376 second=349 amount=-1 +kerning first=89 second=251 amount=-1 +kerning first=915 second=940 amount=-1 +kerning first=932 second=256 amount=-1 +kerning first=8216 second=962 amount=-1 +kerning first=87 second=195 amount=-1 +kerning first=354 second=287 amount=-1 +kerning first=173 second=89 amount=-1 +kerning first=8216 second=243 amount=-1 +kerning first=8220 second=275 amount=-1 +kerning first=221 second=246 amount=-1 +kerning first=160 second=376 amount=-1 +kerning first=84 second=972 amount=-1 +kerning first=8204 second=8222 amount=-1 +kerning first=84 second=250 amount=-1 +kerning first=8216 second=103 amount=-1 +kerning first=933 second=44 amount=-1 +kerning first=1066 second=1058 amount=-1 +kerning first=1027 second=1084 amount=-1 +kerning first=76 second=932 amount=-1 +kerning first=8211 second=933 amount=-1 +kerning first=319 second=39 amount=-1 +kerning first=932 second=171 amount=-1 +kerning first=358 second=281 amount=-1 +kerning first=84 second=109 amount=-1 +kerning first=46 second=39 amount=-1 +kerning first=315 second=221 amount=-1 +kerning first=358 second=125 amount=1 +kerning first=376 second=101 amount=-1 +kerning first=87 second=8230 amount=-1 +kerning first=45 second=221 amount=-1 +kerning first=227 second=356 amount=-1 +kerning first=194 second=933 amount=-1 +kerning first=915 second=260 amount=-1 +kerning first=315 second=84 amount=-1 +kerning first=356 second=367 amount=-1 +kerning first=8216 second=256 amount=-1 +kerning first=258 second=8221 amount=-1 +kerning first=8220 second=1058 amount=1 +kerning first=45 second=84 amount=-1 +kerning first=1058 second=1103 amount=-1 +kerning first=372 second=196 amount=-1 +kerning first=321 second=89 amount=-1 +kerning first=1168 second=1108 amount=-1 +kerning first=354 second=365 amount=-1 +kerning first=1068 second=8221 amount=-1 +kerning first=356 second=972 amount=-1 +kerning first=376 second=46 amount=-1 +kerning first=356 second=250 amount=-1 +kerning first=258 second=354 amount=-1 +kerning first=84 second=324 amount=-1 +kerning first=354 second=941 amount=-1 +kerning first=8220 second=962 amount=-1 +kerning first=1058 second=59 amount=-1 +kerning first=915 second=948 amount=-1 +kerning first=356 second=109 amount=-1 +kerning first=89 second=228 amount=-1 +kerning first=354 second=246 amount=-1 +kerning first=91 second=309 amount=1 +kerning first=8220 second=243 amount=-1 +kerning first=321 second=34 amount=-1 +kerning first=80 second=260 amount=-1 +kerning first=86 second=46 amount=-1 +kerning first=8217 second=8204 amount=-1 +kerning first=1043 second=173 amount=-1 +kerning first=8217 second=273 amount=-1 +kerning first=354 second=105 amount=-1 +kerning first=1059 second=1044 amount=-1 +kerning first=8220 second=103 amount=-1 +kerning first=358 second=940 amount=-1 +kerning first=84 second=226 amount=-1 +kerning first=8217 second=277 amount=-1 +kerning first=358 second=244 amount=-1 +kerning first=932 second=263 amount=-1 +kerning first=260 second=87 amount=-1 +kerning first=1043 second=1100 amount=-1 +kerning first=8230 second=8220 amount=-1 +kerning first=1168 second=8230 amount=-1 +kerning first=354 second=916 amount=-1 +kerning first=70 second=913 amount=-1 +kerning first=89 second=248 amount=-1 +kerning first=187 second=376 amount=-1 +kerning first=70 second=258 amount=-1 +kerning first=196 second=8216 amount=-1 +kerning first=8220 second=256 amount=-1 +kerning first=228 second=358 amount=-1 +kerning first=271 second=295 amount=1 +kerning first=356 second=324 amount=-1 +kerning first=932 second=192 amount=-1 +kerning first=8221 second=248 amount=-1 +kerning first=1058 second=1082 amount=-1 +kerning first=1056 second=46 amount=-2 +kerning first=376 second=198 amount=-1 +kerning first=933 second=923 amount=-1 +kerning first=1168 second=1086 amount=-1 +kerning first=89 second=279 amount=-1 +kerning first=358 second=260 amount=-1 +kerning first=195 second=221 amount=-1 +kerning first=8216 second=263 amount=-1 +kerning first=221 second=265 amount=-1 +kerning first=84 second=331 amount=-1 +kerning first=356 second=226 amount=-1 +kerning first=8217 second=351 amount=-1 +kerning first=1038 second=1044 amount=-1 +kerning first=34 second=65 amount=-1 +kerning first=1027 second=1097 amount=-1 +kerning first=965 second=34 amount=-1 +kerning first=86 second=198 amount=-1 +kerning first=84 second=283 amount=-1 +kerning first=8221 second=279 amount=-1 +kerning first=354 second=949 amount=-1 +kerning first=195 second=84 amount=-1 +kerning first=84 second=122 amount=-1 +kerning first=65 second=39 amount=-1 +kerning first=376 second=261 amount=-1 +kerning first=187 second=358 amount=-1 +kerning first=1058 second=1026 amount=1 +kerning first=358 second=8249 amount=-1 +kerning first=915 second=197 amount=-1 +kerning first=260 second=933 amount=-1 +kerning first=8216 second=192 amount=-1 +kerning first=221 second=195 amount=-1 +kerning first=932 second=961 amount=-1 +kerning first=171 second=939 amount=-1 +kerning first=1040 second=1035 amount=-1 +kerning first=932 second=234 amount=-1 +kerning first=358 second=948 amount=-1 +kerning first=1068 second=1063 amount=-1 +kerning first=1058 second=1118 amount=-1 +kerning first=324 second=356 amount=-1 +kerning first=376 second=194 amount=-1 +kerning first=8217 second=100 amount=-1 +kerning first=1043 second=1079 amount=-1 +kerning first=354 second=378 amount=-1 +kerning first=929 second=256 amount=-1 +kerning first=915 second=187 amount=-1 +kerning first=356 second=331 amount=-1 +kerning first=1027 second=8211 amount=-1 +kerning first=221 second=8230 amount=-1 +kerning first=86 second=194 amount=-1 +kerning first=84 second=349 amount=-1 +kerning first=356 second=283 amount=-1 +kerning first=80 second=197 amount=-1 +kerning first=376 second=337 amount=-1 +kerning first=356 second=122 amount=-1 +kerning first=317 second=39 amount=-1 +kerning first=915 second=963 amount=-1 +kerning first=8216 second=961 amount=-1 +kerning first=44 second=39 amount=-1 +kerning first=313 second=221 amount=-1 +kerning first=354 second=265 amount=-1 +kerning first=8216 second=234 amount=-1 +kerning first=8220 second=263 amount=-1 +kerning first=221 second=232 amount=-1 +kerning first=224 second=356 amount=-1 +kerning first=84 second=236 amount=-1 +kerning first=313 second=84 amount=-1 +kerning first=34 second=44 amount=-1 +kerning first=221 second=97 amount=-1 +kerning first=932 second=289 amount=-1 +kerning first=376 second=231 amount=-1 +kerning first=1027 second=1076 amount=-1 +kerning first=321 second=8220 amount=-1 +kerning first=1043 second=1114 amount=-1 +kerning first=923 second=376 amount=-1 +kerning first=89 second=913 amount=-1 +kerning first=358 second=269 amount=-1 +kerning first=1041 second=1066 amount=-1 +kerning first=84 second=101 amount=-1 +kerning first=354 second=195 amount=-1 +kerning first=70 second=196 amount=-1 +kerning first=358 second=117 amount=-1 +kerning first=39 second=65 amount=-1 +kerning first=91 second=356 amount=1 +kerning first=8220 second=192 amount=-1 +kerning first=376 second=93 amount=1 +kerning first=1066 second=8221 amount=-1 +kerning first=89 second=258 amount=-1 +kerning first=104 second=84 amount=-1 +kerning first=356 second=349 amount=-1 +kerning first=8221 second=913 amount=-1 +kerning first=1058 second=1095 amount=-1 +kerning first=358 second=197 amount=-1 +kerning first=1075 second=46 amount=-1 +kerning first=944 second=39 amount=-1 +kerning first=86 second=93 amount=1 +kerning first=1168 second=1099 amount=-1 +kerning first=8221 second=258 amount=-1 +kerning first=354 second=345 amount=-1 +kerning first=932 second=74 amount=-1 +kerning first=84 second=46 amount=-1 +kerning first=354 second=8230 amount=-1 +kerning first=109 second=358 amount=-1 +kerning first=8216 second=289 amount=-1 +kerning first=934 second=933 amount=-1 +kerning first=356 second=236 amount=-1 +kerning first=932 second=371 amount=-1 +kerning first=1027 second=1111 amount=-1 +kerning first=1114 second=1098 amount=-1 +kerning first=923 second=358 amount=-1 +kerning first=84 second=297 amount=-1 +kerning first=358 second=341 amount=-1 +kerning first=258 second=87 amount=-1 +kerning first=356 second=101 amount=-1 +kerning first=8220 second=961 amount=-1 +kerning first=354 second=232 amount=-1 +kerning first=1058 second=1040 amount=-1 +kerning first=1118 second=8230 amount=-1 +kerning first=8220 second=234 amount=-1 +kerning first=8230 second=8217 amount=-1 +kerning first=8218 second=89 amount=-1 +kerning first=8222 second=376 amount=-1 +kerning first=1168 second=1044 amount=-1 +kerning first=932 second=970 amount=1 +kerning first=261 second=84 amount=-1 +kerning first=354 second=97 amount=-1 +kerning first=84 second=945 amount=-1 +kerning first=193 second=8216 amount=-1 +kerning first=932 second=353 amount=-1 +kerning first=936 second=193 amount=-1 +kerning first=358 second=963 amount=-1 +kerning first=225 second=358 amount=-1 +kerning first=1059 second=1035 amount=1 +kerning first=358 second=235 amount=-1 +kerning first=929 second=192 amount=-1 +kerning first=8216 second=74 amount=-1 +kerning first=8217 second=113 amount=-1 +kerning first=933 second=940 amount=-1 +kerning first=34 second=974 amount=-1 +kerning first=1043 second=1092 amount=-1 +kerning first=227 second=932 amount=-1 +kerning first=376 second=308 amount=-1 +kerning first=356 second=46 amount=-1 +kerning first=39 second=44 amount=-1 +kerning first=910 second=913 amount=-1 +kerning first=197 second=39 amount=-1 +kerning first=221 second=361 amount=-1 +kerning first=192 second=221 amount=-1 +kerning first=8217 second=193 amount=-1 +kerning first=910 second=258 amount=-1 +kerning first=356 second=297 amount=-1 +kerning first=84 second=198 amount=-1 +kerning first=376 second=369 amount=-1 +kerning first=915 second=972 amount=-1 +kerning first=192 second=84 amount=-1 +kerning first=1058 second=1074 amount=-1 +kerning first=173 second=356 amount=-1 +kerning first=34 second=923 amount=-1 +kerning first=8222 second=358 amount=-1 +kerning first=1168 second=1078 amount=-1 +kerning first=8220 second=289 amount=-1 +kerning first=326 second=354 amount=-1 +kerning first=221 second=251 amount=-1 +kerning first=89 second=115 amount=-1 +kerning first=358 second=41 amount=1 +kerning first=258 second=933 amount=-1 +kerning first=356 second=945 amount=-1 +kerning first=933 second=260 amount=-1 +kerning first=8217 second=335 amount=-1 +kerning first=1038 second=1035 amount=1 +kerning first=331 second=84 amount=-1 +kerning first=376 second=242 amount=-1 +kerning first=1027 second=1089 amount=-1 +kerning first=1066 second=1063 amount=-1 +kerning first=84 second=261 amount=-1 +kerning first=932 second=8211 amount=-1 +kerning first=84 second=114 amount=-1 +kerning first=89 second=196 amount=-1 +kerning first=8221 second=115 amount=-1 +kerning first=110 second=356 amount=-1 +kerning first=114 second=44 amount=-1 +kerning first=950 second=125 amount=1 +kerning first=123 second=84 amount=1 +kerning first=902 second=221 amount=-1 +kerning first=315 second=89 amount=-1 +kerning first=319 second=376 amount=-1 +kerning first=8220 second=74 amount=-1 +kerning first=932 second=225 amount=-1 +kerning first=84 second=194 amount=-1 +kerning first=45 second=89 amount=-1 +kerning first=356 second=198 amount=-1 +kerning first=8221 second=196 amount=-1 +kerning first=321 second=356 amount=-1 +kerning first=1027 second=45 amount=-1 +kerning first=902 second=84 amount=-1 +kerning first=8249 second=933 amount=-1 +kerning first=933 second=948 amount=-1 +kerning first=1168 second=1113 amount=-1 +kerning first=354 second=361 amount=-1 +kerning first=89 second=333 amount=-1 +kerning first=1034 second=1026 amount=-1 +kerning first=1059 second=1105 amount=-1 +kerning first=372 second=65 amount=-1 +kerning first=39 second=974 amount=-1 +kerning first=226 second=356 amount=-1 +kerning first=913 second=8216 amount=-1 +kerning first=315 second=34 amount=-1 +kerning first=84 second=337 amount=-1 +kerning first=356 second=261 amount=-1 +kerning first=8221 second=333 amount=-1 +kerning first=932 second=305 amount=-1 +kerning first=358 second=367 amount=-1 +kerning first=356 second=114 amount=-1 +kerning first=354 second=251 amount=-1 +kerning first=89 second=233 amount=-1 +kerning first=87 second=913 amount=-1 +kerning first=915 second=953 amount=-1 +kerning first=321 second=8217 amount=-1 +kerning first=8212 second=376 amount=-1 +kerning first=1043 second=1241 amount=-1 +kerning first=221 second=228 amount=-1 +kerning first=256 second=8216 amount=-1 +kerning first=354 second=110 amount=-1 +kerning first=87 second=258 amount=-1 +kerning first=319 second=358 amount=-1 +kerning first=932 second=273 amount=-1 +kerning first=39 second=923 amount=-1 +kerning first=358 second=972 amount=-1 +kerning first=84 second=231 amount=-1 +kerning first=356 second=194 amount=-1 +kerning first=8217 second=287 amount=-1 +kerning first=358 second=250 amount=-1 +kerning first=8221 second=233 amount=-1 +kerning first=939 second=173 amount=-1 +kerning first=932 second=277 amount=-1 +kerning first=957 second=8230 amount=-1 +kerning first=8216 second=1076 amount=-1 +kerning first=1041 second=1058 amount=-1 +kerning first=974 second=39 amount=-1 +kerning first=916 second=84 amount=-1 +kerning first=84 second=93 amount=1 +kerning first=929 second=74 amount=-1 +kerning first=358 second=109 amount=-1 +kerning first=910 second=196 amount=-1 +kerning first=271 second=8217 amount=1 +kerning first=91 second=86 amount=1 +kerning first=1027 second=8212 amount=-1 +kerning first=1038 second=1105 amount=-1 +kerning first=324 second=932 amount=-1 +kerning first=221 second=248 amount=-1 +kerning first=356 second=337 amount=-1 +kerning first=1058 second=1087 amount=-1 +kerning first=8212 second=358 amount=-1 +kerning first=354 second=328 amount=-1 +kerning first=1056 second=1040 amount=-1 +kerning first=8216 second=273 amount=-1 +kerning first=933 second=197 amount=-1 +kerning first=1168 second=1091 amount=-1 +kerning first=8221 second=8217 amount=-1 +kerning first=372 second=44 amount=-1 +kerning first=259 second=84 amount=-1 +kerning first=221 second=279 amount=-1 +kerning first=8216 second=277 amount=-1 +kerning first=356 second=231 amount=-1 +kerning first=932 second=351 amount=-1 +kerning first=1027 second=1102 amount=-1 +kerning first=1114 second=1090 amount=-1 +kerning first=84 second=285 amount=-1 +kerning first=8221 second=291 amount=-1 +kerning first=358 second=324 amount=-1 +kerning first=195 second=89 amount=-1 +kerning first=8211 second=221 amount=-1 +kerning first=376 second=267 amount=-1 +kerning first=356 second=93 amount=1 +kerning first=354 second=228 amount=-1 +kerning first=224 second=932 amount=-1 +kerning first=910 second=959 amount=-1 +kerning first=196 second=39 amount=-1 +kerning first=8211 second=84 amount=-1 +kerning first=8217 second=246 amount=-1 +kerning first=936 second=916 amount=-1 +kerning first=932 second=239 amount=-1 +kerning first=194 second=221 amount=-1 +kerning first=8220 second=1076 amount=-1 +kerning first=65 second=376 amount=-1 +kerning first=1027 second=58 amount=-1 +kerning first=358 second=226 amount=-1 +kerning first=343 second=46 amount=-1 +kerning first=91 second=932 amount=1 +kerning first=933 second=963 amount=-1 +kerning first=1043 second=1084 amount=-1 +kerning first=84 second=308 amount=-1 +kerning first=194 second=84 amount=-1 +kerning first=932 second=100 amount=-1 +kerning first=195 second=34 amount=-1 +kerning first=89 second=363 amount=-1 +kerning first=354 second=248 amount=-1 +kerning first=70 second=230 amount=-1 +kerning first=74 second=125 amount=1 +kerning first=328 second=354 amount=-1 +kerning first=84 second=369 amount=-1 +kerning first=1035 second=1035 amount=-1 +kerning first=356 second=285 amount=-1 +kerning first=915 second=968 amount=-1 +kerning first=89 second=245 amount=-1 +kerning first=8220 second=273 amount=-1 +kerning first=87 second=196 amount=-1 +kerning first=271 second=107 amount=1 +kerning first=354 second=279 amount=-1 +kerning first=932 second=45 amount=-1 +kerning first=8220 second=277 amount=-1 +kerning first=315 second=8220 amount=-1 +kerning first=329 second=358 amount=-1 +kerning first=34 second=260 amount=-1 +kerning first=313 second=89 amount=-1 +kerning first=65 second=358 amount=-1 +kerning first=317 second=376 amount=-1 +kerning first=84 second=242 amount=-1 +kerning first=358 second=331 amount=-1 +kerning first=8216 second=100 amount=-1 +kerning first=8221 second=245 amount=-1 +kerning first=932 second=303 amount=-1 +kerning first=1027 second=1081 amount=-1 +kerning first=229 second=354 amount=-1 +kerning first=356 second=308 amount=-1 +kerning first=358 second=283 amount=-1 +kerning first=358 second=122 amount=-1 +kerning first=221 second=913 amount=-1 +kerning first=1058 second=173 amount=-1 +kerning first=70 second=65 amount=-1 +kerning first=356 second=369 amount=-1 +kerning first=915 second=46 amount=-1 +kerning first=372 second=923 amount=-1 +kerning first=221 second=258 amount=-1 +kerning first=313 second=34 amount=-1 +kerning first=1058 second=1100 amount=-1 +kerning first=271 second=320 amount=1 +kerning first=321 second=86 amount=-1 +kerning first=1168 second=1105 amount=-1 +kerning first=293 second=84 amount=-1 +kerning first=356 second=242 amount=-1 +kerning first=317 second=358 amount=-1 +kerning first=173 second=932 amount=-1 +kerning first=1027 second=1116 amount=-1 +kerning first=932 second=8212 amount=-1 +kerning first=354 second=969 amount=-1 +kerning first=358 second=349 amount=-1 +kerning first=915 second=945 amount=-1 +kerning first=354 second=241 amount=-1 +kerning first=8218 second=356 amount=-1 +kerning first=8212 second=910 amount=-1 +kerning first=973 second=39 amount=-1 +kerning first=76 second=8216 amount=-1 +kerning first=80 second=46 amount=-2 +kerning first=932 second=912 amount=1 +kerning first=260 second=221 amount=-1 +kerning first=8220 second=100 amount=-1 +kerning first=939 second=962 amount=-1 +kerning first=319 second=173 amount=-1 +kerning first=936 second=195 amount=-1 +kerning first=8217 second=265 amount=-1 +kerning first=86 second=301 amount=1 +kerning first=358 second=236 amount=-1 +kerning first=110 second=932 amount=-1 +kerning first=932 second=257 amount=-1 +kerning first=260 second=84 amount=-1 +kerning first=923 second=936 amount=-1 +kerning first=933 second=972 amount=-1 +kerning first=1027 second=1060 amount=-1 +kerning first=354 second=913 amount=-1 +kerning first=932 second=113 amount=-1 +kerning first=345 second=8230 amount=-1 +kerning first=39 second=260 amount=-1 +kerning first=1043 second=1097 amount=-1 +kerning first=89 second=230 amount=-1 +kerning first=358 second=101 amount=-1 +kerning first=915 second=198 amount=-1 +kerning first=321 second=932 amount=-1 +kerning first=354 second=258 amount=-1 +kerning first=8230 second=939 amount=-1 +kerning first=8217 second=195 amount=-1 +kerning first=70 second=44 amount=-1 +kerning first=84 second=380 amount=-1 +kerning first=932 second=193 amount=-1 +kerning first=195 second=8220 amount=-1 +kerning first=936 second=8230 amount=-1 +kerning first=915 second=944 amount=-1 +kerning first=354 second=307 amount=-1 +kerning first=1058 second=1079 amount=-1 +kerning first=192 second=89 amount=-1 +kerning first=197 second=376 amount=-1 +kerning first=1168 second=1083 amount=-1 +kerning first=226 second=932 amount=-1 +kerning first=89 second=271 amount=-1 +kerning first=939 second=256 amount=-1 +kerning first=34 second=197 amount=-1 +kerning first=358 second=46 amount=-1 +kerning first=193 second=39 amount=-1 +kerning first=1043 second=8211 amount=-1 +kerning first=950 second=41 amount=1 +kerning first=8216 second=113 amount=-1 +kerning first=221 second=115 amount=-1 +kerning first=932 second=335 amount=-1 +kerning first=376 second=252 amount=-1 +kerning first=8217 second=8230 amount=-2 +kerning first=1027 second=1094 amount=-1 +kerning first=84 second=267 amount=-1 +kerning first=376 second=173 amount=-1 +kerning first=358 second=297 amount=-1 +kerning first=341 second=46 amount=-1 +kerning first=80 second=198 amount=-1 +kerning first=8221 second=271 amount=-1 +kerning first=923 second=372 amount=-1 +kerning first=1091 second=8230 amount=-1 +kerning first=372 second=125 amount=1 +kerning first=192 second=34 amount=-1 +kerning first=376 second=111 amount=-1 +kerning first=357 second=8217 amount=1 +kerning first=915 second=194 amount=-1 +kerning first=315 second=356 amount=-1 +kerning first=8216 second=193 amount=-1 +kerning first=221 second=196 amount=-1 +kerning first=8217 second=232 amount=-1 +kerning first=89 second=65 amount=-1 +kerning first=45 second=356 amount=-1 +kerning first=356 second=380 amount=-1 +kerning first=932 second=227 amount=-1 +kerning first=915 second=59 amount=-1 +kerning first=358 second=945 amount=-1 +kerning first=1033 second=1035 amount=-1 +kerning first=1058 second=1114 amount=-1 +kerning first=1043 second=1076 amount=-1 +kerning first=197 second=358 amount=-1 +kerning first=902 second=89 amount=-1 +kerning first=1168 second=1119 amount=-1 +kerning first=89 second=347 amount=-1 +kerning first=8221 second=65 amount=-1 +kerning first=8216 second=335 amount=-1 +kerning first=221 second=333 amount=-1 +kerning first=313 second=8220 amount=-1 +kerning first=1027 second=8250 amount=-1 +kerning first=295 second=358 amount=-1 +kerning first=173 second=939 amount=-1 +kerning first=315 second=8217 amount=-1 +kerning first=84 second=343 amount=-1 +kerning first=356 second=267 amount=-1 +kerning first=8221 second=347 amount=-1 +kerning first=80 second=194 amount=-1 +kerning first=228 second=354 amount=-1 +kerning first=354 second=382 amount=-1 +kerning first=358 second=198 amount=-1 +kerning first=1090 second=46 amount=-1 +kerning first=902 second=34 amount=-1 +kerning first=70 second=259 amount=-1 +kerning first=221 second=233 amount=-1 +kerning first=354 second=115 amount=-1 +kerning first=89 second=99 amount=-1 +kerning first=8222 second=372 amount=-1 +kerning first=8220 second=113 amount=-1 +kerning first=84 second=237 amount=-1 +kerning first=39 second=197 amount=-1 +kerning first=1043 second=1111 amount=-1 +kerning first=932 second=287 amount=-1 +kerning first=376 second=224 amount=-1 +kerning first=70 second=923 amount=-1 +kerning first=358 second=261 amount=-1 +kerning first=8221 second=99 amount=-1 +kerning first=1034 second=1066 amount=-1 +kerning first=354 second=196 amount=-1 +kerning first=358 second=114 amount=-1 +kerning first=8220 second=193 amount=-1 +kerning first=187 second=354 amount=-1 +kerning first=913 second=39 amount=-1 +kerning first=89 second=44 amount=-1 +kerning first=356 second=343 amount=-1 +kerning first=241 second=358 amount=-1 +kerning first=102 second=34 amount=1 +kerning first=910 second=65 amount=-1 +kerning first=939 second=192 amount=-1 +kerning first=1058 second=1092 amount=-1 +kerning first=358 second=194 amount=-1 +kerning first=376 second=339 amount=-1 +kerning first=1168 second=1096 amount=-1 +kerning first=354 second=333 amount=-1 +kerning first=8220 second=335 amount=-1 +kerning first=372 second=260 amount=-1 +kerning first=916 second=34 amount=-1 +kerning first=256 second=39 amount=-1 +kerning first=8221 second=44 amount=-2 +kerning first=8216 second=287 amount=-1 +kerning first=258 second=221 amount=-1 +kerning first=356 second=237 amount=-1 +kerning first=317 second=173 amount=-1 +kerning first=932 second=365 amount=-1 +kerning first=195 second=356 amount=-1 +kerning first=84 second=301 amount=-1 +kerning first=1027 second=1108 amount=-1 +kerning first=354 second=959 amount=-1 +kerning first=358 second=337 amount=-1 +kerning first=971 second=34 amount=-1 +kerning first=258 second=84 amount=-1 +kerning first=376 second=275 amount=-1 +kerning first=354 second=233 amount=-1 +kerning first=70 second=229 amount=-1 +kerning first=8218 second=86 amount=-1 +kerning first=910 second=966 amount=-1 +kerning first=8211 second=89 amount=-1 +kerning first=932 second=941 amount=-1 +kerning first=1059 second=44 amount=-1 +kerning first=74 second=41 amount=1 +kerning first=939 second=961 amount=-1 +kerning first=932 second=246 amount=-1 +kerning first=1059 second=1032 amount=-1 +kerning first=358 second=231 amount=-1 +kerning first=929 second=193 amount=-1 +kerning first=319 second=372 amount=-1 +kerning first=192 second=8220 amount=-1 +kerning first=934 second=8230 amount=-1 +kerning first=1043 second=1089 amount=-1 +kerning first=194 second=89 amount=-1 +kerning first=932 second=105 amount=-1 +kerning first=196 second=376 amount=-1 +kerning first=195 second=8217 amount=-1 +kerning first=358 second=93 amount=1 +kerning first=40 second=106 amount=1 +kerning first=1100 second=8221 amount=-1 +kerning first=257 second=358 amount=-1 +kerning first=221 second=363 amount=-1 +kerning first=40 second=1095 amount=-1 +kerning first=1027 second=8230 amount=-1 +kerning first=932 second=916 amount=-1 +kerning first=356 second=301 amount=-1 +kerning first=915 second=942 amount=-1 +kerning first=89 second=249 amount=-1 +kerning first=910 second=44 amount=-1 +kerning first=955 second=34 amount=-1 +kerning first=8216 second=941 amount=-1 +kerning first=80 second=308 amount=-1 +kerning first=923 second=8221 amount=-1 +kerning first=123 second=309 amount=1 +kerning first=1168 second=1075 amount=-1 +kerning first=1043 second=45 amount=-1 +kerning first=194 second=34 amount=-1 +kerning first=354 second=291 amount=-1 +kerning first=89 second=259 amount=-1 +kerning first=8220 second=287 amount=-1 +kerning first=8216 second=246 amount=-1 +kerning first=221 second=245 amount=-1 +kerning first=313 second=356 amount=-1 +kerning first=1038 second=44 amount=-1 +kerning first=84 second=252 amount=-1 +kerning first=87 second=65 amount=-1 +kerning first=8218 second=932 amount=-1 +kerning first=109 second=354 amount=-1 +kerning first=1038 second=1032 amount=-1 +kerning first=84 second=173 amount=-1 +kerning first=8221 second=160 amount=-1 +kerning first=902 second=8220 amount=-1 +kerning first=376 second=243 amount=-1 +kerning first=933 second=46 amount=-1 +kerning first=1027 second=1086 amount=-1 +kerning first=89 second=923 amount=-1 +kerning first=358 second=285 amount=-1 +kerning first=196 second=358 amount=-1 +kerning first=84 second=111 amount=-1 +kerning first=923 second=354 amount=-1 +kerning first=8216 second=916 amount=-1 +kerning first=104 second=356 amount=-1 +kerning first=1058 second=1241 amount=-1 +kerning first=932 second=949 amount=-1 +kerning first=315 second=86 amount=-1 +kerning first=8221 second=923 amount=-1 +kerning first=8204 second=8216 amount=-1 +kerning first=65 second=936 amount=-1 +kerning first=1033 second=8217 amount=-1 +kerning first=313 second=8217 amount=-1 +kerning first=372 second=197 amount=-1 +kerning first=933 second=945 amount=-1 +kerning first=225 second=354 amount=-1 +kerning first=354 second=363 amount=-1 +kerning first=358 second=308 amount=-1 +kerning first=376 second=256 amount=-1 +kerning first=102 second=8220 amount=1 +kerning first=356 second=252 amount=-1 +kerning first=1043 second=8212 amount=-1 +kerning first=356 second=173 amount=-1 +kerning first=932 second=378 amount=-1 +kerning first=8217 second=248 amount=-1 +kerning first=358 second=369 amount=-1 +kerning first=8220 second=941 amount=-1 +kerning first=356 second=111 amount=-1 +kerning first=354 second=245 amount=-1 +kerning first=86 second=256 amount=-1 +kerning first=89 second=229 amount=-1 +kerning first=8220 second=246 amount=-1 +kerning first=376 second=171 amount=-1 +kerning first=261 second=356 amount=-1 +kerning first=8216 second=949 amount=-1 +kerning first=933 second=198 amount=-1 +kerning first=8222 second=354 amount=-1 +kerning first=84 second=224 amount=-1 +kerning first=87 second=44 amount=-1 +kerning first=8217 second=279 amount=-1 +kerning first=358 second=242 amount=-1 +kerning first=932 second=265 amount=-1 +kerning first=1043 second=1102 amount=-1 +kerning first=260 second=89 amount=-1 +kerning first=40 second=358 amount=1 +kerning first=65 second=372 amount=-1 +kerning first=315 second=932 amount=-1 +kerning first=8220 second=916 amount=-1 +kerning first=1034 second=1058 amount=-1 +kerning first=45 second=932 amount=-1 +kerning first=910 second=923 amount=-1 +kerning first=70 second=260 amount=-1 +kerning first=221 second=230 amount=-1 +kerning first=932 second=195 amount=-1 +kerning first=192 second=356 amount=-1 +kerning first=84 second=339 amount=-1 +kerning first=1043 second=58 amount=-1 +kerning first=1058 second=1084 amount=-1 +kerning first=260 second=34 amount=-1 +kerning first=1168 second=1088 amount=-1 +kerning first=76 second=39 amount=-1 +kerning first=89 second=281 amount=-1 +kerning first=933 second=194 amount=-1 +kerning first=89 second=125 amount=1 +kerning first=372 second=41 amount=1 +kerning first=331 second=356 amount=-1 +kerning first=8216 second=265 amount=-1 +kerning first=221 second=271 amount=-1 +kerning first=84 second=312 amount=-1 +kerning first=356 second=224 amount=-1 +kerning first=932 second=345 amount=-1 +kerning first=1027 second=1099 amount=-1 +kerning first=84 second=275 amount=-1 +kerning first=319 second=8221 amount=-1 +kerning first=317 second=372 amount=-1 +kerning first=194 second=8220 amount=-1 +kerning first=932 second=8230 amount=-1 +kerning first=195 second=86 amount=-1 +kerning first=376 second=263 amount=-1 +kerning first=8221 second=281 amount=-1 +kerning first=939 second=8211 amount=-1 +kerning first=46 second=8221 amount=-1 +kerning first=8220 second=949 amount=-1 +kerning first=193 second=376 amount=-1 +kerning first=192 second=8217 amount=-1 +kerning first=123 second=356 amount=1 +kerning first=1028 second=1095 amount=-1 +kerning first=1168 second=1032 amount=-1 +kerning first=1168 second=44 amount=-1 +kerning first=8216 second=195 amount=-1 +kerning first=1098 second=8221 amount=-1 +kerning first=936 second=913 amount=-1 +kerning first=932 second=232 amount=-1 +kerning first=929 second=916 amount=-1 +kerning first=902 second=356 amount=-1 +kerning first=356 second=339 amount=-1 +kerning first=319 second=354 amount=-1 +kerning first=221 second=65 amount=-1 +kerning first=376 second=192 amount=-1 +kerning first=936 second=258 amount=-1 +kerning first=1027 second=1044 amount=-1 +kerning first=1043 second=1081 amount=-1 +kerning first=932 second=97 amount=-1 +kerning first=354 second=230 amount=-1 +kerning first=306 second=125 amount=1 +kerning first=221 second=347 amount=-1 +kerning first=356 second=312 amount=-1 +kerning first=8217 second=913 amount=-1 +kerning first=8216 second=8230 amount=-1 +kerning first=86 second=192 amount=-1 +kerning first=356 second=275 amount=-1 +kerning first=358 second=380 amount=-1 +kerning first=8217 second=258 amount=-1 +kerning first=89 second=244 amount=-1 +kerning first=197 second=936 amount=-1 +kerning first=87 second=923 amount=-1 +kerning first=915 second=965 amount=-1 +kerning first=193 second=358 amount=-1 +kerning first=902 second=8217 amount=-1 +kerning first=271 second=104 amount=1 +kerning first=354 second=271 amount=-1 +kerning first=8216 second=232 amount=-1 +kerning first=8220 second=265 amount=-1 +kerning first=195 second=932 amount=-1 +kerning first=8212 second=354 amount=-1 +kerning first=84 second=962 amount=-1 +kerning first=326 second=84 amount=-1 +kerning first=313 second=86 amount=-1 +kerning first=84 second=243 amount=-1 +kerning first=8221 second=244 amount=-1 +kerning first=34 second=46 amount=-1 +kerning first=221 second=99 amount=-1 +kerning first=376 second=234 amount=-1 +kerning first=1027 second=1078 amount=-1 +kerning first=916 second=356 amount=-1 +kerning first=1043 second=1116 amount=-1 +kerning first=358 second=267 amount=-1 +kerning first=84 second=103 amount=-1 +kerning first=70 second=197 amount=-1 +kerning first=8220 second=195 amount=-1 +kerning first=45 second=939 amount=-1 +kerning first=923 second=87 amount=-1 +kerning first=89 second=260 amount=-1 +kerning first=1026 second=1026 amount=-1 +kerning first=354 second=65 amount=-1 +kerning first=102 second=8217 amount=1 +kerning first=1058 second=1097 amount=-1 +kerning first=271 second=314 amount=1 +kerning first=221 second=44 amount=-1 +kerning first=1043 second=1060 amount=-1 +kerning first=8230 second=8216 amount=-1 +kerning first=84 second=256 amount=-1 +kerning first=354 second=347 amount=-1 +kerning first=8221 second=260 amount=-1 +kerning first=1168 second=1101 amount=-1 +kerning first=913 second=376 amount=-1 +kerning first=197 second=372 amount=-1 +kerning first=916 second=8217 amount=-1 +kerning first=259 second=356 amount=-1 +kerning first=89 second=8249 amount=-1 +kerning first=8220 second=8230 amount=-1 +kerning first=356 second=962 amount=-1 +kerning first=356 second=243 amount=-1 +kerning first=932 second=361 amount=-1 +kerning first=260 second=8220 amount=-1 +kerning first=1027 second=1113 amount=-1 +kerning first=354 second=966 amount=-1 +kerning first=358 second=343 amount=-1 +kerning first=258 second=89 amount=-1 +kerning first=84 second=171 amount=-1 +kerning first=256 second=376 amount=-1 +kerning first=65 second=8221 amount=-1 +kerning first=356 second=103 amount=-1 +kerning first=354 second=238 amount=-1 +kerning first=8220 second=232 amount=-1 +kerning first=313 second=932 amount=-1 +kerning first=910 second=940 amount=-1 +kerning first=8211 second=356 amount=-1 +kerning first=34 second=198 amount=-1 +kerning first=354 second=99 amount=-1 +kerning first=932 second=251 amount=-1 +kerning first=936 second=196 amount=-1 +kerning first=8222 second=87 amount=-1 +kerning first=1058 second=8211 amount=-1 +kerning first=929 second=195 amount=-1 +kerning first=358 second=237 amount=-1 +kerning first=194 second=356 amount=-1 +kerning first=329 second=354 amount=-1 +kerning first=8217 second=115 amount=-1 +kerning first=923 second=933 amount=-1 +kerning first=1043 second=1094 amount=-1 +kerning first=104 second=932 amount=-1 +kerning first=65 second=354 amount=-1 +kerning first=356 second=256 amount=-1 +kerning first=932 second=110 amount=-1 +kerning first=913 second=358 amount=-1 +kerning first=258 second=34 amount=-1 +kerning first=1107 second=8230 amount=-1 +kerning first=39 second=46 amount=-1 +kerning first=376 second=74 amount=-1 +kerning first=87 second=125 amount=1 +kerning first=950 second=93 amount=1 +kerning first=8250 second=376 amount=-1 +kerning first=8217 second=196 amount=-1 +kerning first=354 second=44 amount=-1 +kerning first=910 second=260 amount=-1 +kerning first=1034 second=8221 amount=-1 +kerning first=256 second=358 amount=-1 +kerning first=317 second=8221 amount=-1 +kerning first=356 second=171 amount=-1 +kerning first=376 second=371 amount=-1 +kerning first=929 second=8230 amount=-2 +kerning first=915 second=971 amount=-1 +kerning first=192 second=86 amount=-1 +kerning first=44 second=8221 amount=-1 +kerning first=955 second=8217 amount=-1 +kerning first=915 second=173 amount=-1 +kerning first=1058 second=1076 amount=-1 +kerning first=194 second=8217 amount=-1 +kerning first=354 second=299 amount=-1 +kerning first=89 second=269 amount=-1 +kerning first=221 second=249 amount=-1 +kerning first=34 second=194 amount=-1 +kerning first=89 second=117 amount=-1 +kerning first=195 second=939 amount=-1 +kerning first=939 second=45 amount=-1 +kerning first=1168 second=1080 amount=-1 +kerning first=1059 second=1072 amount=-1 +kerning first=1118 second=44 amount=-1 +kerning first=221 second=259 amount=-1 +kerning first=8217 second=333 amount=-1 +kerning first=1043 second=8250 amount=-1 +kerning first=932 second=328 amount=-1 +kerning first=376 second=353 amount=-1 +kerning first=1027 second=1091 amount=-1 +kerning first=84 second=263 amount=-1 +kerning first=319 second=8211 amount=-1 +kerning first=261 second=932 amount=-1 +kerning first=317 second=354 amount=-1 +kerning first=358 second=301 amount=-1 +kerning first=8221 second=269 amount=-1 +kerning first=89 second=197 amount=-1 +kerning first=910 second=948 amount=-1 +kerning first=221 second=923 amount=-1 +kerning first=114 second=46 amount=-1 +kerning first=1113 second=8217 amount=-1 +kerning first=8250 second=358 amount=-1 +kerning first=123 second=86 amount=1 +kerning first=8217 second=233 amount=-1 +kerning first=932 second=228 amount=-1 +kerning first=84 second=192 amount=-1 +kerning first=8221 second=197 amount=-1 +kerning first=1058 second=1111 amount=-1 +kerning first=39 second=198 amount=-1 +kerning first=902 second=86 amount=-1 +kerning first=196 second=936 amount=-1 +kerning first=321 second=8216 amount=-1 +kerning first=319 second=87 amount=-1 +kerning first=293 second=356 amount=-1 +kerning first=192 second=932 amount=-1 +kerning first=1038 second=1072 amount=-1 +kerning first=328 second=84 amount=-1 +kerning first=356 second=263 amount=-1 +kerning first=932 second=248 amount=-1 +kerning first=354 second=974 amount=-1 +kerning first=939 second=8212 amount=-1 +kerning first=354 second=249 amount=-1 +kerning first=89 second=235 amount=-1 +kerning first=331 second=932 amount=-1 +kerning first=376 second=8211 amount=-1 +kerning first=160 second=902 amount=-1 +kerning first=8217 second=8217 amount=-1 +kerning first=354 second=259 amount=-1 +kerning first=221 second=229 amount=-1 +kerning first=354 second=112 amount=-1 +kerning first=87 second=260 amount=-1 +kerning first=84 second=961 amount=-1 +kerning first=84 second=234 amount=-1 +kerning first=356 second=192 amount=-1 +kerning first=260 second=356 amount=-1 +kerning first=8217 second=291 amount=-1 +kerning first=358 second=252 amount=-1 +kerning first=39 second=194 amount=-1 +kerning first=8221 second=235 amount=-1 +kerning first=932 second=279 amount=-1 +kerning first=358 second=173 amount=-1 +kerning first=376 second=225 amount=-1 +kerning first=123 second=932 amount=1 +kerning first=1043 second=1108 amount=-1 +kerning first=354 second=923 amount=-1 +kerning first=229 second=84 amount=-1 +kerning first=358 second=111 amount=-1 +kerning first=1034 second=1063 amount=-1 +kerning first=196 second=372 amount=-1 +kerning first=197 second=8221 amount=-1 +kerning first=902 second=932 amount=-1 +kerning first=910 second=197 amount=-1 +kerning first=8216 second=248 amount=-1 +kerning first=89 second=41 amount=1 +kerning first=46 second=933 amount=-1 +kerning first=1068 second=1035 amount=-1 +kerning first=258 second=8220 amount=-1 +kerning first=939 second=193 amount=-1 +kerning first=947 second=8230 amount=-1 +kerning first=1058 second=1089 amount=-1 +kerning first=260 second=8217 amount=-1 +kerning first=1168 second=1093 amount=-1 +kerning first=354 second=326 amount=-1 +kerning first=197 second=354 amount=-1 +kerning first=969 second=39 amount=-1 +kerning first=74 second=93 amount=1 +kerning first=372 second=46 amount=-1 +kerning first=34 second=308 amount=-1 +kerning first=221 second=281 amount=-1 +kerning first=8216 second=279 amount=-1 +kerning first=356 second=234 amount=-1 +kerning first=356 second=961 amount=-1 +kerning first=1043 second=8230 amount=-1 +kerning first=97 second=358 amount=-1 +kerning first=376 second=273 amount=-1 +kerning first=221 second=125 amount=1 +kerning first=1027 second=1105 amount=-1 +kerning first=84 second=289 amount=-1 +kerning first=76 second=376 amount=-1 +kerning first=295 second=354 amount=-1 +kerning first=376 second=277 amount=-1 +kerning first=957 second=44 amount=-1 +kerning first=354 second=229 amount=-1 +kerning first=70 second=226 amount=-1 +kerning first=910 second=963 amount=-1 +kerning first=8212 second=933 amount=-1 +kerning first=1058 second=45 amount=-1 +kerning first=932 second=969 amount=-1 +kerning first=8217 second=245 amount=-1 +kerning first=916 second=932 amount=-1 +kerning first=932 second=241 amount=-1 +kerning first=306 second=41 amount=1 +kerning first=358 second=224 amount=-1 +kerning first=1043 second=1086 amount=-1 +kerning first=1056 second=1076 amount=-1 +kerning first=194 second=86 amount=-1 +kerning first=89 second=367 amount=-1 +kerning first=84 second=74 amount=-1 +kerning first=65 second=87 amount=-1 +kerning first=40 second=372 amount=1 +kerning first=8220 second=248 amount=-1 +kerning first=192 second=939 amount=-1 +kerning first=932 second=913 amount=-1 +kerning first=84 second=371 amount=-1 +kerning first=356 second=289 amount=-1 +kerning first=76 second=358 amount=-1 +kerning first=376 second=351 amount=-1 +kerning first=317 second=8211 amount=-1 +kerning first=259 second=932 amount=-1 +kerning first=358 second=339 amount=-1 +kerning first=372 second=198 amount=-1 +kerning first=89 second=250 amount=-1 +kerning first=241 second=354 amount=-1 +kerning first=932 second=258 amount=-1 +kerning first=915 second=962 amount=-1 +kerning first=87 second=197 amount=-1 +kerning first=319 second=45 amount=-1 +kerning first=354 second=281 amount=-1 +kerning first=8216 second=969 amount=-1 +kerning first=1168 second=1072 amount=-1 +kerning first=8220 second=279 amount=-1 +kerning first=160 second=221 amount=-1 +kerning first=221 second=244 amount=-1 +kerning first=354 second=125 amount=1 +kerning first=8204 second=8218 amount=-1 +kerning first=932 second=307 amount=-1 +kerning first=1058 second=8212 amount=-1 +kerning first=84 second=353 amount=-1 +kerning first=358 second=312 amount=-1 +kerning first=376 second=239 amount=1 +kerning first=1027 second=1083 amount=-1 +kerning first=8211 second=932 amount=-1 +kerning first=358 second=275 amount=-1 +kerning first=39 second=308 amount=-1 +kerning first=193 second=936 amount=-1 +kerning first=356 second=74 amount=-1 +kerning first=317 second=87 amount=-1 +kerning first=376 second=100 amount=-1 +kerning first=8216 second=913 amount=-1 +kerning first=902 second=939 amount=-1 +kerning first=194 second=932 amount=-1 +kerning first=915 second=256 amount=-1 +kerning first=86 second=239 amount=1 +kerning first=356 second=371 amount=-1 +kerning first=65 second=933 amount=-1 +kerning first=8216 second=258 amount=-1 +kerning first=221 second=260 amount=-1 +kerning first=1058 second=1102 amount=-1 +kerning first=372 second=194 amount=-1 +kerning first=8216 second=1035 amount=1 +kerning first=1168 second=1107 amount=-1 +kerning first=376 second=45 amount=-1 +kerning first=356 second=353 amount=-1 +kerning first=221 second=8249 amount=-1 +kerning first=8216 second=8220 amount=-1 +kerning first=1027 second=1119 amount=-1 +kerning first=258 second=356 amount=-1 +kerning first=257 second=354 amount=-1 +kerning first=319 second=8212 amount=-1 +kerning first=354 second=940 amount=-1 +kerning first=8220 second=969 amount=-1 +kerning first=1058 second=58 amount=-1 +kerning first=84 second=8211 amount=-1 +kerning first=354 second=244 amount=-1 +kerning first=89 second=226 amount=-1 +kerning first=910 second=972 amount=-1 +kerning first=228 second=84 amount=-1 +kerning first=80 second=256 amount=-1 +kerning first=196 second=8221 amount=-1 +kerning first=193 second=372 amount=-1 +kerning first=1026 second=1066 amount=-1 +kerning first=916 second=939 amount=-1 +kerning first=932 second=382 amount=-1 +kerning first=939 second=941 amount=-1 +kerning first=358 second=962 amount=-1 +kerning first=84 second=225 amount=-1 +kerning first=87 second=41 amount=1 +kerning first=8217 second=271 amount=-1 +kerning first=1033 second=1059 amount=-1 +kerning first=358 second=243 amount=-1 +kerning first=44 second=933 amount=-1 +kerning first=1043 second=1099 amount=-1 +kerning first=1168 second=187 amount=-1 +kerning first=1066 second=1035 amount=-1 +kerning first=260 second=86 amount=-1 +kerning first=8230 second=39 amount=-1 +kerning first=271 second=322 amount=1 +kerning first=932 second=115 amount=-1 +kerning first=936 second=65 amount=-1 +kerning first=8220 second=913 amount=-1 +kerning first=258 second=8217 amount=-1 +kerning first=933 second=173 amount=-1 +kerning first=187 second=221 amount=-1 +kerning first=358 second=103 amount=-1 +kerning first=372 second=93 amount=1 +kerning first=196 second=354 amount=-1 +kerning first=354 second=260 amount=-1 +kerning first=1114 second=8221 amount=-1 +kerning first=8220 second=258 amount=-1 +kerning first=187 second=84 amount=-1 +kerning first=70 second=46 amount=-1 +kerning first=932 second=196 amount=-1 +kerning first=939 second=916 amount=-1 +kerning first=1068 second=8217 amount=-1 +kerning first=8220 second=1035 amount=1 +kerning first=84 second=305 amount=-1 +kerning first=293 second=932 amount=-1 +kerning first=356 second=8211 amount=-1 +kerning first=1058 second=1081 amount=-1 +kerning first=1043 second=1044 amount=-1 +kerning first=376 second=8212 amount=-1 +kerning first=8217 second=65 amount=-1 +kerning first=913 second=936 amount=-1 +kerning first=1168 second=1085 amount=-1 +kerning first=89 second=283 amount=-1 +kerning first=358 second=256 amount=-1 +kerning first=354 second=8249 amount=-1 +kerning first=1059 second=1077 amount=-1 +kerning first=8220 second=8220 amount=-1 +kerning first=197 second=87 amount=-1 +kerning first=221 second=269 amount=-1 +kerning first=84 second=273 amount=-1 +kerning first=8217 second=347 amount=-1 +kerning first=356 second=225 amount=-1 +kerning first=221 second=117 amount=-1 +kerning first=932 second=333 amount=-1 +kerning first=1027 second=1096 amount=-1 +kerning first=8211 second=939 amount=-1 +kerning first=84 second=277 amount=-1 +kerning first=8221 second=283 amount=-1 +kerning first=256 second=936 amount=-1 +kerning first=354 second=948 amount=-1 +kerning first=376 second=257 amount=-1 +kerning first=358 second=171 amount=-1 +kerning first=376 second=113 amount=-1 +kerning first=915 second=192 amount=-1 +kerning first=260 second=932 amount=-1 +kerning first=8216 second=196 amount=-1 +kerning first=345 second=44 amount=-1 +kerning first=221 second=197 amount=-1 +kerning first=194 second=939 amount=-1 +kerning first=932 second=959 amount=-1 +kerning first=315 second=8216 amount=-1 +kerning first=171 second=910 amount=-1 +kerning first=939 second=949 amount=-1 +kerning first=932 second=233 amount=-1 +kerning first=929 second=913 amount=-1 +kerning first=356 second=305 amount=-1 +kerning first=1033 second=1038 amount=-1 +kerning first=1058 second=1116 amount=-1 +kerning first=376 second=193 amount=-1 +kerning first=8217 second=99 amount=-1 +kerning first=1043 second=1078 amount=-1 +kerning first=1168 second=1169 amount=-1 +kerning first=89 second=349 amount=-1 +kerning first=929 second=258 amount=-1 +kerning first=936 second=44 amount=-1 +kerning first=317 second=45 amount=-1 +kerning first=40 second=354 amount=1 +kerning first=70 second=198 amount=-1 +kerning first=8216 second=333 amount=-1 +kerning first=913 second=372 amount=-1 +kerning first=356 second=273 amount=-1 +kerning first=1038 second=1077 amount=-1 +kerning first=86 second=193 amount=-1 +kerning first=84 second=351 amount=-1 +kerning first=356 second=277 amount=-1 +kerning first=8221 second=349 amount=-1 +kerning first=80 second=192 amount=-1 +kerning first=376 second=335 amount=-1 +kerning first=76 second=173 amount=-1 +kerning first=197 second=933 amount=-1 +kerning first=915 second=961 amount=-1 +kerning first=1058 second=1060 amount=-1 +kerning first=8217 second=44 amount=-2 +kerning first=8216 second=959 amount=-1 +kerning first=256 second=372 amount=-1 +kerning first=354 second=269 amount=-1 +kerning first=70 second=261 amount=-1 +kerning first=8216 second=233 amount=-1 +kerning first=221 second=235 amount=-1 +kerning first=354 second=117 amount=-1 +kerning first=89 second=101 amount=-1 +kerning first=1091 second=44 amount=-1 +kerning first=84 second=239 amount=-1 +kerning first=932 second=291 amount=-1 +kerning first=376 second=227 amount=-1 +kerning first=1043 second=1113 amount=-1 +kerning first=321 second=39 amount=-1 +kerning first=109 second=84 amount=-1 +kerning first=923 second=221 amount=-1 +kerning first=1027 second=1075 amount=-1 +kerning first=358 second=263 amount=-1 +kerning first=84 second=100 amount=-1 +kerning first=8221 second=101 amount=-1 +kerning first=354 second=197 amount=-1 +kerning first=70 second=194 amount=-1 +kerning first=8220 second=196 amount=-1 +kerning first=8204 second=376 amount=-1 +kerning first=923 second=84 amount=-1 +kerning first=89 second=46 amount=-1 +kerning first=308 second=125 amount=1 +kerning first=356 second=351 amount=-1 +kerning first=939 second=195 amount=-1 +kerning first=317 second=8212 amount=-1 +kerning first=1058 second=1094 amount=-1 +kerning first=358 second=192 amount=-1 +kerning first=221 second=41 amount=1 +kerning first=1168 second=1098 amount=-1 +kerning first=354 second=341 amount=-1 +kerning first=8220 second=333 amount=-1 +kerning first=225 second=84 amount=-1 +kerning first=84 second=45 amount=-1 +kerning first=8221 second=46 amount=-2 +kerning first=193 second=8221 amount=-1 +kerning first=102 second=125 amount=1 +kerning first=8216 second=291 amount=-1 +kerning first=356 second=239 amount=-1 +kerning first=932 second=363 amount=-1 +kerning first=84 second=303 amount=-1 +kerning first=354 second=963 amount=-1 +kerning first=195 second=8216 amount=-1 +kerning first=258 second=86 amount=-1 +kerning first=8220 second=959 amount=-1 +kerning first=356 second=100 amount=-1 +kerning first=227 second=358 amount=-1 +kerning first=354 second=235 amount=-1 +kerning first=939 second=8230 amount=-1 +kerning first=8220 second=233 amount=-1 +kerning first=8222 second=221 amount=-1 +kerning first=260 second=939 amount=-1 +kerning first=193 second=354 amount=-1 +kerning first=936 second=923 amount=-1 +kerning first=965 second=39 amount=-1 +kerning first=1026 second=1058 amount=-1 +kerning first=8217 second=160 amount=-1 +kerning first=932 second=245 amount=-1 +kerning first=1059 second=46 amount=-1 +kerning first=358 second=961 amount=-1 +kerning first=1058 second=8250 amount=-1 +kerning first=8222 second=84 amount=-1 +kerning first=1066 second=8217 amount=-1 +kerning first=358 second=234 amount=-1 +kerning first=929 second=196 amount=-1 +kerning first=933 second=962 amount=-1 +kerning first=1043 second=1091 amount=-1 +kerning first=356 second=45 amount=-1 +kerning first=89 second=198 amount=-1 +kerning first=968 second=34 amount=-1 +kerning first=221 second=367 amount=-1 +kerning first=8217 second=923 amount=-1 +kerning first=196 second=87 amount=-1 +kerning first=354 second=41 amount=1 +kerning first=356 second=303 amount=-1 +kerning first=84 second=8212 amount=-1 +kerning first=915 second=970 amount=-1 +kerning first=376 second=365 amount=-1 +kerning first=8221 second=198 amount=-1 +kerning first=910 second=46 amount=-1 +kerning first=1168 second=1077 amount=-1 +kerning first=89 second=261 amount=-1 +kerning first=8216 second=245 amount=-1 +kerning first=8220 second=291 amount=-1 +kerning first=80 second=74 amount=-1 +kerning first=326 second=356 amount=-1 +kerning first=221 second=250 amount=-1 +kerning first=258 second=932 amount=-1 +kerning first=933 second=256 amount=-1 +kerning first=1038 second=46 amount=-1 +kerning first=313 second=8216 amount=-1 +kerning first=160 second=89 amount=-1 +kerning first=376 second=246 amount=-1 +kerning first=1027 second=1088 amount=-1 +kerning first=84 second=257 amount=-1 +kerning first=358 second=289 amount=-1 +kerning first=84 second=113 amount=-1 +kerning first=89 second=194 amount=-1 +kerning first=910 second=945 amount=-1 +kerning first=934 second=44 amount=-1 +kerning first=91 second=106 amount=1 +kerning first=70 second=308 amount=-1 +kerning first=913 second=8221 amount=-1 +kerning first=91 second=1095 amount=-1 +kerning first=319 second=221 amount=-1 +kerning first=1040 second=1026 amount=-1 +kerning first=84 second=193 amount=-1 +kerning first=8221 second=194 amount=-1 +kerning first=356 second=8212 amount=-1 +kerning first=1058 second=1108 amount=-1 +kerning first=1027 second=44 amount=-1 +kerning first=1027 second=1032 amount=-1 +kerning first=196 second=933 amount=-1 +kerning first=319 second=84 amount=-1 +kerning first=354 second=367 amount=-1 +kerning first=89 second=337 amount=-1 +kerning first=256 second=8221 amount=-1 +kerning first=358 second=74 amount=-1 +kerning first=915 second=8211 amount=-1 +kerning first=913 second=354 amount=-1 +kerning first=40 second=87 amount=1 +kerning first=934 second=939 amount=-1 +kerning first=910 second=198 amount=-1 +kerning first=84 second=335 amount=-1 +kerning first=356 second=257 amount=-1 +kerning first=8221 second=337 amount=-1 +kerning first=932 second=230 amount=-1 +kerning first=358 second=371 amount=-1 +kerning first=354 second=972 amount=-1 +kerning first=356 second=113 amount=-1 +kerning first=354 second=250 amount=-1 +kerning first=89 second=231 amount=-1 +kerning first=8220 second=245 amount=-1 +kerning first=76 second=372 amount=-1 +kerning first=8212 second=221 amount=-1 +kerning first=256 second=354 amount=-1 +kerning first=1061 second=1095 amount=-1 +kerning first=221 second=226 amount=-1 +kerning first=354 second=109 amount=-1 +kerning first=324 second=358 amount=-1 +kerning first=89 second=93 amount=1 +kerning first=8212 second=84 amount=-1 +kerning first=1058 second=8230 amount=-1 +kerning first=84 second=227 amount=-1 +kerning first=904 second=912 amount=1 +kerning first=356 second=193 amount=-1 +kerning first=87 second=46 amount=-1 +kerning first=358 second=353 amount=-1 +kerning first=8217 second=281 amount=-1 +kerning first=8221 second=231 amount=-1 +kerning first=1043 second=1105 amount=-1 +kerning first=932 second=271 amount=-1 +kerning first=1169 second=8230 amount=-1 +kerning first=910 second=194 amount=-1 +kerning first=187 second=89 amount=-1 +kerning first=356 second=335 amount=-1 +kerning first=8250 second=354 amount=-1 +kerning first=1058 second=1086 amount=-1 +kerning first=192 second=8216 amount=-1 +kerning first=224 second=358 amount=-1 +kerning first=1168 second=1090 amount=-1 +kerning first=932 second=65 amount=-1 +kerning first=354 second=324 amount=-1 +kerning first=933 second=192 amount=-1 +kerning first=258 second=939 amount=-1 +kerning first=1040 second=1095 amount=-1 +kerning first=306 second=93 amount=1 +kerning first=8216 second=271 amount=-1 +kerning first=221 second=283 amount=-1 +kerning first=356 second=227 amount=-1 +kerning first=932 second=347 amount=-1 +kerning first=1027 second=1101 amount=-1 +kerning first=917 second=912 amount=1 +kerning first=84 second=287 amount=-1 +kerning first=8221 second=285 amount=-1 +kerning first=91 second=358 amount=1 +kerning first=372 second=301 amount=1 +kerning first=376 second=265 amount=-1 +kerning first=354 second=226 amount=-1 +kerning first=358 second=8211 amount=-1 +kerning first=1168 second=46 amount=-1 +kerning first=87 second=198 amount=-1 +kerning first=89 second=308 amount=-1 +kerning first=932 second=966 amount=-1 +kerning first=8217 second=244 amount=-1 +kerning first=1059 second=1026 amount=1 +kerning first=193 second=87 amount=-1 +kerning first=932 second=238 amount=-1 +kerning first=65 second=221 amount=-1 +kerning first=358 second=225 amount=-1 +kerning first=902 second=8216 amount=-1 +kerning first=376 second=195 amount=-1 +kerning first=8216 second=65 amount=-1 +kerning first=936 second=260 amount=-1 +kerning first=933 second=961 amount=-1 +kerning first=8221 second=308 amount=-1 +kerning first=8249 second=939 amount=-1 +kerning first=932 second=99 amount=-1 +kerning first=89 second=369 amount=-1 +kerning first=329 second=84 amount=-1 +kerning first=1041 second=1035 amount=-1 +kerning first=1043 second=1083 amount=-1 +kerning first=65 second=84 amount=-1 +kerning first=328 second=356 amount=-1 +kerning first=221 second=349 amount=-1 +kerning first=160 second=8220 amount=-1 +kerning first=86 second=195 amount=-1 +kerning first=84 second=365 amount=-1 +kerning first=356 second=287 amount=-1 +kerning first=173 second=376 amount=-1 +kerning first=8217 second=260 amount=-1 +kerning first=354 second=331 amount=-1 +kerning first=358 second=305 amount=-1 +kerning first=89 second=242 amount=-1 +kerning first=376 second=8230 amount=-1 +kerning first=8216 second=966 amount=-1 +kerning first=87 second=194 amount=-1 +kerning first=354 second=283 amount=-1 +kerning first=932 second=44 amount=-1 +kerning first=8220 second=271 amount=-1 +kerning first=354 second=122 amount=-1 +kerning first=315 second=39 amount=-1 +kerning first=84 second=941 amount=-1 +kerning first=102 second=8216 amount=1 +kerning first=34 second=256 amount=-1 +kerning first=84 second=246 amount=-1 +kerning first=8221 second=242 amount=-1 +kerning first=317 second=221 amount=-1 +kerning first=1038 second=1026 amount=1 +kerning first=358 second=273 amount=-1 +kerning first=8216 second=99 amount=-1 +kerning first=221 second=101 amount=-1 +kerning first=932 second=299 amount=-1 +kerning first=376 second=232 amount=-1 +kerning first=308 second=41 amount=1 +kerning first=86 second=8230 amount=-1 +kerning first=1027 second=1080 amount=-1 +kerning first=1043 second=1119 amount=-1 +kerning first=229 second=356 amount=-1 +kerning first=358 second=277 amount=-1 +kerning first=97 second=354 amount=-1 +kerning first=84 second=105 amount=-1 +kerning first=317 second=84 amount=-1 +kerning first=193 second=933 amount=-1 +kerning first=376 second=97 amount=-1 +kerning first=1111 second=1115 amount=1 +kerning first=923 second=89 amount=-1 +kerning first=321 second=376 amount=-1 +kerning first=8220 second=65 amount=-1 +kerning first=356 second=365 amount=-1 +kerning first=84 second=916 amount=-1 +kerning first=173 second=358 amount=-1 +kerning first=102 second=41 amount=1 +kerning first=915 second=45 amount=-1 +kerning first=1058 second=1099 amount=-1 +kerning first=271 second=316 amount=1 +kerning first=221 second=46 amount=-1 +kerning first=8216 second=44 amount=-1 +kerning first=8216 second=1032 amount=-1 +kerning first=1168 second=1103 amount=-1 +kerning first=354 second=349 amount=-1 +kerning first=76 second=8221 amount=-1 +kerning first=356 second=941 amount=-1 +kerning first=923 second=34 amount=-1 +kerning first=356 second=246 amount=-1 +kerning first=87 second=93 amount=1 +kerning first=913 second=87 amount=-1 +kerning first=1056 second=8230 amount=-2 +kerning first=110 second=358 amount=-1 +kerning first=358 second=351 amount=-1 +kerning first=326 second=932 amount=-1 +kerning first=8220 second=966 amount=-1 +kerning first=356 second=105 amount=-1 +kerning first=354 second=236 amount=-1 +kerning first=1058 second=1044 amount=-1 +kerning first=1168 second=59 amount=-1 +kerning first=76 second=354 amount=-1 +kerning first=256 second=87 amount=-1 +kerning first=932 second=974 amount=-1 +kerning first=321 second=358 amount=-1 +kerning first=354 second=101 amount=-1 +kerning first=8220 second=99 amount=-1 +kerning first=356 second=916 amount=-1 +kerning first=932 second=249 amount=-1 +kerning first=84 second=949 amount=-1 +kerning first=936 second=197 amount=-1 +kerning first=1026 second=1063 amount=-1 +kerning first=1059 second=1040 amount=-1 +kerning first=8222 second=89 amount=-1 +kerning first=8217 second=269 amount=-1 +kerning first=358 second=239 amount=-1 +kerning first=932 second=259 amount=-1 +kerning first=933 second=970 amount=1 +kerning first=1043 second=1096 amount=-1 +kerning first=194 second=8216 amount=-1 +kerning first=932 second=112 amount=-1 +kerning first=39 second=256 amount=-1 +kerning first=226 second=358 amount=-1 +kerning first=358 second=100 amount=-1 +kerning first=929 second=65 amount=-1 +kerning first=915 second=8212 amount=-1 +kerning first=221 second=198 amount=-1 +kerning first=160 second=8222 amount=-1 +kerning first=932 second=923 amount=-1 +kerning first=8217 second=197 amount=-1 +kerning first=354 second=46 amount=-1 +kerning first=84 second=378 amount=-1 +kerning first=8220 second=44 amount=-1 +kerning first=939 second=913 amount=-1 +kerning first=195 second=39 amount=-1 +kerning first=8220 second=1032 amount=-1 +kerning first=915 second=912 amount=-1 +kerning first=376 second=361 amount=-1 +kerning first=1058 second=1078 amount=-1 +kerning first=197 second=221 amount=-1 +kerning first=913 second=933 amount=-1 +kerning first=8216 second=974 amount=-1 +kerning first=1168 second=1082 amount=-1 +kerning first=939 second=258 amount=-1 +kerning first=354 second=297 amount=-1 +kerning first=89 second=267 amount=-1 +kerning first=1118 second=46 amount=-1 +kerning first=34 second=192 amount=-1 +kerning first=358 second=45 amount=-1 +kerning first=356 second=949 amount=-1 +kerning first=197 second=84 amount=-1 +kerning first=221 second=261 amount=-1 +kerning first=1038 second=1040 amount=-1 +kerning first=932 second=326 amount=-1 +kerning first=376 second=251 amount=-1 +kerning first=1027 second=1093 amount=-1 +kerning first=84 second=265 amount=-1 +kerning first=8221 second=267 amount=-1 +kerning first=358 second=303 amount=-1 +kerning first=256 second=933 amount=-1 +kerning first=354 second=945 amount=-1 +kerning first=295 second=84 amount=-1 +kerning first=8216 second=923 amount=-1 +kerning first=915 second=193 amount=-1 +kerning first=1168 second=1026 amount=1 +kerning first=933 second=8211 amount=-1 +kerning first=221 second=194 amount=-1 +kerning first=8217 second=235 amount=-1 +kerning first=356 second=378 amount=-1 +kerning first=1107 second=44 amount=-1 +kerning first=932 second=229 amount=-1 +kerning first=915 second=58 amount=-1 +kerning first=1068 second=1059 amount=-1 +kerning first=84 second=195 amount=-1 +kerning first=1058 second=1113 amount=-1 +kerning first=1043 second=1075 amount=-1 +kerning first=34 second=961 amount=-1 +kerning first=1168 second=1118 amount=-1 +kerning first=319 second=89 amount=-1 +kerning first=354 second=198 amount=-1 +kerning first=929 second=44 amount=-2 +kerning first=221 second=337 amount=-1 +kerning first=313 second=39 amount=-1 +kerning first=1075 second=8230 amount=-1 +kerning first=173 second=910 amount=-1 +kerning first=84 second=345 amount=-1 +kerning first=356 second=265 amount=-1 +kerning first=1035 second=1026 amount=-1 +kerning first=80 second=193 amount=-1 +kerning first=84 second=8230 amount=-1 +kerning first=8220 second=974 amount=-1 +kerning first=228 second=356 amount=-1 +kerning first=358 second=8212 amount=-1 +kerning first=923 second=8220 amount=-1 +kerning first=319 second=34 amount=-1 +kerning first=271 second=98 amount=1 +kerning first=354 second=261 amount=-1 +kerning first=241 second=84 amount=-1 +kerning first=221 second=231 amount=-1 +kerning first=46 second=34 amount=-1 +kerning first=354 second=114 amount=-1 +kerning first=1040 second=1066 amount=-1 +kerning first=8212 second=89 amount=-1 +kerning first=84 second=232 amount=-1 +kerning first=356 second=195 amount=-1 +kerning first=39 second=192 amount=-1 +kerning first=221 second=93 amount=1 +kerning first=932 second=281 amount=-1 +kerning first=376 second=228 amount=-1 +kerning first=1027 second=1072 amount=-1 +kerning first=260 second=8216 amount=-1 +kerning first=932 second=125 amount=1 +kerning first=358 second=257 amount=-1 +kerning first=8220 second=923 amount=-1 +kerning first=84 second=97 amount=-1 +kerning first=354 second=194 amount=-1 +kerning first=358 second=113 amount=-1 +kerning first=187 second=356 amount=-1 +kerning first=1057 second=1095 amount=-1 +kerning first=356 second=345 amount=-1 +kerning first=1068 second=1038 amount=-1 +kerning first=935 second=912 amount=1 +kerning first=356 second=8230 amount=-1 +kerning first=939 second=196 amount=-1 +kerning first=1058 second=1091 amount=-1 +kerning first=358 second=193 amount=-1 +kerning first=328 second=932 amount=-1 +kerning first=376 second=248 amount=-1 +kerning first=1056 second=1044 amount=-1 +kerning first=1168 second=1095 amount=-1 +kerning first=354 second=337 amount=-1 +kerning first=76 second=8211 amount=-1 +kerning first=372 second=256 amount=-1 +kerning first=1113 second=1098 amount=-1 diff --git a/art/font/myriad-medium-small.png b/art/font/myriad-medium-small.png new file mode 100644 index 00000000..628dd2b8 Binary files /dev/null and b/art/font/myriad-medium-small.png differ diff --git a/art/font/myriad-medium.fnt b/art/font/myriad-medium.fnt new file mode 100644 index 00000000..7e302b2b --- /dev/null +++ b/art/font/myriad-medium.fnt @@ -0,0 +1,3951 @@ +info face="MyriadPro-Regular" size=14 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=18 base=11 scaleW=128 scaleH=512 pages=1 packed=0 +page id=0 file="myriad-medium.png" +chars count=506 +char id=0 x=9 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=13 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=0 page=0 chnl=0 +char id=33 x=121 y=121 width=5 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=34 x=81 y=425 width=7 height=6 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=35 x=18 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=36 x=110 y=0 width=9 height=15 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=37 x=27 y=162 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=38 x=40 y=162 width=11 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=39 x=88 y=425 width=4 height=6 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=40 x=115 y=92 width=6 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=41 x=121 y=92 width=6 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=42 x=12 y=425 width=8 height=7 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=43 x=110 y=367 width=10 height=10 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=44 x=20 y=425 width=5 height=7 xoffset=-1 yoffset=8 xadvance=3 page=0 chnl=0 +char id=45 x=75 y=433 width=6 height=3 xoffset=-1 yoffset=6 xadvance=4 page=0 chnl=0 +char id=46 x=39 y=433 width=5 height=4 xoffset=-1 yoffset=8 xadvance=3 page=0 chnl=0 +char id=47 x=105 y=135 width=8 height=13 xoffset=-2 yoffset=0 xadvance=5 page=0 chnl=0 +char id=48 x=51 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=49 x=60 y=162 width=6 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=50 x=66 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=51 x=75 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=52 x=84 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=53 x=93 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=54 x=102 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=55 x=111 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=56 x=0 y=175 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=57 x=113 y=135 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=58 x=120 y=367 width=5 height=9 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=59 x=120 y=162 width=5 height=12 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=60 x=32 y=379 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=61 x=92 y=425 width=10 height=6 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=0 +char id=62 x=42 y=379 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=63 x=9 y=175 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=64 x=17 y=175 width=12 height=12 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=65 x=29 y=175 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=66 x=40 y=175 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=67 x=49 y=175 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=68 x=59 y=175 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=69 x=69 y=175 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=70 x=77 y=175 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=71 x=85 y=175 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=72 x=96 y=175 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=73 x=122 y=135 width=4 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=74 x=106 y=175 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=75 x=113 y=175 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=76 x=0 y=187 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=77 x=8 y=187 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=78 x=21 y=187 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=79 x=31 y=187 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=80 x=43 y=187 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=81 x=0 y=107 width=12 height=14 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=82 x=51 y=187 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=83 x=60 y=187 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=84 x=69 y=187 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=85 x=79 y=187 width=9 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=86 x=88 y=187 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=87 x=98 y=187 width=14 height=12 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=88 x=112 y=187 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=89 x=0 y=199 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=90 x=10 y=199 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=91 x=12 y=107 width=5 height=14 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=92 x=0 y=149 width=7 height=13 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=93 x=17 y=107 width=5 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=94 x=52 y=379 width=10 height=9 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=95 x=81 y=433 width=9 height=3 xoffset=-1 yoffset=11 xadvance=7 page=0 chnl=0 +char id=96 x=121 y=425 width=5 height=5 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=97 x=62 y=379 width=8 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=98 x=20 y=199 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=99 x=70 y=379 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=100 x=30 y=199 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=101 x=78 y=379 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=102 x=39 y=199 width=7 height=12 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=103 x=46 y=199 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=104 x=55 y=199 width=8 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=105 x=122 y=175 width=5 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=106 x=119 y=0 width=6 height=15 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=107 x=63 y=199 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=108 x=122 y=187 width=4 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=109 x=87 y=379 width=13 height=9 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=110 x=100 y=379 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=111 x=109 y=379 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=112 x=71 y=199 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=113 x=81 y=199 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=114 x=119 y=379 width=7 height=9 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=115 x=0 y=389 width=7 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=116 x=18 y=367 width=7 height=11 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=117 x=7 y=389 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=118 x=16 y=389 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=119 x=25 y=389 width=13 height=9 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=120 x=38 y=389 width=9 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=121 x=22 y=107 width=9 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=122 x=47 y=389 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=123 x=31 y=107 width=6 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=124 x=0 y=0 width=4 height=17 xoffset=0 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=125 x=37 y=107 width=6 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=126 x=0 y=433 width=10 height=5 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0 +char id=160 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=161 x=90 y=199 width=5 height=12 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=162 x=7 y=149 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=163 x=95 y=199 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=164 x=0 y=379 width=9 height=10 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=165 x=104 y=199 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=166 x=43 y=107 width=4 height=14 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=167 x=16 y=149 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=168 x=44 y=433 width=7 height=4 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=169 x=25 y=367 width=11 height=11 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=0 +char id=170 x=25 y=425 width=7 height=7 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=171 x=94 y=416 width=8 height=8 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=172 x=32 y=425 width=10 height=7 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=0 +char id=173 x=90 y=433 width=6 height=3 xoffset=-1 yoffset=6 xadvance=4 page=0 chnl=0 +char id=174 x=42 y=425 width=8 height=7 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=175 x=96 y=433 width=6 height=3 xoffset=-1 yoffset=1 xadvance=4 page=0 chnl=0 +char id=176 x=102 y=425 width=7 height=6 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=177 x=9 y=379 width=10 height=10 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=178 x=102 y=416 width=6 height=8 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=179 x=108 y=416 width=6 height=8 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=180 x=10 y=433 width=5 height=5 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=181 x=113 y=199 width=9 height=12 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=182 x=47 y=107 width=8 height=14 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=183 x=51 y=433 width=5 height=4 xoffset=-1 yoffset=5 xadvance=3 page=0 chnl=0 +char id=184 x=15 y=433 width=6 height=5 xoffset=-1 yoffset=10 xadvance=4 page=0 chnl=0 +char id=185 x=114 y=416 width=5 height=8 xoffset=-1 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=186 x=50 y=425 width=7 height=7 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=187 x=119 y=416 width=8 height=8 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=188 x=0 y=211 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=189 x=13 y=211 width=12 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=190 x=25 y=211 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=191 x=38 y=211 width=8 height=12 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=192 x=0 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=193 x=11 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=194 x=22 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=195 x=33 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=196 x=55 y=107 width=11 height=14 xoffset=-1 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=197 x=44 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=198 x=46 y=211 width=14 height=12 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=199 x=55 y=17 width=10 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=200 x=65 y=17 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=201 x=73 y=17 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=202 x=81 y=17 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=203 x=66 y=107 width=8 height=14 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=204 x=89 y=17 width=6 height=15 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=205 x=95 y=17 width=6 height=15 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=206 x=101 y=17 width=7 height=15 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=207 x=74 y=107 width=7 height=14 xoffset=-2 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=208 x=60 y=211 width=12 height=12 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=209 x=108 y=17 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=210 x=0 y=32 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=211 x=12 y=32 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=212 x=81 y=107 width=12 height=14 xoffset=-1 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=213 x=24 y=32 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=214 x=93 y=107 width=12 height=14 xoffset=-1 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=215 x=55 y=389 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=216 x=25 y=149 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=217 x=118 y=17 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=218 x=36 y=32 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=219 x=45 y=32 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=220 x=105 y=107 width=9 height=14 xoffset=0 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=221 x=54 y=32 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=222 x=72 y=211 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=223 x=80 y=211 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=224 x=89 y=211 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=225 x=97 y=211 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=226 x=105 y=211 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=227 x=113 y=211 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=228 x=0 y=223 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=229 x=8 y=223 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=230 x=65 y=389 width=13 height=9 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=231 x=16 y=223 width=8 height=12 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=232 x=24 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=233 x=33 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=234 x=42 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=235 x=51 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=236 x=121 y=211 width=6 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=237 x=60 y=223 width=6 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=238 x=66 y=223 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=239 x=73 y=223 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=240 x=80 y=223 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=241 x=90 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=242 x=99 y=223 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=243 x=109 y=223 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=244 x=0 y=235 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=245 x=10 y=235 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=246 x=20 y=235 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=247 x=78 y=389 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=248 x=36 y=367 width=10 height=11 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=249 x=30 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=250 x=39 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=251 x=48 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=252 x=57 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=253 x=4 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=254 x=64 y=32 width=9 height=15 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=255 x=13 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=256 x=114 y=107 width=11 height=14 xoffset=-1 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=257 x=46 y=367 width=8 height=11 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=258 x=73 y=32 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=259 x=119 y=223 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=260 x=84 y=32 width=11 height=15 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=261 x=66 y=235 width=9 height=12 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=262 x=95 y=32 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=263 x=75 y=235 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=264 x=105 y=32 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=265 x=83 y=235 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=266 x=0 y=121 width=10 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=267 x=91 y=235 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=268 x=10 y=121 width=10 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=269 x=99 y=235 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=270 x=115 y=32 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=271 x=107 y=235 width=11 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=272 x=0 y=247 width=12 height=12 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=273 x=12 y=247 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=274 x=20 y=121 width=8 height=14 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=275 x=54 y=367 width=9 height=11 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=276 x=0 y=47 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=277 x=118 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=278 x=28 y=121 width=8 height=14 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=279 x=22 y=247 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=280 x=8 y=47 width=8 height=15 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=281 x=31 y=247 width=9 height=12 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=282 x=16 y=47 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=283 x=40 y=247 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=284 x=24 y=47 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=285 x=35 y=47 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=286 x=44 y=47 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=287 x=55 y=47 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=288 x=36 y=121 width=11 height=14 xoffset=-1 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=289 x=64 y=47 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=290 x=40 y=0 width=11 height=16 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=291 x=73 y=47 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=292 x=82 y=47 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=293 x=47 y=121 width=10 height=14 xoffset=-2 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=294 x=49 y=247 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=295 x=60 y=247 width=10 height=12 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=296 x=92 y=47 width=7 height=15 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=297 x=70 y=247 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=298 x=57 y=121 width=6 height=14 xoffset=-1 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=299 x=121 y=307 width=6 height=11 xoffset=-1 yoffset=1 xadvance=3 page=0 chnl=0 +char id=300 x=99 y=47 width=7 height=15 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=301 x=77 y=247 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=302 x=106 y=47 width=5 height=15 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=303 x=111 y=47 width=5 height=15 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=304 x=63 y=121 width=5 height=14 xoffset=-1 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=305 x=123 y=331 width=4 height=9 xoffset=0 yoffset=3 xadvance=3 page=0 chnl=0 +char id=306 x=84 y=247 width=9 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=307 x=116 y=47 width=8 height=15 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=308 x=0 y=62 width=8 height=15 xoffset=-1 yoffset=-3 xadvance=5 page=0 chnl=0 +char id=309 x=8 y=62 width=7 height=15 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=310 x=51 y=0 width=9 height=16 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=311 x=60 y=0 width=8 height=16 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=312 x=88 y=389 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=313 x=15 y=62 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=314 x=23 y=62 width=6 height=15 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=315 x=68 y=0 width=8 height=16 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=316 x=76 y=0 width=5 height=16 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=317 x=93 y=247 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=318 x=101 y=247 width=7 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=319 x=108 y=247 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=320 x=116 y=247 width=6 height=12 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=321 x=0 y=259 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=322 x=10 y=259 width=6 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=323 x=29 y=62 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=324 x=16 y=259 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=325 x=81 y=0 width=10 height=16 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=326 x=37 y=149 width=9 height=13 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=327 x=39 y=62 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=328 x=25 y=259 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=329 x=46 y=149 width=9 height=13 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=330 x=49 y=62 width=10 height=15 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=331 x=34 y=259 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=332 x=68 y=121 width=12 height=14 xoffset=-1 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=333 x=63 y=367 width=10 height=11 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=334 x=59 y=62 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=335 x=43 y=259 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=336 x=71 y=62 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=337 x=53 y=259 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=338 x=80 y=121 width=14 height=14 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=0 +char id=339 x=96 y=389 width=14 height=9 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=340 x=83 y=62 width=9 height=15 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=341 x=63 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=342 x=91 y=0 width=9 height=16 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=343 x=55 y=149 width=7 height=13 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=344 x=92 y=62 width=9 height=15 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=345 x=70 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=346 x=101 y=62 width=9 height=15 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=347 x=77 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=348 x=94 y=121 width=9 height=14 xoffset=-1 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=349 x=84 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=350 x=110 y=62 width=9 height=15 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=351 x=91 y=259 width=7 height=12 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=352 x=103 y=121 width=9 height=14 xoffset=-1 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=353 x=98 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=354 x=100 y=0 width=10 height=16 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=355 x=119 y=62 width=7 height=15 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=356 x=0 y=77 width=10 height=15 xoffset=-2 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=357 x=105 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=358 x=112 y=259 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=359 x=73 y=367 width=7 height=11 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=360 x=10 y=77 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=361 x=0 y=271 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=362 x=112 y=121 width=9 height=14 xoffset=0 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=363 x=80 y=367 width=9 height=11 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=364 x=19 y=77 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=365 x=9 y=271 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=366 x=28 y=77 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=367 x=18 y=271 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=368 x=37 y=77 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=369 x=27 y=271 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=370 x=46 y=77 width=9 height=15 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=371 x=36 y=271 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=372 x=55 y=77 width=14 height=15 xoffset=-1 yoffset=-3 xadvance=12 page=0 chnl=0 +char id=373 x=46 y=271 width=13 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=374 x=69 y=77 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=375 x=22 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=376 x=0 y=135 width=10 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=377 x=79 y=77 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=378 x=59 y=271 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=379 x=10 y=135 width=10 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=380 x=67 y=271 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=381 x=89 y=77 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=382 x=75 y=271 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=894 x=89 y=367 width=5 height=11 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=0 +char id=900 x=21 y=433 width=5 height=5 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=901 x=26 y=433 width=7 height=5 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=902 x=83 y=271 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=903 x=56 y=433 width=5 height=4 xoffset=-1 yoffset=5 xadvance=3 page=0 chnl=0 +char id=904 x=94 y=271 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=905 x=104 y=271 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=906 x=116 y=271 width=6 height=12 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=908 x=0 y=283 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=910 x=12 y=283 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=911 x=24 y=283 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=912 x=62 y=149 width=9 height=13 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=913 x=36 y=283 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=914 x=47 y=283 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=915 x=56 y=283 width=8 height=12 xoffset=0 yoffset=0 xadvance=6 page=0 chnl=0 +char id=916 x=64 y=283 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=917 x=75 y=283 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=918 x=83 y=283 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=919 x=93 y=283 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=920 x=103 y=283 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=921 x=122 y=199 width=4 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=922 x=115 y=283 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=923 x=0 y=295 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=924 x=11 y=295 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=925 x=24 y=295 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=926 x=34 y=295 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=927 x=44 y=295 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=928 x=56 y=295 width=9 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=929 x=65 y=295 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=931 x=73 y=295 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=932 x=83 y=295 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=933 x=93 y=295 width=11 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=934 x=20 y=135 width=12 height=14 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=935 x=104 y=295 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=936 x=114 y=295 width=11 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=937 x=0 y=307 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=938 x=32 y=135 width=7 height=14 xoffset=-2 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=939 x=39 y=135 width=11 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=940 x=12 y=307 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=941 x=22 y=307 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=942 x=99 y=77 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=943 x=122 y=247 width=5 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=944 x=71 y=149 width=9 height=13 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=945 x=110 y=389 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=946 x=108 y=77 width=10 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=947 x=30 y=307 width=10 height=12 xoffset=-2 yoffset=3 xadvance=7 page=0 chnl=0 +char id=948 x=40 y=307 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=949 x=0 y=398 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=950 x=118 y=77 width=8 height=15 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=951 x=50 y=307 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=952 x=59 y=307 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=953 x=120 y=389 width=4 height=9 xoffset=0 yoffset=3 xadvance=3 page=0 chnl=0 +char id=954 x=8 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=955 x=68 y=307 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=956 x=77 y=307 width=9 height=12 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=957 x=17 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=958 x=0 y=92 width=8 height=15 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=959 x=26 y=398 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=960 x=36 y=398 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=961 x=86 y=307 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=962 x=94 y=367 width=8 height=11 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=963 x=46 y=398 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=964 x=56 y=398 width=9 height=9 xoffset=-2 yoffset=3 xadvance=6 page=0 chnl=0 +char id=965 x=65 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=966 x=80 y=149 width=11 height=13 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=967 x=96 y=307 width=9 height=12 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=968 x=50 y=135 width=11 height=14 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=0 +char id=969 x=74 y=398 width=12 height=9 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=970 x=105 y=307 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=971 x=112 y=307 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=972 x=0 y=319 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=973 x=10 y=319 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=974 x=19 y=319 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1025 x=61 y=135 width=8 height=14 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=1026 x=69 y=135 width=12 height=14 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1027 x=8 y=92 width=8 height=15 xoffset=0 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=1028 x=31 y=319 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1029 x=41 y=319 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1030 x=122 y=259 width=4 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=1031 x=81 y=135 width=7 height=14 xoffset=-2 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=1032 x=50 y=319 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=1033 x=91 y=149 width=15 height=13 xoffset=-2 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1034 x=57 y=319 width=14 height=12 xoffset=0 yoffset=0 xadvance=13 page=0 chnl=0 +char id=1035 x=71 y=319 width=12 height=12 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1036 x=16 y=92 width=9 height=15 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=1038 x=25 y=92 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=1039 x=35 y=92 width=9 height=15 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1040 x=83 y=319 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1041 x=94 y=319 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1042 x=103 y=319 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1043 x=112 y=319 width=8 height=12 xoffset=0 yoffset=0 xadvance=6 page=0 chnl=0 +char id=1044 x=44 y=92 width=11 height=15 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1045 x=0 y=331 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1046 x=8 y=331 width=14 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1047 x=22 y=331 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1048 x=31 y=331 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1049 x=55 y=92 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=1050 x=41 y=331 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1051 x=50 y=331 width=11 height=12 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1052 x=61 y=331 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1053 x=74 y=331 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1054 x=84 y=331 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1055 x=96 y=331 width=9 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1056 x=105 y=331 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1057 x=113 y=331 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1058 x=0 y=343 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1059 x=10 y=343 width=10 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1060 x=106 y=149 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1061 x=20 y=343 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1062 x=65 y=92 width=10 height=15 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1063 x=30 y=343 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1064 x=40 y=343 width=12 height=12 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1065 x=75 y=92 width=13 height=15 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1066 x=52 y=343 width=12 height=12 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1067 x=64 y=343 width=11 height=12 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1068 x=75 y=343 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1069 x=84 y=343 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1070 x=94 y=343 width=13 height=12 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1071 x=107 y=343 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1072 x=86 y=398 width=8 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1073 x=116 y=343 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1074 x=94 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1075 x=103 y=398 width=8 height=9 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=1076 x=0 y=355 width=9 height=12 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1077 x=111 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1078 x=0 y=407 width=12 height=9 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1079 x=12 y=407 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1080 x=20 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1081 x=9 y=355 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1082 x=29 y=407 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1083 x=37 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1084 x=46 y=407 width=11 height=9 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1085 x=57 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1086 x=66 y=407 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1087 x=76 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1088 x=18 y=355 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1089 x=85 y=407 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1090 x=93 y=407 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1091 x=88 y=135 width=9 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1092 x=88 y=92 width=11 height=15 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1093 x=101 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1094 x=28 y=355 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1095 x=110 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1096 x=0 y=416 width=12 height=9 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=1097 x=38 y=355 width=13 height=12 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=1098 x=12 y=416 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1099 x=22 y=416 width=11 height=9 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1100 x=33 y=416 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1101 x=119 y=407 width=8 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1102 x=42 y=416 width=12 height=9 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=1103 x=54 y=416 width=8 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1105 x=51 y=355 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1106 x=99 y=92 width=10 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1107 x=60 y=355 width=8 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=1108 x=62 y=416 width=9 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1109 x=120 y=398 width=7 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1110 x=122 y=271 width=5 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=1111 x=120 y=319 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=1112 x=109 y=92 width=6 height=15 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=1113 x=19 y=379 width=13 height=10 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1114 x=71 y=416 width=13 height=9 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1115 x=68 y=355 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1116 x=78 y=355 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1118 x=31 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1119 x=86 y=355 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1168 x=97 y=135 width=8 height=14 xoffset=0 yoffset=-2 xadvance=6 page=0 chnl=0 +char id=1169 x=102 y=367 width=8 height=11 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=1241 x=84 y=416 width=10 height=9 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=8204 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=8211 x=102 y=433 width=9 height=3 xoffset=-1 yoffset=6 xadvance=7 page=0 chnl=0 +char id=8212 x=111 y=433 width=16 height=3 xoffset=-1 yoffset=6 xadvance=14 page=0 chnl=0 +char id=8216 x=57 y=425 width=5 height=7 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=8217 x=62 y=425 width=5 height=7 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=8218 x=109 y=425 width=5 height=6 xoffset=-1 yoffset=8 xadvance=3 page=0 chnl=0 +char id=8220 x=67 y=425 width=7 height=7 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=8221 x=74 y=425 width=7 height=7 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=8222 x=114 y=425 width=7 height=6 xoffset=-1 yoffset=8 xadvance=5 page=0 chnl=0 +char id=8224 x=118 y=149 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=8225 x=0 y=162 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=8226 x=33 y=433 width=6 height=5 xoffset=-1 yoffset=5 xadvance=4 page=0 chnl=0 +char id=8230 x=61 y=433 width=14 height=4 xoffset=0 yoffset=8 xadvance=14 page=0 chnl=0 +char id=8240 x=95 y=355 width=18 height=12 xoffset=-1 yoffset=0 xadvance=16 page=0 chnl=0 +char id=8249 x=0 y=425 width=6 height=8 xoffset=-1 yoffset=3 xadvance=4 page=0 chnl=0 +char id=8250 x=6 y=425 width=6 height=8 xoffset=-1 yoffset=3 xadvance=4 page=0 chnl=0 +char id=8260 x=113 y=355 width=12 height=12 xoffset=-4 yoffset=0 xadvance=2 page=0 chnl=0 +char id=8363 x=0 y=367 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=8364 x=9 y=367 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +kernings count=3440 +kerning first=8216 second=281 amount=-1 +kerning first=221 second=285 amount=-1 +kerning first=39 second=961 amount=-1 +kerning first=356 second=232 amount=-1 +kerning first=34 second=74 amount=-1 +kerning first=1027 second=1107 amount=-1 +kerning first=8218 second=376 amount=-1 +kerning first=8221 second=301 amount=-1 +kerning first=358 second=335 amount=-1 +kerning first=957 second=46 amount=-1 +kerning first=257 second=84 amount=-1 +kerning first=376 second=279 amount=-1 +kerning first=356 second=97 amount=-1 +kerning first=354 second=231 amount=-1 +kerning first=89 second=210 amount=-1 +kerning first=70 second=224 amount=-1 +kerning first=1058 second=1035 amount=1 +kerning first=8216 second=937 amount=-1 +kerning first=1168 second=1040 amount=-1 +kerning first=76 second=87 amount=-1 +kerning first=932 second=940 amount=-1 +kerning first=354 second=93 amount=1 +kerning first=229 second=932 amount=-1 +kerning first=939 second=959 amount=-1 +kerning first=321 second=173 amount=-1 +kerning first=932 second=244 amount=-1 +kerning first=915 second=71 amount=-1 +kerning first=929 second=923 amount=-1 +kerning first=221 second=308 amount=-1 +kerning first=358 second=227 amount=-1 +kerning first=192 second=39 amount=-1 +kerning first=1043 second=1088 amount=-1 +kerning first=8217 second=109 amount=-1 +kerning first=196 second=221 amount=-1 +kerning first=65 second=89 amount=-1 +kerning first=947 second=44 amount=-1 +kerning first=221 second=369 amount=-1 +kerning first=315 second=262 amount=-1 +kerning first=1027 second=187 amount=-1 +kerning first=196 second=84 amount=-1 +kerning first=931 second=264 amount=-1 +kerning first=8218 second=358 amount=-1 +kerning first=1098 second=1091 amount=-1 +kerning first=84 second=361 amount=-1 +kerning first=915 second=941 amount=-1 +kerning first=939 second=181 amount=-1 +kerning first=1043 second=44 amount=-1 +kerning first=89 second=252 amount=-1 +kerning first=1043 second=1032 amount=-1 +kerning first=932 second=260 amount=-1 +kerning first=89 second=173 amount=-1 +kerning first=8216 second=940 amount=-1 +kerning first=1168 second=1074 amount=-1 +kerning first=354 second=285 amount=-1 +kerning first=8216 second=244 amount=-1 +kerning first=8220 second=281 amount=-1 +kerning first=221 second=242 amount=-1 +kerning first=65 second=34 amount=-1 +kerning first=89 second=111 amount=-1 +kerning first=1059 second=1066 amount=1 +kerning first=84 second=973 amount=-1 +kerning first=84 second=251 amount=-1 +kerning first=8217 second=324 amount=-1 +kerning first=109 second=356 amount=-1 +kerning first=933 second=45 amount=-1 +kerning first=160 second=86 amount=-1 +kerning first=1066 second=1059 amount=-1 +kerning first=902 second=39 amount=-1 +kerning first=1027 second=1085 amount=-1 +kerning first=319 second=8220 amount=-2 +kerning first=932 second=8249 amount=-1 +kerning first=358 second=287 amount=-1 +kerning first=8220 second=937 amount=-1 +kerning first=84 second=110 amount=-1 +kerning first=8221 second=111 amount=-1 +kerning first=915 second=916 amount=-2 +kerning first=317 second=89 amount=-1 +kerning first=46 second=8220 amount=-1 +kerning first=315 second=376 amount=-1 +kerning first=39 second=74 amount=-1 +kerning first=923 second=356 amount=-1 +kerning first=91 second=372 amount=1 +kerning first=45 second=376 amount=-1 +kerning first=227 second=354 amount=-1 +kerning first=354 second=308 amount=-1 +kerning first=315 second=332 amount=-1 +kerning first=8204 second=354 amount=-1 +kerning first=171 second=933 amount=-1 +kerning first=932 second=948 amount=-1 +kerning first=315 second=85 amount=-1 +kerning first=319 second=219 amount=-1 +kerning first=356 second=361 amount=-1 +kerning first=8216 second=260 amount=-1 +kerning first=1100 second=8217 amount=-1 +kerning first=221 second=262 amount=-1 +kerning first=376 second=913 amount=-1 +kerning first=1033 second=1026 amount=-1 +kerning first=1058 second=1105 amount=-1 +kerning first=1059 second=173 amount=-1 +kerning first=372 second=192 amount=-1 +kerning first=40 second=221 amount=1 +kerning first=225 second=356 amount=-1 +kerning first=1168 second=1109 amount=-1 +kerning first=319 second=81 amount=-1 +kerning first=354 second=369 amount=-1 +kerning first=376 second=258 amount=-1 +kerning first=317 second=34 amount=-1 +kerning first=356 second=973 amount=-1 +kerning first=102 second=39 amount=1 +kerning first=915 second=8250 amount=-1 +kerning first=40 second=84 amount=1 +kerning first=44 second=34 amount=-1 +kerning first=923 second=8217 amount=-1 +kerning first=356 second=251 amount=-1 +kerning first=1038 second=1066 amount=1 +kerning first=86 second=913 amount=-1 +kerning first=1027 second=1169 amount=-1 +kerning first=80 second=916 amount=-1 +kerning first=84 second=328 amount=-1 +kerning first=358 second=365 amount=-1 +kerning first=8220 second=940 amount=-1 +kerning first=258 second=8216 amount=-1 +kerning first=916 second=39 amount=-1 +kerning first=356 second=110 amount=-1 +kerning first=915 second=949 amount=-1 +kerning first=354 second=242 amount=-1 +kerning first=86 second=258 amount=-1 +kerning first=89 second=224 amount=-1 +kerning first=315 second=358 amount=-1 +kerning first=8220 second=244 amount=-1 +kerning first=246 second=358 amount=-1 +kerning first=76 second=366 amount=-1 +kerning first=8216 second=948 amount=-1 +kerning first=160 second=932 amount=-1 +kerning first=45 second=358 amount=-1 +kerning first=933 second=8212 amount=-1 +kerning first=910 second=173 amount=-1 +kerning first=8217 second=331 amount=-1 +kerning first=915 second=336 amount=-1 +kerning first=8222 second=356 amount=-1 +kerning first=1040 second=1058 amount=-1 +kerning first=971 second=39 amount=-1 +kerning first=358 second=941 amount=-1 +kerning first=221 second=332 amount=-1 +kerning first=84 second=228 amount=-1 +kerning first=8217 second=283 amount=-1 +kerning first=358 second=246 amount=-1 +kerning first=1043 second=1101 amount=-1 +kerning first=1066 second=1038 amount=-1 +kerning first=932 second=269 amount=-1 +kerning first=933 second=912 amount=1 +kerning first=1038 second=173 amount=-1 +kerning first=932 second=117 amount=-1 +kerning first=89 second=339 amount=-1 +kerning first=315 second=199 amount=-1 +kerning first=358 second=105 amount=-1 +kerning first=87 second=301 amount=1 +kerning first=111 second=932 amount=-1 +kerning first=376 second=81 amount=-1 +kerning first=944 second=34 amount=-1 +kerning first=915 second=338 amount=-1 +kerning first=70 second=256 amount=-1 +kerning first=315 second=288 amount=-1 +kerning first=76 second=45 amount=-1 +kerning first=8220 second=260 amount=-1 +kerning first=343 second=8230 amount=-1 +kerning first=356 second=328 amount=-1 +kerning first=932 second=197 amount=-1 +kerning first=358 second=916 amount=-1 +kerning first=84 second=248 amount=-1 +kerning first=8221 second=339 amount=-1 +kerning first=1058 second=1083 amount=-1 +kerning first=1168 second=1087 amount=-1 +kerning first=89 second=275 amount=-1 +kerning first=933 second=193 amount=-1 +kerning first=1113 second=1090 amount=-1 +kerning first=197 second=89 amount=-1 +kerning first=195 second=376 amount=-1 +kerning first=8216 second=269 amount=-1 +kerning first=221 second=267 amount=-1 +kerning first=8221 second=312 amount=-1 +kerning first=356 second=228 amount=-1 +kerning first=8217 second=349 amount=-1 +kerning first=228 second=932 amount=-1 +kerning first=933 second=58 amount=-1 +kerning first=955 second=39 amount=-1 +kerning first=932 second=341 amount=-1 +kerning first=1027 second=1098 amount=-1 +kerning first=84 second=279 amount=-1 +kerning first=8221 second=275 amount=-1 +kerning first=194 second=39 amount=-1 +kerning first=932 second=187 amount=-1 +kerning first=8220 second=948 amount=-1 +kerning first=65 second=8220 amount=-1 +kerning first=358 second=8250 amount=-1 +kerning first=193 second=221 amount=-1 +kerning first=376 second=115 amount=-1 +kerning first=915 second=195 amount=-2 +kerning first=315 second=362 amount=-1 +kerning first=76 second=79 amount=-1 +kerning first=8216 second=197 amount=-1 +kerning first=1046 second=1033 amount=1 +kerning first=345 second=46 amount=-1 +kerning first=221 second=199 amount=-1 +kerning first=932 second=963 amount=-1 +kerning first=8217 second=236 amount=-1 +kerning first=915 second=290 amount=-1 +kerning first=313 second=262 amount=-1 +kerning first=193 second=84 amount=-1 +kerning first=939 second=951 amount=-1 +kerning first=932 second=235 amount=-1 +kerning first=121 second=46 amount=-1 +kerning first=197 second=34 amount=-1 +kerning first=358 second=949 amount=-1 +kerning first=221 second=288 amount=-1 +kerning first=356 second=248 amount=-1 +kerning first=321 second=372 amount=-1 +kerning first=1058 second=1119 amount=-1 +kerning first=319 second=356 amount=-1 +kerning first=324 second=354 amount=-1 +kerning first=1043 second=1080 amount=-1 +kerning first=376 second=196 amount=-1 +kerning first=8217 second=101 amount=-1 +kerning first=242 second=356 amount=-1 +kerning first=354 second=380 amount=-1 +kerning first=187 second=932 amount=-1 +kerning first=112 second=354 amount=-1 +kerning first=76 second=8212 amount=-1 +kerning first=929 second=260 amount=-1 +kerning first=936 second=46 amount=-1 +kerning first=1034 second=1035 amount=-1 +kerning first=358 second=84 amount=1 +kerning first=915 second=8230 amount=-2 +kerning first=195 second=358 amount=-1 +kerning first=308 second=93 amount=1 +kerning first=86 second=196 amount=-1 +kerning first=356 second=279 amount=-1 +kerning first=358 second=378 amount=-1 +kerning first=80 second=195 amount=-1 +kerning first=376 second=333 amount=-1 +kerning first=317 second=8220 amount=-2 +kerning first=354 second=358 amount=1 +kerning first=89 second=243 amount=-1 +kerning first=8217 second=46 amount=-2 +kerning first=8216 second=963 amount=-1 +kerning first=1168 second=1066 amount=1 +kerning first=44 second=8220 amount=-1 +kerning first=313 second=376 amount=-1 +kerning first=319 second=8217 amount=-1 +kerning first=354 second=267 amount=-1 +kerning first=932 second=41 amount=1 +kerning first=8216 second=235 amount=-1 +kerning first=8220 second=269 amount=-1 +kerning first=46 second=8217 amount=-2 +kerning first=354 second=119 amount=-1 +kerning first=89 second=103 amount=-1 +kerning first=8212 second=356 amount=-1 +kerning first=224 second=354 amount=-1 +kerning first=84 second=969 amount=-1 +kerning first=1059 second=1058 amount=1 +kerning first=313 second=332 amount=-1 +kerning first=1091 second=46 amount=-1 +kerning first=102 second=93 amount=1 +kerning first=84 second=241 amount=-1 +kerning first=8217 second=297 amount=-1 +kerning first=313 second=85 amount=-1 +kerning first=8221 second=243 amount=-1 +kerning first=317 second=219 amount=-1 +kerning first=8216 second=8216 amount=-1 +kerning first=1098 second=8217 amount=-1 +kerning first=376 second=233 amount=-1 +kerning first=1027 second=1077 amount=-1 +kerning first=321 second=171 amount=-1 +kerning first=8230 second=8221 amount=-2 +kerning first=358 second=265 amount=-1 +kerning first=80 second=8230 amount=-2 +kerning first=8221 second=103 amount=-1 +kerning first=317 second=81 amount=-1 +kerning first=70 second=192 amount=-1 +kerning first=315 second=210 amount=-1 +kerning first=358 second=118 amount=-1 +kerning first=8220 second=197 amount=-1 +kerning first=45 second=910 amount=-1 +kerning first=91 second=354 amount=1 +kerning first=923 second=86 amount=-1 +kerning first=89 second=256 amount=-1 +kerning first=321 second=220 amount=-1 +kerning first=1168 second=173 amount=-1 +kerning first=84 second=913 amount=-1 +kerning first=1035 second=1066 amount=-1 +kerning first=931 second=79 amount=-1 +kerning first=8204 second=87 amount=-1 +kerning first=936 second=198 amount=-1 +kerning first=1058 second=1096 amount=-1 +kerning first=358 second=195 amount=-1 +kerning first=1043 second=1059 amount=1 +kerning first=271 second=311 amount=1 +kerning first=912 second=950 amount=1 +kerning first=1168 second=1100 amount=-1 +kerning first=84 second=258 amount=-1 +kerning first=313 second=358 amount=-1 +kerning first=8221 second=256 amount=-1 +kerning first=354 second=343 amount=-1 +kerning first=243 second=358 amount=-1 +kerning first=913 second=221 amount=-1 +kerning first=939 second=65 amount=-1 +kerning first=89 second=171 amount=-1 +kerning first=1059 second=1092 amount=-1 +kerning first=356 second=969 amount=-1 +kerning first=84 second=307 amount=-1 +kerning first=356 second=241 amount=-1 +kerning first=1038 second=1058 amount=1 +kerning first=913 second=84 amount=-1 +kerning first=932 second=367 amount=-1 +kerning first=8217 second=198 amount=-1 +kerning first=260 second=39 amount=-1 +kerning first=354 second=965 amount=-1 +kerning first=358 second=345 amount=-1 +kerning first=8220 second=963 amount=-1 +kerning first=104 second=358 amount=-1 +kerning first=256 second=221 amount=-1 +kerning first=376 second=291 amount=-1 +kerning first=354 second=237 amount=-1 +kerning first=358 second=8230 amount=-1 +kerning first=910 second=962 amount=-1 +kerning first=8220 second=235 amount=-1 +kerning first=315 second=173 amount=-1 +kerning first=915 second=214 amount=-1 +kerning first=313 second=199 amount=-1 +kerning first=109 second=932 amount=-1 +kerning first=974 second=34 amount=-1 +kerning first=221 second=210 amount=-1 +kerning first=123 second=106 amount=1 +kerning first=932 second=972 amount=-1 +kerning first=256 second=84 amount=-1 +kerning first=123 second=1095 amount=-1 +kerning first=8220 second=8216 amount=-1 +kerning first=313 second=288 amount=-1 +kerning first=356 second=913 amount=-1 +kerning first=932 second=250 amount=-1 +kerning first=939 second=966 amount=-1 +kerning first=936 second=194 amount=-1 +kerning first=341 second=8230 amount=-1 +kerning first=8222 second=86 amount=-1 +kerning first=358 second=232 amount=-1 +kerning first=923 second=932 amount=-1 +kerning first=929 second=197 amount=-1 +kerning first=1043 second=1093 amount=-1 +kerning first=329 second=356 amount=-1 +kerning first=8217 second=114 amount=-1 +kerning first=933 second=941 amount=-1 +kerning first=65 second=356 amount=-1 +kerning first=356 second=258 amount=-1 +kerning first=932 second=109 amount=-1 +kerning first=926 second=970 amount=1 +kerning first=358 second=97 amount=-1 +kerning first=197 second=8220 amount=-1 +kerning first=356 second=307 amount=-1 +kerning first=1038 second=1092 amount=-1 +kerning first=321 second=927 amount=-1 +kerning first=196 second=89 amount=-1 +kerning first=8250 second=221 amount=-1 +kerning first=192 second=376 amount=-1 +kerning first=8217 second=194 amount=-1 +kerning first=8211 second=1026 amount=-1 +kerning first=225 second=932 amount=-1 +kerning first=910 second=256 amount=-1 +kerning first=376 second=363 amount=-1 +kerning first=261 second=358 amount=-1 +kerning first=915 second=973 amount=-1 +kerning first=321 second=286 amount=-1 +kerning first=1058 second=1075 amount=-1 +kerning first=8250 second=84 amount=-1 +kerning first=319 second=268 amount=-1 +kerning first=1043 second=1038 amount=1 +kerning first=173 second=354 amount=-1 +kerning first=933 second=916 amount=-1 +kerning first=8216 second=972 amount=-1 +kerning first=1168 second=1079 amount=-1 +kerning first=354 second=301 amount=-1 +kerning first=89 second=263 amount=-1 +kerning first=34 second=193 amount=-1 +kerning first=221 second=252 amount=-1 +kerning first=65 second=8217 amount=-1 +kerning first=939 second=44 amount=-1 +kerning first=221 second=173 amount=-1 +kerning first=313 second=362 amount=-1 +kerning first=84 second=382 amount=-1 +kerning first=8217 second=337 amount=-1 +kerning first=1043 second=8249 amount=-1 +kerning first=1090 second=8230 amount=-1 +kerning first=119 second=46 amount=-1 +kerning first=196 second=34 amount=-1 +kerning first=221 second=111 amount=-1 +kerning first=932 second=324 amount=-1 +kerning first=376 second=245 amount=-1 +kerning first=1027 second=1090 amount=-1 +kerning first=321 second=8221 amount=-1 +kerning first=8221 second=263 amount=-1 +kerning first=317 second=356 amount=-1 +kerning first=89 second=927 amount=-1 +kerning first=123 second=376 amount=1 +kerning first=244 second=356 amount=-1 +kerning first=84 second=115 amount=-1 +kerning first=89 second=192 amount=-1 +kerning first=8222 second=932 amount=-1 +kerning first=110 second=354 amount=-1 +kerning first=934 second=46 amount=-1 +kerning first=89 second=286 amount=-1 +kerning first=76 second=71 amount=-1 +kerning first=192 second=358 amount=-1 +kerning first=902 second=376 amount=-1 +kerning first=8217 second=231 amount=-1 +kerning first=70 second=74 amount=-1 +kerning first=932 second=226 amount=-1 +kerning first=84 second=196 amount=-1 +kerning first=8221 second=192 amount=-1 +kerning first=321 second=354 amount=-1 +kerning first=1027 second=46 amount=-1 +kerning first=333 second=84 amount=-1 +kerning first=1043 second=1072 amount=-1 +kerning first=933 second=949 amount=-1 +kerning first=1168 second=1114 amount=-1 +kerning first=319 second=86 amount=-1 +kerning first=271 second=8221 amount=1 +kerning first=331 second=358 amount=-1 +kerning first=1034 second=8217 amount=-1 +kerning first=1113 second=1118 amount=-1 +kerning first=376 second=268 amount=-1 +kerning first=317 second=8217 amount=-1 +kerning first=1059 second=1106 amount=1 +kerning first=40 second=89 amount=1 +kerning first=44 second=8217 amount=-2 +kerning first=226 second=354 amount=-1 +kerning first=356 second=382 amount=-1 +kerning first=84 second=333 amount=-1 +kerning first=354 second=971 amount=-1 +kerning first=358 second=361 amount=-1 +kerning first=8220 second=972 amount=-1 +kerning first=123 second=358 amount=1 +kerning first=8221 second=8221 amount=-1 +kerning first=356 second=115 amount=-1 +kerning first=915 second=954 amount=-1 +kerning first=8218 second=372 amount=-1 +kerning first=354 second=252 amount=-1 +kerning first=89 second=234 amount=-1 +kerning first=354 second=173 amount=-1 +kerning first=1168 second=1058 amount=1 +kerning first=313 second=210 amount=-1 +kerning first=221 second=224 amount=-1 +kerning first=902 second=358 amount=-1 +kerning first=354 second=111 amount=-1 +kerning first=87 second=256 amount=-1 +kerning first=84 second=959 amount=-1 +kerning first=932 second=331 amount=-1 +kerning first=358 second=973 amount=-1 +kerning first=84 second=233 amount=-1 +kerning first=8217 second=285 amount=-1 +kerning first=8221 second=234 amount=-1 +kerning first=356 second=196 amount=-1 +kerning first=1033 second=1066 amount=-1 +kerning first=39 second=193 amount=-1 +kerning first=358 second=251 amount=-1 +kerning first=923 second=939 amount=-1 +kerning first=1043 second=1107 amount=-1 +kerning first=372 second=239 amount=1 +kerning first=932 second=283 amount=-1 +kerning first=84 second=356 amount=1 +kerning first=8221 second=354 amount=1 +kerning first=932 second=122 amount=-1 +kerning first=358 second=110 amount=-1 +kerning first=97 second=84 amount=-1 +kerning first=910 second=192 amount=-1 +kerning first=91 second=87 amount=1 +kerning first=1038 second=1106 amount=1 +kerning first=319 second=932 amount=-1 +kerning first=221 second=339 amount=-1 +kerning first=932 second=934 amount=-1 +kerning first=242 second=932 amount=-1 +kerning first=321 second=211 amount=-1 +kerning first=1035 second=1058 amount=-1 +kerning first=356 second=333 amount=-1 +kerning first=931 second=71 amount=-1 +kerning first=939 second=923 amount=-1 +kerning first=258 second=39 amount=-1 +kerning first=8217 second=308 amount=-1 +kerning first=1058 second=1088 amount=-1 +kerning first=376 second=230 amount=-1 +kerning first=1168 second=1092 amount=-1 +kerning first=89 second=289 amount=-1 +kerning first=933 second=195 amount=-1 +kerning first=313 second=173 amount=-1 +kerning first=197 second=356 amount=-1 +kerning first=356 second=959 amount=-1 +kerning first=973 second=34 amount=-1 +kerning first=8216 second=283 amount=-1 +kerning first=221 second=275 amount=-1 +kerning first=916 second=358 amount=-1 +kerning first=356 second=233 amount=-1 +kerning first=1043 second=187 amount=-1 +kerning first=932 second=349 amount=-1 +kerning first=1114 second=1091 amount=-1 +kerning first=1027 second=1103 amount=-1 +kerning first=84 second=291 amount=-1 +kerning first=356 second=356 amount=1 +kerning first=8221 second=289 amount=-1 +kerning first=118 second=8230 amount=-1 +kerning first=358 second=328 amount=-1 +kerning first=76 second=221 amount=-1 +kerning first=8211 second=376 amount=-1 +kerning first=295 second=356 amount=-1 +kerning first=1058 second=44 amount=-1 +kerning first=376 second=271 amount=-1 +kerning first=354 second=224 amount=-1 +kerning first=89 second=211 amount=-1 +kerning first=8212 second=932 amount=-1 +kerning first=1058 second=1032 amount=-1 +kerning first=70 second=225 amount=-1 +kerning first=910 second=961 amount=-1 +kerning first=76 second=336 amount=-1 +kerning first=76 second=84 amount=-1 +kerning first=196 second=8220 amount=-1 +kerning first=315 second=372 amount=-1 +kerning first=933 second=8230 amount=-1 +kerning first=932 second=968 amount=-1 +kerning first=8217 second=242 amount=-1 +kerning first=89 second=74 amount=-1 +kerning first=193 second=89 amount=-1 +kerning first=932 second=236 amount=-1 +kerning first=194 second=376 amount=-1 +kerning first=197 second=8217 amount=-1 +kerning first=1169 second=44 amount=-1 +kerning first=1027 second=59 amount=-1 +kerning first=358 second=228 amount=-1 +kerning first=319 second=370 amount=-1 +kerning first=1043 second=1085 amount=-1 +kerning first=1168 second=171 amount=-1 +kerning first=34 second=941 amount=-1 +kerning first=259 second=358 amount=-1 +kerning first=317 second=268 amount=-1 +kerning first=932 second=101 amount=-1 +kerning first=89 second=371 amount=-1 +kerning first=76 second=338 amount=-1 +kerning first=65 second=86 amount=-1 +kerning first=8221 second=74 amount=-1 +kerning first=354 second=339 amount=-1 +kerning first=376 second=65 amount=-1 +kerning first=245 second=354 amount=-1 +kerning first=8230 second=933 amount=-1 +kerning first=84 second=363 amount=-1 +kerning first=356 second=291 amount=-1 +kerning first=193 second=34 amount=-1 +kerning first=8211 second=358 amount=-1 +kerning first=376 second=347 amount=-1 +kerning first=354 second=312 amount=-1 +kerning first=321 second=264 amount=-1 +kerning first=89 second=353 amount=-1 +kerning first=358 second=248 amount=-1 +kerning first=241 second=356 amount=-1 +kerning first=34 second=916 amount=-1 +kerning first=86 second=65 amount=-1 +kerning first=87 second=192 amount=-1 +kerning first=271 second=108 amount=1 +kerning first=354 second=275 amount=-1 +kerning first=932 second=46 amount=-1 +kerning first=8220 second=283 amount=-1 +kerning first=221 second=243 amount=-1 +kerning first=195 second=936 amount=-1 +kerning first=315 second=171 amount=-1 +kerning first=194 second=358 amount=-1 +kerning first=84 second=245 amount=-1 +kerning first=8221 second=353 amount=-1 +kerning first=8216 second=101 amount=-1 +kerning first=1043 second=1169 amount=-1 +kerning first=221 second=103 amount=-1 +kerning first=932 second=297 amount=-1 +kerning first=1027 second=1082 amount=-1 +kerning first=321 second=8211 amount=-1 +kerning first=335 second=84 amount=-1 +kerning first=358 second=279 amount=-1 +kerning first=915 second=913 amount=-2 +kerning first=317 second=86 amount=-1 +kerning first=40 second=309 amount=1 +kerning first=315 second=220 amount=-1 +kerning first=376 second=99 amount=-1 +kerning first=76 second=290 amount=-1 +kerning first=89 second=264 amount=-1 +kerning first=931 second=336 amount=-1 +kerning first=932 second=945 amount=-1 +kerning first=329 second=932 amount=-1 +kerning first=915 second=258 amount=-2 +kerning first=1168 second=1241 amount=-1 +kerning first=319 second=213 amount=-1 +kerning first=65 second=932 amount=-1 +kerning first=356 second=363 amount=-1 +kerning first=46 second=939 amount=-1 +kerning first=221 second=256 amount=-1 +kerning first=1058 second=1101 amount=-1 +kerning first=8216 second=46 amount=-2 +kerning first=372 second=193 amount=-1 +kerning first=1027 second=1026 amount=1 +kerning first=34 second=949 amount=-1 +kerning first=321 second=87 amount=-1 +kerning first=912 second=955 amount=1 +kerning first=89 second=8211 amount=-1 +kerning first=931 second=338 amount=-1 +kerning first=376 second=44 amount=-1 +kerning first=39 second=941 amount=-1 +kerning first=356 second=245 amount=-1 +kerning first=913 second=89 amount=-1 +kerning first=221 second=171 amount=-1 +kerning first=195 second=372 amount=-1 +kerning first=173 second=933 amount=-1 +kerning first=80 second=913 amount=-1 +kerning first=1027 second=1118 amount=-1 +kerning first=257 second=356 amount=-1 +kerning first=932 second=198 amount=-1 +kerning first=354 second=962 amount=-1 +kerning first=915 second=946 amount=-1 +kerning first=8218 second=354 amount=-1 +kerning first=354 second=243 amount=-1 +kerning first=89 second=225 amount=-1 +kerning first=8212 second=939 amount=-1 +kerning first=910 second=970 amount=1 +kerning first=76 second=368 amount=-1 +kerning first=8216 second=945 amount=-1 +kerning first=80 second=258 amount=-1 +kerning first=86 second=44 amount=-1 +kerning first=354 second=372 amount=1 +kerning first=932 second=944 amount=-1 +kerning first=256 second=89 amount=-1 +kerning first=8217 second=358 amount=1 +kerning first=260 second=376 amount=-1 +kerning first=354 second=103 amount=-1 +kerning first=8220 second=101 amount=-1 +kerning first=939 second=940 amount=-1 +kerning first=317 second=932 amount=-1 +kerning first=932 second=255 amount=-1 +kerning first=39 second=916 amount=-1 +kerning first=915 second=81 amount=-1 +kerning first=358 second=969 amount=-1 +kerning first=244 second=932 amount=-1 +kerning first=8217 second=267 amount=-1 +kerning first=1033 second=1058 amount=-1 +kerning first=358 second=241 amount=-1 +kerning first=913 second=34 amount=-1 +kerning first=1043 second=1098 amount=-1 +kerning first=932 second=261 amount=-1 +kerning first=376 second=213 amount=-1 +kerning first=293 second=358 amount=-1 +kerning first=922 second=74 amount=1 +kerning first=357 second=8221 amount=1 +kerning first=932 second=114 amount=-1 +kerning first=315 second=927 amount=-1 +kerning first=926 second=912 amount=1 +kerning first=8204 second=902 amount=-1 +kerning first=84 second=86 amount=1 +kerning first=1059 second=8211 amount=-1 +kerning first=196 second=356 amount=-1 +kerning first=354 second=256 amount=-1 +kerning first=373 second=46 amount=-1 +kerning first=315 second=286 amount=-1 +kerning first=8216 second=198 amount=-1 +kerning first=931 second=290 amount=-1 +kerning first=256 second=34 amount=-1 +kerning first=8220 second=46 amount=-2 +kerning first=932 second=194 amount=-1 +kerning first=358 second=913 amount=-1 +kerning first=1068 second=1026 amount=-1 +kerning first=84 second=230 amount=-1 +kerning first=8221 second=305 amount=-1 +kerning first=1058 second=1080 amount=-1 +kerning first=89 second=273 amount=-1 +kerning first=8250 second=89 amount=-1 +kerning first=1056 second=44 amount=-2 +kerning first=1168 second=1084 amount=-1 +kerning first=1056 second=1032 amount=-1 +kerning first=939 second=260 amount=-1 +kerning first=922 second=970 amount=1 +kerning first=89 second=277 amount=-1 +kerning first=358 second=258 amount=-1 +kerning first=34 second=195 amount=-1 +kerning first=8221 second=8204 amount=-1 +kerning first=260 second=358 amount=-1 +kerning first=354 second=171 amount=-1 +kerning first=315 second=8221 amount=-1 +kerning first=1059 second=1076 amount=-1 +kerning first=313 second=372 amount=-1 +kerning first=193 second=8220 amount=-1 +kerning first=197 second=86 amount=-1 +kerning first=39 second=949 amount=-1 +kerning first=221 second=263 amount=-1 +kerning first=910 second=8211 amount=-1 +kerning first=8217 second=343 amount=-1 +kerning first=8221 second=273 amount=-1 +kerning first=358 second=307 amount=-1 +kerning first=196 second=8217 amount=-1 +kerning first=160 second=8216 amount=-1 +kerning first=932 second=337 amount=-1 +kerning first=376 second=249 amount=-1 +kerning first=1027 second=1095 amount=-1 +kerning first=8211 second=910 amount=-1 +kerning first=84 second=271 amount=-1 +kerning first=8221 second=277 amount=-1 +kerning first=317 second=370 amount=-1 +kerning first=76 second=214 amount=-1 +kerning first=8220 second=945 amount=-1 +kerning first=376 second=259 amount=-1 +kerning first=255 second=46 amount=-1 +kerning first=356 second=86 amount=1 +kerning first=915 second=196 amount=-2 +kerning first=1038 second=8211 amount=-1 +kerning first=221 second=927 amount=-1 +kerning first=315 second=354 amount=-1 +kerning first=8216 second=194 amount=-1 +kerning first=34 second=8230 amount=-2 +kerning first=221 second=192 amount=-1 +kerning first=8217 second=237 amount=-1 +kerning first=246 second=354 amount=-1 +kerning first=1107 second=46 amount=-1 +kerning first=84 second=932 amount=1 +kerning first=45 second=354 amount=-1 +kerning first=65 second=939 amount=-1 +kerning first=939 second=948 amount=-1 +kerning first=932 second=231 amount=-1 +kerning first=221 second=286 amount=-1 +kerning first=376 second=923 amount=-1 +kerning first=356 second=230 amount=-1 +kerning first=321 second=366 amount=-1 +kerning first=1114 second=8217 amount=-1 +kerning first=1043 second=1077 amount=-1 +kerning first=933 second=954 amount=-1 +kerning first=1027 second=1040 amount=-1 +kerning first=932 second=93 amount=1 +kerning first=89 second=351 amount=-1 +kerning first=84 second=65 amount=-1 +kerning first=40 second=356 amount=1 +kerning first=929 second=46 amount=-2 +kerning first=8220 second=198 amount=-1 +kerning first=8216 second=337 amount=-1 +kerning first=192 second=936 amount=-1 +kerning first=313 second=171 amount=-1 +kerning first=1038 second=1076 amount=-1 +kerning first=86 second=923 amount=-1 +kerning first=84 second=347 amount=-1 +kerning first=8221 second=351 amount=-1 +kerning first=356 second=271 amount=-1 +kerning first=80 second=196 amount=-1 +kerning first=197 second=932 amount=-1 +kerning first=915 second=959 amount=-1 +kerning first=89 second=239 amount=1 +kerning first=1058 second=1059 amount=1 +kerning first=321 second=45 amount=-1 +kerning first=313 second=220 amount=-1 +kerning first=354 second=263 amount=-1 +kerning first=70 second=257 amount=-1 +kerning first=8216 second=231 amount=-1 +kerning first=221 second=234 amount=-1 +kerning first=89 second=100 amount=-1 +kerning first=84 second=966 amount=-1 +kerning first=356 second=932 amount=1 +kerning first=295 second=932 amount=-1 +kerning first=84 second=238 amount=-1 +kerning first=8217 second=301 amount=-1 +kerning first=8221 second=239 amount=-1 +kerning first=317 second=213 amount=-1 +kerning first=39 second=195 amount=-1 +kerning first=358 second=382 amount=-1 +kerning first=44 second=939 amount=-1 +kerning first=932 second=285 amount=-1 +kerning first=376 second=229 amount=-1 +kerning first=1027 second=1074 amount=-1 +kerning first=84 second=99 amount=-1 +kerning first=8221 second=100 amount=-1 +kerning first=356 second=65 amount=-1 +kerning first=354 second=192 amount=-1 +kerning first=315 second=211 amount=-1 +kerning first=70 second=193 amount=-1 +kerning first=358 second=115 amount=-1 +kerning first=8220 second=194 amount=-1 +kerning first=931 second=214 amount=-1 +kerning first=8204 second=221 amount=-1 +kerning first=915 second=181 amount=-1 +kerning first=902 second=936 amount=-1 +kerning first=913 second=8220 amount=-1 +kerning first=227 second=84 amount=-1 +kerning first=89 second=45 amount=-1 +kerning first=1035 second=1063 amount=-1 +kerning first=356 second=347 amount=-1 +kerning first=8204 second=84 amount=-1 +kerning first=195 second=8221 amount=-1 +kerning first=192 second=372 amount=-1 +kerning first=939 second=197 amount=-1 +kerning first=1058 second=1093 amount=-1 +kerning first=39 second=8230 amount=-2 +kerning first=929 second=198 amount=-1 +kerning first=358 second=196 amount=-1 +kerning first=1075 second=44 amount=-1 +kerning first=932 second=308 amount=-1 +kerning first=8216 second=1026 amount=1 +kerning first=321 second=79 amount=-1 +kerning first=1168 second=1097 amount=-1 +kerning first=8220 second=337 amount=-1 +kerning first=84 second=44 amount=-1 +kerning first=256 second=8220 amount=-1 +kerning first=1059 second=1089 amount=-1 +kerning first=356 second=966 amount=-1 +kerning first=8216 second=285 amount=-1 +kerning first=258 second=376 amount=-1 +kerning first=221 second=289 amount=-1 +kerning first=356 second=238 amount=-1 +kerning first=932 second=369 amount=-1 +kerning first=241 second=932 amount=-1 +kerning first=1027 second=1109 amount=-1 +kerning first=195 second=354 amount=-1 +kerning first=321 second=8212 amount=-1 +kerning first=84 second=299 amount=-1 +kerning first=8221 second=303 amount=-1 +kerning first=354 second=961 amount=-1 +kerning first=358 second=333 amount=-1 +kerning first=376 second=281 amount=-1 +kerning first=356 second=99 amount=-1 +kerning first=354 second=234 amount=-1 +kerning first=1058 second=1038 amount=1 +kerning first=70 second=227 amount=-1 +kerning first=313 second=927 amount=-1 +kerning first=8220 second=231 amount=-1 +kerning first=98 second=358 amount=-1 +kerning first=376 second=125 amount=1 +kerning first=8218 second=87 amount=-1 +kerning first=123 second=372 amount=1 +kerning first=253 second=8230 amount=-1 +kerning first=354 second=354 amount=1 +kerning first=76 second=89 amount=-1 +kerning first=193 second=356 amount=-1 +kerning first=221 second=211 amount=-1 +kerning first=1059 second=45 amount=-1 +kerning first=916 second=936 amount=-1 +kerning first=89 second=79 amount=-1 +kerning first=313 second=286 amount=-1 +kerning first=939 second=963 amount=-1 +kerning first=932 second=242 amount=-1 +kerning first=358 second=959 amount=-1 +kerning first=8216 second=308 amount=-1 +kerning first=1058 second=8249 amount=-1 +kerning first=902 second=372 amount=-1 +kerning first=358 second=233 amount=-1 +kerning first=929 second=194 amount=-1 +kerning first=221 second=74 amount=-1 +kerning first=1043 second=1090 amount=-1 +kerning first=1168 second=8211 amount=-1 +kerning first=8217 second=111 amount=-1 +kerning first=1066 second=1026 amount=-1 +kerning first=86 second=125 amount=1 +kerning first=114 second=8230 amount=-1 +kerning first=358 second=356 amount=1 +kerning first=356 second=44 amount=-1 +kerning first=89 second=8212 amount=-1 +kerning first=947 second=46 amount=-1 +kerning first=1033 second=8221 amount=-1 +kerning first=258 second=358 amount=-1 +kerning first=221 second=371 amount=-1 +kerning first=313 second=8221 amount=-1 +kerning first=1038 second=1089 amount=-1 +kerning first=315 second=264 amount=-1 +kerning first=76 second=34 amount=-1 +kerning first=196 second=86 amount=-1 +kerning first=84 second=373 amount=-1 +kerning first=356 second=299 amount=-1 +kerning first=193 second=8217 amount=-1 +kerning first=8220 second=1026 amount=1 +kerning first=197 second=939 amount=-1 +kerning first=915 second=943 amount=-1 +kerning first=910 second=45 amount=-1 +kerning first=1043 second=46 amount=-1 +kerning first=1058 second=1072 amount=-1 +kerning first=933 second=913 amount=-1 +kerning first=1168 second=1076 amount=-1 +kerning first=354 second=289 amount=-1 +kerning first=89 second=257 amount=-1 +kerning first=8216 second=242 amount=-1 +kerning first=8220 second=285 amount=-1 +kerning first=221 second=353 amount=-1 +kerning first=89 second=113 amount=-1 +kerning first=315 second=8211 amount=-1 +kerning first=257 second=932 amount=-1 +kerning first=84 second=974 amount=-1 +kerning first=313 second=354 amount=-1 +kerning first=933 second=258 amount=-1 +kerning first=243 second=354 amount=-1 +kerning first=1038 second=45 amount=-1 +kerning first=84 second=249 amount=-1 +kerning first=75 second=308 amount=1 +kerning first=376 second=244 amount=-1 +kerning first=1027 second=1087 amount=-1 +kerning first=84 second=259 amount=-1 +kerning first=319 second=8249 amount=-1 +kerning first=358 second=291 amount=-1 +kerning first=1059 second=8212 amount=-1 +kerning first=84 second=112 amount=-1 +kerning first=8221 second=113 amount=-1 +kerning first=89 second=193 amount=-1 +kerning first=923 second=8216 amount=-1 +kerning first=104 second=354 amount=-1 +kerning first=1061 second=1060 amount=-1 +kerning first=8220 second=308 amount=-1 +kerning first=1026 second=1035 amount=-1 +kerning first=194 second=936 amount=-1 +kerning first=915 second=268 amount=-1 +kerning first=354 second=74 amount=-1 +kerning first=315 second=87 amount=-1 +kerning first=84 second=923 amount=-1 +kerning first=319 second=217 amount=-1 +kerning first=356 second=373 amount=-1 +kerning first=221 second=264 amount=-1 +kerning first=8221 second=193 amount=-1 +kerning first=1058 second=1107 amount=-1 +kerning first=319 second=334 amount=-1 +kerning first=372 second=195 amount=-1 +kerning first=196 second=932 amount=-1 +kerning first=933 second=946 amount=-1 +kerning first=8216 second=1040 amount=-1 +kerning first=1168 second=1111 amount=-1 +kerning first=87 second=239 amount=1 +kerning first=324 second=84 amount=-1 +kerning first=354 second=371 amount=-1 +kerning first=89 second=335 amount=-1 +kerning first=376 second=260 amount=-1 +kerning first=112 second=84 amount=-1 +kerning first=356 second=974 amount=-1 +kerning first=40 second=86 amount=1 +kerning first=913 second=356 amount=-1 +kerning first=910 second=8212 amount=-1 +kerning first=356 second=249 amount=-1 +kerning first=221 second=8211 amount=-1 +kerning first=932 second=380 amount=-1 +kerning first=8217 second=339 amount=-1 +kerning first=84 second=326 amount=-1 +kerning first=319 second=216 amount=-1 +kerning first=356 second=259 amount=-1 +kerning first=8221 second=335 amount=-1 +kerning first=358 second=363 amount=-1 +kerning first=337 second=358 amount=-1 +kerning first=356 second=112 amount=-1 +kerning first=915 second=951 amount=-1 +kerning first=354 second=353 amount=-1 +kerning first=86 second=260 amount=-1 +kerning first=89 second=227 amount=-1 +kerning first=910 second=912 amount=1 +kerning first=8220 second=242 amount=-1 +kerning first=372 second=8230 amount=-1 +kerning first=376 second=8249 amount=-1 +kerning first=1038 second=8212 amount=-1 +kerning first=256 second=356 amount=-1 +kerning first=313 second=211 amount=-1 +kerning first=261 second=354 amount=-1 +kerning first=221 second=225 amount=-1 +kerning first=1059 second=58 amount=-1 +kerning first=8217 second=312 amount=-1 +kerning first=356 second=923 amount=-1 +kerning first=939 second=972 amount=-1 +kerning first=932 second=358 amount=1 +kerning first=1058 second=187 amount=-1 +kerning first=224 second=84 amount=-1 +kerning first=84 second=229 amount=-1 +kerning first=8217 second=275 amount=-1 +kerning first=1033 second=1063 amount=-1 +kerning first=358 second=245 amount=-1 +kerning first=248 second=358 amount=-1 +kerning first=913 second=8217 amount=-1 +kerning first=192 second=8221 amount=-1 +kerning first=932 second=267 amount=-1 +kerning first=194 second=372 amount=-1 +kerning first=1027 second=1066 amount=1 +kerning first=1043 second=1103 amount=-1 +kerning first=91 second=221 amount=1 +kerning first=932 second=119 amount=-1 +kerning first=929 second=308 amount=-1 +kerning first=376 second=334 amount=-1 +kerning first=1034 second=1059 amount=-1 +kerning first=45 second=933 amount=-1 +kerning first=910 second=193 amount=-1 +kerning first=91 second=84 amount=1 +kerning first=256 second=8217 amount=-1 +kerning first=356 second=326 amount=-1 +kerning first=8250 second=356 amount=-1 +kerning first=8220 second=1040 amount=-1 +kerning first=192 second=354 amount=-1 +kerning first=910 second=58 amount=-1 +kerning first=1043 second=59 amount=-1 +kerning first=968 second=39 amount=-1 +kerning first=40 second=932 amount=1 +kerning first=1058 second=1085 amount=-1 +kerning first=319 second=284 amount=-1 +kerning first=376 second=216 amount=-1 +kerning first=321 second=71 amount=-1 +kerning first=1168 second=1089 amount=-1 +kerning first=1036 second=1051 amount=1 +kerning first=922 second=912 amount=1 +kerning first=89 second=287 amount=-1 +kerning first=76 second=8220 amount=-2 +kerning first=8216 second=358 amount=1 +kerning first=933 second=196 amount=-1 +kerning first=221 second=273 amount=-1 +kerning first=1027 second=173 amount=-1 +kerning first=354 second=8211 amount=-1 +kerning first=331 second=354 amount=-1 +kerning first=8216 second=267 amount=-1 +kerning first=1038 second=58 amount=-1 +kerning first=221 second=277 amount=-1 +kerning first=356 second=229 amount=-1 +kerning first=1100 second=1098 amount=-1 +kerning first=902 second=8221 amount=-1 +kerning first=932 second=343 amount=-1 +kerning first=1027 second=1100 amount=-1 +kerning first=84 second=281 amount=-1 +kerning first=8221 second=287 amount=-1 +kerning first=195 second=87 amount=-1 +kerning first=76 second=219 amount=-1 +kerning first=84 second=125 amount=1 +kerning first=376 second=269 amount=-1 +kerning first=354 second=225 amount=-1 +kerning first=1168 second=45 amount=-1 +kerning first=376 second=117 amount=-1 +kerning first=123 second=354 amount=1 +kerning first=260 second=936 amount=-1 +kerning first=315 second=366 amount=-1 +kerning first=76 second=81 amount=-1 +kerning first=932 second=965 amount=-1 +kerning first=8217 second=243 amount=-1 +kerning first=354 second=87 amount=1 +kerning first=89 second=71 amount=-1 +kerning first=313 second=264 amount=-1 +kerning first=193 second=86 amount=-1 +kerning first=932 second=237 amount=-1 +kerning first=915 second=65 amount=-2 +kerning first=1068 second=1066 amount=-1 +kerning first=333 second=356 amount=-1 +kerning first=902 second=354 amount=-1 +kerning first=1058 second=1169 amount=-1 +kerning first=319 second=364 amount=-1 +kerning first=1043 second=1082 amount=-1 +kerning first=343 second=44 amount=-1 +kerning first=376 second=197 amount=-1 +kerning first=8217 second=103 amount=-1 +kerning first=196 second=939 amount=-1 +kerning first=936 second=256 amount=-1 +kerning first=933 second=959 amount=-1 +kerning first=8249 second=910 amount=-1 +kerning first=34 second=969 amount=-1 +kerning first=319 second=8216 amount=-2 +kerning first=89 second=365 amount=-1 +kerning first=958 second=125 amount=1 +kerning first=376 second=284 amount=-1 +kerning first=46 second=8216 amount=-1 +kerning first=354 second=305 amount=-1 +kerning first=1034 second=1038 amount=-1 +kerning first=358 second=86 amount=1 +kerning first=102 second=8221 amount=1 +kerning first=221 second=351 amount=-1 +kerning first=313 second=8211 amount=-1 +kerning first=86 second=197 amount=-1 +kerning first=315 second=45 amount=-1 +kerning first=356 second=281 amount=-1 +kerning first=173 second=221 amount=-1 +kerning first=916 second=8221 amount=-1 +kerning first=8217 second=256 amount=-1 +kerning first=356 second=125 amount=1 +kerning first=915 second=966 amount=-1 +kerning first=317 second=8249 amount=-1 +kerning first=89 second=246 amount=-1 +kerning first=963 second=912 amount=1 +kerning first=358 second=230 amount=-1 +kerning first=354 second=273 amount=-1 +kerning first=8220 second=358 amount=1 +kerning first=1043 second=1026 amount=1 +kerning first=34 second=913 amount=-1 +kerning first=87 second=193 amount=-1 +kerning first=354 second=277 amount=-1 +kerning first=173 second=84 amount=-1 +kerning first=933 second=181 amount=-1 +kerning first=8220 second=267 amount=-1 +kerning first=80 second=65 amount=-1 +kerning first=221 second=239 amount=1 +kerning first=195 second=933 amount=-1 +kerning first=354 second=121 amount=-1 +kerning first=84 second=940 amount=-1 +kerning first=34 second=258 amount=-1 +kerning first=84 second=244 amount=-1 +kerning first=313 second=87 amount=-1 +kerning first=8221 second=246 amount=-1 +kerning first=260 second=372 amount=-1 +kerning first=317 second=217 amount=-1 +kerning first=1043 second=1118 amount=-1 +kerning first=221 second=100 amount=-1 +kerning first=932 second=301 amount=-1 +kerning first=376 second=235 amount=-1 +kerning first=1027 second=1079 amount=-1 +kerning first=1168 second=8212 amount=-1 +kerning first=916 second=354 amount=-1 +kerning first=317 second=334 amount=-1 +kerning first=358 second=271 amount=-1 +kerning first=97 second=356 amount=-1 +kerning first=193 second=932 amount=-1 +kerning first=8221 second=105 amount=-1 +kerning first=70 second=195 amount=-1 +kerning first=110 second=84 amount=-1 +kerning first=321 second=221 amount=-1 +kerning first=315 second=79 amount=-1 +kerning first=319 second=212 amount=-1 +kerning first=931 second=81 amount=-1 +kerning first=8204 second=89 amount=-1 +kerning first=358 second=932 amount=1 +kerning first=915 second=44 amount=-2 +kerning first=317 second=216 amount=-1 +kerning first=321 second=336 amount=-1 +kerning first=1058 second=1098 amount=-1 +kerning first=271 second=318 amount=1 +kerning first=326 second=358 amount=-1 +kerning first=221 second=45 amount=-1 +kerning first=321 second=84 amount=-1 +kerning first=1168 second=1102 amount=-1 +kerning first=84 second=260 amount=-1 +kerning first=354 second=351 amount=-1 +kerning first=259 second=354 amount=-1 +kerning first=315 second=8212 amount=-1 +kerning first=70 second=8230 amount=-1 +kerning first=358 second=65 amount=-1 +kerning first=356 second=940 amount=-1 +kerning first=376 second=41 amount=1 +kerning first=39 second=969 amount=-1 +kerning first=356 second=244 amount=-1 +kerning first=913 second=86 amount=-1 +kerning first=955 second=8221 amount=-1 +kerning first=226 second=84 amount=-1 +kerning first=1027 second=1114 amount=-1 +kerning first=321 second=338 amount=-1 +kerning first=194 second=8221 amount=-1 +kerning first=358 second=347 amount=-1 +kerning first=84 second=8249 amount=-1 +kerning first=354 second=239 amount=-1 +kerning first=910 second=941 amount=-1 +kerning first=1168 second=58 amount=-1 +kerning first=915 second=213 amount=-1 +kerning first=76 second=356 amount=-1 +kerning first=8211 second=354 amount=-1 +kerning first=86 second=41 amount=1 +kerning first=89 second=336 amount=-1 +kerning first=80 second=44 amount=-2 +kerning first=932 second=971 amount=-1 +kerning first=256 second=86 amount=-1 +kerning first=354 second=100 amount=-1 +kerning first=70 second=97 amount=-1 +kerning first=84 second=948 amount=-1 +kerning first=932 second=252 amount=-1 +kerning first=39 second=913 amount=-1 +kerning first=358 second=966 amount=-1 +kerning first=936 second=192 amount=-1 +kerning first=932 second=173 amount=-1 +kerning first=8217 second=263 amount=-1 +kerning first=358 second=238 amount=-1 +kerning first=221 second=79 amount=-1 +kerning first=194 second=354 amount=-1 +kerning first=376 second=212 amount=-1 +kerning first=1027 second=1058 amount=1 +kerning first=1043 second=1095 amount=-1 +kerning first=8216 second=1066 amount=1 +kerning first=356 second=260 amount=-1 +kerning first=1113 second=8221 amount=-1 +kerning first=317 second=284 amount=-1 +kerning first=932 second=111 amount=-1 +kerning first=39 second=258 amount=-1 +kerning first=8221 second=84 amount=1 +kerning first=65 second=8216 amount=-1 +kerning first=89 second=338 amount=-1 +kerning first=358 second=99 amount=-1 +kerning first=910 second=916 amount=-1 +kerning first=76 second=8217 amount=-1 +kerning first=319 second=920 amount=-1 +kerning first=160 second=8218 amount=-2 +kerning first=221 second=8212 amount=-1 +kerning first=8217 second=192 amount=-1 +kerning first=354 second=45 amount=-1 +kerning first=969 second=34 amount=-1 +kerning first=1098 second=1098 amount=-1 +kerning first=356 second=8249 amount=-1 +kerning first=376 second=367 amount=-1 +kerning first=321 second=290 amount=-1 +kerning first=1058 second=1077 amount=-1 +kerning first=319 second=266 amount=-1 +kerning first=192 second=87 amount=-1 +kerning first=1043 second=1040 amount=-1 +kerning first=913 second=932 amount=-1 +kerning first=1168 second=1081 amount=-1 +kerning first=354 second=303 amount=-1 +kerning first=89 second=265 amount=-1 +kerning first=34 second=196 amount=-1 +kerning first=936 second=961 amount=-1 +kerning first=939 second=46 amount=-1 +kerning first=258 second=936 amount=-1 +kerning first=358 second=44 amount=-1 +kerning first=313 second=366 amount=-1 +kerning first=356 second=948 amount=-1 +kerning first=88 second=934 amount=-1 +kerning first=221 second=257 amount=-1 +kerning first=1100 second=1090 amount=-1 +kerning first=8216 second=111 amount=-1 +kerning first=221 second=113 amount=-1 +kerning first=1066 second=1066 amount=-1 +kerning first=335 second=356 amount=-1 +kerning first=376 second=250 amount=-1 +kerning first=8217 second=8221 amount=-1 +kerning first=1027 second=1092 amount=-1 +kerning first=84 second=269 amount=-1 +kerning first=256 second=932 amount=-1 +kerning first=8221 second=265 amount=-1 +kerning first=317 second=364 amount=-1 +kerning first=358 second=299 amount=-1 +kerning first=341 second=44 amount=-1 +kerning first=193 second=939 amount=-1 +kerning first=84 second=117 amount=-1 +kerning first=915 second=923 amount=-2 +kerning first=317 second=8216 amount=-2 +kerning first=89 second=195 amount=-1 +kerning first=910 second=949 amount=-1 +kerning first=44 second=8216 amount=-1 +kerning first=89 second=290 amount=-1 +kerning first=221 second=193 amount=-1 +kerning first=123 second=87 amount=1 +kerning first=8217 second=234 amount=-1 +kerning first=939 second=945 amount=-1 +kerning first=932 second=224 amount=-1 +kerning first=1068 second=1058 amount=-1 +kerning first=8220 second=1066 amount=1 +kerning first=84 second=197 amount=-1 +kerning first=376 second=920 amount=-1 +kerning first=313 second=45 amount=-1 +kerning first=8217 second=354 amount=1 +kerning first=8221 second=195 amount=-1 +kerning first=321 second=368 amount=-1 +kerning first=1043 second=1074 amount=-1 +kerning first=902 second=87 amount=-1 +kerning first=933 second=951 amount=-1 +kerning first=1168 second=1116 amount=-1 +kerning first=1041 second=1026 amount=-1 +kerning first=376 second=266 amount=-1 +kerning first=293 second=354 amount=-1 +kerning first=354 second=8212 amount=-1 +kerning first=89 second=8230 amount=-1 +kerning first=1059 second=1108 amount=-1 +kerning first=8250 second=932 amount=-1 +kerning first=192 second=933 amount=-1 +kerning first=221 second=335 amount=-1 +kerning first=1027 second=171 amount=-1 +kerning first=245 second=84 amount=-1 +kerning first=260 second=8221 amount=-1 +kerning first=80 second=923 amount=-1 +kerning first=258 second=372 amount=-1 +kerning first=84 second=341 amount=-1 +kerning first=356 second=269 amount=-1 +kerning first=8221 second=345 amount=-1 +kerning first=932 second=339 amount=-1 +kerning first=358 second=373 amount=-1 +kerning first=84 second=187 amount=-1 +kerning first=8221 second=8230 amount=-2 +kerning first=356 second=117 amount=-1 +kerning first=939 second=198 amount=-1 +kerning first=354 second=253 amount=-1 +kerning first=89 second=232 amount=-1 +kerning first=1090 second=44 amount=-1 +kerning first=1168 second=1060 amount=-1 +kerning first=923 second=39 amount=-1 +kerning first=354 second=257 amount=-1 +kerning first=221 second=227 amount=-1 +kerning first=354 second=113 amount=-1 +kerning first=89 second=97 amount=-1 +kerning first=8220 second=111 amount=-1 +kerning first=84 second=963 amount=-1 +kerning first=8204 second=8220 amount=-1 +kerning first=932 second=312 amount=-1 +kerning first=358 second=974 amount=-1 +kerning first=84 second=235 amount=-1 +kerning first=313 second=79 amount=-1 +kerning first=356 second=197 amount=-1 +kerning first=8217 second=289 amount=-1 +kerning first=260 second=354 amount=-1 +kerning first=317 second=212 amount=-1 +kerning first=8221 second=232 amount=-1 +kerning first=39 second=196 amount=-1 +kerning first=358 second=249 amount=-1 +kerning first=1043 second=1109 amount=-1 +kerning first=932 second=275 amount=-1 +kerning first=376 second=226 amount=-1 +kerning first=328 second=358 amount=-1 +kerning first=358 second=259 amount=-1 +kerning first=1059 second=8230 amount=-1 +kerning first=354 second=193 amount=-1 +kerning first=358 second=112 amount=-1 +kerning first=1111 second=1106 amount=1 +kerning first=76 second=268 amount=-1 +kerning first=333 second=932 amount=-1 +kerning first=902 second=933 amount=-1 +kerning first=910 second=195 amount=-1 +kerning first=313 second=8212 amount=-1 +kerning first=91 second=89 amount=1 +kerning first=1038 second=1108 amount=-1 +kerning first=8216 second=339 amount=-1 +kerning first=321 second=214 amount=-1 +kerning first=315 second=71 amount=-1 +kerning first=356 second=341 amount=-1 +kerning first=358 second=923 amount=-1 +kerning first=372 second=913 amount=-1 +kerning first=356 second=187 amount=-1 +kerning first=939 second=194 amount=-1 +kerning first=1058 second=1090 amount=-1 +kerning first=271 second=293 amount=1 +kerning first=8217 second=74 amount=-1 +kerning first=913 second=939 amount=-1 +kerning first=1168 second=1094 amount=-1 +kerning first=319 second=67 amount=-1 +kerning first=354 second=335 amount=-1 +kerning first=372 second=258 amount=-1 +kerning first=84 second=41 amount=1 +kerning first=1027 second=1241 amount=-1 +kerning first=939 second=59 amount=-1 +kerning first=1059 second=1086 amount=-1 +kerning first=356 second=963 amount=-1 +kerning first=197 second=8216 amount=-1 +kerning first=221 second=287 amount=-1 +kerning first=8216 second=275 amount=-1 +kerning first=910 second=8230 amount=-1 +kerning first=229 second=358 amount=-1 +kerning first=356 second=235 amount=-1 +kerning first=933 second=65 amount=-1 +kerning first=8218 second=221 amount=-1 +kerning first=256 second=939 amount=-1 +kerning first=358 second=326 amount=-1 +kerning first=1058 second=46 amount=-1 +kerning first=376 second=283 amount=-1 +kerning first=354 second=227 amount=-1 +kerning first=89 second=214 amount=-1 +kerning first=70 second=228 amount=-1 +kerning first=8218 second=84 amount=-1 +kerning first=1038 second=8230 amount=-1 +kerning first=8230 second=34 amount=-1 +kerning first=76 second=86 amount=-1 +kerning first=958 second=41 amount=1 +kerning first=932 second=962 amount=-1 +kerning first=8217 second=353 amount=-1 +kerning first=916 second=933 amount=-1 +kerning first=317 second=920 amount=-1 +kerning first=932 second=243 amount=-1 +kerning first=1169 second=46 amount=-1 +kerning first=97 second=932 amount=-1 +kerning first=358 second=229 amount=-1 +kerning first=319 second=360 amount=-1 +kerning first=221 second=71 amount=-1 +kerning first=932 second=372 amount=1 +kerning first=1043 second=1087 amount=-1 +kerning first=1168 second=8250 amount=-1 +kerning first=933 second=966 amount=-1 +kerning first=8216 second=1058 amount=1 +kerning first=317 second=266 amount=-1 +kerning first=932 second=103 amount=-1 +kerning first=194 second=87 amount=-1 +kerning first=89 second=361 amount=-1 +kerning first=356 second=41 amount=1 +kerning first=8220 second=339 amount=-1 +kerning first=376 second=67 amount=-1 +kerning first=221 second=365 amount=-1 +kerning first=1038 second=1086 amount=-1 +kerning first=931 second=268 amount=-1 +kerning first=1098 second=1090 amount=-1 +kerning first=84 second=367 amount=-1 +kerning first=376 second=349 amount=-1 +kerning first=915 second=940 amount=-1 +kerning first=89 second=251 amount=-1 +kerning first=932 second=256 amount=-1 +kerning first=8216 second=962 amount=-1 +kerning first=87 second=195 amount=-1 +kerning first=354 second=287 amount=-1 +kerning first=118 second=44 amount=-1 +kerning first=173 second=89 amount=-1 +kerning first=8216 second=243 amount=-1 +kerning first=8220 second=275 amount=-1 +kerning first=160 second=376 amount=-1 +kerning first=221 second=246 amount=-1 +kerning first=84 second=972 amount=-1 +kerning first=8204 second=8222 amount=-2 +kerning first=84 second=250 amount=-1 +kerning first=8216 second=103 amount=-1 +kerning first=933 second=44 amount=-1 +kerning first=1066 second=1058 amount=-1 +kerning first=1027 second=1084 amount=-1 +kerning first=76 second=932 amount=-1 +kerning first=8211 second=933 amount=-1 +kerning first=319 second=39 amount=-1 +kerning first=1060 second=1061 amount=-1 +kerning first=932 second=171 amount=-1 +kerning first=358 second=281 amount=-1 +kerning first=84 second=109 amount=-1 +kerning first=8221 second=110 amount=-1 +kerning first=46 second=39 amount=-1 +kerning first=315 second=221 amount=-1 +kerning first=358 second=125 amount=1 +kerning first=376 second=101 amount=-1 +kerning first=87 second=8230 amount=-1 +kerning first=45 second=221 amount=-1 +kerning first=227 second=356 amount=-1 +kerning first=315 second=336 amount=-1 +kerning first=8204 second=356 amount=-1 +kerning first=98 second=354 amount=-1 +kerning first=194 second=933 amount=-1 +kerning first=915 second=260 amount=-2 +kerning first=315 second=84 amount=-1 +kerning first=319 second=218 amount=-1 +kerning first=356 second=367 amount=-1 +kerning first=246 second=84 amount=-1 +kerning first=8216 second=256 amount=-1 +kerning first=8220 second=1058 amount=1 +kerning first=258 second=8221 amount=-1 +kerning first=45 second=84 amount=-1 +kerning first=1058 second=1103 amount=-1 +kerning first=372 second=196 amount=-1 +kerning first=1043 second=1066 amount=1 +kerning first=321 second=89 amount=-1 +kerning first=1168 second=1108 amount=-1 +kerning first=354 second=365 amount=-1 +kerning first=160 second=358 amount=-1 +kerning first=315 second=338 amount=-1 +kerning first=1068 second=8221 amount=-1 +kerning first=356 second=972 amount=-1 +kerning first=376 second=46 amount=-1 +kerning first=356 second=250 amount=-1 +kerning first=1100 second=1118 amount=-1 +kerning first=8217 second=305 amount=-1 +kerning first=258 second=354 amount=-1 +kerning first=84 second=324 amount=-1 +kerning first=8221 second=328 amount=-1 +kerning first=354 second=941 amount=-1 +kerning first=8220 second=962 amount=-1 +kerning first=1058 second=59 amount=-1 +kerning first=915 second=948 amount=-1 +kerning first=356 second=109 amount=-1 +kerning first=354 second=246 amount=-1 +kerning first=89 second=228 amount=-1 +kerning first=8220 second=243 amount=-1 +kerning first=91 second=309 amount=1 +kerning first=8217 second=8204 amount=-1 +kerning first=76 second=370 amount=-1 +kerning first=321 second=34 amount=-1 +kerning first=80 second=260 amount=-1 +kerning first=86 second=46 amount=-1 +kerning first=111 second=358 amount=-1 +kerning first=1043 second=173 amount=-1 +kerning first=335 second=932 amount=-1 +kerning first=8217 second=273 amount=-1 +kerning first=915 second=334 amount=-1 +kerning first=354 second=105 amount=-1 +kerning first=1059 second=1044 amount=-1 +kerning first=8220 second=103 amount=-1 +kerning first=939 second=942 amount=-1 +kerning first=358 second=940 amount=-1 +kerning first=221 second=336 amount=-1 +kerning first=84 second=226 amount=-1 +kerning first=313 second=71 amount=-1 +kerning first=8217 second=277 amount=-1 +kerning first=358 second=244 amount=-1 +kerning first=1043 second=1100 amount=-1 +kerning first=932 second=263 amount=-1 +kerning first=1168 second=8230 amount=-1 +kerning first=260 second=87 amount=-1 +kerning first=8230 second=8220 amount=-1 +kerning first=354 second=916 amount=-1 +kerning first=70 second=913 amount=-1 +kerning first=317 second=67 amount=-1 +kerning first=89 second=248 amount=-1 +kerning first=187 second=376 amount=-1 +kerning first=915 second=216 amount=-1 +kerning first=315 second=290 amount=-1 +kerning first=70 second=258 amount=-1 +kerning first=196 second=8216 amount=-1 +kerning first=8220 second=256 amount=-1 +kerning first=221 second=338 amount=-1 +kerning first=228 second=358 amount=-1 +kerning first=356 second=324 amount=-1 +kerning first=271 second=295 amount=1 +kerning first=932 second=192 amount=-1 +kerning first=8221 second=248 amount=-1 +kerning first=1058 second=1082 amount=-1 +kerning first=1056 second=46 amount=-2 +kerning first=376 second=198 amount=-1 +kerning first=933 second=923 amount=-1 +kerning first=1168 second=1086 amount=-1 +kerning first=89 second=279 amount=-1 +kerning first=358 second=260 amount=-1 +kerning first=354 second=8250 amount=-1 +kerning first=195 second=221 amount=-1 +kerning first=8216 second=263 amount=-1 +kerning first=221 second=265 amount=-1 +kerning first=84 second=331 amount=-1 +kerning first=8217 second=351 amount=-1 +kerning first=356 second=226 amount=-1 +kerning first=1038 second=1044 amount=-1 +kerning first=34 second=65 amount=-1 +kerning first=1027 second=1097 amount=-1 +kerning first=965 second=34 amount=-1 +kerning first=86 second=198 amount=-1 +kerning first=84 second=283 amount=-1 +kerning first=8221 second=279 amount=-1 +kerning first=317 second=360 amount=-1 +kerning first=354 second=949 amount=-1 +kerning first=76 second=213 amount=-1 +kerning first=195 second=84 amount=-1 +kerning first=84 second=122 amount=-1 +kerning first=376 second=261 amount=-1 +kerning first=65 second=39 amount=-1 +kerning first=187 second=358 amount=-1 +kerning first=1058 second=1026 amount=1 +kerning first=358 second=8249 amount=-1 +kerning first=910 second=954 amount=-1 +kerning first=915 second=197 amount=-2 +kerning first=337 second=354 amount=-1 +kerning first=260 second=933 amount=-1 +kerning first=315 second=368 amount=-1 +kerning first=8216 second=192 amount=-1 +kerning first=221 second=195 amount=-1 +kerning first=932 second=961 amount=-1 +kerning first=171 second=939 amount=-1 +kerning first=8217 second=239 amount=-1 +kerning first=915 second=284 amount=-1 +kerning first=354 second=84 amount=1 +kerning first=84 second=934 amount=-1 +kerning first=1040 second=1035 amount=-1 +kerning first=932 second=234 amount=-1 +kerning first=358 second=948 amount=-1 +kerning first=1068 second=1063 amount=-1 +kerning first=221 second=290 amount=-1 +kerning first=1058 second=1118 amount=-1 +kerning first=324 second=356 amount=-1 +kerning first=1043 second=1079 amount=-1 +kerning first=932 second=354 amount=1 +kerning first=376 second=194 amount=-1 +kerning first=8217 second=100 amount=-1 +kerning first=354 second=378 amount=-1 +kerning first=112 second=356 amount=-1 +kerning first=248 second=354 amount=-1 +kerning first=929 second=256 amount=-1 +kerning first=915 second=187 amount=-1 +kerning first=356 second=331 amount=-1 +kerning first=1027 second=8211 amount=-1 +kerning first=221 second=8230 amount=-1 +kerning first=86 second=194 amount=-1 +kerning first=84 second=349 amount=-1 +kerning first=356 second=283 amount=-1 +kerning first=80 second=197 amount=-1 +kerning first=376 second=337 amount=-1 +kerning first=356 second=122 amount=-1 +kerning first=915 second=963 amount=-1 +kerning first=317 second=39 amount=-1 +kerning first=8216 second=961 amount=-1 +kerning first=44 second=39 amount=-1 +kerning first=313 second=221 amount=-1 +kerning first=354 second=265 amount=-1 +kerning first=8216 second=234 amount=-1 +kerning first=8220 second=263 amount=-1 +kerning first=221 second=232 amount=-1 +kerning first=354 second=118 amount=-1 +kerning first=224 second=356 amount=-1 +kerning first=84 second=968 amount=-1 +kerning first=313 second=336 amount=-1 +kerning first=356 second=934 amount=-1 +kerning first=8216 second=354 amount=1 +kerning first=84 second=236 amount=-1 +kerning first=8217 second=303 amount=-1 +kerning first=313 second=84 amount=-1 +kerning first=8221 second=241 amount=-1 +kerning first=317 second=218 amount=-1 +kerning first=243 second=84 amount=-1 +kerning first=34 second=44 amount=-2 +kerning first=1043 second=1114 amount=-1 +kerning first=221 second=97 amount=-1 +kerning first=932 second=289 amount=-1 +kerning first=376 second=231 amount=-1 +kerning first=1027 second=1076 amount=-1 +kerning first=321 second=8220 amount=-2 +kerning first=923 second=376 amount=-1 +kerning first=89 second=913 amount=-1 +kerning first=1041 second=1066 amount=-1 +kerning first=358 second=269 amount=-1 +kerning first=84 second=101 amount=-1 +kerning first=354 second=195 amount=-1 +kerning first=39 second=65 amount=-1 +kerning first=70 second=196 amount=-1 +kerning first=315 second=214 amount=-1 +kerning first=358 second=117 amount=-1 +kerning first=8220 second=192 amount=-1 +kerning first=91 second=356 amount=1 +kerning first=931 second=213 amount=-1 +kerning first=376 second=93 amount=1 +kerning first=313 second=338 amount=-1 +kerning first=1066 second=8221 amount=-1 +kerning first=89 second=258 amount=-1 +kerning first=104 second=84 amount=-1 +kerning first=321 second=219 amount=-1 +kerning first=1098 second=1118 amount=-1 +kerning first=356 second=349 amount=-1 +kerning first=8221 second=913 amount=-1 +kerning first=8204 second=86 amount=-1 +kerning first=1058 second=1095 amount=-1 +kerning first=8212 second=1026 amount=-1 +kerning first=358 second=197 amount=-1 +kerning first=1043 second=1058 amount=1 +kerning first=1075 second=46 amount=-1 +kerning first=944 second=39 amount=-1 +kerning first=321 second=81 amount=-1 +kerning first=86 second=93 amount=1 +kerning first=1168 second=1099 amount=-1 +kerning first=8221 second=258 amount=-1 +kerning first=354 second=345 amount=-1 +kerning first=932 second=74 amount=-1 +kerning first=84 second=46 amount=-1 +kerning first=1050 second=1051 amount=1 +kerning first=354 second=8230 amount=-1 +kerning first=109 second=358 amount=-1 +kerning first=356 second=968 amount=-1 +kerning first=8216 second=289 amount=-1 +kerning first=934 second=933 amount=-1 +kerning first=8221 second=307 amount=-1 +kerning first=356 second=236 amount=-1 +kerning first=932 second=371 amount=-1 +kerning first=1027 second=1111 amount=-1 +kerning first=1114 second=1098 amount=-1 +kerning first=923 second=358 amount=-1 +kerning first=84 second=297 amount=-1 +kerning first=1118 second=8230 amount=-1 +kerning first=358 second=341 amount=-1 +kerning first=8220 second=961 amount=-1 +kerning first=258 second=87 amount=-1 +kerning first=376 second=285 amount=-1 +kerning first=356 second=101 amount=-1 +kerning first=354 second=232 amount=-1 +kerning first=1058 second=1040 amount=-1 +kerning first=358 second=187 amount=-1 +kerning first=8220 second=234 amount=-1 +kerning first=915 second=212 amount=-1 +kerning first=8218 second=89 amount=-1 +kerning first=8230 second=8217 amount=-2 +kerning first=8222 second=376 amount=-1 +kerning first=1168 second=1044 amount=-1 +kerning first=8220 second=354 amount=1 +kerning first=221 second=214 amount=-1 +kerning first=932 second=970 amount=1 +kerning first=261 second=84 amount=-1 +kerning first=354 second=97 amount=-1 +kerning first=89 second=81 amount=-1 +kerning first=1059 second=1035 amount=1 +kerning first=84 second=945 amount=-1 +kerning first=313 second=290 amount=-1 +kerning first=193 second=8216 amount=-1 +kerning first=932 second=353 amount=-1 +kerning first=358 second=963 amount=-1 +kerning first=936 second=193 amount=-1 +kerning first=225 second=358 amount=-1 +kerning first=358 second=235 amount=-1 +kerning first=929 second=192 amount=-1 +kerning first=8216 second=74 amount=-1 +kerning first=1043 second=1092 amount=-1 +kerning first=8217 second=113 amount=-1 +kerning first=933 second=940 amount=-1 +kerning first=34 second=974 amount=-1 +kerning first=1036 second=1095 amount=-1 +kerning first=227 second=932 amount=-1 +kerning first=8204 second=932 amount=-1 +kerning first=376 second=308 amount=-1 +kerning first=356 second=46 amount=-1 +kerning first=39 second=44 amount=-2 +kerning first=910 second=913 amount=-1 +kerning first=197 second=39 amount=-1 +kerning first=221 second=361 amount=-1 +kerning first=192 second=221 amount=-1 +kerning first=8217 second=193 amount=-1 +kerning first=356 second=297 amount=-1 +kerning first=910 second=258 amount=-1 +kerning first=84 second=198 amount=-1 +kerning first=376 second=369 amount=-1 +kerning first=915 second=972 amount=-1 +kerning first=1058 second=1074 amount=-1 +kerning first=319 second=262 amount=-1 +kerning first=192 second=84 amount=-1 +kerning first=173 second=356 amount=-1 +kerning first=34 second=923 amount=-1 +kerning first=8222 second=358 amount=-1 +kerning first=1168 second=1078 amount=-1 +kerning first=8220 second=289 amount=-1 +kerning first=326 second=354 amount=-1 +kerning first=221 second=251 amount=-1 +kerning first=89 second=115 amount=-1 +kerning first=258 second=933 amount=-1 +kerning first=358 second=41 amount=1 +kerning first=84 second=944 amount=-1 +kerning first=313 second=368 amount=-1 +kerning first=356 second=945 amount=-1 +kerning first=933 second=260 amount=-1 +kerning first=253 second=44 amount=-1 +kerning first=84 second=255 amount=-1 +kerning first=8217 second=335 amount=-1 +kerning first=1043 second=171 amount=-1 +kerning first=1038 second=1035 amount=1 +kerning first=331 second=84 amount=-1 +kerning first=1066 second=1063 amount=-1 +kerning first=376 second=242 amount=-1 +kerning first=1027 second=1089 amount=-1 +kerning first=84 second=261 amount=-1 +kerning first=75 second=74 amount=1 +kerning first=932 second=8211 amount=-1 +kerning first=123 second=221 amount=1 +kerning first=84 second=114 amount=-1 +kerning first=8221 second=115 amount=-1 +kerning first=915 second=920 amount=-1 +kerning first=89 second=196 amount=-1 +kerning first=110 second=356 amount=-1 +kerning first=910 second=946 amount=-1 +kerning first=114 second=44 amount=-1 +kerning first=950 second=125 amount=1 +kerning first=123 second=84 amount=1 +kerning first=902 second=221 amount=-1 +kerning first=915 second=266 amount=-1 +kerning first=315 second=89 amount=-1 +kerning first=8220 second=74 amount=-1 +kerning first=319 second=376 amount=-1 +kerning first=932 second=225 amount=-1 +kerning first=84 second=194 amount=-1 +kerning first=45 second=89 amount=-1 +kerning first=356 second=198 amount=-1 +kerning first=8221 second=196 amount=-1 +kerning first=321 second=356 amount=-1 +kerning first=1058 second=1109 amount=-1 +kerning first=1027 second=45 amount=-1 +kerning first=319 second=332 amount=-1 +kerning first=902 second=84 amount=-1 +kerning first=8249 second=933 amount=-1 +kerning first=933 second=948 amount=-1 +kerning first=1168 second=1113 amount=-1 +kerning first=319 second=85 amount=-1 +kerning first=932 second=87 amount=1 +kerning first=354 second=361 amount=-1 +kerning first=89 second=333 amount=-1 +kerning first=376 second=262 amount=-1 +kerning first=1034 second=1026 amount=-1 +kerning first=1059 second=1105 amount=-1 +kerning first=372 second=65 amount=-1 +kerning first=356 second=944 amount=-1 +kerning first=39 second=974 amount=-1 +kerning first=226 second=356 amount=-1 +kerning first=356 second=255 amount=-1 +kerning first=913 second=8216 amount=-1 +kerning first=315 second=34 amount=-1 +kerning first=84 second=337 amount=-1 +kerning first=8221 second=333 amount=-1 +kerning first=356 second=261 amount=-1 +kerning first=932 second=305 amount=-1 +kerning first=354 second=973 amount=-1 +kerning first=358 second=367 amount=-1 +kerning first=356 second=114 amount=-1 +kerning first=915 second=953 amount=-1 +kerning first=354 second=251 amount=-1 +kerning first=89 second=233 amount=-1 +kerning first=87 second=913 amount=-1 +kerning first=321 second=8217 amount=-1 +kerning first=8212 second=376 amount=-1 +kerning first=313 second=214 amount=-1 +kerning first=1043 second=1241 amount=-1 +kerning first=221 second=228 amount=-1 +kerning first=256 second=8216 amount=-1 +kerning first=354 second=110 amount=-1 +kerning first=87 second=258 amount=-1 +kerning first=319 second=358 amount=-1 +kerning first=932 second=273 amount=-1 +kerning first=39 second=923 amount=-1 +kerning first=358 second=972 amount=-1 +kerning first=242 second=358 amount=-1 +kerning first=957 second=8230 amount=-1 +kerning first=84 second=231 amount=-1 +kerning first=8217 second=287 amount=-1 +kerning first=356 second=194 amount=-1 +kerning first=8221 second=233 amount=-1 +kerning first=358 second=250 amount=-1 +kerning first=939 second=173 amount=-1 +kerning first=932 second=277 amount=-1 +kerning first=8216 second=1076 amount=-1 +kerning first=8221 second=356 amount=1 +kerning first=932 second=121 amount=-1 +kerning first=1041 second=1058 amount=-1 +kerning first=974 second=39 amount=-1 +kerning first=916 second=84 amount=-1 +kerning first=84 second=93 amount=1 +kerning first=376 second=332 amount=-1 +kerning first=358 second=109 amount=-1 +kerning first=929 second=74 amount=-1 +kerning first=910 second=196 amount=-1 +kerning first=271 second=8217 amount=1 +kerning first=91 second=86 amount=1 +kerning first=1038 second=1105 amount=-1 +kerning first=1027 second=8212 amount=-1 +kerning first=324 second=932 amount=-1 +kerning first=221 second=248 amount=-1 +kerning first=319 second=199 amount=-1 +kerning first=356 second=337 amount=-1 +kerning first=112 second=932 amount=-1 +kerning first=1058 second=1087 amount=-1 +kerning first=319 second=288 amount=-1 +kerning first=8212 second=358 amount=-1 +kerning first=1168 second=1091 amount=-1 +kerning first=1056 second=1040 amount=-1 +kerning first=354 second=328 amount=-1 +kerning first=89 second=291 amount=-1 +kerning first=76 second=8249 amount=-1 +kerning first=8216 second=273 amount=-1 +kerning first=933 second=197 amount=-1 +kerning first=958 second=93 amount=1 +kerning first=8221 second=8217 amount=-1 +kerning first=372 second=44 amount=-1 +kerning first=8216 second=277 amount=-1 +kerning first=160 second=372 amount=-1 +kerning first=259 second=84 amount=-1 +kerning first=221 second=279 amount=-1 +kerning first=356 second=231 amount=-1 +kerning first=932 second=351 amount=-1 +kerning first=1114 second=1090 amount=-1 +kerning first=1027 second=1102 amount=-1 +kerning first=84 second=285 amount=-1 +kerning first=8221 second=291 amount=-1 +kerning first=358 second=324 amount=-1 +kerning first=76 second=217 amount=-1 +kerning first=195 second=89 amount=-1 +kerning first=8211 second=221 amount=-1 +kerning first=376 second=267 amount=-1 +kerning first=356 second=93 amount=1 +kerning first=915 second=934 amount=-1 +kerning first=354 second=228 amount=-1 +kerning first=224 second=932 amount=-1 +kerning first=910 second=959 amount=-1 +kerning first=76 second=334 amount=-1 +kerning first=1168 second=1035 amount=1 +kerning first=196 second=39 amount=-1 +kerning first=8211 second=84 amount=-1 +kerning first=8217 second=246 amount=-1 +kerning first=936 second=916 amount=-1 +kerning first=932 second=239 amount=-1 +kerning first=194 second=221 amount=-1 +kerning first=915 second=67 amount=-1 +kerning first=8220 second=1076 amount=-1 +kerning first=65 second=376 amount=-1 +kerning first=1027 second=58 amount=-1 +kerning first=358 second=226 amount=-1 +kerning first=319 second=362 amount=-1 +kerning first=91 second=932 amount=1 +kerning first=343 second=46 amount=-1 +kerning first=8217 second=105 amount=-1 +kerning first=376 second=199 amount=-1 +kerning first=933 second=963 amount=-1 +kerning first=1043 second=1084 amount=-1 +kerning first=84 second=308 amount=-1 +kerning first=317 second=262 amount=-1 +kerning first=932 second=100 amount=-1 +kerning first=194 second=84 amount=-1 +kerning first=89 second=363 amount=-1 +kerning first=195 second=34 amount=-1 +kerning first=76 second=216 amount=-1 +kerning first=376 second=288 amount=-1 +kerning first=354 second=248 amount=-1 +kerning first=70 second=230 amount=-1 +kerning first=74 second=125 amount=1 +kerning first=328 second=354 amount=-1 +kerning first=245 second=356 amount=-1 +kerning first=910 second=181 amount=-1 +kerning first=1035 second=1035 amount=-1 +kerning first=84 second=369 amount=-1 +kerning first=356 second=285 amount=-1 +kerning first=915 second=968 amount=-1 +kerning first=321 second=268 amount=-1 +kerning first=89 second=245 amount=-1 +kerning first=1058 second=1066 amount=1 +kerning first=8220 second=273 amount=-1 +kerning first=87 second=196 amount=-1 +kerning first=271 second=107 amount=1 +kerning first=354 second=279 amount=-1 +kerning first=932 second=45 amount=-1 +kerning first=8220 second=277 amount=-1 +kerning first=315 second=8220 amount=-2 +kerning first=1107 second=1076 amount=-1 +kerning first=329 second=358 amount=-1 +kerning first=34 second=260 amount=-1 +kerning first=84 second=242 amount=-1 +kerning first=313 second=89 amount=-1 +kerning first=65 second=358 amount=-1 +kerning first=8221 second=245 amount=-1 +kerning first=317 second=376 amount=-1 +kerning first=358 second=331 amount=-1 +kerning first=8216 second=100 amount=-1 +kerning first=932 second=303 amount=-1 +kerning first=1027 second=1081 amount=-1 +kerning first=229 second=354 amount=-1 +kerning first=356 second=308 amount=-1 +kerning first=317 second=332 amount=-1 +kerning first=358 second=283 amount=-1 +kerning first=317 second=85 amount=-1 +kerning first=315 second=219 amount=-1 +kerning first=358 second=122 amount=-1 +kerning first=76 second=284 amount=-1 +kerning first=221 second=913 amount=-1 +kerning first=89 second=268 amount=-1 +kerning first=1058 second=173 amount=-1 +kerning first=931 second=334 amount=-1 +kerning first=315 second=81 amount=-1 +kerning first=70 second=65 amount=-1 +kerning first=319 second=210 amount=-1 +kerning first=356 second=369 amount=-1 +kerning first=915 second=46 amount=-2 +kerning first=358 second=934 amount=-1 +kerning first=372 second=923 amount=-1 +kerning first=221 second=258 amount=-1 +kerning first=313 second=34 amount=-1 +kerning first=1058 second=1100 amount=-1 +kerning first=271 second=320 amount=1 +kerning first=8217 second=84 amount=1 +kerning first=321 second=86 amount=-1 +kerning first=1168 second=1105 amount=-1 +kerning first=931 second=216 amount=-1 +kerning first=293 second=84 amount=-1 +kerning first=356 second=242 amount=-1 +kerning first=317 second=358 amount=-1 +kerning first=244 second=358 amount=-1 +kerning first=1027 second=1116 amount=-1 +kerning first=173 second=932 amount=-1 +kerning first=932 second=8212 amount=-1 +kerning first=354 second=969 amount=-1 +kerning first=358 second=349 amount=-1 +kerning first=935 second=934 amount=-1 +kerning first=915 second=945 amount=-1 +kerning first=354 second=241 amount=-1 +kerning first=8218 second=356 amount=-1 +kerning first=8212 second=910 amount=-1 +kerning first=310 second=308 amount=1 +kerning first=973 second=39 amount=-1 +kerning first=76 second=364 amount=-1 +kerning first=76 second=8216 amount=-2 +kerning first=80 second=46 amount=-2 +kerning first=1046 second=1051 amount=1 +kerning first=932 second=912 amount=1 +kerning first=260 second=221 amount=-1 +kerning first=8220 second=100 amount=-1 +kerning first=939 second=962 amount=-1 +kerning first=932 second=253 amount=-1 +kerning first=358 second=968 amount=-1 +kerning first=936 second=195 amount=-1 +kerning first=319 second=173 amount=-1 +kerning first=8217 second=265 amount=-1 +kerning first=317 second=199 amount=-1 +kerning first=86 second=301 amount=1 +kerning first=358 second=236 amount=-1 +kerning first=110 second=932 amount=-1 +kerning first=923 second=936 amount=-1 +kerning first=932 second=257 amount=-1 +kerning first=221 second=81 amount=-1 +kerning first=376 second=210 amount=-1 +kerning first=1027 second=1060 amount=-1 +kerning first=933 second=972 amount=-1 +kerning first=260 second=84 amount=-1 +kerning first=1043 second=1097 amount=-1 +kerning first=317 second=288 amount=-1 +kerning first=354 second=913 amount=-1 +kerning first=932 second=113 amount=-1 +kerning first=39 second=260 amount=-1 +kerning first=345 second=8230 amount=-1 +kerning first=89 second=230 amount=-1 +kerning first=358 second=101 amount=-1 +kerning first=121 second=8230 amount=-1 +kerning first=915 second=198 amount=-2 +kerning first=321 second=932 amount=-1 +kerning first=354 second=258 amount=-1 +kerning first=8230 second=939 amount=-1 +kerning first=931 second=284 amount=-1 +kerning first=8217 second=195 amount=-1 +kerning first=70 second=44 amount=-1 +kerning first=84 second=380 amount=-1 +kerning first=932 second=193 amount=-1 +kerning first=195 second=8220 amount=-1 +kerning first=936 second=8230 amount=-1 +kerning first=915 second=944 amount=-1 +kerning first=354 second=307 amount=-1 +kerning first=1058 second=1079 amount=-1 +kerning first=192 second=89 amount=-1 +kerning first=197 second=376 amount=-1 +kerning first=1168 second=1083 amount=-1 +kerning first=226 second=932 amount=-1 +kerning first=939 second=256 amount=-1 +kerning first=89 second=271 amount=-1 +kerning first=34 second=197 amount=-1 +kerning first=358 second=46 amount=-1 +kerning first=193 second=39 amount=-1 +kerning first=160 second=354 amount=-1 +kerning first=84 second=358 amount=1 +kerning first=8217 second=345 amount=-1 +kerning first=1043 second=8211 amount=-1 +kerning first=950 second=41 amount=1 +kerning first=8216 second=113 amount=-1 +kerning first=221 second=115 amount=-1 +kerning first=932 second=335 amount=-1 +kerning first=376 second=252 amount=-1 +kerning first=8217 second=8230 amount=-2 +kerning first=1027 second=1094 amount=-1 +kerning first=84 second=267 amount=-1 +kerning first=376 second=173 amount=-1 +kerning first=8221 second=271 amount=-1 +kerning first=317 second=362 amount=-1 +kerning first=76 second=212 amount=-1 +kerning first=358 second=297 amount=-1 +kerning first=341 second=46 amount=-1 +kerning first=80 second=198 amount=-1 +kerning first=84 second=119 amount=-1 +kerning first=923 second=372 amount=-1 +kerning first=910 second=951 amount=-1 +kerning first=1091 second=8230 amount=-1 +kerning first=372 second=125 amount=1 +kerning first=192 second=34 amount=-1 +kerning first=376 second=111 amount=-1 +kerning first=915 second=194 amount=-2 +kerning first=357 second=8217 amount=1 +kerning first=315 second=356 amount=-1 +kerning first=8216 second=193 amount=-1 +kerning first=123 second=89 amount=1 +kerning first=221 second=196 amount=-1 +kerning first=246 second=356 amount=-1 +kerning first=8217 second=232 amount=-1 +kerning first=89 second=65 amount=-1 +kerning first=45 second=356 amount=-1 +kerning first=356 second=380 amount=-1 +kerning first=8221 second=932 amount=1 +kerning first=111 second=354 amount=-1 +kerning first=932 second=227 amount=-1 +kerning first=915 second=59 amount=-1 +kerning first=358 second=945 amount=-1 +kerning first=1033 second=1035 amount=-1 +kerning first=321 second=370 amount=-1 +kerning first=1058 second=1114 amount=-1 +kerning first=1043 second=1076 amount=-1 +kerning first=902 second=89 amount=-1 +kerning first=197 second=358 amount=-1 +kerning first=1168 second=1119 amount=-1 +kerning first=89 second=347 amount=-1 +kerning first=8221 second=65 amount=-1 +kerning first=8216 second=335 amount=-1 +kerning first=221 second=333 amount=-1 +kerning first=313 second=8220 amount=-2 +kerning first=356 second=358 amount=1 +kerning first=1027 second=8250 amount=-1 +kerning first=295 second=358 amount=-1 +kerning first=1114 second=1118 amount=-1 +kerning first=173 second=939 amount=-1 +kerning first=315 second=8217 amount=-1 +kerning first=84 second=343 amount=-1 +kerning first=8221 second=347 amount=-1 +kerning first=356 second=267 amount=-1 +kerning first=80 second=194 amount=-1 +kerning first=356 second=119 amount=-1 +kerning first=228 second=354 amount=-1 +kerning first=354 second=382 amount=-1 +kerning first=1058 second=1058 amount=1 +kerning first=1090 second=46 amount=-1 +kerning first=358 second=198 amount=-1 +kerning first=902 second=34 amount=-1 +kerning first=313 second=219 amount=-1 +kerning first=70 second=259 amount=-1 +kerning first=221 second=233 amount=-1 +kerning first=354 second=115 amount=-1 +kerning first=89 second=99 amount=-1 +kerning first=8222 second=372 amount=-1 +kerning first=84 second=965 amount=-1 +kerning first=8220 second=113 amount=-1 +kerning first=358 second=944 amount=-1 +kerning first=84 second=237 amount=-1 +kerning first=8221 second=238 amount=-1 +kerning first=313 second=81 amount=-1 +kerning first=317 second=210 amount=-1 +kerning first=39 second=197 amount=-1 +kerning first=358 second=255 amount=-1 +kerning first=1043 second=1111 amount=-1 +kerning first=932 second=287 amount=-1 +kerning first=376 second=224 amount=-1 +kerning first=76 second=920 amount=-1 +kerning first=1041 second=1063 amount=-1 +kerning first=70 second=923 amount=-1 +kerning first=358 second=261 amount=-1 +kerning first=8221 second=99 amount=-1 +kerning first=1034 second=1066 amount=-1 +kerning first=354 second=196 amount=-1 +kerning first=358 second=114 amount=-1 +kerning first=8220 second=193 amount=-1 +kerning first=931 second=212 amount=-1 +kerning first=76 second=266 amount=-1 +kerning first=187 second=354 amount=-1 +kerning first=913 second=39 amount=-1 +kerning first=321 second=213 amount=-1 +kerning first=89 second=44 amount=-1 +kerning first=356 second=343 amount=-1 +kerning first=98 second=84 amount=-1 +kerning first=241 second=358 amount=-1 +kerning first=102 second=34 amount=1 +kerning first=910 second=65 amount=-1 +kerning first=939 second=192 amount=-1 +kerning first=1058 second=1092 amount=-1 +kerning first=358 second=194 amount=-1 +kerning first=376 second=339 amount=-1 +kerning first=245 second=932 amount=-1 +kerning first=1168 second=1096 amount=-1 +kerning first=354 second=333 amount=-1 +kerning first=8220 second=335 amount=-1 +kerning first=916 second=34 amount=-1 +kerning first=372 second=260 amount=-1 +kerning first=256 second=39 amount=-1 +kerning first=8221 second=44 amount=-2 +kerning first=356 second=965 amount=-1 +kerning first=929 second=912 amount=1 +kerning first=8216 second=287 amount=-1 +kerning first=258 second=221 amount=-1 +kerning first=221 second=291 amount=-1 +kerning first=356 second=237 amount=-1 +kerning first=317 second=173 amount=-1 +kerning first=932 second=365 amount=-1 +kerning first=1027 second=1108 amount=-1 +kerning first=195 second=356 amount=-1 +kerning first=84 second=301 amount=-1 +kerning first=8221 second=299 amount=-1 +kerning first=354 second=959 amount=-1 +kerning first=971 second=34 amount=-1 +kerning first=358 second=337 amount=-1 +kerning first=258 second=84 amount=-1 +kerning first=376 second=275 amount=-1 +kerning first=354 second=233 amount=-1 +kerning first=89 second=213 amount=-1 +kerning first=70 second=229 amount=-1 +kerning first=910 second=966 amount=-1 +kerning first=8218 second=86 amount=-1 +kerning first=354 second=356 amount=1 +kerning first=119 second=8230 amount=-1 +kerning first=8211 second=89 amount=-1 +kerning first=932 second=941 amount=-1 +kerning first=1059 second=44 amount=-1 +kerning first=1059 second=1032 amount=-1 +kerning first=74 second=41 amount=1 +kerning first=939 second=961 amount=-1 +kerning first=932 second=246 amount=-1 +kerning first=1058 second=171 amount=-1 +kerning first=358 second=231 amount=-1 +kerning first=929 second=193 amount=-1 +kerning first=319 second=372 amount=-1 +kerning first=192 second=8220 amount=-1 +kerning first=934 second=8230 amount=-1 +kerning first=8217 second=110 amount=-1 +kerning first=1043 second=1089 amount=-1 +kerning first=194 second=89 amount=-1 +kerning first=932 second=105 amount=-1 +kerning first=196 second=376 amount=-1 +kerning first=195 second=8217 amount=-1 +kerning first=931 second=920 amount=-1 +kerning first=358 second=93 amount=1 +kerning first=1100 second=8221 amount=-1 +kerning first=40 second=106 amount=1 +kerning first=221 second=363 amount=-1 +kerning first=257 second=358 amount=-1 +kerning first=40 second=1095 amount=-1 +kerning first=315 second=268 amount=-1 +kerning first=1027 second=8230 amount=-1 +kerning first=931 second=266 amount=-1 +kerning first=932 second=916 amount=-1 +kerning first=356 second=301 amount=-1 +kerning first=910 second=44 amount=-1 +kerning first=915 second=942 amount=-1 +kerning first=1043 second=45 amount=-1 +kerning first=89 second=249 amount=-1 +kerning first=955 second=34 amount=-1 +kerning first=8216 second=941 amount=-1 +kerning first=80 second=308 amount=-1 +kerning first=123 second=309 amount=1 +kerning first=1168 second=1075 amount=-1 +kerning first=923 second=8221 amount=-1 +kerning first=354 second=291 amount=-1 +kerning first=194 second=34 amount=-1 +kerning first=118 second=46 amount=-1 +kerning first=89 second=259 amount=-1 +kerning first=8216 second=246 amount=-1 +kerning first=8220 second=287 amount=-1 +kerning first=221 second=245 amount=-1 +kerning first=84 second=971 amount=-1 +kerning first=313 second=356 amount=-1 +kerning first=243 second=356 amount=-1 +kerning first=1038 second=44 amount=-1 +kerning first=84 second=252 amount=-1 +kerning first=87 second=65 amount=-1 +kerning first=8217 second=328 amount=-1 +kerning first=8218 second=932 amount=-1 +kerning first=1038 second=1032 amount=-1 +kerning first=109 second=354 amount=-1 +kerning first=84 second=173 amount=-1 +kerning first=933 second=46 amount=-1 +kerning first=8221 second=160 amount=-1 +kerning first=160 second=87 amount=-1 +kerning first=902 second=8220 amount=-1 +kerning first=376 second=243 amount=-1 +kerning first=1027 second=1086 amount=-1 +kerning first=319 second=171 amount=-1 +kerning first=932 second=8250 amount=-1 +kerning first=89 second=923 amount=-1 +kerning first=358 second=285 amount=-1 +kerning first=196 second=358 amount=-1 +kerning first=84 second=111 amount=-1 +kerning first=8221 second=112 amount=-1 +kerning first=923 second=354 amount=-1 +kerning first=376 second=103 amount=-1 +kerning first=8216 second=916 amount=-1 +kerning first=104 second=356 amount=-1 +kerning first=1058 second=1241 amount=-1 +kerning first=76 second=67 amount=-1 +kerning first=337 second=84 amount=-1 +kerning first=932 second=949 amount=-1 +kerning first=915 second=262 amount=-1 +kerning first=315 second=86 amount=-1 +kerning first=319 second=220 amount=-1 +kerning first=8221 second=923 amount=-1 +kerning first=8204 second=8216 amount=-1 +kerning first=65 second=936 amount=-1 +kerning first=1033 second=8217 amount=-1 +kerning first=221 second=268 amount=-1 +kerning first=313 second=8217 amount=-1 +kerning first=372 second=197 amount=-1 +kerning first=933 second=945 amount=-1 +kerning first=40 second=376 amount=1 +kerning first=225 second=354 amount=-1 +kerning first=932 second=84 amount=1 +kerning first=354 second=363 amount=-1 +kerning first=358 second=308 amount=-1 +kerning first=376 second=256 amount=-1 +kerning first=248 second=84 amount=-1 +kerning first=356 second=971 amount=-1 +kerning first=102 second=8220 amount=1 +kerning first=1028 second=1026 amount=1 +kerning first=1043 second=8212 amount=-1 +kerning first=356 second=252 amount=-1 +kerning first=356 second=173 amount=-1 +kerning first=932 second=378 amount=-1 +kerning first=8217 second=248 amount=-1 +kerning first=8221 second=326 amount=-1 +kerning first=358 second=369 amount=-1 +kerning first=8220 second=941 amount=-1 +kerning first=356 second=111 amount=-1 +kerning first=354 second=245 amount=-1 +kerning first=86 second=256 amount=-1 +kerning first=89 second=229 amount=-1 +kerning first=8220 second=246 amount=-1 +kerning first=376 second=171 amount=-1 +kerning first=76 second=360 amount=-1 +kerning first=8216 second=949 amount=-1 +kerning first=261 second=356 amount=-1 +kerning first=933 second=198 amount=-1 +kerning first=915 second=332 amount=-1 +kerning first=8222 second=354 amount=-1 +kerning first=84 second=224 amount=-1 +kerning first=87 second=44 amount=-1 +kerning first=8217 second=279 amount=-1 +kerning first=358 second=242 amount=-1 +kerning first=8216 second=84 amount=1 +kerning first=1043 second=1102 amount=-1 +kerning first=932 second=265 amount=-1 +kerning first=260 second=89 amount=-1 +kerning first=40 second=358 amount=1 +kerning first=65 second=372 amount=-1 +kerning first=932 second=118 amount=-1 +kerning first=315 second=932 amount=-1 +kerning first=8220 second=916 amount=-1 +kerning first=1050 second=1095 amount=-1 +kerning first=246 second=932 amount=-1 +kerning first=1034 second=1058 amount=-1 +kerning first=910 second=923 amount=-1 +kerning first=45 second=932 amount=-1 +kerning first=70 second=260 amount=-1 +kerning first=319 second=927 amount=-1 +kerning first=221 second=230 amount=-1 +kerning first=958 second=955 amount=1 +kerning first=931 second=67 amount=-1 +kerning first=932 second=195 amount=-1 +kerning first=192 second=356 amount=-1 +kerning first=84 second=339 amount=-1 +kerning first=1043 second=58 amount=-1 +kerning first=1058 second=1084 amount=-1 +kerning first=319 second=286 amount=-1 +kerning first=260 second=34 amount=-1 +kerning first=1168 second=1088 amount=-1 +kerning first=89 second=281 amount=-1 +kerning first=76 second=39 amount=-1 +kerning first=933 second=194 amount=-1 +kerning first=1113 second=1091 amount=-1 +kerning first=89 second=125 amount=1 +kerning first=372 second=41 amount=1 +kerning first=331 second=356 amount=-1 +kerning first=8216 second=265 amount=-1 +kerning first=221 second=271 amount=-1 +kerning first=84 second=312 amount=-1 +kerning first=356 second=224 amount=-1 +kerning first=933 second=59 amount=-1 +kerning first=932 second=345 amount=-1 +kerning first=1027 second=1099 amount=-1 +kerning first=84 second=275 amount=-1 +kerning first=319 second=8221 amount=-1 +kerning first=8221 second=281 amount=-1 +kerning first=317 second=372 amount=-1 +kerning first=932 second=8230 amount=-1 +kerning first=194 second=8220 amount=-1 +kerning first=76 second=218 amount=-1 +kerning first=195 second=86 amount=-1 +kerning first=8220 second=949 amount=-1 +kerning first=376 second=263 amount=-1 +kerning first=939 second=8211 amount=-1 +kerning first=46 second=8221 amount=-2 +kerning first=193 second=376 amount=-1 +kerning first=192 second=8217 amount=-1 +kerning first=915 second=199 amount=-1 +kerning first=1168 second=44 amount=-1 +kerning first=1028 second=1095 amount=-1 +kerning first=123 second=356 amount=1 +kerning first=1168 second=1032 amount=-1 +kerning first=315 second=370 amount=-1 +kerning first=8216 second=195 amount=-1 +kerning first=1098 second=8221 amount=-1 +kerning first=8217 second=241 amount=-1 +kerning first=915 second=288 amount=-1 +kerning first=936 second=913 amount=-1 +kerning first=354 second=86 amount=1 +kerning first=8220 second=84 amount=1 +kerning first=313 second=268 amount=-1 +kerning first=932 second=232 amount=-1 +kerning first=929 second=916 amount=-1 +kerning first=902 second=356 amount=-1 +kerning first=376 second=927 amount=-1 +kerning first=356 second=339 amount=-1 +kerning first=319 second=354 amount=-1 +kerning first=221 second=65 amount=-1 +kerning first=1043 second=1081 amount=-1 +kerning first=376 second=192 amount=-1 +kerning first=936 second=258 amount=-1 +kerning first=1027 second=1044 amount=-1 +kerning first=242 second=354 amount=-1 +kerning first=932 second=97 amount=-1 +kerning first=376 second=286 amount=-1 +kerning first=354 second=230 amount=-1 +kerning first=306 second=125 amount=1 +kerning first=221 second=347 amount=-1 +kerning first=8217 second=913 amount=-1 +kerning first=356 second=312 amount=-1 +kerning first=8216 second=8230 amount=-2 +kerning first=86 second=192 amount=-1 +kerning first=356 second=275 amount=-1 +kerning first=358 second=380 amount=-1 +kerning first=8217 second=258 amount=-1 +kerning first=197 second=936 amount=-1 +kerning first=915 second=965 amount=-1 +kerning first=317 second=171 amount=-1 +kerning first=89 second=244 amount=-1 +kerning first=87 second=923 amount=-1 +kerning first=193 second=358 amount=-1 +kerning first=902 second=8217 amount=-1 +kerning first=271 second=104 amount=1 +kerning first=354 second=271 amount=-1 +kerning first=8216 second=232 amount=-1 +kerning first=8220 second=265 amount=-1 +kerning first=8217 second=307 amount=-1 +kerning first=195 second=932 amount=-1 +kerning first=8212 second=354 amount=-1 +kerning first=84 second=962 amount=-1 +kerning first=326 second=84 amount=-1 +kerning first=84 second=243 amount=-1 +kerning first=313 second=86 amount=-1 +kerning first=8221 second=244 amount=-1 +kerning first=317 second=220 amount=-1 +kerning first=358 second=358 amount=1 +kerning first=34 second=46 amount=-2 +kerning first=1043 second=1116 amount=-1 +kerning first=221 second=99 amount=-1 +kerning first=376 second=234 amount=-1 +kerning first=1027 second=1078 amount=-1 +kerning first=321 second=8249 amount=-1 +kerning first=916 second=356 amount=-1 +kerning first=84 second=372 amount=1 +kerning first=354 second=932 amount=1 +kerning first=358 second=267 amount=-1 +kerning first=84 second=103 amount=-1 +kerning first=315 second=213 amount=-1 +kerning first=70 second=197 amount=-1 +kerning first=358 second=119 amount=-1 +kerning first=8220 second=195 amount=-1 +kerning first=45 second=939 amount=-1 +kerning first=923 second=87 amount=-1 +kerning first=89 second=260 amount=-1 +kerning first=1026 second=1026 amount=-1 +kerning first=321 second=217 amount=-1 +kerning first=354 second=65 amount=-1 +kerning first=319 second=211 amount=-1 +kerning first=102 second=8217 amount=1 +kerning first=321 second=334 amount=-1 +kerning first=1058 second=1097 amount=-1 +kerning first=271 second=314 amount=1 +kerning first=1043 second=1060 amount=-1 +kerning first=221 second=44 amount=-1 +kerning first=8230 second=8216 amount=-1 +kerning first=1168 second=1101 amount=-1 +kerning first=84 second=256 amount=-1 +kerning first=8221 second=260 amount=-1 +kerning first=354 second=347 amount=-1 +kerning first=373 second=8230 amount=-1 +kerning first=913 second=376 amount=-1 +kerning first=916 second=8217 amount=-1 +kerning first=197 second=372 amount=-1 +kerning first=259 second=356 amount=-1 +kerning first=89 second=8249 amount=-1 +kerning first=8220 second=8230 amount=-2 +kerning first=356 second=962 amount=-1 +kerning first=356 second=243 amount=-1 +kerning first=932 second=361 amount=-1 +kerning first=1027 second=1113 amount=-1 +kerning first=260 second=8220 amount=-1 +kerning first=321 second=216 amount=-1 +kerning first=356 second=372 amount=1 +kerning first=354 second=966 amount=-1 +kerning first=358 second=343 amount=-1 +kerning first=258 second=89 amount=-1 +kerning first=84 second=171 amount=-1 +kerning first=256 second=376 amount=-1 +kerning first=376 second=289 amount=-1 +kerning first=65 second=8221 amount=-1 +kerning first=356 second=103 amount=-1 +kerning first=354 second=238 amount=-1 +kerning first=910 second=940 amount=-1 +kerning first=8220 second=232 amount=-1 +kerning first=313 second=932 amount=-1 +kerning first=915 second=210 amount=-1 +kerning first=8211 second=356 amount=-1 +kerning first=243 second=932 amount=-1 +kerning first=89 second=334 amount=-1 +kerning first=34 second=198 amount=-1 +kerning first=221 second=213 amount=-1 +kerning first=932 second=973 amount=-1 +kerning first=354 second=99 amount=-1 +kerning first=317 second=927 amount=-1 +kerning first=932 second=251 amount=-1 +kerning first=358 second=965 amount=-1 +kerning first=936 second=196 amount=-1 +kerning first=1058 second=8211 amount=-1 +kerning first=8222 second=87 amount=-1 +kerning first=255 second=8230 amount=-1 +kerning first=929 second=195 amount=-1 +kerning first=358 second=237 amount=-1 +kerning first=923 second=933 amount=-1 +kerning first=1043 second=1094 amount=-1 +kerning first=194 second=356 amount=-1 +kerning first=329 second=354 amount=-1 +kerning first=376 second=211 amount=-1 +kerning first=8217 second=115 amount=-1 +kerning first=933 second=942 amount=-1 +kerning first=104 second=932 amount=-1 +kerning first=65 second=354 amount=-1 +kerning first=356 second=256 amount=-1 +kerning first=317 second=286 amount=-1 +kerning first=932 second=110 amount=-1 +kerning first=913 second=358 amount=-1 +kerning first=258 second=34 amount=-1 +kerning first=1107 second=8230 amount=-1 +kerning first=89 second=216 amount=-1 +kerning first=39 second=46 amount=-2 +kerning first=376 second=74 amount=-1 +kerning first=87 second=125 amount=1 +kerning first=950 second=93 amount=1 +kerning first=8250 second=376 amount=-1 +kerning first=8217 second=196 amount=-1 +kerning first=354 second=44 amount=-1 +kerning first=910 second=260 amount=-1 +kerning first=1034 second=8221 amount=-1 +kerning first=256 second=358 amount=-1 +kerning first=915 second=971 amount=-1 +kerning first=356 second=171 amount=-1 +kerning first=317 second=8221 amount=-1 +kerning first=321 second=284 amount=-1 +kerning first=376 second=371 amount=-1 +kerning first=1058 second=1076 amount=-1 +kerning first=929 second=8230 amount=-2 +kerning first=319 second=264 amount=-1 +kerning first=192 second=86 amount=-1 +kerning first=955 second=8217 amount=-1 +kerning first=44 second=8221 amount=-2 +kerning first=1168 second=1080 amount=-1 +kerning first=915 second=173 amount=-1 +kerning first=354 second=299 amount=-1 +kerning first=194 second=8217 amount=-1 +kerning first=89 second=269 amount=-1 +kerning first=1118 second=44 amount=-1 +kerning first=34 second=194 amount=-1 +kerning first=221 second=249 amount=-1 +kerning first=195 second=939 amount=-1 +kerning first=939 second=45 amount=-1 +kerning first=89 second=117 amount=-1 +kerning first=1059 second=1072 amount=-1 +kerning first=313 second=370 amount=-1 +kerning first=221 second=259 amount=-1 +kerning first=253 second=46 amount=-1 +kerning first=8217 second=333 amount=-1 +kerning first=1043 second=8250 amount=-1 +kerning first=1169 second=1076 amount=-1 +kerning first=932 second=328 amount=-1 +kerning first=376 second=353 amount=-1 +kerning first=1027 second=1091 amount=-1 +kerning first=84 second=263 amount=-1 +kerning first=319 second=8211 amount=-1 +kerning first=261 second=932 amount=-1 +kerning first=317 second=354 amount=-1 +kerning first=8221 second=269 amount=-1 +kerning first=358 second=301 amount=-1 +kerning first=244 second=354 amount=-1 +kerning first=89 second=197 amount=-1 +kerning first=910 second=948 amount=-1 +kerning first=221 second=923 amount=-1 +kerning first=114 second=46 amount=-1 +kerning first=1113 second=8217 amount=-1 +kerning first=89 second=284 amount=-1 +kerning first=8250 second=358 amount=-1 +kerning first=123 second=86 amount=1 +kerning first=8217 second=233 amount=-1 +kerning first=932 second=228 amount=-1 +kerning first=84 second=192 amount=-1 +kerning first=8217 second=356 amount=1 +kerning first=8221 second=197 amount=-1 +kerning first=321 second=364 amount=-1 +kerning first=1058 second=1111 amount=-1 +kerning first=39 second=198 amount=-1 +kerning first=902 second=86 amount=-1 +kerning first=1027 second=1035 amount=1 +kerning first=196 second=936 amount=-1 +kerning first=321 second=8216 amount=-2 +kerning first=319 second=87 amount=-1 +kerning first=354 second=373 amount=-1 +kerning first=376 second=264 amount=-1 +kerning first=293 second=356 amount=-1 +kerning first=192 second=932 amount=-1 +kerning first=1038 second=1072 amount=-1 +kerning first=328 second=84 amount=-1 +kerning first=8221 second=341 amount=-1 +kerning first=356 second=263 amount=-1 +kerning first=932 second=248 amount=-1 +kerning first=354 second=974 amount=-1 +kerning first=939 second=8212 amount=-1 +kerning first=354 second=249 amount=-1 +kerning first=89 second=235 amount=-1 +kerning first=376 second=8211 amount=-1 +kerning first=8217 second=8217 amount=-1 +kerning first=331 second=932 amount=-1 +kerning first=160 second=902 amount=-1 +kerning first=1168 second=1059 amount=1 +kerning first=313 second=213 amount=-1 +kerning first=354 second=259 amount=-1 +kerning first=333 second=358 amount=-1 +kerning first=221 second=229 amount=-1 +kerning first=354 second=112 amount=-1 +kerning first=87 second=260 amount=-1 +kerning first=84 second=961 amount=-1 +kerning first=358 second=971 amount=-1 +kerning first=84 second=234 amount=-1 +kerning first=8217 second=291 amount=-1 +kerning first=356 second=192 amount=-1 +kerning first=8221 second=235 amount=-1 +kerning first=260 second=356 amount=-1 +kerning first=317 second=211 amount=-1 +kerning first=39 second=194 amount=-1 +kerning first=358 second=252 amount=-1 +kerning first=1043 second=1108 amount=-1 +kerning first=932 second=279 amount=-1 +kerning first=376 second=225 amount=-1 +kerning first=358 second=173 amount=-1 +kerning first=123 second=932 amount=1 +kerning first=84 second=354 amount=1 +kerning first=354 second=923 amount=-1 +kerning first=229 second=84 amount=-1 +kerning first=1034 second=1063 amount=-1 +kerning first=358 second=111 amount=-1 +kerning first=197 second=8221 amount=-1 +kerning first=76 second=262 amount=-1 +kerning first=196 second=372 amount=-1 +kerning first=902 second=932 amount=-1 +kerning first=910 second=197 amount=-1 +kerning first=8216 second=248 amount=-1 +kerning first=321 second=212 amount=-1 +kerning first=89 second=41 amount=1 +kerning first=46 second=933 amount=-1 +kerning first=1068 second=1035 amount=-1 +kerning first=258 second=8220 amount=-1 +kerning first=939 second=193 amount=-1 +kerning first=947 second=8230 amount=-1 +kerning first=1058 second=1089 amount=-1 +kerning first=260 second=8217 amount=-1 +kerning first=1168 second=1093 amount=-1 +kerning first=354 second=326 amount=-1 +kerning first=1046 second=1095 amount=-1 +kerning first=197 second=354 amount=-1 +kerning first=939 second=58 amount=-1 +kerning first=969 second=39 amount=-1 +kerning first=74 second=93 amount=1 +kerning first=372 second=46 amount=-1 +kerning first=356 second=961 amount=-1 +kerning first=8216 second=279 amount=-1 +kerning first=34 second=308 amount=-1 +kerning first=221 second=281 amount=-1 +kerning first=356 second=234 amount=-1 +kerning first=1043 second=8230 amount=-1 +kerning first=97 second=358 amount=-1 +kerning first=221 second=125 amount=1 +kerning first=376 second=273 amount=-1 +kerning first=1027 second=1105 amount=-1 +kerning first=8216 second=1113 amount=-1 +kerning first=84 second=289 amount=-1 +kerning first=356 second=354 amount=1 +kerning first=76 second=376 amount=-1 +kerning first=295 second=354 amount=-1 +kerning first=957 second=44 amount=-1 +kerning first=1058 second=45 amount=-1 +kerning first=376 second=277 amount=-1 +kerning first=354 second=229 amount=-1 +kerning first=89 second=212 amount=-1 +kerning first=8212 second=933 amount=-1 +kerning first=70 second=226 amount=-1 +kerning first=910 second=963 amount=-1 +kerning first=76 second=332 amount=-1 +kerning first=1168 second=1038 amount=1 +kerning first=76 second=85 amount=-1 +kerning first=932 second=969 amount=-1 +kerning first=8217 second=245 amount=-1 +kerning first=916 second=932 amount=-1 +kerning first=932 second=241 amount=-1 +kerning first=306 second=41 amount=1 +kerning first=358 second=224 amount=-1 +kerning first=319 second=366 amount=-1 +kerning first=1043 second=1086 amount=-1 +kerning first=1168 second=8249 amount=-1 +kerning first=1056 second=1076 amount=-1 +kerning first=317 second=264 amount=-1 +kerning first=89 second=367 amount=-1 +kerning first=194 second=86 amount=-1 +kerning first=84 second=74 amount=-1 +kerning first=65 second=87 amount=-1 +kerning first=40 second=372 amount=1 +kerning first=8220 second=248 amount=-1 +kerning first=192 second=939 amount=-1 +kerning first=321 second=920 amount=-1 +kerning first=931 second=262 amount=-1 +kerning first=932 second=913 amount=-1 +kerning first=84 second=371 amount=-1 +kerning first=356 second=289 amount=-1 +kerning first=76 second=358 amount=-1 +kerning first=376 second=351 amount=-1 +kerning first=915 second=962 amount=-1 +kerning first=321 second=266 amount=-1 +kerning first=259 second=932 amount=-1 +kerning first=317 second=8211 amount=-1 +kerning first=358 second=339 amount=-1 +kerning first=89 second=250 amount=-1 +kerning first=372 second=198 amount=-1 +kerning first=932 second=258 amount=-1 +kerning first=241 second=354 amount=-1 +kerning first=8216 second=969 amount=-1 +kerning first=1168 second=1072 amount=-1 +kerning first=87 second=197 amount=-1 +kerning first=319 second=45 amount=-1 +kerning first=1036 second=1033 amount=1 +kerning first=354 second=281 amount=-1 +kerning first=8220 second=279 amount=-1 +kerning first=160 second=221 amount=-1 +kerning first=221 second=244 amount=-1 +kerning first=354 second=125 amount=1 +kerning first=315 second=8249 amount=-1 +kerning first=8204 second=8218 amount=-2 +kerning first=932 second=307 amount=-1 +kerning first=8220 second=1113 amount=-1 +kerning first=1058 second=8212 amount=-1 +kerning first=84 second=353 amount=-1 +kerning first=358 second=312 amount=-1 +kerning first=160 second=84 amount=-1 +kerning first=376 second=239 amount=1 +kerning first=1027 second=1083 amount=-1 +kerning first=8211 second=932 amount=-1 +kerning first=89 second=920 amount=-1 +kerning first=39 second=308 amount=-1 +kerning first=76 second=199 amount=-1 +kerning first=358 second=275 amount=-1 +kerning first=193 second=936 amount=-1 +kerning first=8221 second=109 amount=-1 +kerning first=356 second=74 amount=-1 +kerning first=317 second=87 amount=-1 +kerning first=315 second=217 amount=-1 +kerning first=376 second=100 amount=-1 +kerning first=76 second=288 amount=-1 +kerning first=8216 second=913 amount=-1 +kerning first=902 second=939 amount=-1 +kerning first=89 second=266 amount=-1 +kerning first=315 second=334 amount=-1 +kerning first=931 second=332 amount=-1 +kerning first=98 second=356 amount=-1 +kerning first=194 second=932 amount=-1 +kerning first=915 second=256 amount=-2 +kerning first=86 second=239 amount=1 +kerning first=356 second=371 amount=-1 +kerning first=65 second=933 amount=-1 +kerning first=8216 second=258 amount=-1 +kerning first=221 second=260 amount=-1 +kerning first=111 second=84 amount=-1 +kerning first=1058 second=1102 amount=-1 +kerning first=372 second=194 amount=-1 +kerning first=8216 second=1035 amount=1 +kerning first=1168 second=1107 amount=-1 +kerning first=319 second=79 amount=-1 +kerning first=315 second=216 amount=-1 +kerning first=335 second=358 amount=-1 +kerning first=376 second=45 amount=-1 +kerning first=356 second=353 amount=-1 +kerning first=8216 second=8220 amount=-1 +kerning first=221 second=8249 amount=-1 +kerning first=1027 second=1119 amount=-1 +kerning first=258 second=356 amount=-1 +kerning first=257 second=354 amount=-1 +kerning first=319 second=8212 amount=-1 +kerning first=8221 second=324 amount=-1 +kerning first=354 second=940 amount=-1 +kerning first=8220 second=969 amount=-1 +kerning first=1058 second=58 amount=-1 +kerning first=84 second=8211 amount=-1 +kerning first=915 second=947 amount=-1 +kerning first=354 second=244 amount=-1 +kerning first=89 second=226 amount=-1 +kerning first=910 second=972 amount=-1 +kerning first=76 second=362 amount=-1 +kerning first=228 second=84 amount=-1 +kerning first=80 second=256 amount=-1 +kerning first=310 second=74 amount=1 +kerning first=196 second=8221 amount=-1 +kerning first=193 second=372 amount=-1 +kerning first=1026 second=1066 amount=-1 +kerning first=916 second=939 amount=-1 +kerning first=939 second=941 amount=-1 +kerning first=932 second=382 amount=-1 +kerning first=358 second=962 amount=-1 +kerning first=221 second=334 amount=-1 +kerning first=84 second=225 amount=-1 +kerning first=87 second=41 amount=1 +kerning first=8217 second=271 amount=-1 +kerning first=1033 second=1059 amount=-1 +kerning first=358 second=243 amount=-1 +kerning first=44 second=933 amount=-1 +kerning first=1043 second=1099 amount=-1 +kerning first=1168 second=187 amount=-1 +kerning first=1066 second=1035 amount=-1 +kerning first=260 second=86 amount=-1 +kerning first=1075 second=1076 amount=-1 +kerning first=8230 second=39 amount=-1 +kerning first=271 second=322 amount=1 +kerning first=932 second=115 amount=-1 +kerning first=358 second=372 amount=1 +kerning first=936 second=65 amount=-1 +kerning first=8220 second=913 amount=-1 +kerning first=258 second=8217 amount=-1 +kerning first=84 second=87 amount=1 +kerning first=933 second=173 amount=-1 +kerning first=187 second=221 amount=-1 +kerning first=358 second=103 amount=-1 +kerning first=372 second=93 amount=1 +kerning first=931 second=199 amount=-1 +kerning first=376 second=79 amount=-1 +kerning first=196 second=354 amount=-1 +kerning first=8217 second=932 amount=1 +kerning first=354 second=260 amount=-1 +kerning first=1114 second=8221 amount=-1 +kerning first=315 second=284 amount=-1 +kerning first=8220 second=258 amount=-1 +kerning first=931 second=288 amount=-1 +kerning first=221 second=216 amount=-1 +kerning first=187 second=84 amount=-1 +kerning first=70 second=46 amount=-1 +kerning first=1068 second=8217 amount=-1 +kerning first=939 second=916 amount=-1 +kerning first=932 second=196 amount=-1 +kerning first=8220 second=1035 amount=1 +kerning first=84 second=305 amount=-1 +kerning first=356 second=8211 amount=-1 +kerning first=293 second=932 amount=-1 +kerning first=1058 second=1081 amount=-1 +kerning first=1043 second=1044 amount=-1 +kerning first=376 second=8212 amount=-1 +kerning first=8217 second=65 amount=-1 +kerning first=321 second=67 amount=-1 +kerning first=913 second=936 amount=-1 +kerning first=1168 second=1085 amount=-1 +kerning first=89 second=283 amount=-1 +kerning first=358 second=256 amount=-1 +kerning first=354 second=8249 amount=-1 +kerning first=1059 second=1077 amount=-1 +kerning first=8220 second=8220 amount=-1 +kerning first=197 second=87 amount=-1 +kerning first=221 second=269 amount=-1 +kerning first=84 second=273 amount=-1 +kerning first=8221 second=331 amount=-1 +kerning first=356 second=225 amount=-1 +kerning first=8217 second=347 amount=-1 +kerning first=221 second=117 amount=-1 +kerning first=932 second=333 amount=-1 +kerning first=1027 second=1096 amount=-1 +kerning first=8211 second=939 amount=-1 +kerning first=84 second=277 amount=-1 +kerning first=8221 second=283 amount=-1 +kerning first=256 second=936 amount=-1 +kerning first=317 second=366 amount=-1 +kerning first=354 second=948 amount=-1 +kerning first=76 second=210 amount=-1 +kerning first=84 second=121 amount=-1 +kerning first=376 second=257 amount=-1 +kerning first=356 second=87 amount=1 +kerning first=915 second=927 amount=-1 +kerning first=358 second=171 amount=-1 +kerning first=376 second=113 amount=-1 +kerning first=915 second=192 amount=-2 +kerning first=337 second=356 amount=-1 +kerning first=260 second=932 amount=-1 +kerning first=315 second=364 amount=-1 +kerning first=8216 second=196 amount=-1 +kerning first=345 second=44 amount=-1 +kerning first=221 second=197 amount=-1 +kerning first=171 second=910 amount=-1 +kerning first=194 second=939 amount=-1 +kerning first=932 second=959 amount=-1 +kerning first=8217 second=238 amount=-1 +kerning first=915 second=286 amount=-1 +kerning first=89 second=67 amount=-1 +kerning first=315 second=8216 amount=-2 +kerning first=939 second=949 amount=-1 +kerning first=932 second=233 amount=-1 +kerning first=121 second=44 amount=-1 +kerning first=929 second=913 amount=-1 +kerning first=221 second=284 amount=-1 +kerning first=356 second=305 amount=-1 +kerning first=1033 second=1038 amount=-1 +kerning first=321 second=360 amount=-1 +kerning first=1058 second=1116 amount=-1 +kerning first=1043 second=1078 amount=-1 +kerning first=932 second=356 amount=1 +kerning first=376 second=193 amount=-1 +kerning first=8217 second=99 amount=-1 +kerning first=1168 second=1169 amount=-1 +kerning first=89 second=349 amount=-1 +kerning first=248 second=356 amount=-1 +kerning first=929 second=258 amount=-1 +kerning first=936 second=44 amount=-1 +kerning first=317 second=45 amount=-1 +kerning first=40 second=354 amount=1 +kerning first=70 second=198 amount=-1 +kerning first=8216 second=333 amount=-1 +kerning first=913 second=372 amount=-1 +kerning first=313 second=8249 amount=-1 +kerning first=356 second=273 amount=-1 +kerning first=1038 second=1077 amount=-1 +kerning first=86 second=193 amount=-1 +kerning first=84 second=351 amount=-1 +kerning first=8221 second=349 amount=-1 +kerning first=356 second=277 amount=-1 +kerning first=80 second=192 amount=-1 +kerning first=197 second=933 amount=-1 +kerning first=376 second=335 amount=-1 +kerning first=356 second=121 amount=-1 +kerning first=76 second=173 amount=-1 +kerning first=915 second=961 amount=-1 +kerning first=1058 second=1060 amount=-1 +kerning first=8217 second=44 amount=-2 +kerning first=8216 second=959 amount=-1 +kerning first=256 second=372 amount=-1 +kerning first=313 second=217 amount=-1 +kerning first=354 second=269 amount=-1 +kerning first=70 second=261 amount=-1 +kerning first=8216 second=233 amount=-1 +kerning first=221 second=235 amount=-1 +kerning first=354 second=117 amount=-1 +kerning first=89 second=101 amount=-1 +kerning first=1091 second=44 amount=-1 +kerning first=313 second=334 amount=-1 +kerning first=8216 second=356 amount=1 +kerning first=84 second=239 amount=-1 +kerning first=8217 second=299 amount=-1 +kerning first=8221 second=236 amount=-1 +kerning first=1043 second=1113 amount=-1 +kerning first=932 second=291 amount=-1 +kerning first=376 second=227 amount=-1 +kerning first=1027 second=1075 amount=-1 +kerning first=8216 second=1083 amount=-1 +kerning first=321 second=39 amount=-1 +kerning first=109 second=84 amount=-1 +kerning first=923 second=221 amount=-1 +kerning first=358 second=263 amount=-1 +kerning first=84 second=100 amount=-1 +kerning first=8221 second=101 amount=-1 +kerning first=317 second=79 amount=-1 +kerning first=354 second=197 amount=-1 +kerning first=315 second=212 amount=-1 +kerning first=70 second=194 amount=-1 +kerning first=8220 second=196 amount=-1 +kerning first=931 second=210 amount=-1 +kerning first=8204 second=376 amount=-1 +kerning first=923 second=84 amount=-1 +kerning first=313 second=216 amount=-1 +kerning first=308 second=125 amount=1 +kerning first=321 second=218 amount=-1 +kerning first=89 second=46 amount=-1 +kerning first=356 second=351 amount=-1 +kerning first=939 second=195 amount=-1 +kerning first=317 second=8212 amount=-1 +kerning first=1058 second=1094 amount=-1 +kerning first=358 second=192 amount=-1 +kerning first=221 second=41 amount=1 +kerning first=1168 second=1098 amount=-1 +kerning first=319 second=71 amount=-1 +kerning first=354 second=341 amount=-1 +kerning first=8220 second=333 amount=-1 +kerning first=225 second=84 amount=-1 +kerning first=84 second=45 amount=-1 +kerning first=8221 second=46 amount=-2 +kerning first=354 second=187 amount=-1 +kerning first=193 second=8221 amount=-1 +kerning first=102 second=125 amount=1 +kerning first=8216 second=291 amount=-1 +kerning first=356 second=239 amount=-1 +kerning first=932 second=363 amount=-1 +kerning first=84 second=303 amount=-1 +kerning first=8221 second=297 amount=-1 +kerning first=354 second=963 amount=-1 +kerning first=195 second=8216 amount=-1 +kerning first=8220 second=959 amount=-1 +kerning first=258 second=86 amount=-1 +kerning first=376 second=287 amount=-1 +kerning first=356 second=100 amount=-1 +kerning first=939 second=8230 amount=-1 +kerning first=227 second=358 amount=-1 +kerning first=354 second=235 amount=-1 +kerning first=8220 second=233 amount=-1 +kerning first=8204 second=358 amount=-1 +kerning first=915 second=211 amount=-1 +kerning first=8222 second=221 amount=-1 +kerning first=260 second=939 amount=-1 +kerning first=193 second=354 amount=-1 +kerning first=221 second=212 amount=-1 +kerning first=8220 second=356 amount=1 +kerning first=1026 second=1058 amount=-1 +kerning first=1059 second=46 amount=-1 +kerning first=936 second=923 amount=-1 +kerning first=965 second=39 amount=-1 +kerning first=313 second=284 amount=-1 +kerning first=8217 second=160 amount=-1 +kerning first=932 second=245 amount=-1 +kerning first=358 second=961 amount=-1 +kerning first=1058 second=8250 amount=-1 +kerning first=8220 second=1083 amount=-1 +kerning first=8222 second=84 amount=-1 +kerning first=1066 second=8217 amount=-1 +kerning first=358 second=234 amount=-1 +kerning first=929 second=196 amount=-1 +kerning first=1043 second=1091 amount=-1 +kerning first=8217 second=112 amount=-1 +kerning first=933 second=962 amount=-1 +kerning first=315 second=920 amount=-1 +kerning first=358 second=354 amount=1 +kerning first=98 second=932 amount=-1 +kerning first=356 second=45 amount=-1 +kerning first=968 second=34 amount=-1 +kerning first=89 second=198 amount=-1 +kerning first=376 second=71 amount=-1 +kerning first=221 second=367 amount=-1 +kerning first=8217 second=923 amount=-1 +kerning first=315 second=266 amount=-1 +kerning first=196 second=87 amount=-1 +kerning first=354 second=41 amount=1 +kerning first=356 second=303 amount=-1 +kerning first=84 second=8212 amount=-1 +kerning first=376 second=365 amount=-1 +kerning first=915 second=970 amount=-1 +kerning first=8221 second=198 amount=-1 +kerning first=910 second=46 amount=-1 +kerning first=1043 second=1035 amount=1 +kerning first=1168 second=1077 amount=-1 +kerning first=89 second=261 amount=-1 +kerning first=8216 second=245 amount=-1 +kerning first=8220 second=291 amount=-1 +kerning first=80 second=74 amount=-1 +kerning first=326 second=356 amount=-1 +kerning first=221 second=250 amount=-1 +kerning first=258 second=932 amount=-1 +kerning first=313 second=364 amount=-1 +kerning first=933 second=256 amount=-1 +kerning first=1038 second=46 amount=-1 +kerning first=84 second=253 amount=-1 +kerning first=313 second=8216 amount=-2 +kerning first=8217 second=326 amount=-1 +kerning first=119 second=44 amount=-1 +kerning first=160 second=89 amount=-1 +kerning first=376 second=246 amount=-1 +kerning first=1027 second=1088 amount=-1 +kerning first=84 second=257 amount=-1 +kerning first=358 second=289 amount=-1 +kerning first=84 second=113 amount=-1 +kerning first=8221 second=114 amount=-1 +kerning first=89 second=194 amount=-1 +kerning first=910 second=945 amount=-1 +kerning first=934 second=44 amount=-1 +kerning first=221 second=920 amount=-1 +kerning first=91 second=106 amount=1 +kerning first=70 second=308 amount=-1 +kerning first=913 second=8221 amount=-1 +kerning first=91 second=1095 amount=-1 +kerning first=915 second=264 amount=-1 +kerning first=173 second=1026 amount=-1 +kerning first=319 second=221 amount=-1 +kerning first=1040 second=1026 amount=-1 +kerning first=221 second=266 amount=-1 +kerning first=84 second=193 amount=-1 +kerning first=8221 second=194 amount=-1 +kerning first=356 second=8212 amount=-1 +kerning first=1058 second=1108 amount=-1 +kerning first=1027 second=44 amount=-1 +kerning first=319 second=336 amount=-1 +kerning first=1027 second=1032 amount=-1 +kerning first=196 second=933 amount=-1 +kerning first=319 second=84 amount=-1 +kerning first=932 second=86 amount=1 +kerning first=354 second=367 amount=-1 +kerning first=89 second=337 amount=-1 +kerning first=242 second=84 amount=-1 +kerning first=256 second=8221 amount=-1 +kerning first=358 second=74 amount=-1 +kerning first=1059 second=1103 amount=-1 +kerning first=915 second=8211 amount=-1 +kerning first=40 second=87 amount=1 +kerning first=913 second=354 amount=-1 +kerning first=934 second=939 amount=-1 +kerning first=910 second=198 amount=-1 +kerning first=356 second=253 amount=-1 +kerning first=84 second=335 amount=-1 +kerning first=319 second=338 amount=-1 +kerning first=356 second=257 amount=-1 +kerning first=8221 second=337 amount=-1 +kerning first=932 second=230 amount=-1 +kerning first=354 second=972 amount=-1 +kerning first=358 second=371 amount=-1 +kerning first=356 second=113 amount=-1 +kerning first=354 second=250 amount=-1 +kerning first=89 second=231 amount=-1 +kerning first=8220 second=245 amount=-1 +kerning first=76 second=372 amount=-1 +kerning first=8212 second=221 amount=-1 +kerning first=256 second=354 amount=-1 +kerning first=313 second=212 amount=-1 +kerning first=1061 second=1095 amount=-1 +kerning first=221 second=226 amount=-1 +kerning first=1059 second=59 amount=-1 +kerning first=354 second=109 amount=-1 +kerning first=89 second=93 amount=1 +kerning first=324 second=358 amount=-1 +kerning first=8212 second=84 amount=-1 +kerning first=1058 second=8230 amount=-1 +kerning first=84 second=227 amount=-1 +kerning first=87 second=46 amount=-1 +kerning first=356 second=193 amount=-1 +kerning first=904 second=912 amount=1 +kerning first=8217 second=281 amount=-1 +kerning first=8221 second=231 amount=-1 +kerning first=112 second=358 amount=-1 +kerning first=358 second=353 amount=-1 +kerning first=1043 second=1105 amount=-1 +kerning first=932 second=271 amount=-1 +kerning first=337 second=932 amount=-1 +kerning first=91 second=376 amount=1 +kerning first=376 second=336 amount=-1 +kerning first=317 second=71 amount=-1 +kerning first=1169 second=8230 amount=-1 +kerning first=910 second=194 amount=-1 +kerning first=1038 second=1103 amount=-1 +kerning first=932 second=932 amount=1 +kerning first=187 second=89 amount=-1 +kerning first=315 second=67 amount=-1 +kerning first=356 second=335 amount=-1 +kerning first=248 second=932 amount=-1 +kerning first=8250 second=354 amount=-1 +kerning first=935 second=970 amount=1 +kerning first=910 second=59 amount=-1 +kerning first=1058 second=1086 amount=-1 +kerning first=319 second=290 amount=-1 +kerning first=192 second=8216 amount=-1 +kerning first=376 second=338 amount=-1 +kerning first=224 second=358 amount=-1 +kerning first=1168 second=1090 amount=-1 +kerning first=354 second=324 amount=-1 +kerning first=932 second=65 amount=-1 +kerning first=89 second=285 amount=-1 +kerning first=76 second=171 amount=-1 +kerning first=933 second=192 amount=-1 +kerning first=258 second=939 amount=-1 +kerning first=1040 second=1095 amount=-1 +kerning first=306 second=93 amount=1 +kerning first=8216 second=271 amount=-1 +kerning first=1038 second=59 amount=-1 +kerning first=221 second=283 amount=-1 +kerning first=356 second=227 amount=-1 +kerning first=932 second=347 amount=-1 +kerning first=1027 second=1101 amount=-1 +kerning first=917 second=912 amount=1 +kerning first=84 second=287 amount=-1 +kerning first=8221 second=285 amount=-1 +kerning first=91 second=358 amount=1 +kerning first=76 second=220 amount=-1 +kerning first=372 second=301 amount=1 +kerning first=376 second=265 amount=-1 +kerning first=354 second=226 amount=-1 +kerning first=358 second=8211 amount=-1 +kerning first=313 second=920 amount=-1 +kerning first=1168 second=46 amount=-1 +kerning first=8216 second=932 amount=1 +kerning first=87 second=198 amount=-1 +kerning first=89 second=308 amount=-1 +kerning first=315 second=360 amount=-1 +kerning first=932 second=966 amount=-1 +kerning first=8217 second=244 amount=-1 +kerning first=1059 second=1026 amount=1 +kerning first=313 second=266 amount=-1 +kerning first=193 second=87 amount=-1 +kerning first=939 second=954 amount=-1 +kerning first=932 second=238 amount=-1 +kerning first=333 second=354 amount=-1 +kerning first=65 second=221 amount=-1 +kerning first=358 second=225 amount=-1 +kerning first=8216 second=65 amount=-1 +kerning first=319 second=368 amount=-1 +kerning first=221 second=67 amount=-1 +kerning first=902 second=8216 amount=-1 +kerning first=376 second=195 amount=-1 +kerning first=8249 second=939 amount=-1 +kerning first=936 second=260 amount=-1 +kerning first=933 second=961 amount=-1 +kerning first=1043 second=1083 amount=-1 +kerning first=8221 second=308 amount=-1 +kerning first=932 second=99 amount=-1 +kerning first=89 second=369 amount=-1 +kerning first=1041 second=1035 amount=-1 +kerning first=329 second=84 amount=-1 +kerning first=376 second=290 amount=-1 +kerning first=65 second=84 amount=-1 +kerning first=358 second=87 amount=1 +kerning first=328 second=356 amount=-1 +kerning first=221 second=349 amount=-1 +kerning first=160 second=8220 amount=-1 +kerning first=86 second=195 amount=-1 +kerning first=84 second=365 amount=-1 +kerning first=356 second=287 amount=-1 +kerning first=173 second=376 amount=-1 +kerning first=8217 second=260 amount=-1 +kerning first=321 second=262 amount=-1 +kerning first=354 second=331 amount=-1 +kerning first=358 second=305 amount=-1 +kerning first=89 second=242 amount=-1 +kerning first=376 second=8230 amount=-1 +kerning first=8216 second=966 amount=-1 +kerning first=87 second=194 amount=-1 +kerning first=354 second=283 amount=-1 +kerning first=932 second=44 amount=-1 +kerning first=8220 second=271 amount=-1 +kerning first=354 second=122 amount=-1 +kerning first=315 second=39 amount=-1 +kerning first=84 second=941 amount=-1 +kerning first=102 second=8216 amount=1 +kerning first=34 second=256 amount=-1 +kerning first=84 second=246 amount=-1 +kerning first=8221 second=242 amount=-1 +kerning first=317 second=221 amount=-1 +kerning first=1038 second=1026 amount=1 +kerning first=358 second=273 amount=-1 +kerning first=8216 second=99 amount=-1 +kerning first=1043 second=1119 amount=-1 +kerning first=221 second=101 amount=-1 +kerning first=932 second=299 amount=-1 +kerning first=376 second=232 amount=-1 +kerning first=1027 second=1080 amount=-1 +kerning first=76 second=927 amount=-1 +kerning first=308 second=41 amount=1 +kerning first=86 second=8230 amount=-1 +kerning first=229 second=356 amount=-1 +kerning first=317 second=336 amount=-1 +kerning first=354 second=934 amount=-1 +kerning first=358 second=277 amount=-1 +kerning first=8220 second=932 amount=1 +kerning first=97 second=354 amount=-1 +kerning first=193 second=933 amount=-1 +kerning first=84 second=105 amount=-1 +kerning first=317 second=84 amount=-1 +kerning first=315 second=218 amount=-1 +kerning first=358 second=121 amount=-1 +kerning first=244 second=84 amount=-1 +kerning first=376 second=97 amount=-1 +kerning first=76 second=286 amount=-1 +kerning first=1111 second=1115 amount=1 +kerning first=923 second=89 amount=-1 +kerning first=89 second=262 amount=-1 +kerning first=321 second=376 amount=-1 +kerning first=8220 second=65 amount=-1 +kerning first=319 second=214 amount=-1 +kerning first=356 second=365 amount=-1 +kerning first=84 second=916 amount=-1 +kerning first=173 second=358 amount=-1 +kerning first=915 second=45 amount=-1 +kerning first=102 second=41 amount=1 +kerning first=317 second=338 amount=-1 +kerning first=321 second=332 amount=-1 +kerning first=1058 second=1099 amount=-1 +kerning first=8216 second=44 amount=-2 +kerning first=271 second=316 amount=1 +kerning first=221 second=46 amount=-1 +kerning first=1090 second=1076 amount=-1 +kerning first=8216 second=1032 amount=-1 +kerning first=321 second=85 amount=-1 +kerning first=1168 second=1103 amount=-1 +kerning first=354 second=349 amount=-1 +kerning first=76 second=8221 amount=-1 +kerning first=356 second=941 amount=-1 +kerning first=923 second=34 amount=-1 +kerning first=87 second=93 amount=1 +kerning first=356 second=246 amount=-1 +kerning first=913 second=87 amount=-1 +kerning first=1056 second=8230 amount=-2 +kerning first=932 second=373 amount=-1 +kerning first=110 second=358 amount=-1 +kerning first=354 second=968 amount=-1 +kerning first=358 second=351 amount=-1 +kerning first=8220 second=966 amount=-1 +kerning first=326 second=932 amount=-1 +kerning first=84 second=8250 amount=-1 +kerning first=356 second=105 amount=-1 +kerning first=354 second=236 amount=-1 +kerning first=1058 second=1044 amount=-1 +kerning first=910 second=942 amount=-1 +kerning first=1168 second=59 amount=-1 +kerning first=76 second=354 amount=-1 +kerning first=89 second=332 amount=-1 +kerning first=932 second=974 amount=-1 +kerning first=256 second=87 amount=-1 +kerning first=1026 second=1063 amount=-1 +kerning first=321 second=358 amount=-1 +kerning first=354 second=101 amount=-1 +kerning first=8220 second=99 amount=-1 +kerning first=356 second=916 amount=-1 +kerning first=84 second=949 amount=-1 +kerning first=1059 second=1040 amount=-1 +kerning first=932 second=249 amount=-1 +kerning first=915 second=79 amount=-1 +kerning first=936 second=197 amount=-1 +kerning first=8222 second=89 amount=-1 +kerning first=313 second=67 amount=-1 +kerning first=8217 second=269 amount=-1 +kerning first=922 second=308 amount=1 +kerning first=358 second=239 amount=-1 +kerning first=1043 second=1096 amount=-1 +kerning first=932 second=259 amount=-1 +kerning first=376 second=214 amount=-1 +kerning first=1027 second=1059 amount=1 +kerning first=933 second=970 amount=1 +kerning first=317 second=290 amount=-1 +kerning first=194 second=8216 amount=-1 +kerning first=932 second=112 amount=-1 +kerning first=39 second=256 amount=-1 +kerning first=931 second=927 amount=-1 +kerning first=84 second=84 amount=1 +kerning first=226 second=358 amount=-1 +kerning first=358 second=100 amount=-1 +kerning first=929 second=65 amount=-1 +kerning first=915 second=8212 amount=-1 +kerning first=373 second=44 amount=-1 +kerning first=160 second=8222 amount=-2 +kerning first=931 second=286 amount=-1 +kerning first=221 second=198 amount=-1 +kerning first=932 second=923 amount=-1 +kerning first=8217 second=197 amount=-1 +kerning first=321 second=199 amount=-1 +kerning first=354 second=46 amount=-1 +kerning first=84 second=378 amount=-1 +kerning first=8220 second=44 amount=-2 +kerning first=939 second=913 amount=-1 +kerning first=195 second=39 amount=-1 +kerning first=8220 second=1032 amount=-1 +kerning first=915 second=912 amount=-1 +kerning first=356 second=8250 amount=-1 +kerning first=376 second=361 amount=-1 +kerning first=321 second=288 amount=-1 +kerning first=1058 second=1078 amount=-1 +kerning first=197 second=221 amount=-1 +kerning first=8216 second=974 amount=-1 +kerning first=913 second=933 amount=-1 +kerning first=1168 second=1082 amount=-1 +kerning first=939 second=258 amount=-1 +kerning first=354 second=297 amount=-1 +kerning first=89 second=267 amount=-1 +kerning first=1118 second=46 amount=-1 +kerning first=34 second=192 amount=-1 +kerning first=1050 second=1033 amount=1 +kerning first=358 second=45 amount=-1 +kerning first=313 second=360 amount=-1 +kerning first=356 second=949 amount=-1 +kerning first=197 second=84 amount=-1 +kerning first=160 second=356 amount=-1 +kerning first=221 second=261 amount=-1 +kerning first=8217 second=341 amount=-1 +kerning first=8221 second=358 amount=1 +kerning first=1057 second=1026 amount=1 +kerning first=1100 second=1091 amount=-1 +kerning first=1038 second=1040 amount=-1 +kerning first=932 second=326 amount=-1 +kerning first=335 second=354 amount=-1 +kerning first=376 second=251 amount=-1 +kerning first=1027 second=1093 amount=-1 +kerning first=84 second=265 amount=-1 +kerning first=256 second=933 amount=-1 +kerning first=8221 second=267 amount=-1 +kerning first=317 second=368 amount=-1 +kerning first=354 second=945 amount=-1 +kerning first=358 second=303 amount=-1 +kerning first=76 second=211 amount=-1 +kerning first=84 second=118 amount=-1 +kerning first=255 second=44 amount=-1 +kerning first=356 second=84 amount=1 +kerning first=89 second=199 amount=-1 +kerning first=295 second=84 amount=-1 +kerning first=915 second=193 amount=-2 +kerning first=8216 second=923 amount=-1 +kerning first=1168 second=1026 amount=1 +kerning first=89 second=288 amount=-1 +kerning first=933 second=8211 amount=-1 +kerning first=221 second=194 amount=-1 +kerning first=8204 second=372 amount=-1 +kerning first=8217 second=235 amount=-1 +kerning first=1107 second=44 amount=-1 +kerning first=356 second=378 amount=-1 +kerning first=939 second=946 amount=-1 +kerning first=111 second=356 amount=-1 +kerning first=932 second=229 amount=-1 +kerning first=915 second=58 amount=-1 +kerning first=1068 second=1059 amount=-1 +kerning first=84 second=195 amount=-1 +kerning first=321 second=362 amount=-1 +kerning first=1058 second=1113 amount=-1 +kerning first=1043 second=1075 amount=-1 +kerning first=1027 second=1038 amount=1 +kerning first=34 second=961 amount=-1 +kerning first=1168 second=1118 amount=-1 +kerning first=319 second=89 amount=-1 +kerning first=354 second=198 amount=-1 +kerning first=929 second=44 amount=-2 +kerning first=1059 second=1109 amount=-1 +kerning first=221 second=337 amount=-1 +kerning first=313 second=39 amount=-1 +kerning first=1027 second=8249 amount=-1 +kerning first=1075 second=8230 amount=-1 +kerning first=173 second=910 amount=-1 +kerning first=84 second=345 amount=-1 +kerning first=1035 second=1026 amount=-1 +kerning first=356 second=265 amount=-1 +kerning first=8221 second=343 amount=-1 +kerning first=354 second=944 amount=-1 +kerning first=8220 second=974 amount=-1 +kerning first=80 second=193 amount=-1 +kerning first=84 second=8230 amount=-1 +kerning first=356 second=118 amount=-1 +kerning first=915 second=957 amount=-1 +kerning first=228 second=356 amount=-1 +kerning first=354 second=255 amount=-1 +kerning first=358 second=8212 amount=-1 +kerning first=45 second=1026 amount=-1 +kerning first=923 second=8220 amount=-1 +kerning first=313 second=218 amount=-1 +kerning first=319 second=34 amount=-1 +kerning first=271 second=98 amount=1 +kerning first=354 second=261 amount=-1 +kerning first=241 second=84 amount=-1 +kerning first=221 second=231 amount=-1 +kerning first=46 second=34 amount=-1 +kerning first=354 second=114 amount=-1 +kerning first=1040 second=1066 amount=-1 +kerning first=8212 second=89 amount=-1 +kerning first=84 second=232 amount=-1 +kerning first=8221 second=237 amount=-1 +kerning first=356 second=195 amount=-1 +kerning first=317 second=214 amount=-1 +kerning first=39 second=192 amount=-1 +kerning first=358 second=253 amount=-1 +kerning first=221 second=93 amount=1 +kerning first=932 second=281 amount=-1 +kerning first=376 second=228 amount=-1 +kerning first=1027 second=1072 amount=-1 +kerning first=260 second=8216 amount=-1 +kerning first=932 second=125 amount=1 +kerning first=358 second=257 amount=-1 +kerning first=8220 second=923 amount=-1 +kerning first=245 second=358 amount=-1 +kerning first=84 second=97 amount=-1 +kerning first=354 second=194 amount=-1 +kerning first=358 second=113 amount=-1 +kerning first=931 second=211 amount=-1 +kerning first=76 second=264 amount=-1 +kerning first=1057 second=1095 amount=-1 +kerning first=187 second=356 amount=-1 +kerning first=1038 second=1109 amount=-1 +kerning first=321 second=210 amount=-1 +kerning first=356 second=345 amount=-1 +kerning first=1068 second=1038 amount=-1 +kerning first=935 second=912 amount=1 +kerning first=356 second=8230 amount=-1 +kerning first=939 second=196 amount=-1 +kerning first=1058 second=1091 amount=-1 +kerning first=358 second=193 amount=-1 +kerning first=328 second=932 amount=-1 +kerning first=376 second=248 amount=-1 +kerning first=1168 second=1095 amount=-1 +kerning first=1056 second=1044 amount=-1 +kerning first=354 second=337 amount=-1 +kerning first=76 second=8211 amount=-1 +kerning first=372 second=256 amount=-1 +kerning first=1113 second=1098 amount=-1 diff --git a/art/font/myriad-medium.png b/art/font/myriad-medium.png new file mode 100644 index 00000000..27b39f8c Binary files /dev/null and b/art/font/myriad-medium.png differ diff --git a/art/splash_textures/bg_color.png b/art/splash_textures/bg_color.png new file mode 100644 index 00000000..469e01f7 Binary files /dev/null and b/art/splash_textures/bg_color.png differ diff --git a/art/splash_textures/splash_bg.png b/art/splash_textures/splash_bg.png new file mode 100644 index 00000000..dcba81c2 Binary files /dev/null and b/art/splash_textures/splash_bg.png differ diff --git a/art/splash_textures/splash_logo.png b/art/splash_textures/splash_logo.png new file mode 100644 index 00000000..889009db Binary files /dev/null and b/art/splash_textures/splash_logo.png differ diff --git a/art/splash_textures/splash_logo_text.png b/art/splash_textures/splash_logo_text.png new file mode 100644 index 00000000..8dcc9500 Binary files /dev/null and b/art/splash_textures/splash_logo_text.png differ diff --git a/art/textures/align-center-horisontal.png b/art/textures/align-center-horisontal.png new file mode 100644 index 00000000..928c01a3 Binary files /dev/null and b/art/textures/align-center-horisontal.png differ diff --git a/art/textures/align-center-vertical.png b/art/textures/align-center-vertical.png new file mode 100644 index 00000000..90c7a3e4 Binary files /dev/null and b/art/textures/align-center-vertical.png differ diff --git a/art/textures/align-edge-down.png b/art/textures/align-edge-down.png new file mode 100644 index 00000000..7ec85f2f Binary files /dev/null and b/art/textures/align-edge-down.png differ diff --git a/art/textures/align-edge-left.png b/art/textures/align-edge-left.png new file mode 100644 index 00000000..0aefa7c9 Binary files /dev/null and b/art/textures/align-edge-left.png differ diff --git a/art/textures/align-edge-right.png b/art/textures/align-edge-right.png new file mode 100644 index 00000000..9c4d9974 Binary files /dev/null and b/art/textures/align-edge-right.png differ diff --git a/art/textures/align-edge-up.png b/art/textures/align-edge-up.png new file mode 100644 index 00000000..deb4051d Binary files /dev/null and b/art/textures/align-edge-up.png differ diff --git a/art/textures/align-simple-down.png b/art/textures/align-simple-down.png new file mode 100644 index 00000000..b69caba9 Binary files /dev/null and b/art/textures/align-simple-down.png differ diff --git a/art/textures/align-simple-left.png b/art/textures/align-simple-left.png new file mode 100644 index 00000000..9d24341e Binary files /dev/null and b/art/textures/align-simple-left.png differ diff --git a/art/textures/align-simple-right.png b/art/textures/align-simple-right.png new file mode 100644 index 00000000..89a7a803 Binary files /dev/null and b/art/textures/align-simple-right.png differ diff --git a/art/textures/align-simple-up.png b/art/textures/align-simple-up.png new file mode 100644 index 00000000..d8e8144a Binary files /dev/null and b/art/textures/align-simple-up.png differ diff --git a/art/textures/alpha-bar-10px.png b/art/textures/alpha-bar-10px.png new file mode 100644 index 00000000..118e92d6 Binary files /dev/null and b/art/textures/alpha-bar-10px.png differ diff --git a/art/textures/alpha-bar-25px-shifted.png b/art/textures/alpha-bar-25px-shifted.png new file mode 100644 index 00000000..9229a9a2 Binary files /dev/null and b/art/textures/alpha-bar-25px-shifted.png differ diff --git a/art/textures/alpha-bar-25px.png b/art/textures/alpha-bar-25px.png new file mode 100644 index 00000000..b852d001 Binary files /dev/null and b/art/textures/alpha-bar-25px.png differ diff --git a/art/textures/border-circle-error.png b/art/textures/border-circle-error.png new file mode 100644 index 00000000..d3fd9440 Binary files /dev/null and b/art/textures/border-circle-error.png differ diff --git a/art/textures/border-circle.png b/art/textures/border-circle.png new file mode 100644 index 00000000..86ed43d8 Binary files /dev/null and b/art/textures/border-circle.png differ diff --git a/art/textures/border-error.9.png b/art/textures/border-error.9.png new file mode 100644 index 00000000..0df41a66 Binary files /dev/null and b/art/textures/border-error.9.png differ diff --git a/art/textures/border.9.png b/art/textures/border.9.png new file mode 100644 index 00000000..984224e2 Binary files /dev/null and b/art/textures/border.9.png differ diff --git a/art/textures/box-colapse-off.png b/art/textures/box-colapse-off.png new file mode 100644 index 00000000..1d14201b Binary files /dev/null and b/art/textures/box-colapse-off.png differ diff --git a/art/textures/box-colapse-on.png b/art/textures/box-colapse-on.png new file mode 100644 index 00000000..4cc93eaf Binary files /dev/null and b/art/textures/box-colapse-on.png differ diff --git a/art/textures/box.9.png b/art/textures/box.9.png new file mode 100644 index 00000000..4b5fdef5 Binary files /dev/null and b/art/textures/box.9.png differ diff --git a/art/textures/button-dark-down.9.png b/art/textures/button-dark-down.9.png new file mode 100644 index 00000000..d393c0a3 Binary files /dev/null and b/art/textures/button-dark-down.9.png differ diff --git a/art/textures/button-dark-over.9.png b/art/textures/button-dark-over.9.png new file mode 100644 index 00000000..71dd8feb Binary files /dev/null and b/art/textures/button-dark-over.9.png differ diff --git a/art/textures/button-dark.9.png b/art/textures/button-dark.9.png new file mode 100644 index 00000000..e30612eb Binary files /dev/null and b/art/textures/button-dark.9.png differ diff --git a/art/textures/button-down.9.png b/art/textures/button-down.9.png new file mode 100644 index 00000000..d53d2afb Binary files /dev/null and b/art/textures/button-down.9.png differ diff --git a/art/textures/button-orange-down.9.png b/art/textures/button-orange-down.9.png new file mode 100644 index 00000000..75e15d05 Binary files /dev/null and b/art/textures/button-orange-down.9.png differ diff --git a/art/textures/button-orange-over.9.png b/art/textures/button-orange-over.9.png new file mode 100644 index 00000000..3760bb4a Binary files /dev/null and b/art/textures/button-orange-over.9.png differ diff --git a/art/textures/button-orange.9.png b/art/textures/button-orange.9.png new file mode 100644 index 00000000..5ef40d64 Binary files /dev/null and b/art/textures/button-orange.9.png differ diff --git a/art/textures/button-over.9.png b/art/textures/button-over.9.png new file mode 100644 index 00000000..6b297372 Binary files /dev/null and b/art/textures/button-over.9.png differ diff --git a/art/textures/button-red.9.png b/art/textures/button-red.9.png new file mode 100644 index 00000000..f9571703 Binary files /dev/null and b/art/textures/button-red.9.png differ diff --git a/art/textures/button-resource-over.9.png b/art/textures/button-resource-over.9.png new file mode 100644 index 00000000..b8fc7719 Binary files /dev/null and b/art/textures/button-resource-over.9.png differ diff --git a/art/textures/button-resource.9.png b/art/textures/button-resource.9.png new file mode 100644 index 00000000..dde9be45 Binary files /dev/null and b/art/textures/button-resource.9.png differ diff --git a/art/textures/button.9.png b/art/textures/button.9.png new file mode 100644 index 00000000..4b379961 Binary files /dev/null and b/art/textures/button.9.png differ diff --git a/art/textures/check-down-on.png b/art/textures/check-down-on.png new file mode 100644 index 00000000..5478800f Binary files /dev/null and b/art/textures/check-down-on.png differ diff --git a/art/textures/check-down.png b/art/textures/check-down.png new file mode 100644 index 00000000..954592f6 Binary files /dev/null and b/art/textures/check-down.png differ diff --git a/art/textures/check-off.png b/art/textures/check-off.png new file mode 100644 index 00000000..572b98db Binary files /dev/null and b/art/textures/check-off.png differ diff --git a/art/textures/check-on-disabled.png b/art/textures/check-on-disabled.png new file mode 100644 index 00000000..20964dc7 Binary files /dev/null and b/art/textures/check-on-disabled.png differ diff --git a/art/textures/check-on.png b/art/textures/check-on.png new file mode 100644 index 00000000..42b425b8 Binary files /dev/null and b/art/textures/check-on.png differ diff --git a/art/textures/check-over-off.png b/art/textures/check-over-off.png new file mode 100644 index 00000000..49b16428 Binary files /dev/null and b/art/textures/check-over-off.png differ diff --git a/art/textures/check-over-on.png b/art/textures/check-over-on.png new file mode 100644 index 00000000..a833bc83 Binary files /dev/null and b/art/textures/check-over-on.png differ diff --git a/art/textures/color-picker-bar-selector.png b/art/textures/color-picker-bar-selector.png new file mode 100644 index 00000000..efc1238d Binary files /dev/null and b/art/textures/color-picker-bar-selector.png differ diff --git a/art/textures/color-picker-cross.png b/art/textures/color-picker-cross.png new file mode 100644 index 00000000..6d976403 Binary files /dev/null and b/art/textures/color-picker-cross.png differ diff --git a/art/textures/color-picker-selector-horizontal.png b/art/textures/color-picker-selector-horizontal.png new file mode 100644 index 00000000..ad355cf3 Binary files /dev/null and b/art/textures/color-picker-selector-horizontal.png differ diff --git a/art/textures/color-picker-selector-vertical.png b/art/textures/color-picker-selector-vertical.png new file mode 100644 index 00000000..1617b251 Binary files /dev/null and b/art/textures/color-picker-selector-vertical.png differ diff --git a/art/textures/cursor.9.png b/art/textures/cursor.9.png new file mode 100644 index 00000000..aeed93c0 Binary files /dev/null and b/art/textures/cursor.9.png differ diff --git a/art/textures/default-pane-noborder.9.png b/art/textures/default-pane-noborder.9.png new file mode 100644 index 00000000..d2c3e66a Binary files /dev/null and b/art/textures/default-pane-noborder.9.png differ diff --git a/art/textures/default-pane.9.png b/art/textures/default-pane.9.png new file mode 100644 index 00000000..6b3f9042 Binary files /dev/null and b/art/textures/default-pane.9.png differ diff --git a/art/textures/default-select-selection.9.png b/art/textures/default-select-selection.9.png new file mode 100644 index 00000000..1d24aa7b Binary files /dev/null and b/art/textures/default-select-selection.9.png differ diff --git a/art/textures/default-select-white-over.9.png b/art/textures/default-select-white-over.9.png new file mode 100644 index 00000000..971638ef Binary files /dev/null and b/art/textures/default-select-white-over.9.png differ diff --git a/art/textures/default-select-white.9.png b/art/textures/default-select-white.9.png new file mode 100644 index 00000000..aef4befa Binary files /dev/null and b/art/textures/default-select-white.9.png differ diff --git a/art/textures/default-select.9.png b/art/textures/default-select.9.png new file mode 100644 index 00000000..4399ea2b Binary files /dev/null and b/art/textures/default-select.9.png differ diff --git a/art/textures/dropHere.png b/art/textures/dropHere.png new file mode 100644 index 00000000..370ed445 Binary files /dev/null and b/art/textures/dropHere.png differ diff --git a/art/textures/expandable-properties-active-bg.9.png b/art/textures/expandable-properties-active-bg.9.png new file mode 100644 index 00000000..684f11ac Binary files /dev/null and b/art/textures/expandable-properties-active-bg.9.png differ diff --git a/art/textures/expandable-properties-collapse-off.png b/art/textures/expandable-properties-collapse-off.png new file mode 100644 index 00000000..137103d4 Binary files /dev/null and b/art/textures/expandable-properties-collapse-off.png differ diff --git a/art/textures/expandable-properties-collapse-on.png b/art/textures/expandable-properties-collapse-on.png new file mode 100644 index 00000000..247bbdac Binary files /dev/null and b/art/textures/expandable-properties-collapse-on.png differ diff --git a/art/textures/expandable-properties-inactive-bg.9.png b/art/textures/expandable-properties-inactive-bg.9.png new file mode 100644 index 00000000..ccf04925 Binary files /dev/null and b/art/textures/expandable-properties-inactive-bg.9.png differ diff --git a/art/textures/icon-animation.png b/art/textures/icon-animation.png new file mode 100644 index 00000000..c18b5023 Binary files /dev/null and b/art/textures/icon-animation.png differ diff --git a/art/textures/icon-arrow-left.png b/art/textures/icon-arrow-left.png new file mode 100644 index 00000000..bbb0db7b Binary files /dev/null and b/art/textures/icon-arrow-left.png differ diff --git a/art/textures/icon-arrow-right.png b/art/textures/icon-arrow-right.png new file mode 100644 index 00000000..80bb8446 Binary files /dev/null and b/art/textures/icon-arrow-right.png differ diff --git a/art/textures/icon-close-orange-down.png b/art/textures/icon-close-orange-down.png new file mode 100644 index 00000000..b41ea58a Binary files /dev/null and b/art/textures/icon-close-orange-down.png differ diff --git a/art/textures/icon-close-orange-over.png b/art/textures/icon-close-orange-over.png new file mode 100644 index 00000000..96738285 Binary files /dev/null and b/art/textures/icon-close-orange-over.png differ diff --git a/art/textures/icon-close-orange.png b/art/textures/icon-close-orange.png new file mode 100644 index 00000000..7af49475 Binary files /dev/null and b/art/textures/icon-close-orange.png differ diff --git a/art/textures/icon-close-small.png b/art/textures/icon-close-small.png new file mode 100644 index 00000000..3e0904c7 Binary files /dev/null and b/art/textures/icon-close-small.png differ diff --git a/art/textures/icon-close.png b/art/textures/icon-close.png new file mode 100644 index 00000000..81364d47 Binary files /dev/null and b/art/textures/icon-close.png differ diff --git a/art/textures/icon-composite.png b/art/textures/icon-composite.png new file mode 100644 index 00000000..d4e02818 Binary files /dev/null and b/art/textures/icon-composite.png differ diff --git a/art/textures/icon-composite2.png b/art/textures/icon-composite2.png new file mode 100644 index 00000000..c27fbdab Binary files /dev/null and b/art/textures/icon-composite2.png differ diff --git a/art/textures/icon-drive.png b/art/textures/icon-drive.png new file mode 100644 index 00000000..8d42c869 Binary files /dev/null and b/art/textures/icon-drive.png differ diff --git a/art/textures/icon-file-audio.png b/art/textures/icon-file-audio.png new file mode 100644 index 00000000..ffb3199c Binary files /dev/null and b/art/textures/icon-file-audio.png differ diff --git a/art/textures/icon-file-image.png b/art/textures/icon-file-image.png new file mode 100644 index 00000000..0ead27f3 Binary files /dev/null and b/art/textures/icon-file-image.png differ diff --git a/art/textures/icon-file-pdf.png b/art/textures/icon-file-pdf.png new file mode 100644 index 00000000..9985f113 Binary files /dev/null and b/art/textures/icon-file-pdf.png differ diff --git a/art/textures/icon-file-text.png b/art/textures/icon-file-text.png new file mode 100644 index 00000000..02053c7e Binary files /dev/null and b/art/textures/icon-file-text.png differ diff --git a/art/textures/icon-folder-new.png b/art/textures/icon-folder-new.png new file mode 100644 index 00000000..2ec050e4 Binary files /dev/null and b/art/textures/icon-folder-new.png differ diff --git a/art/textures/icon-folder-parent.png b/art/textures/icon-folder-parent.png new file mode 100644 index 00000000..083850d3 Binary files /dev/null and b/art/textures/icon-folder-parent.png differ diff --git a/art/textures/icon-folder-star.png b/art/textures/icon-folder-star.png new file mode 100644 index 00000000..8ebda464 Binary files /dev/null and b/art/textures/icon-folder-star.png differ diff --git a/art/textures/icon-folder.png b/art/textures/icon-folder.png new file mode 100644 index 00000000..e6d87df3 Binary files /dev/null and b/art/textures/icon-folder.png differ diff --git a/art/textures/icon-group.png b/art/textures/icon-group.png new file mode 100644 index 00000000..83dfe64c Binary files /dev/null and b/art/textures/icon-group.png differ diff --git a/art/textures/icon-image.png b/art/textures/icon-image.png new file mode 100644 index 00000000..59d84b6b Binary files /dev/null and b/art/textures/icon-image.png differ diff --git a/art/textures/icon-label.png b/art/textures/icon-label.png new file mode 100644 index 00000000..99b9fc65 Binary files /dev/null and b/art/textures/icon-label.png differ diff --git a/art/textures/icon-library-over.png b/art/textures/icon-library-over.png new file mode 100644 index 00000000..fbb9e8cb Binary files /dev/null and b/art/textures/icon-library-over.png differ diff --git a/art/textures/icon-library.png b/art/textures/icon-library.png new file mode 100644 index 00000000..75454135 Binary files /dev/null and b/art/textures/icon-library.png differ diff --git a/art/textures/icon-link-active.png b/art/textures/icon-link-active.png new file mode 100644 index 00000000..317c035c Binary files /dev/null and b/art/textures/icon-link-active.png differ diff --git a/art/textures/icon-link-inactive.png b/art/textures/icon-link-inactive.png new file mode 100644 index 00000000..088dfa55 Binary files /dev/null and b/art/textures/icon-link-inactive.png differ diff --git a/art/textures/icon-list-settings.png b/art/textures/icon-list-settings.png new file mode 100644 index 00000000..066878c5 Binary files /dev/null and b/art/textures/icon-list-settings.png differ diff --git a/art/textures/icon-lock-active.png b/art/textures/icon-lock-active.png new file mode 100644 index 00000000..8c7e219e Binary files /dev/null and b/art/textures/icon-lock-active.png differ diff --git a/art/textures/icon-lock-inactive.png b/art/textures/icon-lock-inactive.png new file mode 100644 index 00000000..db30c1df Binary files /dev/null and b/art/textures/icon-lock-inactive.png differ diff --git a/art/textures/icon-new-layer.png b/art/textures/icon-new-layer.png new file mode 100644 index 00000000..793067ee Binary files /dev/null and b/art/textures/icon-new-layer.png differ diff --git a/art/textures/icon-particle-over.png b/art/textures/icon-particle-over.png new file mode 100644 index 00000000..55f27769 Binary files /dev/null and b/art/textures/icon-particle-over.png differ diff --git a/art/textures/icon-particle-white.png b/art/textures/icon-particle-white.png new file mode 100644 index 00000000..e26c22c8 Binary files /dev/null and b/art/textures/icon-particle-white.png differ diff --git a/art/textures/icon-particle.png b/art/textures/icon-particle.png new file mode 100644 index 00000000..08481b4b Binary files /dev/null and b/art/textures/icon-particle.png differ diff --git a/art/textures/icon-refresh.png b/art/textures/icon-refresh.png new file mode 100644 index 00000000..3fc3d28b Binary files /dev/null and b/art/textures/icon-refresh.png differ diff --git a/art/textures/icon-root.png b/art/textures/icon-root.png new file mode 100644 index 00000000..72ea033e Binary files /dev/null and b/art/textures/icon-root.png differ diff --git a/art/textures/icon-spine.png b/art/textures/icon-spine.png new file mode 100644 index 00000000..169ed9f4 Binary files /dev/null and b/art/textures/icon-spine.png differ diff --git a/art/textures/icon-star-outline.png b/art/textures/icon-star-outline.png new file mode 100644 index 00000000..106e43a0 Binary files /dev/null and b/art/textures/icon-star-outline.png differ diff --git a/art/textures/icon-star.png b/art/textures/icon-star.png new file mode 100644 index 00000000..fa86bc22 Binary files /dev/null and b/art/textures/icon-star.png differ diff --git a/art/textures/icon-trash-disabled.png b/art/textures/icon-trash-disabled.png new file mode 100644 index 00000000..969f912f Binary files /dev/null and b/art/textures/icon-trash-disabled.png differ diff --git a/art/textures/icon-trash-over.png b/art/textures/icon-trash-over.png new file mode 100644 index 00000000..baa3349f Binary files /dev/null and b/art/textures/icon-trash-over.png differ diff --git a/art/textures/icon-trash.png b/art/textures/icon-trash.png new file mode 100644 index 00000000..82fad16f Binary files /dev/null and b/art/textures/icon-trash.png differ diff --git a/art/textures/icon-unlink-active.png b/art/textures/icon-unlink-active.png new file mode 100644 index 00000000..cd2c9762 Binary files /dev/null and b/art/textures/icon-unlink-active.png differ diff --git a/art/textures/icon-unlink-inactive.png b/art/textures/icon-unlink-inactive.png new file mode 100644 index 00000000..f5d01240 Binary files /dev/null and b/art/textures/icon-unlink-inactive.png differ diff --git a/art/textures/icon-visible-off.png b/art/textures/icon-visible-off.png new file mode 100644 index 00000000..7ea4e756 Binary files /dev/null and b/art/textures/icon-visible-off.png differ diff --git a/art/textures/icon-visible-on.png b/art/textures/icon-visible-on.png new file mode 100644 index 00000000..b2db821d Binary files /dev/null and b/art/textures/icon-visible-on.png differ diff --git a/art/textures/icon-zoomin-disabled.png b/art/textures/icon-zoomin-disabled.png new file mode 100644 index 00000000..9df40c89 Binary files /dev/null and b/art/textures/icon-zoomin-disabled.png differ diff --git a/art/textures/icon-zoomin-over.png b/art/textures/icon-zoomin-over.png new file mode 100644 index 00000000..189157ca Binary files /dev/null and b/art/textures/icon-zoomin-over.png differ diff --git a/art/textures/icon-zoomin.png b/art/textures/icon-zoomin.png new file mode 100644 index 00000000..ffc0c65d Binary files /dev/null and b/art/textures/icon-zoomin.png differ diff --git a/art/textures/icon-zoomout-disabled.png b/art/textures/icon-zoomout-disabled.png new file mode 100644 index 00000000..d1ed24e7 Binary files /dev/null and b/art/textures/icon-zoomout-disabled.png differ diff --git a/art/textures/icon-zoomout-over.png b/art/textures/icon-zoomout-over.png new file mode 100644 index 00000000..5cd91e09 Binary files /dev/null and b/art/textures/icon-zoomout-over.png differ diff --git a/art/textures/icon-zoomout.png b/art/textures/icon-zoomout.png new file mode 100644 index 00000000..8b3f9e26 Binary files /dev/null and b/art/textures/icon-zoomout.png differ diff --git a/art/textures/layer-bg-over.9.png b/art/textures/layer-bg-over.9.png new file mode 100644 index 00000000..ff999bc8 Binary files /dev/null and b/art/textures/layer-bg-over.9.png differ diff --git a/art/textures/layer-bg.9.png b/art/textures/layer-bg.9.png new file mode 100644 index 00000000..80897dba Binary files /dev/null and b/art/textures/layer-bg.9.png differ diff --git a/art/textures/list-selection-white.png b/art/textures/list-selection-white.png new file mode 100644 index 00000000..32ff3c66 Binary files /dev/null and b/art/textures/list-selection-white.png differ diff --git a/art/textures/list-selection.png b/art/textures/list-selection.png new file mode 100644 index 00000000..b203a5a2 Binary files /dev/null and b/art/textures/list-selection.png differ diff --git a/art/textures/logo.png b/art/textures/logo.png new file mode 100644 index 00000000..b09a5ed4 Binary files /dev/null and b/art/textures/logo.png differ diff --git a/art/textures/menu-bg-down.9.png b/art/textures/menu-bg-down.9.png new file mode 100644 index 00000000..838f16a9 Binary files /dev/null and b/art/textures/menu-bg-down.9.png differ diff --git a/art/textures/menu-bg-over.9.png b/art/textures/menu-bg-over.9.png new file mode 100644 index 00000000..518aab05 Binary files /dev/null and b/art/textures/menu-bg-over.9.png differ diff --git a/art/textures/menu-bg-up.9.png b/art/textures/menu-bg-up.9.png new file mode 100644 index 00000000..e596c84c Binary files /dev/null and b/art/textures/menu-bg-up.9.png differ diff --git a/art/textures/menu-bg.9.png b/art/textures/menu-bg.9.png new file mode 100644 index 00000000..d2dc6fe9 Binary files /dev/null and b/art/textures/menu-bg.9.png differ diff --git a/art/textures/myriad-medium-big.png b/art/textures/myriad-medium-big.png new file mode 100644 index 00000000..5a7df5c3 Binary files /dev/null and b/art/textures/myriad-medium-big.png differ diff --git a/art/textures/myriad-medium-small.png b/art/textures/myriad-medium-small.png new file mode 100644 index 00000000..628dd2b8 Binary files /dev/null and b/art/textures/myriad-medium-small.png differ diff --git a/art/textures/myriad-medium.png b/art/textures/myriad-medium.png new file mode 100644 index 00000000..27b39f8c Binary files /dev/null and b/art/textures/myriad-medium.png differ diff --git a/art/textures/origin-anchor.png b/art/textures/origin-anchor.png new file mode 100644 index 00000000..12edc1ff Binary files /dev/null and b/art/textures/origin-anchor.png differ diff --git a/art/textures/popup-menu-disabled.9.png b/art/textures/popup-menu-disabled.9.png new file mode 100644 index 00000000..74cf1dcf Binary files /dev/null and b/art/textures/popup-menu-disabled.9.png differ diff --git a/art/textures/popup-menu-down.9.png b/art/textures/popup-menu-down.9.png new file mode 100644 index 00000000..c6197750 Binary files /dev/null and b/art/textures/popup-menu-down.9.png differ diff --git a/art/textures/popup-menu-over.9.png b/art/textures/popup-menu-over.9.png new file mode 100644 index 00000000..45b2f67a Binary files /dev/null and b/art/textures/popup-menu-over.9.png differ diff --git a/art/textures/popup-menu.9.png b/art/textures/popup-menu.9.png new file mode 100644 index 00000000..77a2d18c Binary files /dev/null and b/art/textures/popup-menu.9.png differ diff --git a/art/textures/progressbar-filled-vertical.png b/art/textures/progressbar-filled-vertical.png new file mode 100644 index 00000000..33f6e17b Binary files /dev/null and b/art/textures/progressbar-filled-vertical.png differ diff --git a/art/textures/progressbar-filled.png b/art/textures/progressbar-filled.png new file mode 100644 index 00000000..9c1c5501 Binary files /dev/null and b/art/textures/progressbar-filled.png differ diff --git a/art/textures/progressbar-vertical.png b/art/textures/progressbar-vertical.png new file mode 100644 index 00000000..9bc74b38 Binary files /dev/null and b/art/textures/progressbar-vertical.png differ diff --git a/art/textures/progressbar.png b/art/textures/progressbar.png new file mode 100644 index 00000000..5f6d2298 Binary files /dev/null and b/art/textures/progressbar.png differ diff --git a/art/textures/radio-down-on.png b/art/textures/radio-down-on.png new file mode 100644 index 00000000..e7333c7a Binary files /dev/null and b/art/textures/radio-down-on.png differ diff --git a/art/textures/radio-down.png b/art/textures/radio-down.png new file mode 100644 index 00000000..a54f9194 Binary files /dev/null and b/art/textures/radio-down.png differ diff --git a/art/textures/radio-off.png b/art/textures/radio-off.png new file mode 100644 index 00000000..7064c709 Binary files /dev/null and b/art/textures/radio-off.png differ diff --git a/art/textures/radio-on-disabled.png b/art/textures/radio-on-disabled.png new file mode 100644 index 00000000..3a42b8f5 Binary files /dev/null and b/art/textures/radio-on-disabled.png differ diff --git a/art/textures/radio-on.png b/art/textures/radio-on.png new file mode 100644 index 00000000..f7121d67 Binary files /dev/null and b/art/textures/radio-on.png differ diff --git a/art/textures/radio-over-off.png b/art/textures/radio-over-off.png new file mode 100644 index 00000000..bdbd9006 Binary files /dev/null and b/art/textures/radio-over-off.png differ diff --git a/art/textures/radio-over-on.png b/art/textures/radio-over-on.png new file mode 100644 index 00000000..f3f850c6 Binary files /dev/null and b/art/textures/radio-over-on.png differ diff --git a/art/textures/scroll-horizontal.9.png b/art/textures/scroll-horizontal.9.png new file mode 100644 index 00000000..f0009a68 Binary files /dev/null and b/art/textures/scroll-horizontal.9.png differ diff --git a/art/textures/scroll-knob-horizontal.9.png b/art/textures/scroll-knob-horizontal.9.png new file mode 100644 index 00000000..0cb56575 Binary files /dev/null and b/art/textures/scroll-knob-horizontal.9.png differ diff --git a/art/textures/scroll-knob-vertical.9.png b/art/textures/scroll-knob-vertical.9.png new file mode 100644 index 00000000..942399c4 Binary files /dev/null and b/art/textures/scroll-knob-vertical.9.png differ diff --git a/art/textures/scroll.9.png b/art/textures/scroll.9.png new file mode 100644 index 00000000..c301a5d8 Binary files /dev/null and b/art/textures/scroll.9.png differ diff --git a/art/textures/select-box-list-bg-white.png b/art/textures/select-box-list-bg-white.png new file mode 100644 index 00000000..35d451f9 Binary files /dev/null and b/art/textures/select-box-list-bg-white.png differ diff --git a/art/textures/select-box-list-bg.png b/art/textures/select-box-list-bg.png new file mode 100644 index 00000000..949295ba Binary files /dev/null and b/art/textures/select-box-list-bg.png differ diff --git a/art/textures/select-down.png b/art/textures/select-down.png new file mode 100644 index 00000000..08ab9664 Binary files /dev/null and b/art/textures/select-down.png differ diff --git a/art/textures/select-up.png b/art/textures/select-up.png new file mode 100644 index 00000000..e9ee3288 Binary files /dev/null and b/art/textures/select-up.png differ diff --git a/art/textures/selection-anchor.png b/art/textures/selection-anchor.png new file mode 100644 index 00000000..17d2fc2c Binary files /dev/null and b/art/textures/selection-anchor.png differ diff --git a/art/textures/selection.png b/art/textures/selection.png new file mode 100644 index 00000000..3bbad981 Binary files /dev/null and b/art/textures/selection.png differ diff --git a/art/textures/separator-menu.png b/art/textures/separator-menu.png new file mode 100644 index 00000000..b99a132b Binary files /dev/null and b/art/textures/separator-menu.png differ diff --git a/art/textures/separator-vertical.png b/art/textures/separator-vertical.png new file mode 100644 index 00000000..0897266a Binary files /dev/null and b/art/textures/separator-vertical.png differ diff --git a/art/textures/separator.png b/art/textures/separator.png new file mode 100644 index 00000000..b99a132b Binary files /dev/null and b/art/textures/separator.png differ diff --git a/art/textures/slider-knob-disabled.png b/art/textures/slider-knob-disabled.png new file mode 100644 index 00000000..0051523d Binary files /dev/null and b/art/textures/slider-knob-disabled.png differ diff --git a/art/textures/slider-knob-down.png b/art/textures/slider-knob-down.png new file mode 100644 index 00000000..019dad14 Binary files /dev/null and b/art/textures/slider-knob-down.png differ diff --git a/art/textures/slider-knob-over.png b/art/textures/slider-knob-over.png new file mode 100644 index 00000000..fc99072b Binary files /dev/null and b/art/textures/slider-knob-over.png differ diff --git a/art/textures/slider-knob.png b/art/textures/slider-knob.png new file mode 100644 index 00000000..297fee49 Binary files /dev/null and b/art/textures/slider-knob.png differ diff --git a/art/textures/slider-vertical.png b/art/textures/slider-vertical.png new file mode 100644 index 00000000..15215af8 Binary files /dev/null and b/art/textures/slider-vertical.png differ diff --git a/art/textures/slider.png b/art/textures/slider.png new file mode 100644 index 00000000..b34acc3f Binary files /dev/null and b/art/textures/slider.png differ diff --git a/art/textures/splash_logo.png b/art/textures/splash_logo.png new file mode 100644 index 00000000..889009db Binary files /dev/null and b/art/textures/splash_logo.png differ diff --git a/art/textures/splitpane-over.png b/art/textures/splitpane-over.png new file mode 100644 index 00000000..3436d8cd Binary files /dev/null and b/art/textures/splitpane-over.png differ diff --git a/art/textures/splitpane-vertical-over.png b/art/textures/splitpane-vertical-over.png new file mode 100644 index 00000000..c39ce363 Binary files /dev/null and b/art/textures/splitpane-vertical-over.png differ diff --git a/art/textures/splitpane-vertical.png b/art/textures/splitpane-vertical.png new file mode 100644 index 00000000..0b5cd802 Binary files /dev/null and b/art/textures/splitpane-vertical.png differ diff --git a/art/textures/splitpane.png b/art/textures/splitpane.png new file mode 100644 index 00000000..ebf9ca67 Binary files /dev/null and b/art/textures/splitpane.png differ diff --git a/art/textures/static-text.9.png b/art/textures/static-text.9.png new file mode 100644 index 00000000..d7be296c Binary files /dev/null and b/art/textures/static-text.9.png differ diff --git a/art/textures/sub-menu-bg.9.png b/art/textures/sub-menu-bg.9.png new file mode 100644 index 00000000..467ef145 Binary files /dev/null and b/art/textures/sub-menu-bg.9.png differ diff --git a/art/textures/sub-menu.png b/art/textures/sub-menu.png new file mode 100644 index 00000000..30c08ed2 Binary files /dev/null and b/art/textures/sub-menu.png differ diff --git a/art/textures/tab-active.9.png b/art/textures/tab-active.9.png new file mode 100644 index 00000000..e0b56a26 Binary files /dev/null and b/art/textures/tab-active.9.png differ diff --git a/art/textures/tab-inactive.9.png b/art/textures/tab-inactive.9.png new file mode 100644 index 00000000..2ead50d1 Binary files /dev/null and b/art/textures/tab-inactive.9.png differ diff --git a/art/textures/textfield-light-down.9.png b/art/textures/textfield-light-down.9.png new file mode 100644 index 00000000..29a9bcf0 Binary files /dev/null and b/art/textures/textfield-light-down.9.png differ diff --git a/art/textures/textfield-light-over.9.png b/art/textures/textfield-light-over.9.png new file mode 100644 index 00000000..12172313 Binary files /dev/null and b/art/textures/textfield-light-over.9.png differ diff --git a/art/textures/textfield-light.9.png b/art/textures/textfield-light.9.png new file mode 100644 index 00000000..d4706c41 Binary files /dev/null and b/art/textures/textfield-light.9.png differ diff --git a/art/textures/textfield-over.9.png b/art/textures/textfield-over.9.png new file mode 100644 index 00000000..0659cc31 Binary files /dev/null and b/art/textures/textfield-over.9.png differ diff --git a/art/textures/textfield.9.png b/art/textures/textfield.9.png new file mode 100644 index 00000000..b0d2740d Binary files /dev/null and b/art/textures/textfield.9.png differ diff --git a/art/textures/thumbnail-over.9.png b/art/textures/thumbnail-over.9.png new file mode 100644 index 00000000..ad5700d8 Binary files /dev/null and b/art/textures/thumbnail-over.9.png differ diff --git a/art/textures/thumbnail.9.png b/art/textures/thumbnail.9.png new file mode 100644 index 00000000..32f799fb Binary files /dev/null and b/art/textures/thumbnail.9.png differ diff --git a/art/textures/tint-border.9.png b/art/textures/tint-border.9.png new file mode 100644 index 00000000..b3c81fb7 Binary files /dev/null and b/art/textures/tint-border.9.png differ diff --git a/art/textures/tool-align.png b/art/textures/tool-align.png new file mode 100644 index 00000000..ef272f90 Binary files /dev/null and b/art/textures/tool-align.png differ diff --git a/art/textures/tool-conuslight.png b/art/textures/tool-conuslight.png new file mode 100644 index 00000000..9228e113 Binary files /dev/null and b/art/textures/tool-conuslight.png differ diff --git a/art/textures/tool-label.png b/art/textures/tool-label.png new file mode 100644 index 00000000..c8e1b56e Binary files /dev/null and b/art/textures/tool-label.png differ diff --git a/art/textures/tool-mesh.png b/art/textures/tool-mesh.png new file mode 100644 index 00000000..6e720282 Binary files /dev/null and b/art/textures/tool-mesh.png differ diff --git a/art/textures/tool-move.png b/art/textures/tool-move.png new file mode 100644 index 00000000..cab2c360 Binary files /dev/null and b/art/textures/tool-move.png differ diff --git a/art/textures/tool-sphericlight.png b/art/textures/tool-sphericlight.png new file mode 100644 index 00000000..1cab8928 Binary files /dev/null and b/art/textures/tool-sphericlight.png differ diff --git a/art/textures/tool-transform.png b/art/textures/tool-transform.png new file mode 100644 index 00000000..1bb7304d Binary files /dev/null and b/art/textures/tool-transform.png differ diff --git a/art/textures/toolbar-bg.9.png b/art/textures/toolbar-bg.9.png new file mode 100644 index 00000000..c8aa1dd0 Binary files /dev/null and b/art/textures/toolbar-bg.9.png differ diff --git a/art/textures/toolbar-down.9.png b/art/textures/toolbar-down.9.png new file mode 100644 index 00000000..accf9ee8 Binary files /dev/null and b/art/textures/toolbar-down.9.png differ diff --git a/art/textures/toolbar-normal.9.png b/art/textures/toolbar-normal.9.png new file mode 100644 index 00000000..75ea0704 Binary files /dev/null and b/art/textures/toolbar-normal.9.png differ diff --git a/art/textures/toolbar-over.9.png b/art/textures/toolbar-over.9.png new file mode 100644 index 00000000..a6faee05 Binary files /dev/null and b/art/textures/toolbar-over.9.png differ diff --git a/art/textures/tooltip-bg.9.png b/art/textures/tooltip-bg.9.png new file mode 100644 index 00000000..e2fb2595 Binary files /dev/null and b/art/textures/tooltip-bg.9.png differ diff --git a/art/textures/touchpad-knob.png b/art/textures/touchpad-knob.png new file mode 100644 index 00000000..0a0c9806 Binary files /dev/null and b/art/textures/touchpad-knob.png differ diff --git a/art/textures/tree-minus.png b/art/textures/tree-minus.png new file mode 100644 index 00000000..9bc4e584 Binary files /dev/null and b/art/textures/tree-minus.png differ diff --git a/art/textures/tree-over.png b/art/textures/tree-over.png new file mode 100644 index 00000000..499ce540 Binary files /dev/null and b/art/textures/tree-over.png differ diff --git a/art/textures/tree-plus.png b/art/textures/tree-plus.png new file mode 100644 index 00000000..c479c3b7 Binary files /dev/null and b/art/textures/tree-plus.png differ diff --git a/art/textures/tree-selection.9.png b/art/textures/tree-selection.9.png new file mode 100644 index 00000000..d242e107 Binary files /dev/null and b/art/textures/tree-selection.9.png differ diff --git a/art/textures/vis-blue.png b/art/textures/vis-blue.png new file mode 100644 index 00000000..ef51bde2 Binary files /dev/null and b/art/textures/vis-blue.png differ diff --git a/art/textures/vis-check-down.png b/art/textures/vis-check-down.png new file mode 100644 index 00000000..12f5756d Binary files /dev/null and b/art/textures/vis-check-down.png differ diff --git a/art/textures/vis-check-over.png b/art/textures/vis-check-over.png new file mode 100644 index 00000000..b9b9d0a1 Binary files /dev/null and b/art/textures/vis-check-over.png differ diff --git a/art/textures/vis-check-tick-disabled.png b/art/textures/vis-check-tick-disabled.png new file mode 100644 index 00000000..597dcf44 Binary files /dev/null and b/art/textures/vis-check-tick-disabled.png differ diff --git a/art/textures/vis-check-tick.png b/art/textures/vis-check-tick.png new file mode 100644 index 00000000..6a8dad02 Binary files /dev/null and b/art/textures/vis-check-tick.png differ diff --git a/art/textures/vis-check.png b/art/textures/vis-check.png new file mode 100644 index 00000000..9950de74 Binary files /dev/null and b/art/textures/vis-check.png differ diff --git a/art/textures/vis-radio-down.png b/art/textures/vis-radio-down.png new file mode 100644 index 00000000..4d1ddd18 Binary files /dev/null and b/art/textures/vis-radio-down.png differ diff --git a/art/textures/vis-radio-over.png b/art/textures/vis-radio-over.png new file mode 100644 index 00000000..832126d8 Binary files /dev/null and b/art/textures/vis-radio-over.png differ diff --git a/art/textures/vis-radio-tick-disabled.png b/art/textures/vis-radio-tick-disabled.png new file mode 100644 index 00000000..3b56069d Binary files /dev/null and b/art/textures/vis-radio-tick-disabled.png differ diff --git a/art/textures/vis-radio-tick.png b/art/textures/vis-radio-tick.png new file mode 100644 index 00000000..5851c2b1 Binary files /dev/null and b/art/textures/vis-radio-tick.png differ diff --git a/art/textures/vis-radio.png b/art/textures/vis-radio.png new file mode 100644 index 00000000..00243b84 Binary files /dev/null and b/art/textures/vis-radio.png differ diff --git a/art/textures/vis-red.png b/art/textures/vis-red.png new file mode 100644 index 00000000..e4663d01 Binary files /dev/null and b/art/textures/vis-red.png differ diff --git a/art/textures/white.png b/art/textures/white.png new file mode 100644 index 00000000..5c947040 Binary files /dev/null and b/art/textures/white.png differ diff --git a/art/textures/window-bg.png b/art/textures/window-bg.png new file mode 100644 index 00000000..cd316d13 Binary files /dev/null and b/art/textures/window-bg.png differ diff --git a/art/textures/window-noborder.9.png b/art/textures/window-noborder.9.png new file mode 100644 index 00000000..7e3521eb Binary files /dev/null and b/art/textures/window-noborder.9.png differ diff --git a/art/textures/window.9.png b/art/textures/window.9.png new file mode 100644 index 00000000..f01cb404 Binary files /dev/null and b/art/textures/window.9.png differ diff --git a/assets/configs/app.properties b/assets/configs/app.properties new file mode 100644 index 00000000..9759e31c --- /dev/null +++ b/assets/configs/app.properties @@ -0,0 +1 @@ +version=0.0.1 \ No newline at end of file diff --git a/assets/configs/config.pit b/assets/configs/config.pit new file mode 100644 index 00000000..5634e920 --- /dev/null +++ b/assets/configs/config.pit @@ -0,0 +1 @@ +{"lastOpenedSystemPath":"/home/kalculon/Documents/HyperLap2D/Test5","lastImportedSystemPath":"/mnt/Data/Red&Black/graphics/rolly-monkey-graphics"} \ No newline at end of file diff --git a/assets/cursors/cross.png b/assets/cursors/cross.png new file mode 100644 index 00000000..4dcd07d9 Binary files /dev/null and b/assets/cursors/cross.png differ diff --git a/assets/cursors/eyedropper.png b/assets/cursors/eyedropper.png new file mode 100644 index 00000000..2bbe79f6 Binary files /dev/null and b/assets/cursors/eyedropper.png differ diff --git a/assets/cursors/fingerpoint.png b/assets/cursors/fingerpoint.png new file mode 100644 index 00000000..5def5ab3 Binary files /dev/null and b/assets/cursors/fingerpoint.png differ diff --git a/assets/cursors/label-tool.png b/assets/cursors/label-tool.png new file mode 100644 index 00000000..aecb1bca Binary files /dev/null and b/assets/cursors/label-tool.png differ diff --git a/assets/cursors/label.png b/assets/cursors/label.png new file mode 100644 index 00000000..c8465d5f Binary files /dev/null and b/assets/cursors/label.png differ diff --git a/assets/cursors/left-down-up.png b/assets/cursors/left-down-up.png new file mode 100644 index 00000000..16e83c3f Binary files /dev/null and b/assets/cursors/left-down-up.png differ diff --git a/assets/cursors/left-right.png b/assets/cursors/left-right.png new file mode 100644 index 00000000..2129ca23 Binary files /dev/null and b/assets/cursors/left-right.png differ diff --git a/assets/cursors/left-rotate-down.png b/assets/cursors/left-rotate-down.png new file mode 100644 index 00000000..06e00b00 Binary files /dev/null and b/assets/cursors/left-rotate-down.png differ diff --git a/assets/cursors/left-rotate-up.png b/assets/cursors/left-rotate-up.png new file mode 100644 index 00000000..8dc1d6b2 Binary files /dev/null and b/assets/cursors/left-rotate-up.png differ diff --git a/assets/cursors/normal.png b/assets/cursors/normal.png new file mode 100644 index 00000000..cd20c549 Binary files /dev/null and b/assets/cursors/normal.png differ diff --git a/assets/cursors/right-down-up.png b/assets/cursors/right-down-up.png new file mode 100644 index 00000000..e87753cd Binary files /dev/null and b/assets/cursors/right-down-up.png differ diff --git a/assets/cursors/right-rotate-down.png b/assets/cursors/right-rotate-down.png new file mode 100644 index 00000000..73f56a9e Binary files /dev/null and b/assets/cursors/right-rotate-down.png differ diff --git a/assets/cursors/right-rotate-up.png b/assets/cursors/right-rotate-up.png new file mode 100644 index 00000000..3cfeb25b Binary files /dev/null and b/assets/cursors/right-rotate-up.png differ diff --git a/assets/cursors/rotate-left.png b/assets/cursors/rotate-left.png new file mode 100644 index 00000000..098ae7d2 Binary files /dev/null and b/assets/cursors/rotate-left.png differ diff --git a/assets/cursors/rotate-right.png b/assets/cursors/rotate-right.png new file mode 100644 index 00000000..14fc0166 Binary files /dev/null and b/assets/cursors/rotate-right.png differ diff --git a/assets/cursors/selection.png b/assets/cursors/selection.png new file mode 100644 index 00000000..1ff988f2 Binary files /dev/null and b/assets/cursors/selection.png differ diff --git a/assets/cursors/up-down.png b/assets/cursors/up-down.png new file mode 100644 index 00000000..549b0ba8 Binary files /dev/null and b/assets/cursors/up-down.png differ diff --git a/assets/freetypefonts/Roboto-Medium.ttf b/assets/freetypefonts/Roboto-Medium.ttf new file mode 100644 index 00000000..a3c1a1f1 Binary files /dev/null and b/assets/freetypefonts/Roboto-Medium.ttf differ diff --git a/assets/freetypefonts/arial.ttf b/assets/freetypefonts/arial.ttf new file mode 100644 index 00000000..4ba94d11 Binary files /dev/null and b/assets/freetypefonts/arial.ttf differ diff --git a/assets/hyperlap_icon_16.png b/assets/hyperlap_icon_16.png new file mode 100644 index 00000000..c0cf3c58 Binary files /dev/null and b/assets/hyperlap_icon_16.png differ diff --git a/assets/hyperlap_icon_32.png b/assets/hyperlap_icon_32.png new file mode 100644 index 00000000..4f226193 Binary files /dev/null and b/assets/hyperlap_icon_32.png differ diff --git a/assets/hyperlap_icon_48.png b/assets/hyperlap_icon_48.png new file mode 100644 index 00000000..de1858d2 Binary files /dev/null and b/assets/hyperlap_icon_48.png differ diff --git a/assets/hyperlap_icon_96.png b/assets/hyperlap_icon_96.png new file mode 100644 index 00000000..38db1305 Binary files /dev/null and b/assets/hyperlap_icon_96.png differ diff --git a/assets/plugins/plugin-9patch-0.0.1.jar b/assets/plugins/plugin-9patch-0.0.1.jar new file mode 100644 index 00000000..fcbc3c23 Binary files /dev/null and b/assets/plugins/plugin-9patch-0.0.1.jar differ diff --git a/assets/plugins/plugin-performance-0.0.1.jar b/assets/plugins/plugin-performance-0.0.1.jar new file mode 100644 index 00000000..35aeb04b Binary files /dev/null and b/assets/plugins/plugin-performance-0.0.1.jar differ diff --git a/assets/plugins/plugin-tiled-0.0.1.jar b/assets/plugins/plugin-tiled-0.0.1.jar new file mode 100644 index 00000000..1a5f899d Binary files /dev/null and b/assets/plugins/plugin-tiled-0.0.1.jar differ diff --git a/assets/splash/myriad.fnt b/assets/splash/myriad.fnt new file mode 100644 index 00000000..3c993398 --- /dev/null +++ b/assets/splash/myriad.fnt @@ -0,0 +1,204 @@ +info face="MyriadPro-Regular" size=11 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=14 base=9 scaleW=512 scaleH=512 pages=1 packed=0 +page id=0 file="myriad.png" +chars count=97 +char id=0 x=182 y=16 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=10 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=0 page=0 chnl=0 +char id=32 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=2 page=0 chnl=0 +char id=33 x=488 y=0 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=34 x=482 y=0 width=6 height=16 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=35 x=142 y=16 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=36 x=100 y=16 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=37 x=113 y=16 width=11 height=16 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=38 x=157 y=16 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=39 x=504 y=0 width=4 height=16 xoffset=-1 yoffset=-1 xadvance=2 page=0 chnl=0 +char id=40 x=16 y=16 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=41 x=21 y=16 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=42 x=175 y=16 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=43 x=124 y=16 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=44 x=4 y=16 width=4 height=16 xoffset=-1 yoffset=-1 xadvance=2 page=0 chnl=0 +char id=45 x=108 y=16 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=46 x=0 y=16 width=4 height=16 xoffset=-1 yoffset=-1 xadvance=2 page=0 chnl=0 +char id=47 x=69 y=16 width=6 height=16 xoffset=-2 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=48 x=474 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=49 x=402 y=0 width=8 height=16 xoffset=0 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=50 x=410 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=51 x=418 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=52 x=426 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=53 x=434 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=54 x=442 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=55 x=450 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=56 x=458 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=57 x=466 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=58 x=12 y=16 width=4 height=16 xoffset=-1 yoffset=-1 xadvance=2 page=0 chnl=0 +char id=59 x=8 y=16 width=4 height=16 xoffset=-1 yoffset=-1 xadvance=2 page=0 chnl=0 +char id=60 x=46 y=16 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=61 x=133 y=16 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=62 x=55 y=16 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=63 x=498 y=0 width=6 height=16 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=64 x=75 y=16 width=10 height=16 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=65 x=0 y=0 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=66 x=9 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=67 x=17 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=68 x=25 y=0 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=69 x=34 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=70 x=41 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=71 x=48 y=0 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=72 x=57 y=0 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=73 x=66 y=0 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=74 x=71 y=0 width=6 height=16 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=75 x=77 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=76 x=85 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=77 x=92 y=0 width=11 height=16 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=78 x=103 y=0 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=79 x=112 y=0 width=10 height=16 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=80 x=122 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=81 x=130 y=0 width=10 height=16 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=82 x=140 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=83 x=148 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=84 x=155 y=0 width=7 height=16 xoffset=-2 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=85 x=162 y=0 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=86 x=171 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=87 x=179 y=0 width=11 height=16 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=88 x=190 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=89 x=198 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=90 x=206 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=91 x=26 y=16 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=92 x=85 y=16 width=6 height=16 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=93 x=31 y=16 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=94 x=91 y=16 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=95 x=149 y=16 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=96 x=493 y=0 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=97 x=214 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=98 x=221 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=99 x=229 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=100 x=236 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=101 x=244 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=102 x=252 y=0 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=103 x=257 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=104 x=265 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=105 x=273 y=0 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=106 x=278 y=0 width=5 height=16 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=107 x=283 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=108 x=290 y=0 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=109 x=295 y=0 width=11 height=16 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=110 x=306 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=111 x=314 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=112 x=322 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=113 x=330 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=114 x=338 y=0 width=6 height=16 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=115 x=344 y=0 width=6 height=16 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=116 x=350 y=0 width=6 height=16 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=117 x=356 y=0 width=8 height=16 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=118 x=364 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=119 x=371 y=0 width=10 height=16 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=120 x=381 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=121 x=388 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=122 x=395 y=0 width=7 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=123 x=36 y=16 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=124 x=64 y=16 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=125 x=41 y=16 width=5 height=16 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=126 x=166 y=16 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +kernings count=102 +kerning first=34 second=74 amount=-1 +kerning first=76 second=87 amount=-1 +kerning first=65 second=89 amount=-1 +kerning first=65 second=34 amount=-1 +kerning first=89 second=111 amount=-1 +kerning first=39 second=74 amount=-1 +kerning first=102 second=39 amount=1 +kerning first=40 second=84 amount=1 +kerning first=44 second=34 amount=-1 +kerning first=102 second=93 amount=1 +kerning first=123 second=106 amount=1 +kerning first=84 second=115 amount=-1 +kerning first=70 second=74 amount=-1 +kerning first=97 second=84 amount=-1 +kerning first=91 second=87 amount=1 +kerning first=76 second=84 amount=-1 +kerning first=89 second=74 amount=-1 +kerning first=65 second=86 amount=-1 +kerning first=86 second=65 amount=-1 +kerning first=86 second=44 amount=-1 +kerning first=84 second=65 amount=-1 +kerning first=89 second=100 amount=-1 +kerning first=84 second=99 amount=-1 +kerning first=89 second=45 amount=-1 +kerning first=84 second=44 amount=-1 +kerning first=76 second=89 amount=-1 +kerning first=86 second=125 amount=1 +kerning first=76 second=34 amount=-1 +kerning first=89 second=113 amount=-1 +kerning first=40 second=86 amount=1 +kerning first=91 second=84 amount=1 +kerning first=84 second=125 amount=1 +kerning first=80 second=65 amount=-1 +kerning first=110 second=84 amount=-1 +kerning first=32 second=89 amount=-1 +kerning first=86 second=41 amount=1 +kerning first=80 second=44 amount=-2 +kerning first=123 second=87 amount=1 +kerning first=89 second=97 amount=-1 +kerning first=84 second=41 amount=1 +kerning first=76 second=86 amount=-1 +kerning first=46 second=39 amount=-1 +kerning first=45 second=84 amount=-1 +kerning first=86 second=46 amount=-1 +kerning first=34 second=65 amount=-1 +kerning first=84 second=122 amount=-1 +kerning first=65 second=39 amount=-1 +kerning first=44 second=39 amount=-1 +kerning first=34 second=44 amount=-1 +kerning first=84 second=101 amount=-1 +kerning first=39 second=65 amount=-1 +kerning first=104 second=84 amount=-1 +kerning first=86 second=93 amount=1 +kerning first=84 second=46 amount=-1 +kerning first=39 second=44 amount=-1 +kerning first=89 second=115 amount=-1 +kerning first=114 second=44 amount=-1 +kerning first=123 second=84 amount=1 +kerning first=45 second=89 amount=-1 +kerning first=84 second=93 amount=1 +kerning first=91 second=86 amount=1 +kerning first=70 second=65 amount=-1 +kerning first=80 second=46 amount=-2 +kerning first=70 second=44 amount=-1 +kerning first=89 second=65 amount=-1 +kerning first=89 second=99 amount=-1 +kerning first=89 second=44 amount=-1 +kerning first=102 second=34 amount=1 +kerning first=40 second=106 amount=1 +kerning first=87 second=65 amount=-1 +kerning first=84 second=111 amount=-1 +kerning first=87 second=44 amount=-1 +kerning first=76 second=39 amount=-1 +kerning first=89 second=125 amount=1 +kerning first=34 second=46 amount=-1 +kerning first=84 second=103 amount=-1 +kerning first=39 second=46 amount=-1 +kerning first=87 second=125 amount=1 +kerning first=89 second=117 amount=-1 +kerning first=114 second=46 amount=-1 +kerning first=123 second=86 amount=1 +kerning first=89 second=41 amount=1 +kerning first=65 second=87 amount=-1 +kerning first=87 second=41 amount=1 +kerning first=70 second=46 amount=-1 +kerning first=89 second=101 amount=-1 +kerning first=109 second=84 amount=-1 +kerning first=84 second=100 amount=-1 +kerning first=89 second=46 amount=-1 +kerning first=84 second=45 amount=-1 +kerning first=102 second=125 amount=1 +kerning first=80 second=74 amount=-1 +kerning first=84 second=113 amount=-1 +kerning first=91 second=106 amount=1 +kerning first=40 second=87 amount=1 +kerning first=89 second=93 amount=1 +kerning first=87 second=46 amount=-1 +kerning first=65 second=84 amount=-1 +kerning first=102 second=41 amount=1 +kerning first=87 second=93 amount=1 +kerning first=46 second=34 amount=-1 +kerning first=84 second=97 amount=-1 diff --git a/assets/splash/myriad.png b/assets/splash/myriad.png new file mode 100644 index 00000000..150cedf3 Binary files /dev/null and b/assets/splash/myriad.png differ diff --git a/assets/splash/roboto.fnt b/assets/splash/roboto.fnt new file mode 100644 index 00000000..44d9c4c2 --- /dev/null +++ b/assets/splash/roboto.fnt @@ -0,0 +1,99 @@ +info face="Roboto Medium" size=11 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=0,0 +common lineHeight=14 base=11 scaleW=512 scaleH=512 pages=1 packed=0 +page id=0 file="roboto.png" +chars count=94 +char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=11 xadvance=3 page=0 chnl=0 +char id=36 x=0 y=0 width=7 height=13 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=0 +char id=93 x=7 y=0 width=4 height=13 xoffset=0 yoffset=1 xadvance=3 page=0 chnl=0 +char id=91 x=11 y=0 width=4 height=13 xoffset=0 yoffset=1 xadvance=3 page=0 chnl=0 +char id=41 x=15 y=0 width=5 height=13 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 +char id=40 x=20 y=0 width=5 height=13 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 +char id=106 x=25 y=0 width=5 height=13 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=64 x=30 y=0 width=11 height=12 xoffset=0 yoffset=3 xadvance=10 page=0 chnl=0 +char id=125 x=41 y=0 width=5 height=12 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 +char id=123 x=46 y=0 width=5 height=12 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 +char id=124 x=51 y=0 width=3 height=11 xoffset=0 yoffset=3 xadvance=3 page=0 chnl=0 +char id=100 x=54 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=0 +char id=98 x=61 y=0 width=7 height=11 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=0 +char id=81 x=68 y=0 width=9 height=11 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=38 x=77 y=0 width=8 height=10 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=37 x=85 y=0 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=92 x=94 y=0 width=6 height=10 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=0 +char id=47 x=100 y=0 width=5 height=10 xoffset=0 yoffset=3 xadvance=4 page=0 chnl=0 +char id=59 x=105 y=0 width=4 height=10 xoffset=0 yoffset=4 xadvance=3 page=0 chnl=0 +char id=63 x=109 y=0 width=6 height=10 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=0 +char id=33 x=115 y=0 width=4 height=10 xoffset=0 yoffset=3 xadvance=3 page=0 chnl=0 +char id=48 x=119 y=0 width=7 height=10 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=57 x=126 y=0 width=7 height=10 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=56 x=133 y=0 width=7 height=10 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=54 x=140 y=0 width=7 height=10 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=53 x=147 y=0 width=7 height=10 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=51 x=154 y=0 width=7 height=10 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=121 x=161 y=0 width=7 height=10 xoffset=0 yoffset=5 xadvance=5 page=0 chnl=0 +char id=116 x=168 y=0 width=5 height=10 xoffset=0 yoffset=3 xadvance=4 page=0 chnl=0 +char id=113 x=173 y=0 width=7 height=10 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=112 x=180 y=0 width=7 height=10 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=108 x=187 y=0 width=4 height=10 xoffset=0 yoffset=2 xadvance=3 page=0 chnl=0 +char id=107 x=191 y=0 width=7 height=10 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=0 +char id=105 x=198 y=0 width=4 height=10 xoffset=0 yoffset=2 xadvance=3 page=0 chnl=0 +char id=104 x=202 y=0 width=7 height=10 xoffset=0 yoffset=2 xadvance=6 page=0 chnl=0 +char id=103 x=209 y=0 width=7 height=10 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=102 x=216 y=0 width=5 height=10 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 +char id=85 x=221 y=0 width=8 height=10 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=83 x=229 y=0 width=8 height=10 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=79 x=237 y=0 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=74 x=246 y=0 width=7 height=10 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=71 x=253 y=0 width=8 height=10 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=67 x=261 y=0 width=8 height=10 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=35 x=269 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=58 x=277 y=0 width=4 height=9 xoffset=0 yoffset=4 xadvance=3 page=0 chnl=0 +char id=55 x=281 y=0 width=7 height=9 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=52 x=288 y=0 width=7 height=9 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=50 x=295 y=0 width=7 height=9 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=49 x=302 y=0 width=6 height=9 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=90 x=308 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=89 x=316 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=88 x=324 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=87 x=332 y=0 width=11 height=9 xoffset=0 yoffset=3 xadvance=10 page=0 chnl=0 +char id=86 x=343 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=84 x=351 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=82 x=359 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=80 x=367 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=78 x=375 y=0 width=9 height=9 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=77 x=384 y=0 width=10 height=9 xoffset=0 yoffset=3 xadvance=10 page=0 chnl=0 +char id=76 x=394 y=0 width=7 height=9 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=75 x=401 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=73 x=409 y=0 width=4 height=9 xoffset=0 yoffset=3 xadvance=3 page=0 chnl=0 +char id=72 x=413 y=0 width=9 height=9 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=70 x=422 y=0 width=7 height=9 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=69 x=429 y=0 width=7 height=9 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=68 x=436 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=66 x=444 y=0 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=65 x=452 y=0 width=9 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=43 x=461 y=0 width=7 height=8 xoffset=0 yoffset=4 xadvance=6 page=0 chnl=0 +char id=117 x=468 y=0 width=7 height=8 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=115 x=475 y=0 width=7 height=8 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=111 x=482 y=0 width=7 height=8 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=101 x=489 y=0 width=7 height=8 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=99 x=496 y=0 width=7 height=8 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=97 x=503 y=0 width=7 height=8 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=62 x=0 y=13 width=7 height=7 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=122 x=7 y=13 width=7 height=7 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=120 x=14 y=13 width=7 height=7 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=119 x=21 y=13 width=9 height=7 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 +char id=118 x=30 y=13 width=7 height=7 xoffset=0 yoffset=5 xadvance=5 page=0 chnl=0 +char id=114 x=37 y=13 width=5 height=7 xoffset=0 yoffset=5 xadvance=4 page=0 chnl=0 +char id=110 x=42 y=13 width=7 height=7 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=109 x=49 y=13 width=10 height=7 xoffset=0 yoffset=5 xadvance=10 page=0 chnl=0 +char id=42 x=59 y=13 width=6 height=6 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=0 +char id=61 x=65 y=13 width=7 height=6 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=94 x=72 y=13 width=6 height=6 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=0 +char id=60 x=78 y=13 width=6 height=6 xoffset=0 yoffset=5 xadvance=6 page=0 chnl=0 +char id=44 x=84 y=13 width=3 height=5 xoffset=0 yoffset=9 xadvance=2 page=0 chnl=0 +char id=39 x=87 y=13 width=3 height=5 xoffset=0 yoffset=2 xadvance=2 page=0 chnl=0 +char id=34 x=90 y=13 width=5 height=5 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 +char id=126 x=95 y=13 width=8 height=4 xoffset=0 yoffset=6 xadvance=7 page=0 chnl=0 +char id=95 x=103 y=13 width=6 height=4 xoffset=0 yoffset=10 xadvance=5 page=0 chnl=0 +char id=46 x=109 y=13 width=4 height=4 xoffset=0 yoffset=9 xadvance=3 page=0 chnl=0 +char id=96 x=113 y=13 width=4 height=4 xoffset=0 yoffset=2 xadvance=4 page=0 chnl=0 +char id=45 x=117 y=13 width=5 height=3 xoffset=0 yoffset=7 xadvance=4 page=0 chnl=0 diff --git a/assets/splash/roboto.png b/assets/splash/roboto.png new file mode 100644 index 00000000..3a4ec9b9 Binary files /dev/null and b/assets/splash/roboto.png differ diff --git a/assets/splash/splash.atlas b/assets/splash/splash.atlas new file mode 100644 index 00000000..efc99f91 --- /dev/null +++ b/assets/splash/splash.atlas @@ -0,0 +1,34 @@ + +splash.png +size: 512,512 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +bg_color + rotate: false + xy: 471, 480 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +splash_bg + rotate: false + xy: 2, 122 + size: 467, 366 + orig: 467, 366 + offset: 0, 0 + index: -1 +splash_logo + rotate: false + xy: 2, 2 + size: 76, 72 + orig: 76, 72 + offset: 0, 0 + index: -1 +splash_logo_text + rotate: false + xy: 2, 76 + size: 191, 44 + orig: 191, 44 + offset: 0, 0 + index: -1 diff --git a/assets/splash/splash.png b/assets/splash/splash.png new file mode 100644 index 00000000..8c1e5722 Binary files /dev/null and b/assets/splash/splash.png differ diff --git a/assets/style/bglogo.png b/assets/style/bglogo.png new file mode 100644 index 00000000..693627ea Binary files /dev/null and b/assets/style/bglogo.png differ diff --git a/assets/style/myriad-medium-big.fnt b/assets/style/myriad-medium-big.fnt new file mode 100644 index 00000000..52bdba57 --- /dev/null +++ b/assets/style/myriad-medium-big.fnt @@ -0,0 +1,4827 @@ +info face="MyriadPro-Regular" size=16 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=20 base=12 scaleW=256 scaleH=512 pages=1 packed=0 +page id=0 file="myriad-medium-big.png" +chars count=506 +char id=0 x=210 y=127 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=13 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=0 page=0 chnl=0 +char id=33 x=250 y=113 width=5 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=34 x=205 y=253 width=7 height=6 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=35 x=220 y=127 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=36 x=102 y=19 width=9 height=16 xoffset=0 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=37 x=110 y=84 width=15 height=14 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=0 +char id=38 x=230 y=127 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=39 x=212 y=253 width=5 height=6 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=40 x=111 y=19 width=6 height=16 xoffset=0 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=41 x=117 y=19 width=6 height=16 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=42 x=88 y=253 width=9 height=8 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=43 x=185 y=219 width=11 height=11 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=44 x=148 y=253 width=5 height=7 xoffset=-1 yoffset=9 xadvance=3 page=0 chnl=0 +char id=45 x=68 y=263 width=7 height=4 xoffset=-1 yoffset=6 xadvance=5 page=0 chnl=0 +char id=46 x=6 y=263 width=5 height=5 xoffset=-1 yoffset=8 xadvance=3 page=0 chnl=0 +char id=47 x=125 y=84 width=9 height=14 xoffset=-2 yoffset=0 xadvance=5 page=0 chnl=0 +char id=48 x=242 y=127 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=49 x=0 y=141 width=7 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=50 x=7 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=51 x=17 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=52 x=27 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=53 x=37 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=54 x=47 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=55 x=57 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=56 x=67 y=141 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=57 x=134 y=84 width=10 height=14 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=58 x=248 y=219 width=5 height=10 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=59 x=98 y=219 width=5 height=12 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=0 +char id=60 x=196 y=219 width=10 height=11 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=0 +char id=61 x=217 y=253 width=11 height=6 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=0 +char id=62 x=206 y=219 width=10 height=11 xoffset=0 yoffset=2 xadvance=10 page=0 chnl=0 +char id=63 x=77 y=141 width=8 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=64 x=144 y=84 width=14 height=14 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=0 +char id=65 x=85 y=141 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=66 x=97 y=141 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=67 x=107 y=141 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=68 x=118 y=141 width=12 height=13 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=69 x=130 y=141 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=70 x=139 y=141 width=8 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=71 x=147 y=141 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=72 x=159 y=141 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=73 x=251 y=84 width=4 height=13 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=74 x=170 y=141 width=7 height=13 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=75 x=177 y=141 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=76 x=187 y=141 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=77 x=196 y=141 width=14 height=13 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=0 +char id=78 x=210 y=141 width=11 height=13 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=79 x=221 y=141 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=80 x=234 y=141 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=81 x=179 y=68 width=13 height=15 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=82 x=243 y=141 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=83 x=0 y=154 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=84 x=10 y=154 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=85 x=21 y=154 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=86 x=32 y=154 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=87 x=43 y=154 width=16 height=13 xoffset=-1 yoffset=0 xadvance=14 page=0 chnl=0 +char id=88 x=59 y=154 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=89 x=70 y=154 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=90 x=81 y=154 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=91 x=192 y=68 width=6 height=15 xoffset=0 yoffset=0 xadvance=5 page=0 chnl=0 +char id=92 x=158 y=84 width=8 height=14 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=93 x=198 y=68 width=6 height=15 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=94 x=14 y=232 width=11 height=10 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=95 x=94 y=263 width=10 height=3 xoffset=-1 yoffset=12 xadvance=8 page=0 chnl=0 +char id=96 x=11 y=263 width=6 height=5 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=97 x=25 y=232 width=9 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=98 x=166 y=84 width=10 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=99 x=34 y=232 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=100 x=176 y=84 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=101 x=43 y=232 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=102 x=186 y=84 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=103 x=194 y=84 width=10 height=14 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=104 x=204 y=84 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=105 x=250 y=68 width=5 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=106 x=100 y=0 width=6 height=17 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=107 x=213 y=84 width=9 height=14 xoffset=0 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=108 x=251 y=52 width=4 height=14 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=109 x=53 y=232 width=14 height=10 xoffset=0 yoffset=3 xadvance=13 page=0 chnl=0 +char id=110 x=67 y=232 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=111 x=76 y=232 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=112 x=222 y=84 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=113 x=232 y=84 width=10 height=14 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=114 x=87 y=232 width=6 height=10 xoffset=0 yoffset=3 xadvance=5 page=0 chnl=0 +char id=115 x=93 y=232 width=8 height=10 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=116 x=103 y=219 width=7 height=12 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=117 x=101 y=232 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=118 x=110 y=232 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=119 x=120 y=232 width=14 height=10 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=120 x=134 y=232 width=10 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=121 x=204 y=68 width=10 height=15 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=122 x=144 y=232 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=123 x=214 y=68 width=7 height=15 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=124 x=20 y=0 width=4 height=18 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=125 x=221 y=68 width=7 height=15 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=126 x=17 y=263 width=11 height=5 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=0 +char id=160 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=161 x=92 y=154 width=5 height=13 xoffset=-1 yoffset=3 xadvance=4 page=0 chnl=0 +char id=162 x=242 y=84 width=9 height=14 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=163 x=97 y=154 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=164 x=216 y=219 width=10 height=11 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=165 x=107 y=154 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=166 x=123 y=19 width=4 height=16 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=167 x=0 y=99 width=10 height=14 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=168 x=75 y=263 width=7 height=4 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=169 x=117 y=154 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=170 x=153 y=253 width=7 height=7 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=171 x=97 y=253 width=9 height=8 xoffset=-1 yoffset=4 xadvance=7 page=0 chnl=0 +char id=172 x=160 y=253 width=11 height=7 xoffset=-1 yoffset=5 xadvance=10 page=0 chnl=0 +char id=173 x=82 y=263 width=7 height=4 xoffset=-1 yoffset=6 xadvance=5 page=0 chnl=0 +char id=174 x=106 y=253 width=9 height=8 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=175 x=104 y=263 width=7 height=3 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=176 x=228 y=253 width=7 height=6 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=177 x=110 y=219 width=11 height=12 xoffset=-1 yoffset=1 xadvance=10 page=0 chnl=0 +char id=178 x=115 y=253 width=7 height=8 xoffset=-1 yoffset=-2 xadvance=5 page=0 chnl=0 +char id=179 x=81 y=253 width=7 height=9 xoffset=-1 yoffset=-3 xadvance=5 page=0 chnl=0 +char id=180 x=28 y=263 width=6 height=5 xoffset=0 yoffset=0 xadvance=5 page=0 chnl=0 +char id=181 x=10 y=99 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=182 x=228 y=68 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=183 x=89 y=263 width=5 height=4 xoffset=-1 yoffset=6 xadvance=3 page=0 chnl=0 +char id=184 x=235 y=253 width=6 height=6 xoffset=-1 yoffset=11 xadvance=5 page=0 chnl=0 +char id=185 x=122 y=253 width=5 height=8 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=186 x=171 y=253 width=8 height=7 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=187 x=127 y=253 width=9 height=8 xoffset=-1 yoffset=4 xadvance=7 page=0 chnl=0 +char id=188 x=130 y=154 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=189 x=144 y=154 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=190 x=158 y=154 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=191 x=20 y=99 width=8 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=192 x=127 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=193 x=139 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=194 x=151 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=195 x=163 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=196 x=175 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=197 x=187 y=19 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=198 x=172 y=154 width=16 height=13 xoffset=-2 yoffset=0 xadvance=13 page=0 chnl=0 +char id=199 x=106 y=0 width=11 height=17 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=200 x=199 y=19 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=201 x=208 y=19 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=202 x=217 y=19 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=203 x=226 y=19 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=204 x=235 y=19 width=6 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=205 x=241 y=19 width=6 height=16 xoffset=0 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=206 x=247 y=19 width=8 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=207 x=0 y=36 width=8 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=208 x=188 y=154 width=14 height=13 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=209 x=8 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=210 x=19 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=211 x=32 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=212 x=45 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=213 x=58 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=214 x=71 y=36 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=215 x=226 y=219 width=11 height=11 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=216 x=237 y=68 width=13 height=15 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=0 +char id=217 x=84 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=218 x=95 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=219 x=106 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=220 x=117 y=36 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=221 x=128 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=222 x=202 y=154 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=223 x=28 y=99 width=10 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=224 x=38 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=225 x=47 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=226 x=56 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=227 x=211 y=154 width=9 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=228 x=220 y=154 width=9 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=229 x=65 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=230 x=153 y=232 width=14 height=10 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=231 x=74 y=99 width=9 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=232 x=83 y=99 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=233 x=93 y=99 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=234 x=103 y=99 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=235 x=229 y=154 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=236 x=113 y=99 width=6 height=14 xoffset=-2 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=237 x=119 y=99 width=6 height=14 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=238 x=125 y=99 width=7 height=14 xoffset=-2 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=239 x=239 y=154 width=8 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=240 x=132 y=99 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=241 x=0 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=242 x=143 y=99 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=243 x=154 y=99 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=244 x=165 y=99 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=245 x=9 y=167 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=246 x=20 y=167 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=247 x=167 y=232 width=11 height=10 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=248 x=121 y=219 width=11 height=12 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=249 x=176 y=99 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=250 x=185 y=99 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=251 x=194 y=99 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=252 x=31 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=253 x=0 y=0 width=10 height=19 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=254 x=117 y=0 width=10 height=17 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=255 x=24 y=0 width=10 height=18 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=256 x=0 y=84 width=12 height=15 xoffset=-1 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=257 x=132 y=219 width=9 height=12 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=258 x=139 y=36 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=259 x=40 y=167 width=9 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=260 x=127 y=0 width=12 height=17 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=261 x=203 y=99 width=10 height=14 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=262 x=151 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=263 x=213 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=264 x=162 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=265 x=222 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=266 x=173 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=267 x=49 y=167 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=268 x=184 y=36 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=269 x=231 y=99 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=270 x=195 y=36 width=12 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=271 x=240 y=99 width=14 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=272 x=58 y=167 width=14 height=13 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=273 x=0 y=113 width=12 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=274 x=12 y=84 width=9 height=15 xoffset=0 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=275 x=141 y=219 width=10 height=12 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=276 x=207 y=36 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=277 x=72 y=167 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=278 x=216 y=36 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=279 x=82 y=167 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=280 x=139 y=0 width=9 height=17 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=281 x=12 y=113 width=10 height=14 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=282 x=225 y=36 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=283 x=22 y=113 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=284 x=234 y=36 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=285 x=34 y=0 width=10 height=18 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=286 x=0 y=52 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=287 x=148 y=0 width=10 height=17 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=288 x=12 y=52 width=12 height=16 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=289 x=158 y=0 width=10 height=17 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=290 x=168 y=0 width=12 height=17 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=291 x=44 y=0 width=10 height=18 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=292 x=24 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=293 x=180 y=0 width=11 height=17 xoffset=-2 yoffset=-4 xadvance=9 page=0 chnl=0 +char id=294 x=92 y=167 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=295 x=32 y=113 width=11 height=14 xoffset=-2 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=296 x=246 y=36 width=7 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=297 x=247 y=154 width=7 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=298 x=21 y=84 width=6 height=15 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=299 x=105 y=167 width=6 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=300 x=35 y=52 width=7 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=301 x=111 y=167 width=7 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=302 x=191 y=0 width=6 height=17 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=303 x=197 y=0 width=6 height=17 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=304 x=42 y=52 width=4 height=16 xoffset=0 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=305 x=178 y=232 width=4 height=10 xoffset=0 yoffset=3 xadvance=4 page=0 chnl=0 +char id=306 x=118 y=167 width=10 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=307 x=203 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=308 x=46 y=52 width=9 height=16 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=309 x=212 y=0 width=7 height=17 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=310 x=219 y=0 width=10 height=17 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=311 x=54 y=0 width=9 height=18 xoffset=0 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=312 x=182 y=232 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=313 x=55 y=52 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=314 x=229 y=0 width=7 height=17 xoffset=-1 yoffset=-4 xadvance=4 page=0 chnl=0 +char id=315 x=236 y=0 width=9 height=17 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=316 x=63 y=0 width=5 height=18 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=317 x=128 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=318 x=43 y=113 width=6 height=14 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=319 x=137 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=320 x=49 y=113 width=6 height=14 xoffset=0 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=321 x=146 y=167 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=322 x=55 y=113 width=6 height=14 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=323 x=64 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=324 x=61 y=113 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=325 x=0 y=19 width=11 height=17 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=326 x=70 y=113 width=9 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=327 x=75 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=328 x=79 y=113 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=329 x=88 y=113 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=330 x=11 y=19 width=11 height=17 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=331 x=157 y=167 width=9 height=13 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=332 x=27 y=84 width=13 height=15 xoffset=-1 yoffset=-2 xadvance=11 page=0 chnl=0 +char id=333 x=151 y=219 width=11 height=12 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=0 +char id=334 x=86 y=52 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=335 x=166 y=167 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=336 x=99 y=52 width=13 height=16 xoffset=-1 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=337 x=98 y=113 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=338 x=40 y=84 width=16 height=15 xoffset=-1 yoffset=-1 xadvance=14 page=0 chnl=0 +char id=339 x=191 y=232 width=16 height=10 xoffset=-1 yoffset=3 xadvance=14 page=0 chnl=0 +char id=340 x=112 y=52 width=10 height=16 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=341 x=109 y=113 width=6 height=14 xoffset=0 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=342 x=245 y=0 width=10 height=17 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=343 x=115 y=113 width=7 height=14 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=344 x=122 y=52 width=10 height=16 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=345 x=122 y=113 width=7 height=14 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=346 x=132 y=52 width=10 height=16 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=347 x=129 y=113 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=348 x=142 y=52 width=10 height=16 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=349 x=137 y=113 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=350 x=22 y=19 width=10 height=17 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=351 x=145 y=113 width=8 height=14 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=352 x=152 y=52 width=10 height=16 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=353 x=153 y=113 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=354 x=32 y=19 width=11 height=17 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=355 x=162 y=52 width=7 height=16 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=356 x=169 y=52 width=11 height=16 xoffset=-2 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=357 x=161 y=113 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=358 x=177 y=167 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=359 x=162 y=219 width=7 height=12 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=360 x=180 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=361 x=188 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=362 x=56 y=84 width=11 height=15 xoffset=0 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=363 x=197 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=364 x=191 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=365 x=206 y=167 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=366 x=202 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=367 x=169 y=113 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=368 x=213 y=52 width=11 height=16 xoffset=0 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=369 x=178 y=113 width=9 height=14 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=370 x=43 y=19 width=11 height=17 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=371 x=187 y=113 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=372 x=224 y=52 width=16 height=16 xoffset=-1 yoffset=-3 xadvance=14 page=0 chnl=0 +char id=373 x=197 y=113 width=14 height=14 xoffset=-1 yoffset=-1 xadvance=12 page=0 chnl=0 +char id=374 x=240 y=52 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=375 x=10 y=0 width=10 height=19 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=376 x=0 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=377 x=11 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=378 x=211 y=113 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=379 x=22 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=380 x=215 y=167 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=381 x=33 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=382 x=220 y=113 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=894 x=224 y=167 width=5 height=13 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=900 x=34 y=263 width=5 height=5 xoffset=0 yoffset=0 xadvance=5 page=0 chnl=0 +char id=901 x=39 y=263 width=8 height=5 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=902 x=229 y=167 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=903 x=47 y=263 width=5 height=5 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=0 +char id=904 x=241 y=167 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=905 x=0 y=180 width=13 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=906 x=13 y=180 width=6 height=13 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=908 x=19 y=180 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=910 x=33 y=180 width=14 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=911 x=47 y=180 width=14 height=13 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=912 x=229 y=113 width=8 height=14 xoffset=-2 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=913 x=61 y=180 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=914 x=73 y=180 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=915 x=83 y=180 width=8 height=13 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=916 x=91 y=180 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=917 x=103 y=180 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=918 x=112 y=180 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=919 x=123 y=180 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=920 x=134 y=180 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=921 x=147 y=180 width=4 height=13 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=922 x=151 y=180 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=923 x=161 y=180 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=924 x=173 y=180 width=14 height=13 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=0 +char id=925 x=187 y=180 width=11 height=13 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=926 x=198 y=180 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=927 x=209 y=180 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=928 x=222 y=180 width=10 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=929 x=232 y=180 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=931 x=241 y=180 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=932 x=0 y=193 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=933 x=11 y=193 width=12 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=934 x=237 y=113 width=13 height=14 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=0 +char id=935 x=23 y=193 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=936 x=34 y=193 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=937 x=47 y=193 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=938 x=44 y=68 width=8 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=939 x=67 y=84 width=12 height=15 xoffset=-1 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=940 x=60 y=193 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=941 x=71 y=193 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=942 x=54 y=19 width=10 height=17 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=943 x=80 y=193 width=5 height=13 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=944 x=0 y=127 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=945 x=207 y=232 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=946 x=68 y=0 width=10 height=18 xoffset=0 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=947 x=10 y=127 width=11 height=14 xoffset=-2 yoffset=3 xadvance=7 page=0 chnl=0 +char id=948 x=21 y=127 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=949 x=218 y=232 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=950 x=52 y=68 width=9 height=16 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=951 x=32 y=127 width=10 height=14 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=952 x=42 y=127 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=953 x=227 y=232 width=5 height=10 xoffset=0 yoffset=3 xadvance=4 page=0 chnl=0 +char id=954 x=232 y=232 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=955 x=52 y=127 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=956 x=62 y=127 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=957 x=241 y=232 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=958 x=64 y=19 width=9 height=17 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=959 x=0 y=243 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=960 x=11 y=243 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=961 x=72 y=127 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=962 x=85 y=193 width=9 height=13 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=963 x=237 y=219 width=11 height=11 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=964 x=22 y=243 width=10 height=10 xoffset=-2 yoffset=3 xadvance=7 page=0 chnl=0 +char id=965 x=32 y=243 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=966 x=79 y=84 width=12 height=15 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=967 x=82 y=127 width=10 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=968 x=73 y=19 width=12 height=17 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=969 x=42 y=243 width=13 height=10 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=970 x=94 y=193 width=8 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=971 x=102 y=193 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=972 x=112 y=193 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=973 x=123 y=193 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=974 x=133 y=193 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1025 x=61 y=68 width=9 height=16 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=1026 x=70 y=68 width=13 height=16 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1027 x=83 y=68 width=8 height=16 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=1028 x=146 y=193 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1029 x=157 y=193 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1030 x=167 y=193 width=4 height=13 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=1031 x=91 y=68 width=8 height=16 xoffset=-2 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=1032 x=171 y=193 width=7 height=13 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=1033 x=92 y=127 width=17 height=14 xoffset=-2 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1034 x=178 y=193 width=15 height=13 xoffset=0 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1035 x=193 y=193 width=13 height=13 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1036 x=99 y=68 width=10 height=16 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=1038 x=109 y=68 width=11 height=16 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=1039 x=120 y=68 width=10 height=16 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1040 x=206 y=193 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1041 x=218 y=193 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1042 x=228 y=193 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1043 x=238 y=193 width=8 height=13 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1044 x=130 y=68 width=12 height=16 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1045 x=246 y=193 width=9 height=13 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1046 x=0 y=206 width=15 height=13 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=0 +char id=1047 x=15 y=206 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1048 x=25 y=206 width=11 height=13 xoffset=0 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1049 x=142 y=68 width=11 height=16 xoffset=0 yoffset=-3 xadvance=11 page=0 chnl=0 +char id=1050 x=36 y=206 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1051 x=46 y=206 width=12 height=13 xoffset=-2 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1052 x=58 y=206 width=14 height=13 xoffset=-1 yoffset=0 xadvance=13 page=0 chnl=0 +char id=1053 x=72 y=206 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1054 x=83 y=206 width=13 height=13 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1055 x=96 y=206 width=11 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1056 x=107 y=206 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1057 x=116 y=206 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1058 x=127 y=206 width=11 height=13 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1059 x=138 y=206 width=11 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1060 x=109 y=127 width=13 height=14 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1061 x=149 y=206 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1062 x=153 y=68 width=11 height=16 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1063 x=160 y=206 width=10 height=13 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1064 x=170 y=206 width=14 height=13 xoffset=0 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1065 x=164 y=68 width=15 height=16 xoffset=0 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1066 x=184 y=206 width=13 height=13 xoffset=-2 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1067 x=197 y=206 width=12 height=13 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1068 x=209 y=206 width=10 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1069 x=219 y=206 width=11 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1070 x=230 y=206 width=15 height=13 xoffset=0 yoffset=0 xadvance=14 page=0 chnl=0 +char id=1071 x=245 y=206 width=10 height=13 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1072 x=55 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1073 x=122 y=127 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1074 x=64 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1075 x=73 y=243 width=7 height=10 xoffset=0 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1076 x=0 y=219 width=10 height=13 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1077 x=80 y=243 width=10 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1078 x=90 y=243 width=13 height=10 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1079 x=103 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1080 x=112 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1081 x=10 y=219 width=9 height=13 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1082 x=121 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1083 x=130 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1084 x=139 y=243 width=12 height=10 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=1085 x=151 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1086 x=160 y=243 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1087 x=171 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1088 x=132 y=127 width=10 height=14 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1089 x=180 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1090 x=189 y=243 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1091 x=91 y=84 width=10 height=15 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1092 x=78 y=0 width=12 height=18 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1093 x=198 y=243 width=10 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1094 x=19 y=219 width=10 height=13 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1095 x=208 y=243 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1096 x=217 y=243 width=12 height=10 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0 +char id=1097 x=29 y=219 width=13 height=13 xoffset=0 yoffset=3 xadvance=12 page=0 chnl=0 +char id=1098 x=229 y=243 width=11 height=10 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1099 x=240 y=243 width=11 height=10 xoffset=0 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1100 x=0 y=253 width=9 height=10 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1101 x=9 y=253 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1102 x=18 y=253 width=12 height=10 xoffset=0 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1103 x=30 y=253 width=9 height=10 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1105 x=42 y=219 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1106 x=85 y=19 width=11 height=17 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=1107 x=142 y=127 width=7 height=14 xoffset=0 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1108 x=39 y=253 width=9 height=10 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1109 x=48 y=253 width=8 height=10 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1110 x=52 y=219 width=5 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=1111 x=57 y=219 width=8 height=13 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=1112 x=96 y=19 width=6 height=17 xoffset=-2 yoffset=0 xadvance=4 page=0 chnl=0 +char id=1113 x=0 y=232 width=14 height=11 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=1114 x=56 y=253 width=13 height=10 xoffset=0 yoffset=3 xadvance=13 page=0 chnl=0 +char id=1115 x=149 y=127 width=11 height=14 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=1116 x=160 y=127 width=9 height=14 xoffset=0 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1118 x=90 y=0 width=10 height=18 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1119 x=65 y=219 width=9 height=13 xoffset=0 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1168 x=101 y=84 width=9 height=15 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=1169 x=169 y=219 width=7 height=12 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=0 +char id=1241 x=69 y=253 width=12 height=10 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=8204 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=8211 x=111 y=263 width=10 height=3 xoffset=-1 yoffset=6 xadvance=8 page=0 chnl=0 +char id=8212 x=121 y=263 width=18 height=3 xoffset=-1 yoffset=6 xadvance=16 page=0 chnl=0 +char id=8216 x=179 y=253 width=5 height=7 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=8217 x=184 y=253 width=5 height=7 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=8218 x=241 y=253 width=5 height=6 xoffset=-1 yoffset=9 xadvance=3 page=0 chnl=0 +char id=8220 x=189 y=253 width=8 height=7 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8221 x=197 y=253 width=8 height=7 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8222 x=246 y=253 width=8 height=6 xoffset=-1 yoffset=9 xadvance=6 page=0 chnl=0 +char id=8224 x=169 y=127 width=10 height=14 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=8225 x=179 y=127 width=10 height=14 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=8226 x=0 y=263 width=6 height=6 xoffset=-1 yoffset=5 xadvance=5 page=0 chnl=0 +char id=8230 x=52 y=263 width=16 height=5 xoffset=0 yoffset=8 xadvance=16 page=0 chnl=0 +char id=8240 x=189 y=127 width=21 height=14 xoffset=-1 yoffset=-1 xadvance=19 page=0 chnl=0 +char id=8249 x=136 y=253 width=6 height=8 xoffset=-1 yoffset=4 xadvance=4 page=0 chnl=0 +char id=8250 x=142 y=253 width=6 height=8 xoffset=-1 yoffset=4 xadvance=4 page=0 chnl=0 +char id=8260 x=74 y=219 width=14 height=13 xoffset=-4 yoffset=0 xadvance=2 page=0 chnl=0 +char id=8363 x=176 y=219 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=8364 x=88 y=219 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +kernings count=4316 +kerning first=362 second=913 amount=-1 +kerning first=8216 second=281 amount=-1 +kerning first=221 second=285 amount=-1 +kerning first=39 second=961 amount=-1 +kerning first=356 second=232 amount=-1 +kerning first=1090 second=8212 amount=-1 +kerning first=34 second=74 amount=-1 +kerning first=1027 second=1107 amount=-1 +kerning first=8218 second=376 amount=-2 +kerning first=86 second=248 amount=-1 +kerning first=8221 second=301 amount=-1 +kerning first=362 second=258 amount=-1 +kerning first=358 second=335 amount=-1 +kerning first=957 second=46 amount=-1 +kerning first=257 second=84 amount=-1 +kerning first=376 second=279 amount=-1 +kerning first=356 second=97 amount=-1 +kerning first=354 second=231 amount=-1 +kerning first=89 second=210 amount=-1 +kerning first=70 second=224 amount=-1 +kerning first=1058 second=1035 amount=1 +kerning first=910 second=965 amount=-1 +kerning first=8220 second=229 amount=-1 +kerning first=8216 second=937 amount=-1 +kerning first=1168 second=1040 amount=-1 +kerning first=76 second=87 amount=-1 +kerning first=208 second=8230 amount=-1 +kerning first=932 second=940 amount=-1 +kerning first=354 second=93 amount=1 +kerning first=229 second=932 amount=-1 +kerning first=939 second=959 amount=-1 +kerning first=321 second=173 amount=-1 +kerning first=932 second=244 amount=-1 +kerning first=220 second=198 amount=-1 +kerning first=915 second=71 amount=-1 +kerning first=929 second=923 amount=-1 +kerning first=221 second=308 amount=-1 +kerning first=86 second=279 amount=-1 +kerning first=358 second=227 amount=-1 +kerning first=192 second=39 amount=-1 +kerning first=8217 second=109 amount=-1 +kerning first=1043 second=1088 amount=-1 +kerning first=87 second=358 amount=1 +kerning first=196 second=221 amount=-1 +kerning first=279 second=932 amount=-1 +kerning first=65 second=89 amount=-1 +kerning first=947 second=44 amount=-1 +kerning first=87 second=267 amount=-1 +kerning first=221 second=369 amount=-1 +kerning first=315 second=262 amount=-1 +kerning first=196 second=84 amount=-1 +kerning first=1027 second=187 amount=-1 +kerning first=931 second=264 amount=-1 +kerning first=91 second=1058 amount=1 +kerning first=8218 second=358 amount=-1 +kerning first=1098 second=1091 amount=-1 +kerning first=84 second=361 amount=-1 +kerning first=915 second=941 amount=-1 +kerning first=939 second=181 amount=-1 +kerning first=1043 second=44 amount=-1 +kerning first=89 second=252 amount=-1 +kerning first=334 second=44 amount=-1 +kerning first=1043 second=1032 amount=-1 +kerning first=219 second=195 amount=-1 +kerning first=932 second=260 amount=-1 +kerning first=89 second=173 amount=-1 +kerning first=8216 second=940 amount=-1 +kerning first=1168 second=1074 amount=-1 +kerning first=354 second=285 amount=-1 +kerning first=8216 second=244 amount=-1 +kerning first=8220 second=281 amount=-1 +kerning first=221 second=242 amount=-1 +kerning first=65 second=34 amount=-1 +kerning first=227 second=8221 amount=-1 +kerning first=89 second=111 amount=-1 +kerning first=1059 second=1066 amount=1 +kerning first=84 second=973 amount=-1 +kerning first=931 second=8211 amount=-1 +kerning first=220 second=194 amount=-1 +kerning first=84 second=251 amount=-1 +kerning first=8217 second=324 amount=-1 +kerning first=109 second=356 amount=-1 +kerning first=230 second=354 amount=-1 +kerning first=933 second=45 amount=-1 +kerning first=160 second=86 amount=-1 +kerning first=1066 second=1059 amount=-1 +kerning first=902 second=39 amount=-1 +kerning first=1027 second=1085 amount=-1 +kerning first=319 second=8220 amount=-2 +kerning first=932 second=8249 amount=-1 +kerning first=358 second=287 amount=-1 +kerning first=8220 second=937 amount=-1 +kerning first=372 second=263 amount=-1 +kerning first=84 second=110 amount=-1 +kerning first=8221 second=111 amount=-1 +kerning first=915 second=916 amount=-2 +kerning first=317 second=89 amount=-1 +kerning first=46 second=8220 amount=-2 +kerning first=315 second=376 amount=-1 +kerning first=39 second=74 amount=-1 +kerning first=923 second=356 amount=-1 +kerning first=91 second=372 amount=1 +kerning first=910 second=210 amount=-1 +kerning first=45 second=376 amount=-1 +kerning first=927 second=44 amount=-1 +kerning first=227 second=354 amount=-1 +kerning first=354 second=308 amount=-1 +kerning first=315 second=332 amount=-1 +kerning first=8204 second=354 amount=-1 +kerning first=171 second=933 amount=-1 +kerning first=932 second=948 amount=-1 +kerning first=315 second=85 amount=-1 +kerning first=319 second=219 amount=-1 +kerning first=356 second=361 amount=-1 +kerning first=102 second=46 amount=-1 +kerning first=8216 second=260 amount=-1 +kerning first=1100 second=8217 amount=-1 +kerning first=221 second=262 amount=-1 +kerning first=376 second=913 amount=-1 +kerning first=1033 second=1026 amount=-1 +kerning first=1058 second=1105 amount=-1 +kerning first=8212 second=1035 amount=-1 +kerning first=1059 second=173 amount=-1 +kerning first=372 second=192 amount=-1 +kerning first=275 second=354 amount=-1 +kerning first=40 second=221 amount=1 +kerning first=109 second=8217 amount=-1 +kerning first=912 second=958 amount=1 +kerning first=225 second=356 amount=-1 +kerning first=1168 second=1109 amount=-1 +kerning first=319 second=81 amount=-1 +kerning first=354 second=369 amount=-1 +kerning first=376 second=258 amount=-1 +kerning first=317 second=34 amount=-2 +kerning first=356 second=973 amount=-1 +kerning first=102 second=39 amount=1 +kerning first=915 second=8250 amount=-1 +kerning first=40 second=84 amount=1 +kerning first=44 second=34 amount=-2 +kerning first=923 second=8217 amount=-1 +kerning first=356 second=251 amount=-1 +kerning first=362 second=196 amount=-1 +kerning first=86 second=913 amount=-1 +kerning first=1038 second=1066 amount=1 +kerning first=933 second=79 amount=-1 +kerning first=1027 second=1169 amount=-1 +kerning first=80 second=916 amount=-1 +kerning first=84 second=328 amount=-1 +kerning first=354 second=942 amount=-1 +kerning first=358 second=365 amount=-1 +kerning first=8220 second=940 amount=-1 +kerning first=258 second=8216 amount=-1 +kerning first=916 second=39 amount=-1 +kerning first=356 second=110 amount=-1 +kerning first=915 second=949 amount=-1 +kerning first=354 second=242 amount=-1 +kerning first=86 second=258 amount=-1 +kerning first=89 second=224 amount=-1 +kerning first=315 second=358 amount=-1 +kerning first=8220 second=244 amount=-1 +kerning first=910 second=971 amount=-1 +kerning first=101 second=84 amount=-1 +kerning first=246 second=358 amount=-1 +kerning first=76 second=366 amount=-1 +kerning first=8216 second=948 amount=-1 +kerning first=160 second=932 amount=-1 +kerning first=45 second=358 amount=-1 +kerning first=933 second=8212 amount=-1 +kerning first=910 second=173 amount=-1 +kerning first=225 second=8217 amount=-1 +kerning first=8217 second=331 amount=-1 +kerning first=915 second=336 amount=-1 +kerning first=173 second=1058 amount=-1 +kerning first=8222 second=356 amount=-1 +kerning first=84 second=954 amount=-1 +kerning first=1040 second=1058 amount=-1 +kerning first=939 second=943 amount=-1 +kerning first=971 second=39 amount=-1 +kerning first=358 second=941 amount=-1 +kerning first=221 second=332 amount=-1 +kerning first=84 second=228 amount=-1 +kerning first=8217 second=283 amount=-1 +kerning first=358 second=246 amount=-1 +kerning first=372 second=234 amount=-1 +kerning first=81 second=46 amount=-1 +kerning first=932 second=269 amount=-1 +kerning first=1043 second=1101 amount=-1 +kerning first=933 second=912 amount=-1 +kerning first=1066 second=1038 amount=-1 +kerning first=1038 second=173 amount=-1 +kerning first=932 second=117 amount=-1 +kerning first=372 second=354 amount=1 +kerning first=89 second=339 amount=-1 +kerning first=315 second=199 amount=-1 +kerning first=358 second=105 amount=-1 +kerning first=87 second=301 amount=1 +kerning first=111 second=932 amount=-1 +kerning first=360 second=256 amount=-1 +kerning first=376 second=81 amount=-1 +kerning first=915 second=338 amount=-1 +kerning first=944 second=34 amount=-1 +kerning first=70 second=256 amount=-1 +kerning first=315 second=288 amount=-1 +kerning first=76 second=45 amount=-1 +kerning first=364 second=913 amount=-1 +kerning first=8220 second=260 amount=-1 +kerning first=343 second=8230 amount=-1 +kerning first=356 second=328 amount=-1 +kerning first=932 second=197 amount=-1 +kerning first=358 second=916 amount=-1 +kerning first=84 second=248 amount=-1 +kerning first=8221 second=339 amount=-1 +kerning first=1058 second=1083 amount=-1 +kerning first=364 second=258 amount=-1 +kerning first=1168 second=1087 amount=-1 +kerning first=939 second=268 amount=-1 +kerning first=89 second=275 amount=-1 +kerning first=933 second=193 amount=-2 +kerning first=221 second=358 amount=1 +kerning first=1113 second=1090 amount=-1 +kerning first=356 second=954 amount=-1 +kerning first=197 second=89 amount=-1 +kerning first=195 second=376 amount=-1 +kerning first=8216 second=269 amount=-1 +kerning first=221 second=267 amount=-1 +kerning first=8221 second=312 amount=-1 +kerning first=356 second=228 amount=-1 +kerning first=228 second=932 amount=-1 +kerning first=8217 second=349 amount=-1 +kerning first=218 second=198 amount=-1 +kerning first=933 second=58 amount=-1 +kerning first=955 second=39 amount=-1 +kerning first=932 second=341 amount=-1 +kerning first=1027 second=1098 amount=-1 +kerning first=84 second=279 amount=-1 +kerning first=8221 second=275 amount=-1 +kerning first=324 second=8221 amount=-1 +kerning first=194 second=39 amount=-1 +kerning first=932 second=187 amount=-1 +kerning first=8220 second=948 amount=-1 +kerning first=65 second=8220 amount=-1 +kerning first=112 second=8221 amount=-1 +kerning first=358 second=8250 amount=-1 +kerning first=193 second=221 amount=-1 +kerning first=277 second=932 amount=-1 +kerning first=376 second=115 amount=-1 +kerning first=915 second=195 amount=-2 +kerning first=315 second=362 amount=-1 +kerning first=76 second=79 amount=-1 +kerning first=8216 second=197 amount=-1 +kerning first=1046 second=1033 amount=1 +kerning first=345 second=46 amount=-1 +kerning first=221 second=199 amount=-1 +kerning first=8217 second=236 amount=-1 +kerning first=932 second=963 amount=-1 +kerning first=915 second=290 amount=-1 +kerning first=313 second=262 amount=-1 +kerning first=193 second=84 amount=-1 +kerning first=939 second=951 amount=-1 +kerning first=932 second=235 amount=-1 +kerning first=121 second=46 amount=-1 +kerning first=197 second=34 amount=-1 +kerning first=102 second=59 amount=1 +kerning first=358 second=949 amount=-1 +kerning first=221 second=288 amount=-1 +kerning first=356 second=248 amount=-1 +kerning first=321 second=372 amount=-1 +kerning first=1058 second=1119 amount=-1 +kerning first=319 second=356 amount=-1 +kerning first=324 second=354 amount=-1 +kerning first=1043 second=1080 amount=-1 +kerning first=376 second=196 amount=-1 +kerning first=8217 second=101 amount=-1 +kerning first=242 second=356 amount=-1 +kerning first=354 second=380 amount=-1 +kerning first=187 second=932 amount=-1 +kerning first=112 second=354 amount=-1 +kerning first=76 second=8212 amount=-1 +kerning first=929 second=260 amount=-1 +kerning first=936 second=46 amount=-1 +kerning first=1034 second=1035 amount=-1 +kerning first=358 second=84 amount=1 +kerning first=915 second=8230 amount=-2 +kerning first=195 second=358 amount=-1 +kerning first=224 second=8221 amount=-1 +kerning first=87 second=111 amount=-1 +kerning first=1057 second=1066 amount=1 +kerning first=218 second=194 amount=-1 +kerning first=308 second=93 amount=1 +kerning first=86 second=196 amount=-1 +kerning first=123 second=1026 amount=1 +kerning first=356 second=279 amount=-1 +kerning first=931 second=45 amount=-1 +kerning first=358 second=378 amount=-1 +kerning first=80 second=195 amount=-1 +kerning first=376 second=333 amount=-1 +kerning first=317 second=8220 amount=-2 +kerning first=354 second=358 amount=1 +kerning first=89 second=243 amount=-1 +kerning first=934 second=88 amount=-1 +kerning first=8217 second=46 amount=-2 +kerning first=8216 second=963 amount=-1 +kerning first=1168 second=1066 amount=1 +kerning first=44 second=8220 amount=-2 +kerning first=313 second=376 amount=-1 +kerning first=319 second=8217 amount=-2 +kerning first=354 second=267 amount=-1 +kerning first=932 second=41 amount=1 +kerning first=8216 second=235 amount=-1 +kerning first=242 second=8217 amount=-1 +kerning first=8220 second=269 amount=-1 +kerning first=46 second=8217 amount=-2 +kerning first=354 second=119 amount=-1 +kerning first=89 second=103 amount=-1 +kerning first=224 second=354 amount=-1 +kerning first=8212 second=356 amount=-1 +kerning first=84 second=969 amount=-1 +kerning first=313 second=332 amount=-1 +kerning first=1059 second=1058 amount=1 +kerning first=1091 second=46 amount=-1 +kerning first=102 second=93 amount=2 +kerning first=216 second=44 amount=-1 +kerning first=84 second=241 amount=-1 +kerning first=8217 second=297 amount=-1 +kerning first=313 second=85 amount=-1 +kerning first=8221 second=243 amount=-1 +kerning first=317 second=219 amount=-1 +kerning first=86 second=333 amount=-1 +kerning first=8216 second=8216 amount=-1 +kerning first=1043 second=1115 amount=1 +kerning first=1098 second=8217 amount=-1 +kerning first=376 second=233 amount=-1 +kerning first=1027 second=1077 amount=-1 +kerning first=217 second=913 amount=-1 +kerning first=321 second=171 amount=-1 +kerning first=8230 second=8221 amount=-2 +kerning first=366 second=65 amount=-1 +kerning first=360 second=192 amount=-1 +kerning first=358 second=265 amount=-1 +kerning first=283 second=354 amount=-1 +kerning first=80 second=8230 amount=-2 +kerning first=376 second=356 amount=1 +kerning first=8221 second=103 amount=-1 +kerning first=317 second=81 amount=-1 +kerning first=70 second=192 amount=-1 +kerning first=315 second=210 amount=-1 +kerning first=358 second=118 amount=-1 +kerning first=8220 second=197 amount=-1 +kerning first=91 second=354 amount=1 +kerning first=45 second=910 amount=-1 +kerning first=217 second=258 amount=-1 +kerning first=923 second=86 amount=-1 +kerning first=89 second=256 amount=-1 +kerning first=321 second=220 amount=-1 +kerning first=86 second=233 amount=-1 +kerning first=364 second=196 amount=-1 +kerning first=84 second=913 amount=-1 +kerning first=1168 second=173 amount=-1 +kerning first=931 second=79 amount=-1 +kerning first=8204 second=87 amount=-1 +kerning first=1035 second=1066 amount=-1 +kerning first=936 second=198 amount=-1 +kerning first=86 second=356 amount=1 +kerning first=1058 second=1096 amount=-1 +kerning first=358 second=195 amount=-1 +kerning first=1043 second=1059 amount=1 +kerning first=45 second=1066 amount=-1 +kerning first=271 second=311 amount=1 +kerning first=912 second=950 amount=1 +kerning first=1168 second=1100 amount=-1 +kerning first=84 second=258 amount=-1 +kerning first=87 second=224 amount=-1 +kerning first=313 second=358 amount=-1 +kerning first=8221 second=256 amount=-1 +kerning first=213 second=46 amount=-1 +kerning first=354 second=343 amount=-1 +kerning first=243 second=358 amount=-1 +kerning first=913 second=221 amount=-1 +kerning first=939 second=65 amount=-2 +kerning first=89 second=171 amount=-1 +kerning first=1059 second=1092 amount=-1 +kerning first=931 second=8212 amount=-1 +kerning first=356 second=969 amount=-1 +kerning first=84 second=307 amount=-1 +kerning first=356 second=241 amount=-1 +kerning first=1038 second=1058 amount=1 +kerning first=933 second=71 amount=-1 +kerning first=913 second=84 amount=-1 +kerning first=932 second=367 amount=-1 +kerning first=8217 second=198 amount=-1 +kerning first=260 second=39 amount=-1 +kerning first=354 second=965 amount=-1 +kerning first=79 second=46 amount=-1 +kerning first=358 second=345 amount=-1 +kerning first=8220 second=963 amount=-1 +kerning first=931 second=912 amount=1 +kerning first=104 second=358 amount=-1 +kerning first=256 second=221 amount=-1 +kerning first=376 second=291 amount=-1 +kerning first=354 second=237 amount=-1 +kerning first=358 second=8230 amount=-1 +kerning first=910 second=962 amount=-1 +kerning first=8220 second=235 amount=-1 +kerning first=315 second=173 amount=-1 +kerning first=915 second=214 amount=-1 +kerning first=87 second=339 amount=-1 +kerning first=313 second=199 amount=-1 +kerning first=109 second=932 amount=-1 +kerning first=370 second=256 amount=-1 +kerning first=974 second=34 amount=-1 +kerning first=221 second=210 amount=-1 +kerning first=123 second=106 amount=1 +kerning first=932 second=972 amount=-1 +kerning first=256 second=84 amount=-1 +kerning first=123 second=1095 amount=-1 +kerning first=8220 second=8216 amount=-1 +kerning first=313 second=288 amount=-1 +kerning first=356 second=913 amount=-1 +kerning first=932 second=250 amount=-1 +kerning first=84 second=946 amount=-1 +kerning first=939 second=966 amount=-1 +kerning first=936 second=194 amount=-1 +kerning first=341 second=8230 amount=-1 +kerning first=8222 second=86 amount=-1 +kerning first=358 second=232 amount=-1 +kerning first=923 second=932 amount=-1 +kerning first=929 second=197 amount=-1 +kerning first=372 second=225 amount=-1 +kerning first=1043 second=1093 amount=-1 +kerning first=329 second=356 amount=-1 +kerning first=8217 second=114 amount=-1 +kerning first=933 second=941 amount=-1 +kerning first=65 second=356 amount=-1 +kerning first=356 second=258 amount=-1 +kerning first=932 second=109 amount=-1 +kerning first=926 second=970 amount=1 +kerning first=358 second=97 amount=-1 +kerning first=87 second=275 amount=-1 +kerning first=197 second=8220 amount=-1 +kerning first=356 second=307 amount=-1 +kerning first=1038 second=1092 amount=-1 +kerning first=321 second=927 amount=-1 +kerning first=196 second=89 amount=-1 +kerning first=8250 second=221 amount=-1 +kerning first=192 second=376 amount=-1 +kerning first=8217 second=194 amount=-1 +kerning first=8211 second=1026 amount=-1 +kerning first=225 second=932 amount=-1 +kerning first=910 second=256 amount=-2 +kerning first=376 second=363 amount=-1 +kerning first=261 second=358 amount=-1 +kerning first=915 second=973 amount=-1 +kerning first=321 second=286 amount=-1 +kerning first=1058 second=1075 amount=-1 +kerning first=8250 second=84 amount=-1 +kerning first=319 second=268 amount=-1 +kerning first=1043 second=1038 amount=1 +kerning first=173 second=354 amount=-1 +kerning first=933 second=916 amount=-2 +kerning first=8216 second=972 amount=-1 +kerning first=1168 second=1079 amount=-1 +kerning first=110 second=8221 amount=-1 +kerning first=354 second=301 amount=-1 +kerning first=89 second=263 amount=-1 +kerning first=329 second=8217 amount=-1 +kerning first=34 second=193 amount=-1 +kerning first=221 second=252 amount=-1 +kerning first=65 second=8217 amount=-1 +kerning first=221 second=173 amount=-1 +kerning first=939 second=44 amount=-2 +kerning first=313 second=362 amount=-1 +kerning first=356 second=946 amount=-1 +kerning first=84 second=382 amount=-1 +kerning first=8217 second=337 amount=-1 +kerning first=1043 second=8249 amount=-1 +kerning first=1090 second=8230 amount=-1 +kerning first=119 second=46 amount=-1 +kerning first=196 second=34 amount=-1 +kerning first=372 second=273 amount=-1 +kerning first=221 second=111 amount=-1 +kerning first=932 second=324 amount=-1 +kerning first=376 second=245 amount=-1 +kerning first=1027 second=1090 amount=-1 +kerning first=321 second=8221 amount=-2 +kerning first=8221 second=263 amount=-1 +kerning first=317 second=356 amount=-1 +kerning first=89 second=927 amount=-1 +kerning first=217 second=196 amount=-1 +kerning first=372 second=277 amount=-1 +kerning first=123 second=376 amount=1 +kerning first=244 second=356 amount=-1 +kerning first=84 second=115 amount=-1 +kerning first=89 second=192 amount=-1 +kerning first=8222 second=932 amount=-1 +kerning first=110 second=354 amount=-1 +kerning first=934 second=46 amount=-1 +kerning first=89 second=286 amount=-1 +kerning first=76 second=71 amount=-1 +kerning first=933 second=8250 amount=-1 +kerning first=192 second=358 amount=-1 +kerning first=902 second=376 amount=-1 +kerning first=226 second=8221 amount=-1 +kerning first=8217 second=231 amount=-1 +kerning first=86 second=245 amount=-1 +kerning first=932 second=953 amount=-1 +kerning first=70 second=74 amount=-1 +kerning first=932 second=226 amount=-1 +kerning first=84 second=196 amount=-1 +kerning first=8221 second=192 amount=-1 +kerning first=939 second=213 amount=-1 +kerning first=321 second=354 amount=-1 +kerning first=1027 second=46 amount=-1 +kerning first=333 second=84 amount=-1 +kerning first=1043 second=1072 amount=-1 +kerning first=933 second=949 amount=-1 +kerning first=1168 second=1114 amount=-1 +kerning first=87 second=243 amount=-1 +kerning first=319 second=86 amount=-1 +kerning first=271 second=8221 amount=1 +kerning first=331 second=358 amount=-1 +kerning first=70 second=371 amount=-1 +kerning first=1034 second=8217 amount=-1 +kerning first=1113 second=1118 amount=-1 +kerning first=376 second=268 amount=-1 +kerning first=317 second=8217 amount=-2 +kerning first=1059 second=1106 amount=1 +kerning first=210 second=8230 amount=-1 +kerning first=244 second=8217 amount=-1 +kerning first=933 second=336 amount=-1 +kerning first=40 second=89 amount=1 +kerning first=44 second=8217 amount=-2 +kerning first=226 second=354 amount=-1 +kerning first=356 second=382 amount=-1 +kerning first=1057 second=1058 amount=1 +kerning first=84 second=333 amount=-1 +kerning first=339 second=84 amount=-1 +kerning first=354 second=971 amount=-1 +kerning first=358 second=361 amount=-1 +kerning first=8220 second=972 amount=-1 +kerning first=219 second=913 amount=-1 +kerning first=123 second=358 amount=1 +kerning first=356 second=115 amount=-1 +kerning first=8221 second=8221 amount=-1 +kerning first=8218 second=372 amount=-1 +kerning first=354 second=252 amount=-1 +kerning first=362 second=65 amount=-1 +kerning first=89 second=234 amount=-1 +kerning first=370 second=192 amount=-1 +kerning first=915 second=954 amount=-1 +kerning first=1058 second=1054 amount=-1 +kerning first=354 second=173 amount=-1 +kerning first=1168 second=1058 amount=1 +kerning first=313 second=210 amount=-1 +kerning first=89 second=354 amount=1 +kerning first=366 second=923 amount=-1 +kerning first=8216 second=226 amount=-1 +kerning first=219 second=258 amount=-1 +kerning first=221 second=224 amount=-1 +kerning first=902 second=358 amount=-1 +kerning first=933 second=338 amount=-1 +kerning first=354 second=111 amount=-1 +kerning first=235 second=84 amount=-1 +kerning first=87 second=256 amount=-1 +kerning first=84 second=959 amount=-1 +kerning first=932 second=331 amount=-1 +kerning first=358 second=973 amount=-1 +kerning first=84 second=233 amount=-1 +kerning first=8217 second=285 amount=-1 +kerning first=8221 second=234 amount=-1 +kerning first=356 second=196 amount=-1 +kerning first=1033 second=1066 amount=-1 +kerning first=39 second=193 amount=-1 +kerning first=358 second=251 amount=-1 +kerning first=923 second=939 amount=-2 +kerning first=1043 second=1107 amount=-1 +kerning first=372 second=239 amount=1 +kerning first=932 second=283 amount=-1 +kerning first=84 second=356 amount=1 +kerning first=8221 second=354 amount=1 +kerning first=932 second=122 amount=-1 +kerning first=291 second=84 amount=-1 +kerning first=214 second=46 amount=-1 +kerning first=358 second=110 amount=-1 +kerning first=910 second=927 amount=-1 +kerning first=97 second=84 amount=-1 +kerning first=372 second=100 amount=-1 +kerning first=952 second=8230 amount=-1 +kerning first=910 second=192 amount=-2 +kerning first=91 second=87 amount=1 +kerning first=1038 second=1106 amount=1 +kerning first=319 second=932 amount=-1 +kerning first=221 second=339 amount=-1 +kerning first=932 second=934 amount=-1 +kerning first=242 second=932 amount=-1 +kerning first=321 second=211 amount=-1 +kerning first=910 second=286 amount=-1 +kerning first=1035 second=1058 amount=-1 +kerning first=356 second=333 amount=-1 +kerning first=931 second=71 amount=-1 +kerning first=939 second=923 amount=-2 +kerning first=258 second=39 amount=-1 +kerning first=84 second=181 amount=-1 +kerning first=8217 second=308 amount=-1 +kerning first=1058 second=1088 amount=-1 +kerning first=45 second=1058 amount=-1 +kerning first=376 second=230 amount=-1 +kerning first=1168 second=1092 amount=-1 +kerning first=89 second=289 amount=-1 +kerning first=933 second=195 amount=-2 +kerning first=313 second=173 amount=-1 +kerning first=1113 second=1095 amount=-1 +kerning first=84 second=8217 amount=1 +kerning first=197 second=356 amount=-1 +kerning first=1059 second=1084 amount=-1 +kerning first=368 second=256 amount=-1 +kerning first=356 second=959 amount=-1 +kerning first=973 second=34 amount=-1 +kerning first=8216 second=283 amount=-1 +kerning first=221 second=275 amount=-1 +kerning first=916 second=358 amount=-1 +kerning first=933 second=290 amount=-1 +kerning first=356 second=233 amount=-1 +kerning first=1043 second=187 amount=-1 +kerning first=932 second=349 amount=-1 +kerning first=1114 second=1091 amount=-1 +kerning first=1027 second=1103 amount=-1 +kerning first=86 second=230 amount=-1 +kerning first=84 second=291 amount=-1 +kerning first=356 second=356 amount=1 +kerning first=8221 second=289 amount=-1 +kerning first=118 second=8230 amount=-1 +kerning first=358 second=328 amount=-1 +kerning first=76 second=221 amount=-1 +kerning first=8211 second=376 amount=-1 +kerning first=295 second=356 amount=-1 +kerning first=1058 second=44 amount=-1 +kerning first=376 second=271 amount=-1 +kerning first=354 second=224 amount=-1 +kerning first=89 second=211 amount=-1 +kerning first=8212 second=932 amount=-1 +kerning first=1058 second=1032 amount=-1 +kerning first=70 second=225 amount=-1 +kerning first=910 second=961 amount=-1 +kerning first=8220 second=226 amount=-1 +kerning first=76 second=336 amount=-1 +kerning first=76 second=84 amount=-1 +kerning first=196 second=8220 amount=-1 +kerning first=315 second=372 amount=-1 +kerning first=933 second=8230 amount=-2 +kerning first=245 second=8221 amount=-1 +kerning first=932 second=968 amount=-1 +kerning first=8217 second=242 amount=-1 +kerning first=89 second=74 amount=-1 +kerning first=193 second=89 amount=-1 +kerning first=171 second=221 amount=-1 +kerning first=932 second=236 amount=-1 +kerning first=194 second=376 amount=-1 +kerning first=197 second=8217 amount=-1 +kerning first=358 second=954 amount=-1 +kerning first=1169 second=44 amount=-1 +kerning first=376 second=932 amount=1 +kerning first=356 second=181 amount=-1 +kerning first=86 second=271 amount=-1 +kerning first=1027 second=59 amount=-1 +kerning first=358 second=228 amount=-1 +kerning first=319 second=370 amount=-1 +kerning first=1043 second=1085 amount=-1 +kerning first=1168 second=171 amount=-1 +kerning first=34 second=941 amount=-1 +kerning first=259 second=358 amount=-1 +kerning first=272 second=46 amount=-1 +kerning first=171 second=84 amount=-1 +kerning first=317 second=268 amount=-1 +kerning first=932 second=101 amount=-1 +kerning first=89 second=371 amount=-1 +kerning first=76 second=338 amount=-1 +kerning first=65 second=86 amount=-1 +kerning first=356 second=8217 amount=1 +kerning first=354 second=339 amount=-1 +kerning first=8221 second=74 amount=-1 +kerning first=87 second=263 amount=-1 +kerning first=295 second=8217 amount=-1 +kerning first=376 second=65 amount=-1 +kerning first=8216 second=349 amount=-1 +kerning first=908 second=44 amount=-1 +kerning first=245 second=354 amount=-1 +kerning first=1038 second=1084 amount=-1 +kerning first=86 second=932 amount=1 +kerning first=8230 second=933 amount=-1 +kerning first=84 second=363 amount=-1 +kerning first=356 second=291 amount=-1 +kerning first=193 second=34 amount=-1 +kerning first=8211 second=358 amount=-1 +kerning first=376 second=347 amount=-1 +kerning first=354 second=312 amount=-1 +kerning first=321 second=264 amount=-1 +kerning first=89 second=353 amount=-1 +kerning first=358 second=248 amount=-1 +kerning first=219 second=196 amount=-1 +kerning first=241 second=356 amount=-1 +kerning first=34 second=916 amount=-1 +kerning first=86 second=65 amount=-1 +kerning first=87 second=192 amount=-1 +kerning first=271 second=108 amount=1 +kerning first=354 second=275 amount=-1 +kerning first=932 second=46 amount=-1 +kerning first=8220 second=283 amount=-1 +kerning first=221 second=243 amount=-1 +kerning first=195 second=936 amount=-1 +kerning first=315 second=171 amount=-1 +kerning first=84 second=943 amount=-1 +kerning first=194 second=358 amount=-1 +kerning first=84 second=245 amount=-1 +kerning first=8221 second=353 amount=-1 +kerning first=40 second=1035 amount=1 +kerning first=8216 second=101 amount=-1 +kerning first=1043 second=1169 amount=-1 +kerning first=221 second=103 amount=-1 +kerning first=932 second=297 amount=-1 +kerning first=1027 second=1082 amount=-1 +kerning first=321 second=8211 amount=-1 +kerning first=103 second=356 amount=-1 +kerning first=335 second=84 amount=-1 +kerning first=358 second=279 amount=-1 +kerning first=372 second=257 amount=-1 +kerning first=915 second=913 amount=-2 +kerning first=317 second=86 amount=-1 +kerning first=40 second=309 amount=1 +kerning first=315 second=220 amount=-1 +kerning first=372 second=113 amount=-1 +kerning first=376 second=99 amount=-1 +kerning first=76 second=290 amount=-1 +kerning first=910 second=211 amount=-1 +kerning first=212 second=8230 amount=-1 +kerning first=89 second=264 amount=-1 +kerning first=241 second=8217 amount=-1 +kerning first=931 second=336 amount=-1 +kerning first=932 second=945 amount=-1 +kerning first=329 second=932 amount=-1 +kerning first=915 second=258 amount=-2 +kerning first=1168 second=1241 amount=-1 +kerning first=123 second=1066 amount=1 +kerning first=319 second=213 amount=-1 +kerning first=65 second=932 amount=-1 +kerning first=356 second=363 amount=-1 +kerning first=46 second=939 amount=-1 +kerning first=221 second=256 amount=-1 +kerning first=1058 second=1101 amount=-1 +kerning first=8216 second=46 amount=-2 +kerning first=372 second=193 amount=-1 +kerning first=1027 second=1026 amount=1 +kerning first=34 second=949 amount=-1 +kerning first=321 second=87 amount=-1 +kerning first=86 second=99 amount=-1 +kerning first=912 second=955 amount=1 +kerning first=364 second=65 amount=-1 +kerning first=87 second=234 amount=-1 +kerning first=368 second=192 amount=-1 +kerning first=1168 second=1106 amount=1 +kerning first=933 second=214 amount=-1 +kerning first=8220 second=349 amount=-1 +kerning first=89 second=8211 amount=-1 +kerning first=87 second=354 amount=1 +kerning first=931 second=338 amount=-1 +kerning first=356 second=943 amount=-1 +kerning first=362 second=923 amount=-1 +kerning first=376 second=44 amount=-2 +kerning first=39 second=941 amount=-1 +kerning first=233 second=84 amount=-1 +kerning first=356 second=245 amount=-1 +kerning first=85 second=256 amount=-1 +kerning first=913 second=89 amount=-1 +kerning first=221 second=171 amount=-1 +kerning first=195 second=372 amount=-1 +kerning first=173 second=933 amount=-1 +kerning first=80 second=913 amount=-1 +kerning first=1027 second=1118 amount=-1 +kerning first=257 second=356 amount=-1 +kerning first=932 second=198 amount=-1 +kerning first=354 second=962 amount=-1 +kerning first=372 second=335 amount=-1 +kerning first=915 second=946 amount=-1 +kerning first=8218 second=354 amount=-1 +kerning first=354 second=243 amount=-1 +kerning first=89 second=225 amount=-1 +kerning first=8212 second=939 amount=-1 +kerning first=910 second=970 amount=-1 +kerning first=287 second=84 amount=-1 +kerning first=76 second=368 amount=-1 +kerning first=8216 second=945 amount=-1 +kerning first=80 second=258 amount=-1 +kerning first=86 second=44 amount=-1 +kerning first=211 second=46 amount=-1 +kerning first=354 second=372 amount=1 +kerning first=932 second=944 amount=-1 +kerning first=256 second=89 amount=-1 +kerning first=8217 second=358 amount=1 +kerning first=260 second=376 amount=-1 +kerning first=354 second=103 amount=-1 +kerning first=84 second=951 amount=-1 +kerning first=8220 second=101 amount=-1 +kerning first=939 second=940 amount=-1 +kerning first=317 second=932 amount=-1 +kerning first=932 second=255 amount=-1 +kerning first=39 second=916 amount=-1 +kerning first=915 second=81 amount=-1 +kerning first=358 second=969 amount=-1 +kerning first=244 second=932 amount=-1 +kerning first=8217 second=267 amount=-1 +kerning first=1033 second=1058 amount=-1 +kerning first=358 second=241 amount=-1 +kerning first=913 second=34 amount=-1 +kerning first=366 second=260 amount=-1 +kerning first=932 second=261 amount=-1 +kerning first=372 second=227 amount=-1 +kerning first=376 second=213 amount=-1 +kerning first=933 second=973 amount=-1 +kerning first=293 second=358 amount=-1 +kerning first=1043 second=1098 amount=-1 +kerning first=922 second=74 amount=1 +kerning first=357 second=8221 amount=1 +kerning first=932 second=114 amount=-1 +kerning first=315 second=927 amount=-1 +kerning first=926 second=912 amount=1 +kerning first=8204 second=902 amount=-1 +kerning first=257 second=8217 amount=-1 +kerning first=84 second=86 amount=1 +kerning first=1059 second=8211 amount=-1 +kerning first=196 second=356 amount=-1 +kerning first=354 second=256 amount=-1 +kerning first=373 second=46 amount=-1 +kerning first=315 second=286 amount=-1 +kerning first=8216 second=198 amount=-1 +kerning first=931 second=290 amount=-1 +kerning first=256 second=34 amount=-1 +kerning first=910 second=264 amount=-1 +kerning first=8220 second=46 amount=-2 +kerning first=932 second=194 amount=-1 +kerning first=358 second=913 amount=-1 +kerning first=1068 second=1026 amount=-1 +kerning first=84 second=230 amount=-1 +kerning first=8221 second=305 amount=-1 +kerning first=1058 second=1080 amount=-1 +kerning first=89 second=273 amount=-1 +kerning first=8250 second=89 amount=-1 +kerning first=1056 second=44 amount=-2 +kerning first=1168 second=1084 amount=-1 +kerning first=1056 second=1032 amount=-1 +kerning first=939 second=260 amount=-2 +kerning first=922 second=970 amount=1 +kerning first=89 second=277 amount=-1 +kerning first=358 second=258 amount=-1 +kerning first=34 second=195 amount=-1 +kerning first=260 second=358 amount=-1 +kerning first=8221 second=8204 amount=-1 +kerning first=354 second=171 amount=-1 +kerning first=315 second=8221 amount=-2 +kerning first=1059 second=1076 amount=-1 +kerning first=313 second=372 amount=-1 +kerning first=193 second=8220 amount=-1 +kerning first=356 second=951 amount=-1 +kerning first=197 second=86 amount=-1 +kerning first=246 second=8221 amount=-1 +kerning first=39 second=949 amount=-1 +kerning first=8216 second=261 amount=-1 +kerning first=221 second=263 amount=-1 +kerning first=910 second=8211 amount=-1 +kerning first=8217 second=343 amount=-1 +kerning first=8221 second=273 amount=-1 +kerning first=358 second=307 amount=-1 +kerning first=196 second=8217 amount=-1 +kerning first=160 second=8216 amount=-1 +kerning first=932 second=337 amount=-1 +kerning first=376 second=249 amount=-1 +kerning first=1027 second=1095 amount=-1 +kerning first=8216 second=1103 amount=-1 +kerning first=8211 second=910 amount=-1 +kerning first=84 second=271 amount=-1 +kerning first=8221 second=277 amount=-1 +kerning first=317 second=370 amount=-1 +kerning first=332 second=46 amount=-1 +kerning first=76 second=214 amount=-1 +kerning first=8220 second=945 amount=-1 +kerning first=84 second=120 amount=-1 +kerning first=376 second=259 amount=-1 +kerning first=255 second=46 amount=-1 +kerning first=356 second=86 amount=1 +kerning first=915 second=196 amount=-2 +kerning first=1038 second=8211 amount=-1 +kerning first=221 second=927 amount=-1 +kerning first=1168 second=1028 amount=-1 +kerning first=8218 second=1063 amount=-1 +kerning first=315 second=354 amount=-1 +kerning first=217 second=65 amount=-1 +kerning first=34 second=8230 amount=-2 +kerning first=8216 second=194 amount=-1 +kerning first=221 second=192 amount=-1 +kerning first=8217 second=237 amount=-1 +kerning first=246 second=354 amount=-1 +kerning first=1107 second=46 amount=-1 +kerning first=8211 second=1066 amount=-1 +kerning first=84 second=932 amount=1 +kerning first=45 second=354 amount=-1 +kerning first=65 second=939 amount=-2 +kerning first=939 second=948 amount=-1 +kerning first=932 second=231 amount=-1 +kerning first=1040 second=1033 amount=1 +kerning first=358 second=946 amount=-1 +kerning first=221 second=286 amount=-1 +kerning first=376 second=923 amount=-1 +kerning first=356 second=230 amount=-1 +kerning first=321 second=366 amount=-1 +kerning first=86 second=259 amount=-1 +kerning first=1058 second=1115 amount=1 +kerning first=1114 second=8217 amount=-1 +kerning first=1043 second=1077 amount=-1 +kerning first=933 second=954 amount=-1 +kerning first=1027 second=1040 amount=-1 +kerning first=939 second=334 amount=-1 +kerning first=932 second=93 amount=1 +kerning first=89 second=351 amount=-1 +kerning first=84 second=65 amount=-1 +kerning first=85 second=192 amount=-1 +kerning first=40 second=356 amount=1 +kerning first=929 second=46 amount=-2 +kerning first=8220 second=198 amount=-1 +kerning first=8216 second=337 amount=-1 +kerning first=1028 second=1035 amount=1 +kerning first=192 second=936 amount=-1 +kerning first=313 second=171 amount=-1 +kerning first=1038 second=1076 amount=-1 +kerning first=86 second=923 amount=-1 +kerning first=84 second=347 amount=-1 +kerning first=8221 second=351 amount=-1 +kerning first=356 second=271 amount=-1 +kerning first=80 second=196 amount=-1 +kerning first=101 second=356 amount=-1 +kerning first=197 second=932 amount=-1 +kerning first=356 second=120 amount=-1 +kerning first=915 second=959 amount=-1 +kerning first=89 second=239 amount=1 +kerning first=939 second=216 amount=-1 +kerning first=1058 second=1059 amount=1 +kerning first=321 second=45 amount=-1 +kerning first=313 second=220 amount=-1 +kerning first=354 second=263 amount=-1 +kerning first=70 second=257 amount=-1 +kerning first=8220 second=261 amount=-1 +kerning first=8216 second=231 amount=-1 +kerning first=221 second=234 amount=-1 +kerning first=89 second=100 amount=-1 +kerning first=84 second=966 amount=-1 +kerning first=356 second=932 amount=1 +kerning first=366 second=197 amount=-1 +kerning first=8220 second=1103 amount=-1 +kerning first=295 second=932 amount=-1 +kerning first=221 second=354 amount=1 +kerning first=84 second=238 amount=-1 +kerning first=8217 second=301 amount=-1 +kerning first=8221 second=239 amount=-1 +kerning first=317 second=213 amount=-1 +kerning first=39 second=195 amount=-1 +kerning first=358 second=382 amount=-1 +kerning first=44 second=939 amount=-1 +kerning first=372 second=246 amount=-1 +kerning first=932 second=285 amount=-1 +kerning first=220 second=256 amount=-1 +kerning first=376 second=229 amount=-1 +kerning first=1027 second=1074 amount=-1 +kerning first=230 second=84 amount=-1 +kerning first=360 second=193 amount=-1 +kerning first=84 second=99 amount=-1 +kerning first=8221 second=100 amount=-1 +kerning first=356 second=65 amount=-1 +kerning first=354 second=192 amount=-1 +kerning first=315 second=211 amount=-1 +kerning first=70 second=193 amount=-1 +kerning first=358 second=115 amount=-1 +kerning first=8220 second=194 amount=-1 +kerning first=931 second=214 amount=-1 +kerning first=8204 second=221 amount=-1 +kerning first=915 second=181 amount=-1 +kerning first=902 second=936 amount=-1 +kerning first=364 second=923 amount=-1 +kerning first=913 second=8220 amount=-1 +kerning first=227 second=84 amount=-1 +kerning first=86 second=229 amount=-1 +kerning first=89 second=45 amount=-1 +kerning first=123 second=1058 amount=1 +kerning first=1035 second=1063 amount=-1 +kerning first=356 second=347 amount=-1 +kerning first=8204 second=84 amount=-1 +kerning first=195 second=8221 amount=-1 +kerning first=192 second=372 amount=-1 +kerning first=939 second=197 amount=-2 +kerning first=1058 second=1093 amount=-1 +kerning first=39 second=8230 amount=-2 +kerning first=929 second=198 amount=-1 +kerning first=358 second=196 amount=-1 +kerning first=1075 second=44 amount=-1 +kerning first=932 second=308 amount=-1 +kerning first=8216 second=1026 amount=1 +kerning first=321 second=79 amount=-1 +kerning first=1168 second=1097 amount=-1 +kerning first=87 second=225 amount=-1 +kerning first=939 second=284 amount=-1 +kerning first=275 second=84 amount=-1 +kerning first=8220 second=337 amount=-1 +kerning first=84 second=44 amount=-1 +kerning first=256 second=8220 amount=-1 +kerning first=354 second=8221 amount=1 +kerning first=1059 second=1089 amount=-1 +kerning first=232 second=358 amount=-1 +kerning first=356 second=966 amount=-1 +kerning first=8216 second=285 amount=-1 +kerning first=258 second=376 amount=-1 +kerning first=221 second=289 amount=-1 +kerning first=356 second=238 amount=-1 +kerning first=932 second=369 amount=-1 +kerning first=241 second=932 amount=-1 +kerning first=195 second=354 amount=-1 +kerning first=321 second=8212 amount=-1 +kerning first=1027 second=1109 amount=-1 +kerning first=84 second=299 amount=-1 +kerning first=8221 second=303 amount=-1 +kerning first=1041 second=1098 amount=-1 +kerning first=362 second=260 amount=-1 +kerning first=358 second=333 amount=-1 +kerning first=354 second=961 amount=-1 +kerning first=289 second=358 amount=-1 +kerning first=376 second=281 amount=-1 +kerning first=356 second=99 amount=-1 +kerning first=939 second=187 amount=-1 +kerning first=354 second=234 amount=-1 +kerning first=1058 second=1038 amount=1 +kerning first=70 second=227 amount=-1 +kerning first=313 second=927 amount=-1 +kerning first=8220 second=231 amount=-1 +kerning first=336 second=8230 amount=-1 +kerning first=98 second=358 amount=-1 +kerning first=376 second=125 amount=1 +kerning first=8218 second=87 amount=-1 +kerning first=123 second=372 amount=1 +kerning first=253 second=8230 amount=-1 +kerning first=354 second=354 amount=1 +kerning first=76 second=89 amount=-1 +kerning first=193 second=356 amount=-1 +kerning first=221 second=211 amount=-1 +kerning first=932 second=942 amount=-1 +kerning first=1059 second=45 amount=-1 +kerning first=916 second=936 amount=-1 +kerning first=89 second=79 amount=-1 +kerning first=103 second=932 amount=-1 +kerning first=313 second=286 amount=-1 +kerning first=939 second=963 amount=-1 +kerning first=932 second=242 amount=-1 +kerning first=358 second=959 amount=-1 +kerning first=8216 second=308 amount=-1 +kerning first=1058 second=8249 amount=-1 +kerning first=902 second=372 amount=-1 +kerning first=86 second=281 amount=-1 +kerning first=8212 second=1059 amount=-1 +kerning first=358 second=233 amount=-1 +kerning first=929 second=194 amount=-1 +kerning first=221 second=74 amount=-1 +kerning first=1043 second=1090 amount=-1 +kerning first=1168 second=8211 amount=-1 +kerning first=8217 second=111 amount=-1 +kerning first=1066 second=1026 amount=-1 +kerning first=86 second=125 amount=1 +kerning first=87 second=273 amount=-1 +kerning first=114 second=8230 amount=-1 +kerning first=171 second=89 amount=-1 +kerning first=8249 second=376 amount=-1 +kerning first=358 second=356 amount=1 +kerning first=356 second=44 amount=-1 +kerning first=89 second=8212 amount=-1 +kerning first=947 second=46 amount=-1 +kerning first=87 second=277 amount=-1 +kerning first=372 second=84 amount=1 +kerning first=1033 second=8221 amount=-1 +kerning first=258 second=358 amount=-1 +kerning first=221 second=371 amount=-1 +kerning first=313 second=8221 amount=-2 +kerning first=1038 second=1089 amount=-1 +kerning first=315 second=264 amount=-1 +kerning first=76 second=34 amount=-2 +kerning first=196 second=86 amount=-1 +kerning first=243 second=8221 amount=-1 +kerning first=84 second=373 amount=-1 +kerning first=356 second=299 amount=-1 +kerning first=193 second=8217 amount=-1 +kerning first=8220 second=1026 amount=1 +kerning first=197 second=939 amount=-2 +kerning first=915 second=943 amount=-1 +kerning first=910 second=45 amount=-1 +kerning first=1043 second=46 amount=-1 +kerning first=1058 second=1072 amount=-1 +kerning first=358 second=181 amount=-1 +kerning first=334 second=46 amount=-1 +kerning first=933 second=913 amount=-2 +kerning first=1168 second=1076 amount=-2 +kerning first=354 second=289 amount=-1 +kerning first=89 second=257 amount=-1 +kerning first=8216 second=242 amount=-1 +kerning first=8220 second=285 amount=-1 +kerning first=221 second=353 amount=-1 +kerning first=104 second=8221 amount=-1 +kerning first=89 second=113 amount=-1 +kerning first=315 second=8211 amount=-1 +kerning first=358 second=8217 amount=1 +kerning first=257 second=932 amount=-1 +kerning first=313 second=354 amount=-1 +kerning first=219 second=65 amount=-1 +kerning first=84 second=974 amount=-1 +kerning first=220 second=192 amount=-1 +kerning first=933 second=258 amount=-2 +kerning first=243 second=354 amount=-1 +kerning first=1038 second=45 amount=-1 +kerning first=84 second=249 amount=-1 +kerning first=1062 second=1112 amount=1 +kerning first=208 second=44 amount=-1 +kerning first=75 second=308 amount=1 +kerning first=376 second=244 amount=-1 +kerning first=1027 second=1087 amount=-1 +kerning first=217 second=923 amount=-1 +kerning first=84 second=259 amount=-1 +kerning first=319 second=8249 amount=-1 +kerning first=8249 second=358 amount=-1 +kerning first=358 second=291 amount=-1 +kerning first=372 second=265 amount=-1 +kerning first=1059 second=8212 amount=-1 +kerning first=84 second=112 amount=-1 +kerning first=8221 second=113 amount=-1 +kerning first=89 second=193 amount=-1 +kerning first=923 second=8216 amount=-1 +kerning first=104 second=354 amount=-1 +kerning first=927 second=46 amount=-1 +kerning first=1061 second=1060 amount=-1 +kerning first=8220 second=308 amount=-1 +kerning first=1026 second=1035 amount=-1 +kerning first=194 second=936 amount=-1 +kerning first=915 second=268 amount=-1 +kerning first=354 second=74 amount=-1 +kerning first=86 second=244 amount=-1 +kerning first=315 second=87 amount=-1 +kerning first=84 second=923 amount=-1 +kerning first=319 second=217 amount=-1 +kerning first=356 second=373 amount=-1 +kerning first=89 second=58 amount=-1 +kerning first=8211 second=1058 amount=-1 +kerning first=221 second=264 amount=-1 +kerning first=8221 second=193 amount=-1 +kerning first=910 second=79 amount=-1 +kerning first=939 second=212 amount=-1 +kerning first=8212 second=1038 amount=-1 +kerning first=1058 second=1107 amount=-1 +kerning first=319 second=334 amount=-1 +kerning first=372 second=195 amount=-1 +kerning first=196 second=932 amount=-1 +kerning first=933 second=946 amount=-1 +kerning first=8216 second=1040 amount=-1 +kerning first=1168 second=1111 amount=-1 +kerning first=87 second=239 amount=1 +kerning first=324 second=84 amount=-1 +kerning first=354 second=371 amount=-1 +kerning first=89 second=335 amount=-1 +kerning first=70 second=365 amount=-1 +kerning first=376 second=260 amount=-1 +kerning first=261 second=8221 amount=-1 +kerning first=112 second=84 amount=-1 +kerning first=356 second=974 amount=-1 +kerning first=40 second=86 amount=1 +kerning first=913 second=356 amount=-1 +kerning first=87 second=100 amount=-1 +kerning first=910 second=8212 amount=-1 +kerning first=356 second=249 amount=-1 +kerning first=362 second=197 amount=-1 +kerning first=933 second=81 amount=-1 +kerning first=221 second=8211 amount=-1 +kerning first=932 second=380 amount=-1 +kerning first=8217 second=339 amount=-1 +kerning first=84 second=326 amount=-1 +kerning first=319 second=216 amount=-1 +kerning first=356 second=259 amount=-1 +kerning first=8221 second=335 amount=-1 +kerning first=354 second=970 amount=-1 +kerning first=358 second=363 amount=-1 +kerning first=337 second=358 amount=-1 +kerning first=218 second=256 amount=-1 +kerning first=356 second=112 amount=-1 +kerning first=915 second=951 amount=-1 +kerning first=354 second=353 amount=-1 +kerning first=86 second=260 amount=-1 +kerning first=89 second=227 amount=-1 +kerning first=910 second=912 amount=-1 +kerning first=370 second=193 amount=-1 +kerning first=372 second=8230 amount=-1 +kerning first=8220 second=242 amount=-1 +kerning first=376 second=8249 amount=-1 +kerning first=1038 second=8212 amount=-1 +kerning first=256 second=356 amount=-1 +kerning first=313 second=211 amount=-1 +kerning first=261 second=354 amount=-1 +kerning first=221 second=225 amount=-1 +kerning first=1059 second=58 amount=-1 +kerning first=8217 second=312 amount=-1 +kerning first=356 second=923 amount=-1 +kerning first=939 second=972 amount=-1 +kerning first=932 second=358 amount=1 +kerning first=358 second=943 amount=-1 +kerning first=1058 second=187 amount=-1 +kerning first=224 second=84 amount=-1 +kerning first=84 second=229 amount=-1 +kerning first=8217 second=275 amount=-1 +kerning first=1033 second=1063 amount=-1 +kerning first=358 second=245 amount=-1 +kerning first=248 second=358 amount=-1 +kerning first=913 second=8217 amount=-1 +kerning first=192 second=8221 amount=-1 +kerning first=932 second=267 amount=-1 +kerning first=194 second=372 amount=-1 +kerning first=372 second=232 amount=-1 +kerning first=1027 second=1066 amount=1 +kerning first=1043 second=1103 amount=-1 +kerning first=91 second=221 amount=1 +kerning first=932 second=119 amount=-1 +kerning first=929 second=308 amount=-1 +kerning first=376 second=334 amount=-1 +kerning first=1034 second=1059 amount=-1 +kerning first=283 second=84 amount=-1 +kerning first=372 second=97 amount=-1 +kerning first=45 second=933 amount=-1 +kerning first=910 second=193 amount=-2 +kerning first=234 second=358 amount=-1 +kerning first=91 second=84 amount=1 +kerning first=331 second=8221 amount=-1 +kerning first=256 second=8217 amount=-1 +kerning first=356 second=326 amount=-1 +kerning first=939 second=920 amount=-1 +kerning first=8250 second=356 amount=-1 +kerning first=8220 second=1040 amount=-1 +kerning first=192 second=354 amount=-1 +kerning first=910 second=58 amount=-1 +kerning first=1043 second=59 amount=-1 +kerning first=968 second=39 amount=-1 +kerning first=40 second=932 amount=1 +kerning first=1058 second=1085 amount=-1 +kerning first=364 second=260 amount=-1 +kerning first=319 second=284 amount=-1 +kerning first=285 second=358 amount=-1 +kerning first=376 second=216 amount=-1 +kerning first=321 second=71 amount=-1 +kerning first=1168 second=1089 amount=-1 +kerning first=1036 second=1051 amount=1 +kerning first=939 second=266 amount=-1 +kerning first=922 second=912 amount=1 +kerning first=89 second=287 amount=-1 +kerning first=76 second=8220 amount=-2 +kerning first=8216 second=358 amount=1 +kerning first=933 second=196 amount=-2 +kerning first=221 second=273 amount=-1 +kerning first=1027 second=173 amount=-1 +kerning first=354 second=8211 amount=-1 +kerning first=331 second=354 amount=-1 +kerning first=8216 second=267 amount=-1 +kerning first=1038 second=58 amount=-1 +kerning first=221 second=277 amount=-1 +kerning first=101 second=932 amount=-1 +kerning first=356 second=229 amount=-1 +kerning first=1057 second=1033 amount=1 +kerning first=1100 second=1098 amount=-1 +kerning first=902 second=8221 amount=-1 +kerning first=932 second=343 amount=-1 +kerning first=1027 second=1100 amount=-1 +kerning first=84 second=281 amount=-1 +kerning first=8221 second=287 amount=-1 +kerning first=1041 second=1090 amount=-1 +kerning first=195 second=87 amount=-1 +kerning first=76 second=219 amount=-1 +kerning first=84 second=125 amount=1 +kerning first=376 second=269 amount=-1 +kerning first=354 second=225 amount=-1 +kerning first=1168 second=45 amount=-1 +kerning first=376 second=117 amount=-1 +kerning first=123 second=354 amount=1 +kerning first=955 second=947 amount=-1 +kerning first=260 second=936 amount=-1 +kerning first=315 second=366 amount=-1 +kerning first=76 second=81 amount=-1 +kerning first=932 second=965 amount=-1 +kerning first=8217 second=243 amount=-1 +kerning first=354 second=87 amount=1 +kerning first=89 second=71 amount=-1 +kerning first=313 second=264 amount=-1 +kerning first=193 second=86 amount=-1 +kerning first=939 second=953 amount=-1 +kerning first=932 second=237 amount=-1 +kerning first=915 second=65 amount=-2 +kerning first=358 second=951 amount=-1 +kerning first=1068 second=1066 amount=-1 +kerning first=333 second=356 amount=-1 +kerning first=902 second=354 amount=-1 +kerning first=86 second=269 amount=-1 +kerning first=1058 second=1169 amount=-1 +kerning first=319 second=364 amount=-1 +kerning first=1043 second=1082 amount=-1 +kerning first=343 second=44 amount=-1 +kerning first=376 second=197 amount=-1 +kerning first=8217 second=103 amount=-1 +kerning first=196 second=939 amount=-2 +kerning first=936 second=256 amount=-1 +kerning first=933 second=959 amount=-1 +kerning first=8249 second=910 amount=-1 +kerning first=34 second=969 amount=-1 +kerning first=319 second=8216 amount=-2 +kerning first=89 second=365 amount=-1 +kerning first=958 second=125 amount=1 +kerning first=376 second=284 amount=-1 +kerning first=46 second=8216 amount=-2 +kerning first=354 second=305 amount=-1 +kerning first=1034 second=1038 amount=-1 +kerning first=358 second=86 amount=1 +kerning first=87 second=257 amount=-1 +kerning first=102 second=8221 amount=1 +kerning first=221 second=351 amount=-1 +kerning first=87 second=113 amount=-1 +kerning first=313 second=8211 amount=-1 +kerning first=218 second=192 amount=-1 +kerning first=339 second=356 amount=-1 +kerning first=86 second=197 amount=-1 +kerning first=315 second=45 amount=-1 +kerning first=356 second=281 amount=-1 +kerning first=173 second=221 amount=-1 +kerning first=916 second=8221 amount=-1 +kerning first=219 second=923 amount=-1 +kerning first=8217 second=256 amount=-1 +kerning first=356 second=125 amount=1 +kerning first=915 second=966 amount=-1 +kerning first=317 second=8249 amount=-1 +kerning first=89 second=246 amount=-1 +kerning first=963 second=912 amount=1 +kerning first=358 second=230 amount=-1 +kerning first=354 second=273 amount=-1 +kerning first=8220 second=358 amount=1 +kerning first=1043 second=1026 amount=1 +kerning first=333 second=8217 amount=-1 +kerning first=34 second=913 amount=-1 +kerning first=87 second=193 amount=-1 +kerning first=354 second=277 amount=-1 +kerning first=235 second=356 amount=-1 +kerning first=173 second=84 amount=-1 +kerning first=8220 second=267 amount=-1 +kerning first=80 second=65 amount=-1 +kerning first=221 second=239 amount=1 +kerning first=933 second=181 amount=-1 +kerning first=195 second=933 amount=-2 +kerning first=354 second=121 amount=-1 +kerning first=84 second=940 amount=-1 +kerning first=34 second=258 amount=-1 +kerning first=216 second=46 amount=-1 +kerning first=313 second=87 amount=-1 +kerning first=84 second=244 amount=-1 +kerning first=260 second=372 amount=-1 +kerning first=317 second=217 amount=-1 +kerning first=8221 second=246 amount=-1 +kerning first=1043 second=1118 amount=-1 +kerning first=221 second=100 amount=-1 +kerning first=932 second=301 amount=-1 +kerning first=376 second=235 amount=-1 +kerning first=1027 second=1079 amount=-1 +kerning first=1168 second=8212 amount=-1 +kerning first=291 second=356 amount=-1 +kerning first=916 second=354 amount=-1 +kerning first=317 second=334 amount=-1 +kerning first=360 second=195 amount=-1 +kerning first=358 second=271 amount=-1 +kerning first=97 second=356 amount=-1 +kerning first=193 second=932 amount=-1 +kerning first=8221 second=105 amount=-1 +kerning first=70 second=195 amount=-1 +kerning first=358 second=120 amount=-1 +kerning first=87 second=335 amount=-1 +kerning first=217 second=260 amount=-1 +kerning first=259 second=8221 amount=-1 +kerning first=110 second=84 amount=-1 +kerning first=321 second=221 amount=-1 +kerning first=86 second=235 amount=-1 +kerning first=315 second=79 amount=-1 +kerning first=364 second=197 amount=-1 +kerning first=319 second=212 amount=-1 +kerning first=931 second=81 amount=-1 +kerning first=8204 second=89 amount=-1 +kerning first=939 second=934 amount=-1 +kerning first=358 second=932 amount=1 +kerning first=915 second=44 amount=-2 +kerning first=910 second=71 amount=-1 +kerning first=317 second=216 amount=-1 +kerning first=321 second=336 amount=-1 +kerning first=1058 second=1098 amount=-1 +kerning first=271 second=318 amount=1 +kerning first=326 second=358 amount=-1 +kerning first=221 second=45 amount=-1 +kerning first=321 second=84 amount=-1 +kerning first=912 second=952 amount=1 +kerning first=1168 second=1102 amount=-1 +kerning first=84 second=260 amount=-1 +kerning first=87 second=227 amount=-1 +kerning first=368 second=193 amount=-1 +kerning first=354 second=351 amount=-1 +kerning first=939 second=67 amount=-1 +kerning first=259 second=354 amount=-1 +kerning first=315 second=8212 amount=-1 +kerning first=70 second=8230 amount=-2 +kerning first=358 second=65 amount=-1 +kerning first=356 second=940 amount=-1 +kerning first=97 second=8217 amount=-1 +kerning first=376 second=41 amount=1 +kerning first=39 second=969 amount=-1 +kerning first=356 second=244 amount=-1 +kerning first=913 second=86 amount=-1 +kerning first=955 second=8221 amount=-1 +kerning first=226 second=84 amount=-1 +kerning first=1027 second=1114 amount=-1 +kerning first=321 second=338 amount=-1 +kerning first=194 second=8221 amount=-1 +kerning first=358 second=347 amount=-1 +kerning first=84 second=8249 amount=-1 +kerning first=354 second=239 amount=-1 +kerning first=910 second=941 amount=-1 +kerning first=1168 second=58 amount=-1 +kerning first=915 second=213 amount=-1 +kerning first=76 second=356 amount=-1 +kerning first=8211 second=354 amount=-1 +kerning first=86 second=41 amount=1 +kerning first=89 second=336 amount=-1 +kerning first=80 second=44 amount=-2 +kerning first=932 second=971 amount=-1 +kerning first=256 second=86 amount=-1 +kerning first=354 second=100 amount=-1 +kerning first=89 second=84 amount=1 +kerning first=70 second=97 amount=-1 +kerning first=84 second=948 amount=-1 +kerning first=942 second=8217 amount=-1 +kerning first=939 second=968 amount=-1 +kerning first=932 second=252 amount=-1 +kerning first=39 second=913 amount=-1 +kerning first=358 second=966 amount=-1 +kerning first=936 second=192 amount=-1 +kerning first=932 second=173 amount=-1 +kerning first=8217 second=263 amount=-1 +kerning first=358 second=238 amount=-1 +kerning first=372 second=228 amount=-1 +kerning first=194 second=354 amount=-1 +kerning first=221 second=79 amount=-1 +kerning first=376 second=212 amount=-1 +kerning first=171 second=356 amount=-1 +kerning first=933 second=943 amount=-1 +kerning first=1027 second=1058 amount=1 +kerning first=1043 second=1095 amount=-1 +kerning first=8216 second=1066 amount=1 +kerning first=356 second=260 amount=-1 +kerning first=1113 second=8221 amount=-1 +kerning first=317 second=284 amount=-1 +kerning first=932 second=111 amount=-1 +kerning first=39 second=258 amount=-1 +kerning first=281 second=358 amount=-1 +kerning first=8221 second=84 amount=1 +kerning first=65 second=8216 amount=-1 +kerning first=89 second=338 amount=-1 +kerning first=358 second=99 amount=-1 +kerning first=910 second=916 amount=-2 +kerning first=76 second=8217 amount=-2 +kerning first=319 second=920 amount=-1 +kerning first=160 second=8218 amount=-2 +kerning first=221 second=8212 amount=-1 +kerning first=8217 second=192 amount=-1 +kerning first=354 second=45 amount=-1 +kerning first=969 second=34 amount=-1 +kerning first=1098 second=1098 amount=-1 +kerning first=356 second=8249 amount=-1 +kerning first=376 second=367 amount=-1 +kerning first=321 second=290 amount=-1 +kerning first=1058 second=1077 amount=-1 +kerning first=319 second=266 amount=-1 +kerning first=192 second=87 amount=-1 +kerning first=372 second=248 amount=-1 +kerning first=1043 second=1040 amount=-1 +kerning first=913 second=932 amount=-1 +kerning first=1168 second=1081 amount=-1 +kerning first=354 second=303 amount=-1 +kerning first=89 second=265 amount=-1 +kerning first=34 second=196 amount=-1 +kerning first=936 second=961 amount=-1 +kerning first=939 second=46 amount=-2 +kerning first=258 second=936 amount=-1 +kerning first=358 second=44 amount=-1 +kerning first=313 second=366 amount=-1 +kerning first=356 second=948 amount=-1 +kerning first=88 second=934 amount=-1 +kerning first=933 second=268 amount=-1 +kerning first=221 second=257 amount=-1 +kerning first=910 second=8250 amount=-1 +kerning first=1100 second=1090 amount=-1 +kerning first=8216 second=111 amount=-1 +kerning first=221 second=113 amount=-1 +kerning first=1066 second=1066 amount=-1 +kerning first=335 second=356 amount=-1 +kerning first=376 second=250 amount=-1 +kerning first=8217 second=8221 amount=-1 +kerning first=1027 second=1092 amount=-1 +kerning first=84 second=269 amount=-1 +kerning first=256 second=932 amount=-1 +kerning first=317 second=364 amount=-1 +kerning first=8221 second=265 amount=-1 +kerning first=358 second=299 amount=-1 +kerning first=341 second=44 amount=-1 +kerning first=217 second=197 amount=-1 +kerning first=372 second=279 amount=-1 +kerning first=193 second=939 amount=-2 +kerning first=84 second=117 amount=-1 +kerning first=915 second=923 amount=-2 +kerning first=317 second=8216 amount=-2 +kerning first=89 second=195 amount=-1 +kerning first=910 second=949 amount=-1 +kerning first=293 second=8221 amount=-1 +kerning first=44 second=8216 amount=-2 +kerning first=89 second=290 amount=-1 +kerning first=221 second=193 amount=-1 +kerning first=123 second=87 amount=1 +kerning first=8217 second=234 amount=-1 +kerning first=910 second=336 amount=-1 +kerning first=366 second=198 amount=-1 +kerning first=939 second=945 amount=-1 +kerning first=932 second=224 amount=-1 +kerning first=1068 second=1058 amount=-1 +kerning first=8220 second=1066 amount=1 +kerning first=84 second=197 amount=-1 +kerning first=376 second=920 amount=-1 +kerning first=313 second=45 amount=-1 +kerning first=8217 second=354 amount=1 +kerning first=8221 second=195 amount=-1 +kerning first=946 second=34 amount=-1 +kerning first=321 second=368 amount=-1 +kerning first=1043 second=1074 amount=-1 +kerning first=221 second=58 amount=-1 +kerning first=902 second=87 amount=-1 +kerning first=933 second=951 amount=-1 +kerning first=1168 second=1116 amount=-1 +kerning first=87 second=246 amount=-1 +kerning first=1041 second=1026 amount=-1 +kerning first=335 second=8217 amount=-1 +kerning first=70 second=361 amount=-1 +kerning first=376 second=266 amount=-1 +kerning first=85 second=193 amount=-1 +kerning first=293 second=354 amount=-1 +kerning first=354 second=8212 amount=-1 +kerning first=89 second=8230 amount=-2 +kerning first=1059 second=1108 amount=-1 +kerning first=233 second=356 amount=-1 +kerning first=8250 second=932 amount=-1 +kerning first=221 second=335 amount=-1 +kerning first=192 second=933 amount=-2 +kerning first=910 second=338 amount=-1 +kerning first=1027 second=171 amount=-1 +kerning first=245 second=84 amount=-1 +kerning first=260 second=8221 amount=-1 +kerning first=80 second=923 amount=-1 +kerning first=258 second=372 amount=-1 +kerning first=84 second=341 amount=-1 +kerning first=356 second=269 amount=-1 +kerning first=8221 second=345 amount=-1 +kerning first=931 second=8217 amount=-1 +kerning first=354 second=912 amount=-1 +kerning first=932 second=339 amount=-1 +kerning first=358 second=373 amount=-1 +kerning first=287 second=356 amount=-1 +kerning first=84 second=187 amount=-1 +kerning first=8221 second=8230 amount=-2 +kerning first=356 second=117 amount=-1 +kerning first=939 second=198 amount=-2 +kerning first=354 second=253 amount=-1 +kerning first=89 second=232 amount=-1 +kerning first=1090 second=44 amount=-1 +kerning first=70 second=251 amount=-1 +kerning first=370 second=195 amount=-1 +kerning first=1168 second=1060 amount=-1 +kerning first=923 second=39 amount=-1 +kerning first=354 second=257 amount=-1 +kerning first=8216 second=224 amount=-1 +kerning first=219 second=260 amount=-1 +kerning first=221 second=227 amount=-1 +kerning first=354 second=113 amount=-1 +kerning first=89 second=97 amount=-1 +kerning first=8220 second=111 amount=-1 +kerning first=84 second=963 amount=-1 +kerning first=366 second=194 amount=-1 +kerning first=8204 second=8220 amount=-1 +kerning first=939 second=944 amount=-1 +kerning first=932 second=312 amount=-1 +kerning first=358 second=974 amount=-1 +kerning first=84 second=235 amount=-1 +kerning first=313 second=79 amount=-1 +kerning first=356 second=197 amount=-1 +kerning first=8217 second=289 amount=-1 +kerning first=260 second=354 amount=-1 +kerning first=317 second=212 amount=-1 +kerning first=8221 second=232 amount=-1 +kerning first=39 second=196 amount=-1 +kerning first=358 second=249 amount=-1 +kerning first=1043 second=1109 amount=-1 +kerning first=932 second=275 amount=-1 +kerning first=376 second=226 amount=-1 +kerning first=328 second=358 amount=-1 +kerning first=358 second=259 amount=-1 +kerning first=1059 second=8230 amount=-2 +kerning first=354 second=193 amount=-1 +kerning first=358 second=112 amount=-1 +kerning first=1111 second=1106 amount=1 +kerning first=76 second=268 amount=-1 +kerning first=333 second=932 amount=-1 +kerning first=902 second=933 amount=-2 +kerning first=910 second=195 amount=-2 +kerning first=313 second=8212 amount=-1 +kerning first=68 second=8230 amount=-1 +kerning first=91 second=89 amount=1 +kerning first=1038 second=1108 amount=-1 +kerning first=8216 second=339 amount=-1 +kerning first=321 second=214 amount=-1 +kerning first=86 second=226 amount=-1 +kerning first=315 second=71 amount=-1 +kerning first=910 second=290 amount=-1 +kerning first=210 second=44 amount=-1 +kerning first=356 second=341 amount=-1 +kerning first=358 second=923 amount=-1 +kerning first=372 second=913 amount=-1 +kerning first=356 second=187 amount=-1 +kerning first=939 second=194 amount=-2 +kerning first=1058 second=1090 amount=-1 +kerning first=271 second=293 amount=1 +kerning first=1107 second=173 amount=-1 +kerning first=8217 second=74 amount=-1 +kerning first=913 second=939 amount=-2 +kerning first=1168 second=1094 amount=-1 +kerning first=319 second=67 amount=-1 +kerning first=354 second=335 amount=-1 +kerning first=339 second=932 amount=-1 +kerning first=372 second=258 amount=-1 +kerning first=84 second=41 amount=1 +kerning first=1027 second=1241 amount=-1 +kerning first=939 second=59 amount=-1 +kerning first=1059 second=1086 amount=-1 +kerning first=356 second=963 amount=-1 +kerning first=197 second=8216 amount=-1 +kerning first=221 second=287 amount=-1 +kerning first=8216 second=275 amount=-1 +kerning first=229 second=358 amount=-1 +kerning first=87 second=84 amount=1 +kerning first=356 second=235 amount=-1 +kerning first=910 second=8230 amount=-2 +kerning first=933 second=65 amount=-2 +kerning first=1027 second=1106 amount=1 +kerning first=8218 second=221 amount=-2 +kerning first=256 second=939 amount=-2 +kerning first=187 second=1026 amount=-1 +kerning first=235 second=932 amount=-1 +kerning first=358 second=326 amount=-1 +kerning first=1058 second=46 amount=-1 +kerning first=376 second=283 amount=-1 +kerning first=354 second=227 amount=-1 +kerning first=89 second=214 amount=-1 +kerning first=70 second=228 amount=-1 +kerning first=8220 second=224 amount=-1 +kerning first=279 second=358 amount=-1 +kerning first=8218 second=84 amount=-1 +kerning first=1038 second=8230 amount=-2 +kerning first=8230 second=34 amount=-2 +kerning first=76 second=86 amount=-1 +kerning first=958 second=41 amount=1 +kerning first=932 second=962 amount=-1 +kerning first=8217 second=353 amount=-1 +kerning first=291 second=932 amount=-1 +kerning first=916 second=933 amount=-1 +kerning first=952 second=44 amount=-1 +kerning first=317 second=920 amount=-1 +kerning first=932 second=243 amount=-1 +kerning first=1169 second=46 amount=-1 +kerning first=97 second=932 amount=-1 +kerning first=86 second=283 amount=-1 +kerning first=358 second=229 amount=-1 +kerning first=319 second=360 amount=-1 +kerning first=221 second=71 amount=-1 +kerning first=932 second=372 amount=1 +kerning first=1043 second=1087 amount=-1 +kerning first=1168 second=8250 amount=-1 +kerning first=933 second=966 amount=-1 +kerning first=8216 second=1058 amount=1 +kerning first=317 second=266 amount=-1 +kerning first=932 second=103 amount=-1 +kerning first=194 second=87 amount=-1 +kerning first=89 second=361 amount=-1 +kerning first=356 second=41 amount=1 +kerning first=87 second=265 amount=-1 +kerning first=8220 second=339 amount=-1 +kerning first=376 second=67 amount=-1 +kerning first=908 second=46 amount=-1 +kerning first=221 second=365 amount=-1 +kerning first=1038 second=1086 amount=-1 +kerning first=931 second=268 amount=-1 +kerning first=1098 second=1090 amount=-1 +kerning first=84 second=367 amount=-1 +kerning first=376 second=349 amount=-1 +kerning first=915 second=940 amount=-1 +kerning first=89 second=251 amount=-1 +kerning first=219 second=197 amount=-1 +kerning first=932 second=256 amount=-1 +kerning first=8216 second=962 amount=-1 +kerning first=87 second=195 amount=-1 +kerning first=354 second=287 amount=-1 +kerning first=118 second=44 amount=-1 +kerning first=173 second=89 amount=-1 +kerning first=8216 second=243 amount=-1 +kerning first=8220 second=275 amount=-1 +kerning first=160 second=376 amount=-1 +kerning first=221 second=246 amount=-1 +kerning first=84 second=972 amount=-1 +kerning first=8204 second=8222 amount=-2 +kerning first=98 second=8221 amount=-1 +kerning first=220 second=193 amount=-1 +kerning first=84 second=250 amount=-1 +kerning first=362 second=198 amount=-1 +kerning first=230 second=356 amount=-1 +kerning first=232 second=354 amount=-1 +kerning first=8216 second=103 amount=-1 +kerning first=933 second=44 amount=-2 +kerning first=1066 second=1058 amount=-1 +kerning first=1027 second=1084 amount=-1 +kerning first=76 second=932 amount=-1 +kerning first=8211 second=933 amount=-1 +kerning first=319 second=39 amount=-2 +kerning first=1060 second=1061 amount=-1 +kerning first=932 second=171 amount=-1 +kerning first=358 second=281 amount=-1 +kerning first=84 second=109 amount=-1 +kerning first=8221 second=110 amount=-1 +kerning first=46 second=39 amount=-2 +kerning first=315 second=221 amount=-1 +kerning first=358 second=125 amount=1 +kerning first=376 second=101 amount=-1 +kerning first=289 second=354 amount=-1 +kerning first=87 second=8230 amount=-1 +kerning first=910 second=214 amount=-1 +kerning first=45 second=221 amount=-1 +kerning first=227 second=356 amount=-1 +kerning first=315 second=336 amount=-1 +kerning first=171 second=932 amount=-1 +kerning first=8204 second=356 amount=-1 +kerning first=98 second=354 amount=-1 +kerning first=194 second=933 amount=-2 +kerning first=915 second=260 amount=-2 +kerning first=315 second=84 amount=-1 +kerning first=319 second=218 amount=-1 +kerning first=356 second=367 amount=-1 +kerning first=246 second=84 amount=-1 +kerning first=8216 second=256 amount=-1 +kerning first=8220 second=1058 amount=1 +kerning first=258 second=8221 amount=-1 +kerning first=45 second=84 amount=-1 +kerning first=1058 second=1103 amount=-1 +kerning first=372 second=196 amount=-1 +kerning first=1043 second=1066 amount=1 +kerning first=275 second=356 amount=-1 +kerning first=1027 second=1028 amount=-1 +kerning first=321 second=89 amount=-1 +kerning first=86 second=101 amount=-1 +kerning first=1168 second=1108 amount=-1 +kerning first=87 second=232 amount=-1 +kerning first=368 second=195 amount=-1 +kerning first=354 second=365 amount=-1 +kerning first=933 second=213 amount=-1 +kerning first=160 second=358 amount=-1 +kerning first=315 second=338 amount=-1 +kerning first=1068 second=8221 amount=-1 +kerning first=356 second=972 amount=-1 +kerning first=376 second=46 amount=-2 +kerning first=87 second=97 amount=-1 +kerning first=356 second=250 amount=-1 +kerning first=1100 second=1118 amount=-1 +kerning first=362 second=194 amount=-1 +kerning first=91 second=1035 amount=1 +kerning first=8217 second=305 amount=-1 +kerning first=227 second=8217 amount=-1 +kerning first=258 second=354 amount=-1 +kerning first=84 second=324 amount=-1 +kerning first=8221 second=328 amount=-1 +kerning first=354 second=941 amount=-1 +kerning first=8220 second=962 amount=-1 +kerning first=372 second=333 amount=-1 +kerning first=1058 second=59 amount=-1 +kerning first=915 second=948 amount=-1 +kerning first=356 second=109 amount=-1 +kerning first=354 second=246 amount=-1 +kerning first=89 second=228 amount=-1 +kerning first=8220 second=243 amount=-1 +kerning first=91 second=309 amount=1 +kerning first=910 second=973 amount=-1 +kerning first=8217 second=8204 amount=-1 +kerning first=76 second=370 amount=-1 +kerning first=321 second=34 amount=-2 +kerning first=80 second=260 amount=-1 +kerning first=86 second=46 amount=-1 +kerning first=955 second=967 amount=-1 +kerning first=111 second=358 amount=-1 +kerning first=1043 second=173 amount=-1 +kerning first=335 second=932 amount=-1 +kerning first=8217 second=273 amount=-1 +kerning first=915 second=334 amount=-1 +kerning first=354 second=105 amount=-1 +kerning first=1059 second=1044 amount=-1 +kerning first=84 second=953 amount=-1 +kerning first=8220 second=103 amount=-1 +kerning first=939 second=942 amount=-1 +kerning first=358 second=940 amount=-1 +kerning first=221 second=336 amount=-1 +kerning first=84 second=226 amount=-1 +kerning first=313 second=71 amount=-1 +kerning first=8217 second=277 amount=-1 +kerning first=212 second=44 amount=-1 +kerning first=358 second=244 amount=-1 +kerning first=951 second=8221 amount=-1 +kerning first=372 second=233 amount=-1 +kerning first=221 second=84 amount=1 +kerning first=932 second=263 amount=-1 +kerning first=360 second=913 amount=-1 +kerning first=260 second=87 amount=-1 +kerning first=1043 second=1100 amount=-1 +kerning first=1168 second=8230 amount=-1 +kerning first=8230 second=8220 amount=-2 +kerning first=354 second=916 amount=-1 +kerning first=70 second=913 amount=-1 +kerning first=372 second=356 amount=1 +kerning first=317 second=67 amount=-1 +kerning first=89 second=248 amount=-1 +kerning first=187 second=376 amount=-1 +kerning first=360 second=258 amount=-1 +kerning first=8249 second=354 amount=-1 +kerning first=915 second=216 amount=-1 +kerning first=315 second=290 amount=-1 +kerning first=70 second=258 amount=-1 +kerning first=196 second=8216 amount=-1 +kerning first=221 second=338 amount=-1 +kerning first=8220 second=256 amount=-1 +kerning first=228 second=358 amount=-1 +kerning first=356 second=324 amount=-1 +kerning first=271 second=295 amount=1 +kerning first=932 second=192 amount=-1 +kerning first=8221 second=248 amount=-1 +kerning first=1058 second=1082 amount=-1 +kerning first=233 second=932 amount=-1 +kerning first=1056 second=46 amount=-2 +kerning first=376 second=198 amount=-1 +kerning first=933 second=923 amount=-2 +kerning first=1168 second=1086 amount=-1 +kerning first=939 second=262 amount=-1 +kerning first=277 second=358 amount=-1 +kerning first=89 second=279 amount=-1 +kerning first=358 second=260 amount=-1 +kerning first=337 second=8221 amount=-1 +kerning first=354 second=8250 amount=-1 +kerning first=356 second=953 amount=-1 +kerning first=195 second=221 amount=-1 +kerning first=8216 second=263 amount=-1 +kerning first=287 second=932 amount=-1 +kerning first=221 second=265 amount=-1 +kerning first=84 second=331 amount=-1 +kerning first=8217 second=351 amount=-1 +kerning first=356 second=226 amount=-1 +kerning first=1100 second=1095 amount=-1 +kerning first=1038 second=1044 amount=-1 +kerning first=34 second=65 amount=-1 +kerning first=1027 second=1097 amount=-1 +kerning first=965 second=34 amount=-1 +kerning first=86 second=198 amount=-1 +kerning first=84 second=283 amount=-1 +kerning first=8221 second=279 amount=-1 +kerning first=317 second=360 amount=-1 +kerning first=354 second=949 amount=-1 +kerning first=932 second=8221 amount=1 +kerning first=76 second=213 amount=-1 +kerning first=195 second=84 amount=-1 +kerning first=84 second=122 amount=-1 +kerning first=376 second=261 amount=-1 +kerning first=65 second=39 amount=-1 +kerning first=187 second=358 amount=-1 +kerning first=1058 second=1026 amount=1 +kerning first=358 second=8249 amount=-1 +kerning first=248 second=8221 amount=-1 +kerning first=910 second=954 amount=-1 +kerning first=337 second=354 amount=-1 +kerning first=915 second=197 amount=-2 +kerning first=260 second=933 amount=-2 +kerning first=315 second=368 amount=-1 +kerning first=8216 second=192 amount=-1 +kerning first=221 second=195 amount=-1 +kerning first=932 second=961 amount=-1 +kerning first=8217 second=239 amount=-1 +kerning first=915 second=284 amount=-1 +kerning first=171 second=939 amount=-1 +kerning first=173 second=1035 amount=-1 +kerning first=354 second=84 amount=1 +kerning first=84 second=934 amount=-1 +kerning first=1040 second=1035 amount=-1 +kerning first=932 second=234 amount=-1 +kerning first=358 second=948 amount=-1 +kerning first=102 second=58 amount=1 +kerning first=1068 second=1063 amount=-1 +kerning first=221 second=290 amount=-1 +kerning first=920 second=8230 amount=-1 +kerning first=86 second=261 amount=-1 +kerning first=1058 second=1118 amount=-1 +kerning first=324 second=356 amount=-1 +kerning first=1043 second=1079 amount=-1 +kerning first=932 second=354 amount=1 +kerning first=376 second=194 amount=-1 +kerning first=8217 second=100 amount=-1 +kerning first=939 second=332 amount=-1 +kerning first=354 second=378 amount=-1 +kerning first=112 second=356 amount=-1 +kerning first=248 second=354 amount=-1 +kerning first=929 second=256 amount=-1 +kerning first=85 second=195 amount=-1 +kerning first=1059 second=1113 amount=-1 +kerning first=376 second=59 amount=-1 +kerning first=915 second=187 amount=-1 +kerning first=356 second=331 amount=-1 +kerning first=270 second=8230 amount=-1 +kerning first=1027 second=8211 amount=-1 +kerning first=218 second=193 amount=-1 +kerning first=221 second=8230 amount=-2 +kerning first=86 second=194 amount=-1 +kerning first=364 second=198 amount=-1 +kerning first=84 second=349 amount=-1 +kerning first=356 second=283 amount=-1 +kerning first=234 second=354 amount=-1 +kerning first=80 second=197 amount=-1 +kerning first=376 second=337 amount=-1 +kerning first=356 second=122 amount=-1 +kerning first=915 second=963 amount=-1 +kerning first=317 second=39 amount=-2 +kerning first=8216 second=961 amount=-2 +kerning first=44 second=39 amount=-2 +kerning first=313 second=221 amount=-1 +kerning first=324 second=8217 amount=-1 +kerning first=354 second=265 amount=-1 +kerning first=8216 second=234 amount=-1 +kerning first=8220 second=263 amount=-1 +kerning first=221 second=232 amount=-1 +kerning first=285 second=354 amount=-1 +kerning first=354 second=118 amount=-1 +kerning first=112 second=8217 amount=-1 +kerning first=224 second=356 amount=-1 +kerning first=84 second=968 amount=-1 +kerning first=313 second=336 amount=-1 +kerning first=356 second=934 amount=-1 +kerning first=8216 second=354 amount=1 +kerning first=84 second=236 amount=-1 +kerning first=8217 second=303 amount=-1 +kerning first=313 second=84 amount=-1 +kerning first=8221 second=241 amount=-1 +kerning first=317 second=218 amount=-1 +kerning first=86 second=337 amount=-1 +kerning first=243 second=84 amount=-1 +kerning first=34 second=44 amount=-2 +kerning first=372 second=245 amount=-1 +kerning first=221 second=97 amount=-1 +kerning first=932 second=289 amount=-1 +kerning first=1043 second=1114 amount=-1 +kerning first=376 second=231 amount=-1 +kerning first=1027 second=1076 amount=-2 +kerning first=321 second=8220 amount=-2 +kerning first=923 second=376 amount=-1 +kerning first=360 second=196 amount=-1 +kerning first=89 second=913 amount=-1 +kerning first=358 second=269 amount=-1 +kerning first=283 second=356 amount=-1 +kerning first=1041 second=1066 amount=-1 +kerning first=84 second=101 amount=-1 +kerning first=354 second=195 amount=-1 +kerning first=39 second=65 amount=-1 +kerning first=70 second=196 amount=-1 +kerning first=315 second=214 amount=-1 +kerning first=358 second=117 amount=-1 +kerning first=8220 second=192 amount=-1 +kerning first=91 second=356 amount=1 +kerning first=931 second=213 amount=-1 +kerning first=376 second=93 amount=1 +kerning first=313 second=338 amount=-1 +kerning first=1066 second=8221 amount=-1 +kerning first=89 second=258 amount=-1 +kerning first=1038 second=1113 amount=-1 +kerning first=104 second=84 amount=-1 +kerning first=321 second=219 amount=-1 +kerning first=86 second=231 amount=-1 +kerning first=1098 second=1118 amount=-1 +kerning first=364 second=194 amount=-1 +kerning first=356 second=349 amount=-1 +kerning first=8221 second=913 amount=-1 +kerning first=8204 second=86 amount=-1 +kerning first=224 second=8217 amount=-1 +kerning first=939 second=199 amount=-1 +kerning first=1058 second=1095 amount=-1 +kerning first=8212 second=1026 amount=-1 +kerning first=358 second=197 amount=-1 +kerning first=1043 second=1058 amount=1 +kerning first=1075 second=46 amount=-1 +kerning first=944 second=39 amount=-1 +kerning first=321 second=81 amount=-1 +kerning first=86 second=93 amount=1 +kerning first=1168 second=1099 amount=-1 +kerning first=87 second=228 amount=-1 +kerning first=8221 second=258 amount=-1 +kerning first=939 second=288 amount=-1 +kerning first=354 second=345 amount=-1 +kerning first=932 second=74 amount=-1 +kerning first=84 second=46 amount=-1 +kerning first=1050 second=1051 amount=1 +kerning first=354 second=8230 amount=-1 +kerning first=109 second=358 amount=-1 +kerning first=356 second=968 amount=-1 +kerning first=8216 second=289 amount=-1 +kerning first=934 second=933 amount=-1 +kerning first=8221 second=307 amount=-1 +kerning first=356 second=236 amount=-1 +kerning first=932 second=371 amount=-1 +kerning first=1027 second=1111 amount=-1 +kerning first=1114 second=1098 amount=-1 +kerning first=923 second=358 amount=-1 +kerning first=84 second=297 amount=-1 +kerning first=1118 second=8230 amount=-1 +kerning first=358 second=341 amount=-1 +kerning first=370 second=913 amount=-1 +kerning first=258 second=87 amount=-1 +kerning first=8220 second=961 amount=-2 +kerning first=376 second=285 amount=-1 +kerning first=356 second=101 amount=-1 +kerning first=354 second=232 amount=-1 +kerning first=1058 second=1040 amount=-1 +kerning first=358 second=187 amount=-1 +kerning first=8220 second=234 amount=-1 +kerning first=915 second=212 amount=-1 +kerning first=8218 second=89 amount=-2 +kerning first=955 second=957 amount=-1 +kerning first=87 second=248 amount=-1 +kerning first=8230 second=8217 amount=-2 +kerning first=8222 second=376 amount=-2 +kerning first=1168 second=1044 amount=-1 +kerning first=230 second=932 amount=-1 +kerning first=370 second=258 amount=-1 +kerning first=221 second=214 amount=-1 +kerning first=8220 second=354 amount=1 +kerning first=932 second=970 amount=-1 +kerning first=261 second=84 amount=-1 +kerning first=354 second=97 amount=-1 +kerning first=89 second=81 amount=-1 +kerning first=1059 second=1035 amount=1 +kerning first=84 second=945 amount=-1 +kerning first=313 second=290 amount=-1 +kerning first=193 second=8216 amount=-1 +kerning first=932 second=353 amount=-1 +kerning first=939 second=965 amount=-1 +kerning first=358 second=963 amount=-1 +kerning first=936 second=193 amount=-1 +kerning first=225 second=358 amount=-1 +kerning first=358 second=235 amount=-1 +kerning first=929 second=192 amount=-1 +kerning first=8216 second=74 amount=-1 +kerning first=1043 second=1092 amount=-1 +kerning first=8217 second=113 amount=-1 +kerning first=933 second=940 amount=-1 +kerning first=34 second=974 amount=-1 +kerning first=1036 second=1095 amount=-1 +kerning first=227 second=932 amount=-1 +kerning first=217 second=198 amount=-1 +kerning first=8204 second=932 amount=-1 +kerning first=376 second=308 amount=-1 +kerning first=356 second=46 amount=-1 +kerning first=39 second=44 amount=-2 +kerning first=87 second=279 amount=-1 +kerning first=910 second=913 amount=-2 +kerning first=326 second=8221 amount=-1 +kerning first=197 second=39 amount=-1 +kerning first=1028 second=1051 amount=1 +kerning first=221 second=361 amount=-1 +kerning first=192 second=221 amount=-1 +kerning first=275 second=932 amount=-1 +kerning first=8217 second=193 amount=-1 +kerning first=1098 second=1095 amount=-1 +kerning first=356 second=297 amount=-1 +kerning first=910 second=258 amount=-2 +kerning first=84 second=198 amount=-1 +kerning first=376 second=369 amount=-1 +kerning first=915 second=972 amount=-1 +kerning first=1058 second=1074 amount=-1 +kerning first=319 second=262 amount=-1 +kerning first=192 second=84 amount=-1 +kerning first=372 second=230 amount=-1 +kerning first=173 second=356 amount=-1 +kerning first=34 second=923 amount=-1 +kerning first=8222 second=358 amount=-1 +kerning first=1168 second=1078 amount=-1 +kerning first=8216 second=353 amount=-1 +kerning first=8220 second=289 amount=-1 +kerning first=326 second=354 amount=-1 +kerning first=221 second=251 amount=-1 +kerning first=89 second=115 amount=-1 +kerning first=258 second=933 amount=-2 +kerning first=358 second=41 amount=1 +kerning first=84 second=944 amount=-1 +kerning first=313 second=368 amount=-1 +kerning first=356 second=945 amount=-1 +kerning first=336 second=44 amount=-1 +kerning first=220 second=195 amount=-1 +kerning first=933 second=260 amount=-2 +kerning first=253 second=44 amount=-1 +kerning first=84 second=255 amount=-1 +kerning first=8217 second=335 amount=-1 +kerning first=1043 second=171 amount=-1 +kerning first=1038 second=1035 amount=1 +kerning first=331 second=84 amount=-1 +kerning first=208 second=46 amount=-1 +kerning first=1066 second=1063 amount=-1 +kerning first=376 second=242 amount=-1 +kerning first=1027 second=1089 amount=-1 +kerning first=84 second=261 amount=-1 +kerning first=75 second=74 amount=1 +kerning first=932 second=8211 amount=-1 +kerning first=217 second=194 amount=-1 +kerning first=372 second=271 amount=-1 +kerning first=123 second=221 amount=1 +kerning first=84 second=114 amount=-1 +kerning first=8221 second=115 amount=-1 +kerning first=915 second=920 amount=-1 +kerning first=89 second=196 amount=-1 +kerning first=110 second=356 amount=-1 +kerning first=910 second=946 amount=-1 +kerning first=114 second=44 amount=-1 +kerning first=950 second=125 amount=1 +kerning first=123 second=84 amount=1 +kerning first=902 second=221 amount=-1 +kerning first=915 second=266 amount=-1 +kerning first=86 second=242 amount=-1 +kerning first=315 second=89 amount=-1 +kerning first=8220 second=74 amount=-1 +kerning first=319 second=376 amount=-1 +kerning first=932 second=225 amount=-1 +kerning first=372 second=932 amount=1 +kerning first=84 second=194 amount=-1 +kerning first=910 second=81 amount=-1 +kerning first=356 second=198 amount=-1 +kerning first=45 second=89 amount=-1 +kerning first=8221 second=196 amount=-1 +kerning first=939 second=210 amount=-1 +kerning first=321 second=356 amount=-1 +kerning first=1058 second=1109 amount=-1 +kerning first=1027 second=45 amount=-1 +kerning first=319 second=332 amount=-1 +kerning first=902 second=84 amount=-1 +kerning first=8249 second=933 amount=-1 +kerning first=933 second=948 amount=-1 +kerning first=1168 second=1113 amount=-1 +kerning first=319 second=85 amount=-1 +kerning first=932 second=87 amount=1 +kerning first=354 second=361 amount=-1 +kerning first=70 second=363 amount=-1 +kerning first=89 second=333 amount=-1 +kerning first=376 second=262 amount=-1 +kerning first=1034 second=1026 amount=-1 +kerning first=1059 second=1105 amount=-1 +kerning first=372 second=65 amount=-1 +kerning first=356 second=944 amount=-1 +kerning first=39 second=974 amount=-1 +kerning first=933 second=334 amount=-1 +kerning first=281 second=354 amount=-1 +kerning first=110 second=8217 amount=-1 +kerning first=226 second=356 amount=-1 +kerning first=356 second=255 amount=-1 +kerning first=913 second=8216 amount=-1 +kerning first=315 second=34 amount=-2 +kerning first=84 second=337 amount=-1 +kerning first=8221 second=333 amount=-1 +kerning first=356 second=261 amount=-1 +kerning first=932 second=305 amount=-1 +kerning first=358 second=367 amount=-1 +kerning first=354 second=973 amount=-1 +kerning first=356 second=114 amount=-1 +kerning first=354 second=251 amount=-1 +kerning first=89 second=233 amount=-1 +kerning first=370 second=196 amount=-1 +kerning first=87 second=913 amount=-1 +kerning first=8220 second=353 amount=-1 +kerning first=915 second=953 amount=-1 +kerning first=321 second=8217 amount=-2 +kerning first=8212 second=376 amount=-1 +kerning first=1168 second=1057 amount=-1 +kerning first=313 second=214 amount=-1 +kerning first=89 second=356 amount=1 +kerning first=8216 second=225 amount=-1 +kerning first=933 second=216 amount=-1 +kerning first=1043 second=1241 amount=-1 +kerning first=221 second=228 amount=-1 +kerning first=256 second=8216 amount=-1 +kerning first=354 second=110 amount=-1 +kerning first=87 second=258 amount=-1 +kerning first=319 second=358 amount=-1 +kerning first=939 second=971 amount=-1 +kerning first=932 second=273 amount=-1 +kerning first=39 second=923 amount=-1 +kerning first=358 second=972 amount=-1 +kerning first=242 second=358 amount=-1 +kerning first=957 second=8230 amount=-1 +kerning first=84 second=231 amount=-1 +kerning first=8217 second=287 amount=-1 +kerning first=356 second=194 amount=-1 +kerning first=8221 second=233 amount=-1 +kerning first=358 second=250 amount=-1 +kerning first=939 second=173 amount=-1 +kerning first=1043 second=1106 amount=1 +kerning first=932 second=277 amount=-1 +kerning first=226 second=8217 amount=-1 +kerning first=8216 second=1076 amount=-1 +kerning first=8221 second=356 amount=1 +kerning first=932 second=121 amount=-1 +kerning first=1041 second=1058 amount=-1 +kerning first=974 second=39 amount=-1 +kerning first=916 second=84 amount=-1 +kerning first=84 second=93 amount=1 +kerning first=376 second=332 amount=-1 +kerning first=358 second=109 amount=-1 +kerning first=929 second=74 amount=-1 +kerning first=372 second=99 amount=-1 +kerning first=910 second=196 amount=-2 +kerning first=271 second=8217 amount=1 +kerning first=91 second=86 amount=1 +kerning first=1038 second=1105 amount=-1 +kerning first=1027 second=8212 amount=-1 +kerning first=324 second=932 amount=-1 +kerning first=221 second=248 amount=-1 +kerning first=319 second=199 amount=-1 +kerning first=356 second=337 amount=-1 +kerning first=112 second=932 amount=-1 +kerning first=1058 second=1087 amount=-1 +kerning first=319 second=288 amount=-1 +kerning first=368 second=913 amount=-1 +kerning first=8212 second=358 amount=-1 +kerning first=1168 second=1091 amount=-1 +kerning first=1056 second=1040 amount=-1 +kerning first=354 second=328 amount=-1 +kerning first=89 second=291 amount=-1 +kerning first=76 second=8249 amount=-1 +kerning first=8216 second=273 amount=-1 +kerning first=933 second=197 amount=-2 +kerning first=958 second=93 amount=1 +kerning first=8221 second=8217 amount=-1 +kerning first=1059 second=1083 amount=-1 +kerning first=368 second=258 amount=-1 +kerning first=372 second=44 amount=-1 +kerning first=8216 second=277 amount=-1 +kerning first=160 second=372 amount=-1 +kerning first=259 second=84 amount=-1 +kerning first=933 second=284 amount=-1 +kerning first=221 second=279 amount=-1 +kerning first=356 second=231 amount=-1 +kerning first=1057 second=1035 amount=1 +kerning first=932 second=351 amount=-1 +kerning first=376 second=358 amount=1 +kerning first=1027 second=1102 amount=-1 +kerning first=1114 second=1090 amount=-1 +kerning first=84 second=285 amount=-1 +kerning first=8221 second=291 amount=-1 +kerning first=354 second=954 amount=-1 +kerning first=358 second=324 amount=-1 +kerning first=76 second=217 amount=-1 +kerning first=195 second=89 amount=-1 +kerning first=8211 second=221 amount=-1 +kerning first=376 second=267 amount=-1 +kerning first=356 second=93 amount=1 +kerning first=915 second=934 amount=-1 +kerning first=354 second=228 amount=-1 +kerning first=224 second=932 amount=-1 +kerning first=910 second=959 amount=-1 +kerning first=8220 second=225 amount=-1 +kerning first=219 second=198 amount=-1 +kerning first=76 second=334 amount=-1 +kerning first=1028 second=1098 amount=-1 +kerning first=1168 second=1035 amount=1 +kerning first=328 second=8221 amount=-1 +kerning first=196 second=39 amount=-1 +kerning first=8211 second=84 amount=-1 +kerning first=933 second=187 amount=-1 +kerning first=8217 second=246 amount=-1 +kerning first=936 second=916 amount=-1 +kerning first=86 second=358 amount=1 +kerning first=932 second=239 amount=-1 +kerning first=194 second=221 amount=-1 +kerning first=283 second=932 amount=-1 +kerning first=915 second=67 amount=-1 +kerning first=358 second=953 amount=-1 +kerning first=8220 second=1076 amount=-1 +kerning first=65 second=376 amount=-1 +kerning first=86 second=267 amount=-1 +kerning first=1027 second=58 amount=-1 +kerning first=358 second=226 amount=-1 +kerning first=319 second=362 amount=-1 +kerning first=91 second=932 amount=1 +kerning first=343 second=46 amount=-1 +kerning first=8217 second=105 amount=-1 +kerning first=376 second=199 amount=-1 +kerning first=933 second=963 amount=-1 +kerning first=1043 second=1084 amount=-1 +kerning first=84 second=308 amount=-1 +kerning first=317 second=262 amount=-1 +kerning first=932 second=100 amount=-1 +kerning first=194 second=84 amount=-1 +kerning first=89 second=363 amount=-1 +kerning first=76 second=216 amount=-1 +kerning first=195 second=34 amount=-1 +kerning first=376 second=288 amount=-1 +kerning first=1107 second=8211 amount=-1 +kerning first=354 second=248 amount=-1 +kerning first=70 second=230 amount=-1 +kerning first=74 second=125 amount=1 +kerning first=328 second=354 amount=-1 +kerning first=102 second=8230 amount=-1 +kerning first=8216 second=351 amount=-1 +kerning first=245 second=356 amount=-1 +kerning first=910 second=181 amount=-1 +kerning first=1038 second=1083 amount=-1 +kerning first=218 second=195 amount=-1 +kerning first=1035 second=1035 amount=-1 +kerning first=84 second=369 amount=-1 +kerning first=356 second=285 amount=-1 +kerning first=229 second=8221 amount=-1 +kerning first=915 second=968 amount=-1 +kerning first=321 second=268 amount=-1 +kerning first=89 second=245 amount=-1 +kerning first=1058 second=1066 amount=1 +kerning first=8220 second=273 amount=-1 +kerning first=1043 second=1028 amount=-1 +kerning first=219 second=194 amount=-1 +kerning first=45 second=1035 amount=-1 +kerning first=87 second=196 amount=-1 +kerning first=271 second=107 amount=1 +kerning first=354 second=279 amount=-1 +kerning first=932 second=45 amount=-1 +kerning first=8220 second=277 amount=-1 +kerning first=315 second=8220 amount=-2 +kerning first=84 second=942 amount=-1 +kerning first=1107 second=1076 amount=-1 +kerning first=329 second=358 amount=-1 +kerning first=34 second=260 amount=-1 +kerning first=84 second=242 amount=-1 +kerning first=313 second=89 amount=-1 +kerning first=65 second=358 amount=-1 +kerning first=8221 second=245 amount=-1 +kerning first=317 second=376 amount=-1 +kerning first=358 second=331 amount=-1 +kerning first=8216 second=100 amount=-1 +kerning first=245 second=8217 amount=-1 +kerning first=932 second=303 amount=-1 +kerning first=1027 second=1081 amount=-1 +kerning first=229 second=354 amount=-1 +kerning first=356 second=308 amount=-1 +kerning first=317 second=332 amount=-1 +kerning first=358 second=283 amount=-1 +kerning first=372 second=259 amount=-1 +kerning first=317 second=85 amount=-1 +kerning first=315 second=219 amount=-1 +kerning first=358 second=122 amount=-1 +kerning first=87 second=333 amount=-1 +kerning first=76 second=284 amount=-1 +kerning first=221 second=913 amount=-1 +kerning first=360 second=65 amount=-1 +kerning first=89 second=268 amount=-1 +kerning first=1058 second=173 amount=-1 +kerning first=279 second=354 amount=-1 +kerning first=931 second=334 amount=-1 +kerning first=81 second=8230 amount=-1 +kerning first=315 second=81 amount=-1 +kerning first=70 second=65 amount=-1 +kerning first=319 second=210 amount=-1 +kerning first=356 second=369 amount=-1 +kerning first=915 second=46 amount=-2 +kerning first=372 second=923 amount=-1 +kerning first=221 second=258 amount=-1 +kerning first=358 second=934 amount=-1 +kerning first=313 second=34 amount=-2 +kerning first=1058 second=1100 amount=-1 +kerning first=271 second=320 amount=1 +kerning first=8217 second=84 amount=1 +kerning first=321 second=86 amount=-1 +kerning first=87 second=233 amount=-1 +kerning first=1168 second=1105 amount=-1 +kerning first=85 second=913 amount=-1 +kerning first=368 second=196 amount=-1 +kerning first=1169 second=173 amount=-1 +kerning first=933 second=212 amount=-1 +kerning first=8220 second=351 amount=-1 +kerning first=87 second=356 amount=1 +kerning first=931 second=216 amount=-1 +kerning first=356 second=942 amount=-1 +kerning first=293 second=84 amount=-1 +kerning first=356 second=242 amount=-1 +kerning first=85 second=258 amount=-1 +kerning first=317 second=358 amount=-1 +kerning first=244 second=358 amount=-1 +kerning first=1027 second=1116 amount=-1 +kerning first=173 second=932 amount=-1 +kerning first=932 second=8212 amount=-1 +kerning first=354 second=969 amount=-1 +kerning first=358 second=349 amount=-1 +kerning first=935 second=934 amount=-1 +kerning first=915 second=945 amount=-1 +kerning first=354 second=241 amount=-1 +kerning first=8218 second=356 amount=-1 +kerning first=8212 second=910 amount=-1 +kerning first=310 second=308 amount=1 +kerning first=910 second=943 amount=-1 +kerning first=973 second=39 amount=-1 +kerning first=76 second=364 amount=-1 +kerning first=76 second=8216 amount=-2 +kerning first=80 second=46 amount=-2 +kerning first=1046 second=1051 amount=1 +kerning first=932 second=912 amount=-1 +kerning first=260 second=221 amount=-1 +kerning first=8220 second=100 amount=-1 +kerning first=939 second=962 amount=-1 +kerning first=932 second=253 amount=-1 +kerning first=936 second=195 amount=-1 +kerning first=319 second=173 amount=-1 +kerning first=358 second=968 amount=-1 +kerning first=8217 second=265 amount=-1 +kerning first=317 second=199 amount=-1 +kerning first=86 second=301 amount=1 +kerning first=8212 second=1066 amount=-1 +kerning first=358 second=236 amount=-1 +kerning first=110 second=932 amount=-1 +kerning first=923 second=936 amount=-1 +kerning first=932 second=257 amount=-1 +kerning first=366 second=256 amount=-1 +kerning first=372 second=229 amount=-1 +kerning first=260 second=84 amount=-1 +kerning first=221 second=81 amount=-1 +kerning first=376 second=210 amount=-1 +kerning first=933 second=972 amount=-1 +kerning first=1027 second=1060 amount=-1 +kerning first=1043 second=1097 amount=-1 +kerning first=317 second=288 amount=-1 +kerning first=354 second=913 amount=-1 +kerning first=932 second=113 amount=-1 +kerning first=39 second=260 amount=-1 +kerning first=345 second=8230 amount=-1 +kerning first=89 second=230 amount=-1 +kerning first=358 second=101 amount=-1 +kerning first=121 second=8230 amount=-1 +kerning first=915 second=198 amount=-2 +kerning first=321 second=932 amount=-1 +kerning first=354 second=258 amount=-1 +kerning first=8230 second=939 amount=-1 +kerning first=931 second=284 amount=-1 +kerning first=8217 second=195 amount=-1 +kerning first=70 second=44 amount=-2 +kerning first=84 second=380 amount=-1 +kerning first=910 second=268 amount=-1 +kerning first=932 second=193 amount=-1 +kerning first=195 second=8220 amount=-1 +kerning first=936 second=8230 amount=-1 +kerning first=915 second=944 amount=-1 +kerning first=354 second=307 amount=-1 +kerning first=1058 second=1079 amount=-1 +kerning first=192 second=89 amount=-1 +kerning first=197 second=376 amount=-1 +kerning first=933 second=920 amount=-1 +kerning first=1168 second=1083 amount=-1 +kerning first=226 second=932 amount=-1 +kerning first=939 second=256 amount=-2 +kerning first=89 second=271 amount=-1 +kerning first=34 second=197 amount=-1 +kerning first=358 second=46 amount=-1 +kerning first=193 second=39 amount=-1 +kerning first=933 second=266 amount=-1 +kerning first=8216 second=257 amount=-1 +kerning first=160 second=354 amount=-1 +kerning first=84 second=358 amount=1 +kerning first=8217 second=345 amount=-1 +kerning first=1043 second=8211 amount=-1 +kerning first=111 second=8221 amount=-1 +kerning first=950 second=41 amount=1 +kerning first=8216 second=113 amount=-1 +kerning first=221 second=115 amount=-1 +kerning first=932 second=335 amount=-1 +kerning first=376 second=252 amount=-1 +kerning first=8217 second=8230 amount=-2 +kerning first=1027 second=1094 amount=-1 +kerning first=84 second=267 amount=-1 +kerning first=376 second=173 amount=-1 +kerning first=8221 second=271 amount=-1 +kerning first=317 second=362 amount=-1 +kerning first=89 second=932 amount=1 +kerning first=354 second=946 amount=-1 +kerning first=76 second=212 amount=-1 +kerning first=358 second=297 amount=-1 +kerning first=341 second=46 amount=-1 +kerning first=80 second=198 amount=-1 +kerning first=372 second=281 amount=-1 +kerning first=84 second=119 amount=-1 +kerning first=923 second=372 amount=-1 +kerning first=910 second=951 amount=-1 +kerning first=1091 second=8230 amount=-1 +kerning first=372 second=125 amount=1 +kerning first=192 second=34 amount=-1 +kerning first=941 second=912 amount=1 +kerning first=376 second=111 amount=-1 +kerning first=915 second=194 amount=-2 +kerning first=1028 second=1090 amount=-1 +kerning first=357 second=8217 amount=1 +kerning first=315 second=356 amount=-1 +kerning first=8216 second=193 amount=-1 +kerning first=123 second=89 amount=1 +kerning first=221 second=196 amount=-1 +kerning first=246 second=356 amount=-1 +kerning first=8217 second=232 amount=-1 +kerning first=89 second=65 amount=-1 +kerning first=45 second=356 amount=-1 +kerning first=356 second=380 amount=-1 +kerning first=8221 second=932 amount=1 +kerning first=111 second=354 amount=-1 +kerning first=932 second=227 amount=-1 +kerning first=1107 second=45 amount=-1 +kerning first=915 second=59 amount=-1 +kerning first=358 second=945 amount=-1 +kerning first=1033 second=1035 amount=-1 +kerning first=321 second=370 amount=-1 +kerning first=1058 second=1114 amount=-1 +kerning first=1043 second=1076 amount=-2 +kerning first=902 second=89 amount=-1 +kerning first=197 second=358 amount=-1 +kerning first=228 second=8221 amount=-1 +kerning first=933 second=953 amount=-1 +kerning first=86 second=111 amount=-1 +kerning first=1168 second=1119 amount=-1 +kerning first=87 second=245 amount=-1 +kerning first=89 second=347 amount=-1 +kerning first=8221 second=65 amount=-1 +kerning first=85 second=196 amount=-1 +kerning first=8216 second=335 amount=-1 +kerning first=221 second=333 amount=-1 +kerning first=313 second=8220 amount=-2 +kerning first=356 second=358 amount=1 +kerning first=1027 second=8250 amount=-1 +kerning first=295 second=358 amount=-1 +kerning first=1114 second=1118 amount=-1 +kerning first=173 second=939 amount=-1 +kerning first=315 second=8217 amount=-2 +kerning first=84 second=343 amount=-1 +kerning first=8221 second=347 amount=-1 +kerning first=356 second=267 amount=-1 +kerning first=213 second=8230 amount=-1 +kerning first=246 second=8217 amount=-1 +kerning first=80 second=194 amount=-1 +kerning first=356 second=119 amount=-1 +kerning first=228 second=354 amount=-1 +kerning first=354 second=382 amount=-1 +kerning first=1058 second=1058 amount=1 +kerning first=358 second=198 amount=-1 +kerning first=70 second=249 amount=-1 +kerning first=1090 second=46 amount=-1 +kerning first=902 second=34 amount=-1 +kerning first=313 second=219 amount=-1 +kerning first=70 second=259 amount=-1 +kerning first=8216 second=227 amount=-1 +kerning first=8220 second=257 amount=-1 +kerning first=221 second=233 amount=-1 +kerning first=220 second=913 amount=-1 +kerning first=354 second=115 amount=-1 +kerning first=89 second=99 amount=-1 +kerning first=8222 second=372 amount=-1 +kerning first=370 second=65 amount=-1 +kerning first=8220 second=113 amount=-1 +kerning first=84 second=965 amount=-1 +kerning first=366 second=192 amount=-1 +kerning first=277 second=354 amount=-1 +kerning first=358 second=944 amount=-1 +kerning first=79 second=8230 amount=-1 +kerning first=221 second=356 amount=1 +kerning first=84 second=237 amount=-1 +kerning first=8221 second=238 amount=-1 +kerning first=313 second=81 amount=-1 +kerning first=317 second=210 amount=-1 +kerning first=40 second=1026 amount=1 +kerning first=39 second=197 amount=-1 +kerning first=358 second=255 amount=-1 +kerning first=372 second=244 amount=-1 +kerning first=932 second=287 amount=-1 +kerning first=360 second=923 amount=-1 +kerning first=220 second=258 amount=-1 +kerning first=76 second=920 amount=-1 +kerning first=376 second=224 amount=-1 +kerning first=1043 second=1111 amount=-1 +kerning first=232 second=84 amount=-1 +kerning first=1041 second=1063 amount=-1 +kerning first=70 second=923 amount=-1 +kerning first=358 second=261 amount=-1 +kerning first=8221 second=99 amount=-1 +kerning first=1107 second=8212 amount=-1 +kerning first=1034 second=1066 amount=-1 +kerning first=354 second=196 amount=-1 +kerning first=358 second=114 amount=-1 +kerning first=8220 second=193 amount=-1 +kerning first=931 second=212 amount=-1 +kerning first=76 second=266 amount=-1 +kerning first=187 second=354 amount=-1 +kerning first=913 second=39 amount=-1 +kerning first=289 second=84 amount=-1 +kerning first=321 second=213 amount=-1 +kerning first=86 second=224 amount=-1 +kerning first=89 second=44 amount=-2 +kerning first=210 second=46 amount=-1 +kerning first=356 second=343 amount=-1 +kerning first=939 second=927 amount=-1 +kerning first=98 second=84 amount=-1 +kerning first=241 second=358 amount=-1 +kerning first=102 second=34 amount=1 +kerning first=910 second=65 amount=-2 +kerning first=939 second=192 amount=-2 +kerning first=1058 second=1092 amount=-1 +kerning first=358 second=194 amount=-1 +kerning first=376 second=339 amount=-1 +kerning first=933 second=934 amount=-1 +kerning first=912 second=946 amount=1 +kerning first=245 second=932 amount=-1 +kerning first=1168 second=1096 amount=-1 +kerning first=939 second=286 amount=-1 +kerning first=354 second=333 amount=-1 +kerning first=8220 second=335 amount=-1 +kerning first=916 second=34 amount=-1 +kerning first=372 second=260 amount=-1 +kerning first=256 second=39 amount=-1 +kerning first=8221 second=44 amount=-2 +kerning first=356 second=965 amount=-1 +kerning first=929 second=912 amount=1 +kerning first=8216 second=287 amount=-1 +kerning first=103 second=358 amount=-1 +kerning first=258 second=221 amount=-1 +kerning first=221 second=291 amount=-1 +kerning first=356 second=237 amount=-1 +kerning first=933 second=67 amount=-1 +kerning first=317 second=173 amount=-1 +kerning first=932 second=365 amount=-1 +kerning first=1027 second=1108 amount=-1 +kerning first=1114 second=1095 amount=-1 +kerning first=195 second=356 amount=-1 +kerning first=86 second=339 amount=-1 +kerning first=84 second=301 amount=-1 +kerning first=8221 second=299 amount=-1 +kerning first=362 second=256 amount=-1 +kerning first=354 second=959 amount=-1 +kerning first=358 second=337 amount=-1 +kerning first=971 second=34 amount=-1 +kerning first=258 second=84 amount=-1 +kerning first=376 second=275 amount=-1 +kerning first=354 second=233 amount=-1 +kerning first=89 second=213 amount=-1 +kerning first=70 second=229 amount=-1 +kerning first=8220 second=227 amount=-1 +kerning first=910 second=966 amount=-1 +kerning first=8218 second=86 amount=-1 +kerning first=87 second=230 amount=-1 +kerning first=354 second=356 amount=1 +kerning first=119 second=8230 amount=-1 +kerning first=8211 second=89 amount=-1 +kerning first=932 second=941 amount=-1 +kerning first=1059 second=44 amount=-2 +kerning first=1059 second=1032 amount=-1 +kerning first=74 second=41 amount=1 +kerning first=939 second=961 amount=-1 +kerning first=952 second=46 amount=-1 +kerning first=932 second=246 amount=-1 +kerning first=1058 second=171 amount=-1 +kerning first=68 second=44 amount=-1 +kerning first=86 second=275 amount=-1 +kerning first=8212 second=1058 amount=-1 +kerning first=358 second=231 amount=-1 +kerning first=929 second=193 amount=-1 +kerning first=319 second=372 amount=-1 +kerning first=192 second=8220 amount=-1 +kerning first=934 second=8230 amount=-1 +kerning first=8217 second=110 amount=-1 +kerning first=1043 second=1089 amount=-1 +kerning first=933 second=968 amount=-1 +kerning first=194 second=89 amount=-1 +kerning first=932 second=105 amount=-1 +kerning first=8249 second=221 amount=-1 +kerning first=196 second=376 amount=-1 +kerning first=195 second=8217 amount=-1 +kerning first=931 second=920 amount=-1 +kerning first=354 second=181 amount=-1 +kerning first=358 second=93 amount=1 +kerning first=87 second=271 amount=-1 +kerning first=1100 second=8221 amount=-1 +kerning first=40 second=106 amount=1 +kerning first=221 second=363 amount=-1 +kerning first=257 second=358 amount=-1 +kerning first=40 second=1095 amount=-1 +kerning first=315 second=268 amount=-1 +kerning first=8249 second=84 amount=-1 +kerning first=1027 second=8230 amount=-1 +kerning first=931 second=266 amount=-1 +kerning first=932 second=916 amount=-1 +kerning first=354 second=8217 amount=1 +kerning first=109 second=8221 amount=-1 +kerning first=123 second=1035 amount=1 +kerning first=356 second=301 amount=-1 +kerning first=915 second=942 amount=-1 +kerning first=910 second=44 amount=-2 +kerning first=1043 second=45 amount=-1 +kerning first=89 second=249 amount=-1 +kerning first=87 second=932 amount=1 +kerning first=955 second=34 amount=-1 +kerning first=8216 second=941 amount=-1 +kerning first=80 second=308 amount=-1 +kerning first=123 second=309 amount=1 +kerning first=1168 second=1075 amount=-1 +kerning first=923 second=8221 amount=-1 +kerning first=354 second=291 amount=-1 +kerning first=194 second=34 amount=-1 +kerning first=118 second=46 amount=-1 +kerning first=89 second=259 amount=-1 +kerning first=8220 second=287 amount=-1 +kerning first=8216 second=246 amount=-1 +kerning first=221 second=245 amount=-1 +kerning first=1075 second=173 amount=-1 +kerning first=84 second=971 amount=-1 +kerning first=313 second=356 amount=-1 +kerning first=220 second=196 amount=-1 +kerning first=243 second=356 amount=-1 +kerning first=1038 second=44 amount=-2 +kerning first=84 second=252 amount=-1 +kerning first=87 second=65 amount=-1 +kerning first=8217 second=328 amount=-1 +kerning first=8218 second=932 amount=-1 +kerning first=1038 second=1032 amount=-1 +kerning first=109 second=354 amount=-1 +kerning first=84 second=173 amount=-1 +kerning first=933 second=46 amount=-2 +kerning first=8221 second=160 amount=-1 +kerning first=160 second=87 amount=-1 +kerning first=902 second=8220 amount=-1 +kerning first=376 second=243 amount=-1 +kerning first=1027 second=1086 amount=-1 +kerning first=319 second=171 amount=-1 +kerning first=932 second=8250 amount=-1 +kerning first=89 second=923 amount=-1 +kerning first=358 second=285 amount=-1 +kerning first=196 second=358 amount=-1 +kerning first=372 second=269 amount=-1 +kerning first=225 second=8221 amount=-1 +kerning first=84 second=111 amount=-1 +kerning first=8221 second=112 amount=-1 +kerning first=923 second=354 amount=-1 +kerning first=376 second=103 amount=-1 +kerning first=8216 second=916 amount=-1 +kerning first=104 second=356 amount=-1 +kerning first=910 second=213 amount=-1 +kerning first=1058 second=1241 amount=-1 +kerning first=76 second=67 amount=-1 +kerning first=337 second=84 amount=-1 +kerning first=932 second=949 amount=-1 +kerning first=915 second=262 amount=-1 +kerning first=86 second=243 amount=-1 +kerning first=315 second=86 amount=-1 +kerning first=319 second=220 amount=-1 +kerning first=8221 second=923 amount=-1 +kerning first=8204 second=8216 amount=-1 +kerning first=65 second=936 amount=-1 +kerning first=1033 second=8217 amount=-1 +kerning first=221 second=268 amount=-1 +kerning first=313 second=8217 amount=-2 +kerning first=939 second=211 amount=-1 +kerning first=1058 second=1106 amount=1 +kerning first=214 second=8230 amount=-1 +kerning first=243 second=8217 amount=-1 +kerning first=372 second=197 amount=-1 +kerning first=933 second=945 amount=-1 +kerning first=40 second=376 amount=1 +kerning first=225 second=354 amount=-1 +kerning first=932 second=84 amount=1 +kerning first=354 second=363 amount=-1 +kerning first=358 second=308 amount=-1 +kerning first=376 second=256 amount=-1 +kerning first=248 second=84 amount=-1 +kerning first=356 second=971 amount=-1 +kerning first=218 second=913 amount=-1 +kerning first=102 second=8220 amount=1 +kerning first=1028 second=1026 amount=1 +kerning first=87 second=99 amount=-1 +kerning first=1043 second=8212 amount=-1 +kerning first=356 second=252 amount=-1 +kerning first=368 second=65 amount=-1 +kerning first=362 second=192 amount=-1 +kerning first=356 second=173 amount=-1 +kerning first=932 second=378 amount=-1 +kerning first=104 second=8217 amount=-1 +kerning first=8217 second=248 amount=-1 +kerning first=8221 second=326 amount=-1 +kerning first=358 second=369 amount=-1 +kerning first=370 second=923 amount=-1 +kerning first=218 second=258 amount=-1 +kerning first=354 second=943 amount=-1 +kerning first=8220 second=941 amount=-1 +kerning first=356 second=111 amount=-1 +kerning first=234 second=84 amount=-1 +kerning first=354 second=245 amount=-1 +kerning first=86 second=256 amount=-1 +kerning first=89 second=229 amount=-1 +kerning first=8220 second=246 amount=-1 +kerning first=376 second=171 amount=-1 +kerning first=76 second=360 amount=-1 +kerning first=8216 second=949 amount=-1 +kerning first=1168 second=1054 amount=-1 +kerning first=261 second=356 amount=-1 +kerning first=933 second=198 amount=-2 +kerning first=915 second=332 amount=-1 +kerning first=173 second=1059 amount=-1 +kerning first=8222 second=354 amount=-1 +kerning first=939 second=970 amount=-1 +kerning first=285 second=84 amount=-1 +kerning first=358 second=942 amount=-1 +kerning first=84 second=224 amount=-1 +kerning first=87 second=44 amount=-1 +kerning first=8217 second=279 amount=-1 +kerning first=212 second=46 amount=-1 +kerning first=358 second=242 amount=-1 +kerning first=8216 second=84 amount=1 +kerning first=372 second=235 amount=-1 +kerning first=932 second=265 amount=-1 +kerning first=933 second=944 amount=-1 +kerning first=1043 second=1102 amount=-1 +kerning first=260 second=89 amount=-1 +kerning first=40 second=358 amount=1 +kerning first=65 second=372 amount=-1 +kerning first=932 second=118 amount=-1 +kerning first=315 second=932 amount=-1 +kerning first=8220 second=916 amount=-1 +kerning first=1050 second=1095 amount=-1 +kerning first=246 second=932 amount=-1 +kerning first=1034 second=1058 amount=-1 +kerning first=910 second=923 amount=-2 +kerning first=45 second=932 amount=-1 +kerning first=360 second=260 amount=-1 +kerning first=70 second=260 amount=-1 +kerning first=319 second=927 amount=-1 +kerning first=221 second=230 amount=-1 +kerning first=101 second=358 amount=-1 +kerning first=261 second=8217 amount=-1 +kerning first=8211 second=1035 amount=-1 +kerning first=958 second=955 amount=1 +kerning first=272 second=8230 amount=-1 +kerning first=931 second=67 amount=-1 +kerning first=932 second=195 amount=-1 +kerning first=192 second=356 amount=-1 +kerning first=84 second=339 amount=-1 +kerning first=1043 second=58 amount=-1 +kerning first=1058 second=1084 amount=-1 +kerning first=364 second=256 amount=-1 +kerning first=319 second=286 amount=-1 +kerning first=260 second=34 amount=-1 +kerning first=1168 second=1088 amount=-1 +kerning first=939 second=264 amount=-1 +kerning first=89 second=281 amount=-1 +kerning first=76 second=39 amount=-2 +kerning first=933 second=194 amount=-2 +kerning first=1113 second=1091 amount=-1 +kerning first=89 second=125 amount=1 +kerning first=372 second=41 amount=1 +kerning first=331 second=356 amount=-1 +kerning first=8216 second=265 amount=-1 +kerning first=221 second=271 amount=-1 +kerning first=84 second=312 amount=-1 +kerning first=356 second=224 amount=-1 +kerning first=933 second=59 amount=-1 +kerning first=932 second=345 amount=-1 +kerning first=1027 second=1099 amount=-1 +kerning first=84 second=275 amount=-1 +kerning first=319 second=8221 amount=-2 +kerning first=8221 second=281 amount=-1 +kerning first=317 second=372 amount=-1 +kerning first=932 second=8230 amount=-1 +kerning first=194 second=8220 amount=-1 +kerning first=354 second=951 amount=-1 +kerning first=76 second=218 amount=-1 +kerning first=195 second=86 amount=-1 +kerning first=242 second=8221 amount=-1 +kerning first=8220 second=949 amount=-1 +kerning first=376 second=263 amount=-1 +kerning first=939 second=8211 amount=-1 +kerning first=46 second=8221 amount=-2 +kerning first=1058 second=1028 amount=-1 +kerning first=193 second=376 amount=-1 +kerning first=192 second=8217 amount=-1 +kerning first=915 second=199 amount=-1 +kerning first=1168 second=44 amount=-1 +kerning first=1028 second=1095 amount=-1 +kerning first=8250 second=1026 amount=-1 +kerning first=221 second=932 amount=1 +kerning first=123 second=356 amount=1 +kerning first=1168 second=1032 amount=-1 +kerning first=315 second=370 amount=-1 +kerning first=8216 second=195 amount=-1 +kerning first=1098 second=8221 amount=-1 +kerning first=8217 second=241 amount=-1 +kerning first=915 second=288 amount=-1 +kerning first=936 second=913 amount=-1 +kerning first=354 second=86 amount=1 +kerning first=173 second=1038 amount=-1 +kerning first=8220 second=84 amount=1 +kerning first=313 second=268 amount=-1 +kerning first=932 second=232 amount=-1 +kerning first=929 second=916 amount=-1 +kerning first=902 second=356 amount=-1 +kerning first=376 second=927 amount=-1 +kerning first=356 second=339 amount=-1 +kerning first=86 second=263 amount=-1 +kerning first=331 second=8217 amount=-1 +kerning first=8222 second=1063 amount=-1 +kerning first=319 second=354 amount=-1 +kerning first=221 second=65 amount=-1 +kerning first=1043 second=1081 amount=-1 +kerning first=376 second=192 amount=-1 +kerning first=936 second=258 amount=-1 +kerning first=242 second=354 amount=-1 +kerning first=1027 second=1044 amount=-1 +kerning first=932 second=97 amount=-1 +kerning first=1065 second=1112 amount=1 +kerning first=376 second=286 amount=-1 +kerning first=354 second=230 amount=-1 +kerning first=87 second=259 amount=-1 +kerning first=1059 second=1115 amount=1 +kerning first=306 second=125 amount=1 +kerning first=221 second=347 amount=-1 +kerning first=8217 second=913 amount=-1 +kerning first=356 second=312 amount=-1 +kerning first=8216 second=8230 amount=-2 +kerning first=218 second=196 amount=-1 +kerning first=85 second=65 amount=-1 +kerning first=86 second=192 amount=-1 +kerning first=356 second=275 amount=-1 +kerning first=358 second=380 amount=-1 +kerning first=8217 second=258 amount=-1 +kerning first=197 second=936 amount=-1 +kerning first=317 second=171 amount=-1 +kerning first=915 second=965 amount=-1 +kerning first=89 second=244 amount=-1 +kerning first=87 second=923 amount=-1 +kerning first=193 second=358 amount=-1 +kerning first=902 second=8217 amount=-1 +kerning first=271 second=104 amount=1 +kerning first=354 second=271 amount=-1 +kerning first=8216 second=232 amount=-1 +kerning first=8220 second=265 amount=-1 +kerning first=8217 second=307 amount=-1 +kerning first=195 second=932 amount=-1 +kerning first=354 second=120 amount=-1 +kerning first=8212 second=354 amount=-1 +kerning first=70 second=117 amount=-1 +kerning first=84 second=962 amount=-1 +kerning first=326 second=84 amount=-1 +kerning first=84 second=243 amount=-1 +kerning first=313 second=86 amount=-1 +kerning first=8221 second=244 amount=-1 +kerning first=317 second=220 amount=-1 +kerning first=358 second=358 amount=1 +kerning first=8216 second=97 amount=-1 +kerning first=34 second=46 amount=-2 +kerning first=1043 second=1116 amount=-1 +kerning first=221 second=99 amount=-1 +kerning first=376 second=234 amount=-1 +kerning first=1027 second=1078 amount=-1 +kerning first=321 second=8249 amount=-1 +kerning first=916 second=356 amount=-1 +kerning first=84 second=372 amount=1 +kerning first=211 second=8230 amount=-1 +kerning first=354 second=932 amount=1 +kerning first=360 second=197 amount=-1 +kerning first=358 second=267 amount=-1 +kerning first=920 second=44 amount=-1 +kerning first=84 second=103 amount=-1 +kerning first=376 second=354 amount=1 +kerning first=315 second=213 amount=-1 +kerning first=70 second=197 amount=-1 +kerning first=358 second=119 amount=-1 +kerning first=8220 second=195 amount=-1 +kerning first=45 second=939 amount=-1 +kerning first=217 second=256 amount=-1 +kerning first=1044 second=1112 amount=1 +kerning first=923 second=87 amount=-1 +kerning first=1038 second=1115 amount=1 +kerning first=89 second=260 amount=-1 +kerning first=1026 second=1026 amount=-1 +kerning first=321 second=217 amount=-1 +kerning first=354 second=65 amount=-1 +kerning first=86 second=234 amount=-1 +kerning first=364 second=192 amount=-1 +kerning first=319 second=211 amount=-1 +kerning first=102 second=8217 amount=1 +kerning first=270 second=44 amount=-1 +kerning first=321 second=334 amount=-1 +kerning first=86 second=354 amount=1 +kerning first=1058 second=1097 amount=-1 +kerning first=271 second=314 amount=1 +kerning first=368 second=923 amount=-1 +kerning first=221 second=44 amount=-2 +kerning first=1043 second=1060 amount=-1 +kerning first=8230 second=8216 amount=-2 +kerning first=1168 second=1101 amount=-1 +kerning first=84 second=256 amount=-1 +kerning first=87 second=229 amount=-1 +kerning first=8221 second=260 amount=-1 +kerning first=354 second=347 amount=-1 +kerning first=373 second=8230 amount=-1 +kerning first=913 second=376 amount=-1 +kerning first=916 second=8217 amount=-1 +kerning first=197 second=372 amount=-1 +kerning first=259 second=356 amount=-1 +kerning first=89 second=8249 amount=-1 +kerning first=8220 second=8230 amount=-2 +kerning first=356 second=962 amount=-1 +kerning first=934 second=935 amount=-1 +kerning first=356 second=243 amount=-1 +kerning first=40 second=1066 amount=1 +kerning first=281 second=84 amount=-1 +kerning first=932 second=361 amount=-1 +kerning first=1027 second=1113 amount=-1 +kerning first=260 second=8220 amount=-1 +kerning first=321 second=216 amount=-1 +kerning first=356 second=372 amount=1 +kerning first=354 second=966 amount=-1 +kerning first=329 second=8221 amount=-1 +kerning first=358 second=343 amount=-1 +kerning first=258 second=89 amount=-1 +kerning first=84 second=171 amount=-1 +kerning first=256 second=376 amount=-1 +kerning first=376 second=289 amount=-1 +kerning first=65 second=8221 amount=-1 +kerning first=356 second=103 amount=-1 +kerning first=354 second=238 amount=-1 +kerning first=910 second=940 amount=-1 +kerning first=8220 second=232 amount=-1 +kerning first=313 second=932 amount=-1 +kerning first=915 second=210 amount=-1 +kerning first=8211 second=356 amount=-1 +kerning first=243 second=932 amount=-1 +kerning first=89 second=334 amount=-1 +kerning first=370 second=260 amount=-1 +kerning first=34 second=198 amount=-1 +kerning first=221 second=213 amount=-1 +kerning first=932 second=973 amount=-1 +kerning first=354 second=99 amount=-1 +kerning first=8220 second=97 amount=-1 +kerning first=1040 second=1051 amount=1 +kerning first=317 second=927 amount=-1 +kerning first=932 second=251 amount=-1 +kerning first=332 second=8230 amount=-1 +kerning first=936 second=196 amount=-1 +kerning first=358 second=965 amount=-1 +kerning first=259 second=8217 amount=-1 +kerning first=8222 second=87 amount=-1 +kerning first=1058 second=8211 amount=-1 +kerning first=255 second=8230 amount=-1 +kerning first=929 second=195 amount=-1 +kerning first=358 second=237 amount=-1 +kerning first=372 second=226 amount=-1 +kerning first=923 second=933 amount=-2 +kerning first=194 second=356 amount=-1 +kerning first=329 second=354 amount=-1 +kerning first=376 second=211 amount=-1 +kerning first=8217 second=115 amount=-1 +kerning first=933 second=942 amount=-1 +kerning first=1027 second=1057 amount=-1 +kerning first=1043 second=1094 amount=-1 +kerning first=104 second=932 amount=-1 +kerning first=65 second=354 amount=-1 +kerning first=356 second=256 amount=-1 +kerning first=317 second=286 amount=-1 +kerning first=932 second=110 amount=-1 +kerning first=913 second=358 amount=-1 +kerning first=258 second=34 amount=-1 +kerning first=1107 second=8230 amount=-1 +kerning first=89 second=216 amount=-1 +kerning first=39 second=46 amount=-2 +kerning first=87 second=281 amount=-1 +kerning first=376 second=74 amount=-1 +kerning first=1169 second=8211 amount=-1 +kerning first=87 second=125 amount=1 +kerning first=950 second=93 amount=1 +kerning first=8249 second=89 amount=-1 +kerning first=8250 second=376 amount=-1 +kerning first=8217 second=196 amount=-1 +kerning first=354 second=44 amount=-1 +kerning first=910 second=260 amount=-2 +kerning first=1034 second=8221 amount=-1 +kerning first=256 second=358 amount=-1 +kerning first=915 second=971 amount=-1 +kerning first=356 second=171 amount=-1 +kerning first=317 second=8221 amount=-2 +kerning first=321 second=284 amount=-1 +kerning first=376 second=371 amount=-1 +kerning first=1058 second=1076 amount=-2 +kerning first=929 second=8230 amount=-2 +kerning first=319 second=264 amount=-1 +kerning first=192 second=86 amount=-1 +kerning first=244 second=8221 amount=-1 +kerning first=955 second=8217 amount=-1 +kerning first=44 second=8221 amount=-2 +kerning first=1168 second=1080 amount=-1 +kerning first=915 second=173 amount=-1 +kerning first=354 second=299 amount=-1 +kerning first=194 second=8217 amount=-1 +kerning first=89 second=269 amount=-1 +kerning first=1118 second=44 amount=-1 +kerning first=34 second=194 amount=-1 +kerning first=221 second=249 amount=-1 +kerning first=195 second=939 amount=-2 +kerning first=939 second=45 amount=-1 +kerning first=89 second=117 amount=-1 +kerning first=1059 second=1072 amount=-1 +kerning first=313 second=370 amount=-1 +kerning first=336 second=46 amount=-1 +kerning first=933 second=262 amount=-1 +kerning first=221 second=259 amount=-1 +kerning first=253 second=46 amount=-1 +kerning first=8217 second=333 amount=-1 +kerning first=1043 second=8250 amount=-1 +kerning first=1169 second=1076 amount=-1 +kerning first=932 second=328 amount=-1 +kerning first=376 second=353 amount=-1 +kerning first=1027 second=1091 amount=-1 +kerning first=84 second=263 amount=-1 +kerning first=319 second=8211 amount=-1 +kerning first=261 second=932 amount=-1 +kerning first=317 second=354 amount=-1 +kerning first=220 second=65 amount=-1 +kerning first=8221 second=269 amount=-1 +kerning first=358 second=301 amount=-1 +kerning first=217 second=192 amount=-1 +kerning first=372 second=283 amount=-1 +kerning first=244 second=354 amount=-1 +kerning first=89 second=197 amount=-1 +kerning first=910 second=948 amount=-1 +kerning first=221 second=923 amount=-1 +kerning first=114 second=46 amount=-1 +kerning first=1113 second=8217 amount=-1 +kerning first=89 second=284 amount=-1 +kerning first=8250 second=358 amount=-1 +kerning first=123 second=86 amount=1 +kerning first=932 second=954 amount=-1 +kerning first=8217 second=233 amount=-1 +kerning first=910 second=334 amount=-1 +kerning first=932 second=228 amount=-1 +kerning first=84 second=192 amount=-1 +kerning first=8217 second=356 amount=1 +kerning first=8221 second=197 amount=-1 +kerning first=321 second=364 amount=-1 +kerning first=1058 second=1111 amount=-1 +kerning first=39 second=198 amount=-1 +kerning first=902 second=86 amount=-1 +kerning first=196 second=936 amount=-1 +kerning first=1027 second=1035 amount=1 +kerning first=321 second=8216 amount=-2 +kerning first=1168 second=1115 amount=1 +kerning first=87 second=244 amount=-1 +kerning first=319 second=87 amount=-1 +kerning first=85 second=923 amount=-1 +kerning first=354 second=373 amount=-1 +kerning first=70 second=367 amount=-1 +kerning first=376 second=264 amount=-1 +kerning first=293 second=356 amount=-1 +kerning first=939 second=79 amount=-1 +kerning first=933 second=332 amount=-1 +kerning first=192 second=932 amount=-1 +kerning first=910 second=216 amount=-1 +kerning first=1038 second=1072 amount=-1 +kerning first=328 second=84 amount=-1 +kerning first=8221 second=341 amount=-1 +kerning first=356 second=263 amount=-1 +kerning first=932 second=248 amount=-1 +kerning first=354 second=974 amount=-1 +kerning first=84 second=8221 amount=1 +kerning first=354 second=249 amount=-1 +kerning first=89 second=235 amount=-1 +kerning first=939 second=8212 amount=-1 +kerning first=70 second=250 amount=-1 +kerning first=370 second=197 amount=-1 +kerning first=376 second=8211 amount=-1 +kerning first=8217 second=8217 amount=-1 +kerning first=331 second=932 amount=-1 +kerning first=160 second=902 amount=-1 +kerning first=1168 second=1059 amount=1 +kerning first=313 second=213 amount=-1 +kerning first=354 second=259 amount=-1 +kerning first=8216 second=228 amount=-1 +kerning first=333 second=358 amount=-1 +kerning first=219 second=256 amount=-1 +kerning first=221 second=229 amount=-1 +kerning first=354 second=112 amount=-1 +kerning first=87 second=260 amount=-1 +kerning first=84 second=961 amount=-1 +kerning first=366 second=193 amount=-1 +kerning first=939 second=912 amount=-1 +kerning first=358 second=971 amount=-1 +kerning first=293 second=8217 amount=-1 +kerning first=84 second=234 amount=-1 +kerning first=8217 second=291 amount=-1 +kerning first=356 second=192 amount=-1 +kerning first=8221 second=235 amount=-1 +kerning first=260 second=356 amount=-1 +kerning first=317 second=211 amount=-1 +kerning first=39 second=194 amount=-1 +kerning first=358 second=252 amount=-1 +kerning first=1043 second=1108 amount=-1 +kerning first=932 second=279 amount=-1 +kerning first=376 second=225 amount=-1 +kerning first=358 second=173 amount=-1 +kerning first=123 second=932 amount=1 +kerning first=84 second=354 amount=1 +kerning first=354 second=923 amount=-1 +kerning first=229 second=84 amount=-1 +kerning first=1034 second=1063 amount=-1 +kerning first=358 second=111 amount=-1 +kerning first=339 second=358 amount=-1 +kerning first=372 second=101 amount=-1 +kerning first=197 second=8221 amount=-1 +kerning first=76 second=262 amount=-1 +kerning first=196 second=372 amount=-1 +kerning first=1028 second=1066 amount=1 +kerning first=902 second=932 amount=-1 +kerning first=910 second=197 amount=-2 +kerning first=8216 second=248 amount=-1 +kerning first=321 second=212 amount=-1 +kerning first=86 second=225 amount=-1 +kerning first=89 second=41 amount=1 +kerning first=910 second=284 amount=-1 +kerning first=279 second=84 amount=-1 +kerning first=46 second=933 amount=-1 +kerning first=1068 second=1035 amount=-1 +kerning first=258 second=8220 amount=-1 +kerning first=356 second=8221 amount=1 +kerning first=939 second=193 amount=-2 +kerning first=947 second=8230 amount=-1 +kerning first=235 second=358 amount=-1 +kerning first=1058 second=1089 amount=-1 +kerning first=295 second=8221 amount=-1 +kerning first=45 second=1059 amount=-1 +kerning first=260 second=8217 amount=-1 +kerning first=1168 second=1093 amount=-1 +kerning first=354 second=326 amount=-1 +kerning first=933 second=199 amount=-1 +kerning first=1046 second=1095 amount=-1 +kerning first=197 second=354 amount=-1 +kerning first=939 second=58 amount=-1 +kerning first=969 second=39 amount=-1 +kerning first=74 second=93 amount=1 +kerning first=368 second=260 amount=-1 +kerning first=372 second=46 amount=-1 +kerning first=356 second=961 amount=-1 +kerning first=1040 second=1098 amount=-1 +kerning first=291 second=358 amount=-1 +kerning first=34 second=308 amount=-1 +kerning first=8216 second=279 amount=-1 +kerning first=221 second=281 amount=-1 +kerning first=933 second=288 amount=-1 +kerning first=910 second=187 amount=-1 +kerning first=356 second=234 amount=-1 +kerning first=1043 second=8230 amount=-1 +kerning first=40 second=1058 amount=1 +kerning first=334 second=8230 amount=-1 +kerning first=97 second=358 amount=-1 +kerning first=221 second=125 amount=1 +kerning first=376 second=273 amount=-1 +kerning first=1027 second=1105 amount=-1 +kerning first=8216 second=1113 amount=-1 +kerning first=84 second=289 amount=-1 +kerning first=356 second=354 amount=1 +kerning first=76 second=376 amount=-1 +kerning first=295 second=354 amount=-1 +kerning first=376 second=277 amount=-1 +kerning first=957 second=44 amount=-1 +kerning first=1058 second=45 amount=-1 +kerning first=354 second=229 amount=-1 +kerning first=89 second=212 amount=-1 +kerning first=8212 second=933 amount=-1 +kerning first=70 second=226 amount=-1 +kerning first=8220 second=228 amount=-1 +kerning first=910 second=963 amount=-1 +kerning first=76 second=332 amount=-1 +kerning first=1168 second=1038 amount=1 +kerning first=76 second=85 amount=-1 +kerning first=932 second=969 amount=-1 +kerning first=1090 second=173 amount=-1 +kerning first=8217 second=245 amount=-1 +kerning first=86 second=273 amount=-1 +kerning first=916 second=932 amount=-1 +kerning first=171 second=376 amount=-1 +kerning first=932 second=241 amount=-1 +kerning first=1169 second=45 amount=-1 +kerning first=306 second=41 amount=1 +kerning first=86 second=277 amount=-1 +kerning first=358 second=224 amount=-1 +kerning first=319 second=366 amount=-1 +kerning first=1043 second=1086 amount=-1 +kerning first=1168 second=8249 amount=-1 +kerning first=933 second=965 amount=-1 +kerning first=1056 second=1076 amount=-1 +kerning first=927 second=8230 amount=-1 +kerning first=317 second=264 amount=-1 +kerning first=89 second=367 amount=-1 +kerning first=194 second=86 amount=-1 +kerning first=241 second=8221 amount=-1 +kerning first=84 second=74 amount=-1 +kerning first=65 second=87 amount=-1 +kerning first=40 second=372 amount=1 +kerning first=87 second=269 amount=-1 +kerning first=8220 second=248 amount=-1 +kerning first=192 second=939 amount=-2 +kerning first=946 second=39 amount=-1 +kerning first=321 second=920 amount=-1 +kerning first=931 second=262 amount=-1 +kerning first=932 second=913 amount=-1 +kerning first=84 second=371 amount=-1 +kerning first=356 second=289 amount=-1 +kerning first=76 second=358 amount=-1 +kerning first=376 second=351 amount=-1 +kerning first=915 second=962 amount=-1 +kerning first=321 second=266 amount=-1 +kerning first=259 second=932 amount=-1 +kerning first=317 second=8211 amount=-1 +kerning first=358 second=339 amount=-1 +kerning first=218 second=65 amount=-1 +kerning first=372 second=198 amount=-1 +kerning first=89 second=250 amount=-1 +kerning first=219 second=192 amount=-1 +kerning first=45 second=1038 amount=-1 +kerning first=932 second=258 amount=-1 +kerning first=241 second=354 amount=-1 +kerning first=8216 second=969 amount=-1 +kerning first=1168 second=1072 amount=-1 +kerning first=87 second=197 amount=-1 +kerning first=319 second=45 amount=-1 +kerning first=1036 second=1033 amount=1 +kerning first=354 second=281 amount=-1 +kerning first=8220 second=279 amount=-1 +kerning first=160 second=221 amount=-1 +kerning first=221 second=244 amount=-1 +kerning first=220 second=923 amount=-1 +kerning first=354 second=125 amount=1 +kerning first=315 second=8249 amount=-1 +kerning first=84 second=970 amount=-1 +kerning first=171 second=358 amount=-1 +kerning first=8204 second=8218 amount=-2 +kerning first=932 second=307 amount=-1 +kerning first=8220 second=1113 amount=-1 +kerning first=1058 second=8212 amount=-1 +kerning first=84 second=353 amount=-1 +kerning first=358 second=312 amount=-1 +kerning first=232 second=356 amount=-1 +kerning first=160 second=84 amount=-1 +kerning first=376 second=239 amount=1 +kerning first=1027 second=1083 amount=-1 +kerning first=8211 second=932 amount=-1 +kerning first=103 second=354 amount=-1 +kerning first=89 second=920 amount=-1 +kerning first=39 second=308 amount=-1 +kerning first=76 second=199 amount=-1 +kerning first=358 second=275 amount=-1 +kerning first=372 second=261 amount=-1 +kerning first=193 second=936 amount=-1 +kerning first=8221 second=109 amount=-1 +kerning first=356 second=74 amount=-1 +kerning first=317 second=87 amount=-1 +kerning first=315 second=217 amount=-1 +kerning first=376 second=100 amount=-1 +kerning first=76 second=288 amount=-1 +kerning first=8216 second=913 amount=-1 +kerning first=1169 second=8212 amount=-1 +kerning first=289 second=356 amount=-1 +kerning first=902 second=939 amount=-2 +kerning first=910 second=212 amount=-1 +kerning first=89 second=266 amount=-1 +kerning first=315 second=334 amount=-1 +kerning first=931 second=332 amount=-1 +kerning first=932 second=946 amount=-1 +kerning first=98 second=356 amount=-1 +kerning first=194 second=932 amount=-1 +kerning first=915 second=256 amount=-2 +kerning first=86 second=239 amount=1 +kerning first=356 second=371 amount=-1 +kerning first=65 second=933 amount=-2 +kerning first=102 second=44 amount=-1 +kerning first=8216 second=258 amount=-1 +kerning first=221 second=260 amount=-1 +kerning first=257 second=8221 amount=-1 +kerning first=111 second=84 amount=-1 +kerning first=1058 second=1102 amount=-1 +kerning first=372 second=194 amount=-1 +kerning first=8216 second=1035 amount=1 +kerning first=86 second=100 amount=-1 +kerning first=1168 second=1107 amount=-1 +kerning first=87 second=235 amount=-1 +kerning first=319 second=79 amount=-1 +kerning first=368 second=197 amount=-1 +kerning first=933 second=210 amount=-1 +kerning first=939 second=71 amount=-1 +kerning first=315 second=216 amount=-1 +kerning first=356 second=970 amount=-1 +kerning first=335 second=358 amount=-1 +kerning first=376 second=45 amount=-1 +kerning first=356 second=353 amount=-1 +kerning first=85 second=260 amount=-1 +kerning first=1057 second=1051 amount=1 +kerning first=362 second=193 amount=-1 +kerning first=8216 second=8220 amount=-1 +kerning first=221 second=8249 amount=-1 +kerning first=1075 second=8211 amount=-1 +kerning first=1027 second=1119 amount=-1 +kerning first=258 second=356 amount=-1 +kerning first=257 second=354 amount=-1 +kerning first=319 second=8212 amount=-1 +kerning first=8221 second=324 amount=-1 +kerning first=98 second=8217 amount=-1 +kerning first=354 second=940 amount=-1 +kerning first=8220 second=969 amount=-1 +kerning first=372 second=337 amount=-1 +kerning first=1058 second=58 amount=-1 +kerning first=84 second=8211 amount=-1 +kerning first=915 second=947 amount=-1 +kerning first=354 second=244 amount=-1 +kerning first=89 second=226 amount=-1 +kerning first=910 second=972 amount=-1 +kerning first=76 second=362 amount=-1 +kerning first=228 second=84 amount=-1 +kerning first=80 second=256 amount=-1 +kerning first=310 second=74 amount=1 +kerning first=196 second=8221 amount=-1 +kerning first=193 second=372 amount=-1 +kerning first=1026 second=1066 amount=-1 +kerning first=916 second=939 amount=-1 +kerning first=939 second=941 amount=-1 +kerning first=932 second=382 amount=-1 +kerning first=358 second=962 amount=-1 +kerning first=221 second=334 amount=-1 +kerning first=84 second=225 amount=-1 +kerning first=87 second=41 amount=1 +kerning first=8217 second=271 amount=-1 +kerning first=1033 second=1059 amount=-1 +kerning first=277 second=84 amount=-1 +kerning first=358 second=243 amount=-1 +kerning first=44 second=933 amount=-1 +kerning first=372 second=231 amount=-1 +kerning first=1043 second=1099 amount=-1 +kerning first=81 second=44 amount=-1 +kerning first=1168 second=187 amount=-1 +kerning first=1066 second=1035 amount=-1 +kerning first=933 second=971 amount=-1 +kerning first=260 second=86 amount=-1 +kerning first=1075 second=1076 amount=-1 +kerning first=8230 second=39 amount=-2 +kerning first=233 second=358 amount=-1 +kerning first=271 second=322 amount=1 +kerning first=932 second=115 amount=-1 +kerning first=358 second=372 amount=1 +kerning first=936 second=65 amount=-1 +kerning first=8220 second=913 amount=-1 +kerning first=258 second=8217 amount=-1 +kerning first=84 second=87 amount=1 +kerning first=933 second=173 amount=-1 +kerning first=187 second=221 amount=-1 +kerning first=358 second=103 amount=-1 +kerning first=372 second=93 amount=1 +kerning first=931 second=199 amount=-1 +kerning first=376 second=79 amount=-1 +kerning first=8249 second=356 amount=-1 +kerning first=196 second=354 amount=-1 +kerning first=910 second=920 amount=-1 +kerning first=1028 second=1058 amount=1 +kerning first=8217 second=932 amount=1 +kerning first=354 second=260 amount=-1 +kerning first=1114 second=8221 amount=-1 +kerning first=315 second=284 amount=-1 +kerning first=8220 second=258 amount=-1 +kerning first=931 second=288 amount=-1 +kerning first=287 second=358 amount=-1 +kerning first=221 second=216 amount=-1 +kerning first=187 second=84 amount=-1 +kerning first=70 second=46 amount=-2 +kerning first=939 second=916 amount=-2 +kerning first=910 second=266 amount=-1 +kerning first=1068 second=8217 amount=-1 +kerning first=932 second=196 amount=-1 +kerning first=8220 second=1035 amount=1 +kerning first=84 second=305 amount=-1 +kerning first=356 second=8211 amount=-1 +kerning first=293 second=932 amount=-1 +kerning first=1058 second=1081 amount=-1 +kerning first=1043 second=1044 amount=-1 +kerning first=376 second=8212 amount=-1 +kerning first=8217 second=65 amount=-1 +kerning first=321 second=67 amount=-1 +kerning first=913 second=936 amount=-1 +kerning first=1168 second=1085 amount=-1 +kerning first=89 second=283 amount=-1 +kerning first=358 second=256 amount=-1 +kerning first=354 second=8249 amount=-1 +kerning first=1059 second=1077 amount=-1 +kerning first=8220 second=8220 amount=-1 +kerning first=1040 second=1090 amount=-1 +kerning first=197 second=87 amount=-1 +kerning first=221 second=269 amount=-1 +kerning first=84 second=273 amount=-1 +kerning first=8221 second=331 amount=-1 +kerning first=356 second=225 amount=-1 +kerning first=8217 second=347 amount=-1 +kerning first=8216 second=115 amount=-1 +kerning first=221 second=117 amount=-1 +kerning first=932 second=333 amount=-1 +kerning first=1027 second=1096 amount=-1 +kerning first=8211 second=939 amount=-1 +kerning first=84 second=277 amount=-1 +kerning first=8221 second=283 amount=-1 +kerning first=256 second=936 amount=-1 +kerning first=317 second=366 amount=-1 +kerning first=354 second=948 amount=-1 +kerning first=76 second=210 amount=-1 +kerning first=84 second=121 amount=-1 +kerning first=376 second=257 amount=-1 +kerning first=356 second=87 amount=1 +kerning first=915 second=927 amount=-1 +kerning first=939 second=8250 amount=-1 +kerning first=358 second=171 amount=-1 +kerning first=910 second=953 amount=-1 +kerning first=951 second=8217 amount=-1 +kerning first=376 second=113 amount=-1 +kerning first=337 second=356 amount=-1 +kerning first=915 second=192 amount=-2 +kerning first=216 second=8230 amount=-1 +kerning first=260 second=932 amount=-1 +kerning first=315 second=364 amount=-1 +kerning first=8216 second=196 amount=-1 +kerning first=345 second=44 amount=-1 +kerning first=221 second=197 amount=-1 +kerning first=194 second=939 amount=-2 +kerning first=932 second=959 amount=-1 +kerning first=8217 second=238 amount=-1 +kerning first=915 second=286 amount=-1 +kerning first=171 second=910 amount=-1 +kerning first=89 second=67 amount=-1 +kerning first=315 second=8216 amount=-2 +kerning first=939 second=949 amount=-1 +kerning first=932 second=233 amount=-1 +kerning first=121 second=44 amount=-1 +kerning first=929 second=913 amount=-1 +kerning first=221 second=284 amount=-1 +kerning first=356 second=305 amount=-1 +kerning first=1033 second=1038 amount=-1 +kerning first=321 second=360 amount=-1 +kerning first=86 second=257 amount=-1 +kerning first=1058 second=1116 amount=-1 +kerning first=1043 second=1078 amount=-1 +kerning first=932 second=356 amount=1 +kerning first=376 second=193 amount=-1 +kerning first=8217 second=99 amount=-1 +kerning first=86 second=113 amount=-1 +kerning first=1168 second=1169 amount=-1 +kerning first=939 second=336 amount=-1 +kerning first=360 second=198 amount=-1 +kerning first=89 second=349 amount=-1 +kerning first=248 second=356 amount=-1 +kerning first=929 second=258 amount=-1 +kerning first=936 second=44 amount=-1 +kerning first=85 second=197 amount=-1 +kerning first=317 second=45 amount=-1 +kerning first=40 second=354 amount=1 +kerning first=70 second=198 amount=-1 +kerning first=376 second=58 amount=-1 +kerning first=8216 second=333 amount=-1 +kerning first=218 second=923 amount=-1 +kerning first=913 second=372 amount=-1 +kerning first=313 second=8249 amount=-1 +kerning first=356 second=273 amount=-1 +kerning first=1038 second=1077 amount=-1 +kerning first=337 second=8217 amount=-1 +kerning first=86 second=193 amount=-1 +kerning first=84 second=351 amount=-1 +kerning first=8221 second=349 amount=-1 +kerning first=356 second=277 amount=-1 +kerning first=234 second=356 amount=-1 +kerning first=932 second=181 amount=-1 +kerning first=80 second=192 amount=-1 +kerning first=101 second=354 amount=-1 +kerning first=356 second=121 amount=-1 +kerning first=76 second=173 amount=-1 +kerning first=376 second=335 amount=-1 +kerning first=197 second=933 amount=-2 +kerning first=915 second=961 amount=-2 +kerning first=939 second=338 amount=-1 +kerning first=1058 second=1060 amount=-1 +kerning first=8217 second=44 amount=-2 +kerning first=8216 second=959 amount=-1 +kerning first=256 second=372 amount=-1 +kerning first=313 second=217 amount=-1 +kerning first=354 second=269 amount=-1 +kerning first=932 second=8217 amount=1 +kerning first=70 second=261 amount=-1 +kerning first=8216 second=233 amount=-1 +kerning first=221 second=235 amount=-1 +kerning first=285 second=356 amount=-1 +kerning first=354 second=117 amount=-1 +kerning first=89 second=101 amount=-1 +kerning first=248 second=8217 amount=-1 +kerning first=313 second=334 amount=-1 +kerning first=366 second=195 amount=-1 +kerning first=8220 second=115 amount=-1 +kerning first=1091 second=44 amount=-1 +kerning first=8216 second=356 amount=1 +kerning first=84 second=239 amount=-1 +kerning first=8217 second=299 amount=-1 +kerning first=8221 second=236 amount=-1 +kerning first=86 second=335 amount=-1 +kerning first=372 second=242 amount=-1 +kerning first=1043 second=1113 amount=-1 +kerning first=932 second=291 amount=-1 +kerning first=220 second=260 amount=-1 +kerning first=376 second=227 amount=-1 +kerning first=1027 second=1075 amount=-1 +kerning first=8216 second=1083 amount=-1 +kerning first=321 second=39 amount=-2 +kerning first=109 second=84 amount=-1 +kerning first=923 second=221 amount=-1 +kerning first=360 second=194 amount=-1 +kerning first=358 second=263 amount=-1 +kerning first=84 second=100 amount=-1 +kerning first=8221 second=101 amount=-1 +kerning first=317 second=79 amount=-1 +kerning first=354 second=197 amount=-1 +kerning first=315 second=212 amount=-1 +kerning first=70 second=194 amount=-1 +kerning first=910 second=934 amount=-1 +kerning first=8220 second=196 amount=-1 +kerning first=931 second=210 amount=-1 +kerning first=8204 second=376 amount=-1 +kerning first=923 second=84 amount=-1 +kerning first=313 second=216 amount=-1 +kerning first=1057 second=1098 amount=-1 +kerning first=308 second=125 amount=1 +kerning first=321 second=218 amount=-1 +kerning first=86 second=227 amount=-1 +kerning first=89 second=46 amount=-2 +kerning first=364 second=193 amount=-1 +kerning first=356 second=351 amount=-1 +kerning first=910 second=67 amount=-1 +kerning first=939 second=195 amount=-2 +kerning first=317 second=8212 amount=-1 +kerning first=1058 second=1094 amount=-1 +kerning first=358 second=192 amount=-1 +kerning first=1043 second=1057 amount=-1 +kerning first=1075 second=45 amount=-1 +kerning first=221 second=41 amount=1 +kerning first=1168 second=1098 amount=-1 +kerning first=87 second=226 amount=-1 +kerning first=319 second=71 amount=-1 +kerning first=939 second=290 amount=-1 +kerning first=213 second=44 amount=-1 +kerning first=354 second=341 amount=-1 +kerning first=8220 second=333 amount=-1 +kerning first=225 second=84 amount=-1 +kerning first=84 second=45 amount=-1 +kerning first=8221 second=46 amount=-2 +kerning first=354 second=187 amount=-1 +kerning first=230 second=358 amount=-1 +kerning first=193 second=8221 amount=-1 +kerning first=102 second=125 amount=2 +kerning first=8216 second=291 amount=-1 +kerning first=356 second=239 amount=-1 +kerning first=91 second=1026 amount=1 +kerning first=932 second=363 amount=-1 +kerning first=84 second=303 amount=-1 +kerning first=8221 second=297 amount=-1 +kerning first=354 second=963 amount=-1 +kerning first=79 second=44 amount=-1 +kerning first=195 second=8216 amount=-1 +kerning first=258 second=86 amount=-1 +kerning first=8220 second=959 amount=-1 +kerning first=376 second=287 amount=-1 +kerning first=356 second=100 amount=-1 +kerning first=227 second=358 amount=-1 +kerning first=354 second=235 amount=-1 +kerning first=939 second=8230 amount=-2 +kerning first=358 second=8221 amount=1 +kerning first=910 second=968 amount=-1 +kerning first=8220 second=233 amount=-1 +kerning first=8204 second=358 amount=-1 +kerning first=915 second=211 amount=-1 +kerning first=931 second=173 amount=-1 +kerning first=8222 second=221 amount=-2 +kerning first=260 second=939 amount=-2 +kerning first=232 second=932 amount=-1 +kerning first=193 second=354 amount=-1 +kerning first=221 second=212 amount=-1 +kerning first=8220 second=356 amount=1 +kerning first=932 second=943 amount=-1 +kerning first=936 second=923 amount=-1 +kerning first=965 second=39 amount=-1 +kerning first=1026 second=1058 amount=-1 +kerning first=1059 second=46 amount=-2 +kerning first=313 second=284 amount=-1 +kerning first=8217 second=160 amount=-1 +kerning first=932 second=245 amount=-1 +kerning first=275 second=358 amount=-1 +kerning first=358 second=961 amount=-1 +kerning first=1058 second=8250 amount=-1 +kerning first=8220 second=1083 amount=-1 +kerning first=8222 second=84 amount=-1 +kerning first=68 second=46 amount=-1 +kerning first=1066 second=8217 amount=-1 +kerning first=358 second=234 amount=-1 +kerning first=929 second=196 amount=-1 +kerning first=1043 second=1091 amount=-1 +kerning first=950 second=955 amount=1 +kerning first=8217 second=112 amount=-1 +kerning first=1027 second=1054 amount=-1 +kerning first=933 second=962 amount=-1 +kerning first=289 second=932 amount=-1 +kerning first=315 second=920 amount=-1 +kerning first=358 second=354 amount=1 +kerning first=98 second=932 amount=-1 +kerning first=356 second=45 amount=-1 +kerning first=968 second=34 amount=-1 +kerning first=89 second=198 amount=-1 +kerning first=87 second=283 amount=-1 +kerning first=376 second=71 amount=-1 +kerning first=221 second=367 amount=-1 +kerning first=8217 second=923 amount=-1 +kerning first=315 second=266 amount=-1 +kerning first=196 second=87 amount=-1 +kerning first=1075 second=8212 amount=-1 +kerning first=354 second=41 amount=1 +kerning first=356 second=303 amount=-1 +kerning first=84 second=8212 amount=-1 +kerning first=376 second=365 amount=-1 +kerning first=915 second=970 amount=-1 +kerning first=8221 second=198 amount=-1 +kerning first=910 second=46 amount=-2 +kerning first=1043 second=1035 amount=1 +kerning first=1168 second=1077 amount=-1 +kerning first=89 second=261 amount=-1 +kerning first=8216 second=245 amount=-1 +kerning first=8220 second=291 amount=-1 +kerning first=80 second=74 amount=-1 +kerning first=326 second=356 amount=-1 +kerning first=221 second=250 amount=-1 +kerning first=258 second=932 amount=-1 +kerning first=84 second=912 amount=-1 +kerning first=313 second=364 amount=-1 +kerning first=220 second=197 amount=-1 +kerning first=933 second=256 amount=-2 +kerning first=1038 second=46 amount=-2 +kerning first=84 second=253 amount=-1 +kerning first=313 second=8216 amount=-2 +kerning first=8217 second=326 amount=-1 +kerning first=119 second=44 amount=-1 +kerning first=160 second=89 amount=-1 +kerning first=372 second=358 amount=1 +kerning first=376 second=246 amount=-1 +kerning first=1027 second=1088 amount=-1 +kerning first=84 second=257 amount=-1 +kerning first=358 second=289 amount=-1 +kerning first=217 second=193 amount=-1 +kerning first=372 second=267 amount=-1 +kerning first=84 second=113 amount=-1 +kerning first=8221 second=114 amount=-1 +kerning first=89 second=194 amount=-1 +kerning first=370 second=198 amount=-1 +kerning first=910 second=945 amount=-1 +kerning first=934 second=44 amount=-1 +kerning first=221 second=920 amount=-1 +kerning first=91 second=106 amount=1 +kerning first=70 second=308 amount=-1 +kerning first=913 second=8221 amount=-1 +kerning first=91 second=1095 amount=-1 +kerning first=932 second=951 amount=-1 +kerning first=86 second=246 amount=-1 +kerning first=89 second=59 amount=-1 +kerning first=915 second=264 amount=-1 +kerning first=173 second=1026 amount=-1 +kerning first=8211 second=1059 amount=-1 +kerning first=319 second=221 amount=-1 +kerning first=1040 second=1026 amount=-1 +kerning first=326 second=8217 amount=-1 +kerning first=221 second=266 amount=-1 +kerning first=84 second=193 amount=-1 +kerning first=356 second=8212 amount=-1 +kerning first=8221 second=194 amount=-1 +kerning first=939 second=214 amount=-1 +kerning first=1058 second=1108 amount=-1 +kerning first=1027 second=44 amount=-1 +kerning first=319 second=336 amount=-1 +kerning first=8249 second=932 amount=-1 +kerning first=196 second=933 amount=-2 +kerning first=1027 second=1032 amount=-1 +kerning first=319 second=84 amount=-1 +kerning first=932 second=86 amount=1 +kerning first=354 second=367 amount=-1 +kerning first=89 second=337 amount=-1 +kerning first=70 second=369 amount=-1 +kerning first=242 second=84 amount=-1 +kerning first=256 second=8221 amount=-1 +kerning first=358 second=74 amount=-1 +kerning first=1059 second=1103 amount=-1 +kerning first=356 second=912 amount=-1 +kerning first=915 second=8211 amount=-1 +kerning first=281 second=356 amount=-1 +kerning first=40 second=87 amount=1 +kerning first=913 second=354 amount=-1 +kerning first=934 second=939 amount=-1 +kerning first=87 second=101 amount=-1 +kerning first=910 second=198 amount=-2 +kerning first=356 second=253 amount=-1 +kerning first=362 second=195 amount=-1 +kerning first=84 second=335 amount=-1 +kerning first=319 second=338 amount=-1 +kerning first=356 second=257 amount=-1 +kerning first=8221 second=337 amount=-1 +kerning first=932 second=230 amount=-1 +kerning first=358 second=371 amount=-1 +kerning first=218 second=260 amount=-1 +kerning first=354 second=972 amount=-1 +kerning first=356 second=113 amount=-1 +kerning first=354 second=250 amount=-1 +kerning first=89 second=231 amount=-1 +kerning first=370 second=194 amount=-1 +kerning first=8220 second=245 amount=-1 +kerning first=910 second=944 amount=-1 +kerning first=76 second=372 amount=-1 +kerning first=8212 second=221 amount=-1 +kerning first=256 second=354 amount=-1 +kerning first=313 second=212 amount=-1 +kerning first=1061 second=1095 amount=-1 +kerning first=221 second=226 amount=-1 +kerning first=1059 second=59 amount=-1 +kerning first=354 second=109 amount=-1 +kerning first=89 second=93 amount=1 +kerning first=324 second=358 amount=-1 +kerning first=939 second=973 amount=-1 +kerning first=358 second=970 amount=-1 +kerning first=8212 second=84 amount=-1 +kerning first=1058 second=8230 amount=-1 +kerning first=84 second=227 amount=-1 +kerning first=87 second=46 amount=-1 +kerning first=356 second=193 amount=-1 +kerning first=904 second=912 amount=1 +kerning first=8217 second=281 amount=-1 +kerning first=8221 second=231 amount=-1 +kerning first=112 second=358 amount=-1 +kerning first=358 second=353 amount=-1 +kerning first=1043 second=1105 amount=-1 +kerning first=932 second=271 amount=-1 +kerning first=337 second=932 amount=-1 +kerning first=91 second=376 amount=1 +kerning first=932 second=120 amount=-1 +kerning first=376 second=336 amount=-1 +kerning first=317 second=71 amount=-1 +kerning first=214 second=44 amount=-1 +kerning first=376 second=84 amount=1 +kerning first=1169 second=8230 amount=-1 +kerning first=910 second=194 amount=-2 +kerning first=1057 second=1090 amount=-1 +kerning first=1038 second=1103 amount=-1 +kerning first=8216 second=230 amount=-1 +kerning first=932 second=932 amount=1 +kerning first=187 second=89 amount=-1 +kerning first=8211 second=1038 amount=-1 +kerning first=315 second=67 amount=-1 +kerning first=356 second=335 amount=-1 +kerning first=248 second=932 amount=-1 +kerning first=8250 second=354 amount=-1 +kerning first=935 second=970 amount=1 +kerning first=910 second=59 amount=-1 +kerning first=1058 second=1086 amount=-1 +kerning first=319 second=290 amount=-1 +kerning first=192 second=8216 amount=-1 +kerning first=376 second=338 amount=-1 +kerning first=933 second=927 amount=-1 +kerning first=908 second=8230 amount=-1 +kerning first=224 second=358 amount=-1 +kerning first=86 second=84 amount=1 +kerning first=1168 second=1090 amount=-1 +kerning first=354 second=324 amount=-1 +kerning first=932 second=65 amount=-1 +kerning first=89 second=285 amount=-1 +kerning first=76 second=171 amount=-1 +kerning first=933 second=192 amount=-2 +kerning first=258 second=939 amount=-2 +kerning first=1040 second=1095 amount=-1 +kerning first=234 second=932 amount=-1 +kerning first=306 second=93 amount=1 +kerning first=8216 second=271 amount=-1 +kerning first=933 second=286 amount=-1 +kerning first=1038 second=59 amount=-1 +kerning first=221 second=283 amount=-1 +kerning first=356 second=227 amount=-1 +kerning first=283 second=358 amount=-1 +kerning first=333 second=8221 amount=-1 +kerning first=932 second=347 amount=-1 +kerning first=1027 second=1101 amount=-1 +kerning first=917 second=912 amount=1 +kerning first=84 second=287 amount=-1 +kerning first=8221 second=285 amount=-1 +kerning first=91 second=358 amount=1 +kerning first=354 second=953 amount=-1 +kerning first=76 second=220 amount=-1 +kerning first=372 second=301 amount=1 +kerning first=285 second=932 amount=-1 +kerning first=376 second=265 amount=-1 +kerning first=354 second=226 amount=-1 +kerning first=358 second=8211 amount=-1 +kerning first=313 second=920 amount=-1 +kerning first=1168 second=46 amount=-1 +kerning first=8216 second=932 amount=1 +kerning first=87 second=198 amount=-1 +kerning first=89 second=308 amount=-1 +kerning first=315 second=360 amount=-1 +kerning first=932 second=966 amount=-1 +kerning first=8217 second=244 amount=-1 +kerning first=1059 second=1026 amount=1 +kerning first=313 second=266 amount=-1 +kerning first=193 second=87 amount=-1 +kerning first=939 second=954 amount=-1 +kerning first=932 second=238 amount=-1 +kerning first=333 second=354 amount=-1 +kerning first=65 second=221 amount=-1 +kerning first=86 second=265 amount=-1 +kerning first=358 second=225 amount=-1 +kerning first=8216 second=65 amount=-1 +kerning first=319 second=368 amount=-1 +kerning first=221 second=67 amount=-1 +kerning first=902 second=8216 amount=-1 +kerning first=376 second=195 amount=-1 +kerning first=8249 second=939 amount=-1 +kerning first=936 second=260 amount=-1 +kerning first=933 second=961 amount=-1 +kerning first=1043 second=1083 amount=-1 +kerning first=272 second=44 amount=-1 +kerning first=8221 second=308 amount=-1 +kerning first=932 second=99 amount=-1 +kerning first=89 second=369 amount=-1 +kerning first=1041 second=1035 amount=-1 +kerning first=329 second=84 amount=-1 +kerning first=376 second=290 amount=-1 +kerning first=65 second=84 amount=-1 +kerning first=358 second=87 amount=1 +kerning first=87 second=261 amount=-1 +kerning first=8220 second=230 amount=-1 +kerning first=328 second=356 amount=-1 +kerning first=8216 second=347 amount=-1 +kerning first=221 second=349 amount=-1 +kerning first=218 second=197 amount=-1 +kerning first=160 second=8220 amount=-1 +kerning first=339 second=354 amount=-1 +kerning first=86 second=195 amount=-1 +kerning first=84 second=365 amount=-1 +kerning first=356 second=287 amount=-1 +kerning first=173 second=376 amount=-1 +kerning first=8217 second=260 amount=-1 +kerning first=321 second=262 amount=-1 +kerning first=354 second=331 amount=-1 +kerning first=358 second=305 amount=-1 +kerning first=89 second=242 amount=-1 +kerning first=97 second=8221 amount=-1 +kerning first=219 second=193 amount=-1 +kerning first=376 second=8230 amount=-2 +kerning first=8216 second=966 amount=-1 +kerning first=87 second=194 amount=-1 +kerning first=368 second=198 amount=-1 +kerning first=354 second=283 amount=-1 +kerning first=932 second=44 amount=-1 +kerning first=235 second=354 amount=-1 +kerning first=8220 second=271 amount=-1 +kerning first=354 second=122 amount=-1 +kerning first=315 second=39 amount=-2 +kerning first=84 second=941 amount=-1 +kerning first=102 second=8216 amount=1 +kerning first=34 second=256 amount=-1 +kerning first=84 second=246 amount=-1 +kerning first=8221 second=242 amount=-1 +kerning first=317 second=221 amount=-1 +kerning first=1038 second=1026 amount=1 +kerning first=1090 second=8211 amount=-1 +kerning first=328 second=8217 amount=-1 +kerning first=358 second=273 amount=-1 +kerning first=8216 second=99 amount=-1 +kerning first=1043 second=1119 amount=-1 +kerning first=221 second=101 amount=-1 +kerning first=932 second=299 amount=-1 +kerning first=376 second=232 amount=-1 +kerning first=1027 second=1080 amount=-1 +kerning first=76 second=927 amount=-1 +kerning first=291 second=354 amount=-1 +kerning first=308 second=41 amount=1 +kerning first=86 second=8230 amount=-1 +kerning first=229 second=356 amount=-1 +kerning first=317 second=336 amount=-1 +kerning first=354 second=934 amount=-1 +kerning first=358 second=277 amount=-1 +kerning first=8220 second=932 amount=1 +kerning first=97 second=354 amount=-1 +kerning first=920 second=46 amount=-1 +kerning first=84 second=105 amount=-1 +kerning first=193 second=933 amount=-2 +kerning first=317 second=84 amount=-1 +kerning first=315 second=218 amount=-1 +kerning first=358 second=121 amount=-1 +kerning first=87 second=337 amount=-1 +kerning first=942 second=8221 amount=-1 +kerning first=372 second=111 amount=-1 +kerning first=244 second=84 amount=-1 +kerning first=76 second=286 amount=-1 +kerning first=376 second=97 amount=-1 +kerning first=1111 second=1115 amount=1 +kerning first=923 second=89 amount=-1 +kerning first=89 second=262 amount=-1 +kerning first=279 second=356 amount=-1 +kerning first=321 second=376 amount=-1 +kerning first=86 second=232 amount=-1 +kerning first=364 second=195 amount=-1 +kerning first=8220 second=65 amount=-1 +kerning first=319 second=214 amount=-1 +kerning first=356 second=365 amount=-1 +kerning first=84 second=916 amount=-1 +kerning first=173 second=358 amount=-1 +kerning first=102 second=41 amount=2 +kerning first=915 second=45 amount=-1 +kerning first=317 second=338 amount=-1 +kerning first=321 second=332 amount=-1 +kerning first=270 second=46 amount=-1 +kerning first=1058 second=1099 amount=-1 +kerning first=8216 second=44 amount=-2 +kerning first=271 second=316 amount=1 +kerning first=221 second=46 amount=-2 +kerning first=1090 second=1076 amount=-1 +kerning first=8216 second=1032 amount=-1 +kerning first=321 second=85 amount=-1 +kerning first=86 second=97 amount=-1 +kerning first=87 second=231 amount=-1 +kerning first=368 second=194 amount=-1 +kerning first=1168 second=1103 amount=-1 +kerning first=354 second=349 amount=-1 +kerning first=76 second=8221 amount=-2 +kerning first=933 second=211 amount=-1 +kerning first=8220 second=347 amount=-1 +kerning first=229 second=8217 amount=-1 +kerning first=1059 second=1095 amount=-1 +kerning first=356 second=941 amount=-1 +kerning first=923 second=34 amount=-1 +kerning first=87 second=93 amount=1 +kerning first=356 second=246 amount=-1 +kerning first=913 second=87 amount=-1 +kerning first=1056 second=8230 amount=-2 +kerning first=932 second=373 amount=-1 +kerning first=1027 second=1115 amount=1 +kerning first=110 second=358 amount=-1 +kerning first=354 second=968 amount=-1 +kerning first=358 second=351 amount=-1 +kerning first=8220 second=966 amount=-1 +kerning first=326 second=932 amount=-1 +kerning first=84 second=8250 amount=-1 +kerning first=356 second=105 amount=-1 +kerning first=354 second=236 amount=-1 +kerning first=1058 second=1044 amount=-1 +kerning first=910 second=942 amount=-1 +kerning first=1168 second=59 amount=-1 +kerning first=76 second=354 amount=-1 +kerning first=211 second=44 amount=-1 +kerning first=89 second=332 amount=-1 +kerning first=366 second=913 amount=-1 +kerning first=932 second=974 amount=-1 +kerning first=256 second=87 amount=-1 +kerning first=1026 second=1063 amount=-1 +kerning first=321 second=358 amount=-1 +kerning first=354 second=101 amount=-1 +kerning first=8220 second=99 amount=-1 +kerning first=356 second=916 amount=-1 +kerning first=84 second=949 amount=-1 +kerning first=1059 second=1040 amount=-1 +kerning first=932 second=249 amount=-1 +kerning first=915 second=79 amount=-1 +kerning first=936 second=197 amount=-1 +kerning first=8222 second=89 amount=-2 +kerning first=313 second=67 amount=-1 +kerning first=8217 second=269 amount=-1 +kerning first=922 second=308 amount=1 +kerning first=358 second=239 amount=-1 +kerning first=366 second=258 amount=-1 +kerning first=372 second=224 amount=-1 +kerning first=932 second=259 amount=-1 +kerning first=376 second=214 amount=-1 +kerning first=171 second=354 amount=-1 +kerning first=933 second=970 amount=-1 +kerning first=1027 second=1059 amount=1 +kerning first=1043 second=1096 amount=-1 +kerning first=317 second=290 amount=-1 +kerning first=194 second=8216 amount=-1 +kerning first=932 second=112 amount=-1 +kerning first=39 second=256 amount=-1 +kerning first=931 second=927 amount=-1 +kerning first=84 second=84 amount=1 +kerning first=226 second=358 amount=-1 +kerning first=358 second=100 amount=-1 +kerning first=929 second=65 amount=-1 +kerning first=915 second=8212 amount=-1 +kerning first=1038 second=1095 amount=-1 +kerning first=373 second=44 amount=-1 +kerning first=160 second=8222 amount=-2 +kerning first=931 second=286 amount=-1 +kerning first=221 second=198 amount=-1 +kerning first=91 second=1066 amount=1 +kerning first=932 second=923 amount=-1 +kerning first=8217 second=197 amount=-1 +kerning first=321 second=199 amount=-1 +kerning first=354 second=46 amount=-1 +kerning first=84 second=378 amount=-1 +kerning first=910 second=262 amount=-1 +kerning first=8220 second=44 amount=-2 +kerning first=939 second=913 amount=-2 +kerning first=335 second=8221 amount=-1 +kerning first=195 second=39 amount=-1 +kerning first=8220 second=1032 amount=-1 +kerning first=915 second=912 amount=-1 +kerning first=356 second=8250 amount=-1 +kerning first=376 second=361 amount=-1 +kerning first=321 second=288 amount=-1 +kerning first=89 second=358 amount=1 +kerning first=1058 second=1078 amount=-1 +kerning first=372 second=339 amount=-1 +kerning first=197 second=221 amount=-1 +kerning first=281 second=932 amount=-1 +kerning first=8216 second=974 amount=-1 +kerning first=913 second=933 amount=-2 +kerning first=1168 second=1082 amount=-1 +kerning first=939 second=258 amount=-2 +kerning first=354 second=297 amount=-1 +kerning first=89 second=267 amount=-1 +kerning first=1118 second=46 amount=-1 +kerning first=34 second=192 amount=-1 +kerning first=1050 second=1033 amount=1 +kerning first=85 second=198 amount=-1 +kerning first=358 second=45 amount=-1 +kerning first=313 second=360 amount=-1 +kerning first=931 second=8221 amount=-1 +kerning first=356 second=949 amount=-1 +kerning first=197 second=84 amount=-1 +kerning first=8216 second=259 amount=-1 +kerning first=933 second=264 amount=-1 +kerning first=160 second=356 amount=-1 +kerning first=221 second=261 amount=-1 +kerning first=8217 second=341 amount=-1 +kerning first=8221 second=358 amount=1 +kerning first=1057 second=1026 amount=1 +kerning first=1100 second=1091 amount=-1 +kerning first=1038 second=1040 amount=-1 +kerning first=932 second=326 amount=-1 +kerning first=335 second=354 amount=-1 +kerning first=376 second=251 amount=-1 +kerning first=1027 second=1093 amount=-1 +kerning first=84 second=265 amount=-1 +kerning first=256 second=933 amount=-2 +kerning first=8221 second=267 amount=-1 +kerning first=317 second=368 amount=-1 +kerning first=354 second=945 amount=-1 +kerning first=332 second=44 amount=-1 +kerning first=76 second=211 amount=-1 +kerning first=358 second=303 amount=-1 +kerning first=217 second=195 amount=-1 +kerning first=372 second=275 amount=-1 +kerning first=84 second=118 amount=-1 +kerning first=255 second=44 amount=-1 +kerning first=356 second=84 amount=1 +kerning first=89 second=199 amount=-1 +kerning first=295 second=84 amount=-1 +kerning first=8216 second=923 amount=-1 +kerning first=915 second=193 amount=-2 +kerning first=1168 second=1026 amount=1 +kerning first=89 second=288 amount=-1 +kerning first=933 second=8211 amount=-1 +kerning first=221 second=194 amount=-1 +kerning first=8204 second=372 amount=-1 +kerning first=8217 second=235 amount=-1 +kerning first=910 second=332 amount=-1 +kerning first=1107 second=44 amount=-1 +kerning first=356 second=378 amount=-1 +kerning first=939 second=946 amount=-1 +kerning first=111 second=356 amount=-1 +kerning first=932 second=229 amount=-1 +kerning first=915 second=58 amount=-1 +kerning first=1068 second=1059 amount=-1 +kerning first=84 second=195 amount=-1 +kerning first=321 second=362 amount=-1 +kerning first=1058 second=1113 amount=-1 +kerning first=1043 second=1075 amount=-1 +kerning first=221 second=59 amount=-1 +kerning first=1027 second=1038 amount=1 +kerning first=34 second=961 amount=-1 +kerning first=1168 second=1118 amount=-1 +kerning first=87 second=242 amount=-1 +kerning first=319 second=89 amount=-1 +kerning first=85 second=194 amount=-1 +kerning first=354 second=198 amount=-1 +kerning first=939 second=81 amount=-1 +kerning first=929 second=44 amount=-2 +kerning first=233 second=354 amount=-1 +kerning first=1059 second=1109 amount=-1 +kerning first=1028 second=1033 amount=1 +kerning first=221 second=337 amount=-1 +kerning first=313 second=39 amount=-2 +kerning first=1027 second=8249 amount=-1 +kerning first=1075 second=8230 amount=-1 +kerning first=173 second=910 amount=-1 +kerning first=84 second=345 amount=-1 +kerning first=356 second=265 amount=-1 +kerning first=8221 second=343 amount=-1 +kerning first=1035 second=1026 amount=-1 +kerning first=354 second=944 amount=-1 +kerning first=8220 second=974 amount=-1 +kerning first=287 second=354 amount=-1 +kerning first=80 second=193 amount=-1 +kerning first=84 second=8230 amount=-1 +kerning first=356 second=118 amount=-1 +kerning first=111 second=8217 amount=-1 +kerning first=228 second=356 amount=-1 +kerning first=354 second=255 amount=-1 +kerning first=915 second=957 amount=-1 +kerning first=1058 second=1057 amount=-1 +kerning first=358 second=8212 amount=-1 +kerning first=70 second=252 amount=-1 +kerning first=1090 second=45 amount=-1 +kerning first=45 second=1026 amount=-1 +kerning first=923 second=8220 amount=-1 +kerning first=313 second=218 amount=-1 +kerning first=319 second=34 amount=-2 +kerning first=271 second=98 amount=1 +kerning first=354 second=261 amount=-1 +kerning first=241 second=84 amount=-1 +kerning first=8216 second=229 amount=-1 +kerning first=8220 second=259 amount=-1 +kerning first=221 second=231 amount=-1 +kerning first=173 second=1066 amount=-1 +kerning first=46 second=34 amount=-2 +kerning first=354 second=114 amount=-1 +kerning first=1040 second=1066 amount=-1 +kerning first=366 second=196 amount=-1 +kerning first=277 second=356 amount=-1 +kerning first=358 second=912 amount=-1 +kerning first=8212 second=89 amount=-1 +kerning first=84 second=232 amount=-1 +kerning first=8221 second=237 amount=-1 +kerning first=356 second=195 amount=-1 +kerning first=317 second=214 amount=-1 +kerning first=39 second=192 amount=-1 +kerning first=358 second=253 amount=-1 +kerning first=372 second=243 amount=-1 +kerning first=932 second=281 amount=-1 +kerning first=376 second=228 amount=-1 +kerning first=221 second=93 amount=1 +kerning first=260 second=8216 amount=-1 +kerning first=1027 second=1072 amount=-1 +kerning first=932 second=125 amount=1 +kerning first=358 second=257 amount=-1 +kerning first=8220 second=923 amount=-1 +kerning first=103 second=84 amount=-1 +kerning first=245 second=358 amount=-1 +kerning first=84 second=97 amount=-1 +kerning first=354 second=194 amount=-1 +kerning first=358 second=113 amount=-1 +kerning first=931 second=211 amount=-1 +kerning first=76 second=264 amount=-1 +kerning first=228 second=8217 amount=-1 +kerning first=910 second=199 amount=-1 +kerning first=1057 second=1095 amount=-1 +kerning first=187 second=356 amount=-1 +kerning first=1038 second=1109 amount=-1 +kerning first=321 second=210 amount=-1 +kerning first=86 second=228 amount=-1 +kerning first=910 second=288 amount=-1 +kerning first=356 second=345 amount=-1 +kerning first=1068 second=1038 amount=-1 +kerning first=935 second=912 amount=1 +kerning first=356 second=8230 amount=-1 +kerning first=939 second=196 amount=-2 +kerning first=1058 second=1091 amount=-1 +kerning first=358 second=193 amount=-1 +kerning first=1043 second=1054 amount=-1 +kerning first=328 second=932 amount=-1 +kerning first=376 second=248 amount=-1 +kerning first=1168 second=1095 amount=-1 +kerning first=1056 second=1044 amount=-1 +kerning first=354 second=337 amount=-1 +kerning first=76 second=8211 amount=-1 +kerning first=372 second=256 amount=-1 +kerning first=1113 second=1098 amount=-1 diff --git a/assets/style/myriad-medium-small.fnt b/assets/style/myriad-medium-small.fnt new file mode 100644 index 00000000..7c582e6b --- /dev/null +++ b/assets/style/myriad-medium-small.fnt @@ -0,0 +1,3178 @@ +info face="MyriadPro-Regular" size=12 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=15 base=9 scaleW=128 scaleH=512 pages=1 packed=0 +page id=0 file="myriad-medium-small.png" +chars count=506 +char id=0 x=72 y=121 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=13 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=0 page=0 chnl=0 +char id=33 x=80 y=121 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=34 x=93 y=349 width=6 height=5 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=35 x=117 y=276 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=36 x=8 y=42 width=8 height=13 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=37 x=0 y=287 width=12 height=10 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=38 x=85 y=121 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=39 x=123 y=254 width=4 height=5 xoffset=-1 yoffset=0 xadvance=2 page=0 chnl=0 +char id=40 x=91 y=108 width=6 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=41 x=97 y=108 width=5 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=42 x=0 y=349 width=7 height=7 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=43 x=78 y=307 width=9 height=9 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=44 x=38 y=349 width=5 height=6 xoffset=-1 yoffset=7 xadvance=2 page=0 chnl=0 +char id=45 x=64 y=356 width=6 height=3 xoffset=-1 yoffset=4 xadvance=4 page=0 chnl=0 +char id=46 x=11 y=356 width=5 height=4 xoffset=-1 yoffset=6 xadvance=2 page=0 chnl=0 +char id=47 x=95 y=121 width=8 height=11 xoffset=-2 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=48 x=12 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=49 x=20 y=287 width=5 height=10 xoffset=0 yoffset=0 xadvance=6 page=0 chnl=0 +char id=50 x=25 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=51 x=33 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=52 x=41 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=53 x=49 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=54 x=57 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=55 x=65 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=56 x=73 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=57 x=103 y=121 width=8 height=11 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=58 x=122 y=297 width=5 height=8 xoffset=-1 yoffset=2 xadvance=2 page=0 chnl=0 +char id=59 x=111 y=121 width=5 height=11 xoffset=-1 yoffset=2 xadvance=2 page=0 chnl=0 +char id=60 x=87 y=307 width=9 height=9 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=61 x=99 y=349 width=9 height=5 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=62 x=96 y=307 width=9 height=9 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=63 x=116 y=121 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=64 x=81 y=287 width=11 height=10 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=0 +char id=65 x=0 y=133 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=66 x=10 y=133 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=67 x=18 y=133 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=68 x=27 y=133 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=69 x=37 y=133 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=70 x=45 y=133 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=71 x=53 y=133 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=72 x=63 y=133 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=73 x=123 y=121 width=4 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=74 x=72 y=133 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=75 x=78 y=133 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=76 x=87 y=133 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=77 x=95 y=133 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=78 x=106 y=133 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=79 x=115 y=133 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=80 x=0 y=144 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=81 x=16 y=42 width=10 height=13 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=82 x=8 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=83 x=17 y=144 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=84 x=25 y=144 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=85 x=34 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=86 x=43 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=87 x=52 y=144 width=13 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=88 x=65 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=89 x=74 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=90 x=83 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=91 x=26 y=42 width=6 height=13 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=92 x=92 y=144 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=93 x=122 y=28 width=5 height=13 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=94 x=0 y=317 width=9 height=8 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=95 x=70 y=356 width=8 height=3 xoffset=-1 yoffset=9 xadvance=6 page=0 chnl=0 +char id=96 x=16 y=356 width=5 height=4 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=97 x=9 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=98 x=99 y=144 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=99 x=17 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=100 x=108 y=144 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=101 x=25 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=102 x=116 y=144 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=103 x=0 y=155 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=104 x=8 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=105 x=122 y=144 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=106 x=0 y=0 width=6 height=14 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=107 x=16 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=108 x=123 y=82 width=4 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=109 x=33 y=317 width=12 height=8 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=110 x=45 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=111 x=53 y=317 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=112 x=24 y=155 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=113 x=33 y=155 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=114 x=62 y=317 width=6 height=8 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=0 +char id=115 x=68 y=317 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=116 x=92 y=287 width=6 height=10 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=117 x=75 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=118 x=83 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=119 x=91 y=317 width=11 height=8 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=120 x=102 y=317 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=121 x=41 y=155 width=8 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=122 x=110 y=317 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=123 x=32 y=42 width=6 height=13 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=124 x=6 y=0 width=3 height=14 xoffset=0 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=125 x=38 y=42 width=6 height=13 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=126 x=108 y=349 width=9 height=5 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=160 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=161 x=49 y=155 width=5 height=11 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=162 x=102 y=108 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=163 x=98 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=164 x=106 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=165 x=114 y=287 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=166 x=44 y=42 width=3 height=13 xoffset=0 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=167 x=110 y=108 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=168 x=21 y=356 width=6 height=4 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=169 x=0 y=297 width=10 height=10 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=170 x=43 y=349 width=6 height=6 xoffset=-1 yoffset=1 xadvance=4 page=0 chnl=0 +char id=171 x=7 y=349 width=7 height=7 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=172 x=49 y=349 width=9 height=6 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=173 x=78 y=356 width=6 height=3 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=0 +char id=174 x=14 y=349 width=7 height=7 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=175 x=84 y=356 width=6 height=3 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=176 x=58 y=349 width=6 height=6 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=177 x=10 y=297 width=9 height=10 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=178 x=121 y=325 width=6 height=7 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=179 x=117 y=317 width=6 height=8 xoffset=-1 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=180 x=27 y=356 width=5 height=4 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=181 x=54 y=155 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=182 x=118 y=108 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=183 x=32 y=356 width=4 height=4 xoffset=-1 yoffset=4 xadvance=2 page=0 chnl=0 +char id=184 x=117 y=349 width=5 height=5 xoffset=-1 yoffset=8 xadvance=4 page=0 chnl=0 +char id=185 x=121 y=341 width=5 height=7 xoffset=-1 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=186 x=64 y=349 width=7 height=6 xoffset=-1 yoffset=1 xadvance=4 page=0 chnl=0 +char id=187 x=21 y=349 width=7 height=7 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=188 x=19 y=297 width=11 height=10 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=189 x=30 y=297 width=11 height=10 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=190 x=41 y=297 width=11 height=10 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=191 x=63 y=155 width=7 height=11 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=192 x=47 y=42 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=193 x=57 y=42 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=194 x=67 y=42 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=195 x=9 y=0 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=7 page=0 chnl=0 +char id=196 x=77 y=42 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=197 x=19 y=0 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=7 page=0 chnl=0 +char id=198 x=70 y=155 width=13 height=11 xoffset=-2 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=199 x=29 y=0 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=200 x=87 y=42 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=201 x=95 y=42 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=202 x=103 y=42 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=203 x=111 y=42 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=204 x=119 y=42 width=6 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=205 x=0 y=56 width=6 height=13 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=206 x=6 y=56 width=7 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=207 x=13 y=56 width=7 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=208 x=83 y=155 width=11 height=11 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=209 x=38 y=0 width=9 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=210 x=20 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=211 x=30 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=212 x=40 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=213 x=47 y=0 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=214 x=50 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=215 x=105 y=307 width=9 height=9 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=216 x=0 y=121 width=10 height=12 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=217 x=60 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=218 x=69 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=219 x=78 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=220 x=87 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=221 x=96 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=222 x=94 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=223 x=102 y=155 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=224 x=111 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=225 x=119 y=155 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=226 x=0 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=227 x=8 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=228 x=16 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=229 x=24 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=230 x=0 y=325 width=11 height=8 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=231 x=32 y=166 width=8 height=11 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=232 x=40 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=233 x=48 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=234 x=56 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=235 x=64 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=236 x=72 y=166 width=5 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=237 x=77 y=166 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=238 x=83 y=166 width=6 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=239 x=89 y=166 width=7 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=240 x=96 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=241 x=104 y=166 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=242 x=112 y=166 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=243 x=0 y=177 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=244 x=9 y=177 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=245 x=18 y=177 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=246 x=27 y=177 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=247 x=11 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=248 x=52 y=297 width=9 height=10 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=249 x=36 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=250 x=44 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=251 x=52 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=252 x=60 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=253 x=57 y=0 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=254 x=65 y=0 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=255 x=74 y=0 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=256 x=105 y=56 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=257 x=61 y=297 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=258 x=82 y=0 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=7 page=0 chnl=0 +char id=259 x=68 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=260 x=92 y=0 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=261 x=76 y=177 width=8 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=262 x=115 y=56 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=263 x=84 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=264 x=0 y=69 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=265 x=92 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=266 x=9 y=69 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=267 x=100 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=268 x=18 y=69 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=269 x=108 y=177 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=270 x=27 y=69 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=271 x=116 y=177 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=272 x=0 y=188 width=11 height=11 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=273 x=11 y=188 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=274 x=37 y=69 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=275 x=69 y=297 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=276 x=102 y=0 width=8 height=14 xoffset=-1 yoffset=-4 xadvance=6 page=0 chnl=0 +char id=277 x=20 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=278 x=45 y=69 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=279 x=28 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=280 x=110 y=0 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=281 x=36 y=188 width=8 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=282 x=53 y=69 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=283 x=44 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=284 x=61 y=69 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=285 x=118 y=0 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=286 x=0 y=14 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=287 x=10 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=288 x=71 y=69 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=289 x=18 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=290 x=26 y=14 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=291 x=36 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=292 x=81 y=69 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=293 x=90 y=69 width=9 height=13 xoffset=-2 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=294 x=52 y=188 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=295 x=62 y=188 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=296 x=44 y=14 width=6 height=14 xoffset=-2 yoffset=-4 xadvance=3 page=0 chnl=0 +char id=297 x=121 y=166 width=6 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=298 x=99 y=69 width=5 height=13 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=299 x=122 y=287 width=5 height=10 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=300 x=50 y=14 width=6 height=14 xoffset=-2 yoffset=-4 xadvance=3 page=0 chnl=0 +char id=301 x=71 y=188 width=6 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=302 x=56 y=14 width=5 height=14 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=303 x=61 y=14 width=5 height=14 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=304 x=104 y=69 width=5 height=13 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=305 x=123 y=317 width=4 height=8 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=306 x=77 y=188 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=307 x=66 y=14 width=7 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=308 x=109 y=69 width=7 height=13 xoffset=-1 yoffset=-3 xadvance=4 page=0 chnl=0 +char id=309 x=73 y=14 width=6 height=14 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=310 x=79 y=14 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=311 x=88 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=312 x=20 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=313 x=116 y=69 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=314 x=0 y=82 width=6 height=13 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=315 x=96 y=14 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=316 x=104 y=14 width=5 height=14 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=317 x=86 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=318 x=94 y=188 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=319 x=100 y=188 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=320 x=108 y=188 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=321 x=114 y=188 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=322 x=0 y=199 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=323 x=6 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=324 x=5 y=199 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=325 x=109 y=14 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=326 x=13 y=199 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=327 x=15 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=328 x=21 y=199 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=329 x=29 y=199 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=330 x=118 y=14 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=331 x=37 y=199 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=332 x=24 y=82 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=333 x=77 y=297 width=9 height=10 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=334 x=0 y=28 width=10 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=335 x=45 y=199 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=336 x=34 y=82 width=10 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=337 x=54 y=199 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=338 x=44 y=82 width=13 height=13 xoffset=-1 yoffset=-2 xadvance=11 page=0 chnl=0 +char id=339 x=28 y=325 width=12 height=8 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=340 x=57 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=341 x=63 y=199 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=342 x=10 y=28 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=343 x=69 y=199 width=6 height=11 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=0 +char id=344 x=66 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=345 x=75 y=199 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=346 x=75 y=82 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=347 x=81 y=199 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=348 x=83 y=82 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=349 x=88 y=199 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=350 x=19 y=28 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=351 x=95 y=199 width=7 height=11 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=352 x=91 y=82 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=353 x=102 y=199 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=354 x=27 y=28 width=9 height=14 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=355 x=99 y=82 width=6 height=13 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=356 x=105 y=82 width=9 height=13 xoffset=-2 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=357 x=109 y=199 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=358 x=116 y=199 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=359 x=86 y=297 width=6 height=10 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=360 x=36 y=28 width=9 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=361 x=0 y=210 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=362 x=114 y=82 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=363 x=92 y=297 width=8 height=10 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=364 x=45 y=28 width=9 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=365 x=8 y=210 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=366 x=54 y=28 width=9 height=14 xoffset=-1 yoffset=-4 xadvance=8 page=0 chnl=0 +char id=367 x=16 y=210 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=368 x=0 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=369 x=24 y=210 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=370 x=63 y=28 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=371 x=32 y=210 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=372 x=9 y=95 width=13 height=13 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=373 x=41 y=210 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=374 x=22 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=375 x=72 y=28 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=376 x=31 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=377 x=40 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=378 x=52 y=210 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=379 x=49 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=380 x=59 y=210 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=381 x=58 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=382 x=66 y=210 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=894 x=73 y=210 width=5 height=11 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=900 x=36 y=356 width=4 height=4 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=901 x=40 y=356 width=7 height=4 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=902 x=78 y=210 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=903 x=47 y=356 width=5 height=4 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=904 x=88 y=210 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=905 x=97 y=210 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=906 x=107 y=210 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=908 x=112 y=210 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=910 x=0 y=221 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=911 x=11 y=221 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=912 x=22 y=221 width=7 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=913 x=29 y=221 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=914 x=39 y=221 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=915 x=47 y=221 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=916 x=55 y=221 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=917 x=65 y=221 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=918 x=73 y=221 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=919 x=82 y=221 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=920 x=91 y=221 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=921 x=123 y=188 width=4 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=922 x=101 y=221 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=923 x=110 y=221 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=924 x=0 y=232 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=925 x=11 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=926 x=20 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=927 x=29 y=232 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=928 x=39 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=929 x=48 y=232 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=931 x=56 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=932 x=65 y=232 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=933 x=74 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=934 x=10 y=121 width=11 height=12 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=935 x=83 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=936 x=92 y=232 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=937 x=102 y=232 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=938 x=67 y=95 width=7 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=939 x=74 y=95 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=940 x=113 y=232 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=941 x=0 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=942 x=80 y=28 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=943 x=120 y=221 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=944 x=8 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=945 x=40 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=946 x=88 y=28 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=947 x=16 y=243 width=9 height=11 xoffset=-2 yoffset=2 xadvance=6 page=0 chnl=0 +char id=948 x=25 y=243 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=949 x=49 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=950 x=83 y=95 width=7 height=13 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=951 x=34 y=243 width=8 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=952 x=42 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=953 x=57 y=325 width=5 height=8 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=954 x=62 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=955 x=50 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=956 x=58 y=243 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=957 x=70 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=958 x=90 y=95 width=8 height=13 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=959 x=78 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=960 x=87 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=961 x=67 y=243 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=962 x=100 y=297 width=7 height=10 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=963 x=96 y=325 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=964 x=105 y=325 width=8 height=8 xoffset=-2 yoffset=2 xadvance=5 page=0 chnl=0 +char id=965 x=113 y=325 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=966 x=21 y=121 width=10 height=12 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=967 x=76 y=243 width=8 height=11 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=968 x=98 y=95 width=10 height=13 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=969 x=0 y=333 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=970 x=107 y=297 width=7 height=10 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=971 x=114 y=297 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=972 x=84 y=243 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=973 x=93 y=243 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=974 x=101 y=243 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1025 x=108 y=95 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=1026 x=116 y=95 width=11 height=13 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1027 x=0 y=108 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=5 page=0 chnl=0 +char id=1028 x=111 y=243 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1029 x=0 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1030 x=123 y=210 width=4 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=1031 x=8 y=108 width=7 height=13 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=1032 x=120 y=243 width=6 height=11 xoffset=-1 yoffset=-1 xadvance=4 page=0 chnl=0 +char id=1033 x=31 y=121 width=14 height=12 xoffset=-2 yoffset=-1 xadvance=11 page=0 chnl=0 +char id=1034 x=8 y=254 width=13 height=11 xoffset=-1 yoffset=-1 xadvance=11 page=0 chnl=0 +char id=1035 x=21 y=254 width=11 height=11 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1036 x=15 y=108 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=1038 x=24 y=108 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=1039 x=97 y=28 width=9 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1040 x=32 y=254 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1041 x=42 y=254 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1042 x=51 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1043 x=59 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=1044 x=33 y=108 width=10 height=13 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1045 x=67 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1046 x=75 y=254 width=12 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1047 x=87 y=254 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1048 x=95 y=254 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1049 x=43 y=108 width=9 height=13 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=1050 x=104 y=254 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1051 x=113 y=254 width=10 height=11 xoffset=-2 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1052 x=0 y=265 width=11 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1053 x=11 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1054 x=20 y=265 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1055 x=30 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1056 x=39 y=265 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1057 x=47 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1058 x=56 y=265 width=9 height=11 xoffset=-2 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1059 x=65 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1060 x=45 y=121 width=11 height=12 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=1061 x=74 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1062 x=52 y=108 width=10 height=13 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1063 x=83 y=265 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1064 x=92 y=265 width=12 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1065 x=62 y=108 width=12 height=13 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1066 x=104 y=265 width=11 height=11 xoffset=-2 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1067 x=115 y=265 width=10 height=11 xoffset=-1 yoffset=-1 xadvance=9 page=0 chnl=0 +char id=1068 x=0 y=276 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1069 x=9 y=276 width=9 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1070 x=18 y=276 width=12 height=11 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=1071 x=30 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1072 x=10 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1073 x=38 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1074 x=18 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1075 x=26 y=333 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1076 x=0 y=307 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1077 x=33 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1078 x=41 y=333 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=1079 x=51 y=333 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1080 x=58 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1081 x=46 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1082 x=66 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1083 x=74 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1084 x=82 y=333 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=1085 x=92 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1086 x=100 y=333 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1087 x=109 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1088 x=54 y=276 width=9 height=11 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1089 x=117 y=333 width=8 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1090 x=0 y=341 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1091 x=63 y=276 width=8 height=11 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1092 x=106 y=28 width=10 height=14 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=1093 x=7 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1094 x=8 y=307 width=9 height=10 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1095 x=15 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1096 x=23 y=341 width=10 height=8 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=1097 x=17 y=307 width=11 height=10 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=1098 x=33 y=341 width=9 height=8 xoffset=-1 yoffset=2 xadvance=7 page=0 chnl=0 +char id=1099 x=42 y=341 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=1100 x=52 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1101 x=60 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1102 x=68 y=341 width=10 height=8 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=1103 x=78 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1105 x=71 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1106 x=74 y=108 width=9 height=13 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1107 x=79 y=276 width=7 height=11 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=1108 x=86 y=341 width=8 height=8 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1109 x=94 y=341 width=7 height=8 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=1110 x=122 y=232 width=5 height=11 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=1111 x=86 y=276 width=7 height=11 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=1112 x=116 y=28 width=6 height=14 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=1113 x=114 y=307 width=11 height=9 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=1114 x=101 y=341 width=11 height=8 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=1115 x=93 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=1116 x=101 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1118 x=0 y=42 width=8 height=14 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=1119 x=28 y=307 width=8 height=10 xoffset=-1 yoffset=2 xadvance=6 page=0 chnl=0 +char id=1168 x=83 y=108 width=8 height=13 xoffset=-1 yoffset=-3 xadvance=5 page=0 chnl=0 +char id=1169 x=36 y=307 width=7 height=10 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=1241 x=112 y=341 width=9 height=8 xoffset=-1 yoffset=2 xadvance=4 page=0 chnl=0 +char id=8204 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=8211 x=90 y=356 width=8 height=3 xoffset=-1 yoffset=4 xadvance=6 page=0 chnl=0 +char id=8212 x=98 y=356 width=14 height=3 xoffset=-1 yoffset=4 xadvance=12 page=0 chnl=0 +char id=8216 x=71 y=349 width=5 height=6 xoffset=-1 yoffset=-2 xadvance=2 page=0 chnl=0 +char id=8217 x=76 y=349 width=5 height=6 xoffset=-1 yoffset=-2 xadvance=2 page=0 chnl=0 +char id=8218 x=122 y=349 width=5 height=5 xoffset=-1 yoffset=7 xadvance=2 page=0 chnl=0 +char id=8220 x=81 y=349 width=6 height=6 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=8221 x=87 y=349 width=6 height=6 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=8222 x=0 y=356 width=6 height=5 xoffset=-1 yoffset=7 xadvance=4 page=0 chnl=0 +char id=8224 x=56 y=121 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8225 x=64 y=121 width=8 height=12 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8226 x=6 y=356 width=5 height=5 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=8230 x=52 y=356 width=12 height=4 xoffset=0 yoffset=6 xadvance=12 page=0 chnl=0 +char id=8240 x=43 y=307 width=16 height=10 xoffset=-1 yoffset=0 xadvance=14 page=0 chnl=0 +char id=8249 x=28 y=349 width=5 height=7 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=8250 x=33 y=349 width=5 height=7 xoffset=-1 yoffset=2 xadvance=3 page=0 chnl=0 +char id=8260 x=59 y=307 width=11 height=10 xoffset=-3 yoffset=0 xadvance=1 page=0 chnl=0 +char id=8363 x=109 y=276 width=8 height=11 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=8364 x=70 y=307 width=8 height=10 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +kernings count=2667 +kerning first=8216 second=281 amount=-1 +kerning first=356 second=232 amount=-1 +kerning first=39 second=961 amount=-1 +kerning first=34 second=74 amount=-1 +kerning first=8218 second=376 amount=-1 +kerning first=1027 second=1107 amount=-1 +kerning first=358 second=335 amount=-1 +kerning first=957 second=46 amount=-1 +kerning first=257 second=84 amount=-1 +kerning first=376 second=279 amount=-1 +kerning first=356 second=97 amount=-1 +kerning first=354 second=231 amount=-1 +kerning first=70 second=224 amount=-1 +kerning first=8216 second=937 amount=-1 +kerning first=1168 second=1040 amount=-1 +kerning first=76 second=87 amount=-1 +kerning first=932 second=940 amount=-1 +kerning first=354 second=93 amount=1 +kerning first=229 second=932 amount=-1 +kerning first=939 second=959 amount=-1 +kerning first=321 second=173 amount=-1 +kerning first=929 second=923 amount=-1 +kerning first=932 second=244 amount=-1 +kerning first=221 second=308 amount=-1 +kerning first=358 second=227 amount=-1 +kerning first=192 second=39 amount=-1 +kerning first=1043 second=1088 amount=-1 +kerning first=196 second=221 amount=-1 +kerning first=65 second=89 amount=-1 +kerning first=947 second=44 amount=-1 +kerning first=221 second=369 amount=-1 +kerning first=1027 second=187 amount=-1 +kerning first=196 second=84 amount=-1 +kerning first=8218 second=358 amount=-1 +kerning first=84 second=361 amount=-1 +kerning first=915 second=941 amount=-1 +kerning first=89 second=252 amount=-1 +kerning first=1043 second=1032 amount=-1 +kerning first=1043 second=44 amount=-1 +kerning first=932 second=260 amount=-1 +kerning first=89 second=173 amount=-1 +kerning first=8216 second=940 amount=-1 +kerning first=1168 second=1074 amount=-1 +kerning first=354 second=285 amount=-1 +kerning first=8216 second=244 amount=-1 +kerning first=8220 second=281 amount=-1 +kerning first=221 second=242 amount=-1 +kerning first=65 second=34 amount=-1 +kerning first=89 second=111 amount=-1 +kerning first=1059 second=1066 amount=1 +kerning first=84 second=251 amount=-1 +kerning first=109 second=356 amount=-1 +kerning first=933 second=45 amount=-1 +kerning first=1066 second=1059 amount=-1 +kerning first=902 second=39 amount=-1 +kerning first=1027 second=1085 amount=-1 +kerning first=319 second=8220 amount=-1 +kerning first=932 second=8249 amount=-1 +kerning first=358 second=287 amount=-1 +kerning first=8220 second=937 amount=-1 +kerning first=84 second=110 amount=-1 +kerning first=317 second=89 amount=-1 +kerning first=46 second=8220 amount=-1 +kerning first=315 second=376 amount=-1 +kerning first=923 second=356 amount=-1 +kerning first=39 second=74 amount=-1 +kerning first=91 second=372 amount=1 +kerning first=8221 second=111 amount=-1 +kerning first=915 second=916 amount=-1 +kerning first=45 second=376 amount=-1 +kerning first=227 second=354 amount=-1 +kerning first=354 second=308 amount=-1 +kerning first=171 second=933 amount=-1 +kerning first=932 second=948 amount=-1 +kerning first=356 second=361 amount=-1 +kerning first=8216 second=260 amount=-1 +kerning first=1100 second=8217 amount=-1 +kerning first=376 second=913 amount=-1 +kerning first=1033 second=1026 amount=-1 +kerning first=1058 second=1105 amount=-1 +kerning first=372 second=192 amount=-1 +kerning first=225 second=356 amount=-1 +kerning first=354 second=369 amount=-1 +kerning first=376 second=258 amount=-1 +kerning first=317 second=34 amount=-1 +kerning first=915 second=8250 amount=-1 +kerning first=102 second=39 amount=1 +kerning first=40 second=84 amount=1 +kerning first=923 second=8217 amount=-1 +kerning first=356 second=251 amount=-1 +kerning first=44 second=34 amount=-1 +kerning first=86 second=913 amount=-1 +kerning first=1038 second=1066 amount=1 +kerning first=1027 second=1169 amount=-1 +kerning first=80 second=916 amount=-1 +kerning first=84 second=328 amount=-1 +kerning first=358 second=365 amount=-1 +kerning first=8220 second=940 amount=-1 +kerning first=916 second=39 amount=-1 +kerning first=258 second=8216 amount=-1 +kerning first=356 second=110 amount=-1 +kerning first=915 second=949 amount=-1 +kerning first=354 second=242 amount=-1 +kerning first=315 second=358 amount=-1 +kerning first=86 second=258 amount=-1 +kerning first=89 second=224 amount=-1 +kerning first=8220 second=244 amount=-1 +kerning first=8216 second=948 amount=-1 +kerning first=45 second=358 amount=-1 +kerning first=933 second=8212 amount=-1 +kerning first=910 second=173 amount=-1 +kerning first=8222 second=356 amount=-1 +kerning first=1040 second=1058 amount=-1 +kerning first=971 second=39 amount=-1 +kerning first=358 second=941 amount=-1 +kerning first=84 second=228 amount=-1 +kerning first=8217 second=283 amount=-1 +kerning first=358 second=246 amount=-1 +kerning first=932 second=269 amount=-1 +kerning first=1043 second=1101 amount=-1 +kerning first=933 second=912 amount=1 +kerning first=1066 second=1038 amount=-1 +kerning first=932 second=117 amount=-1 +kerning first=89 second=339 amount=-1 +kerning first=358 second=105 amount=-1 +kerning first=87 second=301 amount=1 +kerning first=944 second=34 amount=-1 +kerning first=70 second=256 amount=-1 +kerning first=76 second=45 amount=-1 +kerning first=343 second=8230 amount=-1 +kerning first=8220 second=260 amount=-1 +kerning first=356 second=328 amount=-1 +kerning first=932 second=197 amount=-1 +kerning first=358 second=916 amount=-1 +kerning first=84 second=248 amount=-1 +kerning first=8221 second=339 amount=-1 +kerning first=1058 second=1083 amount=-1 +kerning first=1168 second=1087 amount=-1 +kerning first=89 second=275 amount=-1 +kerning first=933 second=193 amount=-1 +kerning first=1113 second=1090 amount=-1 +kerning first=197 second=89 amount=-1 +kerning first=195 second=376 amount=-1 +kerning first=8216 second=269 amount=-1 +kerning first=221 second=267 amount=-1 +kerning first=8217 second=349 amount=-1 +kerning first=356 second=228 amount=-1 +kerning first=228 second=932 amount=-1 +kerning first=955 second=39 amount=-1 +kerning first=932 second=341 amount=-1 +kerning first=1027 second=1098 amount=-1 +kerning first=84 second=279 amount=-1 +kerning first=194 second=39 amount=-1 +kerning first=8221 second=275 amount=-1 +kerning first=8220 second=948 amount=-1 +kerning first=65 second=8220 amount=-1 +kerning first=193 second=221 amount=-1 +kerning first=376 second=115 amount=-1 +kerning first=915 second=195 amount=-1 +kerning first=8216 second=197 amount=-1 +kerning first=345 second=46 amount=-1 +kerning first=932 second=963 amount=-1 +kerning first=193 second=84 amount=-1 +kerning first=197 second=34 amount=-1 +kerning first=932 second=235 amount=-1 +kerning first=358 second=949 amount=-1 +kerning first=356 second=248 amount=-1 +kerning first=321 second=372 amount=-1 +kerning first=1058 second=1119 amount=-1 +kerning first=319 second=356 amount=-1 +kerning first=324 second=354 amount=-1 +kerning first=376 second=196 amount=-1 +kerning first=8217 second=101 amount=-1 +kerning first=1043 second=1080 amount=-1 +kerning first=354 second=380 amount=-1 +kerning first=187 second=932 amount=-1 +kerning first=76 second=8212 amount=-1 +kerning first=929 second=260 amount=-1 +kerning first=936 second=46 amount=-1 +kerning first=1034 second=1035 amount=-1 +kerning first=915 second=8230 amount=-1 +kerning first=195 second=358 amount=-1 +kerning first=86 second=196 amount=-1 +kerning first=308 second=93 amount=1 +kerning first=356 second=279 amount=-1 +kerning first=358 second=378 amount=-1 +kerning first=80 second=195 amount=-1 +kerning first=376 second=333 amount=-1 +kerning first=317 second=8220 amount=-1 +kerning first=89 second=243 amount=-1 +kerning first=8217 second=46 amount=-2 +kerning first=8216 second=963 amount=-1 +kerning first=44 second=8220 amount=-1 +kerning first=313 second=376 amount=-1 +kerning first=319 second=8217 amount=-1 +kerning first=354 second=267 amount=-1 +kerning first=932 second=41 amount=1 +kerning first=8216 second=235 amount=-1 +kerning first=8220 second=269 amount=-1 +kerning first=8212 second=356 amount=-1 +kerning first=46 second=8217 amount=-1 +kerning first=224 second=354 amount=-1 +kerning first=84 second=969 amount=-1 +kerning first=1059 second=1058 amount=1 +kerning first=1091 second=46 amount=-1 +kerning first=102 second=93 amount=1 +kerning first=84 second=241 amount=-1 +kerning first=8221 second=243 amount=-1 +kerning first=8216 second=8216 amount=-1 +kerning first=376 second=233 amount=-1 +kerning first=1027 second=1077 amount=-1 +kerning first=1098 second=8217 amount=-1 +kerning first=8230 second=8221 amount=-1 +kerning first=358 second=265 amount=-1 +kerning first=80 second=8230 amount=-2 +kerning first=8221 second=103 amount=-1 +kerning first=70 second=192 amount=-1 +kerning first=8220 second=197 amount=-1 +kerning first=91 second=354 amount=1 +kerning first=45 second=910 amount=-1 +kerning first=923 second=86 amount=-1 +kerning first=89 second=256 amount=-1 +kerning first=84 second=913 amount=-1 +kerning first=1168 second=173 amount=-1 +kerning first=1035 second=1066 amount=-1 +kerning first=936 second=198 amount=-1 +kerning first=1058 second=1096 amount=-1 +kerning first=358 second=195 amount=-1 +kerning first=271 second=311 amount=1 +kerning first=912 second=950 amount=1 +kerning first=84 second=258 amount=-1 +kerning first=313 second=358 amount=-1 +kerning first=354 second=343 amount=-1 +kerning first=8221 second=256 amount=-1 +kerning first=1168 second=1100 amount=-1 +kerning first=913 second=221 amount=-1 +kerning first=939 second=65 amount=-1 +kerning first=89 second=171 amount=-1 +kerning first=1059 second=1092 amount=-1 +kerning first=356 second=969 amount=-1 +kerning first=84 second=307 amount=-1 +kerning first=356 second=241 amount=-1 +kerning first=1038 second=1058 amount=1 +kerning first=913 second=84 amount=-1 +kerning first=932 second=367 amount=-1 +kerning first=260 second=39 amount=-1 +kerning first=8217 second=198 amount=-1 +kerning first=358 second=345 amount=-1 +kerning first=8220 second=963 amount=-1 +kerning first=104 second=358 amount=-1 +kerning first=256 second=221 amount=-1 +kerning first=354 second=237 amount=-1 +kerning first=358 second=8230 amount=-1 +kerning first=8220 second=235 amount=-1 +kerning first=910 second=962 amount=-1 +kerning first=315 second=173 amount=-1 +kerning first=109 second=932 amount=-1 +kerning first=974 second=34 amount=-1 +kerning first=123 second=106 amount=1 +kerning first=932 second=972 amount=-1 +kerning first=256 second=84 amount=-1 +kerning first=356 second=913 amount=-1 +kerning first=932 second=250 amount=-1 +kerning first=341 second=8230 amount=-1 +kerning first=8220 second=8216 amount=-1 +kerning first=8222 second=86 amount=-1 +kerning first=936 second=194 amount=-1 +kerning first=939 second=966 amount=-1 +kerning first=358 second=232 amount=-1 +kerning first=923 second=932 amount=-1 +kerning first=929 second=197 amount=-1 +kerning first=329 second=356 amount=-1 +kerning first=933 second=941 amount=-1 +kerning first=1043 second=1093 amount=-1 +kerning first=65 second=356 amount=-1 +kerning first=356 second=258 amount=-1 +kerning first=932 second=109 amount=-1 +kerning first=123 second=1095 amount=-1 +kerning first=358 second=97 amount=-1 +kerning first=197 second=8220 amount=-1 +kerning first=356 second=307 amount=-1 +kerning first=1038 second=1092 amount=-1 +kerning first=196 second=89 amount=-1 +kerning first=192 second=376 amount=-1 +kerning first=8250 second=221 amount=-1 +kerning first=8217 second=194 amount=-1 +kerning first=225 second=932 amount=-1 +kerning first=910 second=256 amount=-1 +kerning first=261 second=358 amount=-1 +kerning first=376 second=363 amount=-1 +kerning first=915 second=973 amount=-1 +kerning first=8250 second=84 amount=-1 +kerning first=1058 second=1075 amount=-1 +kerning first=173 second=354 amount=-1 +kerning first=933 second=916 amount=-1 +kerning first=8216 second=972 amount=-1 +kerning first=1168 second=1079 amount=-1 +kerning first=354 second=301 amount=-1 +kerning first=89 second=263 amount=-1 +kerning first=34 second=193 amount=-1 +kerning first=221 second=252 amount=-1 +kerning first=65 second=8217 amount=-1 +kerning first=221 second=173 amount=-1 +kerning first=939 second=44 amount=-1 +kerning first=84 second=382 amount=-1 +kerning first=8217 second=337 amount=-1 +kerning first=1090 second=8230 amount=-1 +kerning first=196 second=34 amount=-1 +kerning first=932 second=324 amount=-1 +kerning first=221 second=111 amount=-1 +kerning first=376 second=245 amount=-1 +kerning first=1027 second=1090 amount=-1 +kerning first=321 second=8221 amount=-1 +kerning first=317 second=356 amount=-1 +kerning first=8221 second=263 amount=-1 +kerning first=84 second=115 amount=-1 +kerning first=89 second=192 amount=-1 +kerning first=8222 second=932 amount=-1 +kerning first=110 second=354 amount=-1 +kerning first=934 second=46 amount=-1 +kerning first=192 second=358 amount=-1 +kerning first=902 second=376 amount=-1 +kerning first=8217 second=231 amount=-1 +kerning first=70 second=74 amount=-1 +kerning first=932 second=226 amount=-1 +kerning first=84 second=196 amount=-1 +kerning first=8221 second=192 amount=-1 +kerning first=321 second=354 amount=-1 +kerning first=1027 second=46 amount=-1 +kerning first=1043 second=1072 amount=-1 +kerning first=933 second=949 amount=-1 +kerning first=1168 second=1114 amount=-1 +kerning first=319 second=86 amount=-1 +kerning first=271 second=8221 amount=1 +kerning first=331 second=358 amount=-1 +kerning first=1034 second=8217 amount=-1 +kerning first=317 second=8217 amount=-1 +kerning first=44 second=8217 amount=-1 +kerning first=226 second=354 amount=-1 +kerning first=356 second=382 amount=-1 +kerning first=84 second=333 amount=-1 +kerning first=358 second=361 amount=-1 +kerning first=8220 second=972 amount=-1 +kerning first=123 second=358 amount=1 +kerning first=356 second=115 amount=-1 +kerning first=8221 second=8221 amount=-1 +kerning first=354 second=252 amount=-1 +kerning first=89 second=234 amount=-1 +kerning first=8218 second=372 amount=-1 +kerning first=915 second=954 amount=-1 +kerning first=354 second=173 amount=-1 +kerning first=221 second=224 amount=-1 +kerning first=902 second=358 amount=-1 +kerning first=354 second=111 amount=-1 +kerning first=87 second=256 amount=-1 +kerning first=84 second=959 amount=-1 +kerning first=932 second=331 amount=-1 +kerning first=84 second=233 amount=-1 +kerning first=356 second=196 amount=-1 +kerning first=8217 second=285 amount=-1 +kerning first=358 second=251 amount=-1 +kerning first=39 second=193 amount=-1 +kerning first=372 second=239 amount=1 +kerning first=932 second=283 amount=-1 +kerning first=8221 second=234 amount=-1 +kerning first=923 second=939 amount=-1 +kerning first=1043 second=1107 amount=-1 +kerning first=1033 second=1066 amount=-1 +kerning first=932 second=122 amount=-1 +kerning first=358 second=110 amount=-1 +kerning first=97 second=84 amount=-1 +kerning first=910 second=192 amount=-1 +kerning first=91 second=87 amount=1 +kerning first=319 second=932 amount=-1 +kerning first=221 second=339 amount=-1 +kerning first=1035 second=1058 amount=-1 +kerning first=356 second=333 amount=-1 +kerning first=939 second=923 amount=-1 +kerning first=258 second=39 amount=-1 +kerning first=8217 second=308 amount=-1 +kerning first=1058 second=1088 amount=-1 +kerning first=376 second=230 amount=-1 +kerning first=1168 second=1092 amount=-1 +kerning first=933 second=195 amount=-1 +kerning first=313 second=173 amount=-1 +kerning first=197 second=356 amount=-1 +kerning first=356 second=959 amount=-1 +kerning first=973 second=34 amount=-1 +kerning first=221 second=275 amount=-1 +kerning first=356 second=233 amount=-1 +kerning first=8216 second=283 amount=-1 +kerning first=916 second=358 amount=-1 +kerning first=932 second=349 amount=-1 +kerning first=1027 second=1103 amount=-1 +kerning first=1043 second=187 amount=-1 +kerning first=84 second=291 amount=-1 +kerning first=8221 second=289 amount=-1 +kerning first=76 second=221 amount=-1 +kerning first=358 second=328 amount=-1 +kerning first=295 second=356 amount=-1 +kerning first=376 second=271 amount=-1 +kerning first=8211 second=376 amount=-1 +kerning first=1058 second=44 amount=-1 +kerning first=354 second=224 amount=-1 +kerning first=8212 second=932 amount=-1 +kerning first=70 second=225 amount=-1 +kerning first=910 second=961 amount=-1 +kerning first=1058 second=1032 amount=-1 +kerning first=76 second=84 amount=-1 +kerning first=196 second=8220 amount=-1 +kerning first=315 second=372 amount=-1 +kerning first=933 second=8230 amount=-1 +kerning first=8217 second=242 amount=-1 +kerning first=89 second=74 amount=-1 +kerning first=193 second=89 amount=-1 +kerning first=932 second=236 amount=-1 +kerning first=194 second=376 amount=-1 +kerning first=197 second=8217 amount=-1 +kerning first=1169 second=44 amount=-1 +kerning first=1027 second=59 amount=-1 +kerning first=358 second=228 amount=-1 +kerning first=1043 second=1085 amount=-1 +kerning first=34 second=941 amount=-1 +kerning first=259 second=358 amount=-1 +kerning first=932 second=101 amount=-1 +kerning first=89 second=371 amount=-1 +kerning first=65 second=86 amount=-1 +kerning first=8221 second=74 amount=-1 +kerning first=354 second=339 amount=-1 +kerning first=376 second=65 amount=-1 +kerning first=8230 second=933 amount=-1 +kerning first=84 second=363 amount=-1 +kerning first=193 second=34 amount=-1 +kerning first=356 second=291 amount=-1 +kerning first=8211 second=358 amount=-1 +kerning first=376 second=347 amount=-1 +kerning first=354 second=312 amount=-1 +kerning first=358 second=248 amount=-1 +kerning first=89 second=353 amount=-1 +kerning first=241 second=356 amount=-1 +kerning first=86 second=65 amount=-1 +kerning first=34 second=916 amount=-1 +kerning first=87 second=192 amount=-1 +kerning first=271 second=108 amount=1 +kerning first=354 second=275 amount=-1 +kerning first=932 second=46 amount=-1 +kerning first=8220 second=283 amount=-1 +kerning first=221 second=243 amount=-1 +kerning first=195 second=936 amount=-1 +kerning first=194 second=358 amount=-1 +kerning first=84 second=245 amount=-1 +kerning first=8221 second=353 amount=-1 +kerning first=8216 second=101 amount=-1 +kerning first=1043 second=1169 amount=-1 +kerning first=932 second=297 amount=-1 +kerning first=1027 second=1082 amount=-1 +kerning first=321 second=8211 amount=-1 +kerning first=358 second=279 amount=-1 +kerning first=915 second=913 amount=-1 +kerning first=317 second=86 amount=-1 +kerning first=40 second=309 amount=1 +kerning first=376 second=99 amount=-1 +kerning first=932 second=945 amount=-1 +kerning first=329 second=932 amount=-1 +kerning first=915 second=258 amount=-1 +kerning first=1168 second=1241 amount=-1 +kerning first=65 second=932 amount=-1 +kerning first=356 second=363 amount=-1 +kerning first=46 second=939 amount=-1 +kerning first=221 second=256 amount=-1 +kerning first=1058 second=1101 amount=-1 +kerning first=372 second=193 amount=-1 +kerning first=8216 second=46 amount=-1 +kerning first=34 second=949 amount=-1 +kerning first=321 second=87 amount=-1 +kerning first=912 second=955 amount=1 +kerning first=1027 second=1026 amount=1 +kerning first=89 second=8211 amount=-1 +kerning first=376 second=44 amount=-1 +kerning first=39 second=941 amount=-1 +kerning first=356 second=245 amount=-1 +kerning first=913 second=89 amount=-1 +kerning first=221 second=171 amount=-1 +kerning first=195 second=372 amount=-1 +kerning first=80 second=913 amount=-1 +kerning first=257 second=356 amount=-1 +kerning first=932 second=198 amount=-1 +kerning first=354 second=962 amount=-1 +kerning first=173 second=933 amount=-1 +kerning first=1027 second=1118 amount=-1 +kerning first=915 second=946 amount=-1 +kerning first=8218 second=354 amount=-1 +kerning first=354 second=243 amount=-1 +kerning first=89 second=225 amount=-1 +kerning first=910 second=970 amount=1 +kerning first=8212 second=939 amount=-1 +kerning first=8216 second=945 amount=-1 +kerning first=80 second=258 amount=-1 +kerning first=86 second=44 amount=-1 +kerning first=256 second=89 amount=-1 +kerning first=260 second=376 amount=-1 +kerning first=354 second=103 amount=-1 +kerning first=8220 second=101 amount=-1 +kerning first=317 second=932 amount=-1 +kerning first=939 second=940 amount=-1 +kerning first=358 second=969 amount=-1 +kerning first=39 second=916 amount=-1 +kerning first=8217 second=267 amount=-1 +kerning first=1033 second=1058 amount=-1 +kerning first=358 second=241 amount=-1 +kerning first=913 second=34 amount=-1 +kerning first=932 second=261 amount=-1 +kerning first=293 second=358 amount=-1 +kerning first=357 second=8221 amount=1 +kerning first=1043 second=1098 amount=-1 +kerning first=932 second=114 amount=-1 +kerning first=926 second=912 amount=1 +kerning first=8204 second=902 amount=-1 +kerning first=196 second=356 amount=-1 +kerning first=354 second=256 amount=-1 +kerning first=8216 second=198 amount=-1 +kerning first=256 second=34 amount=-1 +kerning first=8220 second=46 amount=-1 +kerning first=932 second=194 amount=-1 +kerning first=358 second=913 amount=-1 +kerning first=1068 second=1026 amount=-1 +kerning first=84 second=230 amount=-1 +kerning first=89 second=273 amount=-1 +kerning first=1058 second=1080 amount=-1 +kerning first=8250 second=89 amount=-1 +kerning first=1056 second=44 amount=-2 +kerning first=1168 second=1084 amount=-1 +kerning first=1056 second=1032 amount=-1 +kerning first=939 second=260 amount=-1 +kerning first=922 second=970 amount=1 +kerning first=89 second=277 amount=-1 +kerning first=358 second=258 amount=-1 +kerning first=34 second=195 amount=-1 +kerning first=8221 second=8204 amount=-1 +kerning first=260 second=358 amount=-1 +kerning first=354 second=171 amount=-1 +kerning first=315 second=8221 amount=-1 +kerning first=1059 second=1076 amount=-1 +kerning first=313 second=372 amount=-1 +kerning first=193 second=8220 amount=-1 +kerning first=197 second=86 amount=-1 +kerning first=39 second=949 amount=-1 +kerning first=221 second=263 amount=-1 +kerning first=910 second=8211 amount=-1 +kerning first=8221 second=273 amount=-1 +kerning first=196 second=8217 amount=-1 +kerning first=358 second=307 amount=-1 +kerning first=932 second=337 amount=-1 +kerning first=376 second=249 amount=-1 +kerning first=160 second=8216 amount=-1 +kerning first=8211 second=910 amount=-1 +kerning first=84 second=271 amount=-1 +kerning first=8221 second=277 amount=-1 +kerning first=1027 second=1095 amount=-1 +kerning first=8220 second=945 amount=-1 +kerning first=376 second=259 amount=-1 +kerning first=915 second=196 amount=-1 +kerning first=315 second=354 amount=-1 +kerning first=34 second=8230 amount=-1 +kerning first=8216 second=194 amount=-1 +kerning first=221 second=192 amount=-1 +kerning first=1107 second=46 amount=-1 +kerning first=45 second=354 amount=-1 +kerning first=932 second=231 amount=-1 +kerning first=65 second=939 amount=-1 +kerning first=939 second=948 amount=-1 +kerning first=356 second=230 amount=-1 +kerning first=376 second=923 amount=-1 +kerning first=1114 second=8217 amount=-1 +kerning first=1043 second=1077 amount=-1 +kerning first=1027 second=1040 amount=-1 +kerning first=932 second=93 amount=1 +kerning first=89 second=351 amount=-1 +kerning first=84 second=65 amount=-1 +kerning first=40 second=356 amount=1 +kerning first=929 second=46 amount=-2 +kerning first=8220 second=198 amount=-1 +kerning first=8216 second=337 amount=-1 +kerning first=192 second=936 amount=-1 +kerning first=1038 second=1076 amount=-1 +kerning first=86 second=923 amount=-1 +kerning first=84 second=347 amount=-1 +kerning first=356 second=271 amount=-1 +kerning first=8221 second=351 amount=-1 +kerning first=80 second=196 amount=-1 +kerning first=197 second=932 amount=-1 +kerning first=915 second=959 amount=-1 +kerning first=89 second=239 amount=1 +kerning first=321 second=45 amount=-1 +kerning first=354 second=263 amount=-1 +kerning first=70 second=257 amount=-1 +kerning first=8216 second=231 amount=-1 +kerning first=221 second=234 amount=-1 +kerning first=89 second=100 amount=-1 +kerning first=84 second=966 amount=-1 +kerning first=295 second=932 amount=-1 +kerning first=84 second=238 amount=-1 +kerning first=39 second=195 amount=-1 +kerning first=358 second=382 amount=-1 +kerning first=44 second=939 amount=-1 +kerning first=932 second=285 amount=-1 +kerning first=376 second=229 amount=-1 +kerning first=1027 second=1074 amount=-1 +kerning first=84 second=99 amount=-1 +kerning first=8221 second=100 amount=-1 +kerning first=356 second=65 amount=-1 +kerning first=354 second=192 amount=-1 +kerning first=70 second=193 amount=-1 +kerning first=358 second=115 amount=-1 +kerning first=8220 second=194 amount=-1 +kerning first=8204 second=221 amount=-1 +kerning first=915 second=181 amount=-1 +kerning first=902 second=936 amount=-1 +kerning first=913 second=8220 amount=-1 +kerning first=227 second=84 amount=-1 +kerning first=89 second=45 amount=-1 +kerning first=1035 second=1063 amount=-1 +kerning first=356 second=347 amount=-1 +kerning first=195 second=8221 amount=-1 +kerning first=192 second=372 amount=-1 +kerning first=939 second=197 amount=-1 +kerning first=1058 second=1093 amount=-1 +kerning first=39 second=8230 amount=-1 +kerning first=929 second=198 amount=-1 +kerning first=358 second=196 amount=-1 +kerning first=1075 second=44 amount=-1 +kerning first=932 second=308 amount=-1 +kerning first=8216 second=1026 amount=1 +kerning first=1168 second=1097 amount=-1 +kerning first=8220 second=337 amount=-1 +kerning first=256 second=8220 amount=-1 +kerning first=84 second=44 amount=-1 +kerning first=1059 second=1089 amount=-1 +kerning first=356 second=966 amount=-1 +kerning first=258 second=376 amount=-1 +kerning first=8216 second=285 amount=-1 +kerning first=356 second=238 amount=-1 +kerning first=241 second=932 amount=-1 +kerning first=932 second=369 amount=-1 +kerning first=195 second=354 amount=-1 +kerning first=321 second=8212 amount=-1 +kerning first=84 second=299 amount=-1 +kerning first=358 second=333 amount=-1 +kerning first=354 second=961 amount=-1 +kerning first=356 second=99 amount=-1 +kerning first=376 second=281 amount=-1 +kerning first=354 second=234 amount=-1 +kerning first=70 second=227 amount=-1 +kerning first=8220 second=231 amount=-1 +kerning first=376 second=125 amount=1 +kerning first=123 second=372 amount=1 +kerning first=8218 second=87 amount=-1 +kerning first=76 second=89 amount=-1 +kerning first=193 second=356 amount=-1 +kerning first=916 second=936 amount=-1 +kerning first=939 second=963 amount=-1 +kerning first=932 second=242 amount=-1 +kerning first=8216 second=308 amount=-1 +kerning first=358 second=959 amount=-1 +kerning first=902 second=372 amount=-1 +kerning first=358 second=233 amount=-1 +kerning first=929 second=194 amount=-1 +kerning first=221 second=74 amount=-1 +kerning first=8217 second=111 amount=-1 +kerning first=86 second=125 amount=1 +kerning first=1043 second=1090 amount=-1 +kerning first=114 second=8230 amount=-1 +kerning first=1168 second=8211 amount=-1 +kerning first=1066 second=1026 amount=-1 +kerning first=356 second=44 amount=-1 +kerning first=89 second=8212 amount=-1 +kerning first=947 second=46 amount=-1 +kerning first=1033 second=8221 amount=-1 +kerning first=258 second=358 amount=-1 +kerning first=313 second=8221 amount=-1 +kerning first=221 second=371 amount=-1 +kerning first=1038 second=1089 amount=-1 +kerning first=196 second=86 amount=-1 +kerning first=76 second=34 amount=-1 +kerning first=356 second=299 amount=-1 +kerning first=193 second=8217 amount=-1 +kerning first=8220 second=1026 amount=1 +kerning first=197 second=939 amount=-1 +kerning first=915 second=943 amount=-1 +kerning first=910 second=45 amount=-1 +kerning first=1058 second=1072 amount=-1 +kerning first=1043 second=46 amount=-1 +kerning first=933 second=913 amount=-1 +kerning first=1168 second=1076 amount=-1 +kerning first=354 second=289 amount=-1 +kerning first=89 second=257 amount=-1 +kerning first=8216 second=242 amount=-1 +kerning first=8220 second=285 amount=-1 +kerning first=221 second=353 amount=-1 +kerning first=89 second=113 amount=-1 +kerning first=315 second=8211 amount=-1 +kerning first=257 second=932 amount=-1 +kerning first=313 second=354 amount=-1 +kerning first=84 second=974 amount=-1 +kerning first=933 second=258 amount=-1 +kerning first=84 second=249 amount=-1 +kerning first=376 second=244 amount=-1 +kerning first=1027 second=1087 amount=-1 +kerning first=84 second=259 amount=-1 +kerning first=358 second=291 amount=-1 +kerning first=84 second=112 amount=-1 +kerning first=8221 second=113 amount=-1 +kerning first=89 second=193 amount=-1 +kerning first=104 second=354 amount=-1 +kerning first=923 second=8216 amount=-1 +kerning first=8220 second=308 amount=-1 +kerning first=1026 second=1035 amount=-1 +kerning first=194 second=936 amount=-1 +kerning first=354 second=74 amount=-1 +kerning first=315 second=87 amount=-1 +kerning first=84 second=923 amount=-1 +kerning first=8221 second=193 amount=-1 +kerning first=1058 second=1107 amount=-1 +kerning first=372 second=195 amount=-1 +kerning first=196 second=932 amount=-1 +kerning first=1168 second=1111 amount=-1 +kerning first=87 second=239 amount=1 +kerning first=8216 second=1040 amount=-1 +kerning first=324 second=84 amount=-1 +kerning first=354 second=371 amount=-1 +kerning first=89 second=335 amount=-1 +kerning first=376 second=260 amount=-1 +kerning first=356 second=974 amount=-1 +kerning first=913 second=356 amount=-1 +kerning first=40 second=86 amount=1 +kerning first=910 second=8212 amount=-1 +kerning first=356 second=249 amount=-1 +kerning first=221 second=8211 amount=-1 +kerning first=932 second=380 amount=-1 +kerning first=8217 second=339 amount=-1 +kerning first=84 second=326 amount=-1 +kerning first=8221 second=335 amount=-1 +kerning first=356 second=259 amount=-1 +kerning first=358 second=363 amount=-1 +kerning first=356 second=112 amount=-1 +kerning first=915 second=951 amount=-1 +kerning first=354 second=353 amount=-1 +kerning first=86 second=260 amount=-1 +kerning first=910 second=912 amount=1 +kerning first=372 second=8230 amount=-1 +kerning first=89 second=227 amount=-1 +kerning first=376 second=8249 amount=-1 +kerning first=256 second=356 amount=-1 +kerning first=261 second=354 amount=-1 +kerning first=8220 second=242 amount=-1 +kerning first=221 second=225 amount=-1 +kerning first=356 second=923 amount=-1 +kerning first=939 second=972 amount=-1 +kerning first=1058 second=187 amount=-1 +kerning first=224 second=84 amount=-1 +kerning first=84 second=229 amount=-1 +kerning first=8217 second=275 amount=-1 +kerning first=358 second=245 amount=-1 +kerning first=1033 second=1063 amount=-1 +kerning first=913 second=8217 amount=-1 +kerning first=194 second=372 amount=-1 +kerning first=192 second=8221 amount=-1 +kerning first=932 second=267 amount=-1 +kerning first=1043 second=1103 amount=-1 +kerning first=929 second=308 amount=-1 +kerning first=1034 second=1059 amount=-1 +kerning first=45 second=933 amount=-1 +kerning first=910 second=193 amount=-1 +kerning first=91 second=84 amount=1 +kerning first=256 second=8217 amount=-1 +kerning first=356 second=326 amount=-1 +kerning first=8250 second=356 amount=-1 +kerning first=192 second=354 amount=-1 +kerning first=1043 second=59 amount=-1 +kerning first=40 second=932 amount=1 +kerning first=968 second=39 amount=-1 +kerning first=1168 second=1089 amount=-1 +kerning first=1058 second=1085 amount=-1 +kerning first=8220 second=1040 amount=-1 +kerning first=922 second=912 amount=1 +kerning first=76 second=8220 amount=-1 +kerning first=933 second=196 amount=-1 +kerning first=221 second=273 amount=-1 +kerning first=1027 second=173 amount=-1 +kerning first=354 second=8211 amount=-1 +kerning first=331 second=354 amount=-1 +kerning first=8216 second=267 amount=-1 +kerning first=221 second=277 amount=-1 +kerning first=356 second=229 amount=-1 +kerning first=1100 second=1098 amount=-1 +kerning first=902 second=8221 amount=-1 +kerning first=932 second=343 amount=-1 +kerning first=1027 second=1100 amount=-1 +kerning first=84 second=281 amount=-1 +kerning first=8221 second=287 amount=-1 +kerning first=195 second=87 amount=-1 +kerning first=84 second=125 amount=1 +kerning first=376 second=269 amount=-1 +kerning first=354 second=225 amount=-1 +kerning first=1168 second=45 amount=-1 +kerning first=376 second=117 amount=-1 +kerning first=123 second=354 amount=1 +kerning first=260 second=936 amount=-1 +kerning first=8217 second=243 amount=-1 +kerning first=193 second=86 amount=-1 +kerning first=932 second=237 amount=-1 +kerning first=915 second=65 amount=-1 +kerning first=1068 second=1066 amount=-1 +kerning first=902 second=354 amount=-1 +kerning first=343 second=44 amount=-1 +kerning first=376 second=197 amount=-1 +kerning first=8217 second=103 amount=-1 +kerning first=196 second=939 amount=-1 +kerning first=936 second=256 amount=-1 +kerning first=933 second=959 amount=-1 +kerning first=319 second=8216 amount=-1 +kerning first=8249 second=910 amount=-1 +kerning first=34 second=969 amount=-1 +kerning first=89 second=365 amount=-1 +kerning first=1043 second=1082 amount=-1 +kerning first=1058 second=1169 amount=-1 +kerning first=46 second=8216 amount=-1 +kerning first=354 second=305 amount=-1 +kerning first=1034 second=1038 amount=-1 +kerning first=102 second=8221 amount=1 +kerning first=221 second=351 amount=-1 +kerning first=313 second=8211 amount=-1 +kerning first=86 second=197 amount=-1 +kerning first=315 second=45 amount=-1 +kerning first=356 second=281 amount=-1 +kerning first=173 second=221 amount=-1 +kerning first=916 second=8221 amount=-1 +kerning first=8217 second=256 amount=-1 +kerning first=356 second=125 amount=1 +kerning first=915 second=966 amount=-1 +kerning first=89 second=246 amount=-1 +kerning first=358 second=230 amount=-1 +kerning first=354 second=273 amount=-1 +kerning first=1043 second=1026 amount=1 +kerning first=34 second=913 amount=-1 +kerning first=87 second=193 amount=-1 +kerning first=354 second=277 amount=-1 +kerning first=173 second=84 amount=-1 +kerning first=80 second=65 amount=-1 +kerning first=221 second=239 amount=1 +kerning first=8220 second=267 amount=-1 +kerning first=195 second=933 amount=-1 +kerning first=84 second=940 amount=-1 +kerning first=34 second=258 amount=-1 +kerning first=313 second=87 amount=-1 +kerning first=84 second=244 amount=-1 +kerning first=260 second=372 amount=-1 +kerning first=8221 second=246 amount=-1 +kerning first=932 second=301 amount=-1 +kerning first=376 second=235 amount=-1 +kerning first=221 second=100 amount=-1 +kerning first=916 second=354 amount=-1 +kerning first=1027 second=1079 amount=-1 +kerning first=1043 second=1118 amount=-1 +kerning first=1168 second=8212 amount=-1 +kerning first=358 second=271 amount=-1 +kerning first=97 second=356 amount=-1 +kerning first=193 second=932 amount=-1 +kerning first=70 second=195 amount=-1 +kerning first=110 second=84 amount=-1 +kerning first=321 second=221 amount=-1 +kerning first=8204 second=89 amount=-1 +kerning first=915 second=44 amount=-1 +kerning first=271 second=318 amount=1 +kerning first=326 second=358 amount=-1 +kerning first=221 second=45 amount=-1 +kerning first=1058 second=1098 amount=-1 +kerning first=321 second=84 amount=-1 +kerning first=1168 second=1102 amount=-1 +kerning first=84 second=260 amount=-1 +kerning first=354 second=351 amount=-1 +kerning first=259 second=354 amount=-1 +kerning first=315 second=8212 amount=-1 +kerning first=70 second=8230 amount=-1 +kerning first=358 second=65 amount=-1 +kerning first=356 second=940 amount=-1 +kerning first=376 second=41 amount=1 +kerning first=39 second=969 amount=-1 +kerning first=356 second=244 amount=-1 +kerning first=913 second=86 amount=-1 +kerning first=955 second=8221 amount=-1 +kerning first=226 second=84 amount=-1 +kerning first=1027 second=1114 amount=-1 +kerning first=194 second=8221 amount=-1 +kerning first=358 second=347 amount=-1 +kerning first=84 second=8249 amount=-1 +kerning first=354 second=239 amount=-1 +kerning first=910 second=941 amount=-1 +kerning first=1168 second=58 amount=-1 +kerning first=76 second=356 amount=-1 +kerning first=86 second=41 amount=1 +kerning first=8211 second=354 amount=-1 +kerning first=80 second=44 amount=-2 +kerning first=256 second=86 amount=-1 +kerning first=354 second=100 amount=-1 +kerning first=70 second=97 amount=-1 +kerning first=84 second=948 amount=-1 +kerning first=932 second=252 amount=-1 +kerning first=39 second=913 amount=-1 +kerning first=936 second=192 amount=-1 +kerning first=358 second=966 amount=-1 +kerning first=932 second=173 amount=-1 +kerning first=8217 second=263 amount=-1 +kerning first=358 second=238 amount=-1 +kerning first=194 second=354 amount=-1 +kerning first=1043 second=1095 amount=-1 +kerning first=8216 second=1066 amount=1 +kerning first=356 second=260 amount=-1 +kerning first=1113 second=8221 amount=-1 +kerning first=932 second=111 amount=-1 +kerning first=39 second=258 amount=-1 +kerning first=65 second=8216 amount=-1 +kerning first=358 second=99 amount=-1 +kerning first=910 second=916 amount=-1 +kerning first=76 second=8217 amount=-1 +kerning first=160 second=8218 amount=-1 +kerning first=221 second=8212 amount=-1 +kerning first=8217 second=192 amount=-1 +kerning first=354 second=45 amount=-1 +kerning first=969 second=34 amount=-1 +kerning first=1098 second=1098 amount=-1 +kerning first=356 second=8249 amount=-1 +kerning first=376 second=367 amount=-1 +kerning first=1058 second=1077 amount=-1 +kerning first=192 second=87 amount=-1 +kerning first=1043 second=1040 amount=-1 +kerning first=913 second=932 amount=-1 +kerning first=1168 second=1081 amount=-1 +kerning first=354 second=303 amount=-1 +kerning first=89 second=265 amount=-1 +kerning first=34 second=196 amount=-1 +kerning first=936 second=961 amount=-1 +kerning first=358 second=44 amount=-1 +kerning first=258 second=936 amount=-1 +kerning first=356 second=948 amount=-1 +kerning first=939 second=46 amount=-1 +kerning first=221 second=257 amount=-1 +kerning first=1100 second=1090 amount=-1 +kerning first=8216 second=111 amount=-1 +kerning first=221 second=113 amount=-1 +kerning first=376 second=250 amount=-1 +kerning first=8217 second=8221 amount=-1 +kerning first=1027 second=1092 amount=-1 +kerning first=1066 second=1066 amount=-1 +kerning first=84 second=269 amount=-1 +kerning first=256 second=932 amount=-1 +kerning first=8221 second=265 amount=-1 +kerning first=358 second=299 amount=-1 +kerning first=341 second=44 amount=-1 +kerning first=193 second=939 amount=-1 +kerning first=84 second=117 amount=-1 +kerning first=915 second=923 amount=-1 +kerning first=317 second=8216 amount=-1 +kerning first=89 second=195 amount=-1 +kerning first=910 second=949 amount=-1 +kerning first=44 second=8216 amount=-1 +kerning first=221 second=193 amount=-1 +kerning first=123 second=87 amount=1 +kerning first=8217 second=234 amount=-1 +kerning first=939 second=945 amount=-1 +kerning first=932 second=224 amount=-1 +kerning first=1068 second=1058 amount=-1 +kerning first=8220 second=1066 amount=1 +kerning first=84 second=197 amount=-1 +kerning first=313 second=45 amount=-1 +kerning first=8221 second=195 amount=-1 +kerning first=1043 second=1074 amount=-1 +kerning first=902 second=87 amount=-1 +kerning first=1168 second=1116 amount=-1 +kerning first=1041 second=1026 amount=-1 +kerning first=293 second=354 amount=-1 +kerning first=354 second=8212 amount=-1 +kerning first=89 second=8230 amount=-1 +kerning first=1059 second=1108 amount=-1 +kerning first=8250 second=932 amount=-1 +kerning first=221 second=335 amount=-1 +kerning first=192 second=933 amount=-1 +kerning first=260 second=8221 amount=-1 +kerning first=80 second=923 amount=-1 +kerning first=258 second=372 amount=-1 +kerning first=84 second=341 amount=-1 +kerning first=356 second=269 amount=-1 +kerning first=932 second=339 amount=-1 +kerning first=356 second=117 amount=-1 +kerning first=8221 second=8230 amount=-2 +kerning first=89 second=232 amount=-1 +kerning first=939 second=198 amount=-1 +kerning first=1090 second=44 amount=-1 +kerning first=1168 second=1060 amount=-1 +kerning first=923 second=39 amount=-1 +kerning first=354 second=257 amount=-1 +kerning first=221 second=227 amount=-1 +kerning first=354 second=113 amount=-1 +kerning first=89 second=97 amount=-1 +kerning first=8220 second=111 amount=-1 +kerning first=84 second=963 amount=-1 +kerning first=8204 second=8220 amount=-1 +kerning first=932 second=312 amount=-1 +kerning first=358 second=974 amount=-1 +kerning first=84 second=235 amount=-1 +kerning first=356 second=197 amount=-1 +kerning first=260 second=354 amount=-1 +kerning first=8217 second=289 amount=-1 +kerning first=358 second=249 amount=-1 +kerning first=39 second=196 amount=-1 +kerning first=8221 second=232 amount=-1 +kerning first=932 second=275 amount=-1 +kerning first=376 second=226 amount=-1 +kerning first=328 second=358 amount=-1 +kerning first=358 second=259 amount=-1 +kerning first=1059 second=8230 amount=-1 +kerning first=354 second=193 amount=-1 +kerning first=358 second=112 amount=-1 +kerning first=1111 second=1106 amount=1 +kerning first=902 second=933 amount=-1 +kerning first=313 second=8212 amount=-1 +kerning first=910 second=195 amount=-1 +kerning first=1038 second=1108 amount=-1 +kerning first=8216 second=339 amount=-1 +kerning first=356 second=341 amount=-1 +kerning first=358 second=923 amount=-1 +kerning first=372 second=913 amount=-1 +kerning first=939 second=194 amount=-1 +kerning first=1058 second=1090 amount=-1 +kerning first=271 second=293 amount=1 +kerning first=8217 second=74 amount=-1 +kerning first=913 second=939 amount=-1 +kerning first=1168 second=1094 amount=-1 +kerning first=354 second=335 amount=-1 +kerning first=372 second=258 amount=-1 +kerning first=84 second=41 amount=1 +kerning first=1027 second=1241 amount=-1 +kerning first=356 second=963 amount=-1 +kerning first=1059 second=1086 amount=-1 +kerning first=197 second=8216 amount=-1 +kerning first=229 second=358 amount=-1 +kerning first=356 second=235 amount=-1 +kerning first=8216 second=275 amount=-1 +kerning first=933 second=65 amount=-1 +kerning first=910 second=8230 amount=-1 +kerning first=8218 second=221 amount=-1 +kerning first=256 second=939 amount=-1 +kerning first=358 second=326 amount=-1 +kerning first=376 second=283 amount=-1 +kerning first=1058 second=46 amount=-1 +kerning first=354 second=227 amount=-1 +kerning first=70 second=228 amount=-1 +kerning first=8218 second=84 amount=-1 +kerning first=8230 second=34 amount=-1 +kerning first=1038 second=8230 amount=-1 +kerning first=76 second=86 amount=-1 +kerning first=932 second=962 amount=-1 +kerning first=8217 second=353 amount=-1 +kerning first=916 second=933 amount=-1 +kerning first=932 second=243 amount=-1 +kerning first=1169 second=46 amount=-1 +kerning first=97 second=932 amount=-1 +kerning first=358 second=229 amount=-1 +kerning first=933 second=966 amount=-1 +kerning first=1043 second=1087 amount=-1 +kerning first=1168 second=8250 amount=-1 +kerning first=8216 second=1058 amount=1 +kerning first=194 second=87 amount=-1 +kerning first=932 second=103 amount=-1 +kerning first=89 second=361 amount=-1 +kerning first=356 second=41 amount=1 +kerning first=8220 second=339 amount=-1 +kerning first=221 second=365 amount=-1 +kerning first=1038 second=1086 amount=-1 +kerning first=1098 second=1090 amount=-1 +kerning first=84 second=367 amount=-1 +kerning first=376 second=349 amount=-1 +kerning first=89 second=251 amount=-1 +kerning first=915 second=940 amount=-1 +kerning first=932 second=256 amount=-1 +kerning first=8216 second=962 amount=-1 +kerning first=87 second=195 amount=-1 +kerning first=354 second=287 amount=-1 +kerning first=173 second=89 amount=-1 +kerning first=8216 second=243 amount=-1 +kerning first=8220 second=275 amount=-1 +kerning first=221 second=246 amount=-1 +kerning first=160 second=376 amount=-1 +kerning first=84 second=972 amount=-1 +kerning first=8204 second=8222 amount=-1 +kerning first=84 second=250 amount=-1 +kerning first=8216 second=103 amount=-1 +kerning first=933 second=44 amount=-1 +kerning first=1066 second=1058 amount=-1 +kerning first=1027 second=1084 amount=-1 +kerning first=76 second=932 amount=-1 +kerning first=8211 second=933 amount=-1 +kerning first=319 second=39 amount=-1 +kerning first=932 second=171 amount=-1 +kerning first=358 second=281 amount=-1 +kerning first=84 second=109 amount=-1 +kerning first=46 second=39 amount=-1 +kerning first=315 second=221 amount=-1 +kerning first=358 second=125 amount=1 +kerning first=376 second=101 amount=-1 +kerning first=87 second=8230 amount=-1 +kerning first=45 second=221 amount=-1 +kerning first=227 second=356 amount=-1 +kerning first=194 second=933 amount=-1 +kerning first=915 second=260 amount=-1 +kerning first=315 second=84 amount=-1 +kerning first=356 second=367 amount=-1 +kerning first=8216 second=256 amount=-1 +kerning first=258 second=8221 amount=-1 +kerning first=8220 second=1058 amount=1 +kerning first=45 second=84 amount=-1 +kerning first=1058 second=1103 amount=-1 +kerning first=372 second=196 amount=-1 +kerning first=321 second=89 amount=-1 +kerning first=1168 second=1108 amount=-1 +kerning first=354 second=365 amount=-1 +kerning first=1068 second=8221 amount=-1 +kerning first=356 second=972 amount=-1 +kerning first=376 second=46 amount=-1 +kerning first=356 second=250 amount=-1 +kerning first=258 second=354 amount=-1 +kerning first=84 second=324 amount=-1 +kerning first=354 second=941 amount=-1 +kerning first=8220 second=962 amount=-1 +kerning first=1058 second=59 amount=-1 +kerning first=915 second=948 amount=-1 +kerning first=356 second=109 amount=-1 +kerning first=89 second=228 amount=-1 +kerning first=354 second=246 amount=-1 +kerning first=91 second=309 amount=1 +kerning first=8220 second=243 amount=-1 +kerning first=321 second=34 amount=-1 +kerning first=80 second=260 amount=-1 +kerning first=86 second=46 amount=-1 +kerning first=8217 second=8204 amount=-1 +kerning first=1043 second=173 amount=-1 +kerning first=8217 second=273 amount=-1 +kerning first=354 second=105 amount=-1 +kerning first=1059 second=1044 amount=-1 +kerning first=8220 second=103 amount=-1 +kerning first=358 second=940 amount=-1 +kerning first=84 second=226 amount=-1 +kerning first=8217 second=277 amount=-1 +kerning first=358 second=244 amount=-1 +kerning first=932 second=263 amount=-1 +kerning first=260 second=87 amount=-1 +kerning first=1043 second=1100 amount=-1 +kerning first=8230 second=8220 amount=-1 +kerning first=1168 second=8230 amount=-1 +kerning first=354 second=916 amount=-1 +kerning first=70 second=913 amount=-1 +kerning first=89 second=248 amount=-1 +kerning first=187 second=376 amount=-1 +kerning first=70 second=258 amount=-1 +kerning first=196 second=8216 amount=-1 +kerning first=8220 second=256 amount=-1 +kerning first=228 second=358 amount=-1 +kerning first=271 second=295 amount=1 +kerning first=356 second=324 amount=-1 +kerning first=932 second=192 amount=-1 +kerning first=8221 second=248 amount=-1 +kerning first=1058 second=1082 amount=-1 +kerning first=1056 second=46 amount=-2 +kerning first=376 second=198 amount=-1 +kerning first=933 second=923 amount=-1 +kerning first=1168 second=1086 amount=-1 +kerning first=89 second=279 amount=-1 +kerning first=358 second=260 amount=-1 +kerning first=195 second=221 amount=-1 +kerning first=8216 second=263 amount=-1 +kerning first=221 second=265 amount=-1 +kerning first=84 second=331 amount=-1 +kerning first=356 second=226 amount=-1 +kerning first=8217 second=351 amount=-1 +kerning first=1038 second=1044 amount=-1 +kerning first=34 second=65 amount=-1 +kerning first=1027 second=1097 amount=-1 +kerning first=965 second=34 amount=-1 +kerning first=86 second=198 amount=-1 +kerning first=84 second=283 amount=-1 +kerning first=8221 second=279 amount=-1 +kerning first=354 second=949 amount=-1 +kerning first=195 second=84 amount=-1 +kerning first=84 second=122 amount=-1 +kerning first=65 second=39 amount=-1 +kerning first=376 second=261 amount=-1 +kerning first=187 second=358 amount=-1 +kerning first=1058 second=1026 amount=1 +kerning first=358 second=8249 amount=-1 +kerning first=915 second=197 amount=-1 +kerning first=260 second=933 amount=-1 +kerning first=8216 second=192 amount=-1 +kerning first=221 second=195 amount=-1 +kerning first=932 second=961 amount=-1 +kerning first=171 second=939 amount=-1 +kerning first=1040 second=1035 amount=-1 +kerning first=932 second=234 amount=-1 +kerning first=358 second=948 amount=-1 +kerning first=1068 second=1063 amount=-1 +kerning first=1058 second=1118 amount=-1 +kerning first=324 second=356 amount=-1 +kerning first=376 second=194 amount=-1 +kerning first=8217 second=100 amount=-1 +kerning first=1043 second=1079 amount=-1 +kerning first=354 second=378 amount=-1 +kerning first=929 second=256 amount=-1 +kerning first=915 second=187 amount=-1 +kerning first=356 second=331 amount=-1 +kerning first=1027 second=8211 amount=-1 +kerning first=221 second=8230 amount=-1 +kerning first=86 second=194 amount=-1 +kerning first=84 second=349 amount=-1 +kerning first=356 second=283 amount=-1 +kerning first=80 second=197 amount=-1 +kerning first=376 second=337 amount=-1 +kerning first=356 second=122 amount=-1 +kerning first=317 second=39 amount=-1 +kerning first=915 second=963 amount=-1 +kerning first=8216 second=961 amount=-1 +kerning first=44 second=39 amount=-1 +kerning first=313 second=221 amount=-1 +kerning first=354 second=265 amount=-1 +kerning first=8216 second=234 amount=-1 +kerning first=8220 second=263 amount=-1 +kerning first=221 second=232 amount=-1 +kerning first=224 second=356 amount=-1 +kerning first=84 second=236 amount=-1 +kerning first=313 second=84 amount=-1 +kerning first=34 second=44 amount=-1 +kerning first=221 second=97 amount=-1 +kerning first=932 second=289 amount=-1 +kerning first=376 second=231 amount=-1 +kerning first=1027 second=1076 amount=-1 +kerning first=321 second=8220 amount=-1 +kerning first=1043 second=1114 amount=-1 +kerning first=923 second=376 amount=-1 +kerning first=89 second=913 amount=-1 +kerning first=358 second=269 amount=-1 +kerning first=1041 second=1066 amount=-1 +kerning first=84 second=101 amount=-1 +kerning first=354 second=195 amount=-1 +kerning first=70 second=196 amount=-1 +kerning first=358 second=117 amount=-1 +kerning first=39 second=65 amount=-1 +kerning first=91 second=356 amount=1 +kerning first=8220 second=192 amount=-1 +kerning first=376 second=93 amount=1 +kerning first=1066 second=8221 amount=-1 +kerning first=89 second=258 amount=-1 +kerning first=104 second=84 amount=-1 +kerning first=356 second=349 amount=-1 +kerning first=8221 second=913 amount=-1 +kerning first=1058 second=1095 amount=-1 +kerning first=358 second=197 amount=-1 +kerning first=1075 second=46 amount=-1 +kerning first=944 second=39 amount=-1 +kerning first=86 second=93 amount=1 +kerning first=1168 second=1099 amount=-1 +kerning first=8221 second=258 amount=-1 +kerning first=354 second=345 amount=-1 +kerning first=932 second=74 amount=-1 +kerning first=84 second=46 amount=-1 +kerning first=354 second=8230 amount=-1 +kerning first=109 second=358 amount=-1 +kerning first=8216 second=289 amount=-1 +kerning first=934 second=933 amount=-1 +kerning first=356 second=236 amount=-1 +kerning first=932 second=371 amount=-1 +kerning first=1027 second=1111 amount=-1 +kerning first=1114 second=1098 amount=-1 +kerning first=923 second=358 amount=-1 +kerning first=84 second=297 amount=-1 +kerning first=358 second=341 amount=-1 +kerning first=258 second=87 amount=-1 +kerning first=356 second=101 amount=-1 +kerning first=8220 second=961 amount=-1 +kerning first=354 second=232 amount=-1 +kerning first=1058 second=1040 amount=-1 +kerning first=1118 second=8230 amount=-1 +kerning first=8220 second=234 amount=-1 +kerning first=8230 second=8217 amount=-1 +kerning first=8218 second=89 amount=-1 +kerning first=8222 second=376 amount=-1 +kerning first=1168 second=1044 amount=-1 +kerning first=932 second=970 amount=1 +kerning first=261 second=84 amount=-1 +kerning first=354 second=97 amount=-1 +kerning first=84 second=945 amount=-1 +kerning first=193 second=8216 amount=-1 +kerning first=932 second=353 amount=-1 +kerning first=936 second=193 amount=-1 +kerning first=358 second=963 amount=-1 +kerning first=225 second=358 amount=-1 +kerning first=1059 second=1035 amount=1 +kerning first=358 second=235 amount=-1 +kerning first=929 second=192 amount=-1 +kerning first=8216 second=74 amount=-1 +kerning first=8217 second=113 amount=-1 +kerning first=933 second=940 amount=-1 +kerning first=34 second=974 amount=-1 +kerning first=1043 second=1092 amount=-1 +kerning first=227 second=932 amount=-1 +kerning first=376 second=308 amount=-1 +kerning first=356 second=46 amount=-1 +kerning first=39 second=44 amount=-1 +kerning first=910 second=913 amount=-1 +kerning first=197 second=39 amount=-1 +kerning first=221 second=361 amount=-1 +kerning first=192 second=221 amount=-1 +kerning first=8217 second=193 amount=-1 +kerning first=910 second=258 amount=-1 +kerning first=356 second=297 amount=-1 +kerning first=84 second=198 amount=-1 +kerning first=376 second=369 amount=-1 +kerning first=915 second=972 amount=-1 +kerning first=192 second=84 amount=-1 +kerning first=1058 second=1074 amount=-1 +kerning first=173 second=356 amount=-1 +kerning first=34 second=923 amount=-1 +kerning first=8222 second=358 amount=-1 +kerning first=1168 second=1078 amount=-1 +kerning first=8220 second=289 amount=-1 +kerning first=326 second=354 amount=-1 +kerning first=221 second=251 amount=-1 +kerning first=89 second=115 amount=-1 +kerning first=358 second=41 amount=1 +kerning first=258 second=933 amount=-1 +kerning first=356 second=945 amount=-1 +kerning first=933 second=260 amount=-1 +kerning first=8217 second=335 amount=-1 +kerning first=1038 second=1035 amount=1 +kerning first=331 second=84 amount=-1 +kerning first=376 second=242 amount=-1 +kerning first=1027 second=1089 amount=-1 +kerning first=1066 second=1063 amount=-1 +kerning first=84 second=261 amount=-1 +kerning first=932 second=8211 amount=-1 +kerning first=84 second=114 amount=-1 +kerning first=89 second=196 amount=-1 +kerning first=8221 second=115 amount=-1 +kerning first=110 second=356 amount=-1 +kerning first=114 second=44 amount=-1 +kerning first=950 second=125 amount=1 +kerning first=123 second=84 amount=1 +kerning first=902 second=221 amount=-1 +kerning first=315 second=89 amount=-1 +kerning first=319 second=376 amount=-1 +kerning first=8220 second=74 amount=-1 +kerning first=932 second=225 amount=-1 +kerning first=84 second=194 amount=-1 +kerning first=45 second=89 amount=-1 +kerning first=356 second=198 amount=-1 +kerning first=8221 second=196 amount=-1 +kerning first=321 second=356 amount=-1 +kerning first=1027 second=45 amount=-1 +kerning first=902 second=84 amount=-1 +kerning first=8249 second=933 amount=-1 +kerning first=933 second=948 amount=-1 +kerning first=1168 second=1113 amount=-1 +kerning first=354 second=361 amount=-1 +kerning first=89 second=333 amount=-1 +kerning first=1034 second=1026 amount=-1 +kerning first=1059 second=1105 amount=-1 +kerning first=372 second=65 amount=-1 +kerning first=39 second=974 amount=-1 +kerning first=226 second=356 amount=-1 +kerning first=913 second=8216 amount=-1 +kerning first=315 second=34 amount=-1 +kerning first=84 second=337 amount=-1 +kerning first=356 second=261 amount=-1 +kerning first=8221 second=333 amount=-1 +kerning first=932 second=305 amount=-1 +kerning first=358 second=367 amount=-1 +kerning first=356 second=114 amount=-1 +kerning first=354 second=251 amount=-1 +kerning first=89 second=233 amount=-1 +kerning first=87 second=913 amount=-1 +kerning first=915 second=953 amount=-1 +kerning first=321 second=8217 amount=-1 +kerning first=8212 second=376 amount=-1 +kerning first=1043 second=1241 amount=-1 +kerning first=221 second=228 amount=-1 +kerning first=256 second=8216 amount=-1 +kerning first=354 second=110 amount=-1 +kerning first=87 second=258 amount=-1 +kerning first=319 second=358 amount=-1 +kerning first=932 second=273 amount=-1 +kerning first=39 second=923 amount=-1 +kerning first=358 second=972 amount=-1 +kerning first=84 second=231 amount=-1 +kerning first=356 second=194 amount=-1 +kerning first=8217 second=287 amount=-1 +kerning first=358 second=250 amount=-1 +kerning first=8221 second=233 amount=-1 +kerning first=939 second=173 amount=-1 +kerning first=932 second=277 amount=-1 +kerning first=957 second=8230 amount=-1 +kerning first=8216 second=1076 amount=-1 +kerning first=1041 second=1058 amount=-1 +kerning first=974 second=39 amount=-1 +kerning first=916 second=84 amount=-1 +kerning first=84 second=93 amount=1 +kerning first=929 second=74 amount=-1 +kerning first=358 second=109 amount=-1 +kerning first=910 second=196 amount=-1 +kerning first=271 second=8217 amount=1 +kerning first=91 second=86 amount=1 +kerning first=1027 second=8212 amount=-1 +kerning first=1038 second=1105 amount=-1 +kerning first=324 second=932 amount=-1 +kerning first=221 second=248 amount=-1 +kerning first=356 second=337 amount=-1 +kerning first=1058 second=1087 amount=-1 +kerning first=8212 second=358 amount=-1 +kerning first=354 second=328 amount=-1 +kerning first=1056 second=1040 amount=-1 +kerning first=8216 second=273 amount=-1 +kerning first=933 second=197 amount=-1 +kerning first=1168 second=1091 amount=-1 +kerning first=8221 second=8217 amount=-1 +kerning first=372 second=44 amount=-1 +kerning first=259 second=84 amount=-1 +kerning first=221 second=279 amount=-1 +kerning first=8216 second=277 amount=-1 +kerning first=356 second=231 amount=-1 +kerning first=932 second=351 amount=-1 +kerning first=1027 second=1102 amount=-1 +kerning first=1114 second=1090 amount=-1 +kerning first=84 second=285 amount=-1 +kerning first=8221 second=291 amount=-1 +kerning first=358 second=324 amount=-1 +kerning first=195 second=89 amount=-1 +kerning first=8211 second=221 amount=-1 +kerning first=376 second=267 amount=-1 +kerning first=356 second=93 amount=1 +kerning first=354 second=228 amount=-1 +kerning first=224 second=932 amount=-1 +kerning first=910 second=959 amount=-1 +kerning first=196 second=39 amount=-1 +kerning first=8211 second=84 amount=-1 +kerning first=8217 second=246 amount=-1 +kerning first=936 second=916 amount=-1 +kerning first=932 second=239 amount=-1 +kerning first=194 second=221 amount=-1 +kerning first=8220 second=1076 amount=-1 +kerning first=65 second=376 amount=-1 +kerning first=1027 second=58 amount=-1 +kerning first=358 second=226 amount=-1 +kerning first=343 second=46 amount=-1 +kerning first=91 second=932 amount=1 +kerning first=933 second=963 amount=-1 +kerning first=1043 second=1084 amount=-1 +kerning first=84 second=308 amount=-1 +kerning first=194 second=84 amount=-1 +kerning first=932 second=100 amount=-1 +kerning first=195 second=34 amount=-1 +kerning first=89 second=363 amount=-1 +kerning first=354 second=248 amount=-1 +kerning first=70 second=230 amount=-1 +kerning first=74 second=125 amount=1 +kerning first=328 second=354 amount=-1 +kerning first=84 second=369 amount=-1 +kerning first=1035 second=1035 amount=-1 +kerning first=356 second=285 amount=-1 +kerning first=915 second=968 amount=-1 +kerning first=89 second=245 amount=-1 +kerning first=8220 second=273 amount=-1 +kerning first=87 second=196 amount=-1 +kerning first=271 second=107 amount=1 +kerning first=354 second=279 amount=-1 +kerning first=932 second=45 amount=-1 +kerning first=8220 second=277 amount=-1 +kerning first=315 second=8220 amount=-1 +kerning first=329 second=358 amount=-1 +kerning first=34 second=260 amount=-1 +kerning first=313 second=89 amount=-1 +kerning first=65 second=358 amount=-1 +kerning first=317 second=376 amount=-1 +kerning first=84 second=242 amount=-1 +kerning first=358 second=331 amount=-1 +kerning first=8216 second=100 amount=-1 +kerning first=8221 second=245 amount=-1 +kerning first=932 second=303 amount=-1 +kerning first=1027 second=1081 amount=-1 +kerning first=229 second=354 amount=-1 +kerning first=356 second=308 amount=-1 +kerning first=358 second=283 amount=-1 +kerning first=358 second=122 amount=-1 +kerning first=221 second=913 amount=-1 +kerning first=1058 second=173 amount=-1 +kerning first=70 second=65 amount=-1 +kerning first=356 second=369 amount=-1 +kerning first=915 second=46 amount=-1 +kerning first=372 second=923 amount=-1 +kerning first=221 second=258 amount=-1 +kerning first=313 second=34 amount=-1 +kerning first=1058 second=1100 amount=-1 +kerning first=271 second=320 amount=1 +kerning first=321 second=86 amount=-1 +kerning first=1168 second=1105 amount=-1 +kerning first=293 second=84 amount=-1 +kerning first=356 second=242 amount=-1 +kerning first=317 second=358 amount=-1 +kerning first=173 second=932 amount=-1 +kerning first=1027 second=1116 amount=-1 +kerning first=932 second=8212 amount=-1 +kerning first=354 second=969 amount=-1 +kerning first=358 second=349 amount=-1 +kerning first=915 second=945 amount=-1 +kerning first=354 second=241 amount=-1 +kerning first=8218 second=356 amount=-1 +kerning first=8212 second=910 amount=-1 +kerning first=973 second=39 amount=-1 +kerning first=76 second=8216 amount=-1 +kerning first=80 second=46 amount=-2 +kerning first=932 second=912 amount=1 +kerning first=260 second=221 amount=-1 +kerning first=8220 second=100 amount=-1 +kerning first=939 second=962 amount=-1 +kerning first=319 second=173 amount=-1 +kerning first=936 second=195 amount=-1 +kerning first=8217 second=265 amount=-1 +kerning first=86 second=301 amount=1 +kerning first=358 second=236 amount=-1 +kerning first=110 second=932 amount=-1 +kerning first=932 second=257 amount=-1 +kerning first=260 second=84 amount=-1 +kerning first=923 second=936 amount=-1 +kerning first=933 second=972 amount=-1 +kerning first=1027 second=1060 amount=-1 +kerning first=354 second=913 amount=-1 +kerning first=932 second=113 amount=-1 +kerning first=345 second=8230 amount=-1 +kerning first=39 second=260 amount=-1 +kerning first=1043 second=1097 amount=-1 +kerning first=89 second=230 amount=-1 +kerning first=358 second=101 amount=-1 +kerning first=915 second=198 amount=-1 +kerning first=321 second=932 amount=-1 +kerning first=354 second=258 amount=-1 +kerning first=8230 second=939 amount=-1 +kerning first=8217 second=195 amount=-1 +kerning first=70 second=44 amount=-1 +kerning first=84 second=380 amount=-1 +kerning first=932 second=193 amount=-1 +kerning first=195 second=8220 amount=-1 +kerning first=936 second=8230 amount=-1 +kerning first=915 second=944 amount=-1 +kerning first=354 second=307 amount=-1 +kerning first=1058 second=1079 amount=-1 +kerning first=192 second=89 amount=-1 +kerning first=197 second=376 amount=-1 +kerning first=1168 second=1083 amount=-1 +kerning first=226 second=932 amount=-1 +kerning first=89 second=271 amount=-1 +kerning first=939 second=256 amount=-1 +kerning first=34 second=197 amount=-1 +kerning first=358 second=46 amount=-1 +kerning first=193 second=39 amount=-1 +kerning first=1043 second=8211 amount=-1 +kerning first=950 second=41 amount=1 +kerning first=8216 second=113 amount=-1 +kerning first=221 second=115 amount=-1 +kerning first=932 second=335 amount=-1 +kerning first=376 second=252 amount=-1 +kerning first=8217 second=8230 amount=-2 +kerning first=1027 second=1094 amount=-1 +kerning first=84 second=267 amount=-1 +kerning first=376 second=173 amount=-1 +kerning first=358 second=297 amount=-1 +kerning first=341 second=46 amount=-1 +kerning first=80 second=198 amount=-1 +kerning first=8221 second=271 amount=-1 +kerning first=923 second=372 amount=-1 +kerning first=1091 second=8230 amount=-1 +kerning first=372 second=125 amount=1 +kerning first=192 second=34 amount=-1 +kerning first=376 second=111 amount=-1 +kerning first=357 second=8217 amount=1 +kerning first=915 second=194 amount=-1 +kerning first=315 second=356 amount=-1 +kerning first=8216 second=193 amount=-1 +kerning first=221 second=196 amount=-1 +kerning first=8217 second=232 amount=-1 +kerning first=89 second=65 amount=-1 +kerning first=45 second=356 amount=-1 +kerning first=356 second=380 amount=-1 +kerning first=932 second=227 amount=-1 +kerning first=915 second=59 amount=-1 +kerning first=358 second=945 amount=-1 +kerning first=1033 second=1035 amount=-1 +kerning first=1058 second=1114 amount=-1 +kerning first=1043 second=1076 amount=-1 +kerning first=197 second=358 amount=-1 +kerning first=902 second=89 amount=-1 +kerning first=1168 second=1119 amount=-1 +kerning first=89 second=347 amount=-1 +kerning first=8221 second=65 amount=-1 +kerning first=8216 second=335 amount=-1 +kerning first=221 second=333 amount=-1 +kerning first=313 second=8220 amount=-1 +kerning first=1027 second=8250 amount=-1 +kerning first=295 second=358 amount=-1 +kerning first=173 second=939 amount=-1 +kerning first=315 second=8217 amount=-1 +kerning first=84 second=343 amount=-1 +kerning first=356 second=267 amount=-1 +kerning first=8221 second=347 amount=-1 +kerning first=80 second=194 amount=-1 +kerning first=228 second=354 amount=-1 +kerning first=354 second=382 amount=-1 +kerning first=358 second=198 amount=-1 +kerning first=1090 second=46 amount=-1 +kerning first=902 second=34 amount=-1 +kerning first=70 second=259 amount=-1 +kerning first=221 second=233 amount=-1 +kerning first=354 second=115 amount=-1 +kerning first=89 second=99 amount=-1 +kerning first=8222 second=372 amount=-1 +kerning first=8220 second=113 amount=-1 +kerning first=84 second=237 amount=-1 +kerning first=39 second=197 amount=-1 +kerning first=1043 second=1111 amount=-1 +kerning first=932 second=287 amount=-1 +kerning first=376 second=224 amount=-1 +kerning first=70 second=923 amount=-1 +kerning first=358 second=261 amount=-1 +kerning first=8221 second=99 amount=-1 +kerning first=1034 second=1066 amount=-1 +kerning first=354 second=196 amount=-1 +kerning first=358 second=114 amount=-1 +kerning first=8220 second=193 amount=-1 +kerning first=187 second=354 amount=-1 +kerning first=913 second=39 amount=-1 +kerning first=89 second=44 amount=-1 +kerning first=356 second=343 amount=-1 +kerning first=241 second=358 amount=-1 +kerning first=102 second=34 amount=1 +kerning first=910 second=65 amount=-1 +kerning first=939 second=192 amount=-1 +kerning first=1058 second=1092 amount=-1 +kerning first=358 second=194 amount=-1 +kerning first=376 second=339 amount=-1 +kerning first=1168 second=1096 amount=-1 +kerning first=354 second=333 amount=-1 +kerning first=8220 second=335 amount=-1 +kerning first=372 second=260 amount=-1 +kerning first=916 second=34 amount=-1 +kerning first=256 second=39 amount=-1 +kerning first=8221 second=44 amount=-2 +kerning first=8216 second=287 amount=-1 +kerning first=258 second=221 amount=-1 +kerning first=356 second=237 amount=-1 +kerning first=317 second=173 amount=-1 +kerning first=932 second=365 amount=-1 +kerning first=195 second=356 amount=-1 +kerning first=84 second=301 amount=-1 +kerning first=1027 second=1108 amount=-1 +kerning first=354 second=959 amount=-1 +kerning first=358 second=337 amount=-1 +kerning first=971 second=34 amount=-1 +kerning first=258 second=84 amount=-1 +kerning first=376 second=275 amount=-1 +kerning first=354 second=233 amount=-1 +kerning first=70 second=229 amount=-1 +kerning first=8218 second=86 amount=-1 +kerning first=910 second=966 amount=-1 +kerning first=8211 second=89 amount=-1 +kerning first=932 second=941 amount=-1 +kerning first=1059 second=44 amount=-1 +kerning first=74 second=41 amount=1 +kerning first=939 second=961 amount=-1 +kerning first=932 second=246 amount=-1 +kerning first=1059 second=1032 amount=-1 +kerning first=358 second=231 amount=-1 +kerning first=929 second=193 amount=-1 +kerning first=319 second=372 amount=-1 +kerning first=192 second=8220 amount=-1 +kerning first=934 second=8230 amount=-1 +kerning first=1043 second=1089 amount=-1 +kerning first=194 second=89 amount=-1 +kerning first=932 second=105 amount=-1 +kerning first=196 second=376 amount=-1 +kerning first=195 second=8217 amount=-1 +kerning first=358 second=93 amount=1 +kerning first=40 second=106 amount=1 +kerning first=1100 second=8221 amount=-1 +kerning first=257 second=358 amount=-1 +kerning first=221 second=363 amount=-1 +kerning first=40 second=1095 amount=-1 +kerning first=1027 second=8230 amount=-1 +kerning first=932 second=916 amount=-1 +kerning first=356 second=301 amount=-1 +kerning first=915 second=942 amount=-1 +kerning first=89 second=249 amount=-1 +kerning first=910 second=44 amount=-1 +kerning first=955 second=34 amount=-1 +kerning first=8216 second=941 amount=-1 +kerning first=80 second=308 amount=-1 +kerning first=923 second=8221 amount=-1 +kerning first=123 second=309 amount=1 +kerning first=1168 second=1075 amount=-1 +kerning first=1043 second=45 amount=-1 +kerning first=194 second=34 amount=-1 +kerning first=354 second=291 amount=-1 +kerning first=89 second=259 amount=-1 +kerning first=8220 second=287 amount=-1 +kerning first=8216 second=246 amount=-1 +kerning first=221 second=245 amount=-1 +kerning first=313 second=356 amount=-1 +kerning first=1038 second=44 amount=-1 +kerning first=84 second=252 amount=-1 +kerning first=87 second=65 amount=-1 +kerning first=8218 second=932 amount=-1 +kerning first=109 second=354 amount=-1 +kerning first=1038 second=1032 amount=-1 +kerning first=84 second=173 amount=-1 +kerning first=8221 second=160 amount=-1 +kerning first=902 second=8220 amount=-1 +kerning first=376 second=243 amount=-1 +kerning first=933 second=46 amount=-1 +kerning first=1027 second=1086 amount=-1 +kerning first=89 second=923 amount=-1 +kerning first=358 second=285 amount=-1 +kerning first=196 second=358 amount=-1 +kerning first=84 second=111 amount=-1 +kerning first=923 second=354 amount=-1 +kerning first=8216 second=916 amount=-1 +kerning first=104 second=356 amount=-1 +kerning first=1058 second=1241 amount=-1 +kerning first=932 second=949 amount=-1 +kerning first=315 second=86 amount=-1 +kerning first=8221 second=923 amount=-1 +kerning first=8204 second=8216 amount=-1 +kerning first=65 second=936 amount=-1 +kerning first=1033 second=8217 amount=-1 +kerning first=313 second=8217 amount=-1 +kerning first=372 second=197 amount=-1 +kerning first=933 second=945 amount=-1 +kerning first=225 second=354 amount=-1 +kerning first=354 second=363 amount=-1 +kerning first=358 second=308 amount=-1 +kerning first=376 second=256 amount=-1 +kerning first=102 second=8220 amount=1 +kerning first=356 second=252 amount=-1 +kerning first=1043 second=8212 amount=-1 +kerning first=356 second=173 amount=-1 +kerning first=932 second=378 amount=-1 +kerning first=8217 second=248 amount=-1 +kerning first=358 second=369 amount=-1 +kerning first=8220 second=941 amount=-1 +kerning first=356 second=111 amount=-1 +kerning first=354 second=245 amount=-1 +kerning first=86 second=256 amount=-1 +kerning first=89 second=229 amount=-1 +kerning first=8220 second=246 amount=-1 +kerning first=376 second=171 amount=-1 +kerning first=261 second=356 amount=-1 +kerning first=8216 second=949 amount=-1 +kerning first=933 second=198 amount=-1 +kerning first=8222 second=354 amount=-1 +kerning first=84 second=224 amount=-1 +kerning first=87 second=44 amount=-1 +kerning first=8217 second=279 amount=-1 +kerning first=358 second=242 amount=-1 +kerning first=932 second=265 amount=-1 +kerning first=1043 second=1102 amount=-1 +kerning first=260 second=89 amount=-1 +kerning first=40 second=358 amount=1 +kerning first=65 second=372 amount=-1 +kerning first=315 second=932 amount=-1 +kerning first=8220 second=916 amount=-1 +kerning first=1034 second=1058 amount=-1 +kerning first=45 second=932 amount=-1 +kerning first=910 second=923 amount=-1 +kerning first=70 second=260 amount=-1 +kerning first=221 second=230 amount=-1 +kerning first=932 second=195 amount=-1 +kerning first=192 second=356 amount=-1 +kerning first=84 second=339 amount=-1 +kerning first=1043 second=58 amount=-1 +kerning first=1058 second=1084 amount=-1 +kerning first=260 second=34 amount=-1 +kerning first=1168 second=1088 amount=-1 +kerning first=76 second=39 amount=-1 +kerning first=89 second=281 amount=-1 +kerning first=933 second=194 amount=-1 +kerning first=89 second=125 amount=1 +kerning first=372 second=41 amount=1 +kerning first=331 second=356 amount=-1 +kerning first=8216 second=265 amount=-1 +kerning first=221 second=271 amount=-1 +kerning first=84 second=312 amount=-1 +kerning first=356 second=224 amount=-1 +kerning first=932 second=345 amount=-1 +kerning first=1027 second=1099 amount=-1 +kerning first=84 second=275 amount=-1 +kerning first=319 second=8221 amount=-1 +kerning first=317 second=372 amount=-1 +kerning first=194 second=8220 amount=-1 +kerning first=932 second=8230 amount=-1 +kerning first=195 second=86 amount=-1 +kerning first=376 second=263 amount=-1 +kerning first=8221 second=281 amount=-1 +kerning first=939 second=8211 amount=-1 +kerning first=46 second=8221 amount=-1 +kerning first=8220 second=949 amount=-1 +kerning first=193 second=376 amount=-1 +kerning first=192 second=8217 amount=-1 +kerning first=123 second=356 amount=1 +kerning first=1028 second=1095 amount=-1 +kerning first=1168 second=1032 amount=-1 +kerning first=1168 second=44 amount=-1 +kerning first=8216 second=195 amount=-1 +kerning first=1098 second=8221 amount=-1 +kerning first=936 second=913 amount=-1 +kerning first=932 second=232 amount=-1 +kerning first=929 second=916 amount=-1 +kerning first=902 second=356 amount=-1 +kerning first=356 second=339 amount=-1 +kerning first=319 second=354 amount=-1 +kerning first=221 second=65 amount=-1 +kerning first=376 second=192 amount=-1 +kerning first=936 second=258 amount=-1 +kerning first=1027 second=1044 amount=-1 +kerning first=1043 second=1081 amount=-1 +kerning first=932 second=97 amount=-1 +kerning first=354 second=230 amount=-1 +kerning first=306 second=125 amount=1 +kerning first=221 second=347 amount=-1 +kerning first=356 second=312 amount=-1 +kerning first=8217 second=913 amount=-1 +kerning first=8216 second=8230 amount=-1 +kerning first=86 second=192 amount=-1 +kerning first=356 second=275 amount=-1 +kerning first=358 second=380 amount=-1 +kerning first=8217 second=258 amount=-1 +kerning first=89 second=244 amount=-1 +kerning first=197 second=936 amount=-1 +kerning first=87 second=923 amount=-1 +kerning first=915 second=965 amount=-1 +kerning first=193 second=358 amount=-1 +kerning first=902 second=8217 amount=-1 +kerning first=271 second=104 amount=1 +kerning first=354 second=271 amount=-1 +kerning first=8216 second=232 amount=-1 +kerning first=8220 second=265 amount=-1 +kerning first=195 second=932 amount=-1 +kerning first=8212 second=354 amount=-1 +kerning first=84 second=962 amount=-1 +kerning first=326 second=84 amount=-1 +kerning first=313 second=86 amount=-1 +kerning first=84 second=243 amount=-1 +kerning first=8221 second=244 amount=-1 +kerning first=34 second=46 amount=-1 +kerning first=221 second=99 amount=-1 +kerning first=376 second=234 amount=-1 +kerning first=1027 second=1078 amount=-1 +kerning first=916 second=356 amount=-1 +kerning first=1043 second=1116 amount=-1 +kerning first=358 second=267 amount=-1 +kerning first=84 second=103 amount=-1 +kerning first=70 second=197 amount=-1 +kerning first=8220 second=195 amount=-1 +kerning first=45 second=939 amount=-1 +kerning first=923 second=87 amount=-1 +kerning first=89 second=260 amount=-1 +kerning first=1026 second=1026 amount=-1 +kerning first=354 second=65 amount=-1 +kerning first=102 second=8217 amount=1 +kerning first=1058 second=1097 amount=-1 +kerning first=271 second=314 amount=1 +kerning first=221 second=44 amount=-1 +kerning first=1043 second=1060 amount=-1 +kerning first=8230 second=8216 amount=-1 +kerning first=84 second=256 amount=-1 +kerning first=354 second=347 amount=-1 +kerning first=8221 second=260 amount=-1 +kerning first=1168 second=1101 amount=-1 +kerning first=913 second=376 amount=-1 +kerning first=197 second=372 amount=-1 +kerning first=916 second=8217 amount=-1 +kerning first=259 second=356 amount=-1 +kerning first=89 second=8249 amount=-1 +kerning first=8220 second=8230 amount=-1 +kerning first=356 second=962 amount=-1 +kerning first=356 second=243 amount=-1 +kerning first=932 second=361 amount=-1 +kerning first=260 second=8220 amount=-1 +kerning first=1027 second=1113 amount=-1 +kerning first=354 second=966 amount=-1 +kerning first=358 second=343 amount=-1 +kerning first=258 second=89 amount=-1 +kerning first=84 second=171 amount=-1 +kerning first=256 second=376 amount=-1 +kerning first=65 second=8221 amount=-1 +kerning first=356 second=103 amount=-1 +kerning first=354 second=238 amount=-1 +kerning first=8220 second=232 amount=-1 +kerning first=313 second=932 amount=-1 +kerning first=910 second=940 amount=-1 +kerning first=8211 second=356 amount=-1 +kerning first=34 second=198 amount=-1 +kerning first=354 second=99 amount=-1 +kerning first=932 second=251 amount=-1 +kerning first=936 second=196 amount=-1 +kerning first=8222 second=87 amount=-1 +kerning first=1058 second=8211 amount=-1 +kerning first=929 second=195 amount=-1 +kerning first=358 second=237 amount=-1 +kerning first=194 second=356 amount=-1 +kerning first=329 second=354 amount=-1 +kerning first=8217 second=115 amount=-1 +kerning first=923 second=933 amount=-1 +kerning first=1043 second=1094 amount=-1 +kerning first=104 second=932 amount=-1 +kerning first=65 second=354 amount=-1 +kerning first=356 second=256 amount=-1 +kerning first=932 second=110 amount=-1 +kerning first=913 second=358 amount=-1 +kerning first=258 second=34 amount=-1 +kerning first=1107 second=8230 amount=-1 +kerning first=39 second=46 amount=-1 +kerning first=376 second=74 amount=-1 +kerning first=87 second=125 amount=1 +kerning first=950 second=93 amount=1 +kerning first=8250 second=376 amount=-1 +kerning first=8217 second=196 amount=-1 +kerning first=354 second=44 amount=-1 +kerning first=910 second=260 amount=-1 +kerning first=1034 second=8221 amount=-1 +kerning first=256 second=358 amount=-1 +kerning first=317 second=8221 amount=-1 +kerning first=356 second=171 amount=-1 +kerning first=376 second=371 amount=-1 +kerning first=929 second=8230 amount=-2 +kerning first=915 second=971 amount=-1 +kerning first=192 second=86 amount=-1 +kerning first=44 second=8221 amount=-1 +kerning first=955 second=8217 amount=-1 +kerning first=915 second=173 amount=-1 +kerning first=1058 second=1076 amount=-1 +kerning first=194 second=8217 amount=-1 +kerning first=354 second=299 amount=-1 +kerning first=89 second=269 amount=-1 +kerning first=221 second=249 amount=-1 +kerning first=34 second=194 amount=-1 +kerning first=89 second=117 amount=-1 +kerning first=195 second=939 amount=-1 +kerning first=939 second=45 amount=-1 +kerning first=1168 second=1080 amount=-1 +kerning first=1059 second=1072 amount=-1 +kerning first=1118 second=44 amount=-1 +kerning first=221 second=259 amount=-1 +kerning first=8217 second=333 amount=-1 +kerning first=1043 second=8250 amount=-1 +kerning first=932 second=328 amount=-1 +kerning first=376 second=353 amount=-1 +kerning first=1027 second=1091 amount=-1 +kerning first=84 second=263 amount=-1 +kerning first=319 second=8211 amount=-1 +kerning first=261 second=932 amount=-1 +kerning first=317 second=354 amount=-1 +kerning first=358 second=301 amount=-1 +kerning first=8221 second=269 amount=-1 +kerning first=89 second=197 amount=-1 +kerning first=910 second=948 amount=-1 +kerning first=221 second=923 amount=-1 +kerning first=114 second=46 amount=-1 +kerning first=1113 second=8217 amount=-1 +kerning first=8250 second=358 amount=-1 +kerning first=123 second=86 amount=1 +kerning first=8217 second=233 amount=-1 +kerning first=932 second=228 amount=-1 +kerning first=84 second=192 amount=-1 +kerning first=8221 second=197 amount=-1 +kerning first=1058 second=1111 amount=-1 +kerning first=39 second=198 amount=-1 +kerning first=902 second=86 amount=-1 +kerning first=196 second=936 amount=-1 +kerning first=321 second=8216 amount=-1 +kerning first=319 second=87 amount=-1 +kerning first=293 second=356 amount=-1 +kerning first=192 second=932 amount=-1 +kerning first=1038 second=1072 amount=-1 +kerning first=328 second=84 amount=-1 +kerning first=356 second=263 amount=-1 +kerning first=932 second=248 amount=-1 +kerning first=354 second=974 amount=-1 +kerning first=939 second=8212 amount=-1 +kerning first=354 second=249 amount=-1 +kerning first=89 second=235 amount=-1 +kerning first=331 second=932 amount=-1 +kerning first=376 second=8211 amount=-1 +kerning first=160 second=902 amount=-1 +kerning first=8217 second=8217 amount=-1 +kerning first=354 second=259 amount=-1 +kerning first=221 second=229 amount=-1 +kerning first=354 second=112 amount=-1 +kerning first=87 second=260 amount=-1 +kerning first=84 second=961 amount=-1 +kerning first=84 second=234 amount=-1 +kerning first=356 second=192 amount=-1 +kerning first=260 second=356 amount=-1 +kerning first=8217 second=291 amount=-1 +kerning first=358 second=252 amount=-1 +kerning first=39 second=194 amount=-1 +kerning first=8221 second=235 amount=-1 +kerning first=932 second=279 amount=-1 +kerning first=358 second=173 amount=-1 +kerning first=376 second=225 amount=-1 +kerning first=123 second=932 amount=1 +kerning first=1043 second=1108 amount=-1 +kerning first=354 second=923 amount=-1 +kerning first=229 second=84 amount=-1 +kerning first=358 second=111 amount=-1 +kerning first=1034 second=1063 amount=-1 +kerning first=196 second=372 amount=-1 +kerning first=197 second=8221 amount=-1 +kerning first=902 second=932 amount=-1 +kerning first=910 second=197 amount=-1 +kerning first=8216 second=248 amount=-1 +kerning first=89 second=41 amount=1 +kerning first=46 second=933 amount=-1 +kerning first=1068 second=1035 amount=-1 +kerning first=258 second=8220 amount=-1 +kerning first=939 second=193 amount=-1 +kerning first=947 second=8230 amount=-1 +kerning first=1058 second=1089 amount=-1 +kerning first=260 second=8217 amount=-1 +kerning first=1168 second=1093 amount=-1 +kerning first=354 second=326 amount=-1 +kerning first=197 second=354 amount=-1 +kerning first=969 second=39 amount=-1 +kerning first=74 second=93 amount=1 +kerning first=372 second=46 amount=-1 +kerning first=34 second=308 amount=-1 +kerning first=221 second=281 amount=-1 +kerning first=8216 second=279 amount=-1 +kerning first=356 second=234 amount=-1 +kerning first=356 second=961 amount=-1 +kerning first=1043 second=8230 amount=-1 +kerning first=97 second=358 amount=-1 +kerning first=376 second=273 amount=-1 +kerning first=221 second=125 amount=1 +kerning first=1027 second=1105 amount=-1 +kerning first=84 second=289 amount=-1 +kerning first=76 second=376 amount=-1 +kerning first=295 second=354 amount=-1 +kerning first=376 second=277 amount=-1 +kerning first=957 second=44 amount=-1 +kerning first=354 second=229 amount=-1 +kerning first=70 second=226 amount=-1 +kerning first=910 second=963 amount=-1 +kerning first=8212 second=933 amount=-1 +kerning first=1058 second=45 amount=-1 +kerning first=932 second=969 amount=-1 +kerning first=8217 second=245 amount=-1 +kerning first=916 second=932 amount=-1 +kerning first=932 second=241 amount=-1 +kerning first=306 second=41 amount=1 +kerning first=358 second=224 amount=-1 +kerning first=1043 second=1086 amount=-1 +kerning first=1056 second=1076 amount=-1 +kerning first=194 second=86 amount=-1 +kerning first=89 second=367 amount=-1 +kerning first=84 second=74 amount=-1 +kerning first=65 second=87 amount=-1 +kerning first=40 second=372 amount=1 +kerning first=8220 second=248 amount=-1 +kerning first=192 second=939 amount=-1 +kerning first=932 second=913 amount=-1 +kerning first=84 second=371 amount=-1 +kerning first=356 second=289 amount=-1 +kerning first=76 second=358 amount=-1 +kerning first=376 second=351 amount=-1 +kerning first=317 second=8211 amount=-1 +kerning first=259 second=932 amount=-1 +kerning first=358 second=339 amount=-1 +kerning first=372 second=198 amount=-1 +kerning first=89 second=250 amount=-1 +kerning first=241 second=354 amount=-1 +kerning first=932 second=258 amount=-1 +kerning first=915 second=962 amount=-1 +kerning first=87 second=197 amount=-1 +kerning first=319 second=45 amount=-1 +kerning first=354 second=281 amount=-1 +kerning first=8216 second=969 amount=-1 +kerning first=1168 second=1072 amount=-1 +kerning first=8220 second=279 amount=-1 +kerning first=160 second=221 amount=-1 +kerning first=221 second=244 amount=-1 +kerning first=354 second=125 amount=1 +kerning first=8204 second=8218 amount=-1 +kerning first=932 second=307 amount=-1 +kerning first=1058 second=8212 amount=-1 +kerning first=84 second=353 amount=-1 +kerning first=358 second=312 amount=-1 +kerning first=376 second=239 amount=1 +kerning first=1027 second=1083 amount=-1 +kerning first=8211 second=932 amount=-1 +kerning first=358 second=275 amount=-1 +kerning first=39 second=308 amount=-1 +kerning first=193 second=936 amount=-1 +kerning first=356 second=74 amount=-1 +kerning first=317 second=87 amount=-1 +kerning first=376 second=100 amount=-1 +kerning first=8216 second=913 amount=-1 +kerning first=902 second=939 amount=-1 +kerning first=194 second=932 amount=-1 +kerning first=915 second=256 amount=-1 +kerning first=86 second=239 amount=1 +kerning first=356 second=371 amount=-1 +kerning first=65 second=933 amount=-1 +kerning first=8216 second=258 amount=-1 +kerning first=221 second=260 amount=-1 +kerning first=1058 second=1102 amount=-1 +kerning first=372 second=194 amount=-1 +kerning first=8216 second=1035 amount=1 +kerning first=1168 second=1107 amount=-1 +kerning first=376 second=45 amount=-1 +kerning first=356 second=353 amount=-1 +kerning first=221 second=8249 amount=-1 +kerning first=8216 second=8220 amount=-1 +kerning first=1027 second=1119 amount=-1 +kerning first=258 second=356 amount=-1 +kerning first=257 second=354 amount=-1 +kerning first=319 second=8212 amount=-1 +kerning first=354 second=940 amount=-1 +kerning first=8220 second=969 amount=-1 +kerning first=1058 second=58 amount=-1 +kerning first=84 second=8211 amount=-1 +kerning first=354 second=244 amount=-1 +kerning first=89 second=226 amount=-1 +kerning first=910 second=972 amount=-1 +kerning first=228 second=84 amount=-1 +kerning first=80 second=256 amount=-1 +kerning first=196 second=8221 amount=-1 +kerning first=193 second=372 amount=-1 +kerning first=1026 second=1066 amount=-1 +kerning first=916 second=939 amount=-1 +kerning first=932 second=382 amount=-1 +kerning first=939 second=941 amount=-1 +kerning first=358 second=962 amount=-1 +kerning first=84 second=225 amount=-1 +kerning first=87 second=41 amount=1 +kerning first=8217 second=271 amount=-1 +kerning first=1033 second=1059 amount=-1 +kerning first=358 second=243 amount=-1 +kerning first=44 second=933 amount=-1 +kerning first=1043 second=1099 amount=-1 +kerning first=1168 second=187 amount=-1 +kerning first=1066 second=1035 amount=-1 +kerning first=260 second=86 amount=-1 +kerning first=8230 second=39 amount=-1 +kerning first=271 second=322 amount=1 +kerning first=932 second=115 amount=-1 +kerning first=936 second=65 amount=-1 +kerning first=8220 second=913 amount=-1 +kerning first=258 second=8217 amount=-1 +kerning first=933 second=173 amount=-1 +kerning first=187 second=221 amount=-1 +kerning first=358 second=103 amount=-1 +kerning first=372 second=93 amount=1 +kerning first=196 second=354 amount=-1 +kerning first=354 second=260 amount=-1 +kerning first=1114 second=8221 amount=-1 +kerning first=8220 second=258 amount=-1 +kerning first=187 second=84 amount=-1 +kerning first=70 second=46 amount=-1 +kerning first=932 second=196 amount=-1 +kerning first=939 second=916 amount=-1 +kerning first=1068 second=8217 amount=-1 +kerning first=8220 second=1035 amount=1 +kerning first=84 second=305 amount=-1 +kerning first=293 second=932 amount=-1 +kerning first=356 second=8211 amount=-1 +kerning first=1058 second=1081 amount=-1 +kerning first=1043 second=1044 amount=-1 +kerning first=376 second=8212 amount=-1 +kerning first=8217 second=65 amount=-1 +kerning first=913 second=936 amount=-1 +kerning first=1168 second=1085 amount=-1 +kerning first=89 second=283 amount=-1 +kerning first=358 second=256 amount=-1 +kerning first=354 second=8249 amount=-1 +kerning first=1059 second=1077 amount=-1 +kerning first=8220 second=8220 amount=-1 +kerning first=197 second=87 amount=-1 +kerning first=221 second=269 amount=-1 +kerning first=84 second=273 amount=-1 +kerning first=8217 second=347 amount=-1 +kerning first=356 second=225 amount=-1 +kerning first=221 second=117 amount=-1 +kerning first=932 second=333 amount=-1 +kerning first=1027 second=1096 amount=-1 +kerning first=8211 second=939 amount=-1 +kerning first=84 second=277 amount=-1 +kerning first=8221 second=283 amount=-1 +kerning first=256 second=936 amount=-1 +kerning first=354 second=948 amount=-1 +kerning first=376 second=257 amount=-1 +kerning first=358 second=171 amount=-1 +kerning first=376 second=113 amount=-1 +kerning first=915 second=192 amount=-1 +kerning first=260 second=932 amount=-1 +kerning first=8216 second=196 amount=-1 +kerning first=345 second=44 amount=-1 +kerning first=221 second=197 amount=-1 +kerning first=194 second=939 amount=-1 +kerning first=932 second=959 amount=-1 +kerning first=315 second=8216 amount=-1 +kerning first=171 second=910 amount=-1 +kerning first=939 second=949 amount=-1 +kerning first=932 second=233 amount=-1 +kerning first=929 second=913 amount=-1 +kerning first=356 second=305 amount=-1 +kerning first=1033 second=1038 amount=-1 +kerning first=1058 second=1116 amount=-1 +kerning first=376 second=193 amount=-1 +kerning first=8217 second=99 amount=-1 +kerning first=1043 second=1078 amount=-1 +kerning first=1168 second=1169 amount=-1 +kerning first=89 second=349 amount=-1 +kerning first=929 second=258 amount=-1 +kerning first=936 second=44 amount=-1 +kerning first=317 second=45 amount=-1 +kerning first=40 second=354 amount=1 +kerning first=70 second=198 amount=-1 +kerning first=8216 second=333 amount=-1 +kerning first=913 second=372 amount=-1 +kerning first=356 second=273 amount=-1 +kerning first=1038 second=1077 amount=-1 +kerning first=86 second=193 amount=-1 +kerning first=84 second=351 amount=-1 +kerning first=356 second=277 amount=-1 +kerning first=8221 second=349 amount=-1 +kerning first=80 second=192 amount=-1 +kerning first=376 second=335 amount=-1 +kerning first=76 second=173 amount=-1 +kerning first=197 second=933 amount=-1 +kerning first=915 second=961 amount=-1 +kerning first=1058 second=1060 amount=-1 +kerning first=8217 second=44 amount=-2 +kerning first=8216 second=959 amount=-1 +kerning first=256 second=372 amount=-1 +kerning first=354 second=269 amount=-1 +kerning first=70 second=261 amount=-1 +kerning first=8216 second=233 amount=-1 +kerning first=221 second=235 amount=-1 +kerning first=354 second=117 amount=-1 +kerning first=89 second=101 amount=-1 +kerning first=1091 second=44 amount=-1 +kerning first=84 second=239 amount=-1 +kerning first=932 second=291 amount=-1 +kerning first=376 second=227 amount=-1 +kerning first=1043 second=1113 amount=-1 +kerning first=321 second=39 amount=-1 +kerning first=109 second=84 amount=-1 +kerning first=923 second=221 amount=-1 +kerning first=1027 second=1075 amount=-1 +kerning first=358 second=263 amount=-1 +kerning first=84 second=100 amount=-1 +kerning first=8221 second=101 amount=-1 +kerning first=354 second=197 amount=-1 +kerning first=70 second=194 amount=-1 +kerning first=8220 second=196 amount=-1 +kerning first=8204 second=376 amount=-1 +kerning first=923 second=84 amount=-1 +kerning first=89 second=46 amount=-1 +kerning first=308 second=125 amount=1 +kerning first=356 second=351 amount=-1 +kerning first=939 second=195 amount=-1 +kerning first=317 second=8212 amount=-1 +kerning first=1058 second=1094 amount=-1 +kerning first=358 second=192 amount=-1 +kerning first=221 second=41 amount=1 +kerning first=1168 second=1098 amount=-1 +kerning first=354 second=341 amount=-1 +kerning first=8220 second=333 amount=-1 +kerning first=225 second=84 amount=-1 +kerning first=84 second=45 amount=-1 +kerning first=8221 second=46 amount=-2 +kerning first=193 second=8221 amount=-1 +kerning first=102 second=125 amount=1 +kerning first=8216 second=291 amount=-1 +kerning first=356 second=239 amount=-1 +kerning first=932 second=363 amount=-1 +kerning first=84 second=303 amount=-1 +kerning first=354 second=963 amount=-1 +kerning first=195 second=8216 amount=-1 +kerning first=258 second=86 amount=-1 +kerning first=8220 second=959 amount=-1 +kerning first=356 second=100 amount=-1 +kerning first=227 second=358 amount=-1 +kerning first=354 second=235 amount=-1 +kerning first=939 second=8230 amount=-1 +kerning first=8220 second=233 amount=-1 +kerning first=8222 second=221 amount=-1 +kerning first=260 second=939 amount=-1 +kerning first=193 second=354 amount=-1 +kerning first=936 second=923 amount=-1 +kerning first=965 second=39 amount=-1 +kerning first=1026 second=1058 amount=-1 +kerning first=8217 second=160 amount=-1 +kerning first=932 second=245 amount=-1 +kerning first=1059 second=46 amount=-1 +kerning first=358 second=961 amount=-1 +kerning first=1058 second=8250 amount=-1 +kerning first=8222 second=84 amount=-1 +kerning first=1066 second=8217 amount=-1 +kerning first=358 second=234 amount=-1 +kerning first=929 second=196 amount=-1 +kerning first=933 second=962 amount=-1 +kerning first=1043 second=1091 amount=-1 +kerning first=356 second=45 amount=-1 +kerning first=89 second=198 amount=-1 +kerning first=968 second=34 amount=-1 +kerning first=221 second=367 amount=-1 +kerning first=8217 second=923 amount=-1 +kerning first=196 second=87 amount=-1 +kerning first=354 second=41 amount=1 +kerning first=356 second=303 amount=-1 +kerning first=84 second=8212 amount=-1 +kerning first=915 second=970 amount=-1 +kerning first=376 second=365 amount=-1 +kerning first=8221 second=198 amount=-1 +kerning first=910 second=46 amount=-1 +kerning first=1168 second=1077 amount=-1 +kerning first=89 second=261 amount=-1 +kerning first=8216 second=245 amount=-1 +kerning first=8220 second=291 amount=-1 +kerning first=80 second=74 amount=-1 +kerning first=326 second=356 amount=-1 +kerning first=221 second=250 amount=-1 +kerning first=258 second=932 amount=-1 +kerning first=933 second=256 amount=-1 +kerning first=1038 second=46 amount=-1 +kerning first=313 second=8216 amount=-1 +kerning first=160 second=89 amount=-1 +kerning first=376 second=246 amount=-1 +kerning first=1027 second=1088 amount=-1 +kerning first=84 second=257 amount=-1 +kerning first=358 second=289 amount=-1 +kerning first=84 second=113 amount=-1 +kerning first=89 second=194 amount=-1 +kerning first=910 second=945 amount=-1 +kerning first=934 second=44 amount=-1 +kerning first=91 second=106 amount=1 +kerning first=70 second=308 amount=-1 +kerning first=913 second=8221 amount=-1 +kerning first=91 second=1095 amount=-1 +kerning first=319 second=221 amount=-1 +kerning first=1040 second=1026 amount=-1 +kerning first=84 second=193 amount=-1 +kerning first=8221 second=194 amount=-1 +kerning first=356 second=8212 amount=-1 +kerning first=1058 second=1108 amount=-1 +kerning first=1027 second=44 amount=-1 +kerning first=1027 second=1032 amount=-1 +kerning first=196 second=933 amount=-1 +kerning first=319 second=84 amount=-1 +kerning first=354 second=367 amount=-1 +kerning first=89 second=337 amount=-1 +kerning first=256 second=8221 amount=-1 +kerning first=358 second=74 amount=-1 +kerning first=915 second=8211 amount=-1 +kerning first=913 second=354 amount=-1 +kerning first=40 second=87 amount=1 +kerning first=934 second=939 amount=-1 +kerning first=910 second=198 amount=-1 +kerning first=84 second=335 amount=-1 +kerning first=356 second=257 amount=-1 +kerning first=8221 second=337 amount=-1 +kerning first=932 second=230 amount=-1 +kerning first=358 second=371 amount=-1 +kerning first=354 second=972 amount=-1 +kerning first=356 second=113 amount=-1 +kerning first=354 second=250 amount=-1 +kerning first=89 second=231 amount=-1 +kerning first=8220 second=245 amount=-1 +kerning first=76 second=372 amount=-1 +kerning first=8212 second=221 amount=-1 +kerning first=256 second=354 amount=-1 +kerning first=1061 second=1095 amount=-1 +kerning first=221 second=226 amount=-1 +kerning first=354 second=109 amount=-1 +kerning first=324 second=358 amount=-1 +kerning first=89 second=93 amount=1 +kerning first=8212 second=84 amount=-1 +kerning first=1058 second=8230 amount=-1 +kerning first=84 second=227 amount=-1 +kerning first=904 second=912 amount=1 +kerning first=356 second=193 amount=-1 +kerning first=87 second=46 amount=-1 +kerning first=358 second=353 amount=-1 +kerning first=8217 second=281 amount=-1 +kerning first=8221 second=231 amount=-1 +kerning first=1043 second=1105 amount=-1 +kerning first=932 second=271 amount=-1 +kerning first=1169 second=8230 amount=-1 +kerning first=910 second=194 amount=-1 +kerning first=187 second=89 amount=-1 +kerning first=356 second=335 amount=-1 +kerning first=8250 second=354 amount=-1 +kerning first=1058 second=1086 amount=-1 +kerning first=192 second=8216 amount=-1 +kerning first=224 second=358 amount=-1 +kerning first=1168 second=1090 amount=-1 +kerning first=932 second=65 amount=-1 +kerning first=354 second=324 amount=-1 +kerning first=933 second=192 amount=-1 +kerning first=258 second=939 amount=-1 +kerning first=1040 second=1095 amount=-1 +kerning first=306 second=93 amount=1 +kerning first=8216 second=271 amount=-1 +kerning first=221 second=283 amount=-1 +kerning first=356 second=227 amount=-1 +kerning first=932 second=347 amount=-1 +kerning first=1027 second=1101 amount=-1 +kerning first=917 second=912 amount=1 +kerning first=84 second=287 amount=-1 +kerning first=8221 second=285 amount=-1 +kerning first=91 second=358 amount=1 +kerning first=372 second=301 amount=1 +kerning first=376 second=265 amount=-1 +kerning first=354 second=226 amount=-1 +kerning first=358 second=8211 amount=-1 +kerning first=1168 second=46 amount=-1 +kerning first=87 second=198 amount=-1 +kerning first=89 second=308 amount=-1 +kerning first=932 second=966 amount=-1 +kerning first=8217 second=244 amount=-1 +kerning first=1059 second=1026 amount=1 +kerning first=193 second=87 amount=-1 +kerning first=932 second=238 amount=-1 +kerning first=65 second=221 amount=-1 +kerning first=358 second=225 amount=-1 +kerning first=902 second=8216 amount=-1 +kerning first=376 second=195 amount=-1 +kerning first=8216 second=65 amount=-1 +kerning first=936 second=260 amount=-1 +kerning first=933 second=961 amount=-1 +kerning first=8221 second=308 amount=-1 +kerning first=8249 second=939 amount=-1 +kerning first=932 second=99 amount=-1 +kerning first=89 second=369 amount=-1 +kerning first=329 second=84 amount=-1 +kerning first=1041 second=1035 amount=-1 +kerning first=1043 second=1083 amount=-1 +kerning first=65 second=84 amount=-1 +kerning first=328 second=356 amount=-1 +kerning first=221 second=349 amount=-1 +kerning first=160 second=8220 amount=-1 +kerning first=86 second=195 amount=-1 +kerning first=84 second=365 amount=-1 +kerning first=356 second=287 amount=-1 +kerning first=173 second=376 amount=-1 +kerning first=8217 second=260 amount=-1 +kerning first=354 second=331 amount=-1 +kerning first=358 second=305 amount=-1 +kerning first=89 second=242 amount=-1 +kerning first=376 second=8230 amount=-1 +kerning first=8216 second=966 amount=-1 +kerning first=87 second=194 amount=-1 +kerning first=354 second=283 amount=-1 +kerning first=932 second=44 amount=-1 +kerning first=8220 second=271 amount=-1 +kerning first=354 second=122 amount=-1 +kerning first=315 second=39 amount=-1 +kerning first=84 second=941 amount=-1 +kerning first=102 second=8216 amount=1 +kerning first=34 second=256 amount=-1 +kerning first=84 second=246 amount=-1 +kerning first=8221 second=242 amount=-1 +kerning first=317 second=221 amount=-1 +kerning first=1038 second=1026 amount=1 +kerning first=358 second=273 amount=-1 +kerning first=8216 second=99 amount=-1 +kerning first=221 second=101 amount=-1 +kerning first=932 second=299 amount=-1 +kerning first=376 second=232 amount=-1 +kerning first=308 second=41 amount=1 +kerning first=86 second=8230 amount=-1 +kerning first=1027 second=1080 amount=-1 +kerning first=1043 second=1119 amount=-1 +kerning first=229 second=356 amount=-1 +kerning first=358 second=277 amount=-1 +kerning first=97 second=354 amount=-1 +kerning first=84 second=105 amount=-1 +kerning first=317 second=84 amount=-1 +kerning first=193 second=933 amount=-1 +kerning first=376 second=97 amount=-1 +kerning first=1111 second=1115 amount=1 +kerning first=923 second=89 amount=-1 +kerning first=321 second=376 amount=-1 +kerning first=8220 second=65 amount=-1 +kerning first=356 second=365 amount=-1 +kerning first=84 second=916 amount=-1 +kerning first=173 second=358 amount=-1 +kerning first=102 second=41 amount=1 +kerning first=915 second=45 amount=-1 +kerning first=1058 second=1099 amount=-1 +kerning first=271 second=316 amount=1 +kerning first=221 second=46 amount=-1 +kerning first=8216 second=44 amount=-1 +kerning first=8216 second=1032 amount=-1 +kerning first=1168 second=1103 amount=-1 +kerning first=354 second=349 amount=-1 +kerning first=76 second=8221 amount=-1 +kerning first=356 second=941 amount=-1 +kerning first=923 second=34 amount=-1 +kerning first=356 second=246 amount=-1 +kerning first=87 second=93 amount=1 +kerning first=913 second=87 amount=-1 +kerning first=1056 second=8230 amount=-2 +kerning first=110 second=358 amount=-1 +kerning first=358 second=351 amount=-1 +kerning first=326 second=932 amount=-1 +kerning first=8220 second=966 amount=-1 +kerning first=356 second=105 amount=-1 +kerning first=354 second=236 amount=-1 +kerning first=1058 second=1044 amount=-1 +kerning first=1168 second=59 amount=-1 +kerning first=76 second=354 amount=-1 +kerning first=256 second=87 amount=-1 +kerning first=932 second=974 amount=-1 +kerning first=321 second=358 amount=-1 +kerning first=354 second=101 amount=-1 +kerning first=8220 second=99 amount=-1 +kerning first=356 second=916 amount=-1 +kerning first=932 second=249 amount=-1 +kerning first=84 second=949 amount=-1 +kerning first=936 second=197 amount=-1 +kerning first=1026 second=1063 amount=-1 +kerning first=1059 second=1040 amount=-1 +kerning first=8222 second=89 amount=-1 +kerning first=8217 second=269 amount=-1 +kerning first=358 second=239 amount=-1 +kerning first=932 second=259 amount=-1 +kerning first=933 second=970 amount=1 +kerning first=1043 second=1096 amount=-1 +kerning first=194 second=8216 amount=-1 +kerning first=932 second=112 amount=-1 +kerning first=39 second=256 amount=-1 +kerning first=226 second=358 amount=-1 +kerning first=358 second=100 amount=-1 +kerning first=929 second=65 amount=-1 +kerning first=915 second=8212 amount=-1 +kerning first=221 second=198 amount=-1 +kerning first=160 second=8222 amount=-1 +kerning first=932 second=923 amount=-1 +kerning first=8217 second=197 amount=-1 +kerning first=354 second=46 amount=-1 +kerning first=84 second=378 amount=-1 +kerning first=8220 second=44 amount=-1 +kerning first=939 second=913 amount=-1 +kerning first=195 second=39 amount=-1 +kerning first=8220 second=1032 amount=-1 +kerning first=915 second=912 amount=-1 +kerning first=376 second=361 amount=-1 +kerning first=1058 second=1078 amount=-1 +kerning first=197 second=221 amount=-1 +kerning first=913 second=933 amount=-1 +kerning first=8216 second=974 amount=-1 +kerning first=1168 second=1082 amount=-1 +kerning first=939 second=258 amount=-1 +kerning first=354 second=297 amount=-1 +kerning first=89 second=267 amount=-1 +kerning first=1118 second=46 amount=-1 +kerning first=34 second=192 amount=-1 +kerning first=358 second=45 amount=-1 +kerning first=356 second=949 amount=-1 +kerning first=197 second=84 amount=-1 +kerning first=221 second=261 amount=-1 +kerning first=1038 second=1040 amount=-1 +kerning first=932 second=326 amount=-1 +kerning first=376 second=251 amount=-1 +kerning first=1027 second=1093 amount=-1 +kerning first=84 second=265 amount=-1 +kerning first=8221 second=267 amount=-1 +kerning first=358 second=303 amount=-1 +kerning first=256 second=933 amount=-1 +kerning first=354 second=945 amount=-1 +kerning first=295 second=84 amount=-1 +kerning first=8216 second=923 amount=-1 +kerning first=915 second=193 amount=-1 +kerning first=1168 second=1026 amount=1 +kerning first=933 second=8211 amount=-1 +kerning first=221 second=194 amount=-1 +kerning first=8217 second=235 amount=-1 +kerning first=356 second=378 amount=-1 +kerning first=1107 second=44 amount=-1 +kerning first=932 second=229 amount=-1 +kerning first=915 second=58 amount=-1 +kerning first=1068 second=1059 amount=-1 +kerning first=84 second=195 amount=-1 +kerning first=1058 second=1113 amount=-1 +kerning first=1043 second=1075 amount=-1 +kerning first=34 second=961 amount=-1 +kerning first=1168 second=1118 amount=-1 +kerning first=319 second=89 amount=-1 +kerning first=354 second=198 amount=-1 +kerning first=929 second=44 amount=-2 +kerning first=221 second=337 amount=-1 +kerning first=313 second=39 amount=-1 +kerning first=1075 second=8230 amount=-1 +kerning first=173 second=910 amount=-1 +kerning first=84 second=345 amount=-1 +kerning first=356 second=265 amount=-1 +kerning first=1035 second=1026 amount=-1 +kerning first=80 second=193 amount=-1 +kerning first=84 second=8230 amount=-1 +kerning first=8220 second=974 amount=-1 +kerning first=228 second=356 amount=-1 +kerning first=358 second=8212 amount=-1 +kerning first=923 second=8220 amount=-1 +kerning first=319 second=34 amount=-1 +kerning first=271 second=98 amount=1 +kerning first=354 second=261 amount=-1 +kerning first=241 second=84 amount=-1 +kerning first=221 second=231 amount=-1 +kerning first=46 second=34 amount=-1 +kerning first=354 second=114 amount=-1 +kerning first=1040 second=1066 amount=-1 +kerning first=8212 second=89 amount=-1 +kerning first=84 second=232 amount=-1 +kerning first=356 second=195 amount=-1 +kerning first=39 second=192 amount=-1 +kerning first=221 second=93 amount=1 +kerning first=932 second=281 amount=-1 +kerning first=376 second=228 amount=-1 +kerning first=1027 second=1072 amount=-1 +kerning first=260 second=8216 amount=-1 +kerning first=932 second=125 amount=1 +kerning first=358 second=257 amount=-1 +kerning first=8220 second=923 amount=-1 +kerning first=84 second=97 amount=-1 +kerning first=354 second=194 amount=-1 +kerning first=358 second=113 amount=-1 +kerning first=187 second=356 amount=-1 +kerning first=1057 second=1095 amount=-1 +kerning first=356 second=345 amount=-1 +kerning first=1068 second=1038 amount=-1 +kerning first=935 second=912 amount=1 +kerning first=356 second=8230 amount=-1 +kerning first=939 second=196 amount=-1 +kerning first=1058 second=1091 amount=-1 +kerning first=358 second=193 amount=-1 +kerning first=328 second=932 amount=-1 +kerning first=376 second=248 amount=-1 +kerning first=1056 second=1044 amount=-1 +kerning first=1168 second=1095 amount=-1 +kerning first=354 second=337 amount=-1 +kerning first=76 second=8211 amount=-1 +kerning first=372 second=256 amount=-1 +kerning first=1113 second=1098 amount=-1 diff --git a/assets/style/myriad-medium.fnt b/assets/style/myriad-medium.fnt new file mode 100644 index 00000000..7e302b2b --- /dev/null +++ b/assets/style/myriad-medium.fnt @@ -0,0 +1,3951 @@ +info face="MyriadPro-Regular" size=14 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=1,1,1,1 spacing=-2,-2 +common lineHeight=18 base=11 scaleW=128 scaleH=512 pages=1 packed=0 +page id=0 file="myriad-medium.png" +chars count=506 +char id=0 x=9 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=13 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=0 page=0 chnl=0 +char id=33 x=121 y=121 width=5 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=34 x=81 y=425 width=7 height=6 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=35 x=18 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=36 x=110 y=0 width=9 height=15 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=37 x=27 y=162 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=38 x=40 y=162 width=11 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=39 x=88 y=425 width=4 height=6 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=40 x=115 y=92 width=6 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=41 x=121 y=92 width=6 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=42 x=12 y=425 width=8 height=7 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=43 x=110 y=367 width=10 height=10 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=44 x=20 y=425 width=5 height=7 xoffset=-1 yoffset=8 xadvance=3 page=0 chnl=0 +char id=45 x=75 y=433 width=6 height=3 xoffset=-1 yoffset=6 xadvance=4 page=0 chnl=0 +char id=46 x=39 y=433 width=5 height=4 xoffset=-1 yoffset=8 xadvance=3 page=0 chnl=0 +char id=47 x=105 y=135 width=8 height=13 xoffset=-2 yoffset=0 xadvance=5 page=0 chnl=0 +char id=48 x=51 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=49 x=60 y=162 width=6 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=50 x=66 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=51 x=75 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=52 x=84 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=53 x=93 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=54 x=102 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=55 x=111 y=162 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=56 x=0 y=175 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=57 x=113 y=135 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=58 x=120 y=367 width=5 height=9 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=59 x=120 y=162 width=5 height=12 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=60 x=32 y=379 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=61 x=92 y=425 width=10 height=6 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=0 +char id=62 x=42 y=379 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=63 x=9 y=175 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=64 x=17 y=175 width=12 height=12 xoffset=-1 yoffset=2 xadvance=10 page=0 chnl=0 +char id=65 x=29 y=175 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=66 x=40 y=175 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=67 x=49 y=175 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=68 x=59 y=175 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=69 x=69 y=175 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=70 x=77 y=175 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=71 x=85 y=175 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=72 x=96 y=175 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=73 x=122 y=135 width=4 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=74 x=106 y=175 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=75 x=113 y=175 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=76 x=0 y=187 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=77 x=8 y=187 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=78 x=21 y=187 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=79 x=31 y=187 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=80 x=43 y=187 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=81 x=0 y=107 width=12 height=14 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=82 x=51 y=187 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=83 x=60 y=187 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=84 x=69 y=187 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=85 x=79 y=187 width=9 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=86 x=88 y=187 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=87 x=98 y=187 width=14 height=12 xoffset=-1 yoffset=0 xadvance=12 page=0 chnl=0 +char id=88 x=112 y=187 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=89 x=0 y=199 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=90 x=10 y=199 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=91 x=12 y=107 width=5 height=14 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=92 x=0 y=149 width=7 height=13 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=93 x=17 y=107 width=5 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=94 x=52 y=379 width=10 height=9 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=95 x=81 y=433 width=9 height=3 xoffset=-1 yoffset=11 xadvance=7 page=0 chnl=0 +char id=96 x=121 y=425 width=5 height=5 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=97 x=62 y=379 width=8 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=98 x=20 y=199 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=99 x=70 y=379 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=100 x=30 y=199 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=101 x=78 y=379 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=102 x=39 y=199 width=7 height=12 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=103 x=46 y=199 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=104 x=55 y=199 width=8 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=105 x=122 y=175 width=5 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=106 x=119 y=0 width=6 height=15 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=107 x=63 y=199 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=108 x=122 y=187 width=4 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=109 x=87 y=379 width=13 height=9 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=110 x=100 y=379 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=111 x=109 y=379 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=112 x=71 y=199 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=113 x=81 y=199 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=114 x=119 y=379 width=7 height=9 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=115 x=0 y=389 width=7 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=116 x=18 y=367 width=7 height=11 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=117 x=7 y=389 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=118 x=16 y=389 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=119 x=25 y=389 width=13 height=9 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=120 x=38 y=389 width=9 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=121 x=22 y=107 width=9 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=122 x=47 y=389 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=123 x=31 y=107 width=6 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=124 x=0 y=0 width=4 height=17 xoffset=0 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=125 x=37 y=107 width=6 height=14 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=126 x=0 y=433 width=10 height=5 xoffset=-1 yoffset=5 xadvance=8 page=0 chnl=0 +char id=160 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=161 x=90 y=199 width=5 height=12 xoffset=-1 yoffset=3 xadvance=3 page=0 chnl=0 +char id=162 x=7 y=149 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=163 x=95 y=199 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=164 x=0 y=379 width=9 height=10 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=165 x=104 y=199 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=166 x=43 y=107 width=4 height=14 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=167 x=16 y=149 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=168 x=44 y=433 width=7 height=4 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=169 x=25 y=367 width=11 height=11 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=0 +char id=170 x=25 y=425 width=7 height=7 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=171 x=94 y=416 width=8 height=8 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=172 x=32 y=425 width=10 height=7 xoffset=-1 yoffset=4 xadvance=8 page=0 chnl=0 +char id=173 x=90 y=433 width=6 height=3 xoffset=-1 yoffset=6 xadvance=4 page=0 chnl=0 +char id=174 x=42 y=425 width=8 height=7 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=175 x=96 y=433 width=6 height=3 xoffset=-1 yoffset=1 xadvance=4 page=0 chnl=0 +char id=176 x=102 y=425 width=7 height=6 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=177 x=9 y=379 width=10 height=10 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=178 x=102 y=416 width=6 height=8 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=179 x=108 y=416 width=6 height=8 xoffset=-1 yoffset=-2 xadvance=4 page=0 chnl=0 +char id=180 x=10 y=433 width=5 height=5 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=181 x=113 y=199 width=9 height=12 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=182 x=47 y=107 width=8 height=14 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=183 x=51 y=433 width=5 height=4 xoffset=-1 yoffset=5 xadvance=3 page=0 chnl=0 +char id=184 x=15 y=433 width=6 height=5 xoffset=-1 yoffset=10 xadvance=4 page=0 chnl=0 +char id=185 x=114 y=416 width=5 height=8 xoffset=-1 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=186 x=50 y=425 width=7 height=7 xoffset=-1 yoffset=2 xadvance=5 page=0 chnl=0 +char id=187 x=119 y=416 width=8 height=8 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=188 x=0 y=211 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=189 x=13 y=211 width=12 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=190 x=25 y=211 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=191 x=38 y=211 width=8 height=12 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=192 x=0 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=193 x=11 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=194 x=22 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=195 x=33 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=196 x=55 y=107 width=11 height=14 xoffset=-1 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=197 x=44 y=17 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=198 x=46 y=211 width=14 height=12 xoffset=-2 yoffset=0 xadvance=11 page=0 chnl=0 +char id=199 x=55 y=17 width=10 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=200 x=65 y=17 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=201 x=73 y=17 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=202 x=81 y=17 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=203 x=66 y=107 width=8 height=14 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=204 x=89 y=17 width=6 height=15 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=205 x=95 y=17 width=6 height=15 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=206 x=101 y=17 width=7 height=15 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=207 x=74 y=107 width=7 height=14 xoffset=-2 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=208 x=60 y=211 width=12 height=12 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=209 x=108 y=17 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=210 x=0 y=32 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=211 x=12 y=32 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=212 x=81 y=107 width=12 height=14 xoffset=-1 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=213 x=24 y=32 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=214 x=93 y=107 width=12 height=14 xoffset=-1 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=215 x=55 y=389 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=216 x=25 y=149 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=217 x=118 y=17 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=218 x=36 y=32 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=219 x=45 y=32 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=220 x=105 y=107 width=9 height=14 xoffset=0 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=221 x=54 y=32 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=222 x=72 y=211 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=223 x=80 y=211 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=224 x=89 y=211 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=225 x=97 y=211 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=226 x=105 y=211 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=227 x=113 y=211 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=228 x=0 y=223 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=229 x=8 y=223 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=230 x=65 y=389 width=13 height=9 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=231 x=16 y=223 width=8 height=12 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=232 x=24 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=233 x=33 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=234 x=42 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=235 x=51 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=236 x=121 y=211 width=6 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=237 x=60 y=223 width=6 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=238 x=66 y=223 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=239 x=73 y=223 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=240 x=80 y=223 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=241 x=90 y=223 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=242 x=99 y=223 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=243 x=109 y=223 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=244 x=0 y=235 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=245 x=10 y=235 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=246 x=20 y=235 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=247 x=78 y=389 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=248 x=36 y=367 width=10 height=11 xoffset=-1 yoffset=2 xadvance=8 page=0 chnl=0 +char id=249 x=30 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=250 x=39 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=251 x=48 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=252 x=57 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=253 x=4 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=254 x=64 y=32 width=9 height=15 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=255 x=13 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=256 x=114 y=107 width=11 height=14 xoffset=-1 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=257 x=46 y=367 width=8 height=11 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=258 x=73 y=32 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=259 x=119 y=223 width=8 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=260 x=84 y=32 width=11 height=15 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=261 x=66 y=235 width=9 height=12 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=262 x=95 y=32 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=263 x=75 y=235 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=264 x=105 y=32 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=265 x=83 y=235 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=266 x=0 y=121 width=10 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=267 x=91 y=235 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=268 x=10 y=121 width=10 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=269 x=99 y=235 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=270 x=115 y=32 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=271 x=107 y=235 width=11 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=272 x=0 y=247 width=12 height=12 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=273 x=12 y=247 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=274 x=20 y=121 width=8 height=14 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=275 x=54 y=367 width=9 height=11 xoffset=-1 yoffset=1 xadvance=7 page=0 chnl=0 +char id=276 x=0 y=47 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=277 x=118 y=235 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=278 x=28 y=121 width=8 height=14 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=279 x=22 y=247 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=280 x=8 y=47 width=8 height=15 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=281 x=31 y=247 width=9 height=12 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=282 x=16 y=47 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=283 x=40 y=247 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=284 x=24 y=47 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=285 x=35 y=47 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=286 x=44 y=47 width=11 height=15 xoffset=-1 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=287 x=55 y=47 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=288 x=36 y=121 width=11 height=14 xoffset=-1 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=289 x=64 y=47 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=290 x=40 y=0 width=11 height=16 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=291 x=73 y=47 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=292 x=82 y=47 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=293 x=47 y=121 width=10 height=14 xoffset=-2 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=294 x=49 y=247 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=295 x=60 y=247 width=10 height=12 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=296 x=92 y=47 width=7 height=15 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=297 x=70 y=247 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=298 x=57 y=121 width=6 height=14 xoffset=-1 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=299 x=121 y=307 width=6 height=11 xoffset=-1 yoffset=1 xadvance=3 page=0 chnl=0 +char id=300 x=99 y=47 width=7 height=15 xoffset=-2 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=301 x=77 y=247 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=302 x=106 y=47 width=5 height=15 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=303 x=111 y=47 width=5 height=15 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=304 x=63 y=121 width=5 height=14 xoffset=-1 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=305 x=123 y=331 width=4 height=9 xoffset=0 yoffset=3 xadvance=3 page=0 chnl=0 +char id=306 x=84 y=247 width=9 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=307 x=116 y=47 width=8 height=15 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=308 x=0 y=62 width=8 height=15 xoffset=-1 yoffset=-3 xadvance=5 page=0 chnl=0 +char id=309 x=8 y=62 width=7 height=15 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=310 x=51 y=0 width=9 height=16 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=311 x=60 y=0 width=8 height=16 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=312 x=88 y=389 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=313 x=15 y=62 width=8 height=15 xoffset=0 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=314 x=23 y=62 width=6 height=15 xoffset=-1 yoffset=-3 xadvance=3 page=0 chnl=0 +char id=315 x=68 y=0 width=8 height=16 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=316 x=76 y=0 width=5 height=16 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=317 x=93 y=247 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=318 x=101 y=247 width=7 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=319 x=108 y=247 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=320 x=116 y=247 width=6 height=12 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=321 x=0 y=259 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=322 x=10 y=259 width=6 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=323 x=29 y=62 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=324 x=16 y=259 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=325 x=81 y=0 width=10 height=16 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=326 x=37 y=149 width=9 height=13 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=327 x=39 y=62 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=328 x=25 y=259 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=329 x=46 y=149 width=9 height=13 xoffset=-1 yoffset=-1 xadvance=8 page=0 chnl=0 +char id=330 x=49 y=62 width=10 height=15 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=331 x=34 y=259 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=332 x=68 y=121 width=12 height=14 xoffset=-1 yoffset=-2 xadvance=10 page=0 chnl=0 +char id=333 x=63 y=367 width=10 height=11 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=334 x=59 y=62 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=335 x=43 y=259 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=336 x=71 y=62 width=12 height=15 xoffset=-1 yoffset=-3 xadvance=10 page=0 chnl=0 +char id=337 x=53 y=259 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=338 x=80 y=121 width=14 height=14 xoffset=-1 yoffset=-1 xadvance=13 page=0 chnl=0 +char id=339 x=96 y=389 width=14 height=9 xoffset=-1 yoffset=3 xadvance=12 page=0 chnl=0 +char id=340 x=83 y=62 width=9 height=15 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=341 x=63 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=342 x=91 y=0 width=9 height=16 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=343 x=55 y=149 width=7 height=13 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=344 x=92 y=62 width=9 height=15 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=345 x=70 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=346 x=101 y=62 width=9 height=15 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=347 x=77 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=348 x=94 y=121 width=9 height=14 xoffset=-1 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=349 x=84 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=350 x=110 y=62 width=9 height=15 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=351 x=91 y=259 width=7 height=12 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=352 x=103 y=121 width=9 height=14 xoffset=-1 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=353 x=98 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=354 x=100 y=0 width=10 height=16 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=355 x=119 y=62 width=7 height=15 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=356 x=0 y=77 width=10 height=15 xoffset=-2 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=357 x=105 y=259 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=358 x=112 y=259 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=359 x=73 y=367 width=7 height=11 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=360 x=10 y=77 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=361 x=0 y=271 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=362 x=112 y=121 width=9 height=14 xoffset=0 yoffset=-2 xadvance=9 page=0 chnl=0 +char id=363 x=80 y=367 width=9 height=11 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=0 +char id=364 x=19 y=77 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=365 x=9 y=271 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=366 x=28 y=77 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=367 x=18 y=271 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=368 x=37 y=77 width=9 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=369 x=27 y=271 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=370 x=46 y=77 width=9 height=15 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=371 x=36 y=271 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=372 x=55 y=77 width=14 height=15 xoffset=-1 yoffset=-3 xadvance=12 page=0 chnl=0 +char id=373 x=46 y=271 width=13 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=374 x=69 y=77 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=375 x=22 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=376 x=0 y=135 width=10 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=377 x=79 y=77 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=378 x=59 y=271 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=379 x=10 y=135 width=10 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=380 x=67 y=271 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=381 x=89 y=77 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=382 x=75 y=271 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=894 x=89 y=367 width=5 height=11 xoffset=-1 yoffset=4 xadvance=3 page=0 chnl=0 +char id=900 x=21 y=433 width=5 height=5 xoffset=0 yoffset=0 xadvance=4 page=0 chnl=0 +char id=901 x=26 y=433 width=7 height=5 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=902 x=83 y=271 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=903 x=56 y=433 width=5 height=4 xoffset=-1 yoffset=5 xadvance=3 page=0 chnl=0 +char id=904 x=94 y=271 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=905 x=104 y=271 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=906 x=116 y=271 width=6 height=12 xoffset=-1 yoffset=0 xadvance=4 page=0 chnl=0 +char id=908 x=0 y=283 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=910 x=12 y=283 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=911 x=24 y=283 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=912 x=62 y=149 width=9 height=13 xoffset=-2 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=913 x=36 y=283 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=914 x=47 y=283 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=915 x=56 y=283 width=8 height=12 xoffset=0 yoffset=0 xadvance=6 page=0 chnl=0 +char id=916 x=64 y=283 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=917 x=75 y=283 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=918 x=83 y=283 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=919 x=93 y=283 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=920 x=103 y=283 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=921 x=122 y=199 width=4 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=922 x=115 y=283 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=923 x=0 y=295 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=924 x=11 y=295 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=925 x=24 y=295 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=926 x=34 y=295 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=927 x=44 y=295 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=928 x=56 y=295 width=9 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=929 x=65 y=295 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=931 x=73 y=295 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=932 x=83 y=295 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=933 x=93 y=295 width=11 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=934 x=20 y=135 width=12 height=14 xoffset=-1 yoffset=-1 xadvance=10 page=0 chnl=0 +char id=935 x=104 y=295 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=936 x=114 y=295 width=11 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=937 x=0 y=307 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=938 x=32 y=135 width=7 height=14 xoffset=-2 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=939 x=39 y=135 width=11 height=14 xoffset=-1 yoffset=-2 xadvance=8 page=0 chnl=0 +char id=940 x=12 y=307 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=941 x=22 y=307 width=8 height=12 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=942 x=99 y=77 width=9 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=943 x=122 y=247 width=5 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=944 x=71 y=149 width=9 height=13 xoffset=-1 yoffset=-1 xadvance=7 page=0 chnl=0 +char id=945 x=110 y=389 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=946 x=108 y=77 width=10 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=947 x=30 y=307 width=10 height=12 xoffset=-2 yoffset=3 xadvance=7 page=0 chnl=0 +char id=948 x=40 y=307 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=949 x=0 y=398 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=950 x=118 y=77 width=8 height=15 xoffset=-1 yoffset=-1 xadvance=6 page=0 chnl=0 +char id=951 x=50 y=307 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=952 x=59 y=307 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=953 x=120 y=389 width=4 height=9 xoffset=0 yoffset=3 xadvance=3 page=0 chnl=0 +char id=954 x=8 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=955 x=68 y=307 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=956 x=77 y=307 width=9 height=12 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 +char id=957 x=17 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=958 x=0 y=92 width=8 height=15 xoffset=-1 yoffset=0 xadvance=6 page=0 chnl=0 +char id=959 x=26 y=398 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=960 x=36 y=398 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=961 x=86 y=307 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=962 x=94 y=367 width=8 height=11 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=963 x=46 y=398 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=964 x=56 y=398 width=9 height=9 xoffset=-2 yoffset=3 xadvance=6 page=0 chnl=0 +char id=965 x=65 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=966 x=80 y=149 width=11 height=13 xoffset=-1 yoffset=2 xadvance=9 page=0 chnl=0 +char id=967 x=96 y=307 width=9 height=12 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=968 x=50 y=135 width=11 height=14 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=0 +char id=969 x=74 y=398 width=12 height=9 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=970 x=105 y=307 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=971 x=112 y=307 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=972 x=0 y=319 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=973 x=10 y=319 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=974 x=19 y=319 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1025 x=61 y=135 width=8 height=14 xoffset=0 yoffset=-2 xadvance=7 page=0 chnl=0 +char id=1026 x=69 y=135 width=12 height=14 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1027 x=8 y=92 width=8 height=15 xoffset=0 yoffset=-3 xadvance=6 page=0 chnl=0 +char id=1028 x=31 y=319 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1029 x=41 y=319 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1030 x=122 y=259 width=4 height=12 xoffset=0 yoffset=0 xadvance=3 page=0 chnl=0 +char id=1031 x=81 y=135 width=7 height=14 xoffset=-2 yoffset=-2 xadvance=3 page=0 chnl=0 +char id=1032 x=50 y=319 width=7 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=1033 x=91 y=149 width=15 height=13 xoffset=-2 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1034 x=57 y=319 width=14 height=12 xoffset=0 yoffset=0 xadvance=13 page=0 chnl=0 +char id=1035 x=71 y=319 width=12 height=12 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1036 x=16 y=92 width=9 height=15 xoffset=0 yoffset=-3 xadvance=8 page=0 chnl=0 +char id=1038 x=25 y=92 width=10 height=15 xoffset=-1 yoffset=-3 xadvance=7 page=0 chnl=0 +char id=1039 x=35 y=92 width=9 height=15 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1040 x=83 y=319 width=11 height=12 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1041 x=94 y=319 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1042 x=103 y=319 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1043 x=112 y=319 width=8 height=12 xoffset=0 yoffset=0 xadvance=6 page=0 chnl=0 +char id=1044 x=44 y=92 width=11 height=15 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1045 x=0 y=331 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1046 x=8 y=331 width=14 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1047 x=22 y=331 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1048 x=31 y=331 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1049 x=55 y=92 width=10 height=15 xoffset=0 yoffset=-3 xadvance=9 page=0 chnl=0 +char id=1050 x=41 y=331 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1051 x=50 y=331 width=11 height=12 xoffset=-2 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1052 x=61 y=331 width=13 height=12 xoffset=-1 yoffset=0 xadvance=11 page=0 chnl=0 +char id=1053 x=74 y=331 width=10 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1054 x=84 y=331 width=12 height=12 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1055 x=96 y=331 width=9 height=12 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1056 x=105 y=331 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1057 x=113 y=331 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1058 x=0 y=343 width=10 height=12 xoffset=-2 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1059 x=10 y=343 width=10 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1060 x=106 y=149 width=12 height=13 xoffset=-1 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1061 x=20 y=343 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1062 x=65 y=92 width=10 height=15 xoffset=0 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1063 x=30 y=343 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1064 x=40 y=343 width=12 height=12 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1065 x=75 y=92 width=13 height=15 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1066 x=52 y=343 width=12 height=12 xoffset=-2 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1067 x=64 y=343 width=11 height=12 xoffset=0 yoffset=0 xadvance=10 page=0 chnl=0 +char id=1068 x=75 y=343 width=9 height=12 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1069 x=84 y=343 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1070 x=94 y=343 width=13 height=12 xoffset=0 yoffset=0 xadvance=12 page=0 chnl=0 +char id=1071 x=107 y=343 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1072 x=86 y=398 width=8 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1073 x=116 y=343 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1074 x=94 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1075 x=103 y=398 width=8 height=9 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=1076 x=0 y=355 width=9 height=12 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1077 x=111 y=398 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1078 x=0 y=407 width=12 height=9 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1079 x=12 y=407 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1080 x=20 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1081 x=9 y=355 width=9 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1082 x=29 y=407 width=8 height=9 xoffset=0 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1083 x=37 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1084 x=46 y=407 width=11 height=9 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1085 x=57 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1086 x=66 y=407 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1087 x=76 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1088 x=18 y=355 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1089 x=85 y=407 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1090 x=93 y=407 width=8 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1091 x=88 y=135 width=9 height=14 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1092 x=88 y=92 width=11 height=15 xoffset=-1 yoffset=0 xadvance=9 page=0 chnl=0 +char id=1093 x=101 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1094 x=28 y=355 width=10 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1095 x=110 y=407 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1096 x=0 y=416 width=12 height=9 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=1097 x=38 y=355 width=13 height=12 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=1098 x=12 y=416 width=10 height=9 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1099 x=22 y=416 width=11 height=9 xoffset=-1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=1100 x=33 y=416 width=9 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1101 x=119 y=407 width=8 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1102 x=42 y=416 width=12 height=9 xoffset=-1 yoffset=3 xadvance=10 page=0 chnl=0 +char id=1103 x=54 y=416 width=8 height=9 xoffset=-1 yoffset=3 xadvance=7 page=0 chnl=0 +char id=1105 x=51 y=355 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1106 x=99 y=92 width=10 height=15 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1107 x=60 y=355 width=8 height=12 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=0 +char id=1108 x=62 y=416 width=9 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1109 x=120 y=398 width=7 height=9 xoffset=-1 yoffset=3 xadvance=6 page=0 chnl=0 +char id=1110 x=122 y=271 width=5 height=12 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=1111 x=120 y=319 width=7 height=12 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=1112 x=109 y=92 width=6 height=15 xoffset=-2 yoffset=0 xadvance=3 page=0 chnl=0 +char id=1113 x=19 y=379 width=13 height=10 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1114 x=71 y=416 width=13 height=9 xoffset=-1 yoffset=3 xadvance=11 page=0 chnl=0 +char id=1115 x=68 y=355 width=10 height=12 xoffset=-1 yoffset=0 xadvance=8 page=0 chnl=0 +char id=1116 x=78 y=355 width=8 height=12 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1118 x=31 y=0 width=9 height=17 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=1119 x=86 y=355 width=9 height=12 xoffset=-1 yoffset=3 xadvance=8 page=0 chnl=0 +char id=1168 x=97 y=135 width=8 height=14 xoffset=0 yoffset=-2 xadvance=6 page=0 chnl=0 +char id=1169 x=102 y=367 width=8 height=11 xoffset=-1 yoffset=1 xadvance=5 page=0 chnl=0 +char id=1241 x=84 y=416 width=10 height=9 xoffset=-1 yoffset=3 xadvance=5 page=0 chnl=0 +char id=8204 x=0 y=0 width=0 height=0 xoffset=-1 yoffset=0 xadvance=3 page=0 chnl=0 +char id=8211 x=102 y=433 width=9 height=3 xoffset=-1 yoffset=6 xadvance=7 page=0 chnl=0 +char id=8212 x=111 y=433 width=16 height=3 xoffset=-1 yoffset=6 xadvance=14 page=0 chnl=0 +char id=8216 x=57 y=425 width=5 height=7 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=8217 x=62 y=425 width=5 height=7 xoffset=-1 yoffset=-1 xadvance=3 page=0 chnl=0 +char id=8218 x=109 y=425 width=5 height=6 xoffset=-1 yoffset=8 xadvance=3 page=0 chnl=0 +char id=8220 x=67 y=425 width=7 height=7 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=8221 x=74 y=425 width=7 height=7 xoffset=-1 yoffset=-1 xadvance=5 page=0 chnl=0 +char id=8222 x=114 y=425 width=7 height=6 xoffset=-1 yoffset=8 xadvance=5 page=0 chnl=0 +char id=8224 x=118 y=149 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=8225 x=0 y=162 width=9 height=13 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=8226 x=33 y=433 width=6 height=5 xoffset=-1 yoffset=5 xadvance=4 page=0 chnl=0 +char id=8230 x=61 y=433 width=14 height=4 xoffset=0 yoffset=8 xadvance=14 page=0 chnl=0 +char id=8240 x=95 y=355 width=18 height=12 xoffset=-1 yoffset=0 xadvance=16 page=0 chnl=0 +char id=8249 x=0 y=425 width=6 height=8 xoffset=-1 yoffset=3 xadvance=4 page=0 chnl=0 +char id=8250 x=6 y=425 width=6 height=8 xoffset=-1 yoffset=3 xadvance=4 page=0 chnl=0 +char id=8260 x=113 y=355 width=12 height=12 xoffset=-4 yoffset=0 xadvance=2 page=0 chnl=0 +char id=8363 x=0 y=367 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +char id=8364 x=9 y=367 width=9 height=12 xoffset=-1 yoffset=0 xadvance=7 page=0 chnl=0 +kernings count=3440 +kerning first=8216 second=281 amount=-1 +kerning first=221 second=285 amount=-1 +kerning first=39 second=961 amount=-1 +kerning first=356 second=232 amount=-1 +kerning first=34 second=74 amount=-1 +kerning first=1027 second=1107 amount=-1 +kerning first=8218 second=376 amount=-1 +kerning first=8221 second=301 amount=-1 +kerning first=358 second=335 amount=-1 +kerning first=957 second=46 amount=-1 +kerning first=257 second=84 amount=-1 +kerning first=376 second=279 amount=-1 +kerning first=356 second=97 amount=-1 +kerning first=354 second=231 amount=-1 +kerning first=89 second=210 amount=-1 +kerning first=70 second=224 amount=-1 +kerning first=1058 second=1035 amount=1 +kerning first=8216 second=937 amount=-1 +kerning first=1168 second=1040 amount=-1 +kerning first=76 second=87 amount=-1 +kerning first=932 second=940 amount=-1 +kerning first=354 second=93 amount=1 +kerning first=229 second=932 amount=-1 +kerning first=939 second=959 amount=-1 +kerning first=321 second=173 amount=-1 +kerning first=932 second=244 amount=-1 +kerning first=915 second=71 amount=-1 +kerning first=929 second=923 amount=-1 +kerning first=221 second=308 amount=-1 +kerning first=358 second=227 amount=-1 +kerning first=192 second=39 amount=-1 +kerning first=1043 second=1088 amount=-1 +kerning first=8217 second=109 amount=-1 +kerning first=196 second=221 amount=-1 +kerning first=65 second=89 amount=-1 +kerning first=947 second=44 amount=-1 +kerning first=221 second=369 amount=-1 +kerning first=315 second=262 amount=-1 +kerning first=1027 second=187 amount=-1 +kerning first=196 second=84 amount=-1 +kerning first=931 second=264 amount=-1 +kerning first=8218 second=358 amount=-1 +kerning first=1098 second=1091 amount=-1 +kerning first=84 second=361 amount=-1 +kerning first=915 second=941 amount=-1 +kerning first=939 second=181 amount=-1 +kerning first=1043 second=44 amount=-1 +kerning first=89 second=252 amount=-1 +kerning first=1043 second=1032 amount=-1 +kerning first=932 second=260 amount=-1 +kerning first=89 second=173 amount=-1 +kerning first=8216 second=940 amount=-1 +kerning first=1168 second=1074 amount=-1 +kerning first=354 second=285 amount=-1 +kerning first=8216 second=244 amount=-1 +kerning first=8220 second=281 amount=-1 +kerning first=221 second=242 amount=-1 +kerning first=65 second=34 amount=-1 +kerning first=89 second=111 amount=-1 +kerning first=1059 second=1066 amount=1 +kerning first=84 second=973 amount=-1 +kerning first=84 second=251 amount=-1 +kerning first=8217 second=324 amount=-1 +kerning first=109 second=356 amount=-1 +kerning first=933 second=45 amount=-1 +kerning first=160 second=86 amount=-1 +kerning first=1066 second=1059 amount=-1 +kerning first=902 second=39 amount=-1 +kerning first=1027 second=1085 amount=-1 +kerning first=319 second=8220 amount=-2 +kerning first=932 second=8249 amount=-1 +kerning first=358 second=287 amount=-1 +kerning first=8220 second=937 amount=-1 +kerning first=84 second=110 amount=-1 +kerning first=8221 second=111 amount=-1 +kerning first=915 second=916 amount=-2 +kerning first=317 second=89 amount=-1 +kerning first=46 second=8220 amount=-1 +kerning first=315 second=376 amount=-1 +kerning first=39 second=74 amount=-1 +kerning first=923 second=356 amount=-1 +kerning first=91 second=372 amount=1 +kerning first=45 second=376 amount=-1 +kerning first=227 second=354 amount=-1 +kerning first=354 second=308 amount=-1 +kerning first=315 second=332 amount=-1 +kerning first=8204 second=354 amount=-1 +kerning first=171 second=933 amount=-1 +kerning first=932 second=948 amount=-1 +kerning first=315 second=85 amount=-1 +kerning first=319 second=219 amount=-1 +kerning first=356 second=361 amount=-1 +kerning first=8216 second=260 amount=-1 +kerning first=1100 second=8217 amount=-1 +kerning first=221 second=262 amount=-1 +kerning first=376 second=913 amount=-1 +kerning first=1033 second=1026 amount=-1 +kerning first=1058 second=1105 amount=-1 +kerning first=1059 second=173 amount=-1 +kerning first=372 second=192 amount=-1 +kerning first=40 second=221 amount=1 +kerning first=225 second=356 amount=-1 +kerning first=1168 second=1109 amount=-1 +kerning first=319 second=81 amount=-1 +kerning first=354 second=369 amount=-1 +kerning first=376 second=258 amount=-1 +kerning first=317 second=34 amount=-1 +kerning first=356 second=973 amount=-1 +kerning first=102 second=39 amount=1 +kerning first=915 second=8250 amount=-1 +kerning first=40 second=84 amount=1 +kerning first=44 second=34 amount=-1 +kerning first=923 second=8217 amount=-1 +kerning first=356 second=251 amount=-1 +kerning first=1038 second=1066 amount=1 +kerning first=86 second=913 amount=-1 +kerning first=1027 second=1169 amount=-1 +kerning first=80 second=916 amount=-1 +kerning first=84 second=328 amount=-1 +kerning first=358 second=365 amount=-1 +kerning first=8220 second=940 amount=-1 +kerning first=258 second=8216 amount=-1 +kerning first=916 second=39 amount=-1 +kerning first=356 second=110 amount=-1 +kerning first=915 second=949 amount=-1 +kerning first=354 second=242 amount=-1 +kerning first=86 second=258 amount=-1 +kerning first=89 second=224 amount=-1 +kerning first=315 second=358 amount=-1 +kerning first=8220 second=244 amount=-1 +kerning first=246 second=358 amount=-1 +kerning first=76 second=366 amount=-1 +kerning first=8216 second=948 amount=-1 +kerning first=160 second=932 amount=-1 +kerning first=45 second=358 amount=-1 +kerning first=933 second=8212 amount=-1 +kerning first=910 second=173 amount=-1 +kerning first=8217 second=331 amount=-1 +kerning first=915 second=336 amount=-1 +kerning first=8222 second=356 amount=-1 +kerning first=1040 second=1058 amount=-1 +kerning first=971 second=39 amount=-1 +kerning first=358 second=941 amount=-1 +kerning first=221 second=332 amount=-1 +kerning first=84 second=228 amount=-1 +kerning first=8217 second=283 amount=-1 +kerning first=358 second=246 amount=-1 +kerning first=1043 second=1101 amount=-1 +kerning first=1066 second=1038 amount=-1 +kerning first=932 second=269 amount=-1 +kerning first=933 second=912 amount=1 +kerning first=1038 second=173 amount=-1 +kerning first=932 second=117 amount=-1 +kerning first=89 second=339 amount=-1 +kerning first=315 second=199 amount=-1 +kerning first=358 second=105 amount=-1 +kerning first=87 second=301 amount=1 +kerning first=111 second=932 amount=-1 +kerning first=376 second=81 amount=-1 +kerning first=944 second=34 amount=-1 +kerning first=915 second=338 amount=-1 +kerning first=70 second=256 amount=-1 +kerning first=315 second=288 amount=-1 +kerning first=76 second=45 amount=-1 +kerning first=8220 second=260 amount=-1 +kerning first=343 second=8230 amount=-1 +kerning first=356 second=328 amount=-1 +kerning first=932 second=197 amount=-1 +kerning first=358 second=916 amount=-1 +kerning first=84 second=248 amount=-1 +kerning first=8221 second=339 amount=-1 +kerning first=1058 second=1083 amount=-1 +kerning first=1168 second=1087 amount=-1 +kerning first=89 second=275 amount=-1 +kerning first=933 second=193 amount=-1 +kerning first=1113 second=1090 amount=-1 +kerning first=197 second=89 amount=-1 +kerning first=195 second=376 amount=-1 +kerning first=8216 second=269 amount=-1 +kerning first=221 second=267 amount=-1 +kerning first=8221 second=312 amount=-1 +kerning first=356 second=228 amount=-1 +kerning first=8217 second=349 amount=-1 +kerning first=228 second=932 amount=-1 +kerning first=933 second=58 amount=-1 +kerning first=955 second=39 amount=-1 +kerning first=932 second=341 amount=-1 +kerning first=1027 second=1098 amount=-1 +kerning first=84 second=279 amount=-1 +kerning first=8221 second=275 amount=-1 +kerning first=194 second=39 amount=-1 +kerning first=932 second=187 amount=-1 +kerning first=8220 second=948 amount=-1 +kerning first=65 second=8220 amount=-1 +kerning first=358 second=8250 amount=-1 +kerning first=193 second=221 amount=-1 +kerning first=376 second=115 amount=-1 +kerning first=915 second=195 amount=-2 +kerning first=315 second=362 amount=-1 +kerning first=76 second=79 amount=-1 +kerning first=8216 second=197 amount=-1 +kerning first=1046 second=1033 amount=1 +kerning first=345 second=46 amount=-1 +kerning first=221 second=199 amount=-1 +kerning first=932 second=963 amount=-1 +kerning first=8217 second=236 amount=-1 +kerning first=915 second=290 amount=-1 +kerning first=313 second=262 amount=-1 +kerning first=193 second=84 amount=-1 +kerning first=939 second=951 amount=-1 +kerning first=932 second=235 amount=-1 +kerning first=121 second=46 amount=-1 +kerning first=197 second=34 amount=-1 +kerning first=358 second=949 amount=-1 +kerning first=221 second=288 amount=-1 +kerning first=356 second=248 amount=-1 +kerning first=321 second=372 amount=-1 +kerning first=1058 second=1119 amount=-1 +kerning first=319 second=356 amount=-1 +kerning first=324 second=354 amount=-1 +kerning first=1043 second=1080 amount=-1 +kerning first=376 second=196 amount=-1 +kerning first=8217 second=101 amount=-1 +kerning first=242 second=356 amount=-1 +kerning first=354 second=380 amount=-1 +kerning first=187 second=932 amount=-1 +kerning first=112 second=354 amount=-1 +kerning first=76 second=8212 amount=-1 +kerning first=929 second=260 amount=-1 +kerning first=936 second=46 amount=-1 +kerning first=1034 second=1035 amount=-1 +kerning first=358 second=84 amount=1 +kerning first=915 second=8230 amount=-2 +kerning first=195 second=358 amount=-1 +kerning first=308 second=93 amount=1 +kerning first=86 second=196 amount=-1 +kerning first=356 second=279 amount=-1 +kerning first=358 second=378 amount=-1 +kerning first=80 second=195 amount=-1 +kerning first=376 second=333 amount=-1 +kerning first=317 second=8220 amount=-2 +kerning first=354 second=358 amount=1 +kerning first=89 second=243 amount=-1 +kerning first=8217 second=46 amount=-2 +kerning first=8216 second=963 amount=-1 +kerning first=1168 second=1066 amount=1 +kerning first=44 second=8220 amount=-1 +kerning first=313 second=376 amount=-1 +kerning first=319 second=8217 amount=-1 +kerning first=354 second=267 amount=-1 +kerning first=932 second=41 amount=1 +kerning first=8216 second=235 amount=-1 +kerning first=8220 second=269 amount=-1 +kerning first=46 second=8217 amount=-2 +kerning first=354 second=119 amount=-1 +kerning first=89 second=103 amount=-1 +kerning first=8212 second=356 amount=-1 +kerning first=224 second=354 amount=-1 +kerning first=84 second=969 amount=-1 +kerning first=1059 second=1058 amount=1 +kerning first=313 second=332 amount=-1 +kerning first=1091 second=46 amount=-1 +kerning first=102 second=93 amount=1 +kerning first=84 second=241 amount=-1 +kerning first=8217 second=297 amount=-1 +kerning first=313 second=85 amount=-1 +kerning first=8221 second=243 amount=-1 +kerning first=317 second=219 amount=-1 +kerning first=8216 second=8216 amount=-1 +kerning first=1098 second=8217 amount=-1 +kerning first=376 second=233 amount=-1 +kerning first=1027 second=1077 amount=-1 +kerning first=321 second=171 amount=-1 +kerning first=8230 second=8221 amount=-2 +kerning first=358 second=265 amount=-1 +kerning first=80 second=8230 amount=-2 +kerning first=8221 second=103 amount=-1 +kerning first=317 second=81 amount=-1 +kerning first=70 second=192 amount=-1 +kerning first=315 second=210 amount=-1 +kerning first=358 second=118 amount=-1 +kerning first=8220 second=197 amount=-1 +kerning first=45 second=910 amount=-1 +kerning first=91 second=354 amount=1 +kerning first=923 second=86 amount=-1 +kerning first=89 second=256 amount=-1 +kerning first=321 second=220 amount=-1 +kerning first=1168 second=173 amount=-1 +kerning first=84 second=913 amount=-1 +kerning first=1035 second=1066 amount=-1 +kerning first=931 second=79 amount=-1 +kerning first=8204 second=87 amount=-1 +kerning first=936 second=198 amount=-1 +kerning first=1058 second=1096 amount=-1 +kerning first=358 second=195 amount=-1 +kerning first=1043 second=1059 amount=1 +kerning first=271 second=311 amount=1 +kerning first=912 second=950 amount=1 +kerning first=1168 second=1100 amount=-1 +kerning first=84 second=258 amount=-1 +kerning first=313 second=358 amount=-1 +kerning first=8221 second=256 amount=-1 +kerning first=354 second=343 amount=-1 +kerning first=243 second=358 amount=-1 +kerning first=913 second=221 amount=-1 +kerning first=939 second=65 amount=-1 +kerning first=89 second=171 amount=-1 +kerning first=1059 second=1092 amount=-1 +kerning first=356 second=969 amount=-1 +kerning first=84 second=307 amount=-1 +kerning first=356 second=241 amount=-1 +kerning first=1038 second=1058 amount=1 +kerning first=913 second=84 amount=-1 +kerning first=932 second=367 amount=-1 +kerning first=8217 second=198 amount=-1 +kerning first=260 second=39 amount=-1 +kerning first=354 second=965 amount=-1 +kerning first=358 second=345 amount=-1 +kerning first=8220 second=963 amount=-1 +kerning first=104 second=358 amount=-1 +kerning first=256 second=221 amount=-1 +kerning first=376 second=291 amount=-1 +kerning first=354 second=237 amount=-1 +kerning first=358 second=8230 amount=-1 +kerning first=910 second=962 amount=-1 +kerning first=8220 second=235 amount=-1 +kerning first=315 second=173 amount=-1 +kerning first=915 second=214 amount=-1 +kerning first=313 second=199 amount=-1 +kerning first=109 second=932 amount=-1 +kerning first=974 second=34 amount=-1 +kerning first=221 second=210 amount=-1 +kerning first=123 second=106 amount=1 +kerning first=932 second=972 amount=-1 +kerning first=256 second=84 amount=-1 +kerning first=123 second=1095 amount=-1 +kerning first=8220 second=8216 amount=-1 +kerning first=313 second=288 amount=-1 +kerning first=356 second=913 amount=-1 +kerning first=932 second=250 amount=-1 +kerning first=939 second=966 amount=-1 +kerning first=936 second=194 amount=-1 +kerning first=341 second=8230 amount=-1 +kerning first=8222 second=86 amount=-1 +kerning first=358 second=232 amount=-1 +kerning first=923 second=932 amount=-1 +kerning first=929 second=197 amount=-1 +kerning first=1043 second=1093 amount=-1 +kerning first=329 second=356 amount=-1 +kerning first=8217 second=114 amount=-1 +kerning first=933 second=941 amount=-1 +kerning first=65 second=356 amount=-1 +kerning first=356 second=258 amount=-1 +kerning first=932 second=109 amount=-1 +kerning first=926 second=970 amount=1 +kerning first=358 second=97 amount=-1 +kerning first=197 second=8220 amount=-1 +kerning first=356 second=307 amount=-1 +kerning first=1038 second=1092 amount=-1 +kerning first=321 second=927 amount=-1 +kerning first=196 second=89 amount=-1 +kerning first=8250 second=221 amount=-1 +kerning first=192 second=376 amount=-1 +kerning first=8217 second=194 amount=-1 +kerning first=8211 second=1026 amount=-1 +kerning first=225 second=932 amount=-1 +kerning first=910 second=256 amount=-1 +kerning first=376 second=363 amount=-1 +kerning first=261 second=358 amount=-1 +kerning first=915 second=973 amount=-1 +kerning first=321 second=286 amount=-1 +kerning first=1058 second=1075 amount=-1 +kerning first=8250 second=84 amount=-1 +kerning first=319 second=268 amount=-1 +kerning first=1043 second=1038 amount=1 +kerning first=173 second=354 amount=-1 +kerning first=933 second=916 amount=-1 +kerning first=8216 second=972 amount=-1 +kerning first=1168 second=1079 amount=-1 +kerning first=354 second=301 amount=-1 +kerning first=89 second=263 amount=-1 +kerning first=34 second=193 amount=-1 +kerning first=221 second=252 amount=-1 +kerning first=65 second=8217 amount=-1 +kerning first=939 second=44 amount=-1 +kerning first=221 second=173 amount=-1 +kerning first=313 second=362 amount=-1 +kerning first=84 second=382 amount=-1 +kerning first=8217 second=337 amount=-1 +kerning first=1043 second=8249 amount=-1 +kerning first=1090 second=8230 amount=-1 +kerning first=119 second=46 amount=-1 +kerning first=196 second=34 amount=-1 +kerning first=221 second=111 amount=-1 +kerning first=932 second=324 amount=-1 +kerning first=376 second=245 amount=-1 +kerning first=1027 second=1090 amount=-1 +kerning first=321 second=8221 amount=-1 +kerning first=8221 second=263 amount=-1 +kerning first=317 second=356 amount=-1 +kerning first=89 second=927 amount=-1 +kerning first=123 second=376 amount=1 +kerning first=244 second=356 amount=-1 +kerning first=84 second=115 amount=-1 +kerning first=89 second=192 amount=-1 +kerning first=8222 second=932 amount=-1 +kerning first=110 second=354 amount=-1 +kerning first=934 second=46 amount=-1 +kerning first=89 second=286 amount=-1 +kerning first=76 second=71 amount=-1 +kerning first=192 second=358 amount=-1 +kerning first=902 second=376 amount=-1 +kerning first=8217 second=231 amount=-1 +kerning first=70 second=74 amount=-1 +kerning first=932 second=226 amount=-1 +kerning first=84 second=196 amount=-1 +kerning first=8221 second=192 amount=-1 +kerning first=321 second=354 amount=-1 +kerning first=1027 second=46 amount=-1 +kerning first=333 second=84 amount=-1 +kerning first=1043 second=1072 amount=-1 +kerning first=933 second=949 amount=-1 +kerning first=1168 second=1114 amount=-1 +kerning first=319 second=86 amount=-1 +kerning first=271 second=8221 amount=1 +kerning first=331 second=358 amount=-1 +kerning first=1034 second=8217 amount=-1 +kerning first=1113 second=1118 amount=-1 +kerning first=376 second=268 amount=-1 +kerning first=317 second=8217 amount=-1 +kerning first=1059 second=1106 amount=1 +kerning first=40 second=89 amount=1 +kerning first=44 second=8217 amount=-2 +kerning first=226 second=354 amount=-1 +kerning first=356 second=382 amount=-1 +kerning first=84 second=333 amount=-1 +kerning first=354 second=971 amount=-1 +kerning first=358 second=361 amount=-1 +kerning first=8220 second=972 amount=-1 +kerning first=123 second=358 amount=1 +kerning first=8221 second=8221 amount=-1 +kerning first=356 second=115 amount=-1 +kerning first=915 second=954 amount=-1 +kerning first=8218 second=372 amount=-1 +kerning first=354 second=252 amount=-1 +kerning first=89 second=234 amount=-1 +kerning first=354 second=173 amount=-1 +kerning first=1168 second=1058 amount=1 +kerning first=313 second=210 amount=-1 +kerning first=221 second=224 amount=-1 +kerning first=902 second=358 amount=-1 +kerning first=354 second=111 amount=-1 +kerning first=87 second=256 amount=-1 +kerning first=84 second=959 amount=-1 +kerning first=932 second=331 amount=-1 +kerning first=358 second=973 amount=-1 +kerning first=84 second=233 amount=-1 +kerning first=8217 second=285 amount=-1 +kerning first=8221 second=234 amount=-1 +kerning first=356 second=196 amount=-1 +kerning first=1033 second=1066 amount=-1 +kerning first=39 second=193 amount=-1 +kerning first=358 second=251 amount=-1 +kerning first=923 second=939 amount=-1 +kerning first=1043 second=1107 amount=-1 +kerning first=372 second=239 amount=1 +kerning first=932 second=283 amount=-1 +kerning first=84 second=356 amount=1 +kerning first=8221 second=354 amount=1 +kerning first=932 second=122 amount=-1 +kerning first=358 second=110 amount=-1 +kerning first=97 second=84 amount=-1 +kerning first=910 second=192 amount=-1 +kerning first=91 second=87 amount=1 +kerning first=1038 second=1106 amount=1 +kerning first=319 second=932 amount=-1 +kerning first=221 second=339 amount=-1 +kerning first=932 second=934 amount=-1 +kerning first=242 second=932 amount=-1 +kerning first=321 second=211 amount=-1 +kerning first=1035 second=1058 amount=-1 +kerning first=356 second=333 amount=-1 +kerning first=931 second=71 amount=-1 +kerning first=939 second=923 amount=-1 +kerning first=258 second=39 amount=-1 +kerning first=8217 second=308 amount=-1 +kerning first=1058 second=1088 amount=-1 +kerning first=376 second=230 amount=-1 +kerning first=1168 second=1092 amount=-1 +kerning first=89 second=289 amount=-1 +kerning first=933 second=195 amount=-1 +kerning first=313 second=173 amount=-1 +kerning first=197 second=356 amount=-1 +kerning first=356 second=959 amount=-1 +kerning first=973 second=34 amount=-1 +kerning first=8216 second=283 amount=-1 +kerning first=221 second=275 amount=-1 +kerning first=916 second=358 amount=-1 +kerning first=356 second=233 amount=-1 +kerning first=1043 second=187 amount=-1 +kerning first=932 second=349 amount=-1 +kerning first=1114 second=1091 amount=-1 +kerning first=1027 second=1103 amount=-1 +kerning first=84 second=291 amount=-1 +kerning first=356 second=356 amount=1 +kerning first=8221 second=289 amount=-1 +kerning first=118 second=8230 amount=-1 +kerning first=358 second=328 amount=-1 +kerning first=76 second=221 amount=-1 +kerning first=8211 second=376 amount=-1 +kerning first=295 second=356 amount=-1 +kerning first=1058 second=44 amount=-1 +kerning first=376 second=271 amount=-1 +kerning first=354 second=224 amount=-1 +kerning first=89 second=211 amount=-1 +kerning first=8212 second=932 amount=-1 +kerning first=1058 second=1032 amount=-1 +kerning first=70 second=225 amount=-1 +kerning first=910 second=961 amount=-1 +kerning first=76 second=336 amount=-1 +kerning first=76 second=84 amount=-1 +kerning first=196 second=8220 amount=-1 +kerning first=315 second=372 amount=-1 +kerning first=933 second=8230 amount=-1 +kerning first=932 second=968 amount=-1 +kerning first=8217 second=242 amount=-1 +kerning first=89 second=74 amount=-1 +kerning first=193 second=89 amount=-1 +kerning first=932 second=236 amount=-1 +kerning first=194 second=376 amount=-1 +kerning first=197 second=8217 amount=-1 +kerning first=1169 second=44 amount=-1 +kerning first=1027 second=59 amount=-1 +kerning first=358 second=228 amount=-1 +kerning first=319 second=370 amount=-1 +kerning first=1043 second=1085 amount=-1 +kerning first=1168 second=171 amount=-1 +kerning first=34 second=941 amount=-1 +kerning first=259 second=358 amount=-1 +kerning first=317 second=268 amount=-1 +kerning first=932 second=101 amount=-1 +kerning first=89 second=371 amount=-1 +kerning first=76 second=338 amount=-1 +kerning first=65 second=86 amount=-1 +kerning first=8221 second=74 amount=-1 +kerning first=354 second=339 amount=-1 +kerning first=376 second=65 amount=-1 +kerning first=245 second=354 amount=-1 +kerning first=8230 second=933 amount=-1 +kerning first=84 second=363 amount=-1 +kerning first=356 second=291 amount=-1 +kerning first=193 second=34 amount=-1 +kerning first=8211 second=358 amount=-1 +kerning first=376 second=347 amount=-1 +kerning first=354 second=312 amount=-1 +kerning first=321 second=264 amount=-1 +kerning first=89 second=353 amount=-1 +kerning first=358 second=248 amount=-1 +kerning first=241 second=356 amount=-1 +kerning first=34 second=916 amount=-1 +kerning first=86 second=65 amount=-1 +kerning first=87 second=192 amount=-1 +kerning first=271 second=108 amount=1 +kerning first=354 second=275 amount=-1 +kerning first=932 second=46 amount=-1 +kerning first=8220 second=283 amount=-1 +kerning first=221 second=243 amount=-1 +kerning first=195 second=936 amount=-1 +kerning first=315 second=171 amount=-1 +kerning first=194 second=358 amount=-1 +kerning first=84 second=245 amount=-1 +kerning first=8221 second=353 amount=-1 +kerning first=8216 second=101 amount=-1 +kerning first=1043 second=1169 amount=-1 +kerning first=221 second=103 amount=-1 +kerning first=932 second=297 amount=-1 +kerning first=1027 second=1082 amount=-1 +kerning first=321 second=8211 amount=-1 +kerning first=335 second=84 amount=-1 +kerning first=358 second=279 amount=-1 +kerning first=915 second=913 amount=-2 +kerning first=317 second=86 amount=-1 +kerning first=40 second=309 amount=1 +kerning first=315 second=220 amount=-1 +kerning first=376 second=99 amount=-1 +kerning first=76 second=290 amount=-1 +kerning first=89 second=264 amount=-1 +kerning first=931 second=336 amount=-1 +kerning first=932 second=945 amount=-1 +kerning first=329 second=932 amount=-1 +kerning first=915 second=258 amount=-2 +kerning first=1168 second=1241 amount=-1 +kerning first=319 second=213 amount=-1 +kerning first=65 second=932 amount=-1 +kerning first=356 second=363 amount=-1 +kerning first=46 second=939 amount=-1 +kerning first=221 second=256 amount=-1 +kerning first=1058 second=1101 amount=-1 +kerning first=8216 second=46 amount=-2 +kerning first=372 second=193 amount=-1 +kerning first=1027 second=1026 amount=1 +kerning first=34 second=949 amount=-1 +kerning first=321 second=87 amount=-1 +kerning first=912 second=955 amount=1 +kerning first=89 second=8211 amount=-1 +kerning first=931 second=338 amount=-1 +kerning first=376 second=44 amount=-1 +kerning first=39 second=941 amount=-1 +kerning first=356 second=245 amount=-1 +kerning first=913 second=89 amount=-1 +kerning first=221 second=171 amount=-1 +kerning first=195 second=372 amount=-1 +kerning first=173 second=933 amount=-1 +kerning first=80 second=913 amount=-1 +kerning first=1027 second=1118 amount=-1 +kerning first=257 second=356 amount=-1 +kerning first=932 second=198 amount=-1 +kerning first=354 second=962 amount=-1 +kerning first=915 second=946 amount=-1 +kerning first=8218 second=354 amount=-1 +kerning first=354 second=243 amount=-1 +kerning first=89 second=225 amount=-1 +kerning first=8212 second=939 amount=-1 +kerning first=910 second=970 amount=1 +kerning first=76 second=368 amount=-1 +kerning first=8216 second=945 amount=-1 +kerning first=80 second=258 amount=-1 +kerning first=86 second=44 amount=-1 +kerning first=354 second=372 amount=1 +kerning first=932 second=944 amount=-1 +kerning first=256 second=89 amount=-1 +kerning first=8217 second=358 amount=1 +kerning first=260 second=376 amount=-1 +kerning first=354 second=103 amount=-1 +kerning first=8220 second=101 amount=-1 +kerning first=939 second=940 amount=-1 +kerning first=317 second=932 amount=-1 +kerning first=932 second=255 amount=-1 +kerning first=39 second=916 amount=-1 +kerning first=915 second=81 amount=-1 +kerning first=358 second=969 amount=-1 +kerning first=244 second=932 amount=-1 +kerning first=8217 second=267 amount=-1 +kerning first=1033 second=1058 amount=-1 +kerning first=358 second=241 amount=-1 +kerning first=913 second=34 amount=-1 +kerning first=1043 second=1098 amount=-1 +kerning first=932 second=261 amount=-1 +kerning first=376 second=213 amount=-1 +kerning first=293 second=358 amount=-1 +kerning first=922 second=74 amount=1 +kerning first=357 second=8221 amount=1 +kerning first=932 second=114 amount=-1 +kerning first=315 second=927 amount=-1 +kerning first=926 second=912 amount=1 +kerning first=8204 second=902 amount=-1 +kerning first=84 second=86 amount=1 +kerning first=1059 second=8211 amount=-1 +kerning first=196 second=356 amount=-1 +kerning first=354 second=256 amount=-1 +kerning first=373 second=46 amount=-1 +kerning first=315 second=286 amount=-1 +kerning first=8216 second=198 amount=-1 +kerning first=931 second=290 amount=-1 +kerning first=256 second=34 amount=-1 +kerning first=8220 second=46 amount=-2 +kerning first=932 second=194 amount=-1 +kerning first=358 second=913 amount=-1 +kerning first=1068 second=1026 amount=-1 +kerning first=84 second=230 amount=-1 +kerning first=8221 second=305 amount=-1 +kerning first=1058 second=1080 amount=-1 +kerning first=89 second=273 amount=-1 +kerning first=8250 second=89 amount=-1 +kerning first=1056 second=44 amount=-2 +kerning first=1168 second=1084 amount=-1 +kerning first=1056 second=1032 amount=-1 +kerning first=939 second=260 amount=-1 +kerning first=922 second=970 amount=1 +kerning first=89 second=277 amount=-1 +kerning first=358 second=258 amount=-1 +kerning first=34 second=195 amount=-1 +kerning first=8221 second=8204 amount=-1 +kerning first=260 second=358 amount=-1 +kerning first=354 second=171 amount=-1 +kerning first=315 second=8221 amount=-1 +kerning first=1059 second=1076 amount=-1 +kerning first=313 second=372 amount=-1 +kerning first=193 second=8220 amount=-1 +kerning first=197 second=86 amount=-1 +kerning first=39 second=949 amount=-1 +kerning first=221 second=263 amount=-1 +kerning first=910 second=8211 amount=-1 +kerning first=8217 second=343 amount=-1 +kerning first=8221 second=273 amount=-1 +kerning first=358 second=307 amount=-1 +kerning first=196 second=8217 amount=-1 +kerning first=160 second=8216 amount=-1 +kerning first=932 second=337 amount=-1 +kerning first=376 second=249 amount=-1 +kerning first=1027 second=1095 amount=-1 +kerning first=8211 second=910 amount=-1 +kerning first=84 second=271 amount=-1 +kerning first=8221 second=277 amount=-1 +kerning first=317 second=370 amount=-1 +kerning first=76 second=214 amount=-1 +kerning first=8220 second=945 amount=-1 +kerning first=376 second=259 amount=-1 +kerning first=255 second=46 amount=-1 +kerning first=356 second=86 amount=1 +kerning first=915 second=196 amount=-2 +kerning first=1038 second=8211 amount=-1 +kerning first=221 second=927 amount=-1 +kerning first=315 second=354 amount=-1 +kerning first=8216 second=194 amount=-1 +kerning first=34 second=8230 amount=-2 +kerning first=221 second=192 amount=-1 +kerning first=8217 second=237 amount=-1 +kerning first=246 second=354 amount=-1 +kerning first=1107 second=46 amount=-1 +kerning first=84 second=932 amount=1 +kerning first=45 second=354 amount=-1 +kerning first=65 second=939 amount=-1 +kerning first=939 second=948 amount=-1 +kerning first=932 second=231 amount=-1 +kerning first=221 second=286 amount=-1 +kerning first=376 second=923 amount=-1 +kerning first=356 second=230 amount=-1 +kerning first=321 second=366 amount=-1 +kerning first=1114 second=8217 amount=-1 +kerning first=1043 second=1077 amount=-1 +kerning first=933 second=954 amount=-1 +kerning first=1027 second=1040 amount=-1 +kerning first=932 second=93 amount=1 +kerning first=89 second=351 amount=-1 +kerning first=84 second=65 amount=-1 +kerning first=40 second=356 amount=1 +kerning first=929 second=46 amount=-2 +kerning first=8220 second=198 amount=-1 +kerning first=8216 second=337 amount=-1 +kerning first=192 second=936 amount=-1 +kerning first=313 second=171 amount=-1 +kerning first=1038 second=1076 amount=-1 +kerning first=86 second=923 amount=-1 +kerning first=84 second=347 amount=-1 +kerning first=8221 second=351 amount=-1 +kerning first=356 second=271 amount=-1 +kerning first=80 second=196 amount=-1 +kerning first=197 second=932 amount=-1 +kerning first=915 second=959 amount=-1 +kerning first=89 second=239 amount=1 +kerning first=1058 second=1059 amount=1 +kerning first=321 second=45 amount=-1 +kerning first=313 second=220 amount=-1 +kerning first=354 second=263 amount=-1 +kerning first=70 second=257 amount=-1 +kerning first=8216 second=231 amount=-1 +kerning first=221 second=234 amount=-1 +kerning first=89 second=100 amount=-1 +kerning first=84 second=966 amount=-1 +kerning first=356 second=932 amount=1 +kerning first=295 second=932 amount=-1 +kerning first=84 second=238 amount=-1 +kerning first=8217 second=301 amount=-1 +kerning first=8221 second=239 amount=-1 +kerning first=317 second=213 amount=-1 +kerning first=39 second=195 amount=-1 +kerning first=358 second=382 amount=-1 +kerning first=44 second=939 amount=-1 +kerning first=932 second=285 amount=-1 +kerning first=376 second=229 amount=-1 +kerning first=1027 second=1074 amount=-1 +kerning first=84 second=99 amount=-1 +kerning first=8221 second=100 amount=-1 +kerning first=356 second=65 amount=-1 +kerning first=354 second=192 amount=-1 +kerning first=315 second=211 amount=-1 +kerning first=70 second=193 amount=-1 +kerning first=358 second=115 amount=-1 +kerning first=8220 second=194 amount=-1 +kerning first=931 second=214 amount=-1 +kerning first=8204 second=221 amount=-1 +kerning first=915 second=181 amount=-1 +kerning first=902 second=936 amount=-1 +kerning first=913 second=8220 amount=-1 +kerning first=227 second=84 amount=-1 +kerning first=89 second=45 amount=-1 +kerning first=1035 second=1063 amount=-1 +kerning first=356 second=347 amount=-1 +kerning first=8204 second=84 amount=-1 +kerning first=195 second=8221 amount=-1 +kerning first=192 second=372 amount=-1 +kerning first=939 second=197 amount=-1 +kerning first=1058 second=1093 amount=-1 +kerning first=39 second=8230 amount=-2 +kerning first=929 second=198 amount=-1 +kerning first=358 second=196 amount=-1 +kerning first=1075 second=44 amount=-1 +kerning first=932 second=308 amount=-1 +kerning first=8216 second=1026 amount=1 +kerning first=321 second=79 amount=-1 +kerning first=1168 second=1097 amount=-1 +kerning first=8220 second=337 amount=-1 +kerning first=84 second=44 amount=-1 +kerning first=256 second=8220 amount=-1 +kerning first=1059 second=1089 amount=-1 +kerning first=356 second=966 amount=-1 +kerning first=8216 second=285 amount=-1 +kerning first=258 second=376 amount=-1 +kerning first=221 second=289 amount=-1 +kerning first=356 second=238 amount=-1 +kerning first=932 second=369 amount=-1 +kerning first=241 second=932 amount=-1 +kerning first=1027 second=1109 amount=-1 +kerning first=195 second=354 amount=-1 +kerning first=321 second=8212 amount=-1 +kerning first=84 second=299 amount=-1 +kerning first=8221 second=303 amount=-1 +kerning first=354 second=961 amount=-1 +kerning first=358 second=333 amount=-1 +kerning first=376 second=281 amount=-1 +kerning first=356 second=99 amount=-1 +kerning first=354 second=234 amount=-1 +kerning first=1058 second=1038 amount=1 +kerning first=70 second=227 amount=-1 +kerning first=313 second=927 amount=-1 +kerning first=8220 second=231 amount=-1 +kerning first=98 second=358 amount=-1 +kerning first=376 second=125 amount=1 +kerning first=8218 second=87 amount=-1 +kerning first=123 second=372 amount=1 +kerning first=253 second=8230 amount=-1 +kerning first=354 second=354 amount=1 +kerning first=76 second=89 amount=-1 +kerning first=193 second=356 amount=-1 +kerning first=221 second=211 amount=-1 +kerning first=1059 second=45 amount=-1 +kerning first=916 second=936 amount=-1 +kerning first=89 second=79 amount=-1 +kerning first=313 second=286 amount=-1 +kerning first=939 second=963 amount=-1 +kerning first=932 second=242 amount=-1 +kerning first=358 second=959 amount=-1 +kerning first=8216 second=308 amount=-1 +kerning first=1058 second=8249 amount=-1 +kerning first=902 second=372 amount=-1 +kerning first=358 second=233 amount=-1 +kerning first=929 second=194 amount=-1 +kerning first=221 second=74 amount=-1 +kerning first=1043 second=1090 amount=-1 +kerning first=1168 second=8211 amount=-1 +kerning first=8217 second=111 amount=-1 +kerning first=1066 second=1026 amount=-1 +kerning first=86 second=125 amount=1 +kerning first=114 second=8230 amount=-1 +kerning first=358 second=356 amount=1 +kerning first=356 second=44 amount=-1 +kerning first=89 second=8212 amount=-1 +kerning first=947 second=46 amount=-1 +kerning first=1033 second=8221 amount=-1 +kerning first=258 second=358 amount=-1 +kerning first=221 second=371 amount=-1 +kerning first=313 second=8221 amount=-1 +kerning first=1038 second=1089 amount=-1 +kerning first=315 second=264 amount=-1 +kerning first=76 second=34 amount=-1 +kerning first=196 second=86 amount=-1 +kerning first=84 second=373 amount=-1 +kerning first=356 second=299 amount=-1 +kerning first=193 second=8217 amount=-1 +kerning first=8220 second=1026 amount=1 +kerning first=197 second=939 amount=-1 +kerning first=915 second=943 amount=-1 +kerning first=910 second=45 amount=-1 +kerning first=1043 second=46 amount=-1 +kerning first=1058 second=1072 amount=-1 +kerning first=933 second=913 amount=-1 +kerning first=1168 second=1076 amount=-1 +kerning first=354 second=289 amount=-1 +kerning first=89 second=257 amount=-1 +kerning first=8216 second=242 amount=-1 +kerning first=8220 second=285 amount=-1 +kerning first=221 second=353 amount=-1 +kerning first=89 second=113 amount=-1 +kerning first=315 second=8211 amount=-1 +kerning first=257 second=932 amount=-1 +kerning first=84 second=974 amount=-1 +kerning first=313 second=354 amount=-1 +kerning first=933 second=258 amount=-1 +kerning first=243 second=354 amount=-1 +kerning first=1038 second=45 amount=-1 +kerning first=84 second=249 amount=-1 +kerning first=75 second=308 amount=1 +kerning first=376 second=244 amount=-1 +kerning first=1027 second=1087 amount=-1 +kerning first=84 second=259 amount=-1 +kerning first=319 second=8249 amount=-1 +kerning first=358 second=291 amount=-1 +kerning first=1059 second=8212 amount=-1 +kerning first=84 second=112 amount=-1 +kerning first=8221 second=113 amount=-1 +kerning first=89 second=193 amount=-1 +kerning first=923 second=8216 amount=-1 +kerning first=104 second=354 amount=-1 +kerning first=1061 second=1060 amount=-1 +kerning first=8220 second=308 amount=-1 +kerning first=1026 second=1035 amount=-1 +kerning first=194 second=936 amount=-1 +kerning first=915 second=268 amount=-1 +kerning first=354 second=74 amount=-1 +kerning first=315 second=87 amount=-1 +kerning first=84 second=923 amount=-1 +kerning first=319 second=217 amount=-1 +kerning first=356 second=373 amount=-1 +kerning first=221 second=264 amount=-1 +kerning first=8221 second=193 amount=-1 +kerning first=1058 second=1107 amount=-1 +kerning first=319 second=334 amount=-1 +kerning first=372 second=195 amount=-1 +kerning first=196 second=932 amount=-1 +kerning first=933 second=946 amount=-1 +kerning first=8216 second=1040 amount=-1 +kerning first=1168 second=1111 amount=-1 +kerning first=87 second=239 amount=1 +kerning first=324 second=84 amount=-1 +kerning first=354 second=371 amount=-1 +kerning first=89 second=335 amount=-1 +kerning first=376 second=260 amount=-1 +kerning first=112 second=84 amount=-1 +kerning first=356 second=974 amount=-1 +kerning first=40 second=86 amount=1 +kerning first=913 second=356 amount=-1 +kerning first=910 second=8212 amount=-1 +kerning first=356 second=249 amount=-1 +kerning first=221 second=8211 amount=-1 +kerning first=932 second=380 amount=-1 +kerning first=8217 second=339 amount=-1 +kerning first=84 second=326 amount=-1 +kerning first=319 second=216 amount=-1 +kerning first=356 second=259 amount=-1 +kerning first=8221 second=335 amount=-1 +kerning first=358 second=363 amount=-1 +kerning first=337 second=358 amount=-1 +kerning first=356 second=112 amount=-1 +kerning first=915 second=951 amount=-1 +kerning first=354 second=353 amount=-1 +kerning first=86 second=260 amount=-1 +kerning first=89 second=227 amount=-1 +kerning first=910 second=912 amount=1 +kerning first=8220 second=242 amount=-1 +kerning first=372 second=8230 amount=-1 +kerning first=376 second=8249 amount=-1 +kerning first=1038 second=8212 amount=-1 +kerning first=256 second=356 amount=-1 +kerning first=313 second=211 amount=-1 +kerning first=261 second=354 amount=-1 +kerning first=221 second=225 amount=-1 +kerning first=1059 second=58 amount=-1 +kerning first=8217 second=312 amount=-1 +kerning first=356 second=923 amount=-1 +kerning first=939 second=972 amount=-1 +kerning first=932 second=358 amount=1 +kerning first=1058 second=187 amount=-1 +kerning first=224 second=84 amount=-1 +kerning first=84 second=229 amount=-1 +kerning first=8217 second=275 amount=-1 +kerning first=1033 second=1063 amount=-1 +kerning first=358 second=245 amount=-1 +kerning first=248 second=358 amount=-1 +kerning first=913 second=8217 amount=-1 +kerning first=192 second=8221 amount=-1 +kerning first=932 second=267 amount=-1 +kerning first=194 second=372 amount=-1 +kerning first=1027 second=1066 amount=1 +kerning first=1043 second=1103 amount=-1 +kerning first=91 second=221 amount=1 +kerning first=932 second=119 amount=-1 +kerning first=929 second=308 amount=-1 +kerning first=376 second=334 amount=-1 +kerning first=1034 second=1059 amount=-1 +kerning first=45 second=933 amount=-1 +kerning first=910 second=193 amount=-1 +kerning first=91 second=84 amount=1 +kerning first=256 second=8217 amount=-1 +kerning first=356 second=326 amount=-1 +kerning first=8250 second=356 amount=-1 +kerning first=8220 second=1040 amount=-1 +kerning first=192 second=354 amount=-1 +kerning first=910 second=58 amount=-1 +kerning first=1043 second=59 amount=-1 +kerning first=968 second=39 amount=-1 +kerning first=40 second=932 amount=1 +kerning first=1058 second=1085 amount=-1 +kerning first=319 second=284 amount=-1 +kerning first=376 second=216 amount=-1 +kerning first=321 second=71 amount=-1 +kerning first=1168 second=1089 amount=-1 +kerning first=1036 second=1051 amount=1 +kerning first=922 second=912 amount=1 +kerning first=89 second=287 amount=-1 +kerning first=76 second=8220 amount=-2 +kerning first=8216 second=358 amount=1 +kerning first=933 second=196 amount=-1 +kerning first=221 second=273 amount=-1 +kerning first=1027 second=173 amount=-1 +kerning first=354 second=8211 amount=-1 +kerning first=331 second=354 amount=-1 +kerning first=8216 second=267 amount=-1 +kerning first=1038 second=58 amount=-1 +kerning first=221 second=277 amount=-1 +kerning first=356 second=229 amount=-1 +kerning first=1100 second=1098 amount=-1 +kerning first=902 second=8221 amount=-1 +kerning first=932 second=343 amount=-1 +kerning first=1027 second=1100 amount=-1 +kerning first=84 second=281 amount=-1 +kerning first=8221 second=287 amount=-1 +kerning first=195 second=87 amount=-1 +kerning first=76 second=219 amount=-1 +kerning first=84 second=125 amount=1 +kerning first=376 second=269 amount=-1 +kerning first=354 second=225 amount=-1 +kerning first=1168 second=45 amount=-1 +kerning first=376 second=117 amount=-1 +kerning first=123 second=354 amount=1 +kerning first=260 second=936 amount=-1 +kerning first=315 second=366 amount=-1 +kerning first=76 second=81 amount=-1 +kerning first=932 second=965 amount=-1 +kerning first=8217 second=243 amount=-1 +kerning first=354 second=87 amount=1 +kerning first=89 second=71 amount=-1 +kerning first=313 second=264 amount=-1 +kerning first=193 second=86 amount=-1 +kerning first=932 second=237 amount=-1 +kerning first=915 second=65 amount=-2 +kerning first=1068 second=1066 amount=-1 +kerning first=333 second=356 amount=-1 +kerning first=902 second=354 amount=-1 +kerning first=1058 second=1169 amount=-1 +kerning first=319 second=364 amount=-1 +kerning first=1043 second=1082 amount=-1 +kerning first=343 second=44 amount=-1 +kerning first=376 second=197 amount=-1 +kerning first=8217 second=103 amount=-1 +kerning first=196 second=939 amount=-1 +kerning first=936 second=256 amount=-1 +kerning first=933 second=959 amount=-1 +kerning first=8249 second=910 amount=-1 +kerning first=34 second=969 amount=-1 +kerning first=319 second=8216 amount=-2 +kerning first=89 second=365 amount=-1 +kerning first=958 second=125 amount=1 +kerning first=376 second=284 amount=-1 +kerning first=46 second=8216 amount=-1 +kerning first=354 second=305 amount=-1 +kerning first=1034 second=1038 amount=-1 +kerning first=358 second=86 amount=1 +kerning first=102 second=8221 amount=1 +kerning first=221 second=351 amount=-1 +kerning first=313 second=8211 amount=-1 +kerning first=86 second=197 amount=-1 +kerning first=315 second=45 amount=-1 +kerning first=356 second=281 amount=-1 +kerning first=173 second=221 amount=-1 +kerning first=916 second=8221 amount=-1 +kerning first=8217 second=256 amount=-1 +kerning first=356 second=125 amount=1 +kerning first=915 second=966 amount=-1 +kerning first=317 second=8249 amount=-1 +kerning first=89 second=246 amount=-1 +kerning first=963 second=912 amount=1 +kerning first=358 second=230 amount=-1 +kerning first=354 second=273 amount=-1 +kerning first=8220 second=358 amount=1 +kerning first=1043 second=1026 amount=1 +kerning first=34 second=913 amount=-1 +kerning first=87 second=193 amount=-1 +kerning first=354 second=277 amount=-1 +kerning first=173 second=84 amount=-1 +kerning first=933 second=181 amount=-1 +kerning first=8220 second=267 amount=-1 +kerning first=80 second=65 amount=-1 +kerning first=221 second=239 amount=1 +kerning first=195 second=933 amount=-1 +kerning first=354 second=121 amount=-1 +kerning first=84 second=940 amount=-1 +kerning first=34 second=258 amount=-1 +kerning first=84 second=244 amount=-1 +kerning first=313 second=87 amount=-1 +kerning first=8221 second=246 amount=-1 +kerning first=260 second=372 amount=-1 +kerning first=317 second=217 amount=-1 +kerning first=1043 second=1118 amount=-1 +kerning first=221 second=100 amount=-1 +kerning first=932 second=301 amount=-1 +kerning first=376 second=235 amount=-1 +kerning first=1027 second=1079 amount=-1 +kerning first=1168 second=8212 amount=-1 +kerning first=916 second=354 amount=-1 +kerning first=317 second=334 amount=-1 +kerning first=358 second=271 amount=-1 +kerning first=97 second=356 amount=-1 +kerning first=193 second=932 amount=-1 +kerning first=8221 second=105 amount=-1 +kerning first=70 second=195 amount=-1 +kerning first=110 second=84 amount=-1 +kerning first=321 second=221 amount=-1 +kerning first=315 second=79 amount=-1 +kerning first=319 second=212 amount=-1 +kerning first=931 second=81 amount=-1 +kerning first=8204 second=89 amount=-1 +kerning first=358 second=932 amount=1 +kerning first=915 second=44 amount=-2 +kerning first=317 second=216 amount=-1 +kerning first=321 second=336 amount=-1 +kerning first=1058 second=1098 amount=-1 +kerning first=271 second=318 amount=1 +kerning first=326 second=358 amount=-1 +kerning first=221 second=45 amount=-1 +kerning first=321 second=84 amount=-1 +kerning first=1168 second=1102 amount=-1 +kerning first=84 second=260 amount=-1 +kerning first=354 second=351 amount=-1 +kerning first=259 second=354 amount=-1 +kerning first=315 second=8212 amount=-1 +kerning first=70 second=8230 amount=-1 +kerning first=358 second=65 amount=-1 +kerning first=356 second=940 amount=-1 +kerning first=376 second=41 amount=1 +kerning first=39 second=969 amount=-1 +kerning first=356 second=244 amount=-1 +kerning first=913 second=86 amount=-1 +kerning first=955 second=8221 amount=-1 +kerning first=226 second=84 amount=-1 +kerning first=1027 second=1114 amount=-1 +kerning first=321 second=338 amount=-1 +kerning first=194 second=8221 amount=-1 +kerning first=358 second=347 amount=-1 +kerning first=84 second=8249 amount=-1 +kerning first=354 second=239 amount=-1 +kerning first=910 second=941 amount=-1 +kerning first=1168 second=58 amount=-1 +kerning first=915 second=213 amount=-1 +kerning first=76 second=356 amount=-1 +kerning first=8211 second=354 amount=-1 +kerning first=86 second=41 amount=1 +kerning first=89 second=336 amount=-1 +kerning first=80 second=44 amount=-2 +kerning first=932 second=971 amount=-1 +kerning first=256 second=86 amount=-1 +kerning first=354 second=100 amount=-1 +kerning first=70 second=97 amount=-1 +kerning first=84 second=948 amount=-1 +kerning first=932 second=252 amount=-1 +kerning first=39 second=913 amount=-1 +kerning first=358 second=966 amount=-1 +kerning first=936 second=192 amount=-1 +kerning first=932 second=173 amount=-1 +kerning first=8217 second=263 amount=-1 +kerning first=358 second=238 amount=-1 +kerning first=221 second=79 amount=-1 +kerning first=194 second=354 amount=-1 +kerning first=376 second=212 amount=-1 +kerning first=1027 second=1058 amount=1 +kerning first=1043 second=1095 amount=-1 +kerning first=8216 second=1066 amount=1 +kerning first=356 second=260 amount=-1 +kerning first=1113 second=8221 amount=-1 +kerning first=317 second=284 amount=-1 +kerning first=932 second=111 amount=-1 +kerning first=39 second=258 amount=-1 +kerning first=8221 second=84 amount=1 +kerning first=65 second=8216 amount=-1 +kerning first=89 second=338 amount=-1 +kerning first=358 second=99 amount=-1 +kerning first=910 second=916 amount=-1 +kerning first=76 second=8217 amount=-1 +kerning first=319 second=920 amount=-1 +kerning first=160 second=8218 amount=-2 +kerning first=221 second=8212 amount=-1 +kerning first=8217 second=192 amount=-1 +kerning first=354 second=45 amount=-1 +kerning first=969 second=34 amount=-1 +kerning first=1098 second=1098 amount=-1 +kerning first=356 second=8249 amount=-1 +kerning first=376 second=367 amount=-1 +kerning first=321 second=290 amount=-1 +kerning first=1058 second=1077 amount=-1 +kerning first=319 second=266 amount=-1 +kerning first=192 second=87 amount=-1 +kerning first=1043 second=1040 amount=-1 +kerning first=913 second=932 amount=-1 +kerning first=1168 second=1081 amount=-1 +kerning first=354 second=303 amount=-1 +kerning first=89 second=265 amount=-1 +kerning first=34 second=196 amount=-1 +kerning first=936 second=961 amount=-1 +kerning first=939 second=46 amount=-1 +kerning first=258 second=936 amount=-1 +kerning first=358 second=44 amount=-1 +kerning first=313 second=366 amount=-1 +kerning first=356 second=948 amount=-1 +kerning first=88 second=934 amount=-1 +kerning first=221 second=257 amount=-1 +kerning first=1100 second=1090 amount=-1 +kerning first=8216 second=111 amount=-1 +kerning first=221 second=113 amount=-1 +kerning first=1066 second=1066 amount=-1 +kerning first=335 second=356 amount=-1 +kerning first=376 second=250 amount=-1 +kerning first=8217 second=8221 amount=-1 +kerning first=1027 second=1092 amount=-1 +kerning first=84 second=269 amount=-1 +kerning first=256 second=932 amount=-1 +kerning first=8221 second=265 amount=-1 +kerning first=317 second=364 amount=-1 +kerning first=358 second=299 amount=-1 +kerning first=341 second=44 amount=-1 +kerning first=193 second=939 amount=-1 +kerning first=84 second=117 amount=-1 +kerning first=915 second=923 amount=-2 +kerning first=317 second=8216 amount=-2 +kerning first=89 second=195 amount=-1 +kerning first=910 second=949 amount=-1 +kerning first=44 second=8216 amount=-1 +kerning first=89 second=290 amount=-1 +kerning first=221 second=193 amount=-1 +kerning first=123 second=87 amount=1 +kerning first=8217 second=234 amount=-1 +kerning first=939 second=945 amount=-1 +kerning first=932 second=224 amount=-1 +kerning first=1068 second=1058 amount=-1 +kerning first=8220 second=1066 amount=1 +kerning first=84 second=197 amount=-1 +kerning first=376 second=920 amount=-1 +kerning first=313 second=45 amount=-1 +kerning first=8217 second=354 amount=1 +kerning first=8221 second=195 amount=-1 +kerning first=321 second=368 amount=-1 +kerning first=1043 second=1074 amount=-1 +kerning first=902 second=87 amount=-1 +kerning first=933 second=951 amount=-1 +kerning first=1168 second=1116 amount=-1 +kerning first=1041 second=1026 amount=-1 +kerning first=376 second=266 amount=-1 +kerning first=293 second=354 amount=-1 +kerning first=354 second=8212 amount=-1 +kerning first=89 second=8230 amount=-1 +kerning first=1059 second=1108 amount=-1 +kerning first=8250 second=932 amount=-1 +kerning first=192 second=933 amount=-1 +kerning first=221 second=335 amount=-1 +kerning first=1027 second=171 amount=-1 +kerning first=245 second=84 amount=-1 +kerning first=260 second=8221 amount=-1 +kerning first=80 second=923 amount=-1 +kerning first=258 second=372 amount=-1 +kerning first=84 second=341 amount=-1 +kerning first=356 second=269 amount=-1 +kerning first=8221 second=345 amount=-1 +kerning first=932 second=339 amount=-1 +kerning first=358 second=373 amount=-1 +kerning first=84 second=187 amount=-1 +kerning first=8221 second=8230 amount=-2 +kerning first=356 second=117 amount=-1 +kerning first=939 second=198 amount=-1 +kerning first=354 second=253 amount=-1 +kerning first=89 second=232 amount=-1 +kerning first=1090 second=44 amount=-1 +kerning first=1168 second=1060 amount=-1 +kerning first=923 second=39 amount=-1 +kerning first=354 second=257 amount=-1 +kerning first=221 second=227 amount=-1 +kerning first=354 second=113 amount=-1 +kerning first=89 second=97 amount=-1 +kerning first=8220 second=111 amount=-1 +kerning first=84 second=963 amount=-1 +kerning first=8204 second=8220 amount=-1 +kerning first=932 second=312 amount=-1 +kerning first=358 second=974 amount=-1 +kerning first=84 second=235 amount=-1 +kerning first=313 second=79 amount=-1 +kerning first=356 second=197 amount=-1 +kerning first=8217 second=289 amount=-1 +kerning first=260 second=354 amount=-1 +kerning first=317 second=212 amount=-1 +kerning first=8221 second=232 amount=-1 +kerning first=39 second=196 amount=-1 +kerning first=358 second=249 amount=-1 +kerning first=1043 second=1109 amount=-1 +kerning first=932 second=275 amount=-1 +kerning first=376 second=226 amount=-1 +kerning first=328 second=358 amount=-1 +kerning first=358 second=259 amount=-1 +kerning first=1059 second=8230 amount=-1 +kerning first=354 second=193 amount=-1 +kerning first=358 second=112 amount=-1 +kerning first=1111 second=1106 amount=1 +kerning first=76 second=268 amount=-1 +kerning first=333 second=932 amount=-1 +kerning first=902 second=933 amount=-1 +kerning first=910 second=195 amount=-1 +kerning first=313 second=8212 amount=-1 +kerning first=91 second=89 amount=1 +kerning first=1038 second=1108 amount=-1 +kerning first=8216 second=339 amount=-1 +kerning first=321 second=214 amount=-1 +kerning first=315 second=71 amount=-1 +kerning first=356 second=341 amount=-1 +kerning first=358 second=923 amount=-1 +kerning first=372 second=913 amount=-1 +kerning first=356 second=187 amount=-1 +kerning first=939 second=194 amount=-1 +kerning first=1058 second=1090 amount=-1 +kerning first=271 second=293 amount=1 +kerning first=8217 second=74 amount=-1 +kerning first=913 second=939 amount=-1 +kerning first=1168 second=1094 amount=-1 +kerning first=319 second=67 amount=-1 +kerning first=354 second=335 amount=-1 +kerning first=372 second=258 amount=-1 +kerning first=84 second=41 amount=1 +kerning first=1027 second=1241 amount=-1 +kerning first=939 second=59 amount=-1 +kerning first=1059 second=1086 amount=-1 +kerning first=356 second=963 amount=-1 +kerning first=197 second=8216 amount=-1 +kerning first=221 second=287 amount=-1 +kerning first=8216 second=275 amount=-1 +kerning first=910 second=8230 amount=-1 +kerning first=229 second=358 amount=-1 +kerning first=356 second=235 amount=-1 +kerning first=933 second=65 amount=-1 +kerning first=8218 second=221 amount=-1 +kerning first=256 second=939 amount=-1 +kerning first=358 second=326 amount=-1 +kerning first=1058 second=46 amount=-1 +kerning first=376 second=283 amount=-1 +kerning first=354 second=227 amount=-1 +kerning first=89 second=214 amount=-1 +kerning first=70 second=228 amount=-1 +kerning first=8218 second=84 amount=-1 +kerning first=1038 second=8230 amount=-1 +kerning first=8230 second=34 amount=-1 +kerning first=76 second=86 amount=-1 +kerning first=958 second=41 amount=1 +kerning first=932 second=962 amount=-1 +kerning first=8217 second=353 amount=-1 +kerning first=916 second=933 amount=-1 +kerning first=317 second=920 amount=-1 +kerning first=932 second=243 amount=-1 +kerning first=1169 second=46 amount=-1 +kerning first=97 second=932 amount=-1 +kerning first=358 second=229 amount=-1 +kerning first=319 second=360 amount=-1 +kerning first=221 second=71 amount=-1 +kerning first=932 second=372 amount=1 +kerning first=1043 second=1087 amount=-1 +kerning first=1168 second=8250 amount=-1 +kerning first=933 second=966 amount=-1 +kerning first=8216 second=1058 amount=1 +kerning first=317 second=266 amount=-1 +kerning first=932 second=103 amount=-1 +kerning first=194 second=87 amount=-1 +kerning first=89 second=361 amount=-1 +kerning first=356 second=41 amount=1 +kerning first=8220 second=339 amount=-1 +kerning first=376 second=67 amount=-1 +kerning first=221 second=365 amount=-1 +kerning first=1038 second=1086 amount=-1 +kerning first=931 second=268 amount=-1 +kerning first=1098 second=1090 amount=-1 +kerning first=84 second=367 amount=-1 +kerning first=376 second=349 amount=-1 +kerning first=915 second=940 amount=-1 +kerning first=89 second=251 amount=-1 +kerning first=932 second=256 amount=-1 +kerning first=8216 second=962 amount=-1 +kerning first=87 second=195 amount=-1 +kerning first=354 second=287 amount=-1 +kerning first=118 second=44 amount=-1 +kerning first=173 second=89 amount=-1 +kerning first=8216 second=243 amount=-1 +kerning first=8220 second=275 amount=-1 +kerning first=160 second=376 amount=-1 +kerning first=221 second=246 amount=-1 +kerning first=84 second=972 amount=-1 +kerning first=8204 second=8222 amount=-2 +kerning first=84 second=250 amount=-1 +kerning first=8216 second=103 amount=-1 +kerning first=933 second=44 amount=-1 +kerning first=1066 second=1058 amount=-1 +kerning first=1027 second=1084 amount=-1 +kerning first=76 second=932 amount=-1 +kerning first=8211 second=933 amount=-1 +kerning first=319 second=39 amount=-1 +kerning first=1060 second=1061 amount=-1 +kerning first=932 second=171 amount=-1 +kerning first=358 second=281 amount=-1 +kerning first=84 second=109 amount=-1 +kerning first=8221 second=110 amount=-1 +kerning first=46 second=39 amount=-1 +kerning first=315 second=221 amount=-1 +kerning first=358 second=125 amount=1 +kerning first=376 second=101 amount=-1 +kerning first=87 second=8230 amount=-1 +kerning first=45 second=221 amount=-1 +kerning first=227 second=356 amount=-1 +kerning first=315 second=336 amount=-1 +kerning first=8204 second=356 amount=-1 +kerning first=98 second=354 amount=-1 +kerning first=194 second=933 amount=-1 +kerning first=915 second=260 amount=-2 +kerning first=315 second=84 amount=-1 +kerning first=319 second=218 amount=-1 +kerning first=356 second=367 amount=-1 +kerning first=246 second=84 amount=-1 +kerning first=8216 second=256 amount=-1 +kerning first=8220 second=1058 amount=1 +kerning first=258 second=8221 amount=-1 +kerning first=45 second=84 amount=-1 +kerning first=1058 second=1103 amount=-1 +kerning first=372 second=196 amount=-1 +kerning first=1043 second=1066 amount=1 +kerning first=321 second=89 amount=-1 +kerning first=1168 second=1108 amount=-1 +kerning first=354 second=365 amount=-1 +kerning first=160 second=358 amount=-1 +kerning first=315 second=338 amount=-1 +kerning first=1068 second=8221 amount=-1 +kerning first=356 second=972 amount=-1 +kerning first=376 second=46 amount=-1 +kerning first=356 second=250 amount=-1 +kerning first=1100 second=1118 amount=-1 +kerning first=8217 second=305 amount=-1 +kerning first=258 second=354 amount=-1 +kerning first=84 second=324 amount=-1 +kerning first=8221 second=328 amount=-1 +kerning first=354 second=941 amount=-1 +kerning first=8220 second=962 amount=-1 +kerning first=1058 second=59 amount=-1 +kerning first=915 second=948 amount=-1 +kerning first=356 second=109 amount=-1 +kerning first=354 second=246 amount=-1 +kerning first=89 second=228 amount=-1 +kerning first=8220 second=243 amount=-1 +kerning first=91 second=309 amount=1 +kerning first=8217 second=8204 amount=-1 +kerning first=76 second=370 amount=-1 +kerning first=321 second=34 amount=-1 +kerning first=80 second=260 amount=-1 +kerning first=86 second=46 amount=-1 +kerning first=111 second=358 amount=-1 +kerning first=1043 second=173 amount=-1 +kerning first=335 second=932 amount=-1 +kerning first=8217 second=273 amount=-1 +kerning first=915 second=334 amount=-1 +kerning first=354 second=105 amount=-1 +kerning first=1059 second=1044 amount=-1 +kerning first=8220 second=103 amount=-1 +kerning first=939 second=942 amount=-1 +kerning first=358 second=940 amount=-1 +kerning first=221 second=336 amount=-1 +kerning first=84 second=226 amount=-1 +kerning first=313 second=71 amount=-1 +kerning first=8217 second=277 amount=-1 +kerning first=358 second=244 amount=-1 +kerning first=1043 second=1100 amount=-1 +kerning first=932 second=263 amount=-1 +kerning first=1168 second=8230 amount=-1 +kerning first=260 second=87 amount=-1 +kerning first=8230 second=8220 amount=-1 +kerning first=354 second=916 amount=-1 +kerning first=70 second=913 amount=-1 +kerning first=317 second=67 amount=-1 +kerning first=89 second=248 amount=-1 +kerning first=187 second=376 amount=-1 +kerning first=915 second=216 amount=-1 +kerning first=315 second=290 amount=-1 +kerning first=70 second=258 amount=-1 +kerning first=196 second=8216 amount=-1 +kerning first=8220 second=256 amount=-1 +kerning first=221 second=338 amount=-1 +kerning first=228 second=358 amount=-1 +kerning first=356 second=324 amount=-1 +kerning first=271 second=295 amount=1 +kerning first=932 second=192 amount=-1 +kerning first=8221 second=248 amount=-1 +kerning first=1058 second=1082 amount=-1 +kerning first=1056 second=46 amount=-2 +kerning first=376 second=198 amount=-1 +kerning first=933 second=923 amount=-1 +kerning first=1168 second=1086 amount=-1 +kerning first=89 second=279 amount=-1 +kerning first=358 second=260 amount=-1 +kerning first=354 second=8250 amount=-1 +kerning first=195 second=221 amount=-1 +kerning first=8216 second=263 amount=-1 +kerning first=221 second=265 amount=-1 +kerning first=84 second=331 amount=-1 +kerning first=8217 second=351 amount=-1 +kerning first=356 second=226 amount=-1 +kerning first=1038 second=1044 amount=-1 +kerning first=34 second=65 amount=-1 +kerning first=1027 second=1097 amount=-1 +kerning first=965 second=34 amount=-1 +kerning first=86 second=198 amount=-1 +kerning first=84 second=283 amount=-1 +kerning first=8221 second=279 amount=-1 +kerning first=317 second=360 amount=-1 +kerning first=354 second=949 amount=-1 +kerning first=76 second=213 amount=-1 +kerning first=195 second=84 amount=-1 +kerning first=84 second=122 amount=-1 +kerning first=376 second=261 amount=-1 +kerning first=65 second=39 amount=-1 +kerning first=187 second=358 amount=-1 +kerning first=1058 second=1026 amount=1 +kerning first=358 second=8249 amount=-1 +kerning first=910 second=954 amount=-1 +kerning first=915 second=197 amount=-2 +kerning first=337 second=354 amount=-1 +kerning first=260 second=933 amount=-1 +kerning first=315 second=368 amount=-1 +kerning first=8216 second=192 amount=-1 +kerning first=221 second=195 amount=-1 +kerning first=932 second=961 amount=-1 +kerning first=171 second=939 amount=-1 +kerning first=8217 second=239 amount=-1 +kerning first=915 second=284 amount=-1 +kerning first=354 second=84 amount=1 +kerning first=84 second=934 amount=-1 +kerning first=1040 second=1035 amount=-1 +kerning first=932 second=234 amount=-1 +kerning first=358 second=948 amount=-1 +kerning first=1068 second=1063 amount=-1 +kerning first=221 second=290 amount=-1 +kerning first=1058 second=1118 amount=-1 +kerning first=324 second=356 amount=-1 +kerning first=1043 second=1079 amount=-1 +kerning first=932 second=354 amount=1 +kerning first=376 second=194 amount=-1 +kerning first=8217 second=100 amount=-1 +kerning first=354 second=378 amount=-1 +kerning first=112 second=356 amount=-1 +kerning first=248 second=354 amount=-1 +kerning first=929 second=256 amount=-1 +kerning first=915 second=187 amount=-1 +kerning first=356 second=331 amount=-1 +kerning first=1027 second=8211 amount=-1 +kerning first=221 second=8230 amount=-1 +kerning first=86 second=194 amount=-1 +kerning first=84 second=349 amount=-1 +kerning first=356 second=283 amount=-1 +kerning first=80 second=197 amount=-1 +kerning first=376 second=337 amount=-1 +kerning first=356 second=122 amount=-1 +kerning first=915 second=963 amount=-1 +kerning first=317 second=39 amount=-1 +kerning first=8216 second=961 amount=-1 +kerning first=44 second=39 amount=-1 +kerning first=313 second=221 amount=-1 +kerning first=354 second=265 amount=-1 +kerning first=8216 second=234 amount=-1 +kerning first=8220 second=263 amount=-1 +kerning first=221 second=232 amount=-1 +kerning first=354 second=118 amount=-1 +kerning first=224 second=356 amount=-1 +kerning first=84 second=968 amount=-1 +kerning first=313 second=336 amount=-1 +kerning first=356 second=934 amount=-1 +kerning first=8216 second=354 amount=1 +kerning first=84 second=236 amount=-1 +kerning first=8217 second=303 amount=-1 +kerning first=313 second=84 amount=-1 +kerning first=8221 second=241 amount=-1 +kerning first=317 second=218 amount=-1 +kerning first=243 second=84 amount=-1 +kerning first=34 second=44 amount=-2 +kerning first=1043 second=1114 amount=-1 +kerning first=221 second=97 amount=-1 +kerning first=932 second=289 amount=-1 +kerning first=376 second=231 amount=-1 +kerning first=1027 second=1076 amount=-1 +kerning first=321 second=8220 amount=-2 +kerning first=923 second=376 amount=-1 +kerning first=89 second=913 amount=-1 +kerning first=1041 second=1066 amount=-1 +kerning first=358 second=269 amount=-1 +kerning first=84 second=101 amount=-1 +kerning first=354 second=195 amount=-1 +kerning first=39 second=65 amount=-1 +kerning first=70 second=196 amount=-1 +kerning first=315 second=214 amount=-1 +kerning first=358 second=117 amount=-1 +kerning first=8220 second=192 amount=-1 +kerning first=91 second=356 amount=1 +kerning first=931 second=213 amount=-1 +kerning first=376 second=93 amount=1 +kerning first=313 second=338 amount=-1 +kerning first=1066 second=8221 amount=-1 +kerning first=89 second=258 amount=-1 +kerning first=104 second=84 amount=-1 +kerning first=321 second=219 amount=-1 +kerning first=1098 second=1118 amount=-1 +kerning first=356 second=349 amount=-1 +kerning first=8221 second=913 amount=-1 +kerning first=8204 second=86 amount=-1 +kerning first=1058 second=1095 amount=-1 +kerning first=8212 second=1026 amount=-1 +kerning first=358 second=197 amount=-1 +kerning first=1043 second=1058 amount=1 +kerning first=1075 second=46 amount=-1 +kerning first=944 second=39 amount=-1 +kerning first=321 second=81 amount=-1 +kerning first=86 second=93 amount=1 +kerning first=1168 second=1099 amount=-1 +kerning first=8221 second=258 amount=-1 +kerning first=354 second=345 amount=-1 +kerning first=932 second=74 amount=-1 +kerning first=84 second=46 amount=-1 +kerning first=1050 second=1051 amount=1 +kerning first=354 second=8230 amount=-1 +kerning first=109 second=358 amount=-1 +kerning first=356 second=968 amount=-1 +kerning first=8216 second=289 amount=-1 +kerning first=934 second=933 amount=-1 +kerning first=8221 second=307 amount=-1 +kerning first=356 second=236 amount=-1 +kerning first=932 second=371 amount=-1 +kerning first=1027 second=1111 amount=-1 +kerning first=1114 second=1098 amount=-1 +kerning first=923 second=358 amount=-1 +kerning first=84 second=297 amount=-1 +kerning first=1118 second=8230 amount=-1 +kerning first=358 second=341 amount=-1 +kerning first=8220 second=961 amount=-1 +kerning first=258 second=87 amount=-1 +kerning first=376 second=285 amount=-1 +kerning first=356 second=101 amount=-1 +kerning first=354 second=232 amount=-1 +kerning first=1058 second=1040 amount=-1 +kerning first=358 second=187 amount=-1 +kerning first=8220 second=234 amount=-1 +kerning first=915 second=212 amount=-1 +kerning first=8218 second=89 amount=-1 +kerning first=8230 second=8217 amount=-2 +kerning first=8222 second=376 amount=-1 +kerning first=1168 second=1044 amount=-1 +kerning first=8220 second=354 amount=1 +kerning first=221 second=214 amount=-1 +kerning first=932 second=970 amount=1 +kerning first=261 second=84 amount=-1 +kerning first=354 second=97 amount=-1 +kerning first=89 second=81 amount=-1 +kerning first=1059 second=1035 amount=1 +kerning first=84 second=945 amount=-1 +kerning first=313 second=290 amount=-1 +kerning first=193 second=8216 amount=-1 +kerning first=932 second=353 amount=-1 +kerning first=358 second=963 amount=-1 +kerning first=936 second=193 amount=-1 +kerning first=225 second=358 amount=-1 +kerning first=358 second=235 amount=-1 +kerning first=929 second=192 amount=-1 +kerning first=8216 second=74 amount=-1 +kerning first=1043 second=1092 amount=-1 +kerning first=8217 second=113 amount=-1 +kerning first=933 second=940 amount=-1 +kerning first=34 second=974 amount=-1 +kerning first=1036 second=1095 amount=-1 +kerning first=227 second=932 amount=-1 +kerning first=8204 second=932 amount=-1 +kerning first=376 second=308 amount=-1 +kerning first=356 second=46 amount=-1 +kerning first=39 second=44 amount=-2 +kerning first=910 second=913 amount=-1 +kerning first=197 second=39 amount=-1 +kerning first=221 second=361 amount=-1 +kerning first=192 second=221 amount=-1 +kerning first=8217 second=193 amount=-1 +kerning first=356 second=297 amount=-1 +kerning first=910 second=258 amount=-1 +kerning first=84 second=198 amount=-1 +kerning first=376 second=369 amount=-1 +kerning first=915 second=972 amount=-1 +kerning first=1058 second=1074 amount=-1 +kerning first=319 second=262 amount=-1 +kerning first=192 second=84 amount=-1 +kerning first=173 second=356 amount=-1 +kerning first=34 second=923 amount=-1 +kerning first=8222 second=358 amount=-1 +kerning first=1168 second=1078 amount=-1 +kerning first=8220 second=289 amount=-1 +kerning first=326 second=354 amount=-1 +kerning first=221 second=251 amount=-1 +kerning first=89 second=115 amount=-1 +kerning first=258 second=933 amount=-1 +kerning first=358 second=41 amount=1 +kerning first=84 second=944 amount=-1 +kerning first=313 second=368 amount=-1 +kerning first=356 second=945 amount=-1 +kerning first=933 second=260 amount=-1 +kerning first=253 second=44 amount=-1 +kerning first=84 second=255 amount=-1 +kerning first=8217 second=335 amount=-1 +kerning first=1043 second=171 amount=-1 +kerning first=1038 second=1035 amount=1 +kerning first=331 second=84 amount=-1 +kerning first=1066 second=1063 amount=-1 +kerning first=376 second=242 amount=-1 +kerning first=1027 second=1089 amount=-1 +kerning first=84 second=261 amount=-1 +kerning first=75 second=74 amount=1 +kerning first=932 second=8211 amount=-1 +kerning first=123 second=221 amount=1 +kerning first=84 second=114 amount=-1 +kerning first=8221 second=115 amount=-1 +kerning first=915 second=920 amount=-1 +kerning first=89 second=196 amount=-1 +kerning first=110 second=356 amount=-1 +kerning first=910 second=946 amount=-1 +kerning first=114 second=44 amount=-1 +kerning first=950 second=125 amount=1 +kerning first=123 second=84 amount=1 +kerning first=902 second=221 amount=-1 +kerning first=915 second=266 amount=-1 +kerning first=315 second=89 amount=-1 +kerning first=8220 second=74 amount=-1 +kerning first=319 second=376 amount=-1 +kerning first=932 second=225 amount=-1 +kerning first=84 second=194 amount=-1 +kerning first=45 second=89 amount=-1 +kerning first=356 second=198 amount=-1 +kerning first=8221 second=196 amount=-1 +kerning first=321 second=356 amount=-1 +kerning first=1058 second=1109 amount=-1 +kerning first=1027 second=45 amount=-1 +kerning first=319 second=332 amount=-1 +kerning first=902 second=84 amount=-1 +kerning first=8249 second=933 amount=-1 +kerning first=933 second=948 amount=-1 +kerning first=1168 second=1113 amount=-1 +kerning first=319 second=85 amount=-1 +kerning first=932 second=87 amount=1 +kerning first=354 second=361 amount=-1 +kerning first=89 second=333 amount=-1 +kerning first=376 second=262 amount=-1 +kerning first=1034 second=1026 amount=-1 +kerning first=1059 second=1105 amount=-1 +kerning first=372 second=65 amount=-1 +kerning first=356 second=944 amount=-1 +kerning first=39 second=974 amount=-1 +kerning first=226 second=356 amount=-1 +kerning first=356 second=255 amount=-1 +kerning first=913 second=8216 amount=-1 +kerning first=315 second=34 amount=-1 +kerning first=84 second=337 amount=-1 +kerning first=8221 second=333 amount=-1 +kerning first=356 second=261 amount=-1 +kerning first=932 second=305 amount=-1 +kerning first=354 second=973 amount=-1 +kerning first=358 second=367 amount=-1 +kerning first=356 second=114 amount=-1 +kerning first=915 second=953 amount=-1 +kerning first=354 second=251 amount=-1 +kerning first=89 second=233 amount=-1 +kerning first=87 second=913 amount=-1 +kerning first=321 second=8217 amount=-1 +kerning first=8212 second=376 amount=-1 +kerning first=313 second=214 amount=-1 +kerning first=1043 second=1241 amount=-1 +kerning first=221 second=228 amount=-1 +kerning first=256 second=8216 amount=-1 +kerning first=354 second=110 amount=-1 +kerning first=87 second=258 amount=-1 +kerning first=319 second=358 amount=-1 +kerning first=932 second=273 amount=-1 +kerning first=39 second=923 amount=-1 +kerning first=358 second=972 amount=-1 +kerning first=242 second=358 amount=-1 +kerning first=957 second=8230 amount=-1 +kerning first=84 second=231 amount=-1 +kerning first=8217 second=287 amount=-1 +kerning first=356 second=194 amount=-1 +kerning first=8221 second=233 amount=-1 +kerning first=358 second=250 amount=-1 +kerning first=939 second=173 amount=-1 +kerning first=932 second=277 amount=-1 +kerning first=8216 second=1076 amount=-1 +kerning first=8221 second=356 amount=1 +kerning first=932 second=121 amount=-1 +kerning first=1041 second=1058 amount=-1 +kerning first=974 second=39 amount=-1 +kerning first=916 second=84 amount=-1 +kerning first=84 second=93 amount=1 +kerning first=376 second=332 amount=-1 +kerning first=358 second=109 amount=-1 +kerning first=929 second=74 amount=-1 +kerning first=910 second=196 amount=-1 +kerning first=271 second=8217 amount=1 +kerning first=91 second=86 amount=1 +kerning first=1038 second=1105 amount=-1 +kerning first=1027 second=8212 amount=-1 +kerning first=324 second=932 amount=-1 +kerning first=221 second=248 amount=-1 +kerning first=319 second=199 amount=-1 +kerning first=356 second=337 amount=-1 +kerning first=112 second=932 amount=-1 +kerning first=1058 second=1087 amount=-1 +kerning first=319 second=288 amount=-1 +kerning first=8212 second=358 amount=-1 +kerning first=1168 second=1091 amount=-1 +kerning first=1056 second=1040 amount=-1 +kerning first=354 second=328 amount=-1 +kerning first=89 second=291 amount=-1 +kerning first=76 second=8249 amount=-1 +kerning first=8216 second=273 amount=-1 +kerning first=933 second=197 amount=-1 +kerning first=958 second=93 amount=1 +kerning first=8221 second=8217 amount=-1 +kerning first=372 second=44 amount=-1 +kerning first=8216 second=277 amount=-1 +kerning first=160 second=372 amount=-1 +kerning first=259 second=84 amount=-1 +kerning first=221 second=279 amount=-1 +kerning first=356 second=231 amount=-1 +kerning first=932 second=351 amount=-1 +kerning first=1114 second=1090 amount=-1 +kerning first=1027 second=1102 amount=-1 +kerning first=84 second=285 amount=-1 +kerning first=8221 second=291 amount=-1 +kerning first=358 second=324 amount=-1 +kerning first=76 second=217 amount=-1 +kerning first=195 second=89 amount=-1 +kerning first=8211 second=221 amount=-1 +kerning first=376 second=267 amount=-1 +kerning first=356 second=93 amount=1 +kerning first=915 second=934 amount=-1 +kerning first=354 second=228 amount=-1 +kerning first=224 second=932 amount=-1 +kerning first=910 second=959 amount=-1 +kerning first=76 second=334 amount=-1 +kerning first=1168 second=1035 amount=1 +kerning first=196 second=39 amount=-1 +kerning first=8211 second=84 amount=-1 +kerning first=8217 second=246 amount=-1 +kerning first=936 second=916 amount=-1 +kerning first=932 second=239 amount=-1 +kerning first=194 second=221 amount=-1 +kerning first=915 second=67 amount=-1 +kerning first=8220 second=1076 amount=-1 +kerning first=65 second=376 amount=-1 +kerning first=1027 second=58 amount=-1 +kerning first=358 second=226 amount=-1 +kerning first=319 second=362 amount=-1 +kerning first=91 second=932 amount=1 +kerning first=343 second=46 amount=-1 +kerning first=8217 second=105 amount=-1 +kerning first=376 second=199 amount=-1 +kerning first=933 second=963 amount=-1 +kerning first=1043 second=1084 amount=-1 +kerning first=84 second=308 amount=-1 +kerning first=317 second=262 amount=-1 +kerning first=932 second=100 amount=-1 +kerning first=194 second=84 amount=-1 +kerning first=89 second=363 amount=-1 +kerning first=195 second=34 amount=-1 +kerning first=76 second=216 amount=-1 +kerning first=376 second=288 amount=-1 +kerning first=354 second=248 amount=-1 +kerning first=70 second=230 amount=-1 +kerning first=74 second=125 amount=1 +kerning first=328 second=354 amount=-1 +kerning first=245 second=356 amount=-1 +kerning first=910 second=181 amount=-1 +kerning first=1035 second=1035 amount=-1 +kerning first=84 second=369 amount=-1 +kerning first=356 second=285 amount=-1 +kerning first=915 second=968 amount=-1 +kerning first=321 second=268 amount=-1 +kerning first=89 second=245 amount=-1 +kerning first=1058 second=1066 amount=1 +kerning first=8220 second=273 amount=-1 +kerning first=87 second=196 amount=-1 +kerning first=271 second=107 amount=1 +kerning first=354 second=279 amount=-1 +kerning first=932 second=45 amount=-1 +kerning first=8220 second=277 amount=-1 +kerning first=315 second=8220 amount=-2 +kerning first=1107 second=1076 amount=-1 +kerning first=329 second=358 amount=-1 +kerning first=34 second=260 amount=-1 +kerning first=84 second=242 amount=-1 +kerning first=313 second=89 amount=-1 +kerning first=65 second=358 amount=-1 +kerning first=8221 second=245 amount=-1 +kerning first=317 second=376 amount=-1 +kerning first=358 second=331 amount=-1 +kerning first=8216 second=100 amount=-1 +kerning first=932 second=303 amount=-1 +kerning first=1027 second=1081 amount=-1 +kerning first=229 second=354 amount=-1 +kerning first=356 second=308 amount=-1 +kerning first=317 second=332 amount=-1 +kerning first=358 second=283 amount=-1 +kerning first=317 second=85 amount=-1 +kerning first=315 second=219 amount=-1 +kerning first=358 second=122 amount=-1 +kerning first=76 second=284 amount=-1 +kerning first=221 second=913 amount=-1 +kerning first=89 second=268 amount=-1 +kerning first=1058 second=173 amount=-1 +kerning first=931 second=334 amount=-1 +kerning first=315 second=81 amount=-1 +kerning first=70 second=65 amount=-1 +kerning first=319 second=210 amount=-1 +kerning first=356 second=369 amount=-1 +kerning first=915 second=46 amount=-2 +kerning first=358 second=934 amount=-1 +kerning first=372 second=923 amount=-1 +kerning first=221 second=258 amount=-1 +kerning first=313 second=34 amount=-1 +kerning first=1058 second=1100 amount=-1 +kerning first=271 second=320 amount=1 +kerning first=8217 second=84 amount=1 +kerning first=321 second=86 amount=-1 +kerning first=1168 second=1105 amount=-1 +kerning first=931 second=216 amount=-1 +kerning first=293 second=84 amount=-1 +kerning first=356 second=242 amount=-1 +kerning first=317 second=358 amount=-1 +kerning first=244 second=358 amount=-1 +kerning first=1027 second=1116 amount=-1 +kerning first=173 second=932 amount=-1 +kerning first=932 second=8212 amount=-1 +kerning first=354 second=969 amount=-1 +kerning first=358 second=349 amount=-1 +kerning first=935 second=934 amount=-1 +kerning first=915 second=945 amount=-1 +kerning first=354 second=241 amount=-1 +kerning first=8218 second=356 amount=-1 +kerning first=8212 second=910 amount=-1 +kerning first=310 second=308 amount=1 +kerning first=973 second=39 amount=-1 +kerning first=76 second=364 amount=-1 +kerning first=76 second=8216 amount=-2 +kerning first=80 second=46 amount=-2 +kerning first=1046 second=1051 amount=1 +kerning first=932 second=912 amount=1 +kerning first=260 second=221 amount=-1 +kerning first=8220 second=100 amount=-1 +kerning first=939 second=962 amount=-1 +kerning first=932 second=253 amount=-1 +kerning first=358 second=968 amount=-1 +kerning first=936 second=195 amount=-1 +kerning first=319 second=173 amount=-1 +kerning first=8217 second=265 amount=-1 +kerning first=317 second=199 amount=-1 +kerning first=86 second=301 amount=1 +kerning first=358 second=236 amount=-1 +kerning first=110 second=932 amount=-1 +kerning first=923 second=936 amount=-1 +kerning first=932 second=257 amount=-1 +kerning first=221 second=81 amount=-1 +kerning first=376 second=210 amount=-1 +kerning first=1027 second=1060 amount=-1 +kerning first=933 second=972 amount=-1 +kerning first=260 second=84 amount=-1 +kerning first=1043 second=1097 amount=-1 +kerning first=317 second=288 amount=-1 +kerning first=354 second=913 amount=-1 +kerning first=932 second=113 amount=-1 +kerning first=39 second=260 amount=-1 +kerning first=345 second=8230 amount=-1 +kerning first=89 second=230 amount=-1 +kerning first=358 second=101 amount=-1 +kerning first=121 second=8230 amount=-1 +kerning first=915 second=198 amount=-2 +kerning first=321 second=932 amount=-1 +kerning first=354 second=258 amount=-1 +kerning first=8230 second=939 amount=-1 +kerning first=931 second=284 amount=-1 +kerning first=8217 second=195 amount=-1 +kerning first=70 second=44 amount=-1 +kerning first=84 second=380 amount=-1 +kerning first=932 second=193 amount=-1 +kerning first=195 second=8220 amount=-1 +kerning first=936 second=8230 amount=-1 +kerning first=915 second=944 amount=-1 +kerning first=354 second=307 amount=-1 +kerning first=1058 second=1079 amount=-1 +kerning first=192 second=89 amount=-1 +kerning first=197 second=376 amount=-1 +kerning first=1168 second=1083 amount=-1 +kerning first=226 second=932 amount=-1 +kerning first=939 second=256 amount=-1 +kerning first=89 second=271 amount=-1 +kerning first=34 second=197 amount=-1 +kerning first=358 second=46 amount=-1 +kerning first=193 second=39 amount=-1 +kerning first=160 second=354 amount=-1 +kerning first=84 second=358 amount=1 +kerning first=8217 second=345 amount=-1 +kerning first=1043 second=8211 amount=-1 +kerning first=950 second=41 amount=1 +kerning first=8216 second=113 amount=-1 +kerning first=221 second=115 amount=-1 +kerning first=932 second=335 amount=-1 +kerning first=376 second=252 amount=-1 +kerning first=8217 second=8230 amount=-2 +kerning first=1027 second=1094 amount=-1 +kerning first=84 second=267 amount=-1 +kerning first=376 second=173 amount=-1 +kerning first=8221 second=271 amount=-1 +kerning first=317 second=362 amount=-1 +kerning first=76 second=212 amount=-1 +kerning first=358 second=297 amount=-1 +kerning first=341 second=46 amount=-1 +kerning first=80 second=198 amount=-1 +kerning first=84 second=119 amount=-1 +kerning first=923 second=372 amount=-1 +kerning first=910 second=951 amount=-1 +kerning first=1091 second=8230 amount=-1 +kerning first=372 second=125 amount=1 +kerning first=192 second=34 amount=-1 +kerning first=376 second=111 amount=-1 +kerning first=915 second=194 amount=-2 +kerning first=357 second=8217 amount=1 +kerning first=315 second=356 amount=-1 +kerning first=8216 second=193 amount=-1 +kerning first=123 second=89 amount=1 +kerning first=221 second=196 amount=-1 +kerning first=246 second=356 amount=-1 +kerning first=8217 second=232 amount=-1 +kerning first=89 second=65 amount=-1 +kerning first=45 second=356 amount=-1 +kerning first=356 second=380 amount=-1 +kerning first=8221 second=932 amount=1 +kerning first=111 second=354 amount=-1 +kerning first=932 second=227 amount=-1 +kerning first=915 second=59 amount=-1 +kerning first=358 second=945 amount=-1 +kerning first=1033 second=1035 amount=-1 +kerning first=321 second=370 amount=-1 +kerning first=1058 second=1114 amount=-1 +kerning first=1043 second=1076 amount=-1 +kerning first=902 second=89 amount=-1 +kerning first=197 second=358 amount=-1 +kerning first=1168 second=1119 amount=-1 +kerning first=89 second=347 amount=-1 +kerning first=8221 second=65 amount=-1 +kerning first=8216 second=335 amount=-1 +kerning first=221 second=333 amount=-1 +kerning first=313 second=8220 amount=-2 +kerning first=356 second=358 amount=1 +kerning first=1027 second=8250 amount=-1 +kerning first=295 second=358 amount=-1 +kerning first=1114 second=1118 amount=-1 +kerning first=173 second=939 amount=-1 +kerning first=315 second=8217 amount=-1 +kerning first=84 second=343 amount=-1 +kerning first=8221 second=347 amount=-1 +kerning first=356 second=267 amount=-1 +kerning first=80 second=194 amount=-1 +kerning first=356 second=119 amount=-1 +kerning first=228 second=354 amount=-1 +kerning first=354 second=382 amount=-1 +kerning first=1058 second=1058 amount=1 +kerning first=1090 second=46 amount=-1 +kerning first=358 second=198 amount=-1 +kerning first=902 second=34 amount=-1 +kerning first=313 second=219 amount=-1 +kerning first=70 second=259 amount=-1 +kerning first=221 second=233 amount=-1 +kerning first=354 second=115 amount=-1 +kerning first=89 second=99 amount=-1 +kerning first=8222 second=372 amount=-1 +kerning first=84 second=965 amount=-1 +kerning first=8220 second=113 amount=-1 +kerning first=358 second=944 amount=-1 +kerning first=84 second=237 amount=-1 +kerning first=8221 second=238 amount=-1 +kerning first=313 second=81 amount=-1 +kerning first=317 second=210 amount=-1 +kerning first=39 second=197 amount=-1 +kerning first=358 second=255 amount=-1 +kerning first=1043 second=1111 amount=-1 +kerning first=932 second=287 amount=-1 +kerning first=376 second=224 amount=-1 +kerning first=76 second=920 amount=-1 +kerning first=1041 second=1063 amount=-1 +kerning first=70 second=923 amount=-1 +kerning first=358 second=261 amount=-1 +kerning first=8221 second=99 amount=-1 +kerning first=1034 second=1066 amount=-1 +kerning first=354 second=196 amount=-1 +kerning first=358 second=114 amount=-1 +kerning first=8220 second=193 amount=-1 +kerning first=931 second=212 amount=-1 +kerning first=76 second=266 amount=-1 +kerning first=187 second=354 amount=-1 +kerning first=913 second=39 amount=-1 +kerning first=321 second=213 amount=-1 +kerning first=89 second=44 amount=-1 +kerning first=356 second=343 amount=-1 +kerning first=98 second=84 amount=-1 +kerning first=241 second=358 amount=-1 +kerning first=102 second=34 amount=1 +kerning first=910 second=65 amount=-1 +kerning first=939 second=192 amount=-1 +kerning first=1058 second=1092 amount=-1 +kerning first=358 second=194 amount=-1 +kerning first=376 second=339 amount=-1 +kerning first=245 second=932 amount=-1 +kerning first=1168 second=1096 amount=-1 +kerning first=354 second=333 amount=-1 +kerning first=8220 second=335 amount=-1 +kerning first=916 second=34 amount=-1 +kerning first=372 second=260 amount=-1 +kerning first=256 second=39 amount=-1 +kerning first=8221 second=44 amount=-2 +kerning first=356 second=965 amount=-1 +kerning first=929 second=912 amount=1 +kerning first=8216 second=287 amount=-1 +kerning first=258 second=221 amount=-1 +kerning first=221 second=291 amount=-1 +kerning first=356 second=237 amount=-1 +kerning first=317 second=173 amount=-1 +kerning first=932 second=365 amount=-1 +kerning first=1027 second=1108 amount=-1 +kerning first=195 second=356 amount=-1 +kerning first=84 second=301 amount=-1 +kerning first=8221 second=299 amount=-1 +kerning first=354 second=959 amount=-1 +kerning first=971 second=34 amount=-1 +kerning first=358 second=337 amount=-1 +kerning first=258 second=84 amount=-1 +kerning first=376 second=275 amount=-1 +kerning first=354 second=233 amount=-1 +kerning first=89 second=213 amount=-1 +kerning first=70 second=229 amount=-1 +kerning first=910 second=966 amount=-1 +kerning first=8218 second=86 amount=-1 +kerning first=354 second=356 amount=1 +kerning first=119 second=8230 amount=-1 +kerning first=8211 second=89 amount=-1 +kerning first=932 second=941 amount=-1 +kerning first=1059 second=44 amount=-1 +kerning first=1059 second=1032 amount=-1 +kerning first=74 second=41 amount=1 +kerning first=939 second=961 amount=-1 +kerning first=932 second=246 amount=-1 +kerning first=1058 second=171 amount=-1 +kerning first=358 second=231 amount=-1 +kerning first=929 second=193 amount=-1 +kerning first=319 second=372 amount=-1 +kerning first=192 second=8220 amount=-1 +kerning first=934 second=8230 amount=-1 +kerning first=8217 second=110 amount=-1 +kerning first=1043 second=1089 amount=-1 +kerning first=194 second=89 amount=-1 +kerning first=932 second=105 amount=-1 +kerning first=196 second=376 amount=-1 +kerning first=195 second=8217 amount=-1 +kerning first=931 second=920 amount=-1 +kerning first=358 second=93 amount=1 +kerning first=1100 second=8221 amount=-1 +kerning first=40 second=106 amount=1 +kerning first=221 second=363 amount=-1 +kerning first=257 second=358 amount=-1 +kerning first=40 second=1095 amount=-1 +kerning first=315 second=268 amount=-1 +kerning first=1027 second=8230 amount=-1 +kerning first=931 second=266 amount=-1 +kerning first=932 second=916 amount=-1 +kerning first=356 second=301 amount=-1 +kerning first=910 second=44 amount=-1 +kerning first=915 second=942 amount=-1 +kerning first=1043 second=45 amount=-1 +kerning first=89 second=249 amount=-1 +kerning first=955 second=34 amount=-1 +kerning first=8216 second=941 amount=-1 +kerning first=80 second=308 amount=-1 +kerning first=123 second=309 amount=1 +kerning first=1168 second=1075 amount=-1 +kerning first=923 second=8221 amount=-1 +kerning first=354 second=291 amount=-1 +kerning first=194 second=34 amount=-1 +kerning first=118 second=46 amount=-1 +kerning first=89 second=259 amount=-1 +kerning first=8216 second=246 amount=-1 +kerning first=8220 second=287 amount=-1 +kerning first=221 second=245 amount=-1 +kerning first=84 second=971 amount=-1 +kerning first=313 second=356 amount=-1 +kerning first=243 second=356 amount=-1 +kerning first=1038 second=44 amount=-1 +kerning first=84 second=252 amount=-1 +kerning first=87 second=65 amount=-1 +kerning first=8217 second=328 amount=-1 +kerning first=8218 second=932 amount=-1 +kerning first=1038 second=1032 amount=-1 +kerning first=109 second=354 amount=-1 +kerning first=84 second=173 amount=-1 +kerning first=933 second=46 amount=-1 +kerning first=8221 second=160 amount=-1 +kerning first=160 second=87 amount=-1 +kerning first=902 second=8220 amount=-1 +kerning first=376 second=243 amount=-1 +kerning first=1027 second=1086 amount=-1 +kerning first=319 second=171 amount=-1 +kerning first=932 second=8250 amount=-1 +kerning first=89 second=923 amount=-1 +kerning first=358 second=285 amount=-1 +kerning first=196 second=358 amount=-1 +kerning first=84 second=111 amount=-1 +kerning first=8221 second=112 amount=-1 +kerning first=923 second=354 amount=-1 +kerning first=376 second=103 amount=-1 +kerning first=8216 second=916 amount=-1 +kerning first=104 second=356 amount=-1 +kerning first=1058 second=1241 amount=-1 +kerning first=76 second=67 amount=-1 +kerning first=337 second=84 amount=-1 +kerning first=932 second=949 amount=-1 +kerning first=915 second=262 amount=-1 +kerning first=315 second=86 amount=-1 +kerning first=319 second=220 amount=-1 +kerning first=8221 second=923 amount=-1 +kerning first=8204 second=8216 amount=-1 +kerning first=65 second=936 amount=-1 +kerning first=1033 second=8217 amount=-1 +kerning first=221 second=268 amount=-1 +kerning first=313 second=8217 amount=-1 +kerning first=372 second=197 amount=-1 +kerning first=933 second=945 amount=-1 +kerning first=40 second=376 amount=1 +kerning first=225 second=354 amount=-1 +kerning first=932 second=84 amount=1 +kerning first=354 second=363 amount=-1 +kerning first=358 second=308 amount=-1 +kerning first=376 second=256 amount=-1 +kerning first=248 second=84 amount=-1 +kerning first=356 second=971 amount=-1 +kerning first=102 second=8220 amount=1 +kerning first=1028 second=1026 amount=1 +kerning first=1043 second=8212 amount=-1 +kerning first=356 second=252 amount=-1 +kerning first=356 second=173 amount=-1 +kerning first=932 second=378 amount=-1 +kerning first=8217 second=248 amount=-1 +kerning first=8221 second=326 amount=-1 +kerning first=358 second=369 amount=-1 +kerning first=8220 second=941 amount=-1 +kerning first=356 second=111 amount=-1 +kerning first=354 second=245 amount=-1 +kerning first=86 second=256 amount=-1 +kerning first=89 second=229 amount=-1 +kerning first=8220 second=246 amount=-1 +kerning first=376 second=171 amount=-1 +kerning first=76 second=360 amount=-1 +kerning first=8216 second=949 amount=-1 +kerning first=261 second=356 amount=-1 +kerning first=933 second=198 amount=-1 +kerning first=915 second=332 amount=-1 +kerning first=8222 second=354 amount=-1 +kerning first=84 second=224 amount=-1 +kerning first=87 second=44 amount=-1 +kerning first=8217 second=279 amount=-1 +kerning first=358 second=242 amount=-1 +kerning first=8216 second=84 amount=1 +kerning first=1043 second=1102 amount=-1 +kerning first=932 second=265 amount=-1 +kerning first=260 second=89 amount=-1 +kerning first=40 second=358 amount=1 +kerning first=65 second=372 amount=-1 +kerning first=932 second=118 amount=-1 +kerning first=315 second=932 amount=-1 +kerning first=8220 second=916 amount=-1 +kerning first=1050 second=1095 amount=-1 +kerning first=246 second=932 amount=-1 +kerning first=1034 second=1058 amount=-1 +kerning first=910 second=923 amount=-1 +kerning first=45 second=932 amount=-1 +kerning first=70 second=260 amount=-1 +kerning first=319 second=927 amount=-1 +kerning first=221 second=230 amount=-1 +kerning first=958 second=955 amount=1 +kerning first=931 second=67 amount=-1 +kerning first=932 second=195 amount=-1 +kerning first=192 second=356 amount=-1 +kerning first=84 second=339 amount=-1 +kerning first=1043 second=58 amount=-1 +kerning first=1058 second=1084 amount=-1 +kerning first=319 second=286 amount=-1 +kerning first=260 second=34 amount=-1 +kerning first=1168 second=1088 amount=-1 +kerning first=89 second=281 amount=-1 +kerning first=76 second=39 amount=-1 +kerning first=933 second=194 amount=-1 +kerning first=1113 second=1091 amount=-1 +kerning first=89 second=125 amount=1 +kerning first=372 second=41 amount=1 +kerning first=331 second=356 amount=-1 +kerning first=8216 second=265 amount=-1 +kerning first=221 second=271 amount=-1 +kerning first=84 second=312 amount=-1 +kerning first=356 second=224 amount=-1 +kerning first=933 second=59 amount=-1 +kerning first=932 second=345 amount=-1 +kerning first=1027 second=1099 amount=-1 +kerning first=84 second=275 amount=-1 +kerning first=319 second=8221 amount=-1 +kerning first=8221 second=281 amount=-1 +kerning first=317 second=372 amount=-1 +kerning first=932 second=8230 amount=-1 +kerning first=194 second=8220 amount=-1 +kerning first=76 second=218 amount=-1 +kerning first=195 second=86 amount=-1 +kerning first=8220 second=949 amount=-1 +kerning first=376 second=263 amount=-1 +kerning first=939 second=8211 amount=-1 +kerning first=46 second=8221 amount=-2 +kerning first=193 second=376 amount=-1 +kerning first=192 second=8217 amount=-1 +kerning first=915 second=199 amount=-1 +kerning first=1168 second=44 amount=-1 +kerning first=1028 second=1095 amount=-1 +kerning first=123 second=356 amount=1 +kerning first=1168 second=1032 amount=-1 +kerning first=315 second=370 amount=-1 +kerning first=8216 second=195 amount=-1 +kerning first=1098 second=8221 amount=-1 +kerning first=8217 second=241 amount=-1 +kerning first=915 second=288 amount=-1 +kerning first=936 second=913 amount=-1 +kerning first=354 second=86 amount=1 +kerning first=8220 second=84 amount=1 +kerning first=313 second=268 amount=-1 +kerning first=932 second=232 amount=-1 +kerning first=929 second=916 amount=-1 +kerning first=902 second=356 amount=-1 +kerning first=376 second=927 amount=-1 +kerning first=356 second=339 amount=-1 +kerning first=319 second=354 amount=-1 +kerning first=221 second=65 amount=-1 +kerning first=1043 second=1081 amount=-1 +kerning first=376 second=192 amount=-1 +kerning first=936 second=258 amount=-1 +kerning first=1027 second=1044 amount=-1 +kerning first=242 second=354 amount=-1 +kerning first=932 second=97 amount=-1 +kerning first=376 second=286 amount=-1 +kerning first=354 second=230 amount=-1 +kerning first=306 second=125 amount=1 +kerning first=221 second=347 amount=-1 +kerning first=8217 second=913 amount=-1 +kerning first=356 second=312 amount=-1 +kerning first=8216 second=8230 amount=-2 +kerning first=86 second=192 amount=-1 +kerning first=356 second=275 amount=-1 +kerning first=358 second=380 amount=-1 +kerning first=8217 second=258 amount=-1 +kerning first=197 second=936 amount=-1 +kerning first=915 second=965 amount=-1 +kerning first=317 second=171 amount=-1 +kerning first=89 second=244 amount=-1 +kerning first=87 second=923 amount=-1 +kerning first=193 second=358 amount=-1 +kerning first=902 second=8217 amount=-1 +kerning first=271 second=104 amount=1 +kerning first=354 second=271 amount=-1 +kerning first=8216 second=232 amount=-1 +kerning first=8220 second=265 amount=-1 +kerning first=8217 second=307 amount=-1 +kerning first=195 second=932 amount=-1 +kerning first=8212 second=354 amount=-1 +kerning first=84 second=962 amount=-1 +kerning first=326 second=84 amount=-1 +kerning first=84 second=243 amount=-1 +kerning first=313 second=86 amount=-1 +kerning first=8221 second=244 amount=-1 +kerning first=317 second=220 amount=-1 +kerning first=358 second=358 amount=1 +kerning first=34 second=46 amount=-2 +kerning first=1043 second=1116 amount=-1 +kerning first=221 second=99 amount=-1 +kerning first=376 second=234 amount=-1 +kerning first=1027 second=1078 amount=-1 +kerning first=321 second=8249 amount=-1 +kerning first=916 second=356 amount=-1 +kerning first=84 second=372 amount=1 +kerning first=354 second=932 amount=1 +kerning first=358 second=267 amount=-1 +kerning first=84 second=103 amount=-1 +kerning first=315 second=213 amount=-1 +kerning first=70 second=197 amount=-1 +kerning first=358 second=119 amount=-1 +kerning first=8220 second=195 amount=-1 +kerning first=45 second=939 amount=-1 +kerning first=923 second=87 amount=-1 +kerning first=89 second=260 amount=-1 +kerning first=1026 second=1026 amount=-1 +kerning first=321 second=217 amount=-1 +kerning first=354 second=65 amount=-1 +kerning first=319 second=211 amount=-1 +kerning first=102 second=8217 amount=1 +kerning first=321 second=334 amount=-1 +kerning first=1058 second=1097 amount=-1 +kerning first=271 second=314 amount=1 +kerning first=1043 second=1060 amount=-1 +kerning first=221 second=44 amount=-1 +kerning first=8230 second=8216 amount=-1 +kerning first=1168 second=1101 amount=-1 +kerning first=84 second=256 amount=-1 +kerning first=8221 second=260 amount=-1 +kerning first=354 second=347 amount=-1 +kerning first=373 second=8230 amount=-1 +kerning first=913 second=376 amount=-1 +kerning first=916 second=8217 amount=-1 +kerning first=197 second=372 amount=-1 +kerning first=259 second=356 amount=-1 +kerning first=89 second=8249 amount=-1 +kerning first=8220 second=8230 amount=-2 +kerning first=356 second=962 amount=-1 +kerning first=356 second=243 amount=-1 +kerning first=932 second=361 amount=-1 +kerning first=1027 second=1113 amount=-1 +kerning first=260 second=8220 amount=-1 +kerning first=321 second=216 amount=-1 +kerning first=356 second=372 amount=1 +kerning first=354 second=966 amount=-1 +kerning first=358 second=343 amount=-1 +kerning first=258 second=89 amount=-1 +kerning first=84 second=171 amount=-1 +kerning first=256 second=376 amount=-1 +kerning first=376 second=289 amount=-1 +kerning first=65 second=8221 amount=-1 +kerning first=356 second=103 amount=-1 +kerning first=354 second=238 amount=-1 +kerning first=910 second=940 amount=-1 +kerning first=8220 second=232 amount=-1 +kerning first=313 second=932 amount=-1 +kerning first=915 second=210 amount=-1 +kerning first=8211 second=356 amount=-1 +kerning first=243 second=932 amount=-1 +kerning first=89 second=334 amount=-1 +kerning first=34 second=198 amount=-1 +kerning first=221 second=213 amount=-1 +kerning first=932 second=973 amount=-1 +kerning first=354 second=99 amount=-1 +kerning first=317 second=927 amount=-1 +kerning first=932 second=251 amount=-1 +kerning first=358 second=965 amount=-1 +kerning first=936 second=196 amount=-1 +kerning first=1058 second=8211 amount=-1 +kerning first=8222 second=87 amount=-1 +kerning first=255 second=8230 amount=-1 +kerning first=929 second=195 amount=-1 +kerning first=358 second=237 amount=-1 +kerning first=923 second=933 amount=-1 +kerning first=1043 second=1094 amount=-1 +kerning first=194 second=356 amount=-1 +kerning first=329 second=354 amount=-1 +kerning first=376 second=211 amount=-1 +kerning first=8217 second=115 amount=-1 +kerning first=933 second=942 amount=-1 +kerning first=104 second=932 amount=-1 +kerning first=65 second=354 amount=-1 +kerning first=356 second=256 amount=-1 +kerning first=317 second=286 amount=-1 +kerning first=932 second=110 amount=-1 +kerning first=913 second=358 amount=-1 +kerning first=258 second=34 amount=-1 +kerning first=1107 second=8230 amount=-1 +kerning first=89 second=216 amount=-1 +kerning first=39 second=46 amount=-2 +kerning first=376 second=74 amount=-1 +kerning first=87 second=125 amount=1 +kerning first=950 second=93 amount=1 +kerning first=8250 second=376 amount=-1 +kerning first=8217 second=196 amount=-1 +kerning first=354 second=44 amount=-1 +kerning first=910 second=260 amount=-1 +kerning first=1034 second=8221 amount=-1 +kerning first=256 second=358 amount=-1 +kerning first=915 second=971 amount=-1 +kerning first=356 second=171 amount=-1 +kerning first=317 second=8221 amount=-1 +kerning first=321 second=284 amount=-1 +kerning first=376 second=371 amount=-1 +kerning first=1058 second=1076 amount=-1 +kerning first=929 second=8230 amount=-2 +kerning first=319 second=264 amount=-1 +kerning first=192 second=86 amount=-1 +kerning first=955 second=8217 amount=-1 +kerning first=44 second=8221 amount=-2 +kerning first=1168 second=1080 amount=-1 +kerning first=915 second=173 amount=-1 +kerning first=354 second=299 amount=-1 +kerning first=194 second=8217 amount=-1 +kerning first=89 second=269 amount=-1 +kerning first=1118 second=44 amount=-1 +kerning first=34 second=194 amount=-1 +kerning first=221 second=249 amount=-1 +kerning first=195 second=939 amount=-1 +kerning first=939 second=45 amount=-1 +kerning first=89 second=117 amount=-1 +kerning first=1059 second=1072 amount=-1 +kerning first=313 second=370 amount=-1 +kerning first=221 second=259 amount=-1 +kerning first=253 second=46 amount=-1 +kerning first=8217 second=333 amount=-1 +kerning first=1043 second=8250 amount=-1 +kerning first=1169 second=1076 amount=-1 +kerning first=932 second=328 amount=-1 +kerning first=376 second=353 amount=-1 +kerning first=1027 second=1091 amount=-1 +kerning first=84 second=263 amount=-1 +kerning first=319 second=8211 amount=-1 +kerning first=261 second=932 amount=-1 +kerning first=317 second=354 amount=-1 +kerning first=8221 second=269 amount=-1 +kerning first=358 second=301 amount=-1 +kerning first=244 second=354 amount=-1 +kerning first=89 second=197 amount=-1 +kerning first=910 second=948 amount=-1 +kerning first=221 second=923 amount=-1 +kerning first=114 second=46 amount=-1 +kerning first=1113 second=8217 amount=-1 +kerning first=89 second=284 amount=-1 +kerning first=8250 second=358 amount=-1 +kerning first=123 second=86 amount=1 +kerning first=8217 second=233 amount=-1 +kerning first=932 second=228 amount=-1 +kerning first=84 second=192 amount=-1 +kerning first=8217 second=356 amount=1 +kerning first=8221 second=197 amount=-1 +kerning first=321 second=364 amount=-1 +kerning first=1058 second=1111 amount=-1 +kerning first=39 second=198 amount=-1 +kerning first=902 second=86 amount=-1 +kerning first=1027 second=1035 amount=1 +kerning first=196 second=936 amount=-1 +kerning first=321 second=8216 amount=-2 +kerning first=319 second=87 amount=-1 +kerning first=354 second=373 amount=-1 +kerning first=376 second=264 amount=-1 +kerning first=293 second=356 amount=-1 +kerning first=192 second=932 amount=-1 +kerning first=1038 second=1072 amount=-1 +kerning first=328 second=84 amount=-1 +kerning first=8221 second=341 amount=-1 +kerning first=356 second=263 amount=-1 +kerning first=932 second=248 amount=-1 +kerning first=354 second=974 amount=-1 +kerning first=939 second=8212 amount=-1 +kerning first=354 second=249 amount=-1 +kerning first=89 second=235 amount=-1 +kerning first=376 second=8211 amount=-1 +kerning first=8217 second=8217 amount=-1 +kerning first=331 second=932 amount=-1 +kerning first=160 second=902 amount=-1 +kerning first=1168 second=1059 amount=1 +kerning first=313 second=213 amount=-1 +kerning first=354 second=259 amount=-1 +kerning first=333 second=358 amount=-1 +kerning first=221 second=229 amount=-1 +kerning first=354 second=112 amount=-1 +kerning first=87 second=260 amount=-1 +kerning first=84 second=961 amount=-1 +kerning first=358 second=971 amount=-1 +kerning first=84 second=234 amount=-1 +kerning first=8217 second=291 amount=-1 +kerning first=356 second=192 amount=-1 +kerning first=8221 second=235 amount=-1 +kerning first=260 second=356 amount=-1 +kerning first=317 second=211 amount=-1 +kerning first=39 second=194 amount=-1 +kerning first=358 second=252 amount=-1 +kerning first=1043 second=1108 amount=-1 +kerning first=932 second=279 amount=-1 +kerning first=376 second=225 amount=-1 +kerning first=358 second=173 amount=-1 +kerning first=123 second=932 amount=1 +kerning first=84 second=354 amount=1 +kerning first=354 second=923 amount=-1 +kerning first=229 second=84 amount=-1 +kerning first=1034 second=1063 amount=-1 +kerning first=358 second=111 amount=-1 +kerning first=197 second=8221 amount=-1 +kerning first=76 second=262 amount=-1 +kerning first=196 second=372 amount=-1 +kerning first=902 second=932 amount=-1 +kerning first=910 second=197 amount=-1 +kerning first=8216 second=248 amount=-1 +kerning first=321 second=212 amount=-1 +kerning first=89 second=41 amount=1 +kerning first=46 second=933 amount=-1 +kerning first=1068 second=1035 amount=-1 +kerning first=258 second=8220 amount=-1 +kerning first=939 second=193 amount=-1 +kerning first=947 second=8230 amount=-1 +kerning first=1058 second=1089 amount=-1 +kerning first=260 second=8217 amount=-1 +kerning first=1168 second=1093 amount=-1 +kerning first=354 second=326 amount=-1 +kerning first=1046 second=1095 amount=-1 +kerning first=197 second=354 amount=-1 +kerning first=939 second=58 amount=-1 +kerning first=969 second=39 amount=-1 +kerning first=74 second=93 amount=1 +kerning first=372 second=46 amount=-1 +kerning first=356 second=961 amount=-1 +kerning first=8216 second=279 amount=-1 +kerning first=34 second=308 amount=-1 +kerning first=221 second=281 amount=-1 +kerning first=356 second=234 amount=-1 +kerning first=1043 second=8230 amount=-1 +kerning first=97 second=358 amount=-1 +kerning first=221 second=125 amount=1 +kerning first=376 second=273 amount=-1 +kerning first=1027 second=1105 amount=-1 +kerning first=8216 second=1113 amount=-1 +kerning first=84 second=289 amount=-1 +kerning first=356 second=354 amount=1 +kerning first=76 second=376 amount=-1 +kerning first=295 second=354 amount=-1 +kerning first=957 second=44 amount=-1 +kerning first=1058 second=45 amount=-1 +kerning first=376 second=277 amount=-1 +kerning first=354 second=229 amount=-1 +kerning first=89 second=212 amount=-1 +kerning first=8212 second=933 amount=-1 +kerning first=70 second=226 amount=-1 +kerning first=910 second=963 amount=-1 +kerning first=76 second=332 amount=-1 +kerning first=1168 second=1038 amount=1 +kerning first=76 second=85 amount=-1 +kerning first=932 second=969 amount=-1 +kerning first=8217 second=245 amount=-1 +kerning first=916 second=932 amount=-1 +kerning first=932 second=241 amount=-1 +kerning first=306 second=41 amount=1 +kerning first=358 second=224 amount=-1 +kerning first=319 second=366 amount=-1 +kerning first=1043 second=1086 amount=-1 +kerning first=1168 second=8249 amount=-1 +kerning first=1056 second=1076 amount=-1 +kerning first=317 second=264 amount=-1 +kerning first=89 second=367 amount=-1 +kerning first=194 second=86 amount=-1 +kerning first=84 second=74 amount=-1 +kerning first=65 second=87 amount=-1 +kerning first=40 second=372 amount=1 +kerning first=8220 second=248 amount=-1 +kerning first=192 second=939 amount=-1 +kerning first=321 second=920 amount=-1 +kerning first=931 second=262 amount=-1 +kerning first=932 second=913 amount=-1 +kerning first=84 second=371 amount=-1 +kerning first=356 second=289 amount=-1 +kerning first=76 second=358 amount=-1 +kerning first=376 second=351 amount=-1 +kerning first=915 second=962 amount=-1 +kerning first=321 second=266 amount=-1 +kerning first=259 second=932 amount=-1 +kerning first=317 second=8211 amount=-1 +kerning first=358 second=339 amount=-1 +kerning first=89 second=250 amount=-1 +kerning first=372 second=198 amount=-1 +kerning first=932 second=258 amount=-1 +kerning first=241 second=354 amount=-1 +kerning first=8216 second=969 amount=-1 +kerning first=1168 second=1072 amount=-1 +kerning first=87 second=197 amount=-1 +kerning first=319 second=45 amount=-1 +kerning first=1036 second=1033 amount=1 +kerning first=354 second=281 amount=-1 +kerning first=8220 second=279 amount=-1 +kerning first=160 second=221 amount=-1 +kerning first=221 second=244 amount=-1 +kerning first=354 second=125 amount=1 +kerning first=315 second=8249 amount=-1 +kerning first=8204 second=8218 amount=-2 +kerning first=932 second=307 amount=-1 +kerning first=8220 second=1113 amount=-1 +kerning first=1058 second=8212 amount=-1 +kerning first=84 second=353 amount=-1 +kerning first=358 second=312 amount=-1 +kerning first=160 second=84 amount=-1 +kerning first=376 second=239 amount=1 +kerning first=1027 second=1083 amount=-1 +kerning first=8211 second=932 amount=-1 +kerning first=89 second=920 amount=-1 +kerning first=39 second=308 amount=-1 +kerning first=76 second=199 amount=-1 +kerning first=358 second=275 amount=-1 +kerning first=193 second=936 amount=-1 +kerning first=8221 second=109 amount=-1 +kerning first=356 second=74 amount=-1 +kerning first=317 second=87 amount=-1 +kerning first=315 second=217 amount=-1 +kerning first=376 second=100 amount=-1 +kerning first=76 second=288 amount=-1 +kerning first=8216 second=913 amount=-1 +kerning first=902 second=939 amount=-1 +kerning first=89 second=266 amount=-1 +kerning first=315 second=334 amount=-1 +kerning first=931 second=332 amount=-1 +kerning first=98 second=356 amount=-1 +kerning first=194 second=932 amount=-1 +kerning first=915 second=256 amount=-2 +kerning first=86 second=239 amount=1 +kerning first=356 second=371 amount=-1 +kerning first=65 second=933 amount=-1 +kerning first=8216 second=258 amount=-1 +kerning first=221 second=260 amount=-1 +kerning first=111 second=84 amount=-1 +kerning first=1058 second=1102 amount=-1 +kerning first=372 second=194 amount=-1 +kerning first=8216 second=1035 amount=1 +kerning first=1168 second=1107 amount=-1 +kerning first=319 second=79 amount=-1 +kerning first=315 second=216 amount=-1 +kerning first=335 second=358 amount=-1 +kerning first=376 second=45 amount=-1 +kerning first=356 second=353 amount=-1 +kerning first=8216 second=8220 amount=-1 +kerning first=221 second=8249 amount=-1 +kerning first=1027 second=1119 amount=-1 +kerning first=258 second=356 amount=-1 +kerning first=257 second=354 amount=-1 +kerning first=319 second=8212 amount=-1 +kerning first=8221 second=324 amount=-1 +kerning first=354 second=940 amount=-1 +kerning first=8220 second=969 amount=-1 +kerning first=1058 second=58 amount=-1 +kerning first=84 second=8211 amount=-1 +kerning first=915 second=947 amount=-1 +kerning first=354 second=244 amount=-1 +kerning first=89 second=226 amount=-1 +kerning first=910 second=972 amount=-1 +kerning first=76 second=362 amount=-1 +kerning first=228 second=84 amount=-1 +kerning first=80 second=256 amount=-1 +kerning first=310 second=74 amount=1 +kerning first=196 second=8221 amount=-1 +kerning first=193 second=372 amount=-1 +kerning first=1026 second=1066 amount=-1 +kerning first=916 second=939 amount=-1 +kerning first=939 second=941 amount=-1 +kerning first=932 second=382 amount=-1 +kerning first=358 second=962 amount=-1 +kerning first=221 second=334 amount=-1 +kerning first=84 second=225 amount=-1 +kerning first=87 second=41 amount=1 +kerning first=8217 second=271 amount=-1 +kerning first=1033 second=1059 amount=-1 +kerning first=358 second=243 amount=-1 +kerning first=44 second=933 amount=-1 +kerning first=1043 second=1099 amount=-1 +kerning first=1168 second=187 amount=-1 +kerning first=1066 second=1035 amount=-1 +kerning first=260 second=86 amount=-1 +kerning first=1075 second=1076 amount=-1 +kerning first=8230 second=39 amount=-1 +kerning first=271 second=322 amount=1 +kerning first=932 second=115 amount=-1 +kerning first=358 second=372 amount=1 +kerning first=936 second=65 amount=-1 +kerning first=8220 second=913 amount=-1 +kerning first=258 second=8217 amount=-1 +kerning first=84 second=87 amount=1 +kerning first=933 second=173 amount=-1 +kerning first=187 second=221 amount=-1 +kerning first=358 second=103 amount=-1 +kerning first=372 second=93 amount=1 +kerning first=931 second=199 amount=-1 +kerning first=376 second=79 amount=-1 +kerning first=196 second=354 amount=-1 +kerning first=8217 second=932 amount=1 +kerning first=354 second=260 amount=-1 +kerning first=1114 second=8221 amount=-1 +kerning first=315 second=284 amount=-1 +kerning first=8220 second=258 amount=-1 +kerning first=931 second=288 amount=-1 +kerning first=221 second=216 amount=-1 +kerning first=187 second=84 amount=-1 +kerning first=70 second=46 amount=-1 +kerning first=1068 second=8217 amount=-1 +kerning first=939 second=916 amount=-1 +kerning first=932 second=196 amount=-1 +kerning first=8220 second=1035 amount=1 +kerning first=84 second=305 amount=-1 +kerning first=356 second=8211 amount=-1 +kerning first=293 second=932 amount=-1 +kerning first=1058 second=1081 amount=-1 +kerning first=1043 second=1044 amount=-1 +kerning first=376 second=8212 amount=-1 +kerning first=8217 second=65 amount=-1 +kerning first=321 second=67 amount=-1 +kerning first=913 second=936 amount=-1 +kerning first=1168 second=1085 amount=-1 +kerning first=89 second=283 amount=-1 +kerning first=358 second=256 amount=-1 +kerning first=354 second=8249 amount=-1 +kerning first=1059 second=1077 amount=-1 +kerning first=8220 second=8220 amount=-1 +kerning first=197 second=87 amount=-1 +kerning first=221 second=269 amount=-1 +kerning first=84 second=273 amount=-1 +kerning first=8221 second=331 amount=-1 +kerning first=356 second=225 amount=-1 +kerning first=8217 second=347 amount=-1 +kerning first=221 second=117 amount=-1 +kerning first=932 second=333 amount=-1 +kerning first=1027 second=1096 amount=-1 +kerning first=8211 second=939 amount=-1 +kerning first=84 second=277 amount=-1 +kerning first=8221 second=283 amount=-1 +kerning first=256 second=936 amount=-1 +kerning first=317 second=366 amount=-1 +kerning first=354 second=948 amount=-1 +kerning first=76 second=210 amount=-1 +kerning first=84 second=121 amount=-1 +kerning first=376 second=257 amount=-1 +kerning first=356 second=87 amount=1 +kerning first=915 second=927 amount=-1 +kerning first=358 second=171 amount=-1 +kerning first=376 second=113 amount=-1 +kerning first=915 second=192 amount=-2 +kerning first=337 second=356 amount=-1 +kerning first=260 second=932 amount=-1 +kerning first=315 second=364 amount=-1 +kerning first=8216 second=196 amount=-1 +kerning first=345 second=44 amount=-1 +kerning first=221 second=197 amount=-1 +kerning first=171 second=910 amount=-1 +kerning first=194 second=939 amount=-1 +kerning first=932 second=959 amount=-1 +kerning first=8217 second=238 amount=-1 +kerning first=915 second=286 amount=-1 +kerning first=89 second=67 amount=-1 +kerning first=315 second=8216 amount=-2 +kerning first=939 second=949 amount=-1 +kerning first=932 second=233 amount=-1 +kerning first=121 second=44 amount=-1 +kerning first=929 second=913 amount=-1 +kerning first=221 second=284 amount=-1 +kerning first=356 second=305 amount=-1 +kerning first=1033 second=1038 amount=-1 +kerning first=321 second=360 amount=-1 +kerning first=1058 second=1116 amount=-1 +kerning first=1043 second=1078 amount=-1 +kerning first=932 second=356 amount=1 +kerning first=376 second=193 amount=-1 +kerning first=8217 second=99 amount=-1 +kerning first=1168 second=1169 amount=-1 +kerning first=89 second=349 amount=-1 +kerning first=248 second=356 amount=-1 +kerning first=929 second=258 amount=-1 +kerning first=936 second=44 amount=-1 +kerning first=317 second=45 amount=-1 +kerning first=40 second=354 amount=1 +kerning first=70 second=198 amount=-1 +kerning first=8216 second=333 amount=-1 +kerning first=913 second=372 amount=-1 +kerning first=313 second=8249 amount=-1 +kerning first=356 second=273 amount=-1 +kerning first=1038 second=1077 amount=-1 +kerning first=86 second=193 amount=-1 +kerning first=84 second=351 amount=-1 +kerning first=8221 second=349 amount=-1 +kerning first=356 second=277 amount=-1 +kerning first=80 second=192 amount=-1 +kerning first=197 second=933 amount=-1 +kerning first=376 second=335 amount=-1 +kerning first=356 second=121 amount=-1 +kerning first=76 second=173 amount=-1 +kerning first=915 second=961 amount=-1 +kerning first=1058 second=1060 amount=-1 +kerning first=8217 second=44 amount=-2 +kerning first=8216 second=959 amount=-1 +kerning first=256 second=372 amount=-1 +kerning first=313 second=217 amount=-1 +kerning first=354 second=269 amount=-1 +kerning first=70 second=261 amount=-1 +kerning first=8216 second=233 amount=-1 +kerning first=221 second=235 amount=-1 +kerning first=354 second=117 amount=-1 +kerning first=89 second=101 amount=-1 +kerning first=1091 second=44 amount=-1 +kerning first=313 second=334 amount=-1 +kerning first=8216 second=356 amount=1 +kerning first=84 second=239 amount=-1 +kerning first=8217 second=299 amount=-1 +kerning first=8221 second=236 amount=-1 +kerning first=1043 second=1113 amount=-1 +kerning first=932 second=291 amount=-1 +kerning first=376 second=227 amount=-1 +kerning first=1027 second=1075 amount=-1 +kerning first=8216 second=1083 amount=-1 +kerning first=321 second=39 amount=-1 +kerning first=109 second=84 amount=-1 +kerning first=923 second=221 amount=-1 +kerning first=358 second=263 amount=-1 +kerning first=84 second=100 amount=-1 +kerning first=8221 second=101 amount=-1 +kerning first=317 second=79 amount=-1 +kerning first=354 second=197 amount=-1 +kerning first=315 second=212 amount=-1 +kerning first=70 second=194 amount=-1 +kerning first=8220 second=196 amount=-1 +kerning first=931 second=210 amount=-1 +kerning first=8204 second=376 amount=-1 +kerning first=923 second=84 amount=-1 +kerning first=313 second=216 amount=-1 +kerning first=308 second=125 amount=1 +kerning first=321 second=218 amount=-1 +kerning first=89 second=46 amount=-1 +kerning first=356 second=351 amount=-1 +kerning first=939 second=195 amount=-1 +kerning first=317 second=8212 amount=-1 +kerning first=1058 second=1094 amount=-1 +kerning first=358 second=192 amount=-1 +kerning first=221 second=41 amount=1 +kerning first=1168 second=1098 amount=-1 +kerning first=319 second=71 amount=-1 +kerning first=354 second=341 amount=-1 +kerning first=8220 second=333 amount=-1 +kerning first=225 second=84 amount=-1 +kerning first=84 second=45 amount=-1 +kerning first=8221 second=46 amount=-2 +kerning first=354 second=187 amount=-1 +kerning first=193 second=8221 amount=-1 +kerning first=102 second=125 amount=1 +kerning first=8216 second=291 amount=-1 +kerning first=356 second=239 amount=-1 +kerning first=932 second=363 amount=-1 +kerning first=84 second=303 amount=-1 +kerning first=8221 second=297 amount=-1 +kerning first=354 second=963 amount=-1 +kerning first=195 second=8216 amount=-1 +kerning first=8220 second=959 amount=-1 +kerning first=258 second=86 amount=-1 +kerning first=376 second=287 amount=-1 +kerning first=356 second=100 amount=-1 +kerning first=939 second=8230 amount=-1 +kerning first=227 second=358 amount=-1 +kerning first=354 second=235 amount=-1 +kerning first=8220 second=233 amount=-1 +kerning first=8204 second=358 amount=-1 +kerning first=915 second=211 amount=-1 +kerning first=8222 second=221 amount=-1 +kerning first=260 second=939 amount=-1 +kerning first=193 second=354 amount=-1 +kerning first=221 second=212 amount=-1 +kerning first=8220 second=356 amount=1 +kerning first=1026 second=1058 amount=-1 +kerning first=1059 second=46 amount=-1 +kerning first=936 second=923 amount=-1 +kerning first=965 second=39 amount=-1 +kerning first=313 second=284 amount=-1 +kerning first=8217 second=160 amount=-1 +kerning first=932 second=245 amount=-1 +kerning first=358 second=961 amount=-1 +kerning first=1058 second=8250 amount=-1 +kerning first=8220 second=1083 amount=-1 +kerning first=8222 second=84 amount=-1 +kerning first=1066 second=8217 amount=-1 +kerning first=358 second=234 amount=-1 +kerning first=929 second=196 amount=-1 +kerning first=1043 second=1091 amount=-1 +kerning first=8217 second=112 amount=-1 +kerning first=933 second=962 amount=-1 +kerning first=315 second=920 amount=-1 +kerning first=358 second=354 amount=1 +kerning first=98 second=932 amount=-1 +kerning first=356 second=45 amount=-1 +kerning first=968 second=34 amount=-1 +kerning first=89 second=198 amount=-1 +kerning first=376 second=71 amount=-1 +kerning first=221 second=367 amount=-1 +kerning first=8217 second=923 amount=-1 +kerning first=315 second=266 amount=-1 +kerning first=196 second=87 amount=-1 +kerning first=354 second=41 amount=1 +kerning first=356 second=303 amount=-1 +kerning first=84 second=8212 amount=-1 +kerning first=376 second=365 amount=-1 +kerning first=915 second=970 amount=-1 +kerning first=8221 second=198 amount=-1 +kerning first=910 second=46 amount=-1 +kerning first=1043 second=1035 amount=1 +kerning first=1168 second=1077 amount=-1 +kerning first=89 second=261 amount=-1 +kerning first=8216 second=245 amount=-1 +kerning first=8220 second=291 amount=-1 +kerning first=80 second=74 amount=-1 +kerning first=326 second=356 amount=-1 +kerning first=221 second=250 amount=-1 +kerning first=258 second=932 amount=-1 +kerning first=313 second=364 amount=-1 +kerning first=933 second=256 amount=-1 +kerning first=1038 second=46 amount=-1 +kerning first=84 second=253 amount=-1 +kerning first=313 second=8216 amount=-2 +kerning first=8217 second=326 amount=-1 +kerning first=119 second=44 amount=-1 +kerning first=160 second=89 amount=-1 +kerning first=376 second=246 amount=-1 +kerning first=1027 second=1088 amount=-1 +kerning first=84 second=257 amount=-1 +kerning first=358 second=289 amount=-1 +kerning first=84 second=113 amount=-1 +kerning first=8221 second=114 amount=-1 +kerning first=89 second=194 amount=-1 +kerning first=910 second=945 amount=-1 +kerning first=934 second=44 amount=-1 +kerning first=221 second=920 amount=-1 +kerning first=91 second=106 amount=1 +kerning first=70 second=308 amount=-1 +kerning first=913 second=8221 amount=-1 +kerning first=91 second=1095 amount=-1 +kerning first=915 second=264 amount=-1 +kerning first=173 second=1026 amount=-1 +kerning first=319 second=221 amount=-1 +kerning first=1040 second=1026 amount=-1 +kerning first=221 second=266 amount=-1 +kerning first=84 second=193 amount=-1 +kerning first=8221 second=194 amount=-1 +kerning first=356 second=8212 amount=-1 +kerning first=1058 second=1108 amount=-1 +kerning first=1027 second=44 amount=-1 +kerning first=319 second=336 amount=-1 +kerning first=1027 second=1032 amount=-1 +kerning first=196 second=933 amount=-1 +kerning first=319 second=84 amount=-1 +kerning first=932 second=86 amount=1 +kerning first=354 second=367 amount=-1 +kerning first=89 second=337 amount=-1 +kerning first=242 second=84 amount=-1 +kerning first=256 second=8221 amount=-1 +kerning first=358 second=74 amount=-1 +kerning first=1059 second=1103 amount=-1 +kerning first=915 second=8211 amount=-1 +kerning first=40 second=87 amount=1 +kerning first=913 second=354 amount=-1 +kerning first=934 second=939 amount=-1 +kerning first=910 second=198 amount=-1 +kerning first=356 second=253 amount=-1 +kerning first=84 second=335 amount=-1 +kerning first=319 second=338 amount=-1 +kerning first=356 second=257 amount=-1 +kerning first=8221 second=337 amount=-1 +kerning first=932 second=230 amount=-1 +kerning first=354 second=972 amount=-1 +kerning first=358 second=371 amount=-1 +kerning first=356 second=113 amount=-1 +kerning first=354 second=250 amount=-1 +kerning first=89 second=231 amount=-1 +kerning first=8220 second=245 amount=-1 +kerning first=76 second=372 amount=-1 +kerning first=8212 second=221 amount=-1 +kerning first=256 second=354 amount=-1 +kerning first=313 second=212 amount=-1 +kerning first=1061 second=1095 amount=-1 +kerning first=221 second=226 amount=-1 +kerning first=1059 second=59 amount=-1 +kerning first=354 second=109 amount=-1 +kerning first=89 second=93 amount=1 +kerning first=324 second=358 amount=-1 +kerning first=8212 second=84 amount=-1 +kerning first=1058 second=8230 amount=-1 +kerning first=84 second=227 amount=-1 +kerning first=87 second=46 amount=-1 +kerning first=356 second=193 amount=-1 +kerning first=904 second=912 amount=1 +kerning first=8217 second=281 amount=-1 +kerning first=8221 second=231 amount=-1 +kerning first=112 second=358 amount=-1 +kerning first=358 second=353 amount=-1 +kerning first=1043 second=1105 amount=-1 +kerning first=932 second=271 amount=-1 +kerning first=337 second=932 amount=-1 +kerning first=91 second=376 amount=1 +kerning first=376 second=336 amount=-1 +kerning first=317 second=71 amount=-1 +kerning first=1169 second=8230 amount=-1 +kerning first=910 second=194 amount=-1 +kerning first=1038 second=1103 amount=-1 +kerning first=932 second=932 amount=1 +kerning first=187 second=89 amount=-1 +kerning first=315 second=67 amount=-1 +kerning first=356 second=335 amount=-1 +kerning first=248 second=932 amount=-1 +kerning first=8250 second=354 amount=-1 +kerning first=935 second=970 amount=1 +kerning first=910 second=59 amount=-1 +kerning first=1058 second=1086 amount=-1 +kerning first=319 second=290 amount=-1 +kerning first=192 second=8216 amount=-1 +kerning first=376 second=338 amount=-1 +kerning first=224 second=358 amount=-1 +kerning first=1168 second=1090 amount=-1 +kerning first=354 second=324 amount=-1 +kerning first=932 second=65 amount=-1 +kerning first=89 second=285 amount=-1 +kerning first=76 second=171 amount=-1 +kerning first=933 second=192 amount=-1 +kerning first=258 second=939 amount=-1 +kerning first=1040 second=1095 amount=-1 +kerning first=306 second=93 amount=1 +kerning first=8216 second=271 amount=-1 +kerning first=1038 second=59 amount=-1 +kerning first=221 second=283 amount=-1 +kerning first=356 second=227 amount=-1 +kerning first=932 second=347 amount=-1 +kerning first=1027 second=1101 amount=-1 +kerning first=917 second=912 amount=1 +kerning first=84 second=287 amount=-1 +kerning first=8221 second=285 amount=-1 +kerning first=91 second=358 amount=1 +kerning first=76 second=220 amount=-1 +kerning first=372 second=301 amount=1 +kerning first=376 second=265 amount=-1 +kerning first=354 second=226 amount=-1 +kerning first=358 second=8211 amount=-1 +kerning first=313 second=920 amount=-1 +kerning first=1168 second=46 amount=-1 +kerning first=8216 second=932 amount=1 +kerning first=87 second=198 amount=-1 +kerning first=89 second=308 amount=-1 +kerning first=315 second=360 amount=-1 +kerning first=932 second=966 amount=-1 +kerning first=8217 second=244 amount=-1 +kerning first=1059 second=1026 amount=1 +kerning first=313 second=266 amount=-1 +kerning first=193 second=87 amount=-1 +kerning first=939 second=954 amount=-1 +kerning first=932 second=238 amount=-1 +kerning first=333 second=354 amount=-1 +kerning first=65 second=221 amount=-1 +kerning first=358 second=225 amount=-1 +kerning first=8216 second=65 amount=-1 +kerning first=319 second=368 amount=-1 +kerning first=221 second=67 amount=-1 +kerning first=902 second=8216 amount=-1 +kerning first=376 second=195 amount=-1 +kerning first=8249 second=939 amount=-1 +kerning first=936 second=260 amount=-1 +kerning first=933 second=961 amount=-1 +kerning first=1043 second=1083 amount=-1 +kerning first=8221 second=308 amount=-1 +kerning first=932 second=99 amount=-1 +kerning first=89 second=369 amount=-1 +kerning first=1041 second=1035 amount=-1 +kerning first=329 second=84 amount=-1 +kerning first=376 second=290 amount=-1 +kerning first=65 second=84 amount=-1 +kerning first=358 second=87 amount=1 +kerning first=328 second=356 amount=-1 +kerning first=221 second=349 amount=-1 +kerning first=160 second=8220 amount=-1 +kerning first=86 second=195 amount=-1 +kerning first=84 second=365 amount=-1 +kerning first=356 second=287 amount=-1 +kerning first=173 second=376 amount=-1 +kerning first=8217 second=260 amount=-1 +kerning first=321 second=262 amount=-1 +kerning first=354 second=331 amount=-1 +kerning first=358 second=305 amount=-1 +kerning first=89 second=242 amount=-1 +kerning first=376 second=8230 amount=-1 +kerning first=8216 second=966 amount=-1 +kerning first=87 second=194 amount=-1 +kerning first=354 second=283 amount=-1 +kerning first=932 second=44 amount=-1 +kerning first=8220 second=271 amount=-1 +kerning first=354 second=122 amount=-1 +kerning first=315 second=39 amount=-1 +kerning first=84 second=941 amount=-1 +kerning first=102 second=8216 amount=1 +kerning first=34 second=256 amount=-1 +kerning first=84 second=246 amount=-1 +kerning first=8221 second=242 amount=-1 +kerning first=317 second=221 amount=-1 +kerning first=1038 second=1026 amount=1 +kerning first=358 second=273 amount=-1 +kerning first=8216 second=99 amount=-1 +kerning first=1043 second=1119 amount=-1 +kerning first=221 second=101 amount=-1 +kerning first=932 second=299 amount=-1 +kerning first=376 second=232 amount=-1 +kerning first=1027 second=1080 amount=-1 +kerning first=76 second=927 amount=-1 +kerning first=308 second=41 amount=1 +kerning first=86 second=8230 amount=-1 +kerning first=229 second=356 amount=-1 +kerning first=317 second=336 amount=-1 +kerning first=354 second=934 amount=-1 +kerning first=358 second=277 amount=-1 +kerning first=8220 second=932 amount=1 +kerning first=97 second=354 amount=-1 +kerning first=193 second=933 amount=-1 +kerning first=84 second=105 amount=-1 +kerning first=317 second=84 amount=-1 +kerning first=315 second=218 amount=-1 +kerning first=358 second=121 amount=-1 +kerning first=244 second=84 amount=-1 +kerning first=376 second=97 amount=-1 +kerning first=76 second=286 amount=-1 +kerning first=1111 second=1115 amount=1 +kerning first=923 second=89 amount=-1 +kerning first=89 second=262 amount=-1 +kerning first=321 second=376 amount=-1 +kerning first=8220 second=65 amount=-1 +kerning first=319 second=214 amount=-1 +kerning first=356 second=365 amount=-1 +kerning first=84 second=916 amount=-1 +kerning first=173 second=358 amount=-1 +kerning first=915 second=45 amount=-1 +kerning first=102 second=41 amount=1 +kerning first=317 second=338 amount=-1 +kerning first=321 second=332 amount=-1 +kerning first=1058 second=1099 amount=-1 +kerning first=8216 second=44 amount=-2 +kerning first=271 second=316 amount=1 +kerning first=221 second=46 amount=-1 +kerning first=1090 second=1076 amount=-1 +kerning first=8216 second=1032 amount=-1 +kerning first=321 second=85 amount=-1 +kerning first=1168 second=1103 amount=-1 +kerning first=354 second=349 amount=-1 +kerning first=76 second=8221 amount=-1 +kerning first=356 second=941 amount=-1 +kerning first=923 second=34 amount=-1 +kerning first=87 second=93 amount=1 +kerning first=356 second=246 amount=-1 +kerning first=913 second=87 amount=-1 +kerning first=1056 second=8230 amount=-2 +kerning first=932 second=373 amount=-1 +kerning first=110 second=358 amount=-1 +kerning first=354 second=968 amount=-1 +kerning first=358 second=351 amount=-1 +kerning first=8220 second=966 amount=-1 +kerning first=326 second=932 amount=-1 +kerning first=84 second=8250 amount=-1 +kerning first=356 second=105 amount=-1 +kerning first=354 second=236 amount=-1 +kerning first=1058 second=1044 amount=-1 +kerning first=910 second=942 amount=-1 +kerning first=1168 second=59 amount=-1 +kerning first=76 second=354 amount=-1 +kerning first=89 second=332 amount=-1 +kerning first=932 second=974 amount=-1 +kerning first=256 second=87 amount=-1 +kerning first=1026 second=1063 amount=-1 +kerning first=321 second=358 amount=-1 +kerning first=354 second=101 amount=-1 +kerning first=8220 second=99 amount=-1 +kerning first=356 second=916 amount=-1 +kerning first=84 second=949 amount=-1 +kerning first=1059 second=1040 amount=-1 +kerning first=932 second=249 amount=-1 +kerning first=915 second=79 amount=-1 +kerning first=936 second=197 amount=-1 +kerning first=8222 second=89 amount=-1 +kerning first=313 second=67 amount=-1 +kerning first=8217 second=269 amount=-1 +kerning first=922 second=308 amount=1 +kerning first=358 second=239 amount=-1 +kerning first=1043 second=1096 amount=-1 +kerning first=932 second=259 amount=-1 +kerning first=376 second=214 amount=-1 +kerning first=1027 second=1059 amount=1 +kerning first=933 second=970 amount=1 +kerning first=317 second=290 amount=-1 +kerning first=194 second=8216 amount=-1 +kerning first=932 second=112 amount=-1 +kerning first=39 second=256 amount=-1 +kerning first=931 second=927 amount=-1 +kerning first=84 second=84 amount=1 +kerning first=226 second=358 amount=-1 +kerning first=358 second=100 amount=-1 +kerning first=929 second=65 amount=-1 +kerning first=915 second=8212 amount=-1 +kerning first=373 second=44 amount=-1 +kerning first=160 second=8222 amount=-2 +kerning first=931 second=286 amount=-1 +kerning first=221 second=198 amount=-1 +kerning first=932 second=923 amount=-1 +kerning first=8217 second=197 amount=-1 +kerning first=321 second=199 amount=-1 +kerning first=354 second=46 amount=-1 +kerning first=84 second=378 amount=-1 +kerning first=8220 second=44 amount=-2 +kerning first=939 second=913 amount=-1 +kerning first=195 second=39 amount=-1 +kerning first=8220 second=1032 amount=-1 +kerning first=915 second=912 amount=-1 +kerning first=356 second=8250 amount=-1 +kerning first=376 second=361 amount=-1 +kerning first=321 second=288 amount=-1 +kerning first=1058 second=1078 amount=-1 +kerning first=197 second=221 amount=-1 +kerning first=8216 second=974 amount=-1 +kerning first=913 second=933 amount=-1 +kerning first=1168 second=1082 amount=-1 +kerning first=939 second=258 amount=-1 +kerning first=354 second=297 amount=-1 +kerning first=89 second=267 amount=-1 +kerning first=1118 second=46 amount=-1 +kerning first=34 second=192 amount=-1 +kerning first=1050 second=1033 amount=1 +kerning first=358 second=45 amount=-1 +kerning first=313 second=360 amount=-1 +kerning first=356 second=949 amount=-1 +kerning first=197 second=84 amount=-1 +kerning first=160 second=356 amount=-1 +kerning first=221 second=261 amount=-1 +kerning first=8217 second=341 amount=-1 +kerning first=8221 second=358 amount=1 +kerning first=1057 second=1026 amount=1 +kerning first=1100 second=1091 amount=-1 +kerning first=1038 second=1040 amount=-1 +kerning first=932 second=326 amount=-1 +kerning first=335 second=354 amount=-1 +kerning first=376 second=251 amount=-1 +kerning first=1027 second=1093 amount=-1 +kerning first=84 second=265 amount=-1 +kerning first=256 second=933 amount=-1 +kerning first=8221 second=267 amount=-1 +kerning first=317 second=368 amount=-1 +kerning first=354 second=945 amount=-1 +kerning first=358 second=303 amount=-1 +kerning first=76 second=211 amount=-1 +kerning first=84 second=118 amount=-1 +kerning first=255 second=44 amount=-1 +kerning first=356 second=84 amount=1 +kerning first=89 second=199 amount=-1 +kerning first=295 second=84 amount=-1 +kerning first=915 second=193 amount=-2 +kerning first=8216 second=923 amount=-1 +kerning first=1168 second=1026 amount=1 +kerning first=89 second=288 amount=-1 +kerning first=933 second=8211 amount=-1 +kerning first=221 second=194 amount=-1 +kerning first=8204 second=372 amount=-1 +kerning first=8217 second=235 amount=-1 +kerning first=1107 second=44 amount=-1 +kerning first=356 second=378 amount=-1 +kerning first=939 second=946 amount=-1 +kerning first=111 second=356 amount=-1 +kerning first=932 second=229 amount=-1 +kerning first=915 second=58 amount=-1 +kerning first=1068 second=1059 amount=-1 +kerning first=84 second=195 amount=-1 +kerning first=321 second=362 amount=-1 +kerning first=1058 second=1113 amount=-1 +kerning first=1043 second=1075 amount=-1 +kerning first=1027 second=1038 amount=1 +kerning first=34 second=961 amount=-1 +kerning first=1168 second=1118 amount=-1 +kerning first=319 second=89 amount=-1 +kerning first=354 second=198 amount=-1 +kerning first=929 second=44 amount=-2 +kerning first=1059 second=1109 amount=-1 +kerning first=221 second=337 amount=-1 +kerning first=313 second=39 amount=-1 +kerning first=1027 second=8249 amount=-1 +kerning first=1075 second=8230 amount=-1 +kerning first=173 second=910 amount=-1 +kerning first=84 second=345 amount=-1 +kerning first=1035 second=1026 amount=-1 +kerning first=356 second=265 amount=-1 +kerning first=8221 second=343 amount=-1 +kerning first=354 second=944 amount=-1 +kerning first=8220 second=974 amount=-1 +kerning first=80 second=193 amount=-1 +kerning first=84 second=8230 amount=-1 +kerning first=356 second=118 amount=-1 +kerning first=915 second=957 amount=-1 +kerning first=228 second=356 amount=-1 +kerning first=354 second=255 amount=-1 +kerning first=358 second=8212 amount=-1 +kerning first=45 second=1026 amount=-1 +kerning first=923 second=8220 amount=-1 +kerning first=313 second=218 amount=-1 +kerning first=319 second=34 amount=-1 +kerning first=271 second=98 amount=1 +kerning first=354 second=261 amount=-1 +kerning first=241 second=84 amount=-1 +kerning first=221 second=231 amount=-1 +kerning first=46 second=34 amount=-1 +kerning first=354 second=114 amount=-1 +kerning first=1040 second=1066 amount=-1 +kerning first=8212 second=89 amount=-1 +kerning first=84 second=232 amount=-1 +kerning first=8221 second=237 amount=-1 +kerning first=356 second=195 amount=-1 +kerning first=317 second=214 amount=-1 +kerning first=39 second=192 amount=-1 +kerning first=358 second=253 amount=-1 +kerning first=221 second=93 amount=1 +kerning first=932 second=281 amount=-1 +kerning first=376 second=228 amount=-1 +kerning first=1027 second=1072 amount=-1 +kerning first=260 second=8216 amount=-1 +kerning first=932 second=125 amount=1 +kerning first=358 second=257 amount=-1 +kerning first=8220 second=923 amount=-1 +kerning first=245 second=358 amount=-1 +kerning first=84 second=97 amount=-1 +kerning first=354 second=194 amount=-1 +kerning first=358 second=113 amount=-1 +kerning first=931 second=211 amount=-1 +kerning first=76 second=264 amount=-1 +kerning first=1057 second=1095 amount=-1 +kerning first=187 second=356 amount=-1 +kerning first=1038 second=1109 amount=-1 +kerning first=321 second=210 amount=-1 +kerning first=356 second=345 amount=-1 +kerning first=1068 second=1038 amount=-1 +kerning first=935 second=912 amount=1 +kerning first=356 second=8230 amount=-1 +kerning first=939 second=196 amount=-1 +kerning first=1058 second=1091 amount=-1 +kerning first=358 second=193 amount=-1 +kerning first=328 second=932 amount=-1 +kerning first=376 second=248 amount=-1 +kerning first=1168 second=1095 amount=-1 +kerning first=1056 second=1044 amount=-1 +kerning first=354 second=337 amount=-1 +kerning first=76 second=8211 amount=-1 +kerning first=372 second=256 amount=-1 +kerning first=1113 second=1098 amount=-1 diff --git a/assets/style/uiskin.atlas b/assets/style/uiskin.atlas new file mode 100644 index 00000000..e597b1eb --- /dev/null +++ b/assets/style/uiskin.atlas @@ -0,0 +1,1506 @@ + +uiskin.png +size: 1024,1024 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +align-center-horisontal + rotate: false + xy: 360, 490 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +align-center-vertical + rotate: false + xy: 306, 416 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +align-edge-down + rotate: false + xy: 380, 490 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +align-edge-left + rotate: false + xy: 400, 490 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +align-edge-right + rotate: false + xy: 420, 490 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +align-edge-up + rotate: false + xy: 440, 490 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +align-simple-down + rotate: false + xy: 460, 490 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +align-simple-left + rotate: false + xy: 480, 490 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +align-simple-right + rotate: false + xy: 500, 490 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +align-simple-up + rotate: false + xy: 235, 387 + size: 18, 18 + orig: 18, 18 + offset: 0, 0 + index: -1 +alpha-bar-10px + rotate: false + xy: 520, 982 + size: 130, 10 + orig: 130, 10 + offset: 0, 0 + index: -1 +alpha-bar-25px + rotate: false + xy: 520, 994 + size: 130, 28 + orig: 130, 28 + offset: 0, 0 + index: -1 +alpha-bar-25px-shifted + rotate: false + xy: 2, 377 + size: 130, 28 + orig: 130, 28 + offset: 0, 0 + index: -1 +border + rotate: false + xy: 134, 378 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +border-circle + rotate: false + xy: 681, 975 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +border-circle-error + rotate: false + xy: 520, 488 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +border-error + rotate: false + xy: 67, 326 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +box + rotate: false + xy: 520, 950 + size: 17, 30 + split: 8, 8, 23, 6 + orig: 17, 30 + offset: 0, 0 + index: -1 +box-colapse-off + rotate: false + xy: 697, 969 + size: 11, 11 + orig: 11, 11 + offset: 0, 0 + index: -1 +box-colapse-on + rotate: false + xy: 710, 969 + size: 11, 11 + orig: 11, 11 + offset: 0, 0 + index: -1 +button + rotate: false + xy: 520, 588 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 3, 3 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-dark + rotate: false + xy: 520, 786 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 3, 3 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-dark-down + rotate: false + xy: 520, 830 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 3, 3 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-dark-over + rotate: false + xy: 520, 808 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 4, 3 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-down + rotate: false + xy: 520, 764 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 3, 3 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-orange + rotate: false + xy: 520, 698 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 3, 3 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-orange-down + rotate: false + xy: 520, 742 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 3, 3 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-orange-over + rotate: false + xy: 520, 720 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 3, 3 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-over + rotate: false + xy: 520, 676 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 3, 3 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-red + rotate: false + xy: 520, 654 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 1, 1 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-resource + rotate: false + xy: 520, 610 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 1, 1 + orig: 12, 20 + offset: 0, 0 + index: -1 +button-resource-over + rotate: false + xy: 520, 632 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 1, 1 + orig: 12, 20 + offset: 0, 0 + index: -1 +check-down + rotate: false + xy: 882, 984 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +check-down-on + rotate: false + xy: 898, 984 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +check-off + rotate: false + xy: 914, 984 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +textfield + rotate: false + xy: 914, 984 + size: 14, 14 + split: 2, 2, 3, 2 + orig: 14, 14 + offset: 0, 0 + index: -1 +check-on + rotate: false + xy: 930, 984 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +check-on-disabled + rotate: false + xy: 946, 984 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +check-over-off + rotate: false + xy: 962, 984 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +check-over-on + rotate: false + xy: 978, 984 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +color-picker-bar-selector + rotate: false + xy: 303, 377 + size: 7, 14 + orig: 7, 14 + offset: 0, 0 + index: -1 +color-picker-cross + rotate: false + xy: 875, 976 + size: 5, 5 + orig: 5, 5 + offset: 0, 0 + index: -1 +color-picker-selector-horizontal + rotate: false + xy: 349, 421 + size: 3, 1 + orig: 3, 1 + offset: 0, 0 + index: -1 +color-picker-selector-vertical + rotate: false + xy: 328, 392 + size: 1, 3 + orig: 1, 3 + offset: 0, 0 + index: -1 +cursor + rotate: false + xy: 355, 482 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +default-pane + rotate: false + xy: 27, 275 + size: 5, 3 + split: 1, 1, 1, 1 + orig: 5, 3 + offset: 0, 0 + index: -1 +default-pane-noborder + rotate: false + xy: 888, 981 + size: 1, 1 + split: 0, 0, 0, 0 + orig: 1, 1 + offset: 0, 0 + index: -1 +default-select + rotate: false + xy: 134, 383 + size: 27, 22 + split: 2, 16, 0, 22 + orig: 27, 22 + offset: 0, 0 + index: -1 +default-select-selection + rotate: false + xy: 360, 485 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +default-select-white + rotate: false + xy: 331, 487 + size: 27, 21 + split: 2, 17, 0, 21 + orig: 27, 21 + offset: 0, 0 + index: -1 +default-select-white-over + rotate: false + xy: 253, 413 + size: 27, 21 + split: 2, 17, 0, 21 + orig: 27, 21 + offset: 0, 0 + index: -1 +dropHere + rotate: false + xy: 2, 407 + size: 249, 101 + orig: 249, 101 + offset: 0, 0 + index: -1 +expandable-properties-active-bg + rotate: false + xy: 46, 280 + size: 4, 17 + split: 1, 2, 0, 17 + orig: 4, 17 + offset: 0, 0 + index: -1 +expandable-properties-collapse-off + rotate: false + xy: 833, 974 + size: 7, 7 + orig: 7, 7 + offset: 0, 0 + index: -1 +expandable-properties-collapse-on + rotate: false + xy: 842, 974 + size: 7, 7 + orig: 7, 7 + offset: 0, 0 + index: -1 +expandable-properties-inactive-bg + rotate: false + xy: 326, 416 + size: 4, 18 + split: 1, 2, 0, 18 + orig: 4, 18 + offset: 0, 0 + index: -1 +icon-animation + rotate: false + xy: 163, 383 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-arrow-left + rotate: false + xy: 349, 424 + size: 6, 11 + orig: 6, 11 + offset: 0, 0 + index: -1 +icon-arrow-right + rotate: false + xy: 723, 969 + size: 6, 11 + orig: 6, 11 + offset: 0, 0 + index: -1 +icon-close + rotate: false + xy: 2, 226 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-close-orange + rotate: false + xy: 783, 973 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +icon-close-orange-down + rotate: false + xy: 793, 973 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +icon-close-orange-over + rotate: false + xy: 803, 973 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +icon-close-small + rotate: false + xy: 994, 986 + size: 12, 12 + orig: 12, 12 + offset: 0, 0 + index: -1 +icon-composite + rotate: false + xy: 75, 353 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-composite2 + rotate: false + xy: 1008, 974 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +icon-drive + rotate: false + xy: 721, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-file-audio + rotate: false + xy: 587, 958 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-file-image + rotate: false + xy: 187, 383 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-file-pdf + rotate: false + xy: 2, 202 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-file-text + rotate: false + xy: 99, 353 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-folder + rotate: false + xy: 745, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-folder-new + rotate: false + xy: 611, 958 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-folder-parent + rotate: false + xy: 211, 383 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-folder-star + rotate: false + xy: 2, 178 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-group + rotate: false + xy: 769, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-image + rotate: false + xy: 2, 154 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-label + rotate: false + xy: 793, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-library + rotate: false + xy: 2, 130 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-library-over + rotate: false + xy: 817, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-link-active + rotate: false + xy: 332, 420 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +icon-link-inactive + rotate: false + xy: 697, 982 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +icon-list-settings + rotate: false + xy: 2, 106 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-lock-active + rotate: false + xy: 841, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-lock-inactive + rotate: false + xy: 2, 82 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-new-layer + rotate: false + xy: 1009, 1007 + size: 13, 15 + orig: 13, 15 + offset: 0, 0 + index: -1 +icon-particle + rotate: false + xy: 865, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-particle-over + rotate: false + xy: 2, 58 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-particle-white + rotate: false + xy: 889, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-refresh + rotate: false + xy: 2, 34 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-root + rotate: false + xy: 539, 941 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +icon-spine + rotate: false + xy: 913, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-star + rotate: false + xy: 2, 10 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-star-outline + rotate: false + xy: 937, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-trash + rotate: false + xy: 1009, 990 + size: 13, 15 + orig: 13, 15 + offset: 0, 0 + index: -1 +icon-trash-disabled + rotate: false + xy: 520, 504 + size: 13, 15 + orig: 13, 15 + offset: 0, 0 + index: -1 +icon-trash-over + rotate: false + xy: 714, 982 + size: 13, 15 + orig: 13, 15 + offset: 0, 0 + index: -1 +icon-unlink-active + rotate: false + xy: 729, 983 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +icon-unlink-inactive + rotate: false + xy: 746, 983 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +icon-visible-off + rotate: false + xy: 961, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-visible-on + rotate: false + xy: 985, 1000 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +icon-zoomin + rotate: false + xy: 35, 299 + size: 17, 17 + orig: 17, 17 + offset: 0, 0 + index: -1 +icon-zoomin-disabled + rotate: false + xy: 255, 394 + size: 17, 17 + orig: 17, 17 + offset: 0, 0 + index: -1 +icon-zoomin-over + rotate: false + xy: 27, 280 + size: 17, 17 + orig: 17, 17 + offset: 0, 0 + index: -1 +icon-zoomout + rotate: false + xy: 274, 393 + size: 17, 17 + orig: 17, 17 + offset: 0, 0 + index: -1 +icon-zoomout-disabled + rotate: false + xy: 293, 393 + size: 17, 17 + orig: 17, 17 + offset: 0, 0 + index: -1 +icon-zoomout-over + rotate: false + xy: 312, 397 + size: 17, 17 + orig: 17, 17 + offset: 0, 0 + index: -1 +layer-bg + rotate: false + xy: 520, 521 + size: 5, 19 + split: 2, 2, 0, 19 + orig: 5, 19 + offset: 0, 0 + index: -1 +layer-bg-over + rotate: false + xy: 67, 331 + size: 5, 19 + split: 2, 2, 0, 19 + orig: 5, 19 + offset: 0, 0 + index: -1 +list-selection + rotate: false + xy: 139, 380 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +selection + rotate: false + xy: 139, 380 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +list-selection-white + rotate: false + xy: 355, 479 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +logo + rotate: false + xy: 2, 275 + size: 23, 23 + orig: 23, 23 + offset: 0, 0 + index: -1 +menu-bg + rotate: false + xy: 35, 344 + size: 14, 31 + split: 2, 2, 0, 31 + orig: 14, 31 + offset: 0, 0 + index: -1 +menu-bg-down + rotate: false + xy: 520, 924 + size: 14, 24 + split: 2, 2, 0, 24 + orig: 14, 24 + offset: 0, 0 + index: -1 +menu-bg-over + rotate: false + xy: 35, 318 + size: 14, 24 + split: 2, 2, 0, 24 + orig: 14, 24 + offset: 0, 0 + index: -1 +menu-bg-up + rotate: false + xy: 51, 326 + size: 14, 24 + split: 2, 2, 0, 24 + orig: 14, 24 + offset: 0, 0 + index: -1 +myriad-medium + rotate: false + xy: 260, 510 + size: 128, 512 + orig: 128, 512 + offset: 0, 0 + index: -1 +myriad-medium-big + rotate: false + xy: 2, 510 + size: 256, 512 + orig: 256, 512 + offset: 0, 0 + index: -1 +myriad-medium-small + rotate: false + xy: 390, 510 + size: 128, 512 + orig: 128, 512 + offset: 0, 0 + index: -1 +origin-anchor + rotate: false + xy: 731, 972 + size: 9, 9 + orig: 9, 9 + offset: 0, 0 + index: -1 +popup-menu + rotate: false + xy: 34, 275 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +popup-menu-disabled + rotate: false + xy: 61, 321 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +popup-menu-down + rotate: false + xy: 661, 983 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +tree-selection + rotate: false + xy: 661, 983 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +popup-menu-over + rotate: false + xy: 648, 971 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +progressbar + rotate: false + xy: 536, 943 + size: 1, 5 + orig: 1, 5 + offset: 0, 0 + index: -1 +progressbar-filled + rotate: false + xy: 533, 917 + size: 1, 5 + orig: 1, 5 + offset: 0, 0 + index: -1 +progressbar-filled-vertical + rotate: false + xy: 332, 417 + size: 5, 1 + orig: 5, 1 + offset: 0, 0 + index: -1 +progressbar-vertical + rotate: false + xy: 536, 922 + size: 5, 1 + orig: 5, 1 + offset: 0, 0 + index: -1 +radio-down + rotate: false + xy: 763, 983 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +radio-down-on + rotate: false + xy: 780, 983 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +radio-off + rotate: false + xy: 797, 983 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +radio-on + rotate: false + xy: 814, 983 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +radio-on-disabled + rotate: false + xy: 831, 983 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +radio-over-off + rotate: false + xy: 848, 983 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +radio-over-on + rotate: false + xy: 865, 983 + size: 15, 15 + orig: 15, 15 + offset: 0, 0 + index: -1 +scroll + rotate: false + xy: 17, 2 + size: 5, 6 + split: 2, 2, 2, 2 + orig: 5, 6 + offset: 0, 0 + index: -1 +scroll-horizontal + rotate: false + xy: 859, 976 + size: 6, 5 + split: 2, 2, 0, 5 + pad: -1, -1, 2, 2 + orig: 6, 5 + offset: 0, 0 + index: -1 +scroll-knob-horizontal + rotate: false + xy: 867, 976 + size: 6, 5 + split: 2, 2, 0, 5 + pad: -1, -1, 2, 2 + orig: 6, 5 + offset: 0, 0 + index: -1 +scroll-knob-vertical + rotate: false + xy: 10, 2 + size: 5, 6 + split: 2, 2, 2, 2 + orig: 5, 6 + offset: 0, 0 + index: -1 +select-box-list-bg + rotate: false + xy: 360, 482 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +select-box-list-bg-white + rotate: false + xy: 365, 487 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +select-down + rotate: false + xy: 652, 982 + size: 7, 4 + orig: 7, 4 + offset: 0, 0 + index: -1 +select-up + rotate: false + xy: 648, 976 + size: 7, 4 + orig: 7, 4 + offset: 0, 0 + index: -1 +selection-anchor + rotate: false + xy: 742, 972 + size: 9, 9 + orig: 9, 9 + offset: 0, 0 + index: -1 +separator + rotate: false + xy: 657, 978 + size: 1, 2 + orig: 1, 2 + offset: 0, 0 + index: -1 +separator-menu + rotate: false + xy: 657, 978 + size: 1, 2 + orig: 1, 2 + offset: 0, 0 + index: -1 +separator-vertical + rotate: false + xy: 731, 969 + size: 2, 1 + orig: 2, 1 + offset: 0, 0 + index: -1 +slider + rotate: false + xy: 529, 559 + size: 1, 4 + orig: 1, 4 + offset: 0, 0 + index: -1 +slider-knob + rotate: false + xy: 635, 958 + size: 11, 22 + orig: 11, 22 + offset: 0, 0 + index: -1 +slider-knob-disabled + rotate: false + xy: 520, 900 + size: 11, 22 + orig: 11, 22 + offset: 0, 0 + index: -1 +slider-knob-down + rotate: false + xy: 520, 876 + size: 11, 22 + orig: 11, 22 + offset: 0, 0 + index: -1 +slider-knob-over + rotate: false + xy: 520, 852 + size: 11, 22 + orig: 11, 22 + offset: 0, 0 + index: -1 +slider-vertical + rotate: false + xy: 306, 413 + size: 4, 1 + orig: 4, 1 + offset: 0, 0 + index: -1 +splash_logo + rotate: false + xy: 253, 436 + size: 76, 72 + orig: 76, 72 + offset: 0, 0 + index: -1 +splitpane + rotate: false + xy: 235, 384 + size: 4, 1 + orig: 4, 1 + offset: 0, 0 + index: -1 +splitpane-over + rotate: false + xy: 312, 378 + size: 4, 1 + orig: 4, 1 + offset: 0, 0 + index: -1 +splitpane-vertical + rotate: false + xy: 584, 935 + size: 1, 4 + orig: 1, 4 + offset: 0, 0 + index: -1 +splitpane-vertical-over + rotate: false + xy: 587, 936 + size: 1, 4 + orig: 1, 4 + offset: 0, 0 + index: -1 +static-text + rotate: false + xy: 520, 542 + size: 7, 21 + split: 3, 3, 0, 21 + orig: 7, 21 + offset: 0, 0 + index: -1 +sub-menu + rotate: false + xy: 851, 974 + size: 6, 7 + orig: 6, 7 + offset: 0, 0 + index: -1 +sub-menu-bg + rotate: false + xy: 681, 991 + size: 14, 31 + split: 2, 2, 0, 31 + orig: 14, 31 + offset: 0, 0 + index: -1 +tab-active + rotate: false + xy: 520, 565 + size: 10, 21 + split: 4, 4, 3, 1 + orig: 10, 21 + offset: 0, 0 + index: -1 +tab-inactive + rotate: false + xy: 123, 354 + size: 8, 21 + split: 3, 3, 2, 1 + orig: 8, 21 + offset: 0, 0 + index: -1 +textfield-light + rotate: false + xy: 587, 942 + size: 14, 14 + split: 3, 3, 4, 3 + orig: 14, 14 + offset: 0, 0 + index: -1 +textfield-light-down + rotate: false + xy: 555, 941 + size: 14, 14 + split: 3, 3, 4, 3 + orig: 14, 14 + offset: 0, 0 + index: -1 +textfield-light-over + rotate: false + xy: 571, 941 + size: 14, 14 + split: 3, 3, 4, 3 + orig: 14, 14 + offset: 0, 0 + index: -1 +textfield-over + rotate: false + xy: 571, 941 + size: 14, 14 + split: 2, 2, 3, 2 + orig: 14, 14 + offset: 0, 0 + index: -1 +thumbnail + rotate: false + xy: 882, 978 + size: 4, 4 + split: 1, 2, 1, 2 + orig: 4, 4 + offset: 0, 0 + index: -1 +thumbnail-over + rotate: false + xy: 26, 269 + size: 4, 4 + split: 1, 2, 1, 2 + orig: 4, 4 + offset: 0, 0 + index: -1 +tint-border + rotate: false + xy: 2, 2 + size: 6, 6 + split: 2, 2, 2, 2 + orig: 6, 6 + offset: 0, 0 + index: -1 +tool-align + rotate: false + xy: 331, 462 + size: 22, 23 + orig: 22, 23 + offset: 0, 0 + index: -1 +tool-conuslight + rotate: false + xy: 539, 957 + size: 22, 23 + orig: 22, 23 + offset: 0, 0 + index: -1 +tool-label + rotate: false + xy: 2, 250 + size: 22, 23 + orig: 22, 23 + offset: 0, 0 + index: -1 +tool-mesh + rotate: false + xy: 51, 352 + size: 22, 23 + orig: 22, 23 + offset: 0, 0 + index: -1 +tool-move + rotate: false + xy: 697, 999 + size: 22, 23 + orig: 22, 23 + offset: 0, 0 + index: -1 +tool-sphericlight + rotate: false + xy: 331, 437 + size: 22, 23 + orig: 22, 23 + offset: 0, 0 + index: -1 +tool-transform + rotate: false + xy: 563, 957 + size: 22, 23 + orig: 22, 23 + offset: 0, 0 + index: -1 +toolbar-bg + rotate: false + xy: 51, 320 + size: 8, 4 + split: 1, 2, 1, 1 + orig: 8, 4 + offset: 0, 0 + index: -1 +toolbar-down + rotate: false + xy: 753, 972 + size: 8, 9 + split: 2, 2, 3, 3 + orig: 8, 9 + offset: 0, 0 + index: -1 +toolbar-normal + rotate: false + xy: 763, 972 + size: 8, 9 + split: 2, 2, 3, 3 + orig: 8, 9 + offset: 0, 0 + index: -1 +toolbar-over + rotate: false + xy: 773, 972 + size: 8, 9 + split: 2, 2, 3, 3 + orig: 8, 9 + offset: 0, 0 + index: -1 +tooltip-bg + rotate: false + xy: 26, 264 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +touchpad-knob + rotate: false + xy: 282, 412 + size: 22, 22 + orig: 22, 22 + offset: 0, 0 + index: -1 +tree-minus + rotate: false + xy: 813, 973 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +tree-over + rotate: false + xy: 66, 323 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +tree-plus + rotate: false + xy: 823, 973 + size: 8, 8 + orig: 8, 8 + offset: 0, 0 + index: -1 +vis-blue + rotate: false + xy: 666, 985 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +vis-check + rotate: false + xy: 603, 942 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-check-down + rotate: false + xy: 619, 942 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-check-over + rotate: false + xy: 536, 925 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-check-tick + rotate: false + xy: 552, 925 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-check-tick-disabled + rotate: false + xy: 568, 925 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-radio + rotate: false + xy: 635, 942 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-radio-down + rotate: false + xy: 255, 378 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-radio-over + rotate: false + xy: 271, 377 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-radio-tick + rotate: false + xy: 287, 377 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-radio-tick-disabled + rotate: false + xy: 312, 381 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +vis-red + rotate: false + xy: 648, 968 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +white + rotate: false + xy: 32, 270 + size: 3, 3 + orig: 3, 3 + offset: 0, 0 + index: -1 +window + rotate: false + xy: 2, 300 + size: 31, 75 + split: 6, 6, 32, 7 + orig: 31, 75 + offset: 0, 0 + index: -1 +window-bg + rotate: false + xy: 653, 973 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +window-noborder + rotate: false + xy: 652, 988 + size: 27, 34 + split: 5, 4, 26, 3 + orig: 27, 34 + offset: 0, 0 + index: -1 diff --git a/assets/style/uiskin.json b/assets/style/uiskin.json new file mode 100644 index 00000000..5785b796 --- /dev/null +++ b/assets/style/uiskin.json @@ -0,0 +1,777 @@ +{ + com.badlogic.gdx.graphics.g2d.BitmapFont: { + default-font: { + file: myriad-medium.fnt + }, + small-font: { + file: myriad-medium-small.fnt + }, + big-font: { + file: myriad-medium-big.fnt + }, + default-font-normal: { + file: myriad-medium.fnt + }, + small-font-normal: { + file: myriad-medium-small.fnt + }, + big-font-normal: { + file: myriad-medium-big.fnt + } + }, + com.badlogic.gdx.graphics.Color: { + hyperlap2d-menuitem-grey: { + a: 1, + b: 0.87, + g: 0.87, + r: 0.87 + }, + hyperlap2d-menuitem-disabled-grey: { + a: 1, + b: 0.45, + g: 0.45, + r: 0.45 + }, + hyperlap2d-menuitem-shortcut-grey: { + a: 1, + b: 0.8, + g: 0.75, + r: 0.72 + }, + hyperlap2d-button-text-black: { + a: 0.9, + b: 0.1, + g: 0.1, + r: 0.1 + }, + green: { + a: 1, + b: 0, + g: 1, + r: 0 + }, + white: { + a: 1, + b: 1, + g: 1, + r: 1 + }, + red: { + a: 1, + b: 0, + g: 0, + r: 1 + }, + black: { + a: 1, + b: 0, + g: 0, + r: 0 + }, + grey: { + a: 1, + b: 0.32, + g: 0.32, + r: 0.32 + }, + menuitem-grey: { + a: 1, + b: 0.65, + g: 0.65, + r: 0.65 + }, + vis-blue: { + a: 1, + b: 0.886, + g: 0.631, + r: 0.105 + }, + link-label: {a: 1, b: 0.886, g: 0.631, r: 0.105 } + }, + com.badlogic.gdx.scenes.scene2d.ui.Skin$TintedDrawable: { + dialogDim: { + name: white, + color: { + r: 0, + g: 0, + b: 0, + a: 0.45 + } + } + }, + com.badlogic.gdx.scenes.scene2d.ui.Button$ButtonStyle: { + default: { + down: button-down, + up: button + }, + toggle: { + down: button-down, + checked: button-down, + up: button + } + }, + com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle: { + default: { + down: button-down, + up: button, + over: button-over, + disabled: button, + font: default-font, + fontColor: hyperlap2d-button-text-black, + disabledFontColor: grey + }, + toggle: { + down: button-down, + up: button, + checked: button-down, + over: button-over, + font: default-font, + fontColor: white + } + }, + com.badlogic.gdx.scenes.scene2d.ui.ScrollPane$ScrollPaneStyle: { + default: { + vScroll: scroll, + vScrollKnob: scroll-knob-vertical, + hScroll: scroll-horizontal, + hScrollKnob: scroll-knob-horizontal, + background: border + }, + list: { + vScroll: scroll, + vScrollKnob: scroll-knob-vertical, + hScroll: scroll-horizontal, + hScrollKnob: scroll-knob-horizontal + } + }, + com.badlogic.gdx.scenes.scene2d.ui.SelectBox$SelectBoxStyle: { + default: { + font: default-font, + fontColor: white, + background: default-select, + scrollStyle: default, + listStyle: { + font: default-font, + selection: list-selection, + background: select-box-list-bg + } + }, + white: { + font: default-font-normal, + fontColor: black, + background: default-select-white, + scrollStyle: default, + listStyle: { + font: default-font-normal, + fontColorSelected: black, + fontColorUnselected: black, + selection: list-selection-white, + background: select-box-list-bg-white + } + } + }, + com.badlogic.gdx.scenes.scene2d.ui.SplitPane$SplitPaneStyle: { + default-vertical: { + handle: splitpane-vertical + }, + default-horizontal: { + handle: splitpane + } + }, + com.badlogic.gdx.scenes.scene2d.ui.Window$WindowStyle: { + default: { + titleFont: big-font, + background: window, + titleFontColor: white + }, + noborder: { + titleFont: big-font, + background: window-noborder, + titleFontColor: white + }, + dialog: { + titleFont: big-font, + background: window, + titleFontColor: white, + stageBackground: dialogDim + }, + box: { + titleFont: big-font, + background: box, + titleFontColor: white + } + }, + com.badlogic.gdx.scenes.scene2d.ui.ProgressBar$ProgressBarStyle: { + default-horizontal: { + background: progressbar, + knob: progressbar-filled, + knobBefore: progressbar-filled + }, + default-vertical: { + background: progressbar-vertical, + knob: progressbar-filled-vertical, + knobBefore: progressbar-filled-vertical + } + }, + com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle: { + default-horizontal: { + background: slider, + knob: slider-knob, + disabledKnob: slider-knob-disabled + }, + default-vertical: { + background: slider-vertical, + knob: slider-knob, + disabledKnob: slider-knob-disabled + } + }, + com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle: { + default: { + font: default-font, + fontColor: white + }, + small: { + font: small-font, + fontColor: white + }, + menuitem-shortcut: { + font: small-font, + fontColor: hyperlap2d-menuitem-shortcut-grey + } + }, + com.badlogic.gdx.scenes.scene2d.ui.TextField$TextFieldStyle: { + default: { + selection: selection, + background: textfield, + font: default-font, + fontColor: white, + cursor: cursor + } + }, + com.badlogic.gdx.scenes.scene2d.ui.CheckBox$CheckBoxStyle: { + default: { + checkboxOn: check-on, + checkboxOff: check-off, + font: default-font, + fontColor: white, + disabledFontColor: grey + }, + radio: { + checkboxOn: radio-on, + checkboxOff: radio-off, + font: default-font, + fontColor: white, + disabledFontColor: grey + } + }, + com.badlogic.gdx.scenes.scene2d.ui.List$ListStyle: { + default: { + fontColorUnselected: white, + selection: list-selection, + fontColorSelected: white, + font: default-font + } + }, + com.badlogic.gdx.scenes.scene2d.ui.Touchpad$TouchpadStyle: { + default: { + background: default-pane, + knob: touchpad-knob + } + }, + com.badlogic.gdx.scenes.scene2d.ui.Tree$TreeStyle: { + default: { + minus: tree-minus, + plus: tree-plus, + selection: tree-selection, + over: tree-over + } + }, + com.kotcrab.vis.ui.widget.VisTextField$VisTextFieldStyle: { + default: { + selection: selection, + background: textfield, + backgroundOver: textfield-over, + focusBorder: border, + errorBorder: border-error, + font: default-font, + fontColor: white, + disabledFontColor: grey, + cursor: cursor + }, + light: { + selection: selection, + background: textfield-light, + backgroundOver: textfield-light-over, + focusBorder: border, + errorBorder: border-error, + font: default-font, + fontColor: white, + disabledFontColor: grey, + cursor: cursor + }, + transparent: { + selection: default-select-selection, + focusBorder: border, + errorBorder: border-error, + font: default-font, + fontColor: white, + cursor: cursor + } + }, + com.kotcrab.vis.ui.widget.VisImageTextButton$VisImageTextButtonStyle: { + hierarchy-item-root: { + imageUp: icon-root, + imageDown: icon-root, + imageOver: icon-root, + font: big-font-normal + }, + hierarchy-item: { + imageUp: icon-composite2, + imageDown: icon-composite2, + imageOver: icon-composite2, + font: big-font-normal + } + }, + com.kotcrab.vis.ui.widget.VisTextButton$VisTextButtonStyle: { + default: { + down: button-down, + up: button, + over: button-over, + disabled: button, + font: big-font-normal, + fontColor: hyperlap2d-button-text-black, + disabledFontColor: grey + }, + dark: { + down: button-dark-down, + up: button-dark, + over: button-dark-over, + disabled: button-dark, + font: big-font, + fontColor: hyperlap2d-button-text-black, + disabledFontColor: grey + }, + orange: { + down: button-orange-down, + up: button-orange, + over: button-orange-over, + disabled: button-orange, + font: big-font-normal, + fontColor: hyperlap2d-button-text-black, + disabledFontColor: grey + }, + tagBtn: { + down: toolbar-over, + up: toolbar-over, + fontColor: white, + font: default-font + }, + toggle: { + down: button-down, + up: button, + checked: button-down, + over: button-over, + font: default-font, + fontColor: white, + focusBorder: border + }, + menu-bar: { + down: menu-bg-down, + up: menu-bg-up, + over: menu-bg-over, + font: big-font, + fontColor: hyperlap2d-menuitem-grey + } + }, + games.rednblack.editor.view.ui.box.resourcespanel.draggable.list.ListItemResource$ListItemResourceStyle: { + library: { + up: button-resource, + over: button-resource-over, + down: button-resource-over, + resourceUp: icon-library, + resourceDown: icon-library-over, + resourceOver: icon-library-over, + labelStyle: { + font: small-font, + fontColor: white + } + }, + particle: { + up: button-resource, + over: button-resource-over, + down: button-resource-over, + resourceUp: icon-particle, + resourceDown: icon-particle-over, + resourceOver: icon-particle-over, + labelStyle: { + font: small-font, + fontColor: white + } + } + }, + com.kotcrab.vis.ui.widget.VisImageButton$VisImageButtonStyle: { + default: { + down: button-down, + up: button, + over: button-over, + disabled: button, + focusBorder: border + }, + dark: { + down: button-dark-down, + up: button-dark, + over: button-dark-over, + disabled: button-dark + }, + toggle: { + down: button-down, + up: button, + checked: button-down, + over: button-over, + focusBorder: border + }, + close-window: { + down: button-down, + up: button, + over: button-over, + imageUp: icon-close + }, + close-panel: { + imageDown: icon-close-orange-down, + imageOver: icon-close-orange-over, + imageUp: icon-close-orange + }, + trash-button: { + imageDown: icon-trash-disabled, + imageOver: icon-trash-over, + imageUp: icon-trash + }, + close: { + down: button-red, + up: button, + over: button-over, + imageUp: icon-close + }, + close-active-tab: { + down: button-red, + up: button, + over: button-over, + imageUp: icon-close + }, + close-box: { + imageUp: box-colapse-on, + imageChecked: box-colapse-off + }, + tool-SELECTION_TOOL: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + checked: toolbar-down, + imageUp: tool-move + }, + tool-TRANSFORM_TOOL: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + checked: toolbar-down, + imageUp: tool-transform + }, + tool-TEXT_TOOL: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + checked: toolbar-down, + imageUp: tool-label + }, + tool-POINT_LIGHT_TOOL: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + checked: toolbar-down, + imageUp: tool-sphericlight + }, + tool-CONE_LIGHT_TOOL: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + checked: toolbar-down, + imageUp: tool-conuslight + }, + tool-MESH_TOOL: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + checked: toolbar-down, + imageUp: tool-mesh + }, + align-center-horisontal: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-center-horisontal + }, + align-center-vertical: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-center-vertical + }, + align-simple-down: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-simple-down + }, + align-simple-up: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-simple-up + }, + align-simple-left: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-simple-left + }, + align-simple-right: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-simple-right + }, + align-edge-down: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-edge-down + }, + align-edge-right: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-edge-right + }, + align-edge-up: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-edge-up + }, + align-edge-left: { + down: toolbar-down, + up: toolbar-normal, + over: toolbar-over, + imageUp: align-edge-left + }, + expandable-properties-button: { + imageUp: expandable-properties-collapse-on, + imageChecked: expandable-properties-collapse-off + }, + layer-lock: { + imageUp: icon-lock-inactive, + imageChecked: icon-lock-active + }, + layer-visible: { + imageUp: icon-visible-on, + imageChecked: icon-visible-off + }, + new-layer-button: { + imageDown: icon-new-layer, + imageOver: icon-new-layer, + imageUp: icon-new-layer + }, + library-link-button: { + imageUp: icon-unlink-inactive, + imageOver: icon-link-inactive, + imageChecked: icon-link-active, + imageCheckedOver: icon-unlink-active + } + }, + com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle: { + default-horizontal: { + background: slider, + knob: slider-knob, + disabledKnob: slider-knob-disabled, + knobOver: slider-knob-over, + knobDown: slider-knob-down + }, + default-vertical: { + background: slider-vertical, + knob: slider-knob, + disabledKnob: slider-knob-disabled, + knobOver: slider-knob-over, + knobDown: slider-knob-down + } + }, + com.kotcrab.vis.ui.widget.VisCheckBox$VisCheckBoxStyle: { + default: { + checkBackground: vis-check, + checkBackgroundOver: vis-check-over, + checkBackgroundDown: vis-check-down, + tick: vis-check-tick, + tickDisabled: vis-check-tick-disabled, + focusBorder: border, + errorBorder: border-error, + font: default-font, + fontColor: white, + disabledFontColor: grey + }, + radio: { + checkBackground: vis-radio, + checkBackgroundOver: vis-radio-over, + checkBackgroundDown: vis-radio-down, + tick: vis-radio-tick, + tickDisabled: vis-radio-tick-disabled, + focusBorder: border-circle, + errorBorder: border-circle-error, + font: default-font, + fontColor: white, + disabledFontColor: grey + } +}, + com.kotcrab.vis.ui.widget.PopupMenu$PopupMenuStyle: { + default: { + background: popup-menu, + border: border + }, + noborder: { + background: button + } + }, + com.kotcrab.vis.ui.widget.Separator$SeparatorStyle: { + default: { + background: separator, + thickness: 2 + }, + vertical: { + background: separator-vertical, + thickness: 2, + }, + menu: { + background: separator-menu, + thickness: 2 + } + }, + com.kotcrab.vis.ui.widget.VisSplitPane$VisSplitPaneStyle: { + default-vertical: { + handle: splitpane-vertical, + handleOver: splitpane-vertical-over + }, + default-horizontal: { + handle: splitpane, + handleOver: splitpane-over + } + }, + com.kotcrab.vis.ui.widget.MenuItem$MenuItemStyle: { + default: { + down: popup-menu-down, + up: popup-menu, + over: popup-menu-over, + disabled: popup-menu, + font: default-font, + fontColor: hyperlap2d-menuitem-grey, + disabledFontColor: hyperlap2d-menuitem-disabled-grey, + subMenu: sub-menu + } + }, + com.kotcrab.vis.ui.Sizes: { + default: {scaleFactor: 1, spacingBottom: 8, spacingRight: 6, buttonBarSpacing: 10, menuItemIconSize: 22, borderSize: 1, spinnerButtonHeight: 12, spinnerFieldSize: 40, fileChooserViewModeBigIconsSize: 200, fileChooserViewModeMediumIconsSize: 128, fileChooserViewModeSmallIconsSize: 64, fileChooserViewModeListWidthSize: 155 }, + x2: {scaleFactor: 2, menuItemIconSize: 44, spinnerButtonHeight: 24, spinnerFieldSize: 80, spacingBottom: 8, spacingRight: 6, buttonBarSpacing: 10, borderSize: 1, fileChooserViewModeBigIconsSize: 200, fileChooserViewModeMediumIconsSize: 128, fileChooserViewModeSmallIconsSize: 64, fileChooserViewModeListWidthSize: 155 } +}, + com.badlogic.gdx.scenes.scene2d.ui.TextTooltip$TextTooltipStyle: { + default: + { + label: {font: default-font}, + background: tooltip-bg + } + }, + com.kotcrab.vis.ui.widget.Tooltip$TooltipStyle: { + default: + { + background: tooltip-bg + } + }, +// com.kotcrab.vis.ui.widget.file.FileChooserStyle: { +// default: { +// highlight: list-selection, +// // popupMenuStyleName: default, +// iconArrowLeft: icon-arrow-left, +// iconArrowRight: icon-arrow-right, +// iconFolder: icon-folder, +// iconFolderParent: icon-folder, +// iconFolderNew: icon-folder, +// iconDrive: icon-drive, +// iconFolderStar: icon-folder, +// iconTrash: icon-trash, +// iconFileText: icon-label, +// iconFileImage: icon-image, +// iconFilePdf: icon-label, +// iconFileAudio: icon-label +// } +// }, + com.kotcrab.vis.ui.widget.file.FileChooserStyle: { + default: {highlight: list-selection, popupMenuStyle: "default", iconArrowLeft: icon-arrow-left, iconArrowRight: icon-arrow-right, iconFolder: icon-folder, iconFolderParent: icon-folder-parent, iconFolderNew: icon-folder-new, iconDrive: icon-drive, iconFolderStar: icon-folder-star, iconTrash: icon-trash, iconStar: icon-star, iconStarOutline: icon-star-outline, iconRefresh: icon-refresh, iconFileText: icon-file-text, iconFileImage: icon-file-image, iconFilePdf: icon-file-pdf, iconFileAudio: icon-file-audio, iconListSettings: icon-list-settings, contextMenuSelectedItem: vis-radio-tick, expandDropdown: select-down } +}, + com.kotcrab.vis.ui.widget.color.ColorPickerStyle: { + default: {pickerStyle: {barSelector: color-picker-bar-selector, cross: color-picker-cross, iconArrowRight: icon-arrow-right, verticalSelector: color-picker-selector-vertical, horizontalSelector: color-picker-selector-horizontal}, titleFont: default-font, background: window, titleFontColor: white } +}, +com.kotcrab.vis.ui.widget.LinkLabel$LinkLabelStyle: { + default: {fontColor: link-label, underline: white, font: default-font } +}, +// com.kotcrab.vis.ui.widget.tabbedpane.TabbedPane$TabbedPaneStyle: { +// default: { +// //background: menu-bg, +// //bottomBar: list-selection, +// buttonStyle: { +// up: tab-inactive, +// checked: tab-active, +// font: default-font, +// fontColor: white +// } +// } +// }, + com.kotcrab.vis.ui.widget.tabbedpane.TabbedPane$TabbedPaneStyle: { + default: { + draggable: false, + background: menu-bg, + separatorBar: list-selection, + vertical: false, + buttonStyle: { + down: tab-active, + up: tab-inactive, + checked: tab-active, + over: tab-inactive, + disabled: tab-inactive, + font: default-font, + fontColor: white, + disabledFontColor: grey} }, + vertical: { + vertical: true, + background: menu-bg, + separatorBar: list-selection, + buttonStyle: { + down: button-down, + up: button, + checked: button-down, + over: button-over, + disabled: button, + font: default-font, + fontColor: white, + disabledFontColor: grey + } + } +}, + + com.kotcrab.vis.ui.widget.ListViewStyle: { + default: {scrollPaneStyle: list } +}, + com.kotcrab.vis.ui.widget.BusyBar$BusyBarStyle: { + default: {height: 2, segment: vis-blue, segmentWidth: 100, segmentOverflow: 50 }, + slim: {height: 1, segment: vis-blue, segmentWidth: 100, segmentOverflow: 50 }, + thick: {height: 6, segment: vis-blue, segmentWidth: 100, segmentOverflow: 50 } +}, + com.kotcrab.vis.ui.widget.spinner.Spinner$SpinnerStyle: { + default: {down: select-down, up: select-up } +} +} diff --git a/assets/style/uiskin.png b/assets/style/uiskin.png new file mode 100644 index 00000000..f4fcdee0 Binary files /dev/null and b/assets/style/uiskin.png differ diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..ea8c0889 --- /dev/null +++ b/build.gradle @@ -0,0 +1,98 @@ +buildscript { + repositories { + mavenCentral() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } + } + dependencies { + classpath 'com.badlogicgames.gdx:gdx-tools:1.9.10' + } +} + +plugins { + id 'java' +} + +group 'games.rednblack' +version '0.0.1' + +repositories { + mavenCentral() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } +} + +ext { + appName = 'HyperLap2D' + gdxVersion = '1.9.10' + gdxVersionBeta = '1.9.11-SNAPSHOT' + box2dlightsVersion = '1.5' + ashleyVersion = '1.7.3' + spineVersion = '3.8.55.1' + visuiVersion = '1.4.4' + + packMain = ["art/textures", "assets/style/", "uiskin"] + packSplash = ["art/splash_textures", "assets/splash/", "splash"] +} + +import com.badlogic.gdx.tools.texturepacker.TexturePacker +task packTextures { + if (project.ext.has('packMain')) { + logger.info "Calling TexturePacker: " + packMain + TexturePacker.processIfModified(file(packMain[0]).absolutePath, file(packMain[1]).absolutePath, (String)packMain[2]) + } + if (project.ext.has('packSplash')) { + logger.info "Calling TexturePacker: " + packSplash + TexturePacker.processIfModified(file(packSplash[0]).absolutePath, file(packSplash[1]).absolutePath, (String)packSplash[2]) + } +} + +project.ext.mainClassName = "games.rednblack.editor.Main" +project.ext.assetsDir = new File("assets/"); + +task run(dependsOn: classes, type: JavaExec) { + main = project.mainClassName + classpath = sourceSets.main.runtimeClasspath + standardInput = System.in + workingDir = project.assetsDir + ignoreExitValue = true +} + +task dist(type: Jar) { + from files(sourceSets.main.output.classesDirs) + from files(sourceSets.main.output.resourcesDir) + from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } + from files(project.assetsDir); + + manifest { + attributes 'Main-Class': project.mainClassName + } +} + +dependencies { + implementation "com.badlogicgames.gdx:gdx:$gdxVersion" + implementation "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" + implementation "com.badlogicgames.box2dlights:box2dlights:$box2dlightsVersion" + implementation ("com.badlogicgames.gdx:gdx-tools:$gdxVersion") { + exclude group: 'com.badlogicgames.gdx', module: 'gdx-backend-lwjgl' + } + implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" + implementation "com.badlogicgames.ashley:ashley:$ashleyVersion" + + implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersionBeta" + + implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" + implementation "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop" + implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop" + + implementation project(":hyperlap2d-common-api") + implementation project(":hyperlap2d-runtime-libgdx") + implementation project(":h2d-libgdx-spine-extension") + + implementation "com.kotcrab.vis:vis-ui:$visuiVersion" + implementation "com.esotericsoftware.spine:spine-libgdx:$spineVersion" + implementation "com.mortennobel:java-image-scaling:0.8.5" + implementation "org.apache.commons:commons-lang3:3.3.2" + implementation "org.apache.commons:commons-io:1.3.2" + implementation 'net.mountainblade:modular:1.0' + + testImplementation group: 'junit', name: 'junit', version: '4.12' +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..f3d88b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..ba94df84 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 00000000..2fe81a7d --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 00000000..9618d8d9 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/h2d-libgdx-spine-extension/build.gradle b/h2d-libgdx-spine-extension/build.gradle new file mode 100644 index 00000000..4a791721 --- /dev/null +++ b/h2d-libgdx-spine-extension/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'java' +} + +group 'games.rednblack' +version '0.0.1' + +ext { + gdxVersion = '1.9.10' + box2dlightsVersion = '1.5' + ashleyVersion = '1.7.3' + spineVersion = '3.8.55.1' +} + +repositories { + mavenCentral() +} + +dependencies { + implementation "com.badlogicgames.gdx:gdx:$gdxVersion" + implementation "com.badlogicgames.ashley:ashley:$ashleyVersion" + implementation "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" + implementation "com.badlogicgames.box2dlights:box2dlights:$box2dlightsVersion" + + implementation "com.esotericsoftware.spine:spine-libgdx:$spineVersion" + + implementation project(":hyperlap2d-runtime-libgdx") + + testImplementation group: 'junit', name: 'junit', version: '4.12' +} diff --git a/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineComponentFactory.java b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineComponentFactory.java new file mode 100644 index 00000000..5b15c26e --- /dev/null +++ b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineComponentFactory.java @@ -0,0 +1,110 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.extention.spine; + +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.physics.box2d.World; +import com.esotericsoftware.spine.*; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.SpineDataComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.data.SpineVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.factory.component.ComponentFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by azakhary on 5/22/2015. + */ +public class SpineComponentFactory extends ComponentFactory { + + private SpineObjectComponent spineObjectComponent; + + public SpineComponentFactory() { + super(); + } + + public SpineComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + } + + @Override + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + createCommonComponents(entity, vo, EntityFactory.SPINE_TYPE); + createParentNodeComponent(root, entity); + createNodeComponent(root, entity); + createPhysicsComponents(entity, vo); + createLightComponents(entity, vo); + spineObjectComponent = createSpineObjectComponent(entity, (SpineVO) vo); + createSpineDataComponent(entity, (SpineVO) vo); + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + + entity.add(component); + return component; + } + + protected SpineObjectComponent createSpineObjectComponent(Entity entity, SpineVO vo) { + ProjectInfoVO projectInfoVO = rm.getProjectVO(); + + SpineObjectComponent component = new SpineObjectComponent(); + component.skeletonJson = new SkeletonJson(rm.getSkeletonAtlas(vo.animationName)); + component.skeletonData = component.skeletonJson.readSkeletonData((rm.getSkeletonJSON(vo.animationName))); + + BoneData rootBone = component.skeletonData.getBones().get(0); // this has to be the root bone. + //TODO this does not work + //rootBone.setScale(vo.scaleX / projectInfoVO.pixelToWorld, vo.scaleY / projectInfoVO.pixelToWorld); // TODO: resolution part and multipliers + component.skeleton = new Skeleton(component.skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc). + component.worldMultiplier = 1f/projectInfoVO.pixelToWorld; + AnimationStateData stateData = new AnimationStateData(component.skeletonData); // Defines mixing (crossfading) between animations. + component.state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc). + + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + component.computeBoundBox(dimensionsComponent, component.worldMultiplier); + + component.setAnimation(vo.currentAnimationName.isEmpty() ? component.skeletonData.getAnimations().get(0).getName() : vo.currentAnimationName); + + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.scaleX = vo.scaleX; + transformComponent.scaleY = vo.scaleY; + + entity.add(component); + + return component; + } + + protected SpineDataComponent createSpineDataComponent(Entity entity, SpineVO vo) { + SpineDataComponent component = new SpineDataComponent(); + component.animationName = vo.animationName; + + component.currentAnimationName = vo.currentAnimationName.isEmpty() ? spineObjectComponent.skeletonData.getAnimations().get(0).getName() : vo.currentAnimationName; + + entity.add(component); + + return component; + } +} diff --git a/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineDrawableLogic.java b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineDrawableLogic.java new file mode 100644 index 00000000..2b3587d1 --- /dev/null +++ b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineDrawableLogic.java @@ -0,0 +1,28 @@ +package games.rednblack.h2d.extention.spine; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; +import com.esotericsoftware.spine.SkeletonRenderer; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.systems.render.logic.Drawable; + +public class SpineDrawableLogic implements Drawable { + + private ComponentMapper spineMapper; + private SkeletonRenderer skeletonRenderer; + + public SpineDrawableLogic() { + spineMapper = ComponentMapper.getFor(SpineObjectComponent.class); + skeletonRenderer = new SkeletonRenderer(); + } + + @Override + public void draw(Batch batch, Entity entity, float parentAlpha) { + SpineObjectComponent spineObjectComponent = spineMapper.get(entity); + //TODO parent alpha thing + skeletonRenderer.draw((PolygonSpriteBatch)batch, spineObjectComponent.skeleton); + } + +} diff --git a/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineDrawableLogic2.java b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineDrawableLogic2.java new file mode 100644 index 00000000..2baaaf3f --- /dev/null +++ b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineDrawableLogic2.java @@ -0,0 +1,81 @@ +package games.rednblack.h2d.extention.spine; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; +import com.badlogic.gdx.math.Affine2; +import com.badlogic.gdx.math.Matrix4; +import com.esotericsoftware.spine.SkeletonRenderer; +import games.rednblack.editor.renderer.components.ParentNodeComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.systems.render.logic.Drawable; + +public class SpineDrawableLogic2 implements Drawable { + + private ComponentMapper spineObjectComponentMapper = ComponentMapper.getFor(SpineObjectComponent.class); + private ComponentMapper transformComponentMapper = ComponentMapper.getFor(TransformComponent.class); + + private ComponentMapper spineMapper; + private SkeletonRenderer skeletonRenderer; + + public SpineDrawableLogic2() { + spineMapper = ComponentMapper.getFor(SpineObjectComponent.class); + skeletonRenderer = new SkeletonRenderer(); + } + + @Override + public void draw(Batch batch, Entity entity, float parentAlpha) { + SpineObjectComponent spineObjectComponent = spineMapper.get(entity); + + ParentNodeComponent parentNodeComponent = entity.getComponent(ParentNodeComponent.class); + Entity parentEntity = parentNodeComponent.parentEntity; + TransformComponent parentTransformComponent = transformComponentMapper.get(parentEntity); + if (parentTransformComponent.scaleX == 1 && parentTransformComponent.scaleY == 1 && parentTransformComponent.rotation == 0) { + computeTransform(entity); + applyTransform(entity, batch); + skeletonRenderer.draw((PolygonSpriteBatch)batch, spineObjectComponent.skeleton); + resetTransform(entity, batch); + } else { + + skeletonRenderer.draw((PolygonSpriteBatch)batch, spineObjectComponent.skeleton); + } + + //TODO parent alpha thing + //TODO rotation when in composite does not work well + //TODO Scale is not aware of ppwu + } + + protected Matrix4 computeTransform (Entity rootEntity) { + SpineObjectComponent spineObjectComponent = spineObjectComponentMapper.get(rootEntity); + TransformComponent curTransform = transformComponentMapper.get(rootEntity); + + Affine2 worldTransform = spineObjectComponent.worldTransform; + + float originX = curTransform.originX; + float originY = curTransform.originY; + float x = curTransform.x; + float y = curTransform.y; + float rotation = curTransform.rotation; + float scaleX = curTransform.scaleX; + float scaleY = curTransform.scaleY; + + worldTransform.setToTrnRotScl(x + originX , y + originY, rotation, scaleX, scaleY); + if (originX != 0 || originY != 0) worldTransform.translate(-originX, -originY); + worldTransform.translate(-spineObjectComponent.minX, -spineObjectComponent.minY); + + spineObjectComponent.computedTransform.set(worldTransform); + return spineObjectComponent.computedTransform; + } + + protected void applyTransform (Entity rootEntity, Batch batch) { + SpineObjectComponent spineObjectComponent = spineObjectComponentMapper.get(rootEntity); + spineObjectComponent.oldTransform.set(batch.getTransformMatrix()); + batch.setTransformMatrix(spineObjectComponent.computedTransform); + } + + protected void resetTransform (Entity rootEntity, Batch batch) { + SpineObjectComponent spineObjectComponent = spineObjectComponentMapper.get(rootEntity); + batch.setTransformMatrix(spineObjectComponent.oldTransform); + } +} \ No newline at end of file diff --git a/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineItemType.java b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineItemType.java new file mode 100644 index 00000000..f80ba9a1 --- /dev/null +++ b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineItemType.java @@ -0,0 +1,75 @@ +package games.rednblack.h2d.extention.spine;/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +import box2dLight.RayHandler; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.commons.IExternalItemType; +import games.rednblack.editor.renderer.components.SpineDataComponent; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.factory.component.ComponentFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.systems.render.logic.Drawable; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by azakhary on 7/20/2015. + */ +public class SpineItemType implements IExternalItemType { + + private ComponentFactory factory; + private IteratingSystem system; + private Drawable drawable; + + public SpineItemType() { + factory = new SpineComponentFactory(); + system = new SpineSystem(); + drawable = new SpineDrawableLogic2(); + } + + @Override + public int getTypeId() { + return EntityFactory.SPINE_TYPE; + } + + @Override + public Drawable getDrawable() { + return drawable; + } + + @Override + public IteratingSystem getSystem() { + return system; + } + + @Override + public ComponentFactory getComponentFactory() { + return factory; + } + + @Override + public void injectMappers() { + ComponentRetriever.addMapper(SpineDataComponent.class); + ComponentRetriever.addMapper(SpineObjectComponent.class); + } + + @Override + public void injectDependencies(RayHandler rayHandler, World world, IResourceRetriever rm) { + factory.injectDependencies(rayHandler, world, rm); + } +} diff --git a/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineObjectComponent.java b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineObjectComponent.java new file mode 100644 index 00000000..dca3e8d9 --- /dev/null +++ b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineObjectComponent.java @@ -0,0 +1,78 @@ +package games.rednblack.h2d.extention.spine; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.math.Affine2; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.FloatArray; +import com.esotericsoftware.spine.*; +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; +import games.rednblack.editor.renderer.components.DimensionsComponent; + +public class SpineObjectComponent implements Component { + public SkeletonData skeletonData; + public Skeleton skeleton; + public SkeletonJson skeletonJson; + public AnimationState state; + public float minX; + public float minY; + public float worldMultiplier; + private FloatArray temp = new FloatArray(); + public final Affine2 worldTransform = new Affine2(); + public final Matrix4 computedTransform = new Matrix4(); + public final Matrix4 oldTransform = new Matrix4(); + + public Array getAnimations() { + return skeletonData.getAnimations(); + } + + public void setAnimation(String animName) { + state.setAnimation(0, animName, true); + } + + public AnimationState getState() { + return state; + } + + public void computeBoundBox(DimensionsComponent dimensionsComponent, float worldMultiplier) { + skeleton.updateWorldTransform(); + Array drawOrder = skeleton.getDrawOrder(); + minX = Float.MAX_VALUE; + minY = Float.MAX_VALUE; + float maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE; + for (int i = 0, n = drawOrder.size; i < n; i++) { + Slot slot = drawOrder.get(i); + if (!slot.getBone().isActive()) continue; + int verticesLength = 0; + float[] vertices = null; + Attachment attachment = slot.getAttachment(); + if (attachment instanceof RegionAttachment) { + verticesLength = 8; + vertices = temp.setSize(8); + ((RegionAttachment)attachment).computeWorldVertices(slot.getBone(), vertices, 0, 2); + } else if (attachment instanceof MeshAttachment) { + MeshAttachment mesh = (MeshAttachment)attachment; + verticesLength = mesh.getWorldVerticesLength(); + vertices = temp.setSize(verticesLength); + mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2); + } + if (vertices != null) { + for (int ii = 0; ii < verticesLength; ii += 2) { + float x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + + dimensionsComponent.width = (maxX - minX);// * worldMultiplier; + dimensionsComponent.height = (maxY - minY);// * worldMultiplier; + + //minX *= worldMultiplier; + //minY *= worldMultiplier; + } +} diff --git a/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineSystem.java b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineSystem.java new file mode 100644 index 00000000..bcd930f8 --- /dev/null +++ b/h2d-libgdx-spine-extension/src/main/java/games/rednblack/h2d/extention/spine/SpineSystem.java @@ -0,0 +1,61 @@ +package games.rednblack.h2d.extention.spine; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.ParentNodeComponent; +import games.rednblack.editor.renderer.components.SpineDataComponent; +import games.rednblack.editor.renderer.components.TransformComponent; + +public class SpineSystem extends IteratingSystem { + + private ComponentMapper spineObjectComponentMapper = ComponentMapper.getFor(SpineObjectComponent.class); + private ComponentMapper transformComponentMapper = ComponentMapper.getFor(TransformComponent.class); + private ComponentMapper dimensionsComponentMapper = ComponentMapper.getFor(DimensionsComponent.class); + + public SpineSystem() { + super(Family.all(SpineDataComponent.class).get()); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + + TransformComponent transformComponent = transformComponentMapper.get(entity); + SpineObjectComponent spineObjectComponent = spineObjectComponentMapper.get(entity); + DimensionsComponent dimensionsComponent = dimensionsComponentMapper.get(entity); + + ParentNodeComponent parentNodeComponent = entity.getComponent(ParentNodeComponent.class); + Entity parentEntity = parentNodeComponent.parentEntity; + TransformComponent parentTransformComponent = transformComponentMapper.get(parentEntity); + float offsetX = 0; + float offsetY = 0; + + if (parentTransformComponent.scaleX == 1 && parentTransformComponent.scaleY == 1 && parentTransformComponent.rotation == 0) { + offsetX = parentTransformComponent.x; + offsetY = parentTransformComponent.y; + + while (true) { + parentNodeComponent = parentEntity.getComponent(ParentNodeComponent.class); + if (parentNodeComponent == null) { + break; + } + + parentEntity = parentNodeComponent.parentEntity; + if (parentEntity == null) { + break; + } + + parentTransformComponent = transformComponentMapper.get(parentEntity); + offsetX += parentTransformComponent.x; + offsetY += parentTransformComponent.y; + } + } + + spineObjectComponent.skeleton.updateWorldTransform(); // + spineObjectComponent.state.update(deltaTime); // Update the animation time. + spineObjectComponent.state.apply(spineObjectComponent.skeleton); // Poses skeleton using current animations. This sets the bones' local SRT. + //spineObjectComponent.skeleton.setPosition(transformComponent.x - spineObjectComponent.minX + offsetX, transformComponent.y - spineObjectComponent.minY + offsetY); + } +} diff --git a/hyperlap2d-common-api/build.gradle b/hyperlap2d-common-api/build.gradle new file mode 100644 index 00000000..d56917a9 --- /dev/null +++ b/hyperlap2d-common-api/build.gradle @@ -0,0 +1,30 @@ +plugins { + id 'java' +} + +group 'games.rednblack' +version '0.0.1' + +repositories { + mavenCentral() +} + +ext { + gdxVersion = '1.9.10' + box2DLightsVersion = '1.5' + ashleyVersion = '1.7.3' + visUIVersion = '1.4.4' +} + +dependencies { + implementation "com.badlogicgames.gdx:gdx:$gdxVersion" + implementation "com.badlogicgames.ashley:ashley:$ashleyVersion" + implementation "com.kotcrab.vis:vis-ui:$visUIVersion" + implementation "com.badlogicgames.box2dlights:box2dlights:$box2DLightsVersion" + + implementation 'net.mountainblade:modular:1.0' + + implementation project(":hyperlap2d-runtime-libgdx") + + testImplementation group: 'junit', name: 'junit', version: '4.12' +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/core/Controller.java b/hyperlap2d-common-api/src/main/java/com/puremvc/core/Controller.java new file mode 100644 index 00000000..8a68216f --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/core/Controller.java @@ -0,0 +1,80 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.core; + +import com.puremvc.patterns.command.Command; +import com.puremvc.patterns.observer.Notification; + +/** + * The interface definition for a PureMVC Controller. + *

+ *

+ * In PureMVC, an IController implementor follows the 'Command + * and Controller' strategy, and assumes these responsibilities: + *

    + *
  • Remembering which ICommands are intended to handle which + * INotifications.
  • + *
  • Registering itself as an IObserver with the + * View for each INotification that it has an + * ICommand mapping for.
  • + *
  • Creating a new instance of the proper ICommand to handle + * a given INotification when notified by the View.
  • + *
  • Calling the ICommand's execute method, + * passing in the INotification.
  • + *
+ * + * @see com.puremvc.patterns.observer Notification + * @see com.puremvc.patterns.command Command + */ +public interface Controller { + + /** + * Register a particular ICommand class as the handler for a + * particular INotification. + * + * @param notificationName the name of the INotification + * @param command the Class of the ICommand + */ + void registerCommand(String notificationName, Class command); + + /** + * Execute the ICommand previously registered as the handler + * for INotifications with the given notification name. + * + * @param notification the INotification to execute the associated + * ICommand for + */ + void executeCommand(Notification notification); + + /** + * Remove a previously registered ICommand to + * INotification mapping. + * + * @param notificationName the name of the INotification to remove the + * ICommand mapping for + */ + void removeCommand(String notificationName); + + /** + * Check if a Command is registered for a given Notification + * + * @param notificationName + * @return whether a Command is currently registered for the given notificationName. + */ + boolean hasCommand(String notificationName); +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/core/CoreController.java b/hyperlap2d-common-api/src/main/java/com/puremvc/core/CoreController.java new file mode 100644 index 00000000..c263a5cc --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/core/CoreController.java @@ -0,0 +1,200 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.core; + + +import java.util.HashMap; +import java.util.Map; + +import com.puremvc.patterns.command.Command; +import com.puremvc.patterns.observer.BaseObserver; +import com.puremvc.patterns.observer.Notification; + +/** + * A Singleton Controller implementation. + *

+ *

+ * In PureMVC, the Controller class follows the + * 'Command and Controller' strategy, and assumes these + * responsibilities: + *

    + *
  • Remembering which ICommands + * are intended to handle which INotifications.
  • + *
  • Registering itself as an IObserver with + * the View for each INotification + * that it has an ICommand mapping for.
  • + *
  • Creating a new instance of the proper ICommand + * to handle a given INotification when notified by the View.
  • + *
  • Calling the ICommand's execute + * method, passing in the INotification.
  • + *
+ *

+ *

+ * Your application must register ICommands with the + * Controller. + *

+ * The simplest way is to subclass Facade, + * and use its initializeController method to add your + * registrations. + * + * @see CoreView View + * @see BaseObserver Observer + * @see com.puremvc.patterns.observer.Notification Notification + * @see com.puremvc.patterns.command.SimpleCommand SimpleCommand + * @see com.puremvc.patterns.command.MacroCommand MacroCommand + */ +public class CoreController implements Controller { + + /** + * Reference to the singleton instance + */ + protected static CoreController instance; + /** + * Mapping of Notification names to Command Class references + */ + protected Map> commandMap; + + /** + * Local reference to View + */ + protected CoreView view; + + /** + * Constructor. + *

+ *

+ * This IController implementation is a Singleton, so you + * should not call the constructor directly, but instead call the static + * Singleton Factory method Controller.getInstance() + */ + protected CoreController() { + instance = this; + commandMap = new HashMap<>(); + initializeController(); + } + + /** + * Controller Singleton Factory method. + * + * @return the Singleton instance of Controller + */ + public synchronized static CoreController getInstance() { + if (instance == null) { + instance = new CoreController(); + } + + return instance; + } + + /** + * Initialize the Singleton Controller instance. + *

+ *

Called automatically by the constructor.

+ *

+ *

Note that if you are using a subclass of View + * in your application, you should also subclass Controller + * and override the initializeController method in the + * following way:

+ *

+ *

+ * // ensure that the Controller is talking to my IView implementation + * override public function initializeController( ) : void + * { + * view = MyView.getInstance(); + * } + * + */ + protected void initializeController() { + view = CoreView.getInstance(); + } + + /** + * If an ICommand has previously been registered to handle a + * the given INotification, then it is executed. + * + * @param note The notification to send associated with the command to call. + */ + public void executeCommand(Notification note) { + //No reflexion in GWT + Class commandClass = commandMap.get(note.getName()); + if (commandClass != null) { + Command command; + try { + command = commandClass.newInstance(); + command.execute(note); + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + + } + } + + /** + * Register a particular ICommand class as the handler for a + * particular INotification. + *

+ *

+ * If an ICommand has already been registered to handle + * INotifications with this name, it is no longer used, the + * new ICommand is used instead. + *

+ *

+ * The Observer for the new ICommand is only created if this the + * first time an ICommand has been regisered for this Notification name. + * + * @param notificationName the name of the Notification + * @param command an instance of Command + */ + public void registerCommand(String notificationName, Class command) { + if (null != commandMap.put(notificationName, command)) { + return; + } + + view.registerObserver + ( + notificationName, + new BaseObserver(this::executeCommand, this) + ); + } + + /** + * Remove a previously registered ICommand to + * INotification mapping. + * + * @param notificationName the name of the INotification to remove the + * ICommand mapping for + */ + public void removeCommand(String notificationName) { + // if the Command is registered... + if (hasCommand(notificationName)) { + // remove the observer + view.removeObserver(notificationName, this); + commandMap.remove(notificationName); + } + } + + /** + * Check if a Command is registered for a given Notification + * + * @param notificationName The name of the command to check for existance. + * @return whether a Command is currently registered for the given notificationName. + */ + public boolean hasCommand(String notificationName) { + return commandMap.containsKey(notificationName); + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/core/CoreModel.java b/hyperlap2d-common-api/src/main/java/com/puremvc/core/CoreModel.java new file mode 100644 index 00000000..2b1ec43c --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/core/CoreModel.java @@ -0,0 +1,153 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.core; + + +import java.util.HashMap; +import java.util.Map; + +import com.puremvc.patterns.proxy.Proxy; + +/** + * A Singleton IModel implementation. + *

+ *

+ * In PureMVC, the Model class provides + * access to model objects (Proxies) by named lookup. + *

+ *

+ * The Model assumes these responsibilities:

+ *

+ *

    + *
  • Maintain a cache of IProxy instances.
  • + *
  • Provide methods for registering, retrieving, and removing + * IProxy instances.
  • + *
+ *

+ *

+ * Your application must register IProxy instances + * with the Model. Typically, you use an + * ICommand to create and register IProxy + * instances once the Facade has initialized the Core + * actors.

+ * + * @see com.puremvc.patterns.proxy.BaseProxy BaseProxy + * @see com.puremvc.patterns.proxy.Proxy Proxy + */ +public class CoreModel implements Model { + + /** + * Singleton instance + */ + protected static CoreModel instance; + + /** + * Mapping of proxyNames to IProxy instances + */ + protected Map proxyMap; + + /** + * Constructor. + *

+ *

+ * This IModel implementation is a Multiton, + * so you should not call the constructor + * directly, but instead call the static Multiton + * Factory method Model.getInstance( multitonKey ) + * + * @throws Error Error if instance for this Multiton key instance has already been constructed + */ + protected CoreModel() { + instance = this; + proxyMap = new HashMap<>(); + initializeModel(); + } + + /** + * Model Multiton Factory method. + * + * @return the instance for this Multiton key + */ + public synchronized static CoreModel getInstance() { + if (instance == null) { + instance = new CoreModel(); + } + + return instance; + } + + /** + * Initialize the Singleton Model instance. + *

+ *

+ * Called automatically by the constructor, this is your opportunity to + * initialize the Singleton instance in your subclass without overriding the + * constructor. + *

+ */ + protected void initializeModel() { + } + + /** + * Register an Proxy with the Model. + * + * @param proxy an Proxy to be held by the Model. + */ + public void registerProxy(Proxy proxy) { + proxyMap.put(proxy.getProxyName(), proxy); + proxy.onRegister(); + } + + /** + * Remove an Proxy from the Model. + * + * @param proxyName Name of the Proxy instance to be removed. + * @return The IProxy that was removed from the Model + */ + public Proxy removeProxy(String proxyName) { + Proxy proxy = proxyMap.get(proxyName); + + if (proxy != null) { + proxyMap.remove(proxyName); + proxy.onRemove(); + } + + return proxy; + } + + /** + * Retrieve an Proxy from the Model. + * + * @param proxy + * @return the Proxy instance previously registered with the + * given proxyName. + */ + public T retrieveProxy(String proxy) { + return (T) proxyMap.get(proxy); + } + + /** + * Check if a Proxy is registered + * + * @param proxyName Name of the Proxy object to check for existance. + * @return Whether a Proxy is currently registered with the given proxyName. + */ + public boolean hasProxy(String proxyName) { + return proxyMap.containsKey(proxyName); + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/core/CoreView.java b/hyperlap2d-common-api/src/main/java/com/puremvc/core/CoreView.java new file mode 100644 index 00000000..623d112d --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/core/CoreView.java @@ -0,0 +1,271 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.core; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import com.puremvc.patterns.mediator.Mediator; +import com.puremvc.patterns.observer.BaseObserver; +import com.puremvc.patterns.observer.Notification; +import com.puremvc.patterns.observer.Observer; + +/** + * A Singleton IView implementation. + *

+ *

+ * In PureMVC, the View class assumes these responsibilities: + *

    + *
  • Maintain a cache of IMediator instances.
  • + *
  • Provide methods for registering, retrieving, and removing + * IMediators.
  • + *
  • Managing the observer lists for each INotification in the + * application.
  • + *
  • Providing a method for attaching IObservers to an + * INotification's observer list.
  • + *
  • Providing a method for broadcasting an INotification.
  • + *
  • Notifying the IObservers of a given + * INotification when it broadcast.
  • + *
+ * + * @see com.puremvc.patterns.mediator.Mediator Mediator + * @see com.puremvc.patterns.observer.Observer Observer + * @see com.puremvc.patterns.observer.Notification Notification + */ +public class CoreView implements View { + + // Singleton instance + private static CoreView instance; + // Mapping of Mediator names to Mediator instances + // Mapping of Notification names to Observer lists + private HashMap> observerMap; + private HashMap mediatorMap; + + /** + * Constructor. + *

+ *

+ * This IView implementation is a Singleton, so you should + * not call the constructor directly, but instead call the static Singleton + * Factory method View.getInstance() + * + * @throws Error Error if Singleton instance has already been constructed + */ + protected CoreView() { + instance = this; + + this.mediatorMap = new HashMap<>(); + this.observerMap = new HashMap<>(); + initializeView(); + } + + /** + * View Singleton Factory method. + * + * @return The Singleton instance of View + */ + public synchronized static CoreView getInstance() { + if (instance == null) + instance = new CoreView(); + + return instance; + } + + /** + * Initialize the Singleton View instance. + *

+ *

+ * Called automatically by the constructor, this is your opportunity to + * initialize the Singleton instance in your subclass without overriding + * the constructor. + *

+ */ + protected void initializeView() { + } + + /** + * Notify the Observers for a particular + * Notification. + *

+ *

+ * All previously attached Observers for this + * Notification's list are notified and are passed a + * reference to the Notification in the order in which they + * were registered. + *

+ * + * @param note the Notification to notify + * Observers of. + */ + public void notifyObservers(Notification note) { + List observerList = observerMap.get(note.getName()); + if (observerList != null) { + + // Copy observers from reference array to working array, + // since the reference array may change during the + //notification loop + Observer[] observers = observerList.toArray(new Observer[observerList.size()]); + + // Notify Observers from the working array + for (Observer observer : observers) { + observer.notifyObserver(note); + } + } + } + + /** + * Remove the observer for a given notifyContext from an observer list for a given Notification name. + * + * @param notificationName Which observer list to remove from + * @param notifyContext Remove the observer with this object as its notifyContext + */ + public void removeObserver(String notificationName, Object notifyContext) { + // the observer list for the notification under inspection + List observers = observerMap.get(notificationName); + + if (observers != null) { + // find the observer for the notifyContext + for (int i = 0; i < observers.size(); i++) { + BaseObserver observer = (BaseObserver) observers.get(i); + if (observer.compareNotifyContext(notifyContext)) { + observers.remove(observer); + } + } + + // Also, when a Notification's Observer list length falls to + // zero, delete the notification key from the observer map + if (observers.size() == 0) { + observerMap.remove(notificationName); + } + } + } + + /** + * Register an Mediator instance with the View. + *

+ *

+ * Registers the Mediator so that it can be retrieved by + * name, and further interrogates the Mediator for its + * Notification interests. + *

+ *

+ * If the Mediator returns any Notification + * names to be notified about, an Observer is created + * encapsulating the Mediator instance's + * handleNotification method and registering it as an + * Observer for all Notifications the + * Mediator is interested in. + *

+ * + * @param mediator the name to associate with this IMediator + * instance + */ + public void registerMediator(final Mediator mediator) { + if (mediatorMap.containsKey(mediator.getMediatorName())) { + return; + } + + // Register the Mediator for retrieval by name + mediatorMap.put(mediator.getMediatorName(), mediator); + + // Get Notification interests, if any. + String[] noteInterests = mediator.listNotificationInterests(); + if (noteInterests.length != 0) { + // Create Observer + BaseObserver observer = new BaseObserver(mediator::handleNotification, mediator); + + // Register Mediator as Observer for its list of Notification + // interests + for (String noteInterest : noteInterests) { + registerObserver(noteInterest, observer); + } + } + + // alert the mediator that it has been registered + mediator.onRegister(); + } + + /** + * Register an Observer to be notified of + * INotifications with a given name. + * + * @param notificationName the name of the Notifications to notify this + * Observer of + * @param observer the Observer to register + */ + public void registerObserver(String notificationName, Observer observer) { + if (observerMap.get(notificationName) == null) { + observerMap.put(notificationName, new ArrayList<>()); + } + + List observers = observerMap.get(notificationName); + observers.add(observer); + } + + /** + * Remove an Mediator from the View. + * + * @param mediatorName name of the Mediator instance to be removed. + */ + public Mediator removeMediator(String mediatorName) { + // Retrieve the named mediator + Mediator mediator = mediatorMap.get(mediatorName); + + if (mediator != null) { + // for every notification this mediator is interested in... + String[] interests = mediator.listNotificationInterests(); + for (String interest : interests) { + // remove the observer linking the mediator + // to the notification interest + removeObserver(interest, mediator); + } + + // remove the mediator from the map + mediatorMap.remove(mediatorName); + + // alert the mediator that it has been removed + mediator.onRemove(); + } + + return mediator; + } + + /** + * Retrieve an Mediator from the View. + * + * @param mediatorName the name of the Mediator instance to + * retrieve. + * @return the Mediator instance previously registered with + * the given mediatorName. + */ + public T retrieveMediator(String mediatorName) { + return (T) mediatorMap.get(mediatorName); + } + + /** + * Check if a Mediator is registered or not + * + * @param mediatorName + * @return whether a Mediator is registered with the given mediatorName. + */ + public boolean hasMediator(String mediatorName) { + return mediatorMap.containsKey(mediatorName); + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/core/Model.java b/hyperlap2d-common-api/src/main/java/com/puremvc/core/Model.java new file mode 100644 index 00000000..cc1847f5 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/core/Model.java @@ -0,0 +1,72 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.core; + +import com.puremvc.patterns.proxy.Proxy; + +/** + * The interface definition for a PureMVC Model. + *

+ *

+ * In PureMVC, Model implementors provide access to + * Proxy objects by named lookup. + *

+ *

+ *

+ * An Model assumes these responsibilities: + *

+ *

+ *

    + *
  • Maintain a cache of Proxy instances
  • + *
  • Provide methods for registering, retrieving, and removing + * Proxy instances
  • + *
+ */ +public interface Model { + + /** + * Register an Proxy instance with the Model. + * + * @param proxy an object reference to be held by the Model. + */ + void registerProxy(Proxy proxy); + + /** + * Retrieve an Proxy instance from the Model. + * + * @param proxy + * @return the Proxy instance previously registered with the + * given proxyName. + */ + T retrieveProxy(String proxy); + + /** + * Remove an Proxy instance from the Model. + * + * @param proxy name of the Proxy instance to be removed. + */ + Proxy removeProxy(String proxy); + + /** + * Check if a Proxy is registered + * + * @param proxyName + * @return whether a Proxy is currently registered with the given proxyName. + */ + boolean hasProxy(String proxyName); +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/core/View.java b/hyperlap2d-common-api/src/main/java/com/puremvc/core/View.java new file mode 100644 index 00000000..2d8fa336 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/core/View.java @@ -0,0 +1,122 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.core; + +import com.puremvc.patterns.mediator.Mediator; +import com.puremvc.patterns.observer.Notification; +import com.puremvc.patterns.observer.Observer; + +/** + * The interface definition for a PureMVC View. + *

+ *

+ * In PureMVC, View implementors assume these responsibilities: + *

+ *

+ *

+ * In PureMVC, the CoreView class assumes these responsibilities: + *

    + *
  • Maintain a cache of Mediator instances.
  • + *
  • Provide methods for registering, retrieving, and removing + * Mediators.
  • + *
  • Managing the observer lists for each Notification in the + * application.
  • + *
  • Providing a method for attaching Observers to an + * Notification's observer list.
  • + *
  • Providing a method for broadcasting an Notification.
  • + *
  • Notifying the Observers of a given + * Notification when it broadcast.
  • + *
+ * + * @see com.puremvc.patterns.mediator.Mediator Mediator + * @see com.puremvc.patterns.observer.Observer Observer + * @see com.puremvc.patterns.observer.Notification Notification + */ +public interface View { + + /** + * Register an IObserver to be notified of + * INotifications with a given name. + * + * @param noteName the name of the INotifications to notify this + * IObserver of + * @param observer the IObserver to register + */ + void registerObserver(String noteName, Observer observer); + + /** + * Notify the IObservers for a particular + * INotification. + *

+ *

+ * All previously attached IObservers for this + * INotification's list are notified and are passed a + * reference to the INotification in the order in which they + * were registered. + *

+ * + * @param note the INotification to notify + * IObservers of. + */ + void notifyObservers(Notification note); + + /** + * Register an IMediator instance with the View. + *

+ *

+ * Registers the IMediator so that it can be retrieved by + * name, and further interrogates the IMediator for its + * INotification interests. + *

+ *

+ * If the IMediator returns any INotification + * names to be notified about, an Observer is created + * encapsulating the IMediator instance's + * handleNotification method and registering it as an + * Observer for all INotifications the + * IMediator is interested in. + *

+ * + * @param mediator a reference to the IMediator instance + */ + void registerMediator(Mediator mediator); + + /** + * Retrieve an IMediator from the View. + * + * @param mediatorName the name of the IMediator instance to retrieve. + * @return the IMediator instance previously registered with + * the given mediatorName. + */ + T retrieveMediator(String mediatorName); + + /** + * Remove an IMediator from the View. + * + * @param mediatorName name of the IMediator instance to be removed. + */ + Mediator removeMediator(String mediatorName); + + /** + * Check if a Mediator is registered or not + * + * @param mediatorName + * @return whether a Mediator is registered with the given mediatorName. + */ + boolean hasMediator(String mediatorName); +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/command/Command.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/command/Command.java new file mode 100644 index 00000000..44b1ae93 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/command/Command.java @@ -0,0 +1,37 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.command; + +import com.puremvc.patterns.observer.Notification; +import com.puremvc.patterns.observer.Notifier; + +/** + * The interface definition for a PureMVC Command. + * + * @see com.puremvc.patterns.observer Notification + */ +public interface Command extends Notifier { + + /** + * Execute the Command's logic to handle a given + * Notification. + * + * @param notification an Notification to handle. + */ + void execute(Notification notification); +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/command/MacroCommand.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/command/MacroCommand.java new file mode 100644 index 00000000..adf281db --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/command/MacroCommand.java @@ -0,0 +1,138 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.command; + + +import java.util.Collection; +import java.util.Vector; + +import com.puremvc.patterns.observer.BaseNotifier; +import com.puremvc.patterns.observer.Notification; + + +/** + * A base ICommand implementation that executes other + * ICommands. + *

+ *

+ * A MacroCommand maintains an list of ICommand + * Class references called SubCommands. + *

+ *

+ *

+ * When execute is called, the MacroCommand + * instantiates and calls execute on each of its SubCommands + * turn. Each SubCommand will be passed a reference to the original + * INotification that was passed to the MacroCommand's + * execute method. + *

+ *

+ *

+ * Unlike SimpleCommand, your subclass should not override + * execute, but instead, should override the + * initializeMacroCommand method, calling + * addSubCommand once for each SubCommand to be executed. + *

+ *

+ *

+ * + * @see com.puremvc.core.Controller Controller + * @see com.puremvc.patterns.observer.Notification Notification + * @see com.puremvc.patterns.command.SimpleCommand SimpleCommand + */ +public class MacroCommand extends BaseNotifier implements Command { + + private Collection> subCommands = null; + + /** + * Constructor. + *

+ *

+ * You should not need to define a constructor, instead, override the + * initializeMacroCommand method. + *

+ *

+ *

+ * If your subclass does define a constructor, be sure to call + * super(). + *

+ */ + public MacroCommand() { + subCommands = new Vector<>(); + initializeMacroCommand(); + } + + /** + * Initialize the MacroCommand. + *

+ *

+ * In your subclass, override this method to initialize the + * MacroCommand's SubCommand list with + * ICommand class references like this: + *

+ *

+ *

// Initialize MyMacroCommand override protected function + * initializeMacroCommand( ) : void { addSubCommand( + * com.me.myapp.controller.FirstCommand ); addSubCommand( + * com.me.myapp.controller.SecondCommand ); addSubCommand( + * com.me.myapp.controller.ThirdCommand ); } + *

+ *

+ * Note that SubCommands may be any ICommand + * implementor, MacroCommands or SimpleCommands + * are both acceptable. + */ + protected void initializeMacroCommand() { + } + + /** + * Add a SubCommand. + *

+ *

+ * The SubCommands will be called in First In/First Out (FIFO) + * order. + *

+ * + * @param commandClassRef a reference to the Class of the + * ICommand. + */ + protected void addSubCommand(Class commandClassRef) { + subCommands.add(commandClassRef); + } + + /** + * Execute this MacroCommand's SubCommands. + *

+ *

+ * The SubCommands will be called in First In/First Out (FIFO) + * order. + * + * @param notification the INotification object to be passsed to each + * SubCommand. + */ + public void execute(Notification notification) { + for (Class commandClass : subCommands) { + try { + Command command = commandClass.newInstance(); + command.execute(notification); + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/command/SimpleCommand.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/command/SimpleCommand.java new file mode 100644 index 00000000..9cdcf32e --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/command/SimpleCommand.java @@ -0,0 +1,53 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.command; + + +import com.puremvc.patterns.observer.BaseNotifier; +import com.puremvc.patterns.observer.Notification; + +/** + * A base ICommand implementation. + *

+ *

+ * Your subclass should override the execute method where your + * business logic will handle the INotification. + *

+ * + * @see com.puremvc.core.Controller Controller + * @see com.puremvc.patterns.observer.Notification Notification + * @see com.puremvc.patterns.command.MacroCommand MacroCommand + */ +public class SimpleCommand extends BaseNotifier implements Command { + + /** + * Fulfill the use-case initiated by the given INotification. + *

+ *

+ * In the Command Pattern, an application use-case typically begins with + * some user action, which results in an INotification being + * broadcast, which is handled by business logic in the execute + * method of an ICommand. + *

+ * + * @param notification the INotification to handle. + */ + public void execute(Notification notification) { + } + +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/facade/Facade.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/facade/Facade.java new file mode 100644 index 00000000..3150ad38 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/facade/Facade.java @@ -0,0 +1,144 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.facade; + +import com.puremvc.patterns.command.Command; +import com.puremvc.patterns.mediator.Mediator; +import com.puremvc.patterns.observer.Notification; +import com.puremvc.patterns.observer.Notifier; +import com.puremvc.patterns.proxy.Proxy; + +/** + * The interface definition for a PureMVC Facade. + *

+ *

+ * The Facade Pattern suggests providing a single class to act as a central + * point of communication for a subsystem. + *

+ *

+ *

+ * In PureMVC, the Facade acts as an interface between the core MVC actors + * (Model, View, Controller) and the rest of your application. + *

+ * + * @see com.puremvc.core.Model Model + * @see com.puremvc.core.View View + * @see com.puremvc.core.Controller Controller + * @see com.puremvc.patterns.command.Command Command + * @see com.puremvc.patterns.observer.Notification Notification + */ +public interface Facade extends Notifier { + /** + * Notify Observers of an INotification. + * + * @param note the INotification to have the View + * notify observers of. + */ + void notifyObservers(Notification note); + + /** + * Register an IProxy with the Model by name. + * + * @param proxy the IProxy to be registered with the + * Model. + */ + void registerProxy(Proxy proxy); + + /** + * Retrieve a IProxy from the Model by name. + * + * @param proxyName the name of the IProxy instance to be + * retrieved. + * @return the IProxy previously regisetered by + * proxyName with the Model. + */ + T retrieveProxy(String proxyName); + + /** + * Remove an IProxy instance from the Model by + * name. + * + * @param proxyName the IProxy to remove from the + * Model. + */ + T removeProxy(String proxyName); + + /** + * Check if a Proxy is registered + * + * @param proxyName + * @return whether a Proxy is currently registered with the given proxyName. + */ + boolean hasProxy(String proxyName); + + /** + * Register an ICommand with the Controller. + * + * @param noteName the name of the INotification to associate the + * ICommand with. + * @param commandClassRef a reference to the Class of the + * ICommand. + */ + void registerCommand(String noteName, Class commandClassRef); + + /** + * Remove a previously registered ICommand to INotification mapping from the Controller. + * + * @param notificationName the name of the INotification to remove the ICommand mapping for + */ + void removeCommand(String notificationName); + + /** + * Check if a Command is registered for a given Notification + * + * @param notificationName + * @return whether a Command is currently registered for the given notificationName. + */ + boolean hasCommand(String notificationName); + + /** + * Register an IMediator instance with the View. + * + * @param mediator a reference to the IMediator instance + */ + void registerMediator(Mediator mediator); + + /** + * Retrieve an IMediator instance from the View. + * + * @param mediatorName the name of the IMediator instance to retrievve + * @return the IMediator previously registered with the given + * mediatorName. + */ + T retrieveMediator(String mediatorName); + + /** + * Check if a Mediator is registered or not + * + * @param mediatorName + * @return whether a Mediator is registered with the given mediatorName. + */ + boolean hasMediator(String mediatorName); + + /** + * Remove a IMediator instance from the View. + * + * @param mediatorName name of the IMediator instance to be removed. + */ + Mediator removeMediator(String mediatorName); +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/facade/SimpleFacade.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/facade/SimpleFacade.java new file mode 100644 index 00000000..282f8cc1 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/facade/SimpleFacade.java @@ -0,0 +1,364 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.facade; + + +import com.puremvc.core.CoreController; +import com.puremvc.core.CoreModel; +import com.puremvc.core.CoreView; +import com.puremvc.patterns.command.Command; +import com.puremvc.patterns.mediator.Mediator; +import com.puremvc.patterns.observer.BaseNotification; +import com.puremvc.patterns.observer.Notification; +import com.puremvc.patterns.proxy.Proxy; + +/** + * A base Singleton Facade implementation. + * + * @see CoreModel Model + * @see CoreView View + * @see CoreController Controller + */ +public class SimpleFacade implements Facade { + /** + * The Singleton instance of the Facade + */ + protected static SimpleFacade instance = null; + + /** + * Reference to the Controller + */ + protected CoreController controller = null; + + /** + * Reference to the Model + */ + protected CoreModel model = null; + + /** + * Reference to the View + */ + protected CoreView view = null; + + /** + * Constructor. + *

+ *

+ * This IFacade implementation is a Singleton, so you should + * not call the constructor directly, but instead call the static Singleton + * Factory method Facade.getInstance() + */ + protected SimpleFacade() { + initializeFacade(); + } + + /** + * Facade Singleton Factory method + * + * @return The Singleton instance of the Facade + */ + public synchronized static SimpleFacade getInstance() { + if (instance == null) { + instance = new SimpleFacade(); + } + + return instance; + } + + /** + * Initialize the Multiton Facade instance. + *

+ *

+ * Called automatically by the constructor. Override in your + * subclass to do any subclass specific initializations. Be + * sure to call super.initializeFacade(), though.

+ */ + protected void initializeFacade() { + initializeModel(); + initializeController(); + initializeView(); + } + + /** + * Initialize the Controller. + *

+ *

+ * Called by the initializeFacade method. Override this + * method in your subclass of Facade if one or both of the + * following are true: + *

    + *
  • You wish to initialize a different IController.
  • + *
  • You have Commands to register with the + * Controller at startup..
  • + *
+ * If you don't want to initialize a different IController, + * call super.initializeController() at the beginning of your + * method, then register Commands. + *

+ */ + protected void initializeController() { + if (controller != null) { + return; + } + + controller = CoreController.getInstance(); + } + + /** + * Initialize the Model. + *

+ *

+ * Called by the initializeFacade method. Override this + * method in your subclass of Facade if one or both of the + * following are true: + *

    + *
  • You wish to initialize a different IModel.
  • + *
  • You have Proxys to register with the Model that do + * not retrieve a reference to the Facade at construction time.
  • + *
+ * If you don't want to initialize a different IModel, call + * super.initializeModel() at the beginning of your method, + * then register Proxys. + *

+ * Note: This method is rarely overridden; in practice you are more + * likely to use a Command to create and register Proxys + * with the Model, since Proxys with mutable + * tools will likely need to send INotifications and thus + * will likely want to fetch a reference to the Facade during + * their construction. + *

+ */ + protected void initializeModel() { + if (model != null) { + return; + } + + model = CoreModel.getInstance(); + } + + /** + * Initialize the View. + *

+ *

+ * Called by the initializeFacade method. Override this + * method in your subclass of Facade if one or both of the + * following are true: + *

    + *
  • You wish to initialize a different IView.
  • + *
  • You have Observers to register with the + * View
  • + *
+ * If you don't want to initialize a different IView, call + * super.initializeView() at the beginning of your method, + * then register IMediator instances. + *

+ * Note: This method is rarely overridden; in practice you are more + * likely to use a Command to create and register + * Mediators with the View, since + * IMediator instances will need to send + * INotifications and thus will likely want to fetch a + * reference to the Facade during their construction. + *

+ */ + protected void initializeView() { + if (view != null) { + return; + } + + view = CoreView.getInstance(); + } + + /** + * Register an ICommand with the Controller by + * Notification name. + * + * @param noteName the name of the INotification to associate the + * ICommand with + * @param command an instance of the ICommand + */ + public void registerCommand(String noteName, Class command) { + controller.registerCommand(noteName, command); + } + + /** + * Remove a previously registered ICommand to INotification mapping from the Controller. + * + * @param notificationName the name of the INotification to remove the ICommand mapping for + */ + public void removeCommand(String notificationName) { + controller.removeCommand(notificationName); + } + + /** + * Check if a Command is registered for a given Notification + * + * @param notificationName + * @return whether a Command is currently registered for the given notificationName. + */ + public boolean hasCommand(String notificationName) { + return controller.hasCommand(notificationName); + } + + /** + * Register a IMediator with the View. + * + * @param mediator the name to associate with this IMediator + */ + public void registerMediator(Mediator mediator) { + if (view != null) { + view.registerMediator(mediator); + } + } + + /** + * Register an IProxy with the Model by name. + * + * @param proxy the name of the IProxy instance to be + * registered with the Model. + */ + public void registerProxy(Proxy proxy) { + model.registerProxy(proxy); + } + + + + /** + * Remove an IMediator from the View. + * + * @param mediatorName name of the IMediator to be removed. + * @return the IMediator that was removed from the View + */ + public Mediator removeMediator(String mediatorName) { + if (this.view != null) { + return this.view.removeMediator(mediatorName); + } + return null; + } + + /** + * Remove an IProxy from the Model by name. + * + * @param proxyName the IProxy to remove from the + * Model. + * @return the IProxy that was removed from the Model + */ + public Proxy removeProxy(String proxyName) { + if (model != null) { + return model.removeProxy(proxyName); + } + return null; + } + + /** + * Check if a Proxy is registered + * + * @param proxyName + * @return whether a Proxy is currently registered with the given proxyName. + */ + public boolean hasProxy(String proxyName) { + return model.hasProxy(proxyName); + } + + + /** + * Check if a Mediator is registered or not + * + * @param mediatorName + * @return whether a Mediator is registered with the given mediatorName. + */ + public boolean hasMediator(String mediatorName) { + return view.hasMediator(mediatorName); + } + + /** + * Retrieve an IMediator from the View. + * + * @param mediatorName + * @return the IMediator previously registered with the given + * mediatorName. + */ + public T retrieveMediator(String mediatorName) { + return this.view.retrieveMediator(mediatorName); + } + + /** + * Retrieve an IProxy from the Model by name. + * + * @param proxyName the name of the proxy to be retrieved. + * @return the IProxy instance previously registered with the + * given proxyName. + */ + + @Override + public T retrieveProxy(String proxyName) { + return this.model.retrieveProxy(proxyName); + } + /** + * Create and send an INotification. + *

+ *

+ * Keeps us from having to construct new notification + * instances in our implementation code. + * + * @param notificationName the name of the notification to send + * @param body the body of the notification (optional) + * @param type the type of the notification (optional) + */ + public void sendNotification(String notificationName, Object body, String type) { + notifyObservers(new BaseNotification(notificationName, body, type)); + } + + /** + * Create and send an INotification. + *

+ *

+ * Keeps us from having to construct new notification + * instances in our implementation code. + * + * @param notificationName the name of the notification to send + * @param body the body of the notification (optional) + */ + public void sendNotification(String notificationName, Object body) { + sendNotification(notificationName, body, null); + } + + /** + * Create and send an INotification. + *

+ *

+ * Keeps us from having to construct new notification + * instances in our implementation code. + * + * @param notificationName the name of the notification to send + */ + public void sendNotification(String notificationName) { + sendNotification(notificationName, null, null); + } + + /** + * Notify Observers of an INotification. + * + * @param note the INotification to have the View + * notify observers of. + */ + public void notifyObservers(Notification note) { + if (view != null) { + view.notifyObservers(note); + } + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/mediator/Mediator.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/mediator/Mediator.java new file mode 100644 index 00000000..3475ee8a --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/mediator/Mediator.java @@ -0,0 +1,143 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.mediator; + +import com.puremvc.patterns.observer.Notification; +import com.puremvc.patterns.observer.Notifier; + +/** + * The interface definition for a PureMVC Mediator. + *

+ *

+ * In PureMVC, IMediator implementors assume these + * responsibilities: + *

+ *
    + *
  • Implement a common method which returns a list of all + * INotifications the IMediator has interest in.
  • + *
  • Implement a common notification (callback) method.
  • + *
+ *

+ * Additionally, IMediators typically: + *

    + *
  • Act as an intermediary between one or more view components such as text + * panels or list controls, maintaining references and coordinating their + * behavior.
  • + *
  • In Flash-based apps, this is often the place where event listeners are + * added to view components, and their handlers implemented.
  • + *
  • Respond to and generate INotifications, interacting with + * of the rest of the PureMVC app. + *
+ *

+ *

+ * When an IMediator is registered with the IView, + * the IView will call the IMediator's + * listNotificationInterests method. The IMediator + * will return an Array of INotification names + * which it wishes to be notified about. + *

+ *

+ *

+ * The IView will then create an Observer object + * encapsulating that IMediator's (handleNotification) + * method and register it as an Observer for each INotification + * name returned by listNotificationInterests. + *

+ *

+ *

+ * A concrete IMediator implementor usually looks something like this: + *

+ *

+ *

import org.puremvc.patterns.mediator.~~; import + * org.puremvc.patterns.observer.~~; import org.puremvc.core.view.~~; + *

+ * import com.me.myapp.model.~~; import com.me.myapp.view.~~; import + * com.me.myapp.controller.~~; + *

+ * import mx.controls.ComboBox; import mx.events.ListEvent; + *

+ * public class MyMediator extends Mediator implements IMediator { + *

+ * public function MyComboMediator( viewComponent:Object ) { super( + * viewComponent ); combo.addEventListener( Event.CHANGE, onChange ); } + *

+ * public function listNotificationInterests():Array { return [ + * MyFacade.SET_SELECTION, MyFacade.SET_DATAPROVIDER ]; } + *

+ * public function handleNotification( notification:INotification ):void { + * switch ( notification.getName() ) { case MyFacade.SET_SELECTION: + * setSelection(notification); break; case MyFacade.SET_DATAPROVIDER: + * setDataProvider(notification); break; } } // Set the tools provider of the + * combo box private function setDataProvider( notification:INotification ):void { + * combo.dataProvider = notification.getBody() as Array; } // Invoked when the + * combo box dispatches a change event, we send a // notification with the + * private function onChange(event:ListEvent):void { sendNotification( + * MyFacade.MYCOMBO_CHANGED, this ); } // A private getter for accessing the + * view object by class private function get combo():ComboBox { return view as + * ComboBox; } }

+ * + * @see com.puremvc.patterns.observer.Notification Notification + */ +public interface Mediator extends Notifier { + + /** + * Get the IMediator instance name + * + * @return the IMediator instance name + */ + String getMediatorName(); + + /** + * Get the IMediator's view component. + * + * @return Object the view component + */ + V getViewComponent(); + + /** + * Set the IMediator's view component. + * + * @param viewComponent The view component + */ + void setViewComponent(V viewComponent); + + /** + * List INotification interests. + * + * @return an Array of the INotification names + * this IMediator has an interest in. + */ + String[] listNotificationInterests(); + + /** + * Handle an INotification. + * + * @param notification the INotification to be handled + */ + void handleNotification(Notification notification); + + /** + * Called by the View when the Mediator is registered + */ + void onRegister(); + + /** + * Called by the View when the Mediator is removed + */ + void onRemove(); +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/mediator/SimpleMediator.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/mediator/SimpleMediator.java new file mode 100644 index 00000000..b904d8f1 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/mediator/SimpleMediator.java @@ -0,0 +1,127 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.mediator; + + +import com.puremvc.patterns.observer.BaseNotifier; +import com.puremvc.patterns.observer.Notification; +import com.puremvc.patterns.observer.Notifier; + +/** + * A base Mediator implementation. + * + * @see com.puremvc.core.View View + */ +public class SimpleMediator extends BaseNotifier implements Mediator, Notifier { + + /** + * The default name of the SimpleMediator. + */ + public static final String NAME = "SimpleMediator"; + + /** + * The name of the Mediator. + */ + protected String mediatorName = null; + + /** + * The view component + */ + protected V viewComponent = null; + + /** + * Constructor. + * + * @param mediatorName + * @param viewComponent + */ + public SimpleMediator(String mediatorName, V viewComponent) { + this.mediatorName = (mediatorName != null) ? mediatorName : NAME; + this.viewComponent = viewComponent; + } + + /** + * Get the name of the Mediator. + * + * @return the name + */ + public final String getMediatorName() { + return mediatorName; + } + + /** + * Get the Mediator's view component. + *

+ *

+ * Additionally, an implicit getter will usually be defined in the subclass + * that casts the view object to a type, like this: + *

+ *

+ *

private function get comboBox : mx.controls.ComboBox { return + * viewComponent as mx.controls.ComboBox; } + * + * @return the view component + */ + public V getViewComponent() { + return viewComponent; + } + + /** + * Set the IMediator's view component. + * + * @param viewComponent The view component + */ + public void setViewComponent(V viewComponent) { + this.viewComponent = viewComponent; + } + + /** + * Handle INotifications. + *

+ *

+ * Typically this will be handled in a switch statement, with one 'case' + * entry per INotification the Mediator is + * interested in. + * + * @param notification + */ + public void handleNotification(Notification notification) { + } + + /** + * List the INotification names this Mediator + * is interested in being notified of. + * + * @return String[] the list of INotification names + */ + public String[] listNotificationInterests() { + return new String[]{}; + } + + /** + * Called by the View when the Mediator is registered + */ + public void onRegister() { + } + + /** + * Called by the View when the Mediator is removed + */ + public void onRemove() { + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/BaseNotification.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/BaseNotification.java new file mode 100644 index 00000000..6671342e --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/BaseNotification.java @@ -0,0 +1,169 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.observer; + + +/** + * A base Notification implementation. + *

+ *

+ * PureMVC does not rely upon underlying event models such as the one provided + * with Flash, and ActionScript 3 does not have an inherent event model. + *

+ *

+ *

+ * The Observer Pattern as implemented within PureMVC exists to support + * event-driven communication between the application and the actors of the MVC + * triad. + *

+ *

+ *

+ * Notifications are not meant to be a replacement for Events in + * Flex/Flash/Apollo. Generally, IMediator implementors place + * event listeners on their view components, which they then handle in the usual + * way. This may lead to the broadcast of Notifications to + * trigger ICommands or to communicate with other + * IMediators. IProxy and ICommand + * instances communicate with each other and IMediators by + * broadcasting INotifications. + *

+ *

+ *

+ * A key difference between Flash Events and PureMVC + * Notifications is that Events follow the + * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy until + * some parent component handles the Event, while PureMVC + * Notifications follow a 'Publish/Subscribe' pattern. PureMVC + * classes need not be related to each other in a parent/child relationship in + * order to communicate with one another using Notifications. + * + * @see com.puremvc.patterns.observer Observer + */ +public class BaseNotification implements Notification { + + // the name of the notification instance + // the type of the notification instance + protected String name = null; + protected String type = null; + + // the body of the notification instance + protected Object body = null; + + /** + * Constructor. + * + * @param name name of the Notification instance. (required) + * @param body the Notification body. (optional) + * @param type the type of the Notification (optional) + */ + public BaseNotification(String name, Object body, String type) { + this.name = name; + this.body = body; + this.type = type; + } + + /** + * Constructor. + * + * @param name name of the Notification instance. (required) + */ + public BaseNotification(String name) { + this.name = name; + body = null; + type = null; + } + + /** + * Constructor. + * + * @param name name of the Notification instance. (required) + * @param body the Notification body. (optional) + */ + public BaseNotification(String name, Object body) { + this.name = name; + this.body = body; + type = null; + } + + /** + * Get the body of the Notification instance. + * + * @return the body object. + */ + public T getBody() { + return (T) body; + } + + /** + * Set the body of the Notification instance. + * + * @param body + */ + public void setBody(T body) { + this.body = body; + } + + /** + * Get the name of the Notification instance. + * + * @return the name of the Notification instance. + */ + public String getName() { + return name; + } + + /** + * Get the type of the Notification instance. + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * Set the type of the Notification instance. + * + * @param type + */ + public void setType(String type) { + this.type = type; + } + + /** + * Get the string representation of the Notification + * instance. + * + * @return the string representation of the Notification + * instance. + */ + public String toString() { + String result = "Notification Name: " + getName() + " Body:"; + if (body != null) + result += body.toString() + " Type:"; + else + result += "null Type:"; + + if (type != null) + result += type; + else + result += "null "; + + return result; + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/BaseNotifier.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/BaseNotifier.java new file mode 100644 index 00000000..4e77a52b --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/BaseNotifier.java @@ -0,0 +1,103 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.observer; + + +import com.puremvc.patterns.facade.SimpleFacade; + +/** + * A Base Notifier implementation. + *

+ *

+ * MacroCommand, Command, Mediator and Proxy all + * have a need to send Notifications. + *

+ *

+ * The INotifier interface provides a common method called + * sendNotification that relieves implementation code of the + * necessity to actually construct Notifications. + *

+ *

+ *

+ * The Notifier class, which all of the above mentioned classes + * extend, provides an initialized reference to the Facade + * Singleton, which is required for the convienience method for sending + * Notifications, but also eases implementation as these classes + * have frequent Facade interactions and usually require access + * to the facade anyway. + *

+ * + * @see com.puremvc.patterns.facade.Facade Facade + * @see com.puremvc.patterns.mediator.Mediator Mediator + * @see com.puremvc.patterns.proxy Proxy + * @see com.puremvc.patterns.command.SimpleCommand SimpleCommand + * @see com.puremvc.patterns.command.MacroCommand MacroCommand + */ +public class BaseNotifier { + // The Multiton Key for this app + /** + * Local reference to the Facade Singleton + */ + protected SimpleFacade facade; + + /** + * Send an Notifications. + *

+ *

+ * Keeps us from having to construct new notification instances in our + * implementation code. + * + * @param notificationName the name of the notiification to send + * @param body the body of the notification (optional) + * @param type the type of the notification (optional) + */ + + public void sendNotification(String notificationName, Object body, String type) { + facade.sendNotification(notificationName, body, type); + } + + /** + * Send an INotifications. + *

+ *

+ * Keeps us from having to construct new notification instances in our + * implementation code. + * + * @param notificationName the name of the notiification to send + * @param body the body of the notification (optional) + */ + + public void sendNotification(String notificationName, Object body) { + facade.sendNotification(notificationName, body); + } + + /** + * Send an INotifications. + *

+ *

+ * Keeps us from having to construct new notification instances in our + * implementation code. + * + * @param notificationName the name of the notiification to send + */ + + public void sendNotification(String notificationName) { + facade.sendNotification(notificationName); + } + +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/BaseObserver.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/BaseObserver.java new file mode 100644 index 00000000..e4dc821a --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/BaseObserver.java @@ -0,0 +1,127 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.observer; + + +/** + * A base IObserver implementation. + *

+ *

+ * An Observer is an object that encapsulates information about + * an interested object with a method that should be called when a particular + * INotification is broadcast. + *

+ *

+ *

+ * In PureMVC, the Observer class assumes these responsibilities: + *

    + *
  • Encapsulate the notification (callback) method of the interested object.
  • + *
  • Encapsulate the notification context (this) of the interested object.
  • + *
  • Provide methods for setting the notification method and context.
  • + *
  • Provide a method for notifying the interested object.
  • + *
+ * + * @see com.puremvc.core.View View + * @see com.puremvc.patterns.observer.Notification Notification + */ +public class BaseObserver implements Observer { + + private Object context; + + private Function notify; + + /** + * Constructor. + *

+ *

+ * The notification method on the interested object should take one + * parameter of type INotification + *

+ * + * @param notify the notification method of the interested object + * @param context the notification context of the interested object + */ + public BaseObserver(Function notify, Object context) { + setNotifyContext(context); + setNotifyMethod(notify); + } + + /** + * Compare an object to the notification context. + * + * @param object the object to compare + * @return boolean indicating if the object and the notification context are + * the same + */ + public boolean compareNotifyContext(Object object) { + return context == object; + } + + /** + * Notify the interested object. + * + * @param notification the INotification to pass to the interested + * object's notification method. + */ + public void notifyObserver(Notification notification) { + getNotifyMethod().onNotification(notification); + } + + /** + * Get the notification method. + * + * @return the notification (callback) method of the interested object. + */ + public Function getNotifyMethod() { + return notify; + } + + /** + * Set the notification method. + *

+ *

+ * The notification method should take one parameter of type + * INotification. + *

+ * + * @param notifyMethod the notification (callback) method of the interested object. + */ + public void setNotifyMethod(Function notifyMethod) { + notify = notifyMethod; + } + + /** + * Get the notification context. + * + * @return the notification context (this) of the + * interested object. + */ + public Object getNotifyContext() { + return context; + } + + /** + * Set the notification context. + * + * @param notifyContext the notification context (this) of the interested object. + */ + public void setNotifyContext(Object notifyContext) { + context = notifyContext; + } + +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/Notification.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/Notification.java new file mode 100644 index 00000000..f7d7503b --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/Notification.java @@ -0,0 +1,103 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.observer; + +/** + * The interface definition for a PureMVC Notification. + *

+ *

+ * PureMVC does not rely upon underlying event models such as the one provided + * with Flash, and ActionScript 3 does not have an inherent event model. + *

+ *

+ *

+ * The Observer Pattern as implemented within PureMVC exists to support + * event-driven communication between the application and the actors of the MVC + * triad. + *

+ *

+ *

+ * Notifications are not meant to be a replacement for Events in + * Flex/Flash/Apollo. Generally, IMediator implementors place + * event listeners on their view components, which they then handle in the usual + * way. This may lead to the broadcast of Notifications to + * trigger ICommands or to communicate with other + * IMediators. IProxy and ICommand + * instances communicate with each other and IMediators by + * broadcasting INotifications. + *

+ *

+ *

+ * A key difference between Flash Events and PureMVC + * Notifications is that Events follow the + * 'Chain of Responsibility' pattern, 'bubbling' up the display hierarchy until + * some parent component handles the Event, while PureMVC + * Notifications follow a 'Publish/Subscribe' pattern. PureMVC + * classes need not be related to each other in a parent/child relationship in + * order to communicate with one another using Notifications. + * + * @see com.puremvc.core.View View + * @see com.puremvc.patterns.observer.Observer Observer + */ +public interface Notification { + + /** + * Get the name of the INotification instance. No setter, + * should be set by constructor only + * + * @return the name + */ + String getName(); + + /** + * Get the body of the INotification instance + * + * @return the body + */ + T getBody(); + + /** + * Set the body of the INotification instance + * + * @param body + */ + void setBody(T body); + + /** + * Get the type of the INotification instance + * + * @return the type + */ + String getType(); + + /** + * Set the type of the Notification instance + * + * @param type the type + */ + void setType(String type); + + /** + * Get the string representation of the INotification + * instance + * + * @return the string representation of the INotification + * instance + */ + String toString(); +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/Notifier.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/Notifier.java new file mode 100644 index 00000000..1a0774d2 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/Notifier.java @@ -0,0 +1,86 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.observer; + +/** + * The interface definition for a PureMVC Notifier. + *

+ *

+ * MacroCommand, Command, Mediator and Proxy all + * have a need to send Notifications. + *

+ *

+ *

+ * The INotifier interface provides a common method called + * sendNotification that relieves implementation code of the + * necessity to actually construct Notifications. + *

+ *

+ *

+ * The Notifier class, which all of the above mentioned classes + * extend, also provides an initialized reference to the Facade + * Singleton, which is required for the convienience method for sending + * Notifications, but also eases implementation as these classes + * have frequent Facade interactions and usually require access + * to the facade anyway. + *

+ * + * @see com.puremvc.patterns.facade.Facade Facade + * @see com.puremvc.patterns.observer.Notification Notification + */ +public interface Notifier { + + /** + * Send a INotification. + *

+ *

+ * Convenience method to prevent having to construct new notification + * instances in our implementation code. + *

+ * + * @param notificationName the name of the notification to send + * @param body the body of the notification (optional) + * @param type the type of the notification (optional) + */ + void sendNotification(String notificationName, Object body, String type); + + /** + * Send a INotification. + *

+ *

+ * Convenience method to prevent having to construct new notification + * instances in our implementation code. + *

+ * + * @param notificationName the name of the notification to send + * @param body the body of the notification (optional) + */ + void sendNotification(String notificationName, Object body); + + /** + * Send a INotification. + *

+ *

+ * Convenience method to prevent having to construct new notification + * instances in our implementation code. + *

+ * + * @param notificationName the name of the notification to send + */ + void sendNotification(String notificationName); +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/Observer.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/Observer.java new file mode 100644 index 00000000..76c24efb --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/observer/Observer.java @@ -0,0 +1,108 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.observer; + +/** + * The interface definition for a PureMVC Observer. + *

+ *

+ * In PureMVC, IObserver implementors assume these + * responsibilities: + *

    + *
  • Encapsulate the notification (callback) method of the interested object.
  • + *
  • Encapsulate the notification context (this) of the interested object.
  • + *
  • Provide methods for setting the interested object' notification method + * and context.
  • + *
  • Provide a method for notifying the interested object.
  • + *
+ *

+ *

+ * PureMVC does not rely upon underlying event models such as the one provided + * with Flash, and ActionScript 3 does not have an inherent event model. + *

+ *

+ *

+ * The Observer Pattern as implemented within PureMVC exists to support event + * driven communication between the application and the actors of the MVC triad. + *

+ *

+ *

+ * An Observer is an object that encapsulates information about an interested + * object with a notification method that should be called when an INotification + * is broadcast. The Observer then acts as a proxy for notifying the interested + * object. + *

+ *

+ * Observers can receive Notifications by having their notifyObserver + * method invoked, passing in an object implementing the INotification + * interface, such as a subclass of Notification. + *

+ * + * @see com.puremvc.core.View View + * @see com.puremvc.patterns.observer.Notification Notification + */ +public interface Observer { + + /** + * Set the notification method. + *

+ *

+ * The notification method should take one parameter of type + * INotification + *

+ * + * @param notifyMethod the notification (callback) method of the interested object + */ + void setNotifyMethod(BaseObserver.Function notifyMethod); + + /** + * Set the notification context. + * + * @param notifyContext the notification context (this) of the interested object + */ + void setNotifyContext(Object notifyContext); + + /** + * Notify the interested object. + * + * @param notification the INotification to pass to the interested + * object's notification method + */ + void notifyObserver(Notification notification); + + /** + * Compare the given object to the notificaiton context object. + * + * @param object the object to compare. + * @return boolean indicating if the notification context and the object are + * the same. + */ + boolean compareNotifyContext(Object object); + + /** + * This interface must be implemented by all classes that want to be notified of + * a notification. + */ + interface Function { + + /** + * @param notification + */ + void onNotification(Notification notification); + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/proxy/BaseProxy.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/proxy/BaseProxy.java new file mode 100644 index 00000000..dc7c69ca --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/proxy/BaseProxy.java @@ -0,0 +1,120 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.proxy; + + +import com.puremvc.patterns.observer.BaseNotifier; + +/** + * A base IProxy implementation. + *

+ *

+ * In PureMVC, Proxy classes are used to manage parts of the + * application's tools model. + *

+ *

+ *

+ * A Proxy might simply manage a reference to a local tools + * object, in which case interacting with it might involve setting and getting + * of its tools in synchronous fashion. + *

+ *

+ *

+ * Proxy classes are also used to encapsulate the application's + * interaction with remote services to save or retrieve tools, in which case, we + * adopt an asyncronous idiom; setting tools (or calling a method) on the + * Proxy and listening for a Notification to be + * sent when the Proxy has retrieved the tools from the service. + *

+ * + * @see com.puremvc.core.Model Model + */ +public class BaseProxy extends BaseNotifier implements Proxy { + + // the proxy name + protected String proxyName = "BaseProxy"; + + // the tools object + protected Object data = null; + + /** + * Constructor + * + * @param proxyName + * @param data + */ + public BaseProxy(String proxyName, Object data) { + if (proxyName != null) { + this.proxyName = proxyName; + } + if (data != null) { + this.data = data; + } + } + + /** + * Constructor + * + * @param proxyName Name of the Proxy + */ + public BaseProxy(String proxyName) { + if (proxyName != null) { + this.proxyName = proxyName; + } + + } + + /** + * Get the proxy name + * + * @return the proxy name + */ + public String getProxyName() { + return proxyName; + } + + /** + * Get the tools object + * + * @return the tools object + */ + public Object getData() { + return data; + } + + /** + * Set the tools object + * + * @param data + */ + public void setData(Object data) { + this.data = data; + } + + /** + * Called by the Model when the Proxy is registered + */ + public void onRegister() { + } + + /** + * Called by the Model when the Proxy is removed + */ + public void onRemove() { + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/proxy/Proxy.java b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/proxy/Proxy.java new file mode 100644 index 00000000..8dfb86b1 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/puremvc/patterns/proxy/Proxy.java @@ -0,0 +1,76 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package com.puremvc.patterns.proxy; + +import com.puremvc.patterns.observer.Notifier; + +/** + * The interface definition for a PureMVC Proxy. + *

+ *

+ * In PureMVC, Iroxy implementors assume these responsibilities: + *

+ *
    + *
  • Implement a common method which returns the name of the Proxy.
  • + *
+ *

+ * Additionally, IProxys typically: + *

+ *
    + *
  • Maintain references to one or more pieces of model tools.
  • + *
  • Provide methods for manipulating that tools.
  • + *
  • Generate INotifications when their model tools changes.
  • + *
  • Expose their name as a public static const called NAME, if they are not instantiated multiple times.
  • + *
  • Encapsulate interaction with local or remote services used to fetch and + * persist model tools.
  • + *
+ */ +public interface Proxy extends Notifier { + + /** + * Get the Proxy name + * + * @return the Proxy instance name + */ + String getProxyName(); + + /** + * Get the tools object + * + * @return the tools as type Object + */ + Object getData(); + + /** + * Set the tools object + * + * @param data the tools object + */ + void setData(Object data); + + /** + * Called by the Model when the Proxy is registered + */ + void onRegister(); + + /** + * Called by the Model when the Proxy is removed + */ + void onRemove(); + +} diff --git a/hyperlap2d-common-api/src/main/java/com/vo/CursorData.java b/hyperlap2d-common-api/src/main/java/com/vo/CursorData.java new file mode 100644 index 00000000..99551058 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/vo/CursorData.java @@ -0,0 +1,50 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package com.vo; + +import com.badlogic.gdx.graphics.Cursor; + +/** + * Created by azakhary on 5/15/2015. + */ +public class CursorData { + + public String region; + public int hotspotX; + public int hotspotY; + public Cursor.SystemCursor systemCursor; + + public CursorData(String region, int x, int y) { + this.region = region; + hotspotX = x; + hotspotY = y; + } + + public CursorData(Cursor.SystemCursor cursor) { + systemCursor = cursor; + } + + public int getHotspotX() { + return hotspotX; + } + + public int getHotspotY() { + return hotspotY; + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/vo/EditorConfigVO.java b/hyperlap2d-common-api/src/main/java/com/vo/EditorConfigVO.java new file mode 100644 index 00000000..5e0264fa --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/vo/EditorConfigVO.java @@ -0,0 +1,39 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package com.vo; + +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; + +/** + * Created by sargis on 8/1/14. + */ +public class EditorConfigVO { + public static final String EDITOR_CONFIG_FILE = "config.pit"; + public String lastOpenedSystemPath = ""; + public String lastImportedSystemPath = ""; + + public String constructJsonString() { + String str = ""; + Json json = new Json(); + json.setOutputType(JsonWriter.OutputType.json); + str = json.toJson(this); + return str; + } +} diff --git a/hyperlap2d-common-api/src/main/java/com/vo/ProjectVO.java b/hyperlap2d-common-api/src/main/java/com/vo/ProjectVO.java new file mode 100644 index 00000000..805462af --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/vo/ProjectVO.java @@ -0,0 +1,50 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package com.vo; + +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter.OutputType; + +import java.util.ArrayList; + +public class ProjectVO { + + public String projectName = ""; + + public String projectVersion = null; + + public String projectMainExportPath = ""; + + public String lastOpenScene = ""; + public String lastOpenResolution = ""; + public String texturepackerWidth = "2048"; + public String texturepackerHeight = "2048"; + public boolean texturepackerDuplicate; + + public ArrayList sceneConfigs = new ArrayList<>(); + + + public String constructJsonString() { + String str = ""; + Json json = new Json(); + json.setOutputType(OutputType.json); + str = json.toJson(this); + return str; + } +} \ No newline at end of file diff --git a/hyperlap2d-common-api/src/main/java/com/vo/SceneConfigVO.java b/hyperlap2d-common-api/src/main/java/com/vo/SceneConfigVO.java new file mode 100644 index 00000000..8bdd000f --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/com/vo/SceneConfigVO.java @@ -0,0 +1,32 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package com.vo; + +/** + * Created by azakhary on 7/18/2015. + * + * Here we keep all editor specific but not runtime specific data per scene. (like for example last camera position) + */ +public class SceneConfigVO { + + public String sceneName = ""; + + // 0 = x, 1 = y + public float[] cameraPosition = new float[2]; +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/H2DDialog.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/H2DDialog.java new file mode 100644 index 00000000..995d0165 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/H2DDialog.java @@ -0,0 +1,73 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.kotcrab.vis.ui.VisUI; +import com.kotcrab.vis.ui.util.InputValidator; +import com.kotcrab.vis.ui.widget.VisDialog; +import com.kotcrab.vis.ui.widget.VisImageButton; +import com.kotcrab.vis.ui.widget.VisTextField; +import com.kotcrab.vis.ui.widget.VisValidatableTextField; + +/** + * Created by sargis on 4/27/15. + */ +public class H2DDialog extends VisDialog { + protected final Skin skin; + + public H2DDialog(String title) { + super(title); + skin = VisUI.getSkin(); + } + + protected VisTextField createTextField() { + return new VisTextField("", "light"); + } + + protected VisTextField createTextField(String text) { + return new VisTextField(text, "light"); + } + + protected VisTextField createTextField(String text, VisTextField.TextFieldFilter textFieldFilter) { + VisTextField visTextField = createTextField(text); + visTextField.setTextFieldFilter(textFieldFilter); + return visTextField; + } + + protected VisValidatableTextField createValidableTextField(String text, InputValidator inputValidator) { + VisValidatableTextField visTextField = new VisValidatableTextField(inputValidator); + visTextField.setText(text); + visTextField.setStyle(skin.get("light", VisTextField.VisTextFieldStyle.class)); + return visTextField; + } + + protected VisValidatableTextField createValidableTextField(InputValidator inputValidator) { + VisValidatableTextField visTextField = createValidableTextField("", inputValidator); + return visTextField; + } + + protected VisValidatableTextField createValidableTextField(String text, InputValidator inputValidator, VisTextField.TextFieldFilter textFieldFilter) { + VisValidatableTextField visTextField = createValidableTextField(text, inputValidator); + visTextField.setTextFieldFilter(textFieldFilter); + return visTextField; + } +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/IItemCommand.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/IItemCommand.java new file mode 100644 index 00000000..7c6183ac --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/IItemCommand.java @@ -0,0 +1,29 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common; + +/** + * Created by azakhary on 10/23/2015. + */ +public interface IItemCommand { + + void doAction(Object body); + void undoAction(Object body); + +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/MsgAPI.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/MsgAPI.java new file mode 100644 index 00000000..f37ce1da --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/MsgAPI.java @@ -0,0 +1,138 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common; + +/** + * Created by azakhary on 10/23/2015. + */ +public class MsgAPI { + + /** + * Previous Overlap2D class notifications + */ + public static final String GLOBAL_PREFIX = "games.rednblack.editor.HyperLap2D"; + + public static final String APP_EXIT = GLOBAL_PREFIX + ".APP_EXIT"; + + public static final String PAUSE = GLOBAL_PREFIX + ".PAUSE"; + public static final String RESUME = GLOBAL_PREFIX + ".RESUME"; + public static final String RENDER = GLOBAL_PREFIX + ".RENDER"; + public static final String RESIZE = GLOBAL_PREFIX + ".RESIZE"; + public static final String DISPOSE = GLOBAL_PREFIX + ".DISPOSE"; + public static final String CREATE = GLOBAL_PREFIX + ".CREATE_BTN_CLICKED"; + + // tmp events + public static final String ZOOM_CHANGED = GLOBAL_PREFIX + ".ZOOM_CHANGED"; + public static final String GRID_SIZE_CHANGED = GLOBAL_PREFIX + ".GRID_SIZE_CHANGED"; + public static final String LOCK_LINES_CHANGED = GLOBAL_PREFIX + ".LOCK_LINES_CHANGED"; + public static final String HIDE_GRID = GLOBAL_PREFIX + ".HIDE_GRID"; + public static final String SHOW_GRID = GLOBAL_PREFIX + ".SHOW_GRID"; + public static final String ITEM_DATA_UPDATED = GLOBAL_PREFIX + ".ITEM_DATA_UPDATED"; + public static final String ITEM_PROPERTY_DATA_FINISHED_MODIFYING = GLOBAL_PREFIX + ".ITEM_PROPERTY_DATA_FINISHED_MODIFYING"; + + // this should move + public static final String HIDE_SELECTIONS = GLOBAL_PREFIX + ".HIDE_SELECTIONS"; + public static final String SHOW_SELECTIONS = GLOBAL_PREFIX + ".SHOW_SELECTIONS"; + public static final String ITEM_SELECTION_CHANGED = GLOBAL_PREFIX + ".ITEM_SELECTION_CHANGED"; + public static final String EMPTY_SPACE_CLICKED = GLOBAL_PREFIX + ".EMPTY_SPACE_CLICKED"; + + public static final String SCENE_RIGHT_CLICK = GLOBAL_PREFIX + ".SCENE_RIGHT_CLICK"; + public static final String ITEM_RIGHT_CLICK = GLOBAL_PREFIX + ".ITEM_RIGHT_CLICK"; + + public static final String LIBRARY_LIST_UPDATED = GLOBAL_PREFIX + ".LIBRARY_LIST_UPDATED"; + + private static final String TOOL_BOX_MEDIATOR_PREFIX = "games.rednblack.editor.view.ui.box.UIToolBoxMediator"; + public static final String TOOL_SELECTED = TOOL_BOX_MEDIATOR_PREFIX + ".TOOL_CHANGED"; + public static final String NEW_TOOL_ADDED = TOOL_BOX_MEDIATOR_PREFIX + ".NEW_TOOL_ADDED"; + + private static final String IMAGES_TAB_MEDIATOR_PREFIX= "games.rednblack.editor.view.ui.box.resourcespanel.UIImagesTabMediator"; + public static final String ADD_TARGET = IMAGES_TAB_MEDIATOR_PREFIX + ".ADD_TARGET"; + + /** + * Previous Sandbox class notifications + */ + public static final String SANDBOX_PREFIX = "games.rednblack.editor.gdx.commands.Sandbox"; + + public static final String ACTION_GROUP_ITEMS = SANDBOX_PREFIX + "ACTION_GROUP_ITEMS"; + public static final String ACTION_CAMERA_CHANGE_COMPOSITE = SANDBOX_PREFIX + "ACTION_CAMERA_CHANGE_COMPOSITE"; + public static final String ACTION_CONVERT_TO_BUTTON = SANDBOX_PREFIX + "ACTION_CONVERT_TO_BUTTON"; + public static final String ACTION_CUT = SANDBOX_PREFIX + "ACTION_CUT"; + public static final String ACTION_COPY = SANDBOX_PREFIX + "ACTION_COPY"; + public static final String ACTION_PASTE = SANDBOX_PREFIX + "ACTION_PASTE"; + public static final String ACTION_DELETE = SANDBOX_PREFIX + "ACTION_DELETE"; + public static final String ACTION_CREATE_ITEM = SANDBOX_PREFIX + "ACTION_CREATE_ITEM"; + + public static final String ACTION_DELETE_LAYER = SANDBOX_PREFIX + "ACTION_DELETE_LAYER"; + public static final String ACTION_NEW_LAYER = SANDBOX_PREFIX + "ACTION_NEW_LAYER"; + public static final String ACTION_SWAP_LAYERS = SANDBOX_PREFIX + "ACTION_SWAP_LAYERS"; + public static final String ACTION_RENAME_LAYER = SANDBOX_PREFIX + "ACTION_RENAME_LAYER"; + + public static final String ACTION_ADD_COMPONENT = SANDBOX_PREFIX + "ACTION_ADD_COMPONENT"; + public static final String ACTION_REMOVE_COMPONENT = SANDBOX_PREFIX + "ACTION_REMOVE_COMPONENT"; + public static final String CUSTOM_VARIABLE_MODIFY = SANDBOX_PREFIX + "CUSTOM_VARIABLE_MODIFY"; + + public static final String SHOW_ADD_LIBRARY_DIALOG = SANDBOX_PREFIX + "SHOW_ADD_LIBRARY_DIALOG"; + public static final String ACTION_ADD_TO_LIBRARY = SANDBOX_PREFIX + "ACTION_ADD_TO_LIBRARY"; + public static final String ACTION_EDIT_PHYSICS = SANDBOX_PREFIX + "ACTION_EDIT_PHYSICS"; + public static final String ACTION_ITEMS_MOVE_TO = SANDBOX_PREFIX + "ACTION_ITEMS_MOVE_TO"; + public static final String ACTION_ITEM_AND_CHILDREN_TO = GLOBAL_PREFIX + "ACTION_ITEM_AND_CHILDREN_TO"; + public static final String ACTION_ITEM_TRANSFORM_TO = SANDBOX_PREFIX + "ACTION_ITEM_TRANSFORM_TO"; + + public static final String ACTION_CREATE_PRIMITIVE = SANDBOX_PREFIX + "ACTION_CREATE_PRIMITIVE"; + + public static final String ACTION_SET_SELECTION = SANDBOX_PREFIX + "ACTION_SET_SELECTION"; + public static final String ACTION_ADD_SELECTION = SANDBOX_PREFIX + "ACTION_ADD_SELECTION"; + public static final String ACTION_RELEASE_SELECTION = SANDBOX_PREFIX + "ACTION_RELEASE_SELECTION"; + public static final String ACTION_Z_INDEX_CHANGED = SANDBOX_PREFIX + "ACTION_Z_INDEX_CHANGED"; + + public static final String ACTION_UPDATE_ITEM_DATA = SANDBOX_PREFIX + "ACTION_UPDATE_ITEM_DATA"; + public static final String ACTION_UPDATE_LABEL_DATA = SANDBOX_PREFIX + "ACTION_UPDATE_LABEL_DATA"; + public static final String ACTION_UPDATE_LIGHT_DATA = SANDBOX_PREFIX + "ACTION_UPDATE_LIGHT_DATA"; + public static final String ACTION_UPDATE_BODY_LIGHT_DATA = SANDBOX_PREFIX + "ACTION_UPDATE_BODY_LIGHT_DATA"; + public static final String ACTION_UPDATE_SPRITE_ANIMATION_DATA = SANDBOX_PREFIX + "ACTION_UPDATE_SPRITE_ANIMATION_DATA"; + public static final String ACTION_UPDATE_MESH_DATA = SANDBOX_PREFIX + "ACTION_UPDATE_MESH_DATA"; + + public static final String ACTION_PLUGIN_PROXY_COMMAND = SANDBOX_PREFIX + "ACTION_PLUGIN_PROXY_COMMAND"; + + public static final String ACTION_EXPORT_PROJECT = SANDBOX_PREFIX + "ACTION_EXPORT_PROJECT"; + public static final String SAVE_EXPORT_PATH = SANDBOX_PREFIX + "SAVE_EXPORT_SETTINGS"; + + // drop down resources + public static final String ACTION_DELETE_IMAGE_RESOURCE = SANDBOX_PREFIX + "ACTION_DELETE_IMAGE_RESOURCE"; + public static final String ACTION_DELETE_SPRITE_ANIMATION_RESOURCE = SANDBOX_PREFIX + "ACTION_DELETE_SPRITE_ANIMATION_RESOURCE"; + public static final String ACTION_DELETE_SPRITER_ANIMATION_RESOURCE = SANDBOX_PREFIX + "ACTION_DELETE_SPRITER_ANIMATION_RESOURCE"; + public static final String ACTION_DELETE_SPINE_ANIMATION_RESOURCE = SANDBOX_PREFIX + "ACTION_DELETE_SPINE_ANIMATION_RESOURCE"; + public static final String ACTION_DELETE_LIBRARY_ITEM = SANDBOX_PREFIX + "ACTION_DELETE_LIBRARY_ITEM"; + public static final String ACTION_DELETE_PARTICLE_EFFECT = SANDBOX_PREFIX + "ACTION_DELETE_PARTICLE_EFFECT"; + + public static final String ACTION_UPDATE_RULER_POSITION = SANDBOX_PREFIX + "ACTION_UPDATE_RULER_POSITION"; + + /** + * Other + */ + public static final String ITEM_FACTORY_PREFIX = "games.rednblack.editor.factory.ItemFactory"; + public static final String NEW_ITEM_ADDED = ITEM_FACTORY_PREFIX + ".NEW_ITEM_ADDED"; + public static final String SCENE_DATA_PREFIX = "games.rednblack.editor.proxy.SceneDataManager"; + public static final String SCENE_LOADED = SCENE_DATA_PREFIX + ".SCENE_LOADED"; + + private static final String DELETE_ITEMS_COMMAND_CLASS_NAME = "games.rednblack.editor.controller.commands.DeleteItemsCommand"; + public static final String DELETE_ITEMS_COMMAND_DONE = DELETE_ITEMS_COMMAND_CLASS_NAME + "DONE"; + + +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/ResourcePayloadObject.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/ResourcePayloadObject.java new file mode 100644 index 00000000..9d146876 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/ResourcePayloadObject.java @@ -0,0 +1,29 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common; + +public class ResourcePayloadObject { + public String name; + public float xOffset; + public float yOffset; + public String className; + + public ResourcePayloadObject() { + } +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/UIDraggablePanel.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/UIDraggablePanel.java new file mode 100644 index 00000000..152647e5 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/UIDraggablePanel.java @@ -0,0 +1,78 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package games.rednblack.h2d.common; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.utils.Align; +import com.kotcrab.vis.ui.VisUI; +import com.kotcrab.vis.ui.widget.VisDialog; +import com.kotcrab.vis.ui.widget.VisImageButton; + +/** + * Created by azakhary on 5/12/2015. + */ +public class UIDraggablePanel extends H2DDialog { + + public boolean isOpen; + + public UIDraggablePanel(String title) { + super(title); + setMovable(true); + setModal(false); + setStyle(VisUI.getSkin().get("box", WindowStyle.class)); + getTitleLabel().setAlignment(Align.left); + } + + @Override + public void addCloseButton() { + VisImageButton closeButton = new VisImageButton("close-panel"); + this.getTitleTable().add(closeButton).padBottom(2); + closeButton.addListener(new ChangeListener() { + public void changed(ChangeEvent event, Actor actor) { + UIDraggablePanel.this.close(); + } + }); + if (this.getTitleTable().getChildren().size == 2) { + this.getTitleTable().getCell(this.getTitleLabel()).padLeft(closeButton.getWidth() * 2.0F); + } + } + + public void invalidateHeight() { + float heightOld = getHeight(); + pack(); + float heightDiff = heightOld - getHeight(); + setPosition(getX(), getY() + heightDiff); + } + + @Override + public VisDialog show(Stage stage) { + + isOpen = true; + + return super.show(stage); + } + + @Override + public void hide() { + super.hide(); + + isOpen = false; + } +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorChannelWidget.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorChannelWidget.java new file mode 100644 index 00000000..82a6f996 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorChannelWidget.java @@ -0,0 +1,156 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common.color; + +/** + * Created by azakhary on 7/14/2015. + */ + +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.utils.Disposable; +import com.kotcrab.vis.ui.Sizes; +import com.kotcrab.vis.ui.widget.VisLabel; +import com.kotcrab.vis.ui.widget.VisTable; +import com.kotcrab.vis.ui.widget.color.ColorPickerStyle; +import com.kotcrab.vis.ui.widget.color.internal.AlphaChannelBar; +import com.kotcrab.vis.ui.widget.color.internal.ChannelBar; +import com.kotcrab.vis.ui.widget.color.internal.ChannelBar.ChannelBarListener; +import com.kotcrab.vis.ui.widget.color.internal.PickerCommons; + +/** + * Used to display one color channel (hue, saturation etc.) with label, ColorInputField and ChannelBar + * @author Kotcrab + */ +public class ColorChannelWidget extends VisTable implements Disposable { + private ColorPickerStyle style; + private Sizes sizes; + private int value; + private int maxValue; + public ColorChannelWidgetListener drawer; + private boolean useAlpha; + + private ColorInputField inputField; + + private Texture texture; + private Pixmap pixmap; + private ChannelBar bar; + + private ChangeListener barListener; + + public ColorChannelWidget (ColorPickerStyle style, Sizes sizes, String label, int maxValue, final ColorChannelWidgetListener drawer) { + this(style, sizes, label, maxValue, false, drawer); + } + + public ColorChannelWidget (ColorPickerStyle style, Sizes sizes, String label, int maxValue, boolean useAlpha, final ColorChannelWidgetListener drawer) { + super(true); + + this.style = style; + this.sizes = sizes; + this.value = 0; + this.maxValue = maxValue; + this.drawer = drawer; + this.useAlpha = useAlpha; + + barListener = new ChangeListener() { + @Override + public void changed (ChangeEvent event, Actor actor) { + value = bar.getValue(); + drawer.updateFields(); + inputField.setValue(value); + } + }; + + if (useAlpha) + pixmap = new Pixmap(maxValue, 1, Pixmap.Format.RGBA8888); + else + pixmap = new Pixmap(maxValue, 1, Pixmap.Format.RGB888); + + texture = new Texture(pixmap); + add(new VisLabel(label)).width(10 * sizes.scaleFactor).center(); + add(inputField = new ColorInputField(maxValue, new ColorInputField.ColorInputFieldListener() { + @Override + public void changed (int newValue) { + value = newValue; + drawer.updateFields(); + bar.setValue(newValue); + } + })).width(CustomColorPicker.FIELD_WIDTH * sizes.scaleFactor); + bar = createBarImage(); + bar.setChannelBarListener(new ChannelBarListener() { + + @Override + public void updateFields() { + + } + + @Override + public void setShaderUniforms(ShaderProgram shader) { + + } + + }); + add(bar).size(CustomColorPicker.BAR_WIDTH * sizes.scaleFactor, CustomColorPicker.BAR_HEIGHT * sizes.scaleFactor); + + inputField.setValue(0); + } + + @Override + public void dispose () { + pixmap.dispose(); + texture.dispose(); + } + + public void redraw () { + drawer.draw(pixmap); + texture.draw(pixmap, 0, 0); + } + + public int getValue () { + return value; + } + + public void setValue (int value) { + this.value = value; + inputField.setValue(value); + bar.setValue(value); + } + + private ChannelBar createBarImage () { + + PickerCommons commons = new PickerCommons(style.pickerStyle, sizes, true); + if (useAlpha) + return new AlphaChannelBar(commons, value, maxValue, barListener); + else + return new ChannelBar(commons, value, maxValue, barListener); + } + + public boolean isInputValid () { + return inputField.isInputValid(); + } + + interface ColorChannelWidgetListener { + void updateFields (); + + void draw (Pixmap pixmap); + } +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorInputField.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorInputField.java new file mode 100644 index 00000000..9c32f367 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorInputField.java @@ -0,0 +1,129 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ +package games.rednblack.h2d.common.color; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputListener; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.scenes.scene2d.utils.FocusListener; +import com.badlogic.gdx.scenes.scene2d.utils.UIUtils; +import com.kotcrab.vis.ui.util.InputValidator; +import com.kotcrab.vis.ui.widget.VisTextField; +import com.kotcrab.vis.ui.widget.VisValidatableTextField; + +/** + * Fields used to enter color numbers in color picker, verifies max allowed value + * provides quick increment/decrement of current value by pressing [shift +] plus or minus on numpad + * @author Kotcrab + */ +public class ColorInputField extends VisValidatableTextField { + private int value; + private int maxValue; + + public ColorInputField (final int maxValue, final ColorInputFieldListener listener) { + super(new ColorFieldValidator(maxValue)); + this.value = 0; + this.maxValue = maxValue; + + setProgrammaticChangeEvents(false); + setMaxLength(3); + setTextFieldFilter(new NumberFilter()); + + addListener(new ChangeListener() { + @Override + public void changed (ChangeEvent event, Actor actor) { + if (getText().length() > 0) + value = Integer.valueOf(getText()); + } + }); + + addListener(new InputListener() { + @Override + public boolean keyTyped (InputEvent event, char character) { + ColorInputField field = (ColorInputField) event.getListenerActor(); + if (character == '+') field.changeValue(UIUtils.shift() ? 10 : 1); + if (character == '-') field.changeValue(UIUtils.shift() ? -10 : -1); + + if (character != 0) listener.changed(getValue()); + + return true; + } + }); + + addListener(new FocusListener() { + @Override + public void keyboardFocusChanged (FocusEvent event, Actor actor, boolean focused) { + if (focused == false && isInputValid() == false) + setValue(maxValue); //only possibility on invalid field is that entered value will be bigger than maxValue so we set field value to maxValue + } + }); + } + + public void changeValue (int byValue) { + this.value += byValue; + + if (value > maxValue) value = maxValue; + if (value < 0) value = 0; + + updateUI(); + } + + public int getValue () { + return value; + } + + public void setValue (int value) { + this.value = value; + updateUI(); + } + + private void updateUI () { + setText(String.valueOf(value)); + setCursorPosition(getMaxLength()); + } + + interface ColorInputFieldListener { + public void changed (int newValue); + } + + private static class NumberFilter implements TextFieldFilter { + @Override + public boolean acceptChar (VisTextField textField, char c) { + return Character.isDigit(c); + } + } + + private static class ColorFieldValidator implements InputValidator { + private int maxValue; + + public ColorFieldValidator (int maxValue) { + this.maxValue = maxValue; + } + + @Override + public boolean validateInput (String input) { + if (input.equals("")) return false; + + Integer number = Integer.parseInt(input); + if (number > maxValue) return false; + + return true; + } + } +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorPickerAdapter.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorPickerAdapter.java new file mode 100644 index 00000000..10b2e34b --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorPickerAdapter.java @@ -0,0 +1,41 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common.color; + +import com.badlogic.gdx.graphics.Color; + +/** + * Created by azakhary on 7/14/2015. + */ +public class ColorPickerAdapter implements ColorPickerListener { + @Override + public void canceled() { + + } + + @Override + public void finished(Color newColor) { + + } + + @Override + public void changed(Color newColor) { + + } +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorPickerListener.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorPickerListener.java new file mode 100644 index 00000000..f8c3bdbe --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorPickerListener.java @@ -0,0 +1,34 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common.color; + +import com.badlogic.gdx.graphics.Color; + +/** + * Created by azakhary on 7/14/2015. + */ +public interface ColorPickerListener { + /** Called when color selection was canceled by user (either by clicking cancel or closing the window) */ + public void canceled (); + + /** Called when user finises selecting new color */ + public void finished (Color newColor); + + public void changed (Color newColor); +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorPickerText.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorPickerText.java new file mode 100644 index 00000000..000963a9 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/ColorPickerText.java @@ -0,0 +1,53 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common.color; + +import com.kotcrab.vis.ui.Locales; +import com.kotcrab.vis.ui.i18n.BundleText; + +/** + * Contains texts for chooser access via I18NBundle + * @since 0.7.0 + */ +public enum ColorPickerText implements BundleText { + // @formatter:off + TITLE {public String getName () {return "title";}}, + RESTORE {public String getName () {return "restore";}}, + CANCEL {public String getName () {return "cancel";}}, + OK {public String getName () {return "ok";}}, + //NEW {public String getName () {return "new";}}, + //OLD {public String getName () {return "old";}}, + HEX {public String getName () {return "hex";}}; + // @formatter:on + + @Override + public String get () { + return Locales.getColorPickerBundle().get(getName()); + } + + @Override + public String format () { + throw new UnsupportedOperationException(); + } + + @Override + public String format (Object... arguments) { + throw new UnsupportedOperationException(); + } +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/CustomColorPicker.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/CustomColorPicker.java new file mode 100644 index 00000000..0dfd8aa3 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/color/CustomColorPicker.java @@ -0,0 +1,589 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common.color; + +import static games.rednblack.h2d.common.color.ColorPickerText.CANCEL; +import static games.rednblack.h2d.common.color.ColorPickerText.HEX; +import static games.rednblack.h2d.common.color.ColorPickerText.OK; +import static games.rednblack.h2d.common.color.ColorPickerText.RESTORE; +import static games.rednblack.h2d.common.color.ColorPickerText.TITLE; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Pixmap.Format; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.scenes.scene2d.utils.Drawable; +import com.badlogic.gdx.utils.Align; +import com.badlogic.gdx.utils.Disposable; +import com.badlogic.gdx.utils.I18NBundle; +import com.kotcrab.vis.ui.Locales; +import com.kotcrab.vis.ui.Sizes; +import com.kotcrab.vis.ui.VisUI; +import com.kotcrab.vis.ui.util.ColorUtils; +import com.kotcrab.vis.ui.widget.VisImageButton; +import com.kotcrab.vis.ui.widget.VisLabel; +import com.kotcrab.vis.ui.widget.VisTable; +import com.kotcrab.vis.ui.widget.VisTextButton; +import com.kotcrab.vis.ui.widget.VisTextField; +import com.kotcrab.vis.ui.widget.VisTextField.TextFieldFilter; +import com.kotcrab.vis.ui.widget.VisValidatableTextField; +import com.kotcrab.vis.ui.widget.VisWindow; +import com.kotcrab.vis.ui.widget.color.ColorPickerStyle; +import com.kotcrab.vis.ui.widget.color.internal.AlphaImage; +import com.kotcrab.vis.ui.widget.color.internal.Palette; +import com.kotcrab.vis.ui.widget.color.internal.PickerCommons; +import com.kotcrab.vis.ui.widget.color.internal.VerticalChannelBar; + +/** + * Created by azakhary on 7/14/2015. + * some methods are modified to better fit the needs of real time updating. + * Also using new ColorPickerListener that has method "changed" + * + * + * @author Kotcrab + */ +public class CustomColorPicker extends VisWindow implements Disposable { + + private static final Drawable WHITE = VisUI.getSkin().getDrawable("white"); + + static final int FIELD_WIDTH = 50; + static final int HEX_FIELD_WIDTH = 95; + + static final int PALETTE_SIZE = 160; + static final int BAR_WIDTH = 130; + static final int BAR_HEIGHT = 11; + static final float VERTICAL_BAR_WIDTH = 15; + + private ColorPickerStyle style; + private Sizes sizes; + private I18NBundle bundle; + + private ColorPickerListener listener; + + private Color oldColor; + private Color color; + private Color tmpColor; //temp color used for hsv to rgb calculations + + private Pixmap barPixmap; + private Texture barTexture; + private VerticalChannelBar verticalBar; + + private Palette palette; + + private ColorChannelWidget hBar; + private ColorChannelWidget sBar; + private ColorChannelWidget vBar; + + private ColorChannelWidget rBar; + private ColorChannelWidget gBar; + private ColorChannelWidget bBar; + + private ColorChannelWidget aBar; + + private VisValidatableTextField hexField; + + private VisTextButton restoreButton; + private VisTextButton cancelButton; + private VisTextButton okButton; + + private Image currentColor; + private Image newColor; + + private boolean pickerCreated = false; + + private boolean closeAfterPickingFinished = true; + + public CustomColorPicker () { + this((String) null); + } + + public CustomColorPicker (String title) { + this("default", title, null); + } + + public CustomColorPicker (String title, ColorPickerListener listener) { + this("default", title, listener); + } + + public CustomColorPicker (ColorPickerListener listener) { + this("default", null, listener); + } + + public CustomColorPicker (String styleName, String title, ColorPickerListener listener) { + super(title != null ? title : ""); + this.listener = listener; + this.style = VisUI.getSkin().get(styleName, ColorPickerStyle.class); + this.sizes = VisUI.getSizes(); + this.bundle = Locales.getColorPickerBundle(); + + if (title == null) getTitleLabel().setText(getText(TITLE)); + + setModal(true); + setMovable(true); + + addCloseButton(); + closeOnEscape(); + + oldColor = new Color(Color.BLACK); + color = new Color(Color.BLACK); + tmpColor = new Color(Color.BLACK); + + createColorWidgets(); + createUI(); + createListeners(); + updatePixmaps(); + + pack(); + centerWindow(); + + setStyle(VisUI.getSkin().get("box", WindowStyle.class)); + getTitleLabel().setAlignment(Align.left); + + pickerCreated = true; + } + + @Override + public void addCloseButton() { + VisImageButton closeButton = new VisImageButton("close-panel"); + this.getTitleTable().add(closeButton).padBottom(2); + closeButton.addListener(new ChangeListener() { + public void changed(ChangeEvent event, Actor actor) { + CustomColorPicker.this.close(); + } + }); + if (this.getTitleTable().getChildren().size == 2) { + this.getTitleTable().getCell(this.getTitleLabel()).padLeft(closeButton.getWidth() * 2.0F); + } + } + + + private void createUI () { + VisTable rightTable = new VisTable(true); + + rightTable.add(hBar).row(); + rightTable.add(sBar).row(); + rightTable.add(vBar).row(); + + rightTable.add(); + rightTable.row(); + + rightTable.add(rBar).row(); + rightTable.add(gBar).row(); + rightTable.add(bBar).row(); + + rightTable.add(); + rightTable.row(); + + rightTable.add(aBar).row(); + + VisTable leftTable = new VisTable(true); + leftTable.add(palette).size(PALETTE_SIZE * sizes.scaleFactor); + leftTable.row(); + leftTable.add(createColorsPreviewTable()).expandX().fillX(); + leftTable.row(); + leftTable.add(createHexTable()).expandX().left(); + + add(leftTable).top().padRight(5); + add(verticalBar).size(VERTICAL_BAR_WIDTH * sizes.scaleFactor, PALETTE_SIZE * sizes.scaleFactor).top(); + add(rightTable).expand().left().top().pad(4); + row(); + add(createButtons()).pad(3).right().expandX().colspan(3); + } + + private VisTable createColorsPreviewTable () { + VisTable table = new VisTable(false); + PickerCommons commons = new PickerCommons(style.pickerStyle, new Sizes(), true); + //FIXME getText(OLD) + table.add(new VisLabel("Old")).spaceRight(3); + table.add(currentColor = new AlphaImage(commons, 0)).height(25 * sizes.scaleFactor).expandX().fillX(); + table.row(); + //FIXME getText(NEW) + table.add(new VisLabel("New")).spaceRight(3); + + table.add(newColor = new AlphaImage(commons, 0)).height(25 * sizes.scaleFactor).expandX().fillX(); + + currentColor.setColor(color); + newColor.setColor(color); + + return table; + } + + private VisTable createHexTable () { + VisTable table = new VisTable(true); + table.add(new VisLabel(getText(HEX))); + table.add(hexField = new VisValidatableTextField("00000000")).width(HEX_FIELD_WIDTH * sizes.scaleFactor); + table.row(); + + hexField.setMaxLength(8); + hexField.setProgrammaticChangeEvents(false); + hexField.setTextFieldFilter(new TextFieldFilter() { + @Override + public boolean acceptChar (VisTextField textField, char c) { + return Character.isDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + } + }); + + hexField.addListener(new ChangeListener() { + @Override + public void changed (ChangeEvent event, Actor actor) { + if (hexField.getText().length() == 8) setColor(Color.valueOf(hexField.getText()), false); + } + }); + + return table; + } + + private VisTable createButtons () { + VisTable table = new VisTable(true); + table.defaults().right(); + table.add(restoreButton = new VisTextButton(getText(RESTORE))); + table.add(okButton = new VisTextButton(getText(OK))); + table.add(cancelButton = new VisTextButton(getText(CANCEL))); + return table; + } + + private void createColorWidgets () { + barPixmap = new Pixmap(1, 360, Format.RGB888); + + for (int h = 0; h < 360; h++) { + ColorUtils.HSVtoRGB(360 - h, 100, 100, tmpColor); + barPixmap.drawPixel(0, h, Color.rgba8888(tmpColor)); + } + + barTexture = new Texture(barPixmap); + PickerCommons pickerCommons = new PickerCommons(style.pickerStyle, sizes, true); + palette = new Palette(pickerCommons, 100, new ChangeListener() { + @Override + public void changed (ChangeEvent event, Actor actor) { + sBar.setValue(palette.getS()); + vBar.setValue(palette.getV()); + + updateHSVValuesFromFields(); + updatePixmaps(); + } + }); + + verticalBar = new VerticalChannelBar(pickerCommons, 360, new ChangeListener() { + @Override + public void changed (ChangeEvent event, Actor actor) { + hBar.setValue(verticalBar.getValue()); + updateHSVValuesFromFields(); + updatePixmaps(); + } + }); + + hBar = new ColorChannelWidget(style, sizes, "H", 360, new ColorChannelWidget.ColorChannelWidgetListener() { + @Override + public void updateFields () { + verticalBar.setValue(hBar.getValue()); + updateHSVValuesFromFields(); + updatePixmaps(); + } + + @Override + public void draw (Pixmap pixmap) { + for (int h = 0; h < 360; h++) { + ColorUtils.HSVtoRGB(h, sBar.getValue(), vBar.getValue(), tmpColor); + pixmap.drawPixel(h, 0, Color.rgba8888(tmpColor)); + } + } + }); + + sBar = new ColorChannelWidget(style, sizes, "S", 100, new ColorChannelWidget.ColorChannelWidgetListener() { + @Override + public void updateFields () { + palette.setValue(sBar.getValue(), vBar.getValue()); + updateHSVValuesFromFields(); + updatePixmaps(); + } + + @Override + public void draw (Pixmap pixmap) { + for (int s = 0; s < 100; s++) { + ColorUtils.HSVtoRGB(hBar.getValue(), s, vBar.getValue(), tmpColor); + pixmap.drawPixel(s, 0, Color.rgba8888(tmpColor)); + } + } + }); + + vBar = new ColorChannelWidget(style, sizes, "V", 100, new ColorChannelWidget.ColorChannelWidgetListener() { + @Override + public void updateFields () { + palette.setValue(sBar.getValue(), vBar.getValue()); + updateHSVValuesFromFields(); + updatePixmaps(); + } + + @Override + public void draw (Pixmap pixmap) { + for (int v = 0; v < 100; v++) { + ColorUtils.HSVtoRGB(hBar.getValue(), sBar.getValue(), v, tmpColor); + pixmap.drawPixel(v, 0, Color.rgba8888(tmpColor)); + } + + } + }); + + rBar = new ColorChannelWidget(style, sizes, "R", 255, new ColorChannelWidget.ColorChannelWidgetListener() { + @Override + public void updateFields () { + updateRGBValuesFromFields(); + updatePixmaps(); + } + + @Override + public void draw (Pixmap pixmap) { + for (int r = 0; r < 255; r++) { + tmpColor.set(r / 255.0f, color.g, color.b, 1); + pixmap.drawPixel(r, 0, Color.rgba8888(tmpColor)); + } + } + }); + + gBar = new ColorChannelWidget(style, sizes, "G", 255, new ColorChannelWidget.ColorChannelWidgetListener() { + @Override + public void updateFields () { + updateRGBValuesFromFields(); + updatePixmaps(); + } + + @Override + public void draw (Pixmap pixmap) { + for (int g = 0; g < 255; g++) { + tmpColor.set(color.r, g / 255.0f, color.b, 1); + pixmap.drawPixel(g, 0, Color.rgba8888(tmpColor)); + } + } + }); + + bBar = new ColorChannelWidget(style, sizes, "B", 255, new ColorChannelWidget.ColorChannelWidgetListener() { + @Override + public void updateFields () { + updateRGBValuesFromFields(); + updatePixmaps(); + } + + @Override + public void draw (Pixmap pixmap) { + for (int b = 0; b < 255; b++) { + tmpColor.set(color.r, color.g, b / 255.0f, 1); + pixmap.drawPixel(b, 0, Color.rgba8888(tmpColor)); + } + + } + }); + + aBar = new ColorChannelWidget(style, sizes, "A", 255, true, new ColorChannelWidget.ColorChannelWidgetListener() { + @Override + public void updateFields () { + if (aBar.isInputValid()) color.a = aBar.getValue() / 255.0f; + updatePixmaps(); + } + + @Override + public void draw (Pixmap pixmap) { + pixmap.fill(); + for (int i = 0; i < 255; i++) { + tmpColor.set(color.r, color.g, color.b, i / 255.0f); + pixmap.drawPixel(i, 0, Color.rgba8888(tmpColor)); + } + } + }); + } + + private void createListeners () { + restoreButton.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + setColor(oldColor); + } + }); + + okButton.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + if (listener != null) listener.finished(new Color(color)); + setColor(color); + if (closeAfterPickingFinished) fadeOut(); + } + }); + + cancelButton.addListener(new ChangeListener() { + @Override + public void changed(ChangeEvent event, Actor actor) { + setColor(oldColor); + close(); + } + }); + } + + @Override + protected void close () { + if (listener != null) listener.canceled(); + super.close(); + } + + public ColorPickerListener getListener () { + return listener; + } + + public void setListener (ColorPickerListener listener) { + this.listener = listener; + } + + private void updatePixmaps () { + palette.setPickerHue(hBar.getValue()); + newColor.setColor(color); + + hBar.redraw(); + sBar.redraw(); + vBar.redraw(); + + rBar.redraw(); + gBar.redraw(); + bBar.redraw(); + + aBar.redraw(); + + hexField.setText(color.toString().toUpperCase()); + hexField.setCursorPosition(hexField.getMaxLength()); + + if (listener != null && pickerCreated) listener.changed(new Color(color)); + } + @Override + /** Sets current selected color in picker.*/ + public void setColor (Color c) { + //this method overrides setColor in Actor, not big deal we definitely don't need it + setColor(c, true); + } + + private void setColor (Color c, boolean updateCurrentColor) { + if (updateCurrentColor) { + currentColor.setColor(new Color(c)); + oldColor = new Color(c); + } + color = new Color(c); + updateFieldsFromColor(); + updatePixmaps(); + } + + private String getText (ColorPickerText text) { + return bundle.get(text.getName()); + } + + /** + * Controls whether to fade out color picker after users finished color picking and has pressed OK button. If + * this is set to false picker won't close after pressing OK button. Default is true. + * Note that by default picker is a modal window so might also want to call {@code colorPicker.setModal(false)} to + * disable it. + */ + public void setCloseAfterPickingFinished (boolean closeAfterPickingFinished) { + this.closeAfterPickingFinished = closeAfterPickingFinished; + } + + @Override + public void dispose () { + barTexture.dispose(); + barPixmap.dispose(); + + hBar.dispose(); + sBar.dispose(); + vBar.dispose(); + + rBar.dispose(); + gBar.dispose(); + bBar.dispose(); + + aBar.dispose(); + } + + private void updateFieldsFromColor () { + int[] hsv = ColorUtils.RGBtoHSV(color); + int ch = hsv[0]; + int cs = hsv[1]; + int cv = hsv[2]; + + int cr = MathUtils.round(color.r * 255.0f); + int cg = MathUtils.round(color.g * 255.0f); + int cb = MathUtils.round(color.b * 255.0f); + int ca = MathUtils.round(color.a * 255.0f); + + hBar.setValue(ch); + sBar.setValue(cs); + vBar.setValue(cv); + + rBar.setValue(cr); + gBar.setValue(cg); + bBar.setValue(cb); + + aBar.setValue(ca); + + verticalBar.setValue(hBar.getValue()); + palette.setValue(sBar.getValue(), vBar.getValue()); + } + + private void updateHSVValuesFromFields () { + int[] hsv = ColorUtils.RGBtoHSV(color); + int h = hsv[0]; + int s = hsv[1]; + int v = hsv[2]; + + if (hBar.isInputValid()) h = hBar.getValue(); + if (sBar.isInputValid()) s = sBar.getValue(); + if (vBar.isInputValid()) v = vBar.getValue(); + + color = ColorUtils.HSVtoRGB(h, s, v, color.a); + + int cr = MathUtils.round(color.r * 255.0f); + int cg = MathUtils.round(color.g * 255.0f); + int cb = MathUtils.round(color.b * 255.0f); + + rBar.setValue(cr); + gBar.setValue(cg); + bBar.setValue(cb); + } + + private void updateRGBValuesFromFields () { + int r = MathUtils.round(color.r * 255.0f); + int g = MathUtils.round(color.g * 255.0f); + int b = MathUtils.round(color.b * 255.0f); + + if (rBar.isInputValid()) r = rBar.getValue(); + if (gBar.isInputValid()) g = gBar.getValue(); + if (bBar.isInputValid()) b = bBar.getValue(); + + color.set(r / 255.0f, g / 255.0f, b / 255.0f, color.a); + + int[] hsv = ColorUtils.RGBtoHSV(color); + int ch = hsv[0]; + int cs = hsv[1]; + int cv = hsv[2]; + + hBar.setValue(ch); + sBar.setValue(cs); + vBar.setValue(cv); + + verticalBar.setValue(hBar.getValue()); + palette.setValue(sBar.getValue(), vBar.getValue()); + } +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/plugins/H2DPlugin.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/plugins/H2DPlugin.java new file mode 100644 index 00000000..b4f3a5dc --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/plugins/H2DPlugin.java @@ -0,0 +1,37 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common.plugins; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; + +import java.util.Set; + +/** + * Created by azakhary on 7/24/2015. + */ +public interface H2DPlugin { + + String getName(); + void initPlugin(); + + public void setAPI(PluginAPI pluginAPI); + + public void onDropDownOpen(Set selectedEntities, Array actionsSet); +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/plugins/H2DPluginAdapter.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/plugins/H2DPluginAdapter.java new file mode 100644 index 00000000..35aabdc6 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/plugins/H2DPluginAdapter.java @@ -0,0 +1,59 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common.plugins; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import com.puremvc.patterns.facade.Facade; +import net.mountainblade.modular.Module; + +import java.util.Set; + +/** + * Created by azakhary on 7/24/2015. + */ +public abstract class H2DPluginAdapter implements H2DPlugin, Module { + + public Facade facade; + protected PluginAPI pluginAPI; + + public String getName() { + return ""; + } + + @Override + public void setAPI(PluginAPI pluginAPI) { + this.pluginAPI = pluginAPI; + facade = pluginAPI.getFacade(); + } + + /** + * Triggered whenever a context menu is displayed + * + * @param selectedEntities list of entities that were selected when context menu was created about, if right clicked on empty space empty array is used + * @param actionsSet list of current actions (notification id's) planned for this particular context menu, it can be modified by adding or removing elements. + */ + @Override + public void onDropDownOpen(Set selectedEntities, Array actionsSet) { + + } + + public PluginAPI getAPI() { + return pluginAPI; + } +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/plugins/PluginAPI.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/plugins/PluginAPI.java new file mode 100644 index 00000000..907b4591 --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/plugins/PluginAPI.java @@ -0,0 +1,178 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common.plugins; + +import com.badlogic.ashley.core.Engine; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.Stage; +import games.rednblack.h2d.common.IItemCommand; +import games.rednblack.h2d.common.view.tools.Tool; +import com.kotcrab.vis.ui.widget.VisImageButton; +import com.puremvc.patterns.facade.Facade; +import games.rednblack.editor.renderer.SceneLoader; +import com.vo.CursorData; + +import java.util.HashMap; +import java.util.HashSet; + +/** + * Plugin API is a main interface of communication between plugin and HyperLap2D editor + * Created by azakhary on 7/24/2015. + */ +public interface PluginAPI { + /** + * Get scene loader of the runtime to work with scene and items + * @return SceneLoader + */ + public SceneLoader getSceneLoader(); + + /** + * Returns MVC facade, to send notifications or commands, and register mediators + * @return Facade + */ + public Facade getFacade(); + + /** + * Returns Ashley engine of main scene where all entities are located + * @return Engine + */ + public Engine getEngine(); + + /** + * Get simple libGDX Stage for UI part of editor, to add dialogs or other UI elements and widgets + * @return + */ + public Stage getUIStage(); + + /** + * @return Path of plugin directory + */ + public String getPluginDir(); + + /** + * @return Path of working project + */ + public String getProjectPath(); + + /** + * @return TextureAtlas of loaded project + */ + public TextureAtlas getProjectTextureAtlas(); + + + /** + * Adds new sub menu item to the top bar + * @param menu unique identifier to global menu items provided in @Overlap2DMenuBar by three constants FILE_MENU, EDIT_MENU, WINDOWS_MENU + * @param subMenuName pretty string to name new submenu item + * @param notificationName unique notification id that will be fired when this menu item is clicked + */ + public void addMenuItem(String menu, String subMenuName, String notificationName); + + /** + * Adds new tool to the tool bar + * @param toolName pretty string to name new tool item + * @param toolBtnStyle tool button style + * @param addSeparator true, if should add menu separator + * @param tool the tool object that is going to be added + */ + public void addTool(String toolName, VisImageButton.VisImageButtonStyle toolBtnStyle, boolean addSeparator, Tool tool); + + + /** + * hot-swaps a tool + */ + public void toolHotSwap(Tool tool); + + /** + * hot-swaps a tool back + */ + public void toolHotSwapBack(); + + /** + * Creates new menu item for Contextual drop down menu, that is created when user right clicks on something in the editor. + * This only creates a menu item, but it should be specifically added later to action set, at the moment context menu is summoned + * @param action unique name of notification id that will be fired when this menu item is clicked + * @param name pretty text to be written on this menu item + */ + public void setDropDownItemName(String action, String name); + + /** + * re-loads current project entirely (used when changes were made that require to whole project to be reloaded) + */ + public void reLoadProject(); + + /** + * Saves current project + */ + public void saveProject(); + + /** + * Creates a revertable command that later can be undone or re-done by user with Ctrl+Z or similar. + * @param command Object containing your command logic + * @param body Additional data that can be send as parameters + */ + public void revertableCommand(IItemCommand command, Object body); + + /** + * Removes follower object (selection rectangle) from particular entity (usually makes sense when entity is deleted without proper action) + * @param entity + */ + public void removeFollower(Entity entity); + + /** + * Draws an image at selected position + * @param regionName name of texture region to create image from + * @param position position to draw image at + * @return image entity + */ + Entity drawImage(String regionName, Vector2 position); + + /** + * @return entities that are on scene + */ + HashSet getProjectEntities(); + + /** + * @param entity + * @return if entity is on visible layer + */ + boolean isEntityVisible(Entity entity); + + /** + * shows drop down menu with specified actions set + * @param actionsSet + * @param observable item with right click on it + */ + void showPopup(HashMap actionsSet, Object observable); + + /** + * sets cursor to new one with cursorData + * @param cursorData + * @param region for plugin unic textureRegion + */ + void setCursor(CursorData cursorData, TextureRegion region); + + /** + * returns current selected layer name + */ + String getCurrentSelectedLayerName(); +} diff --git a/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/view/tools/Tool.java b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/view/tools/Tool.java new file mode 100644 index 00000000..76eb58fd --- /dev/null +++ b/hyperlap2d-common-api/src/main/java/games/rednblack/h2d/common/view/tools/Tool.java @@ -0,0 +1,44 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.h2d.common.view.tools; + +import com.badlogic.ashley.core.Entity; +import com.puremvc.patterns.observer.Notification; + +/** + * Created by azakhary on 4/30/2015. + */ +public interface Tool { + void initTool(); + boolean stageMouseDown(float x, float y); + void stageMouseUp(float x, float y); + void stageMouseDragged(float x, float y); + void stageMouseDoubleClick(float x, float y); + void stageMouseScrolled(int amount); + boolean itemMouseDown(Entity entity, float x, float y); + void itemMouseUp(Entity entity, float x, float y); + void itemMouseDragged(Entity entity, float x, float y); + void itemMouseDoubleClick(Entity entity, float x, float y); + String getName(); + String getTitle(); + String getShortcut(); + void handleNotification(Notification notification); + void keyDown(Entity entity, int keycode); + void keyUp(Entity entity, int keycode); +} diff --git a/hyperlap2d-runtime-libgdx/build.gradle b/hyperlap2d-runtime-libgdx/build.gradle new file mode 100644 index 00000000..95781ac5 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'java' +} + +group 'games.rednblack' +version '0.0.1' + +ext { + gdxVersion = '1.9.10' + box2dlightsVersion = '1.5' + ashleyVersion = '1.7.3' +} + +repositories { + mavenCentral() +} + +dependencies { + implementation "com.badlogicgames.gdx:gdx:$gdxVersion" + implementation "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" + implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion" + implementation "com.badlogicgames.box2dlights:box2dlights:$box2dlightsVersion" + implementation "com.badlogicgames.ashley:ashley:$ashleyVersion" + + testImplementation group: 'junit', name: 'junit', version: '4.12' +} + +task dist(type: Jar) { + from files(sourceSets.main.output.classesDirs) + from files(sourceSets.main.output.resourcesDir) +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Animation.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Animation.java new file mode 100644 index 00000000..3d9cb975 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Animation.java @@ -0,0 +1,204 @@ +package com.brashmonkey.spriter; + +import java.util.HashMap; + +import com.brashmonkey.spriter.Mainline.Key; +import com.brashmonkey.spriter.Mainline.Key.BoneRef; +import com.brashmonkey.spriter.Mainline.Key.ObjectRef; +import com.brashmonkey.spriter.Timeline.Key.Bone; +import com.brashmonkey.spriter.Timeline.Key.Object; +/** + * Represents an animation of a Spriter SCML file. + * An animation holds {@link Timeline}s and a {@link Mainline} to animate objects. + * Furthermore it holds an {@link #id}, a {@link #length}, a {@link #name} and whether it is {@link #looping} or not. + * @author Trixt0r + * + */ +public class Animation { + + public final Mainline mainline; + private final Timeline[] timelines; + private int timelinePointer = 0; + private final HashMap nameToTimeline; + public final int id, length; + public final String name; + public final boolean looping; + Key currentKey; + Timeline.Key[] tweenedKeys, unmappedTweenedKeys; + private boolean prepared; + + public Animation(Mainline mainline, int id, String name, int length, boolean looping, int timelines){ + this.mainline = mainline; + this.id = id; + this.name = name; + this.length = length; + this.looping = looping; + this.timelines = new Timeline[timelines]; + this.prepared = false; + this.nameToTimeline = new HashMap(); + //this.currentKey = mainline.getKey(0); + } + + /** + * Returns a {@link Timeline} with the given index. + * @param index the index of the timeline + * @return the timeline with the given index + * @throws IndexOutOfBoundsException if the index is out of range + */ + public Timeline getTimeline(int index){ + return this.timelines[index]; + } + + /** + * Returns a {@link Timeline} with the given name. + * @param name the name of the time line + * @return the time line with the given name or null if no time line exists with the given name. + */ + public Timeline getTimeline(String name){ + return this.nameToTimeline.get(name); + } + + void addTimeline(Timeline timeline){ + this.timelines[timelinePointer++] = timeline; + this.nameToTimeline.put(timeline.name, timeline); + } + + /** + * Returns the number of time lines this animation holds. + * @return the number of time lines + */ + public int timelines(){ + return timelines.length; + } + + public String toString(){ + String toReturn = getClass().getSimpleName()+"|[id: "+id+", "+name+", duration: "+length+", is looping: "+looping; + toReturn +="Mainline:\n"; + toReturn += mainline; + toReturn += "Timelines\n"; + for(Timeline timeline: this.timelines) + toReturn += timeline; + toReturn+="]"; + return toReturn; + } + + /** + * Updates the bone and object structure with the given time to the given root bone. + * @param time The time which has to be between 0 and {@link #length} to work properly. + * @param root The root bone which is not allowed to be null. The whole animation runs relative to the root bone. + */ + public void update(int time, Bone root){ + if(!this.prepared) throw new SpriterException("This animation is not ready yet to animate itself. Please call prepare()!"); + if(root == null) throw new SpriterException("The root can not be null! Set a root bone to apply this animation relative to the root bone."); + this.currentKey = mainline.getKeyBeforeTime(time); + + for(Timeline.Key timelineKey: this.unmappedTweenedKeys) + timelineKey.active = false; + for(BoneRef ref: currentKey.boneRefs) + this.update(ref, root, time); + for(ObjectRef ref: currentKey.objectRefs) + this.update(ref, root, time); + } + + protected void update(BoneRef ref, Bone root, int time){ + boolean isObject = ref instanceof ObjectRef; + //Get the timelines, the refs pointing to + Timeline timeline = getTimeline(ref.timeline); + Timeline.Key key = timeline.getKey(ref.key); + Timeline.Key nextKey = timeline.getKey((ref.key+1)%timeline.keys.length); + int currentTime = key.time; + int nextTime = nextKey.time; + if(nextTime < currentTime){ + if(!looping) nextKey = key; + else nextTime = length; + } + //Normalize the time + float t = (float)(time - currentTime)/(float)(nextTime - currentTime); + if(Float.isNaN(t) || Float.isInfinite(t)) t = 1f; + if(currentKey.time > currentTime){ + float tMid = (float)(currentKey.time - currentTime)/(float)(nextTime - currentTime); + if(Float.isNaN(tMid) || Float.isInfinite(tMid)) tMid = 0f; + t = (float)(time - currentKey.time)/(float)(nextTime - currentKey.time); + if(Float.isNaN(t) || Float.isInfinite(t)) t = 1f; + t = currentKey.curve.tween(tMid, 1f, t); + } + else + t = currentKey.curve.tween(0f, 1f, t); + //Tween bone/object + Bone bone1 = key.object(); + Bone bone2 = nextKey.object(); + Bone tweenTarget = this.tweenedKeys[ref.timeline].object(); + if(isObject) this.tweenObject((Object)bone1, (Object)bone2, (Object)tweenTarget, t, key.curve, key.spin); + else this.tweenBone(bone1, bone2, tweenTarget, t, key.curve, key.spin); + this.unmappedTweenedKeys[ref.timeline].active = true; + this.unmapTimelineObject(ref.timeline, isObject,(ref.parent != null) ? + this.unmappedTweenedKeys[ref.parent.timeline].object(): root); + } + + void unmapTimelineObject(int timeline, boolean isObject, Bone root){ + Bone tweenTarget = this.tweenedKeys[timeline].object(); + Bone mapTarget = this.unmappedTweenedKeys[timeline].object(); + if(isObject) ((Object)mapTarget).set((Object)tweenTarget); + else mapTarget.set(tweenTarget); + mapTarget.unmap(root); + } + + protected void tweenBone(Bone bone1, Bone bone2, Bone target, float t, Curve curve, int spin){ + target.angle = curve.tweenAngle(bone1.angle, bone2.angle, t, spin); + curve.tweenPoint(bone1.position, bone2.position, t, target.position); + curve.tweenPoint(bone1.scale, bone2.scale, t, target.scale); + curve.tweenPoint(bone1.pivot, bone2.pivot, t, target.pivot); + } + + protected void tweenObject(Object object1, Object object2, Object target, float t, Curve curve, int spin){ + this.tweenBone(object1, object2, target, t, curve, spin); + target.alpha = curve.tweenAngle(object1.alpha, object2.alpha, t); + target.ref.set(object1.ref); + } + + Timeline getSimilarTimeline(Timeline t){ + Timeline found = getTimeline(t.name); + if(found == null && t.id < this.timelines()) found = this.getTimeline(t.id); + return found; + } + + /*Timeline getSimilarTimeline(BoneRef ref, Collection coveredTimelines){ + if(ref.parent == null) return null; + for(BoneRef boneRef: this.currentKey.objectRefs){ + Timeline t = this.getTimeline(boneRef.timeline); + if(boneRef.parent != null && boneRef.parent.id == ref.parent.id && !coveredTimelines.contains(t)) + return t; + } + return null; + } + + Timeline getSimilarTimeline(ObjectRef ref, Collection coveredTimelines){ + if(ref.parent == null) return null; + for(ObjectRef objRef: this.currentKey.objectRefs){ + Timeline t = this.getTimeline(objRef.timeline); + if(objRef.parent != null && objRef.parent.id == ref.parent.id && !coveredTimelines.contains(t)) + return t; + } + return null; + }*/ + + /** + * Prepares this animation to set this animation in any time state. + * This method has to be called before {@link #update(int, Bone)}. + */ + public void prepare(){ + if(this.prepared) return; + this.tweenedKeys = new Timeline.Key[timelines.length]; + this.unmappedTweenedKeys = new Timeline.Key[timelines.length]; + + for(int i = 0; i < this.tweenedKeys.length; i++){ + this.tweenedKeys[i] = new Timeline.Key(i); + this.unmappedTweenedKeys[i] = new Timeline.Key(i); + this.tweenedKeys[i].setObject(new Timeline.Key.Object(new Point(0,0))); + this.unmappedTweenedKeys[i].setObject(new Timeline.Key.Object(new Point(0,0))); + } + if(mainline.keys.length > 0) currentKey = mainline.getKey(0); + this.prepared = true; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Box.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Box.java new file mode 100644 index 00000000..92fb6774 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Box.java @@ -0,0 +1,99 @@ +package com.brashmonkey.spriter; + +import com.brashmonkey.spriter.Entity.ObjectInfo; + +/** + * Represents a box, which consists of four points: top-left, top-right, bottom-left and bottom-right. + * A box is responsible for checking collisions and calculating a bounding box for a {@link Timeline.Key.Bone}. + * @author Trixt0r + * + */ +public class Box { + public final Point[] points; + private Rectangle rect; + + /** + * Creates a new box with no witdh and height. + */ + public Box(){ + this.points = new Point[4]; + //this.temp = new Point[4]; + for(int i = 0; i < 4; i++){ + this.points[i] = new Point(0,0); + //this.temp[i] = new Point(0,0); + } + this.rect = new Rectangle(0,0,0,0); + } + + /** + * Calculates its four points for the given bone or object with the given info. + * @param boneOrObject the bone or object + * @param info the info + * @throws NullPointerException if info or boneOrObject is null + */ + public void calcFor(Timeline.Key.Bone boneOrObject, ObjectInfo info){ + float width = info.size.width*boneOrObject.scale.x; + float height = info.size.height*boneOrObject.scale.y; + + float pivotX = width*boneOrObject.pivot.x; + float pivotY = height*boneOrObject.pivot.y; + + this.points[0].set(-pivotX,-pivotY); + this.points[1].set(width-pivotX, -pivotY); + this.points[2].set(-pivotX,height-pivotY); + this.points[3].set(width-pivotX,height-pivotY); + + for(int i = 0; i < 4; i++) + this.points[i].rotate(boneOrObject.angle); + for(int i = 0; i < 4; i++) + this.points[i].translate(boneOrObject.position); + } + + /** + * Returns whether the given coordinates lie inside the box of the given bone or object. + * @param boneOrObject the bone or object + * @param info the object info of the given bone or object + * @param x the x coordinate + * @param y the y coordinate + * @return true if the given point lies in the box + * @throws NullPointerException if info or boneOrObject is null + */ + public boolean collides(Timeline.Key.Bone boneOrObject, ObjectInfo info, float x, float y){ + float width = info.size.width*boneOrObject.scale.x; + float height = info.size.height*boneOrObject.scale.y; + + float pivotX = width*boneOrObject.pivot.x; + float pivotY = height*boneOrObject.pivot.y; + + Point point = new Point(x-boneOrObject.position.x,y-boneOrObject.position.y); + point.rotate(-boneOrObject.angle); + + return point.x >= -pivotX && point.x <= width-pivotX && point.y >= -pivotY && point.y <= height-pivotY; + } + + /** + * Returns whether this box is inside the given rectangle. + * @param rect the rectangle + * @return true if one of the four points is inside the rectangle + */ + public boolean isInside(Rectangle rect){ + boolean inside = false; + for(Point p: points) + inside |= rect.isInside(p); + return inside; + } + + /** + * Returns a bounding box for this box. + * @return the bounding box + */ + public Rectangle getBoundingRect(){ + this.rect.set(points[0].x,points[0].y,points[0].x,points[0].y); + this.rect.left = Math.min(Math.min(Math.min(Math.min(points[0].x, points[1].x),points[2].x),points[3].x), this.rect.left); + this.rect.right = Math.max(Math.max(Math.max(Math.max(points[0].x, points[1].x),points[2].x),points[3].x), this.rect.right); + this.rect.top = Math.max(Math.max(Math.max(Math.max(points[0].y, points[1].y),points[2].y),points[3].y), this.rect.top); + this.rect.bottom = Math.min(Math.min(Math.min(Math.min(points[0].y, points[1].y),points[2].y),points[3].y), this.rect.bottom); + return this.rect; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/CCDResolver.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/CCDResolver.java new file mode 100644 index 00000000..5e59112c --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/CCDResolver.java @@ -0,0 +1,63 @@ +package com.brashmonkey.spriter; + +import com.brashmonkey.spriter.Mainline.Key.BoneRef; +import com.brashmonkey.spriter.Timeline.Key.Bone; + +/** + * An inverse kinematics resolver implementation. + * An instance of this class uses the CCD (Cyclic Coordinate Descent) algorithm to resolve the constraints. + * @see ccd-algorithm + * and cyclic-coordinate-descent-in-2d . + * @author Trixt0r + * + */ +public class CCDResolver extends IKResolver { + + public CCDResolver(Player player) { + super(player); + } + + @Override + public void resolve(float x, float y, int chainLength, BoneRef effectorRef) { + //player.unmapObjects(null); + Timeline timeline = player.animation.getTimeline(effectorRef.timeline); + Timeline.Key key = player.tweenedKeys[effectorRef.timeline]; + Timeline.Key unmappedKey = player.unmappedTweenedKeys[effectorRef.timeline]; + Bone effector = key.object(); + Bone unmappedffector = unmappedKey.object(); + float width = (timeline.objectInfo != null) ? timeline.objectInfo.size.width: 200; + width *= unmappedffector.scale.x; + float xx = unmappedffector.position.x+(float)Math.cos(Math.toRadians(unmappedffector.angle))*width, + yy = unmappedffector.position.y+(float)Math.sin(Math.toRadians(unmappedffector.angle))*width; + if(Calculator.distanceBetween(xx, yy, x, y) <= this.tolerance) + return; + + effector.angle = Calculator.angleBetween(unmappedffector.position.x, unmappedffector.position.y, x, y); + if(Math.signum(player.root.scale.x) == -1) effector.angle += 180f; + BoneRef parentRef = effectorRef.parent; + Bone parent = null, unmappedParent = null; + if(parentRef != null){ + parent = player.tweenedKeys[parentRef.timeline].object(); + unmappedParent = player.unmappedTweenedKeys[parentRef.timeline].object(); + effector.angle -= unmappedParent.angle; + } + player.unmapObjects(null); + for(int i = 0; i < chainLength && parentRef != null; i++){ + if(Calculator.distanceBetween(xx, yy, x, y) <= this.tolerance) + return; + parent.angle += Calculator.angleDifference(Calculator.angleBetween(unmappedParent.position.x, unmappedParent.position.y, x, y), + Calculator.angleBetween(unmappedParent.position.x, unmappedParent.position.y, xx, yy)); + parentRef = parentRef.parent; + if(parentRef != null && i < chainLength-1){ + parent = player.tweenedKeys[parentRef.timeline].object(); + unmappedParent = player.unmappedTweenedKeys[parentRef.timeline].object(); + parent.angle -= unmappedParent.angle; + } + else parent = null; + player.unmapObjects(null); + xx = unmappedffector.position.x+(float)Math.cos(Math.toRadians(unmappedffector.angle))*width; + yy = unmappedffector.position.y+(float)Math.sin(Math.toRadians(unmappedffector.angle))*width; + } + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Calculator.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Calculator.java new file mode 100644 index 00000000..b3e99adf --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Calculator.java @@ -0,0 +1,209 @@ +package com.brashmonkey.spriter; + +import static java.lang.Math.*; + +/** + * A utility class which provides methods to calculate Spriter specific issues, + * like linear interpolation and rotation around a parent object. + * Other interpolation types are coming with the next releases of Spriter. + * + * @author Trixt0r + * + */ + +public class Calculator { + + public final static float PI = (float)Math.PI; + + /** + * Calculates the smallest difference between angle a and b. + * @param a first angle (in degrees) + * @param b second angle (in degrees) + * @return Smallest difference between a and b (between 180 and -180). + */ + public static float angleDifference(float a, float b){ + return ((((a - b) % 360) + 540) % 360) - 180; + } + + /** + * @param x1 x coordinate of first point. + * @param y1 y coordinate of first point. + * @param x2 x coordinate of second point. + * @param y2 y coordinate of second point. + * @return Angle between the two given points. + */ + public static float angleBetween(float x1, float y1, float x2, float y2){ + return (float)toDegrees(atan2(y2-y1,x2-x1)); + } + + /** + * @param x1 x coordinate of first point. + * @param y1 y coordinate of first point. + * @param x2 x coordinate of second point. + * @param y2 y coordinate of second point. + * @return Distance between the two given points. + */ + public static float distanceBetween(float x1, float y1, float x2, float y2){ + float xDiff = x2-x1; + float yDiff = y2-y1; + return (float)sqrt(xDiff*xDiff+yDiff*yDiff); + } + + /** + * Solves the equation a*x^3 + b*x^2 + c*x +d = 0. + * @param a + * @param b + * @param c + * @param d + * @return the solution of the cubic function + */ + public static Float solveCubic(float a, float b, float c, float d) { + if (a == 0) return solveQuadratic(b, c, d); + if (d == 0) return 0f; + + b /= a; + c /= a; + d /= a; + float squaredB = squared(b); + float q = (3f * c - squaredB) / 9f; + float r = (-27f * d + b * (9f * c - 2f * squaredB)) / 54f; + float disc = cubed(q) + squared(r); + float term1 = b / 3f; + + if (disc > 0) { + float s = r + sqrt(disc); + s = (s < 0) ? -cubicRoot(-s) : cubicRoot(s); + float t = r - sqrt(disc); + t = (t < 0) ? -cubicRoot(-t) : cubicRoot(t); + + float result = -term1 + s + t; + if (result >= 0 && result <= 1) return result; + } else if (disc == 0) { + float r13 = (r < 0) ? -cubicRoot(-r) : cubicRoot(r); + + float result = -term1 + 2f * r13; + if (result >= 0 && result <= 1) return result; + + result = -(r13 + term1); + if (result >= 0 && result <= 1) return result; + } else { + q = -q; + float dum1 = q * q * q; + dum1 = acos(r / sqrt(dum1)); + float r13 = 2f * sqrt(q); + + float result = -term1 + r13 * cos(dum1 / 3f); + if (result >= 0 && result <= 1) return result; + + result = -term1 + r13 * cos((dum1 + 2f * PI) / 3f); + if (result >= 0 && result <= 1) return result; + + result = -term1 + r13 * cos((dum1 + 4f * PI) / 3f); + if (result >= 0 && result <= 1) return result; + } + + return null; + } + + /** + * Solves the equation a*x^2 + b*x + c = 0 + * @param a + * @param b + * @param c + * @return the solution for the quadratic function + */ + public static Float solveQuadratic(float a, float b, float c) { + float squaredB = squared(b); + float twoA = 2 * a; + float fourAC = 4 * a * c; + float result = (-b + sqrt(squaredB - fourAC)) / twoA; + if (result >= 0 && result <= 1) return result; + + result = (-b - sqrt(squaredB - fourAC)) / twoA; + if (result >= 0 && result <= 1) return result; + + return null; + } + + /** + * Returns the square of the given value. + * @param f the value + * @return the square of the value + */ + public static float squared(float f) { return f * f; } + + /** + * Returns the cubed value of the given one. + * @param f the value + * @return the cubed value + */ + public static float cubed(float f) { return f * f * f; } + + /** + * Returns the cubic root of the given value. + * @param f the value + * @return the cubic root + */ + public static float cubicRoot(float f) { return (float) pow(f, 1f / 3f); } + + /** + * Returns the square root of the given value. + * @param x the value + * @return the square root + */ + public static float sqrt(float x){ return (float)Math.sqrt(x); } + + /** + * Returns the arc cosine at the given value. + * @param x the value + * @return the arc cosine + */ + public static float acos(float x){ return (float)Math.acos(x); } + + static private final int SIN_BITS = 14; // 16KB. Adjust for accuracy. + static private final int SIN_MASK = ~(-1 << SIN_BITS); + static private final int SIN_COUNT = SIN_MASK + 1; + + static private final float radFull = PI * 2; + static private final float degFull = 360; + static private final float radToIndex = SIN_COUNT / radFull; + static private final float degToIndex = SIN_COUNT / degFull; + + /** multiply by this to convert from radians to degrees */ + static public final float radiansToDegrees = 180f / PI; + static public final float radDeg = radiansToDegrees; + /** multiply by this to convert from degrees to radians */ + static public final float degreesToRadians = PI / 180; + static public final float degRad = degreesToRadians; + + static private class Sin { + static final float[] table = new float[SIN_COUNT]; + static { + for (int i = 0; i < SIN_COUNT; i++) + table[i] = (float)Math.sin((i + 0.5f) / SIN_COUNT * radFull); + for (int i = 0; i < 360; i += 90) + table[(int)(i * degToIndex) & SIN_MASK] = (float)Math.sin(i * degreesToRadians); + } + } + + /** Returns the sine in radians from a lookup table. */ + static public final float sin (float radians) { + return Sin.table[(int)(radians * radToIndex) & SIN_MASK]; + } + + /** Returns the cosine in radians from a lookup table. */ + static public final float cos (float radians) { + return Sin.table[(int)((radians + PI / 2) * radToIndex) & SIN_MASK]; + } + + /** Returns the sine in radians from a lookup table. */ + static public final float sinDeg (float degrees) { + return Sin.table[(int)(degrees * degToIndex) & SIN_MASK]; + } + + /** Returns the cosine in radians from a lookup table. */ + static public final float cosDeg (float degrees) { + return Sin.table[(int)((degrees + 90) * degToIndex) & SIN_MASK]; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Curve.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Curve.java new file mode 100644 index 00000000..279bb151 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Curve.java @@ -0,0 +1,207 @@ +package com.brashmonkey.spriter; + +import static com.brashmonkey.spriter.Calculator.*; +import static com.brashmonkey.spriter.Interpolator.*; + +/** + * Represents a curve in a Spriter SCML file. + * An instance of this class is responsible for tweening given data. + * The most important method of this class is {@link #tween(float, float, float)}. + * Curves can be changed with sub curves {@link Curve#subCurve}. + * @author Trixt0r + * + */ +public class Curve { + + /** + * Represents a curve type in a Spriter SCML file. + * @author Trixt0r + * + */ + public static enum Type { + Instant, Linear, Quadratic, Cubic, Quartic, Quintic, Bezier; + } + + /** + * Returns a curve type based on the given curve name. + * @param name the name of the curve + * @return the curve type. {@link Type#Linear} is returned as a default type. + */ + public static Type getType(String name){ + if(name.equals("instant")) return Type.Instant; + else if(name.equals("quadratic")) return Type.Quadratic; + else if(name.equals("cubic")) return Type.Cubic; + else if(name.equals("quartic")) return Type.Quartic; + else if(name.equals("quintic")) return Type.Quintic; + else if(name.equals("bezier")) return Type.Bezier; + else return Type.Linear; + } + + private Type type; + /** + * The sub curve of this curve, which can be null. + */ + public Curve subCurve; + /** + * The constraints of a curve which will affect a curve of the types different from {@link Type#Linear} and {@link Type#Instant}. + */ + public final Constraints constraints = new Constraints(0, 0, 0, 0); + + /** + * Creates a new linear curve. + */ + public Curve(){ + this(Type.Linear); + } + + /** + * Creates a new curve with the given type. + * @param type the curve type + */ + public Curve(Type type){ + this(type, null); + } + + /** + * Creates a new curve with the given type and sub cuve. + * @param type the curve type + * @param subCurve the sub curve. Can be null + */ + public Curve(Type type, Curve subCurve){ + this.setType(type); + this.subCurve = subCurve; + } + + /** + * Sets the type of this curve. + * @param type the curve type. + * @throws SpriterException if the type is null + */ + public void setType(Type type){ + if(type == null) throw new SpriterException("The type of a curve cannot be null!"); + this.type = type; + } + + /** + * Returns the type of this curve. + * @return the curve type + */ + public Type getType(){ + return this.type; + } + + + private float lastCubicSolution = 0f; + /** + * Returns a new value based on the given values. + * Tweens the weight with the set sub curve. + * @param a the start value + * @param b the end value + * @param t the weight which lies between 0.0 and 1.0 + * @return tweened value + */ + public float tween(float a, float b, float t){ + t = tweenSub(0f,1f,t); + switch(type){ + case Instant: return a; + case Linear: return linear(a, b, t); + case Quadratic: return quadratic(a, linear(a, b, constraints.c1), b, t); + case Cubic: return cubic(a, linear(a, b, constraints.c1), linear(a, b, constraints.c2), b, t); + case Quartic: return quartic(a, linear(a, b, constraints.c1), linear(a, b, constraints.c2), linear(a, b, constraints.c3), b, t); + case Quintic: return quintic(a, linear(a, b, constraints.c1), linear(a, b, constraints.c2), linear(a, b, constraints.c3), linear(a, b, constraints.c4), b, t); + case Bezier: Float cubicSolution = solveCubic(3f*(constraints.c1-constraints.c3) + 1f, 3f*(constraints.c3-2f*constraints.c1), 3f*constraints.c1, -t); + if(cubicSolution == null) cubicSolution = lastCubicSolution; + else lastCubicSolution = cubicSolution; + return linear(a, b, bezier(cubicSolution, 0f, constraints.c2, constraints.c4, 1f)); + default: return linear(a, b, t); + } + } + + /** + * Interpolates the given two points with the given weight and saves the result in the target point. + * @param a the start point + * @param b the end point + * @param t the weight which lies between 0.0 and 1.0 + * @param target the target point to save the result in + */ + public void tweenPoint(Point a, Point b, float t, Point target){ + target.set(this.tween(a.x, b.x, t), this.tween(a.y, b.y, t)); + } + + private float tweenSub(float a, float b, float t){ + if(this.subCurve != null) return subCurve.tween(a, b, t); + else return t; + } + + /** + * Returns a tweened angle based on the given angles, weight and the spin. + * @param a the start angle + * @param b the end angle + * @param t the weight which lies between 0.0 and 1.0 + * @param spin the spin, which is either 0, 1 or -1 + * @return tweened angle + */ + public float tweenAngle(float a, float b, float t, int spin){ + if(spin>0){ + if(b-a < 0) + b+=360; + } + else if(spin < 0){ + if(b-a > 0) + b-=360; + } + else return a; + + return tween(a, b, t); + } + + /** + * + */ + public float tweenAngle(float a, float b, float t){ + t = tweenSub(0f,1f,t); + switch(type){ + case Instant: return a; + case Linear: return linearAngle(a, b, t); + case Quadratic: return quadraticAngle(a, linearAngle(a, b, constraints.c1), b, t); + case Cubic: return cubicAngle(a, linearAngle(a, b, constraints.c1), linearAngle(a, b, constraints.c2), b, t); + case Quartic: return quarticAngle(a, linearAngle(a, b, constraints.c1), linearAngle(a, b, constraints.c2), linearAngle(a, b, constraints.c3), b, t); + case Quintic: return quinticAngle(a, linearAngle(a, b, constraints.c1), linearAngle(a, b, constraints.c2), linearAngle(a, b, constraints.c3), linearAngle(a, b, constraints.c4), b, t); + case Bezier: Float cubicSolution = solveCubic(3f*(constraints.c1-constraints.c3) + 1f, 3f*(constraints.c3-2f*constraints.c1), 3f*constraints.c1, -t); + if(cubicSolution == null) cubicSolution = lastCubicSolution; + else lastCubicSolution = cubicSolution; + return linearAngle(a, b, bezier(cubicSolution, 0f, constraints.c2, constraints.c4, 1f)); + default: return linearAngle(a, b, t); + } + } + + public String toString(){ + return getClass().getSimpleName()+"|["+type+":"+constraints+", subCurve: "+subCurve+"]"; + } + + /** + * Represents constraints for a curve. + * Constraints are important for curves which have a order higher than 1. + * @author Trixt0r + * + */ + public static class Constraints{ + public float c1, c2, c3, c4; + + public Constraints(float c1, float c2, float c3, float c4){ + this.set(c1, c2, c3, c4); + } + + public void set(float c1, float c2, float c3, float c4){ + this.c1 = c1; + this.c2 = c2; + this.c3 = c3; + this.c4 = c4; + } + + public String toString(){ + return getClass().getSimpleName()+"| [c1:"+c1+", c2:"+c2+", c3:"+c3+", c4:"+c4+"]"; + } + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Data.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Data.java new file mode 100644 index 00000000..ad6747ec --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Data.java @@ -0,0 +1,153 @@ +package com.brashmonkey.spriter; + + +import java.util.ArrayList; + +/** + * Represents all the data which necessary to animate a Spriter generated SCML file. + * An instance of this class holds {@link Folder}s and {@link Entity} instances. + * Specific {@link Folder} and {@link Entity} instances can be accessed via the corresponding methods, i.e. getEntity() and getFolder(). + * @author Trixt0r + * + */ +public class Data { + + final Folder[] folders; + final Entity[] entities; + private int folderPointer = 0, entityPointer = 0; + public final String scmlVersion, generator, generatorVersion; + + Data(String scmlVersion, String generator, String generatorVersion, int folders, int entities){ + this.scmlVersion = scmlVersion; + this.generator = generator; + this.generatorVersion = generatorVersion; + this.folders = new Folder[folders]; + this.entities = new Entity[entities]; + } + + /** + * Adds a folder to this data. + * @param folder the folder to add + */ + void addFolder(Folder folder){ + this.folders[folderPointer++] = folder; + } + + /** + * Adds an entity to this data. + * @param entity the entity to add + */ + void addEntity(Entity entity){ + this.entities[entityPointer++] = entity; + } + + /** + * Returns a {@link Folder} instance with the given name. + * @param name the name of the folder + * @return the folder with the given name or null if no folder with the given name exists + */ + public Folder getFolder(String name){ + int index = getFolderIndex(name); + if(index >= 0) return getFolder(index); + else return null; + } + + /** + * Returns a folder index with the given name. + * @param name name of the folder + * @return the folder index of the Folder with the given name or -1 if no folder with the given name exists + */ + int getFolderIndex(String name){ + for(Folder folder: this.folders) + if(folder.name.equals(name)) return folder.id; + return -1; + } + + /** + * Returns a {@link Folder} instance at the given index. + * @param index the index of the folder + * @return the {@link Folder} instance at the given index + */ + Folder getFolder(int index){ + return this.folders[index]; + } + + /** + * Returns an {@link Entity} instance with the given index. + * @param index index of the entity to return. + * @return the entity with the given index + */ + public Entity getEntity(int index){ + return this.entities[index]; + } + + /** + * Returns an {@link Entity} instance with the given name. + * @param name the name of the entity + * @return the entity with the given name or null if no entity with the given name exists + */ + public Entity getEntity(String name){ + int index = getEntityIndex(name); + if(index >= 0) return getEntity(index); + else return null; + } + + /** + * Returns an entity index with the given name. + * @param name name of the entity + * @return the entity index of the entity with the given name or -1 if no entity with the given name exists + */ + int getEntityIndex(String name){ + for(Entity entity: this.entities) + if(entity.name.equals(name)) return entity.id; + return -1; + } + + /** + * Returns a {@link File} instance in the given {@link Folder} instance at the given file index. + * @param folder {@link Folder} instance to search in. + * @param file index of the file + * @return the {@link File} instance in the given folder at the given file index + */ + public File getFile(Folder folder, int file){ + return folder.getFile(file); + } + + /** + * Returns a {@link File} instance in the given folder at the given file index. + * @param folder index of the folder + * @param file index of the file + * @return the {@link File} instance in the given folder at the given file index + */ + public File getFile(int folder, int file){ + return getFile(this.getFolder(folder), file); + } + + /** + * Returns a {@link File} instance for the given {@link FileReference} instance. + * @param ref reference to the file + * @return the {@link File} instance for the given reference + */ + public File getFile(FileReference ref){ + return this.getFile(ref.folder, ref.file); + } + + public String toString(){ + String toReturn = getClass().getSimpleName()+"|[Version: "+scmlVersion+", Generator: "+generator+" ("+generatorVersion+")]"; + for(Folder folder: folders) + toReturn += "\n"+folder; + for(Entity entity: entities) + toReturn += "\n"+entity; + toReturn+="]"; + return toReturn; + } + + public ArrayList getEntities(){ + ArrayList names = new ArrayList(this.entities.length); + for (int i = 0; i < entities.length; i++) { + names.add(entities[i].name); + } + return names; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Dimension.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Dimension.java new file mode 100644 index 00000000..f9a27d49 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Dimension.java @@ -0,0 +1,52 @@ +package com.brashmonkey.spriter; + +/** + * Represents a dimension in a 2D space. + * A dimension has a width and a height. + * @author Trixt0r + * + */ +public class Dimension { + + public float width, height; + + /** + * Creates a new dimension with the given size. + * @param width the width of the dimension + * @param height the height of the dimension + */ + public Dimension(float width, float height){ + this.set(width, height); + } + + /** + * Creates a new dimension with the given size. + * @param size the size + */ + public Dimension(Dimension size){ + this.set(size); + } + + /** + * Sets the size of this dimension to the given size. + * @param width the width of the dimension + * @param height the height of the dimension + */ + public void set(float width, float height){ + this.width = width; + this.height = height; + } + + /** + * Sets the size of this dimension to the given size. + * @param size the size + */ + public void set(Dimension size){ + this.set(size.width, size.height); + } + + public String toString(){ + return "["+width+"x"+height+"]"; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Drawer.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Drawer.java new file mode 100644 index 00000000..5c13242d --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Drawer.java @@ -0,0 +1,265 @@ +package com.brashmonkey.spriter; + +import java.util.Iterator; + +import com.brashmonkey.spriter.Entity.CharacterMap; +import com.brashmonkey.spriter.Entity.ObjectInfo; +import com.brashmonkey.spriter.Entity.ObjectType; +import com.brashmonkey.spriter.Timeline.Key.Bone; +import com.brashmonkey.spriter.Timeline.Key.Object; + +/** + * A Drawer is responsible for drawing a {@link Player}. + * Since this library is meant to be as generic as possible this class has to be abstract, because it cannot be assumed how to draw a resource. + * Anyone who wants to draw a {@link Player} has to know how to draw a resource. A resource can be e.g. a sprite, a texture or a texture region. + * To draw a {@link Player} call {@link #draw(Player)}. This method relies on {@link #draw(Object)}, which has to be implemented with the chosen backend. + * To debug draw a {@link Player} call {@link #drawBones(Player)}, {@link #drawBoxes(Player)} and {@link #drawPoints(Player)}, + * which rely on {@link #rectangle(float, float, float, float)}, {@link #circle(float, float, float)}, {@link #line(float, float, float, float)} and {@link #setColor(float, float, float, float)}. + * @author Trixt0r + * + * @param The backend specific resource. In general such a resource is called "sprite", "texture" or "image". + */ +public abstract class Drawer { + + /** + * The radius of a point for debug drawing purposes. + */ + public float pointRadius = 5f; + protected Loader loader; + + /** + * Creates a new drawer based on the given loader. + * @param loader the loader containing resources + */ + public Drawer(Loader loader){ + this.loader = loader; + } + + /** + * Sets the loader of this drawer. + * @param loader the loader containing resources + * @throws SpriterException if the loader is null + */ + public void setLoader(Loader loader){ + if(loader == null) throw new SpriterException("The loader instance can not be null!"); + this.loader = loader; + } + + /** + * Draws the bones of the given player composed of lines. + * @param player the player to draw + */ + public void drawBones(Player player){ + this.setColor(1, 0, 0, 1); + Iterator it = player.boneIterator(); + while(it.hasNext()){ + Timeline.Key.Bone bone = it.next(); + Timeline.Key key = player.getKeyFor(bone); + if(!key.active) continue; + ObjectInfo info = player.getObjectInfoFor(bone); + Dimension size = info.size; + drawBone(bone, size); + } + /*for(Mainline.Key.BoneRef ref: player.getCurrentKey().boneRefs){ + Timeline.Key key = player.unmappedTweenedKeys[ref.timeline]; + Timeline.Key.Bone bone = key.object(); + if(player.animation.getTimeline(ref.timeline).objectInfo.type != ObjectType.Bone || !key.active) continue; + ObjectInfo info = player.animation.getTimeline(ref.timeline).objectInfo; + if(info == null) continue; + Dimension size = info.size; + drawBone(bone, size); + }*/ + } + + /** + * Draws the given bone composed of lines with the given size. + * @param bone the bone to draw + * @param size the size of the bone + */ + public void drawBone(Bone bone, Dimension size){ + float halfHeight = size.height/2; + float xx = bone.position.x+(float)Math.cos(Math.toRadians(bone.angle))*size.height; + float yy = bone.position.y+(float)Math.sin(Math.toRadians(bone.angle))*size.height; + float x2 = (float)Math.cos(Math.toRadians(bone.angle+90))*halfHeight*bone.scale.y; + float y2 = (float)Math.sin(Math.toRadians(bone.angle+90))*halfHeight*bone.scale.y; + + float targetX = bone.position.x+(float)Math.cos(Math.toRadians(bone.angle))*size.width*bone.scale.x, + targetY = bone.position.y+(float)Math.sin(Math.toRadians(bone.angle))*size.width*bone.scale.x; + float upperPointX = xx+x2, upperPointY = yy+y2; + this.line(bone.position.x, bone.position.y, upperPointX, upperPointY); + this.line(upperPointX, upperPointY, targetX, targetY); + + float lowerPointX = xx-x2, lowerPointY = yy-y2; + this.line(bone.position.x, bone.position.y, lowerPointX, lowerPointY); + this.line(lowerPointX, lowerPointY, targetX, targetY); + this.line(bone.position.x, bone.position.y, targetX, targetY); + } + + /** + * Draws the boxes of the player. + * @param player the player to draw the boxes from + */ + public void drawBoxes(Player player){ + this.setColor(0f, 1f, 0f, 1f); + this.drawBoneBoxes(player); + this.drawObjectBoxes(player); + this.drawPoints(player); + } + + /** + * Draws the boxes of all bones of the given player. + * @param player the player to draw the bone boxes of + */ + public void drawBoneBoxes(Player player){ + drawBoneBoxes(player, player.boneIterator()); + } + + /** + * Draws the boxes of all bones of the given player based on the given iterator. + * @param player the player to draw the bone boxes of + * @param it the iterator iterating over the bones to draw + */ + public void drawBoneBoxes(Player player, Iterator it){ + while(it.hasNext()){ + Bone bone = it.next(); + this.drawBox(player.getBox(bone)); + } + } + + /** + * Draws the boxes of the player objects, i.e. sprites and objects. + * @param player the player to draw the object boxes of + */ + public void drawObjectBoxes(Player player){ + drawObjectBoxes(player, player.objectIterator()); + } + + /** + * Draws the boxes of sprites and boxes of the given player based on the given iterator. + * @param player player the player to draw the object boxes of + * @param it the iterator iterating over the object to draw + */ + public void drawObjectBoxes(Player player, Iterator it){ + while(it.hasNext()){ + Object bone = it.next(); + this.drawBox(player.getBox(bone)); + } + } + + /** + * Draws all points of the given player. + * @param player the player to draw the points of. + */ + public void drawPoints(Player player){ + drawPoints(player, player.objectIterator()); + } + + /** + * Draws the points of the given player based on the given iterator. + * @param player player the player to draw the points of + * @param it the iterator iterating over the points to draw + */ + public void drawPoints(Player player, Iterator it){ + while(it.hasNext()){ + Object point = it.next(); + if(player.getObjectInfoFor(point).type == ObjectType.Point){ + float x = point.position.x+(float)(Math.cos(Math.toRadians(point.angle))*pointRadius); + float y = point.position.y+(float)(Math.sin(Math.toRadians(point.angle))*pointRadius); + circle(point.position.x, point.position.y, pointRadius); + line(point.position.x, point.position.y, x,y); + } + } + } + + /** + * Draws the given player with its current character map. + * @param player the player to draw + */ + public void draw(Player player){ + this.draw(player, player.characterMaps); + } + + /** + * Draws the given player with the given character map. + * @param player the player to draw + * @param maps the character map to draw + */ + public void draw(Player player, CharacterMap[] maps){ + this.draw(player.objectIterator(), maps); + } + + /** + * Draws the objects the given iterator is providing with the given character map. + * @param it the iterator iterating over the objects to draw + * @param maps the character map to draw + */ + public void draw(Iterator it, CharacterMap[] maps){ + while(it.hasNext()){ + Timeline.Key.Object object = it.next(); + if(object.ref.hasFile()){ + if(maps != null){ + for(CharacterMap map: maps) + if(map != null) + object.ref.set(map.get(object.ref)); + } + this.draw(object); + } + } + } + + /** + * Draws the given box composed of lines. + * @param box the box to draw + */ + public void drawBox(Box box){ + this.line(box.points[0].x, box.points[0].y, box.points[1].x, box.points[1].y); + this.line(box.points[1].x, box.points[1].y, box.points[3].x, box.points[3].y); + this.line(box.points[3].x, box.points[3].y, box.points[2].x, box.points[2].y); + this.line(box.points[2].x, box.points[2].y, box.points[0].x, box.points[0].y); + } + + public void drawRectangle(Rectangle rect){ + this.rectangle(rect.left, rect.bottom, rect.size.width, rect.size.height); + } + + /** + * Sets the color for drawing lines, rectangles and circles. + * @param r the red value between 0.0 - 1.0 + * @param g the green value between 0.0 - 1.0 + * @param b the blue value between 0.0 - 1.0 + * @param a the alpha value between 0.0 - 1.0 + */ + public abstract void setColor(float r, float g, float b, float a); + + /** + * Draws a line from (x1, y1) to (x2, y2). + * @param x1 + * @param y1 + * @param x2 + * @param y2 + */ + public abstract void line(float x1, float y1, float x2, float y2); + + /** + * Draws a rectangle with origin at (x, y) and the given size. + * @param x the x coordinate + * @param y the y coordinate + * @param width the width of the size + * @param height the height of the size + */ + public abstract void rectangle(float x, float y, float width, float height); + + /** + * Draws a circle at (x, y) with the given radius. + * @param x the x coordinate + * @param y the y coordinate + * @param radius the radius of the circle + */ + public abstract void circle(float x, float y, float radius); + + /** + * Draws the given object with its current resource. + * @param object the object to draw. + */ + public abstract void draw(Timeline.Key.Object object); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Entity.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Entity.java new file mode 100644 index 00000000..a630ebbd --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Entity.java @@ -0,0 +1,241 @@ +package com.brashmonkey.spriter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Represents an entity of a Spriter SCML file. + * An entity holds {@link Animation}s, an {@link #id}, a {@link #name}. + * {@link #characterMaps} and {@link #objectInfos} may be empty. + * @author Trixt0r + * + */ +public class Entity { + + public final int id; + public final String name; + private final Animation[] animations; + private int animationPointer = 0; + private final HashMap namedAnimations; + private final CharacterMap[] characterMaps; + private int charMapPointer = 0; + private final ObjectInfo[] objectInfos; + private int objInfoPointer = 0; + + Entity(int id, String name, int animations, int characterMaps, int objectInfos){ + this.id = id; + this.name = name; + this.animations = new Animation[animations]; + this.characterMaps = new CharacterMap[characterMaps]; + this.objectInfos = new ObjectInfo[objectInfos]; + this.namedAnimations = new HashMap(); + } + + void addAnimation(Animation anim){ + this.animations[animationPointer++] = anim; + this.namedAnimations.put(anim.name, anim); + } + + /** + * Returns an {@link Animation} with the given index. + * @param index the index of the animation + * @return the animation with the given index + * @throws IndexOutOfBoundsException if the index is out of range + */ + public Animation getAnimation(int index){ + return this.animations[index]; + } + + /** + * Returns an {@link Animation} with the given name. + * @param name the name of the animation + * @return the animation with the given name or null if no animation exists with the given name + */ + public Animation getAnimation(String name){ + return this.namedAnimations.get(name); + } + + /** + * Returns the number of animations this entity holds. + * @return the number of animations + */ + public int animations(){ + return this.animations.length; + } + + /** + * Returns whether this entity contains the given animation. + * @param anim the animation to check + * @return true if the given animation is in this entity, false otherwise. + */ + public boolean containsAnimation(Animation anim){ + for(Animation a: this.animations) + if(a == anim) return true; + return false; + } + + /** + * Returns the animation with the most number of time lines in this entity. + * @return animation with the maximum amount of time lines. + */ + public Animation getAnimationWithMostTimelines(){ + Animation maxAnim = getAnimation(0); + for(Animation anim: this.animations){ + if(maxAnim.timelines() < anim.timelines()) maxAnim = anim; + } + return maxAnim; + } + + /** + * Returns a {@link CharacterMap} with the given name. + * @param name name of the character map + * @return the character map or null if no character map exists with the given name + */ + public CharacterMap getCharacterMap(String name){ + for(CharacterMap map: this.characterMaps) + if(map.name.equals(name)) return map; + return null; + } + + void addCharacterMap(CharacterMap map){ + this.characterMaps[charMapPointer++] = map; + } + + void addInfo(ObjectInfo info){ + this.objectInfos[objInfoPointer++] = info; + } + + /** + * Returns an {@link ObjectInfo} with the given index. + * @param index the index of the object info + * @return the object info + * @throws IndexOutOfBoundsException if index is out of range + */ + public ObjectInfo getInfo(int index){ + return this.objectInfos[index]; + } + + /** + * Returns an {@link ObjectInfo} with the given name. + * @param name name of the object info + * @return object info or null if no object info exists with the given name + */ + public ObjectInfo getInfo(String name){ + for(ObjectInfo info: this.objectInfos) + if(info.name.equals(name)) return info; + return null; + } + + /** + * Returns an {@link ObjectInfo} with the given name and the given {@link ObjectType} type. + * @param name the name of the object info + * @param type the type if the object info + * @return the object info or null if no object info exists with the given name and type + */ + public ObjectInfo getInfo(String name, ObjectType type){ + ObjectInfo info = this.getInfo(name); + if(info != null && info.type == type) return info; + else return null; + } + + /** + * Represents the object types Spriter supports. + * @author Trixt0r + * + */ + public static enum ObjectType{ + Sprite, Bone, Box, Point, Skin; + + /** + * Returns the object type for the given name + * @param name the name of the type + * @return the object type, Sprite is the default value + */ + public static ObjectType getObjectInfoFor(String name){ + if(name.equals("bone")) return Bone; + else if(name.equals("skin")) return Skin; + else if(name.equals("box")) return Box; + else if(name.equals("point")) return Point; + else return Sprite; + } + } + + /** + * Represents the object info in a Spriter SCML file. + * An object info holds a {@link #type} and a {@link #name}. + * If the type is a Sprite it holds a list of frames. Otherwise it has a {@link #size} for debug drawing purposes. + * @author Trixt0r + * + */ + public static class ObjectInfo{ + public final ObjectType type; + public final List frames; + public final String name; + public final Dimension size; + + ObjectInfo(String name, ObjectType type, Dimension size, List frames){ + this.type = type; + this.frames = frames; + this.name = name; + this.size = size; + } + + ObjectInfo(String name, ObjectType type, Dimension size){ + this(name, type, size, new ArrayList()); + } + + ObjectInfo(String name, ObjectType type, List frames){ + this(name, type, new Dimension(0,0), frames); + } + + public String toString(){ + return name + ": "+ type + ", size: "+size+"|frames:\n"+frames; + } + } + + /** + * Represents a Spriter SCML character map. + * A character map maps {@link FileReference}s to {@link FileReference}s. + * It holds an {@link CharacterMap#id} and a {@link CharacterMap#name}. + * @author Trixt0r + * + */ + public static class CharacterMap extends HashMap{ + private static final long serialVersionUID = 6062776450159802283L; + + public final int id; + public final String name; + + public CharacterMap(int id, String name){ + this.id = id; + this.name = name; + } + + /** + * Returns the mapped reference for the given key. + * @param key the key of the reference + * @return The mapped reference if the key is in this map, otherwise the given key itself is returned. + */ + public FileReference get(FileReference key){ + if(!super.containsKey(key)) return key; + else return super.get(key); + } + } + + public String toString(){ + String toReturn = getClass().getSimpleName()+"|[id: "+id+", name: "+name+"]"; + toReturn +="Object infos:\n"; + for(ObjectInfo info: this.objectInfos) + toReturn += "\n"+info; + toReturn +="Character maps:\n"; + for(CharacterMap map: this.characterMaps) + toReturn += "\n"+map; + toReturn +="Animations:\n"; + for(Animation animaton: this.animations) + toReturn += "\n"+animaton; + toReturn+="]"; + return toReturn; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/File.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/File.java new file mode 100644 index 00000000..0dabec2e --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/File.java @@ -0,0 +1,36 @@ +package com.brashmonkey.spriter; + +/** + * Represents a file in a Spriter SCML file. + * A file has an {@link #id}, a {@link #name}. + * A {@link #size} and a {@link #pivot} point, i.e. origin of an image do not have to be set since a file can be a sound file. + * @author Trixt0r + * + */ +public class File { + + public final int id; + public final String name; + public final Dimension size; + public final Point pivot; + + File(int id, String name, Dimension size, Point pivot){ + this.id = id; + this.name = name; + this.size = size; + this.pivot = pivot; + } + + /** + * Returns whether this file is a sprite, i.e. an image which is going to be animated, or not. + * @return whether this file is a sprite or not. + */ + public boolean isSprite(){ + return pivot != null && size != null; + } + + public String toString(){ + return getClass().getSimpleName()+"|[id: "+id+", name: "+name+", size: "+size+", pivot: "+pivot; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/FileReference.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/FileReference.java new file mode 100644 index 00000000..2015d8dc --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/FileReference.java @@ -0,0 +1,50 @@ +package com.brashmonkey.spriter; + +/** + * Represents a reference to a specific file. + * A file reference consists of a folder and file index. + * @author Trixt0r + * + */ +public class FileReference { + + public int folder, file; + + public FileReference(int folder, int file){ + this.set(folder, file); + } + + @Override + public int hashCode(){ + return folder*10000+file;//We can have 10000 files per folder + } + + @Override + public boolean equals(Object ref){ + if(ref instanceof FileReference){ + return this.file == ((FileReference)ref).file && this.folder == ((FileReference)ref).folder; + } else return false; + } + + public void set(int folder, int file){ + this.folder = folder; + this.file = file; + } + + public void set(FileReference ref){ + this.set(ref.folder, ref.file); + } + + public boolean hasFile(){ + return this.file != -1; + } + + public boolean hasFolder(){ + return this.folder != -1; + } + + public String toString(){ + return "[folder: "+folder+", file: "+file+"]"; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Folder.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Folder.java new file mode 100644 index 00000000..32257207 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Folder.java @@ -0,0 +1,70 @@ +package com.brashmonkey.spriter; + +/** + * Represents a folder in a Spriter SCML file. + * A folder has at least an {@link #id}, {@link #name} and {@link #files} may be empty. + * An instance of this class holds an array of {@link File} instances. + * Specific {@link File} instances can be accessed via the corresponding methods, i.e getFile(). + * @author Trixt0r + * + */ +public class Folder { + + final File[] files; + private int filePointer = 0; + public final int id; + public final String name; + + Folder(int id, String name, int files){ + this.id = id; + this.name = name; + this.files = new File[files]; + } + + /** + * Adds a {@link File} instance to this folder. + * @param file the file to add + */ + void addFile(File file){ + this.files[filePointer++] = file; + } + + /** + * Returns a {@link File} instance with the given index. + * @param index the index of the file + * @return the file with the given name + */ + public File getFile(int index){ + return files[index]; + } + + /** + * Returns a {@link File} instance with the given name. + * @param name the name of the file + * @return the file with the given name or null if no file with the given name exists + */ + public File getFile(String name){ + int index = getFileIndex(name); + if(index >= 0) return getFile(index); + else return null; + } + + /** + * Returns a file index with the given name. + * @param name the name of the file + * @return the file index with the given name or -1 if no file with the given name exists + */ + int getFileIndex(String name){ + for(File file: this.files) + if(file.name.equals(name)) return file.id; + return -1; + } + + public String toString(){ + String toReturn = getClass().getSimpleName()+"|[id: "+id+", name: "+name; + for(File file: files) + toReturn += "\n"+file; + toReturn += "]"; + return toReturn; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/IKObject.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/IKObject.java new file mode 100644 index 00000000..8d908032 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/IKObject.java @@ -0,0 +1,68 @@ +package com.brashmonkey.spriter; + +/** + * An inverse kinematics objects which defines a constraint for a {@link IKResolver}. + * + * @author Trixt0r + * + */ +public class IKObject extends Point { + + int chainLength, iterations; + + /** + * Creates a new IKObject with the given constraints. + * @param x x coordinate constraint + * @param y y coordinate constraint + * @param length the chain length constraint. + * @param iterations the number of iterations. + */ + public IKObject(float x, float y, int length, int iterations) { + super(x, y); + this.setLength(length); + this.setIterations(iterations); + } + + /** + * Sets the chain length of this ik object. + * The chain length indicates how many parent bones should get affected, when a {@link IKResolver} resolves the constraints. + * @param chainLength the chain length + * @return this ik object for chained operations + * @throws SpriterException if the chain length is smaller than 0 + */ + public IKObject setLength(int chainLength){ + if(chainLength < 0) throw new SpriterException("The chain has to be at least 0!"); + this.chainLength = chainLength; + return this; + } + + /** + * Sets the number of iterations. + * The more iterations a {@link IKResolver} is asked to do, the more precise the result will be. + * @param iterations number of iterations + * @return this ik object for chained operations + * @throws SpriterException if the number of iterations is smaller than 0 + */ + public IKObject setIterations(int iterations){ + if(iterations < 0) throw new SpriterException("The number of iterations has to be at least 1!"); + this.iterations = iterations; + return this; + } + + /** + * Returns the current set chain length. + * @return the chain length + */ + public int getChainLength(){ + return this.chainLength; + } + + /** + * Returns the current set number of iterations. + * @return the number of iterations + */ + public int getIterations(){ + return this.iterations; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/IKResolver.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/IKResolver.java new file mode 100644 index 00000000..17789319 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/IKResolver.java @@ -0,0 +1,113 @@ +package com.brashmonkey.spriter; + +import java.util.HashMap; +import java.util.Map.Entry; + +import com.brashmonkey.spriter.Mainline.Key.BoneRef; +import com.brashmonkey.spriter.Timeline.Key.Bone; + +/** + * A IKResolver is responsible for resolving previously set constraints. + * @see Inverse kinematics + * @author Trixt0r + * + */ +public abstract class IKResolver { + + /** + * Resolves the inverse kinematics constraint with a specific algtorithm + * @param x the target x value + * @param y the target y value + * @param chainLength number of parents which are affected + * @param effector the actual effector where the resolved information has to be stored in. + */ + protected abstract void resolve(float x, float y, int chainLength, BoneRef effector); + + protected HashMap ikMap; + protected float tolerance; + protected Player player; + + /** + * Creates a resolver with a default tolerance of 5f. + */ + public IKResolver(Player player) { + this.tolerance = 5f; + this.ikMap = new HashMap(); + this.setPlayer(player); + } + + /** + * Sets the player for this resolver. + * @param player the player which gets affected. + * @throws SpriterException if player is null + */ + public void setPlayer(Player player){ + if(player == null) throw new SpriterException("player cannot be null!"); + this.player = player; + } + + /** + * Returns the current set player. + * @return the current player. + */ + public Player getPlayer(){ + return this.player; + } + + /** + * Resolves the inverse kinematics constraints with the implemented algorithm + * + */ + public void resolve(){ + for(Entry entry: this.ikMap.entrySet()){ + for(int j = 0; j < entry.getKey().iterations; j++) + this.resolve(entry.getKey().x, entry.getKey().y, entry.getKey().chainLength, entry.getValue()); + } + } + + /** + * Adds the given object to the internal IKObject - Bone map. + * This means, the values of the given ik object affect the mapped bone. + * @param ikObject the ik object + * @param boneRef the bone reference which gets affected + */ + public void mapIKObject(IKObject ikObject, BoneRef boneRef){ + this.ikMap.put(ikObject, boneRef); + } + + /** + * Adds the given object to the internal IKObject - Bone map. + * This means, the values of the given ik object affect the mapped bone. + * @param ikObject the ik object + * @param bone the bone which gets affected + */ + public void mapIKObject(IKObject ikObject, Bone bone){ + this.ikMap.put(ikObject, player.getBoneRef(bone)); + } + + /** + * Removes the given object from the internal map. + * @param ikObject the ik object to remove + */ + public void unmapIKObject(IKObject ikObject){ + this.ikMap.remove(ikObject); + } + + /** + * Returns the tolerance of this resolver. + * @return the tolerance + */ + public float getTolerance() { + return tolerance; + } + + /** + * Sets the tolerance distance of this resolver. + * The resolver should stop the algorithm if the distance to the set ik object is less than the tolerance. + * @param tolerance the tolerance + */ + public void setTolerance(float tolerance) { + this.tolerance = tolerance; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Interpolator.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Interpolator.java new file mode 100644 index 00000000..6fdc6544 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Interpolator.java @@ -0,0 +1,75 @@ +package com.brashmonkey.spriter; + + + +/** + * Utility class for various interpolation techniques, Spriter is using. + * @author Trixt0r + * + */ +public class Interpolator { + + public static float linear(float a, float b, float t){ + return a+(b-a)*t; + } + + public static float linearAngle(float a, float b, float t){ + return a + Calculator.angleDifference(b, a)*t; + } + + public static float quadratic(float a, float b, float c, float t){ + return linear(linear(a, b, t), linear(b, c, t), t); + } + + public static float quadraticAngle(float a, float b, float c, float t){ + return linearAngle(linearAngle(a, b, t), linearAngle(b, c, t), t); + } + + public static float cubic(float a, float b, float c, float d, float t){ + return linear(quadratic(a, b, c, t), quadratic(b, c, d, t), t); + } + + public static float cubicAngle(float a, float b, float c, float d, float t){ + return linearAngle(quadraticAngle(a, b, c, t), quadraticAngle(b, c, d, t), t); + } + + public static float quartic(float a, float b, float c, float d, float e, float t){ + return linear(cubic(a, b, c, d, t), cubic(b, c, d, e, t), t); + } + + public static float quarticAngle(float a, float b, float c, float d, float e, float t){ + return linearAngle(cubicAngle(a, b, c, d, t), cubicAngle(b, c, d, e, t), t); + } + + public static float quintic(float a, float b, float c, float d, float e, float f, float t){ + return linear(quartic(a, b, c, d, e, t), quartic(b, c, d, e, f, t), t); + } + + public static float quinticAngle(float a, float b, float c, float d, float e, float f, float t){ + return linearAngle(quarticAngle(a, b, c, d, e, t), quarticAngle(b, c, d, e, f, t), t); + } + + public static float bezier(float t, float x1, float x2, float x3,float x4){ + return bezier0(t)*x1 + bezier1(t)*x2 + bezier2(t)*x3 + bezier3(t)*x4; + } + + private static float bezier0(float t){ + float temp = t*t; + return -temp*t + 3*temp - 3*t + 1; + } + + private static float bezier1(float t){ + float temp = t*t; + return 3*t*temp - 6*temp + 3*t; + } + + private static float bezier2(float t){ + float temp = t*t; + return -3*temp*t+3*temp; + } + + private static float bezier3(float t){ + return t*t*t; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Loader.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Loader.java new file mode 100644 index 00000000..5ad59635 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Loader.java @@ -0,0 +1,117 @@ +package com.brashmonkey.spriter; + +import java.util.HashMap; + +/** + * A loader is responsible for loading all resources. + * Since this library is meant to be as generic as possible, it cannot be assumed how to load a resource. Because of this this class has to be abstract. + * This class takes care of loading all resources a {@link Data} instance contains. + * To load all resources an instance relies on {@link #loadResource(FileReference)} which has to implemented with the backend specific methods. + * + * @author Trixt0r + * + * @param The backend specific resource. In general such a resource is called "sprite", "texture" or "image". + */ +public abstract class Loader { + + /** + * Contains all loaded resources if not {@link #isDisposed()}. + */ + protected final HashMap resources; + + /** + * The current set data containing {@link Folder}s and {@link File}s. + */ + protected Data data; + + /** + * The root path to the previous loaded Spriter SCML file. + */ + protected String root = ""; + + private boolean disposed; + + /** + * Creates a loader with the given Spriter data. + * @param data the generated Spriter data + */ + public Loader(Data data){ + this.data = data; + this.resources = new HashMap(100); + } + + /** + * Loads a resource. + * The path to the file can be resolved with {@link #root} and {@link #data}. + * I recommend using {@link Data#getFile(FileReference)}. Then the path to the resource is {@link File#name} relative to {@link #root}. + * @param ref the reference to load + * @return the loaded resource + */ + protected abstract R loadResource(FileReference ref); + + /** + * Called when all resources from {@link #data} have been loaded. + */ + protected void finishLoading(){} + + /** + * Called before all resources get loaded. + */ + protected void beginLoading(){} + + /** + * Loads all resources indicated by {@link #data}. + * @param root the root folder of the previously loaded Spriter SCML file + */ + public void load(String root){ + this.root = root; + this.beginLoading(); + for(Folder folder: data.folders){ + for(File file: folder.files){ + //if(new java.io.File(root+"/"+file.name).exists()){ + FileReference ref = new FileReference(folder.id, file.id); + this.resources.put(ref, this.loadResource(ref)); + //} + } + } + this.disposed = false; + this.finishLoading(); + } + + /** + * Loads all resources indicated by {@link #data}. + * @param file the previously loaded Spriter SCML file + */ + public void load(java.io.File file){ + this.load(file.getParent()); + } + + /** + * Returns a resource the given reference is pointing to. + * @param ref the reference pointing to a resource + * @return the resource or null if the resource is not loaded yet. + */ + public R get(FileReference ref){ + return this.resources.get(ref); + } + + /** + * Removes all loaded resources from the internal reference-resource map. + * Override this method and dispose all your resources. After that call {@link #dispose()} of the super class. + */ + public void dispose(){ + resources.clear(); + data = null; + root = ""; + disposed = true; + } + + /** + * Returns whether this loader has been disposed or not. + * @return true if this loader is disposed + */ + public boolean isDisposed(){ + return disposed; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Mainline.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Mainline.java new file mode 100644 index 00000000..949b6c5e --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Mainline.java @@ -0,0 +1,216 @@ +package com.brashmonkey.spriter; + +/** + * Represents a mainline in a Spriter SCML file. + * A mainline holds only keys and occurs only once in an animation. + * The mainline is responsible for telling which draw order the sprites have + * and how the objects are related to each other, i.e. which bone is the root and which objects are the children. + * @author Trixt0r + * + */ +public class Mainline { + + final Key[] keys; + private int keyPointer = 0; + + public Mainline(int keys){ + this.keys = new Key[keys]; + } + + public String toString(){ + String toReturn = getClass().getSimpleName()+"|"; + for(Key key: keys) + toReturn += "\n"+key; + toReturn+="]"; + return toReturn; + } + + public void addKey(Key key){ + this.keys[keyPointer++] = key; + } + + /** + * Returns a {@link Key} at the given index. + * @param index the index of the key + * @return the key with the given index + * @throws IndexOutOfBoundsException if index is out of range + */ + public Key getKey(int index){ + return this.keys[index]; + } + + /** + * Returns a {@link Key} before the given time. + * @param time the time a key has to be before + * @return a key which has a time value before the given one. + * The first key is returned if no key was found. + */ + public Key getKeyBeforeTime(int time){ + Key found = this.keys[0]; + for(Key key: this.keys){ + if(key.time <= time) found = key; + else break; + } + return found; + } + + /** + * Represents a mainline key in a Spriter SCML file. + * A mainline key holds an {@link #id}, a {@link #time}, a {@link #curve} + * and lists of bone and object references which build a tree hierarchy. + * @author Trixt0r + * + */ + public static class Key{ + + public final int id, time; + final BoneRef[] boneRefs; + final ObjectRef[] objectRefs; + private int bonePointer = 0, objectPointer = 0; + public final Curve curve; + + public Key(int id, int time, Curve curve, int boneRefs, int objectRefs){ + this.id = id; + this.time = time; + this.curve = curve; + this.boneRefs = new BoneRef[boneRefs]; + this.objectRefs = new ObjectRef[objectRefs]; + } + + /** + * Adds a bone reference to this key. + * @param ref the reference to add + */ + public void addBoneRef(BoneRef ref){ + this.boneRefs[bonePointer++] = ref; + } + + /** + * Adds a object reference to this key. + * @param ref the reference to add + */ + public void addObjectRef(ObjectRef ref){ + this.objectRefs[objectPointer++] = ref; + } + + /** + * Returns a {@link BoneRef} with the given index. + * @param index the index of the bone reference + * @return the bone reference or null if no reference exists with the given index + */ + public BoneRef getBoneRef(int index){ + if(index < 0 || index >= this.boneRefs.length) return null; + else return this.boneRefs[index]; + } + + /** + * Returns a {@link ObjectRef} with the given index. + * @param index the index of the object reference + * @return the object reference or null if no reference exists with the given index + */ + public ObjectRef getObjectRef(int index){ + if(index < 0 || index >= this.objectRefs.length) return null; + else return this.objectRefs[index]; + } + + /** + * Returns a {@link BoneRef} for the given reference. + * @param ref the reference to the reference in this key + * @return a bone reference with the same time line as the given one + */ + public BoneRef getBoneRef(BoneRef ref){ + return getBoneRefTimeline(ref.timeline); + } + + /** + * Returns a {@link BoneRef} with the given time line index. + * @param timeline the time line index + * @return the bone reference with the given time line index or null if no reference exists with the given time line index + */ + public BoneRef getBoneRefTimeline(int timeline){ + for(BoneRef boneRef: this.boneRefs) + if(boneRef.timeline == timeline) return boneRef; + return null; + } + + /** + * Returns an {@link ObjectRef} for the given reference. + * @param ref the reference to the reference in this key + * @return an object reference with the same time line as the given one + */ + public ObjectRef getObjectRef(ObjectRef ref){ + return getObjectRefTimeline(ref.timeline); + } + + /** + * Returns a {@link ObjectRef} with the given time line index. + * @param timeline the time line index + * @return the object reference with the given time line index or null if no reference exists with the given time line index + */ + public ObjectRef getObjectRefTimeline(int timeline){ + for(ObjectRef objRef: this.objectRefs) + if(objRef.timeline == timeline) return objRef; + return null; + } + + public String toString(){ + String toReturn = getClass().getSimpleName()+"|[id:"+id+", time: "+time+", curve: ["+curve+"]"; + for(BoneRef ref: boneRefs) + toReturn += "\n"+ref; + for(ObjectRef ref: objectRefs) + toReturn += "\n"+ref; + toReturn+="]"; + return toReturn; + } + + /** + * Represents a bone reference in a Spriter SCML file. + * A bone reference holds an {@link #id}, a {@link #timeline} and a {@link #key}. + * A bone reference may have a parent reference. + * @author Trixt0r + * + */ + public static class BoneRef{ + public final int id, key, timeline; + public final BoneRef parent; + + public BoneRef(int id, int timeline, int key, BoneRef parent){ + this.id = id; + this.timeline = timeline; + this.key = key; + this.parent = parent; + } + + public String toString(){ + int parentId = (parent != null) ? parent.id:-1; + return getClass().getSimpleName()+"|id: "+id+", parent:"+parentId+", timeline: "+timeline+", key: "+key; + } + } + + /** + * Represents an object reference in a Spriter SCML file. + * An object reference extends a {@link BoneRef} with a {@link #zIndex}, + * which indicates when the object has to be drawn. + * @author Trixt0r + * + */ + public static class ObjectRef extends BoneRef implements Comparable{ + public final int zIndex; + + public ObjectRef(int id, int timeline, int key, BoneRef parent, int zIndex){ + super(id, timeline, key, parent); + this.zIndex = zIndex; + } + + public String toString(){ + return super.toString()+", z_index: "+zIndex; + } + + @Override + public int compareTo(ObjectRef o) { + return (int)Math.signum(zIndex-o.zIndex); + } + } + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Player.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Player.java new file mode 100644 index 00000000..1309b2d4 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Player.java @@ -0,0 +1,1132 @@ +package com.brashmonkey.spriter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import com.brashmonkey.spriter.Entity.CharacterMap; +import com.brashmonkey.spriter.Entity.ObjectInfo; +import com.brashmonkey.spriter.Mainline.Key.BoneRef; +import com.brashmonkey.spriter.Mainline.Key.ObjectRef; +import com.brashmonkey.spriter.Timeline.Key.Bone; +import com.brashmonkey.spriter.Timeline.Key.Object; + +/** + * A Player instance is responsible for updating an {@link Animation} properly. + * With the {@link #update()} method an instance of this class will increase its current time + * and update the current set animation ({@link #setAnimation(Animation)}). + * A Player can be positioned with {@link #setPivot(float, float)}, scaled with {@link #setScale(float)}, + * flipped with {@link #flip(boolean, boolean)} and rotated {@link #setAngle(float)}. + * A Player has various methods for runtime object manipulation such as {@link #setBone(String, Bone)} or . + * Events like the ending of an animation can be observed with the {@link PlayerListener} interface. + * Character maps can be changed on the fly, just by assigning a character maps to {@link #characterMaps}, setting it to null will remove the current character map. + * + * @author Trixt0r + * + */ +public class Player { + + protected Entity entity; + Animation animation; + int time; + public int speed; + Timeline.Key[] tweenedKeys, unmappedTweenedKeys; + private Timeline.Key[] tempTweenedKeys, tempUnmappedTweenedKeys; + private List listeners; + public final List attachments = new ArrayList(); + Timeline.Key.Bone root = new Timeline.Key.Bone(new Point(0,0)); + private final Point position = new Point(0,0), pivot = new Point(0,0); + private final HashMap objToTimeline = new HashMap(); + private float angle; + private boolean dirty = true; + public CharacterMap[] characterMaps; + private Rectangle rect; + public final Box prevBBox; + private BoneIterator boneIterator; + private ObjectIterator objectIterator; + private Mainline.Key currentKey, prevKey; + public boolean copyObjects = true; + + /** + * Creates a {@link Player} instance with the given entity. + * @param entity the entity this player will animate + */ + public Player(Entity entity){ + this.boneIterator = new BoneIterator(); + this.objectIterator = new ObjectIterator(); + this.speed = 15; + this.rect = new Rectangle(0,0,0,0); + this.prevBBox = new Box(); + this.listeners = new ArrayList(); + this.setEntity(entity); + } + + /** + * Updates this player. + * This means the current time gets increased by {@link #speed} and is applied to the current animation. + */ + public void update(){ + for(PlayerListener listener: listeners) + listener.preProcess(this); + if(dirty) this.updateRoot(); + this.animation.update(time, root); + this.currentKey = this.animation.currentKey; + if(prevKey != currentKey){ + for(PlayerListener listener: listeners) + listener.mainlineKeyChanged(prevKey, currentKey); + prevKey = currentKey; + } + if(copyObjects){ + tweenedKeys = tempTweenedKeys; + unmappedTweenedKeys = tempUnmappedTweenedKeys; + this.copyObjects(); + } + else{ + tweenedKeys = animation.tweenedKeys; + unmappedTweenedKeys = animation.unmappedTweenedKeys; + } + + for(Attachment attach: attachments) + attach.update(); + + for(PlayerListener listener: listeners) + listener.postProcess(this); + this.increaseTime(); + } + + private void copyObjects(){ + for(int i = 0; i < animation.tweenedKeys.length; i++){ + this.tweenedKeys[i].active = animation.tweenedKeys[i].active; + this.unmappedTweenedKeys[i].active = animation.unmappedTweenedKeys[i].active; + this.tweenedKeys[i].object().set(animation.tweenedKeys[i].object()); + this.unmappedTweenedKeys[i].object().set(animation.unmappedTweenedKeys[i].object()); + } + } + + private void increaseTime(){ + time += speed; + if(time > animation.length){ + time = time-animation.length; + for(PlayerListener listener: listeners) + listener.animationFinished(animation); + } + if(time < 0){ + for(PlayerListener listener: listeners) + listener.animationFinished(animation); + time += animation.length; + } + } + + private void updateRoot(){ + this.root.angle = angle; + this.root.position.set(pivot); + this.root.position.rotate(angle); + this.root.position.translate(position); + dirty = false; + } + + /** + * Returns a time line bone at the given index. + * @param index the index of the bone + * @return the bone with the given index. + */ + public Bone getBone(int index){ + return this.unmappedTweenedKeys[getCurrentKey().getBoneRef(index).timeline].object(); + } + + /** + * Returns a time line object at the given index. + * @param index the index of the object + * @return the object with the given index. + */ + public Object getObject(int index){ + return (Object) this.unmappedTweenedKeys[getCurrentKey().getObjectRef(index).timeline].object(); + } + + /** + * Returns the index of a time line bone with the given name. + * @param name the name of the bone + * @return the index of the bone or -1 if no bone exists with the given name + */ + public int getBoneIndex(String name){ + for(BoneRef ref: getCurrentKey().boneRefs) + if(animation.getTimeline(ref.timeline).name.equals(name)) + return ref.id; + return -1; + } + + /** + * Returns a time line bone with the given name. + * @param name the name of the bone + * @return the bone with the given name + * @throws ArrayIndexOutOfBoundsException if no bone exists with the given name + * @throws NullPointerException if no bone exists with the given name + */ + public Bone getBone(String name){ + return this.unmappedTweenedKeys[animation.getTimeline(name).id].object(); + } + + /** + * Returns a bone reference for the given time line bone. + * @param bone the time line bone + * @return the bone reference for the given bone + * @throws NullPointerException if no reference for the given bone was found + */ + public BoneRef getBoneRef(Bone bone){ + return this.getCurrentKey().getBoneRefTimeline(this.objToTimeline.get(bone).id); + } + + /** + * Returns the index of a time line object with the given name. + * @param name the name of the object + * @return the index of the object or -1 if no object exists with the given name + */ + public int getObjectIndex(String name){ + for(ObjectRef ref: getCurrentKey().objectRefs) + if(animation.getTimeline(ref.timeline).name.equals(name)) + return ref.id; + return -1; + } + + /** + * Returns a time line object with the given name. + * @param name the name of the object + * @return the object with the given name + * @throws ArrayIndexOutOfBoundsException if no object exists with the given name + * @throws NullPointerException if no object exists with the given name + */ + public Object getObject(String name){ + return (Object)this.unmappedTweenedKeys[animation.getTimeline(name).id].object(); + } + + /** + * Returns a object reference for the given time line bone. + * @param object the time line object + * @return the object reference for the given bone + * @throws NullPointerException if no reference for the given object was found + */ + public ObjectRef getObjectRef(Object object){ + return this.getCurrentKey().getObjectRefTimeline(this.objToTimeline.get(object).id); + } + + /** + * Returns the name for the given bone or object. + * @param boneOrObject the bone or object + * @return the name of the bone or object + * @throws NullPointerException if no name for the given bone or bject was found + */ + public String getNameFor(Bone boneOrObject){ + return this.animation.getTimeline(objToTimeline.get(boneOrObject).id).name; + } + + /** + * Returns the object info for the given bone or object. + * @param boneOrObject the bone or object + * @return the object info of the bone or object + * @throws NullPointerException if no object info for the given bone or bject was found + */ + public ObjectInfo getObjectInfoFor(Bone boneOrObject){ + return this.animation.getTimeline(objToTimeline.get(boneOrObject).id).objectInfo; + } + + /** + * Returns the time line key for the given bone or object + * @param boneOrObject the bone or object + * @return the time line key of the bone or object, or null if no time line key was found + */ + public Timeline.Key getKeyFor(Bone boneOrObject){ + return objToTimeline.get(boneOrObject); + } + + /** + * Calculates and returns a {@link Box} for the given bone or object. + * @param boneOrObject the bone or object to calculate the bounding box for + * @return the box for the given bone or object + * @throws NullPointerException if no object info for the given bone or object exists + */ + public Box getBox(Bone boneOrObject){ + ObjectInfo info = getObjectInfoFor(boneOrObject); + this.prevBBox.calcFor(boneOrObject, info); + return this.prevBBox; + } + + /** + * Returns whether the given point at x,y lies inside the box of the given bone or object. + * @param boneOrObject the bone or object + * @param x the x value of the point + * @param y the y value of the point + * @return true if x,y lies inside the box of the given bone or object + * @throws NullPointerException if no object info for the given bone or object exists + */ + public boolean collidesFor(Bone boneOrObject, float x, float y){ + ObjectInfo info = getObjectInfoFor(boneOrObject); + this.prevBBox.calcFor(boneOrObject, info); + return this.prevBBox.collides(boneOrObject, info, x, y); + } + + /** + * Returns whether the given point lies inside the box of the given bone or object. + * @param boneOrObject the bone or object + * @param point the point + * @return true if the point lies inside the box of the given bone or object + * @throws NullPointerException if no object info for the given bone or object exists + */ + public boolean collidesFor(Bone boneOrObject, Point point){ + return this.collidesFor(boneOrObject, point.x, point.y); + } + + /** + * Returns whether the given area collides with the box of the given bone or object. + * @param boneOrObject the bone or object + * @param area the rectangular area + * @return true if the area collides with the bone or object + */ + public boolean collidesFor(Bone boneOrObject, Rectangle area){ + ObjectInfo info = getObjectInfoFor(boneOrObject); + this.prevBBox.calcFor(boneOrObject, info); + return this.prevBBox.isInside(area); + } + + /** + * Sets the given values of the bone with the given name. + * @param name the name of the bone + * @param x the new x value of the bone + * @param y the new y value of the bone + * @param angle the new angle of the bone + * @param scaleX the new scale in x direction of the bone + * @param scaleY the new scale in y direction of the bone + * @throws SpriterException if no bone exists of the given name + */ + public void setBone(String name, float x, float y, float angle, float scaleX, float scaleY){ + int index = getBoneIndex(name); + if(index == -1) throw new SpriterException("No bone found of name \""+name+"\""); + BoneRef ref = getCurrentKey().getBoneRef(index); + Bone bone = getBone(index); + bone.set(x, y, angle, scaleX, scaleY, 0f, 0f); + unmapObjects(ref); + } + + /** + * Sets the given values of the bone with the given name. + * @param name the name of the bone + * @param position the new position of the bone + * @param angle the new angle of the bone + * @param scale the new scale of the bone + * @throws SpriterException if no bone exists of the given name + */ + public void setBone(String name, Point position, float angle, Point scale){ + this.setBone(name, position.x, position.y, angle, scale.x, scale.y); + } + + /** + * Sets the given values of the bone with the given name. + * @param name the name of the bone + * @param x the new x value of the bone + * @param y the new y value of the bone + * @param angle the new angle of the bone + * @throws SpriterException if no bone exists of the given name + */ + public void setBone(String name, float x, float y, float angle){ + Bone b = getBone(name); + setBone(name, x, y, angle, b.scale.x, b.scale.y); + } + + /** + * Sets the given values of the bone with the given name. + * @param name the name of the bone + * @param position the new position of the bone + * @param angle the new angle of the bone + * @throws SpriterException if no bone exists of the given name + */ + public void setBone(String name, Point position, float angle){ + Bone b = getBone(name); + setBone(name, position.x, position.y, angle, b.scale.x, b.scale.y); + } + + /** + * Sets the position of the bone with the given name. + * @param name the name of the bone + * @param x the new x value of the bone + * @param y the new y value of the bone + * @throws SpriterException if no bone exists of the given name + */ + public void setBone(String name, float x, float y){ + Bone b = getBone(name); + setBone(name, x, y, b.angle); + } + + /** + * Sets the position of the bone with the given name. + * @param name the name of the bone + * @param position the new position of the bone + * @throws SpriterException if no bone exists of the given name + */ + public void setBone(String name, Point position){ + setBone(name, position.x, position.y); + } + + /** + * Sets the angle of the bone with the given name + * @param name the name of the bone + * @param angle the new angle of the bone + * @throws SpriterException if no bone exists of the given name + */ + public void setBone(String name, float angle){ + Bone b = getBone(name); + setBone(name, b.position.x, b.position.y, angle); + } + + /** + * Sets the values of the bone with the given name to the values of the given bone + * @param name the name of the bone + * @param bone the bone with the new values + * @throws SpriterException if no bone exists of the given name + */ + public void setBone(String name, Bone bone){ + setBone(name, bone.position, bone.angle, bone.scale); + } + + /** + * Sets the given values of the object with the given name. + * @param name the name of the object + * @param x the new position in x direction of the object + * @param y the new position in y direction of the object + * @param angle the new angle of the object + * @param scaleX the new scale in x direction of the object + * @param scaleY the new scale in y direction of the object + * @param pivotX the new pivot in x direction of the object + * @param pivotY the new pivot in y direction of the object + * @param alpha the new alpha value of the object + * @param folder the new folder index of the object + * @param file the new file index of the object + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, float x, float y, float angle, float scaleX, float scaleY, float pivotX, float pivotY, float alpha, int folder, int file){ + int index = getObjectIndex(name); + if(index == -1) throw new SpriterException("No object found for name \""+name+"\""); + ObjectRef ref = getCurrentKey().getObjectRef(index); + Object object = getObject(index); + object.set(x, y, angle, scaleX, scaleY, pivotX, pivotY, alpha, folder, file); + unmapObjects(ref); + } + + /** + * Sets the given values of the object with the given name. + * @param name the name of the object + * @param position the new position of the object + * @param angle the new angle of the object + * @param scale the new scale of the object + * @param pivot the new pivot of the object + * @param alpha the new alpha value of the object + * @param ref the new file reference of the object + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, Point position, float angle, Point scale, Point pivot, float alpha, FileReference ref){ + this.setObject(name, position.x, position.y, angle, scale.x, scale.y, pivot.x, pivot.y, alpha, ref.folder, ref.file); + } + + /** + * Sets the given values of the object with the given name. + * @param name the name of the object + * @param x the new position in x direction of the object + * @param y the new position in y direction of the object + * @param angle the new angle of the object + * @param scaleX the new scale in x direction of the object + * @param scaleY the new scale in y direction of the object + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, float x, float y, float angle, float scaleX, float scaleY){ + Object b = getObject(name); + setObject(name, x, y, angle, scaleX, scaleY, b.pivot.x, b.pivot.y, b.alpha, b.ref.folder, b.ref.file); + } + + /** + * Sets the given values of the object with the given name. + * @param name the name of the object + * @param x the new position in x direction of the object + * @param y the new position in y direction of the object + * @param angle the new angle of the object + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, float x, float y, float angle){ + Object b = getObject(name); + setObject(name, x, y, angle, b.scale.x, b.scale.y); + } + + /** + * Sets the given values of the object with the given name. + * @param name the name of the object + * @param position the new position of the object + * @param angle the new angle of the object + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, Point position, float angle){ + Object b = getObject(name); + setObject(name, position.x, position.y, angle, b.scale.x, b.scale.y); + } + + /** + * Sets the position of the object with the given name. + * @param name the name of the object + * @param x the new position in x direction of the object + * @param y the new position in y direction of the object + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, float x, float y){ + Object b = getObject(name); + setObject(name, x, y, b.angle); + } + + /** + * Sets the position of the object with the given name. + * @param name the name of the object + * @param position the new position of the object + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, Point position){ + setObject(name, position.x, position.y); + } + + /** + * Sets the position of the object with the given name. + * @param name the name of the object + * @param angle the new angle of the object + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, float angle){ + Object b = getObject(name); + setObject(name, b.position.x, b.position.y, angle); + } + + /** + * Sets the position of the object with the given name. + * @param name the name of the object + * @param alpha the new alpha value of the object + * @param folder the new folder index of the object + * @param file the new file index of the object + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, float alpha, int folder, int file){ + Object b = getObject(name); + setObject(name, b.position.x, b.position.y, b.angle, b.scale.x, b.scale.y, b.pivot.x, b.pivot.y, alpha, folder, file); + } + + /** + * Sets the values of the object with the given name to the values of the given object. + * @param name the name of the object + * @param object the object with the new values + * @throws SpriterException if no object exists of the given name + */ + public void setObject(String name, Object object){ + setObject(name, object.position, object.angle, object.scale, object.pivot, object.alpha, object.ref); + } + + /** + * Maps all object from the parent's coordinate system to the global coordinate system. + * @param base the root bone to start at. Set it to null to traverse the whole bone hierarchy. + */ + public void unmapObjects(BoneRef base){ + int start = base == null ? -1 : base.id-1; + for(int i = start+1; i < getCurrentKey().boneRefs.length; i++){ + BoneRef ref = getCurrentKey().getBoneRef(i); + if(ref.parent != base && base != null) continue; + Bone parent = ref.parent == null ? this.root : this.unmappedTweenedKeys[ref.parent.timeline].object(); + unmappedTweenedKeys[ref.timeline].object().set(tweenedKeys[ref.timeline].object()); + unmappedTweenedKeys[ref.timeline].object().unmap(parent); + unmapObjects(ref); + } + for(ObjectRef ref: getCurrentKey().objectRefs){ + if(ref.parent != base && base != null) continue; + Bone parent = ref.parent == null ? this.root : this.unmappedTweenedKeys[ref.parent.timeline].object(); + unmappedTweenedKeys[ref.timeline].object().set(tweenedKeys[ref.timeline].object()); + unmappedTweenedKeys[ref.timeline].object().unmap(parent); + } + } + + /** + * Sets the entity for this player instance. + * The animation will be switched to the first one of the new entity. + * @param entity the new entity + * @throws SpriterException if the entity is null + */ + public void setEntity(Entity entity){ + if(entity == null) throw new SpriterException("entity can not be null!"); + this.entity = entity; + int maxAnims = entity.getAnimationWithMostTimelines().timelines(); + tweenedKeys = new Timeline.Key[maxAnims]; + unmappedTweenedKeys = new Timeline.Key[maxAnims]; + for(int i = 0; i < maxAnims; i++){ + Timeline.Key key = new Timeline.Key(i); + Timeline.Key keyU = new Timeline.Key(i); + key.setObject(new Timeline.Key.Object(new Point(0,0))); + keyU.setObject(new Timeline.Key.Object(new Point(0,0))); + tweenedKeys[i] = key; + unmappedTweenedKeys[i] = keyU; + this.objToTimeline.put(keyU.object(), keyU); + } + this.tempTweenedKeys = tweenedKeys; + this.tempUnmappedTweenedKeys = unmappedTweenedKeys; + this.setAnimation(entity.getAnimation(0)); + } + + /** + * Returns the current set entity. + * @return the current entity + */ + public Entity getEntity(){ + return this.entity; + } + + /** + * Sets the animation of this player. + * @param animation the new animation + * @throws SpriterException if the animation is null or the current animation is not a member of the current set entity + */ + public void setAnimation(Animation animation){ + Animation prevAnim = this.animation; + if(animation == this.animation) return; + if(animation == null) throw new SpriterException("animation can not be null!"); + if(!this.entity.containsAnimation(animation) && animation.id != -1) throw new SpriterException("animation has to be in the same entity as the current set one!"); + if(animation != this.animation) time = 0; + this.animation = animation; + int tempTime = this.time; + this.time = 0; + this.update(); + this.time = tempTime; + for(PlayerListener listener: listeners) + listener.animationChanged(prevAnim, animation); + } + + /** + * Sets the animation of this player to the one with the given name. + * @param name the name of the animation + * @throws SpriterException if no animation exists with the given name + */ + public void setAnimation(String name){ + this.setAnimation(entity.getAnimation(name)); + } + + /** + * Sets the animation of this player to the one with the given index. + * @param index the index of the animation + * @throws IndexOutOfBoundsException if the index is out of range + */ + public void setAnimation(int index){ + this.setAnimation(entity.getAnimation(index)); + } + + /** + * Returns the current set animation. + * @return the current animation + */ + public Animation getAnimation(){ + return this.animation; + } + + /** + * Returns a bounding box for this player. + * The bounding box is calculated for all bones and object starting from the given root. + * @param root the starting root. Set it to null to calculate the bounding box for the whole player + * @return the bounding box + */ + public Rectangle getBoundingRectangle(BoneRef root){ + Bone boneRoot = root == null ? this.root : this.unmappedTweenedKeys[root.timeline].object(); + this.rect.set(boneRoot.position.x, boneRoot.position.y, boneRoot.position.x, boneRoot.position.y); + this.calcBoundingRectangle(root); + this.rect.calculateSize(); + return this.rect; + } + + /** + * Returns a bounding box for this player. + * The bounding box is calculated for all bones and object starting from the given root. + * @param root the starting root. Set it to null to calculate the bounding box for the whole player + * @return the bounding box + */ + public Rectangle getBoudingRectangle(Bone root){ + return this.getBoundingRectangle(root == null ? null: getBoneRef(root)); + } + + private void calcBoundingRectangle(BoneRef root){ + for(BoneRef ref: getCurrentKey().boneRefs){ + if(ref.parent != root && root != null) continue; + Bone bone = this.unmappedTweenedKeys[ref.timeline].object(); + this.prevBBox.calcFor(bone, animation.getTimeline(ref.timeline).objectInfo); + Rectangle.setBiggerRectangle(rect, this.prevBBox.getBoundingRect(), rect); + this.calcBoundingRectangle(ref); + } + for(ObjectRef ref: getCurrentKey().objectRefs){ + if(ref.parent != root) continue; + Bone bone = this.unmappedTweenedKeys[ref.timeline].object(); + this.prevBBox.calcFor(bone, animation.getTimeline(ref.timeline).objectInfo); + Rectangle.setBiggerRectangle(rect, this.prevBBox.getBoundingRect(), rect); + } + } + + /** + * Returns the current main line key based on the current {@link #time}. + * @return the current main line key + */ + public Mainline.Key getCurrentKey(){ + return this.currentKey; + } + + /** + * Returns the current time. + * The player will make sure that the current time is always between 0 and {@link Animation#length}. + * @return the current time + */ + public int getTime() { + return time; + } + + /** + * Sets the time for the current time. + * The player will make sure that the new time will not exceed the time bounds of the current animation. + * @param time the new time + * @return this player to enable chained operations + */ + public Player setTime(int time){ + this.time = time; + int prevSpeed = this.speed; + this.speed = 0; + this.increaseTime(); + this.speed = prevSpeed; + return this; + } + + /** + * Sets the scale of this player to the given one. + * Only uniform scaling is supported. + * @param scale the new scale. 1f means 100% scale. + * @return this player to enable chained operations + */ + public Player setScale(float scale){ + this.root.scale.set(scale*flippedX(), scale*flippedY()); + return this; + } + + /** + * Scales this player based on the current set scale. + * @param scale the scaling factor. 1f means no scale. + * @return this player to enable chained operations + */ + public Player scale(float scale){ + this.root.scale.scale(scale, scale); + return this; + } + + /** + * Returns the current scale. + * @return the current scale + */ + public float getScale(){ + return root.scale.x; + } + + /** + * Flips this player around the x and y axis. + * @param x whether to flip the player around the x axis + * @param y whether to flip the player around the y axis + * @return this player to enable chained operations + */ + public Player flip(boolean x, boolean y){ + if(x) this.flipX(); + if(y) this.flipY(); + return this; + } + + /** + * Flips the player around the x axis. + * @return this player to enable chained operations + */ + public Player flipX(){ + this.root.scale.x *= -1; + return this; + } + + /** + * Flips the player around the y axis. + * @return this player to enable chained operations + */ + public Player flipY(){ + this.root.scale.y *= -1; + return this; + } + + /** + * Returns whether this player is flipped around the x axis. + * @return 1 if this player is not flipped, -1 if it is flipped + */ + public int flippedX(){ + return (int) Math.signum(root.scale.x); + } + + /** + * Returns whether this player is flipped around the y axis. + * @return 1 if this player is not flipped, -1 if it is flipped + */ + public int flippedY(){ + return (int) Math.signum(root.scale.y); + } + + /** + * Sets the position of this player to the given coordinates. + * @param x the new position in x direction + * @param y the new position in y direction + * @return this player to enable chained operations + */ + public Player setPosition(float x, float y){ + this.dirty = true; + this.position.set(x,y); + return this; + } + + /** + * Sets the position of the player to the given one. + * @param position the new position + * @return this player to enable chained operations + */ + public Player setPosition(Point position){ + return this.setPosition(position.x, position.y); + } + + /** + * Adds the given coordinates to the current position of this player. + * @param x the amount in x direction + * @param y the amount in y direction + * @return this player to enable chained operations + */ + public Player translatePosition(float x, float y){ + return this.setPosition(position.x+x, position.y+y); + } + + /** + * Adds the given amount to the current position of this player. + * @param amount the amount to add + * @return this player to enable chained operations + */ + public Player translate(Point amount){ + return this.translatePosition(amount.x, amount.y); + } + + /** + * Returns the current position in x direction. + * @return the current position in x direction + */ + public float getX(){ + return position.x; + } + + /** + * Returns the current position in y direction. + * @return the current position in y direction + */ + public float getY(){ + return position.y; + } + + /** + * Sets the angle of this player to the given angle. + * @param angle the angle in degrees + * @return this player to enable chained operations + */ + public Player setAngle(float angle){ + this.dirty = true; + this.angle = angle; + return this; + } + + /** + * Rotates this player by the given angle. + * @param angle the angle in degrees + * @return this player to enable chained operations + */ + public Player rotate(float angle){ + return this.setAngle(angle+this.angle); + } + + /** + * Returns the current set angle. + * @return the current angle + */ + public float getAngle(){ + return this.angle; + } + + /** + * Sets the pivot, i.e. origin, of this player. + * A pivot at (0,0) means that the origin of the played animation will have the same one as in Spriter. + * @param x the new pivot in x direction + * @param y the new pivot in y direction + * @return this player to enable chained operations + */ + public Player setPivot(float x, float y){ + this.dirty = true; + this.pivot.set(x, y); + return this; + } + + /** + * Sets the pivot, i.e. origin, of this player. + * A pivot at (0,0) means that the origin of the played animation will have the same one as in Spriter. + * @param pivot the new pivot + * @return this player to enable chained operations + */ + public Player setPivot(Point pivot){ + return this.setPivot(pivot.x, pivot.y); + } + + /** + * Translates the current set pivot position by the given amount. + * @param x the amount in x direction + * @param y the amount in y direction + * @return this player to enable chained operations + */ + public Player translatePivot(float x, float y){ + return this.setPivot(pivot.x+x, pivot.y+y); + } + + /** + * Adds the given amount to the current set pivot position. + * @param amount the amount to add + * @return this player to enable chained operations + */ + public Player translatePivot(Point amount){ + return this.translatePivot(amount.x, amount.y); + } + + /** + * Returns the current set pivot in x direction. + * @return the pivot in x direction + */ + public float getPivotX(){ + return pivot.x; + } + + /** + * Returns the current set pivot in y direction. + * @return the pivot in y direction + */ + public float getPivotY(){ + return pivot.y; + } + + /** + * Appends a listener to the listeners list of this player. + * @param listener the listener to add + */ + public void addListener(PlayerListener listener){ + this.listeners.add(listener); + } + + /** + * Removes a listener from the listeners list of this player. + * @param listener the listener to remove + */ + public void removeListener(PlayerListener listener){ + this.listeners.remove(listener); + } + + /** + * Returns an iterator to iterate over all time line bones in the current animation. + * @return the bone iterator + */ + public Iterator boneIterator(){ + return this.boneIterator(this.getCurrentKey().boneRefs[0]); + } + + /** + * Returns an iterator to iterate over all time line bones in the current animation starting at a given root. + * @param start the bone reference to start at + * @return the bone iterator + */ + public Iterator boneIterator(BoneRef start){ + this.boneIterator.index = start.id; + return this.boneIterator; + } + + /** + * Returns an iterator to iterate over all time line objects in the current animation. + * @return the object iterator + */ + public Iterator objectIterator(){ + return this.objectIterator(this.getCurrentKey().objectRefs[0]); + } + + /** + * Returns an iterator to iterate over all time line objects in the current animation starting at a given root. + * @param start the object reference to start at + * @return the object iterator + */ + public Iterator objectIterator(ObjectRef start){ + this.objectIterator.index = start.id; + return this.objectIterator; + } + + /** + * An iterator to iterate over all time line objects in the current animation. + * @author Trixt0r + * + */ + class ObjectIterator implements Iterator{ + int index = 0; + @Override + public boolean hasNext() { + return index < getCurrentKey().objectRefs.length; + } + + @Override + public Object next() { + return unmappedTweenedKeys[getCurrentKey().objectRefs[index++].timeline].object(); + } + + @Override + public void remove() { + throw new SpriterException("remove() is not supported by this iterator!"); + } + + } + + /** + * An iterator to iterate over all time line bones in the current animation. + * @author Trixt0r + * + */ + class BoneIterator implements Iterator{ + int index = 0; + @Override + public boolean hasNext() { + return index < getCurrentKey().boneRefs.length; + } + + @Override + public Bone next() { + return unmappedTweenedKeys[getCurrentKey().boneRefs[index++].timeline].object(); + } + + @Override + public void remove() { + throw new SpriterException("remove() is not supported by this iterator!"); + } + } + + /** + * A listener to listen for specific events which can occur during the runtime of a {@link Player} instance. + * @author Trixt0r + * + */ + public static interface PlayerListener{ + + /** + * Gets called if the current animation has reached it's end or it's beginning (depends on the current set {@link Player#speed}). + * @param animation the animation which finished. + */ + public void animationFinished(Animation animation); + + /** + * Gets called if the animation of the player gets changed. + * If {@link Player#setAnimation(Animation)} gets called and the new animation is the same as the previous one, this method will not be called. + * @param oldAnim the old animation + * @param newAnim the new animation + */ + public void animationChanged(Animation oldAnim, Animation newAnim); + + /** + * Gets called before a player updates the current animation. + * @param player the player which is calling this method. + */ + public void preProcess(Player player); + + /** + * Gets called after a player updated the current animation. + * @param player the player which is calling this method. + */ + public void postProcess(Player player); + + /** + * Gets called if the mainline key gets changed. + * If {@link Player#speed} is big enough it can happen that mainline keys between the previous and the new mainline key will be ignored. + * @param prevKey the previous mainline key + * @param newKey the new mainline key + */ + public void mainlineKeyChanged(Mainline.Key prevKey, Mainline.Key newKey); + } + + /** + * An attachment is an abstract object which can be attached to a {@link Player} object. + * An attachment extends a {@link Bone} which means that {@link Bone#position}, {@link Bone#scale} and {@link Bone#angle} can be set to change the relative position to its {@link Attachment#parent} + * The {@link Player} object will make sure that the attachment will be transformed relative to its {@link Attachment#parent}. + * @author Trixt0r + * + */ + public static abstract class Attachment extends Timeline.Key.Bone{ + + private Bone parent; + private final Point positionTemp, scaleTemp; + private float angleTemp; + + /** + * Creates a new attachment + * @param parent the parent of this attachment + */ + public Attachment(Bone parent){ + this.positionTemp = new Point(); + this.scaleTemp = new Point(); + this.setParent(parent); + } + + /** + * Sets the parent of this attachment. + * @param parent the parent + * @throws SpriterException if parent is null + */ + public void setParent(Bone parent){ + if(parent == null) throw new SpriterException("The parent cannot be null!"); + this.parent = parent; + } + + /** + * Returns the current set parent. + * @return the parent + */ + public Bone getParent(){ + return this.parent; + } + + final void update(){ + //Save relative positions + this.positionTemp.set(super.position); + this.scaleTemp.set(super.scale); + this.angleTemp = super.angle; + + super.unmap(parent); + this.setPosition(super.position.x, super.position.y); + this.setScale(super.scale.x, super.scale.y); + this.setAngle(super.angle); + + //Load realtive positions + super.position.set(this.positionTemp); + super.scale.set(this.scaleTemp); + super.angle = this.angleTemp; + } + /** + * Sets the position to the given coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + protected abstract void setPosition(float x, float y); + /** + * Sets the scale to the given scale. + * @param xscale the scale in x direction + * @param yscale the scale in y direction + */ + protected abstract void setScale(float xscale, float yscale); + /** + * Sets the angle to the given one. + * @param angle the angle in degrees + */ + protected abstract void setAngle(float angle); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/PlayerTweener.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/PlayerTweener.java new file mode 100644 index 00000000..8e76840f --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/PlayerTweener.java @@ -0,0 +1,162 @@ +package com.brashmonkey.spriter; + +/** + * A player tweener is responsible for tweening to {@link Player} instances. + * Such a + * @author Trixt0r + * + */ +public class PlayerTweener extends Player{ + + private TweenedAnimation anim; + private Player player1, player2; + /** + * Indicates whether to update the {@link Player} instances this instance is holding. + * If this variable is set to false, you will have to call {@link Player#update()} on your own. + */ + public boolean updatePlayers = true; + + /** + * The name of root bone to start the tweening at. + * Set it to null to tween the whole hierarchy. + */ + public String baseBoneName = null; + + /** + * Creates a player tweener which will tween the given two players. + * @param player1 the first player + * @param player2 the second player + */ + public PlayerTweener(Player player1, Player player2){ + super(player1.getEntity()); + this.setPlayers(player1, player2); + } + + /** + * Creates a player tweener based on the entity. + * The players to tween will be created by this instance. + * @param entity the entity the players will animate + */ + public PlayerTweener(Entity entity){ + this(new Player(entity), new Player(entity)); + } + + /** + * Tweens the current set players. + * This method will update the set players if {@link #updatePlayers} is true. + * @throws SpriterException if no bone with {@link #baseBoneName} exists + */ + @Override + public void update(){ + if(updatePlayers){ + player1.update(); + player2.update(); + } + anim.setAnimations(player1.animation, player2.animation); + super.update(); + if(baseBoneName != null){ + int index = anim.onFirstMainLine()? player1.getBoneIndex(baseBoneName) : player2.getBoneIndex(baseBoneName); + if(index == -1) throw new SpriterException("A bone with name \""+baseBoneName+"\" does no exist!"); + anim.base = anim.getCurrentKey().getBoneRef(index); + super.update(); + } + } + + /** + * Sets the players for this tweener. + * Both players have to hold the same {@link Entity} + * @param player1 the first player + * @param player2 the second player + */ + public void setPlayers(Player player1, Player player2){ + if(player1.entity != player2.entity) + throw new SpriterException("player1 and player2 have to hold the same entity!"); + this.player1 = player1; + this.player2 = player2; + if(player1.entity == entity) return; + this.anim = new TweenedAnimation(player1.getEntity()); + anim.setAnimations(player1.animation, player2.animation); + super.setEntity(player1.getEntity()); + super.setAnimation(anim); + } + + /** + * Returns the first set player. + * @return the first player + */ + public Player getFirstPlayer(){ + return this.player1; + } + + /** + * Returns the second set player. + * @return the second player + */ + public Player getSecondPlayer(){ + return this.player2; + } + + /** + * Sets the interpolation weight of this tweener. + * @param weight the interpolation weight between 0.0f and 1.0f + */ + public void setWeight(float weight){ + this.anim.weight = weight; + } + + /** + * Returns the interpolation weight. + * @return the interpolation weight between 0.0f and 1.0f + */ + public float getWeight(){ + return this.anim.weight; + } + + + /** + * Sets the base animation of this tweener. + * Has only an effect if {@link #baseBoneName} is not null. + * @param anim the base animation + */ + public void setBaseAnimation(Animation anim){ + this.anim.baseAnimation = anim; + } + + /** + * Sets the base animation of this tweener by the given animation index. + * Has only an effect if {@link #baseBoneName} is not null. + * @param index the index of the base animation + */ + public void setBaseAnimation(int index){ + this.setBaseAnimation(entity.getAnimation(index)); + } + + /** + * Sets the base animation of this tweener by the given name. + * Has only an effect if {@link #baseBoneName} is not null. + * @param name the name of the base animation + */ + public void setBaseAnimation(String name){ + this.setBaseAnimation(entity.getAnimation(name)); + } + + /** + * Returns the base animation if this tweener. + * @return the base animation + */ + public Animation getBaseAnimation(){ + return this.anim.baseAnimation; + } + + /** + * Not supported by this class. + */ + @Override + public void setAnimation(Animation anim){} + + /** + * Not supported by this class. + */ + @Override + public void setEntity(Entity entity){} +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Point.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Point.java new file mode 100644 index 00000000..b8616c7d --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Point.java @@ -0,0 +1,135 @@ +package com.brashmonkey.spriter; + +/** + * A utility class to keep the code short. + * A point is essentially that what you would expect if you think about a point in a 2D space. + * It holds an x and y value. You can {@link #translate(Point)}, {@link #scale(Point)}, {@link #rotate(float)} and {@link #set(Point)} a point. + * @author Trixt0r + * + */ +public class Point { + + /** + * The x coordinates of this point. + */ + public float x; + /** + * The y coordinates of this point. + */ + public float y; + + /** + * Creates a point at (0,0). + */ + public Point(){ + this(0,0); + } + + /** + * Creates a point at the position of the given point. + * @param point the point to set this point at + */ + public Point(Point point){ + this(point.x, point.y); + } + + /** + * Creates a point at (x, y). + * @param x the x coordinate + * @param y the y coordinate + */ + public Point(float x, float y){ + this.set(x, y); + } + + /** + * Sets this point to the given coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @return this point for chained operations + */ + public Point set(float x, float y){ + this.x = x; + this.y = y; + return this; + } + + /** + * Adds the given amount to this point. + * @param x the amount in x direction to add + * @param y the amount in y direction to add + * @return this point for chained operations + */ + public Point translate(float x, float y){ + return this.set(this.x+x, this.y+y); + } + + /** + * Scales this point by the given amount. + * @param x the scale amount in x direction + * @param y the scale amount in y direction + * @return this point for chained operations + */ + public Point scale(float x, float y){ + return this.set(this.x*x, this.y*y); + } + + /** + * Sets this point to the given point. + * @param point the new coordinates + * @return this point for chained operations + */ + public Point set(Point point){ + return this.set(point.x, point.y); + } + + /** + * Adds the given amount to this point. + * @param amount the amount to add + * @return this point for chained operations + */ + public Point translate(Point amount){ + return this.translate(amount.x, amount.y); + } + + /** + * Scales this point by the given amount. + * @param amount the amount to scale + * @return this point for chained operations + */ + public Point scale(Point amount){ + return this.scale(amount.x, amount.y); + } + + /** + * Rotates this point around (0,0) by the given amount of degrees. + * @param degrees the angle to rotate this point + * @return this point for chained operations + */ + public Point rotate(float degrees){ + if(x != 0 || y != 0){ + float cos = Calculator.cosDeg(degrees); + float sin = Calculator.sinDeg(degrees); + + float xx = x*cos-y*sin; + float yy = x*sin+y*cos; + + this.x = xx; + this.y = yy; + } + return this; + } + + /** + * Returns a copy of this point with the current set values. + * @return a copy of this point + */ + public Point copy(){ + return new Point(x,y); + } + + public String toString(){ + return "["+x+","+y+"]"; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Rectangle.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Rectangle.java new file mode 100644 index 00000000..42c1387d --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Rectangle.java @@ -0,0 +1,118 @@ +package com.brashmonkey.spriter; + +/** + * Represents a 2D rectangle with left, top, right and bottom bounds. + * A rectangle is responsible for calculating its own size and checking if a point is inside it or if it is intersecting with another rectangle. + * @author Trixt0r + * + */ +public class Rectangle { + + /** + * Belongs to the bounds of this rectangle. + */ + public float left, top, right, bottom; + /** + * The size of this rectangle. + */ + public final Dimension size; + + /** + * Creates a rectangle with the given bounds. + * @param left left bounding + * @param top top bounding + * @param right right bounding + * @param bottom bottom bounding + */ + public Rectangle(float left, float top, float right, float bottom){ + this.set(left, top, right, bottom); + this.size = new Dimension(0, 0); + this.calculateSize(); + } + + /** + * Creates a rectangle with the bounds of the given rectangle. + * @param rect rectangle containing the bounds. + */ + public Rectangle(Rectangle rect){ + this(rect.left, rect.top, rect.right, rect.bottom); + } + + /** + * Returns whether the given point (x,y) is inside this rectangle. + * @param x the x coordinate + * @param y the y coordinate + * @return true if (x,y) is inside + */ + public boolean isInside(float x, float y){ + return x >= this.left && x <= this.right && y <= this.top && y >= this.bottom; + } + + /** + * Returns whether the given point is inside this rectangle. + * @param point the point + * @return true if the point is inside + */ + public boolean isInside(Point point){ + return isInside(point.x, point.y); + } + + /** + * Calculates the size of this rectangle. + */ + public void calculateSize(){ + this.size.set(right-left, top-bottom); + } + + /** + * Sets the bounds of this rectangle to the bounds of the given rectangle. + * @param rect rectangle containing the bounds. + */ + public void set(Rectangle rect){ + if(rect == null) return; + this.bottom = rect.bottom; + this.left = rect.left; + this.right = rect.right; + this.top = rect.top; + this.calculateSize(); + } + + /** + * Sets the bounds of this rectangle to the given bounds. + * @param left left bounding + * @param top top bounding + * @param right right bounding + * @param bottom bottom bounding + */ + public void set(float left, float top, float right, float bottom){ + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + /** + * Returns whether the given two rectangles are intersecting. + * @param rect1 the first rectangle + * @param rect2 the second rectangle + * @return true if the rectangles are intersecting + */ + public static boolean areIntersecting(Rectangle rect1, Rectangle rect2){ + return rect1.isInside(rect2.left, rect2.top) || rect1.isInside(rect2.right, rect2.top) + || rect1.isInside(rect2.left, rect2.bottom) || rect1.isInside(rect2.right, rect2.bottom); + } + + /** + * Creates a bigger rectangle of the given two and saves it in the target. + * @param rect1 the first rectangle + * @param rect2 the second rectangle + * @param target the target to save the new bounds. + */ + public static void setBiggerRectangle(Rectangle rect1, Rectangle rect2, Rectangle target){ + target.left = Math.min(rect1.left, rect2.left); + target.bottom = Math.min(rect1.bottom, rect2.bottom); + target.right = Math.max(rect1.right, rect2.right); + target.top = Math.max(rect1.top, rect2.top); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/SCMLReader.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/SCMLReader.java new file mode 100644 index 00000000..61b1b14e --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/SCMLReader.java @@ -0,0 +1,298 @@ +package com.brashmonkey.spriter; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; + +import com.brashmonkey.spriter.Entity.*; +import com.brashmonkey.spriter.Mainline.Key.*; +import com.brashmonkey.spriter.XmlReader.*; + +/** + * This class parses a SCML file and creates a {@link Data} instance. + * If you want to keep track of what is going on during the build process of the objects parsed from the SCML file, + * you could extend this class and override the load*() methods for pre or post processing. + * This could be e.g. useful for a loading screen which responds to the current building or parsing state. + * @author Trixt0r + */ +public class SCMLReader { + + protected Data data; + + /** + * Creates a new SCML reader and will parse all objects in the given stream. + * @param stream the stream + */ + public SCMLReader(InputStream stream){ + this.data = this.load(stream); + } + + /** + * Creates a new SCML reader and will parse the given xml string. + * @param xml the xml string + */ + public SCMLReader(String xml){ + this.data = this.load(xml); + } + + /** + * Parses the SCML object save in the given xml string and returns the build data object. + * @param xml the xml string + * @return the built data + */ + protected Data load(String xml){ + XmlReader reader = new XmlReader(); + Element root = reader.parse(xml); + ArrayList folders = root.getChildrenByName("folder"); + ArrayList entities = root.getChildrenByName("entity"); + data = new Data(root.get("scml_version"), root.get("generator"),root.get("generator_version"), + folders.size(), entities.size()); + loadFolders(folders); + loadEntities(entities); + return data; + } + + /** + * Parses the SCML objects saved in the given stream and returns the built data object. + * @param stream the stream from the SCML file + * @return the built data + */ + protected Data load(InputStream stream){ + XmlReader reader = new XmlReader(); + try { + Element root = reader.parse(stream); + ArrayList folders = root.getChildrenByName("folder"); + ArrayList entities = root.getChildrenByName("entity"); + data = new Data(root.get("scml_version"), root.get("generator"),root.get("generator_version"), + folders.size(), entities.size()); + loadFolders(folders); + loadEntities(entities); + } catch (IOException e) { + e.printStackTrace(); + } + return data; + } + + /** + * Iterates through the given folders and adds them to the current {@link Data} object. + * @param folders a list of folders to load + */ + protected void loadFolders(ArrayList folders){ + for(int i = 0; i < folders.size(); i++){ + Element repo = folders.get(i); + ArrayList files = repo.getChildrenByName("file"); + Folder folder = new Folder(repo.getInt("id"), repo.get("name", "no_name_"+i), files.size()); + loadFiles(files, folder); + data.addFolder(folder); + } + } + + /** + * Iterates through the given files and adds them to the given {@link Folder} object. + * @param files a list of files to load + * @param folder the folder containing the files + */ + protected void loadFiles(ArrayList files, Folder folder){ + for(int j = 0; j < files.size(); j++){ + Element f = files.get(j); + File file = new File(f.getInt("id"), f.get("name"), + new Dimension(f.getInt("width", 0), f.getInt("height", 0)), + new Point(f.getFloat("pivot_x", 0f), f.getFloat("pivot_y", 1f))); + + folder.addFile(file); + } + } + + /** + * Iterates through the given entities and adds them to the current {@link Data} object. + * @param entities a list of entities to load + */ + protected void loadEntities(ArrayList entities){ + for(int i = 0; i < entities.size(); i++){ + Element e = entities.get(i); + ArrayList infos = e.getChildrenByName("obj_info"); + ArrayList charMaps = e.getChildrenByName("character_map"); + ArrayList animations = e.getChildrenByName("animation"); + Entity entity = new Entity(e.getInt("id"), e.get("name"), + animations.size(), charMaps.size(), infos.size()); + data.addEntity(entity); + loadObjectInfos(infos, entity); + loadCharacterMaps(charMaps, entity); + loadAnimations(animations, entity); + } + } + + /** + * Iterates through the given object infos and adds them to the given {@link Entity} object. + * @param infos a list of infos to load + * @param entity the entity containing the infos + */ + protected void loadObjectInfos(ArrayList infos, Entity entity){ + for(int i = 0; i< infos.size(); i++){ + Element info = infos.get(i); + Entity.ObjectInfo objInfo = new Entity.ObjectInfo(info.get("name","info"+i), + Entity.ObjectType.getObjectInfoFor(info.get("type","")), + new Dimension(info.getFloat("w", 0), info.getFloat("h", 0))); + entity.addInfo(objInfo); + Element frames = info.getChildByName("frames"); + if(frames == null) continue; + ArrayList frameIndices = frames.getChildrenByName("i"); + for(Element index: frameIndices){ + int folder = index.getInt("folder", 0); + int file = index.getInt("file", 0); + objInfo.frames.add(new FileReference(folder, file)); + } + } + } + + /** + * Iterates through the given character maps and adds them to the given {@link Entity} object. + * @param maps a list of character maps to load + * @param entity the entity containing the character maps + */ + protected void loadCharacterMaps(ArrayList maps, Entity entity){ + for(int i = 0; i< maps.size(); i++){ + Element map = maps.get(i); + Entity.CharacterMap charMap = new Entity.CharacterMap(map.getInt("id"), map.getAttribute("name", "charMap"+i)); + entity.addCharacterMap(charMap); + ArrayList mappings = map.getChildrenByName("map"); + for(Element mapping: mappings){ + int folder = mapping.getInt("folder"); + int file = mapping.getInt("file"); + charMap.put(new FileReference(folder, file), + new FileReference(mapping.getInt("target_folder", folder), mapping.getInt("target_file", file))); + } + } + } + + /** + * Iterates through the given animations and adds them to the given {@link Entity} object. + * @param animations a list of animations to load + * @param entity the entity containing the animations maps + */ + protected void loadAnimations(ArrayList animations, Entity entity){ + for(int i = 0; i < animations.size(); i++){ + Element a = animations.get(i); + ArrayList timelines = a.getChildrenByName("timeline"); + Element mainline = a.getChildByName("mainline"); + ArrayList mainlineKeys = mainline.getChildrenByName("key"); + Animation animation = new Animation(new Mainline(mainlineKeys.size()), + a.getInt("id"), a.get("name"), a.getInt("length"), + a.getBoolean("looping", true),timelines.size()); + entity.addAnimation(animation); + loadMainlineKeys(mainlineKeys, animation.mainline); + loadTimelines(timelines, animation, entity); + animation.prepare(); + } + } + + /** + * Iterates through the given mainline keys and adds them to the given {@link Mainline} object. + * @param keys a list of mainline keys + * @param main the mainline + */ + protected void loadMainlineKeys(ArrayList keys, Mainline main){ + for(int i = 0; i < main.keys.length; i++){ + Element k = keys.get(i); + ArrayList objectRefs = k.getChildrenByName("object_ref"); + ArrayList boneRefs = k.getChildrenByName("bone_ref"); + Curve curve = new Curve(); + curve.setType(Curve.getType(k.get("curve_type","linear"))); + curve.constraints.set(k.getFloat("c1", 0f),k.getFloat("c2", 0f),k.getFloat("c3", 0f),k.getFloat("c4", 0f)); + Mainline.Key key = new Mainline.Key(k.getInt("id"), k.getInt("time", 0), curve, + boneRefs.size(), objectRefs.size()); + main.addKey(key); + loadRefs(objectRefs, boneRefs, key); + } + } + + /** + * Iterates through the given bone and object references and adds them to the given {@link Mainline.Key} object. + * @param objectRefs a list of object references + * @param boneRefs a list if bone references + * @param key the mainline key + */ + protected void loadRefs(ArrayList objectRefs, ArrayList boneRefs, Mainline.Key key){ + for(Element e: boneRefs){ + BoneRef boneRef = new BoneRef(e.getInt("id"),e.getInt("timeline"), + e.getInt("key"), key.getBoneRef(e.getInt("parent", -1))); + key.addBoneRef(boneRef); + } + + for(Element o: objectRefs){ + ObjectRef objectRef = new ObjectRef(o.getInt("id"),o.getInt("timeline"), + o.getInt("key"), key.getBoneRef(o.getInt("parent", -1)), o.getInt("z_index",0)); + key.addObjectRef(objectRef); + } + Arrays.sort(key.objectRefs); + } + + /** + * Iterates through the given timelines and adds them to the given {@link Animation} object. + * @param timelines a list of timelines + * @param animation the animation containing the timelines + * @param entity entity for assigning the timeline an object info + */ + protected void loadTimelines(ArrayList timelines, Animation animation, Entity entity){ + for(int i = 0; i< timelines.size(); i++){ + Element t = timelines.get(i); + ArrayList keys = timelines.get(i).getChildrenByName("key"); + String name = t.get("name"); + ObjectType type = ObjectType.getObjectInfoFor(t.get("object_type", "sprite")); + ObjectInfo info = entity.getInfo(name); + if(info == null) info = new ObjectInfo(name, type, new Dimension(0,0)); + Timeline timeline = new Timeline(t.getInt("id"), name, info, keys.size()); + animation.addTimeline(timeline); + loadTimelineKeys(keys, timeline); + } + } + + /** + * Iterates through the given timeline keys and adds them to the given {@link Timeline} object. + * @param keys a list if timeline keys + * @param timeline the timeline containing the keys + */ + protected void loadTimelineKeys(ArrayList keys, Timeline timeline){ + for(int i = 0; i< keys.size(); i++){ + Element k = keys.get(i); + Curve curve = new Curve(); + curve.setType(Curve.getType(k.get("curve_type", "linear"))); + curve.constraints.set(k.getFloat("c1", 0f),k.getFloat("c2", 0f),k.getFloat("c3", 0f),k.getFloat("c4", 0f)); + Timeline.Key key = new Timeline.Key(k.getInt("id"), k.getInt("time", 0), k.getInt("spin", 1), curve); + Element obj = k.getChildByName("bone"); + if(obj == null) obj = k.getChildByName("object"); + + Point position = new Point(obj.getFloat("x", 0f), obj.getFloat("y", 0f)); + Point scale = new Point(obj.getFloat("scale_x", 1f), obj.getFloat("scale_y", 1f)); + Point pivot = new Point(obj.getFloat("pivot_x", 0f), obj.getFloat("pivot_y", (timeline.objectInfo.type == ObjectType.Bone)? .5f:1f)); + float angle = obj.getFloat("angle", 0f), alpha = 1f; + int folder = -1, file = -1; + if(obj.getName().equals("object")){ + if(timeline.objectInfo.type == ObjectType.Sprite){ + alpha = obj.getFloat("a", 1f); + folder = obj.getInt("folder", -1); + file = obj.getInt("file", -1); + File f = data.getFolder(folder).getFile(file); + pivot = new Point(obj.getFloat("pivot_x", f.pivot.x), obj.getFloat("pivot_y", f.pivot.y)); + timeline.objectInfo.size.set(f.size); + } + } + Timeline.Key.Object object; + if(obj.getName().equals("bone")) object = new Timeline.Key.Object(position, scale, pivot, angle, alpha, new FileReference(folder, file)); + else object = new Timeline.Key.Object(position, scale, pivot, angle, alpha, new FileReference(folder, file)); + key.setObject(object); + timeline.addKey(key); + } + } + + /** + * Returns the loaded SCML data. + * @return the SCML data. + */ + public Data getData(){ + return data; + } + +} + diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Spriter.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Spriter.java new file mode 100644 index 00000000..600f93e4 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Spriter.java @@ -0,0 +1,264 @@ +package com.brashmonkey.spriter; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * A utility class for managing multiple {@link Loader} and {@link Player} instances. + * @author Trixt0r + * + */ + +@SuppressWarnings("rawtypes") +public class Spriter { + + private static Object[] loaderDependencies = new Object[1], drawerDependencies = new Object[1]; + private static Class[] loaderTypes = new Class[1], drawerTypes = new Class[1]; + static{ + loaderTypes[0] = Data.class; + drawerTypes[0] = Loader.class; + } + private static Class loaderClass; + + private static final HashMap loadedData = new HashMap(); + private static final List players = new ArrayList(); + private static final List loaders = new ArrayList(); + private static Drawer drawer; + private static final HashMap entityToLoader = new HashMap(); + private static boolean initialized = false; + + /** + * Sets the dependencies for implemented {@link Loader}. + * @param loaderDependencies the dependencies a loader has to get + */ + public static void setLoaderDependencies(Object... loaderDependencies){ + if(loaderDependencies == null) return; + Spriter.loaderDependencies = new Object[loaderDependencies.length+1]; + System.arraycopy(loaderDependencies, 0, Spriter.loaderDependencies, 1, loaderDependencies.length); + loaderTypes = new Class[loaderDependencies.length+1]; + loaderTypes[0] = Data.class; + for(int i = 0; i< loaderDependencies.length; i++) + loaderTypes[i+1] = loaderDependencies[i].getClass(); + } + + /** + * Sets the dependencies for implemented {@link Drawer}. + * @param drawerDependencies the dependencies a drawer has to get + */ + public static void setDrawerDependencies(Object... drawerDependencies){ + if(drawerDependencies == null) return; + Spriter.drawerDependencies = new Object[drawerDependencies.length+1]; + Spriter.drawerDependencies[0] = null; + System.arraycopy(drawerDependencies, 0, Spriter.drawerDependencies, 1, drawerDependencies.length); + drawerTypes = new Class[drawerDependencies.length+1]; + drawerTypes[0] = Loader.class; + for(int i = 0; i< drawerDependencies.length; i++) + if(drawerDependencies[i] != null) + drawerTypes[i+1] = drawerDependencies[i].getClass(); + } + + /** + * Initializes this class with the implemented {@link Loader} class and {@link Drawer} class. + * Before calling this method make sure that you have set all necessary dependecies with {@link #setDrawerDependencies(Object...)} and {@link #setLoaderDependencies(Object...)}. + * A drawer is created with this method. + * @param loaderClass the loader class + * @param drawerClass the drawer class + */ + public static void init(Class loaderClass, Class drawerClass){ + Spriter.loaderClass = loaderClass; + try { + drawer = drawerClass.getDeclaredConstructor(drawerTypes).newInstance(drawerDependencies); + } catch (Exception e) { + e.printStackTrace(); + } + initialized = drawer != null; + } + + /** + * Loads a SCML file with the given path. + * @param scmlFile the path to the SCML file + */ + public static void load(String scmlFile){ + load(new File(scmlFile)); + } + + /** + * Loads the given SCML file. + * @param scmlFile the scml file + */ + public static void load(File scmlFile){ + try { + load(new FileInputStream(scmlFile), scmlFile.getPath().replaceAll("\\\\", "/")); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + /** + * Loads the given SCML stream pointing to a file saved at the given path. + * @param stream the SCML stream + * @param scmlFile the path to the SCML file + */ + public static void load(InputStream stream, String scmlFile){ + SCMLReader reader = new SCMLReader(stream); + Data data = reader.data; + loadedData.put(scmlFile, data); + loaderDependencies[0] = data; + try { + Loader loader = loaderClass.getDeclaredConstructor(loaderTypes).newInstance(loaderDependencies); + loader.load(new File(scmlFile)); + loaders.add(loader); + for(Entity entity: data.entities) + entityToLoader.put(entity, loader); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Creates a new {@link Player} instance based on the given SCML file with the given entity index + * @param scmlFile name of the SCML file + * @param entityIndex the index of the entity + * @return a {@link Player} instance managed by this class + * @throws SpriterException if the given SCML file was not loaded yet + */ + public static Player newPlayer(String scmlFile, int entityIndex){ + return newPlayer(scmlFile, entityIndex, Player.class); + } + + /** + * Creates a new {@link Player} instance based on the given SCML file with the given entity index and the given class extending a {@link Player} + * @param scmlFile name of the SCML file + * @param entityIndex the index of the entity + * @param playerClass the class extending a {@link Player} class, e.g. {@link PlayerTweener}. + * @return a {@link Player} instance managed by this class + * @throws SpriterException if the given SCML file was not loaded yet + */ + public static Player newPlayer(String scmlFile, int entityIndex, Class playerClass){ + if(!loadedData.containsKey(scmlFile)) throw new SpriterException("You have to load \""+scmlFile+"\" before using it!"); + try { + Player player = playerClass.getDeclaredConstructor(Entity.class).newInstance(loadedData.get(scmlFile).getEntity(entityIndex)); + players.add(player); + return player; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * Creates a new {@link Player} instance based on the given SCML file with the given entity name + * @param scmlFile name of the SCML file + * @param entityName name of the entity + * @return a {@link Player} instance managed by this class + * @throws SpriterException if the given SCML file was not loaded yet + */ + public static Player newPlayer(String scmlFile, String entityName){ + if(!loadedData.containsKey(scmlFile)) throw new SpriterException("You have to load \""+scmlFile+"\" before using it!"); + return newPlayer(scmlFile, loadedData.get(scmlFile).getEntityIndex(entityName)); + } + + /** + * Returns a loader for the given SCML filename. + * @param scmlFile the name of the SCML file + * @return the loader for the given SCML filename + * @throws NullPointerException if the SCML file was not loaded yet + */ + public static Loader getLoader(String scmlFile){ + return entityToLoader.get(getData(scmlFile).getEntity(0)); + } + + /** + * Updates each created player by this class and immediately draws it. + * This method should only be called if you want to update and render on the same thread. + * @throws SpriterException if {@link #init(Class, Class)} was not called before + */ + @SuppressWarnings("unchecked") + public static void updateAndDraw(){ + if(!initialized) throw new SpriterException("Call init() before updating!"); + for(Player player: players){ + player.update(); + drawer.loader = entityToLoader.get(player.getEntity()); + drawer.draw(player); + } + } + + /** + * Updates each created player by this class. + * @throws SpriterException if {@link #init(Class, Class)} was not called before + */ + public static void update(){ + if(!initialized) throw new SpriterException("Call init() before updating!"); + for(Player player: players) + player.update(); + } + + /** + * Draws each created player by this class. + * @throws SpriterException if {@link #init(Class, Class)} was not called before + */ + @SuppressWarnings("unchecked") + public static void draw(){ + if(!initialized) throw new SpriterException("Call init() before drawing!"); + for(Player player: players){ + drawer.loader = entityToLoader.get(player.getEntity()); + drawer.draw(player); + } + } + + /** + * Returns the drawer instance this class is using. + * @return the drawer which draws all players + */ + public static Drawer drawer(){ + return drawer; + } + + /** + * Returns the data for the given SCML filename. + * @param fileName the name of the SCML file + * @return the data for the given SCML filename or null if not loaed yet + */ + public static Data getData(String fileName){ + return loadedData.get(fileName); + } + + /** + * The number of players this class is managing. + * @return number of players + */ + public static int players(){ + return players.size(); + } + + /** + * Clears all previous created players, Spriter datas, disposes all loaders, deletes the drawer and resets all internal lists. + * After this methods was called {@link #init(Class, Class)} has to be called again so that everything works again. + */ + public static void dispose(){ + drawer = null; + drawerDependencies = new Object[1]; + drawerTypes = new Class[1]; + drawerTypes[0] = Loader.class; + + entityToLoader.clear(); + + for(Loader loader: loaders) loader.dispose(); + loaders.clear(); + loadedData.clear(); + loaderClass = null; + loaderTypes = new Class[1]; + loaderTypes[0] = Data.class; + loaderDependencies = new Object[1]; + + players.clear(); + + initialized = false; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/SpriterException.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/SpriterException.java new file mode 100644 index 00000000..b01a43b0 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/SpriterException.java @@ -0,0 +1,16 @@ +package com.brashmonkey.spriter; + +/** + * An Exception which will be thrown if a Spriter specific issue happens at runtime. + * @author Trixt0r + * + */ +public class SpriterException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public SpriterException(String message){ + super(message); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Timeline.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Timeline.java new file mode 100644 index 00000000..1996d0e7 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/Timeline.java @@ -0,0 +1,277 @@ +package com.brashmonkey.spriter; + +import com.brashmonkey.spriter.Entity.ObjectInfo; + +/** + * Represents a time line in a Spriter SCML file. + * A time line holds an {@link #id}, a {@link #name} and at least one {@link Key}. + * @author Trixt0r + * + */ +public class Timeline { + + public final Key[] keys; + private int keyPointer = 0; + public final int id; + public final String name; + public final ObjectInfo objectInfo; + + Timeline(int id, String name, ObjectInfo objectInfo, int keys){ + this.id = id; + this.name = name; + this.objectInfo = objectInfo; + this.keys = new Key[keys]; + } + + void addKey(Key key){ + this.keys[keyPointer++] = key; + } + + /** + * Returns a {@link Key} at the given index + * @param index the index of the key. + * @return the key with the given index. + * @throws IndexOutOfBoundsException if the index is out of range + */ + public Key getKey(int index){ + return this.keys[index]; + } + + public String toString(){ + String toReturn = getClass().getSimpleName()+"|[id:"+id+", name: "+name+", object_info: "+objectInfo; + for(Key key: keys) + toReturn += "\n"+key; + toReturn+="]"; + return toReturn; + } + + /** + * Represents a time line key in a Spriter SCML file. + * A key holds an {@link #id}, a {@link #time}, a {@link #spin}, an {@link #object()} and a {@link #curve}. + * @author Trixt0r + * + */ + public static class Key{ + + public final int id, spin; + public int time; + public final Curve curve; + public boolean active; + private Object object; + + public Key(int id, int time, int spin, Curve curve){ + this.id = id; + this.time = time; + this.spin = spin; + this.curve = curve; + } + + public Key(int id,int time, int spin){ + this(id, time, 1, new Curve()); + } + + public Key(int id, int time){ + this(id, time, 1); + } + + public Key(int id){ + this(id, 0); + } + + public void setObject(Object object){ + if(object == null) throw new IllegalArgumentException("object can not be null!"); + this.object = object; + } + + public Object object(){ + return this.object; + } + + public String toString(){ + return getClass().getSimpleName()+"|[id: "+id+", time: "+time+", spin: "+spin+"\ncurve: "+curve+"\nobject:"+object+"]"; + } + + /** + * Represents a bone in a Spriter SCML file. + * A bone holds a {@link #position}, {@link #scale}, an {@link #angle} and a {@link #pivot}. + * Bones are the only objects which can be used as a parent for other tweenable objects. + * @author Trixt0r + * + */ + public static class Bone{ + public final Point position, scale, pivot; + public float angle; + + public Bone(Point position, Point scale, Point pivot, float angle){ + this.position = new Point(position); + this.scale = new Point(scale); + this.angle = angle; + this.pivot = new Point(pivot); + } + + public Bone(Bone bone){ + this(bone.position, bone.scale, bone.pivot, bone.angle); + } + + public Bone(Point position){ + this(position, new Point(1f,1f), new Point(0f, 1f), 0f); + } + + public Bone(){ + this(new Point()); + } + + /** + * Returns whether this instance is a Spriter object or a bone. + * @return true if this instance is a Spriter bone + */ + public boolean isBone(){ + return !(this instanceof Object); + } + + /** + * Sets the values of this bone to the values of the given bone + * @param bone the bone + */ + public void set(Bone bone){ + this.set(bone.position, bone.angle, bone.scale, bone.pivot); + } + + /** + * Sets the given values for this bone. + * @param x the new position in x direction + * @param y the new position in y direction + * @param angle the new angle + * @param scaleX the new scale in x direction + * @param scaleY the new scale in y direction + * @param pivotX the new pivot in x direction + * @param pivotY the new pivot in y direction + */ + public void set(float x, float y, float angle, float scaleX, float scaleY, float pivotX, float pivotY){ + this.angle = angle; + this.position.set(x, y); + this.scale.set(scaleX, scaleY); + this.pivot.set(pivotX, pivotY); + } + + /** + * Sets the given values for this bone. + * @param position the new position + * @param angle the new angle + * @param scale the new scale + * @param pivot the new pivot + */ + public void set(Point position, float angle, Point scale, Point pivot){ + this.set(position.x, position.y, angle, scale.x, scale.y, pivot.x, pivot.y); + } + + /** + * Maps this bone from it's parent's coordinate system to a global one. + * @param parent the parent bone of this bone + */ + public void unmap(Bone parent){ + this.angle *= Math.signum(parent.scale.x)*Math.signum(parent.scale.y); + this.angle += parent.angle; + this.scale.scale(parent.scale); + this.position.scale(parent.scale); + this.position.rotate(parent.angle); + this.position.translate(parent.position); + } + + /** + * Maps this from it's global coordinate system to the parent's one. + * @param parent the parent bone of this bone + */ + public void map(Bone parent){ + this.position.translate(-parent.position.x, -parent.position.y); + this.position.rotate(-parent.angle); + this.position.scale(1f/parent.scale.x, 1f/parent.scale.y); + this.scale.scale(1f/parent.scale.x, 1f/parent.scale.y); + this.angle -=parent.angle; + this.angle *= Math.signum(parent.scale.x)*Math.signum(parent.scale.y); + } + + public String toString(){ + return getClass().getSimpleName()+"|position: "+position+", scale: "+scale+", angle: "+angle; + } + } + + + /** + * Represents an object in a Spriter SCML file. + * A file has the same properties as a bone with an alpha and file extension. + * @author Trixt0r + * + */ + public static class Object extends Bone{ + + public float alpha; + public final FileReference ref; + + public Object(Point position, Point scale, Point pivot, float angle, float alpha, FileReference ref) { + super(position, scale, pivot, angle); + this.alpha = alpha; + this.ref = ref; + } + + public Object(Point position) { + this(position, new Point(1f,1f), new Point(0f,1f), 0f, 1f, new FileReference(-1,-1)); + } + + public Object(Object object){ + this(object.position.copy(), object.scale.copy(),object.pivot.copy(),object.angle,object.alpha,object.ref); + } + + public Object(){ + this(new Point()); + } + + /** + * Sets the values of this object to the values of the given object. + * @param object the object + */ + public void set(Object object){ + this.set(object.position, object.angle, object.scale, object.pivot, object.alpha, object.ref); + } + + /** + * Sets the given values for this object. + * @param x the new position in x direction + * @param y the new position in y direction + * @param angle the new angle + * @param scaleX the new scale in x direction + * @param scaleY the new scale in y direction + * @param pivotX the new pivot in x direction + * @param pivotY the new pivot in y direction + * @param alpha the new alpha value + * @param folder the new folder index + * @param file the new file index + */ + public void set(float x, float y, float angle, float scaleX, float scaleY, float pivotX, float pivotY, float alpha, int folder, int file){ + super.set(x, y, angle, scaleX, scaleY, pivotX, pivotY); + this.alpha = alpha; + this.ref.folder = folder; + this.ref.file = file; + } + + /** + * Sets the given values for this object. + * @param position the new position + * @param angle the new angle + * @param scale the new scale + * @param pivot the new pivot + * @param alpha the new alpha value + * @param fileRef the new file reference + */ + public void set(Point position, float angle, Point scale, Point pivot, float alpha, FileReference fileRef){ + this.set(position.x, position.y, angle, scale.x, scale.y, pivot.x, pivot.y, alpha , fileRef.folder, fileRef.file); + } + + public String toString(){ + return super.toString()+", pivot: "+pivot+", alpha: "+alpha+", reference: "+ref; + } + + } + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/TweenedAnimation.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/TweenedAnimation.java new file mode 100644 index 00000000..190ff6af --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/TweenedAnimation.java @@ -0,0 +1,220 @@ +package com.brashmonkey.spriter; + +import com.brashmonkey.spriter.Mainline.Key.BoneRef; +import com.brashmonkey.spriter.Mainline.Key.ObjectRef; +import com.brashmonkey.spriter.Timeline.Key.Bone; +import com.brashmonkey.spriter.Timeline.Key.Object; + +/** + * A tweened animation is responsible for updating itself based on two given animations. + * The values of the two given animations will get interpolated and save in this animation. + * When tweening two animations, you have to make sure that they have the same structure. + * The best result is achieved if bones of two different animations are named in the same way. + * There are still issues with sprites, which are hard to resolve since Spriter does not save them in a useful order or naming convention. + * @author Trixt0r + * + */ +public class TweenedAnimation extends Animation{ + + /** + * The weight of the interpolation. 0.5f is the default value. + * Values closer to 0.0f mean the first animation will have more influence. + */ + public float weight = .5f; + + /** + * Indicates when a sprite should be switched form the first animation object to the second one. + * A value closer to 0.0f means that the sprites of the second animation will be drawn. + */ + public float spriteThreshold = .5f; + + /** + * The curve which will tween the animations. + * The default type of the curve is {@link Curve.Type#Linear}. + */ + public final Curve curve; + + /** + * The entity the animations have be part of. + * Animations of two different entities can not be tweened. + */ + public final Entity entity; + private Animation anim1, anim2; + + /** + * The base animation an object or bone will get if it will not be tweened. + */ + public Animation baseAnimation; + BoneRef base = null; + + /** + * Indicates whether to tween sprites or not. Default value is false. + * Tweening sprites should be only enabled if they have exactly the same structure. + * If all animations are bone based and sprites only change their references it is not recommended to tween sprites. + */ + public boolean tweenSprites = false; + + /** + * Creates a tweened animation based on the given entity. + * @param entity the entity animations have to be part of + */ + public TweenedAnimation(Entity entity) { + super(new Mainline(0), -1, "__interpolatedAnimation__", 0, true, entity.getAnimationWithMostTimelines().timelines()); + this.entity = entity; + this.curve = new Curve(); + this.setUpTimelines(); + } + + /** + * Returns the current mainline key. + * @return the mainline key + */ + public Mainline.Key getCurrentKey(){ + return this.currentKey; + } + + @Override + public void update(int time, Bone root){ + super.currentKey = onFirstMainLine() ? anim1.currentKey: anim2.currentKey; + for(Timeline.Key timelineKey: this.unmappedTweenedKeys) + timelineKey.active = false; + if(base != null){//TODO: Sprites not working properly because of different timeline naming + Animation currentAnim = onFirstMainLine() ? anim1: anim2; + Animation baseAnim = baseAnimation == null ? (onFirstMainLine() ? anim1:anim2) : baseAnimation; + for(BoneRef ref: currentKey.boneRefs){ + Timeline timeline = baseAnim.getSimilarTimeline(currentAnim.getTimeline(ref.timeline)); + if(timeline == null) continue; + Timeline.Key key, mappedKey; + key = baseAnim.tweenedKeys[timeline.id]; + mappedKey = baseAnim.unmappedTweenedKeys[timeline.id]; + this.tweenedKeys[ref.timeline].active = key.active; + this.tweenedKeys[ref.timeline].object().set(key.object()); + this.unmappedTweenedKeys[ref.timeline].active = mappedKey.active; + this.unmapTimelineObject(ref.timeline, false,(ref.parent != null) ? + this.unmappedTweenedKeys[ref.parent.timeline].object(): root); + } + /*for(ObjectRef ref: baseAnim.currentKey.objectRefs){ + Timeline timeline = baseAnim.getTimeline(ref.timeline);//getSimilarTimeline(ref, tempTimelines); + if(timeline != null){ + //tempTimelines.addLast(timeline); + Timeline.Key key = baseAnim.tweenedKeys[timeline.id]; + Timeline.Key mappedKey = baseAnim.mappedTweenedKeys[timeline.id]; + Object obj = (Object) key.object(); + + this.tweenedKeys[ref.timeline].active = key.active; + ((Object)this.tweenedKeys[ref.timeline].object()).set(obj); + this.mappedTweenedKeys[ref.timeline].active = mappedKey.active; + this.unmapTimelineObject(ref.timeline, true,(ref.parent != null) ? + this.mappedTweenedKeys[ref.parent.timeline].object(): root); + } + }*/ + //tempTimelines.clear(); + } + + this.tweenBoneRefs(base, root); + for(ObjectRef ref: super.currentKey.objectRefs){ + //if(ref.parent == base) + this.update(ref, root, 0); + } + } + + private void tweenBoneRefs(BoneRef base, Bone root){ + int startIndex = base == null ? -1 : base.id-1; + int length = super.currentKey.boneRefs.length; + for(int i = startIndex+1; i < length; i++){ + BoneRef ref = currentKey.boneRefs[i]; + if(base == ref || ref.parent == base) this.update(ref, root, 0); + if(base == ref.parent) this.tweenBoneRefs(ref, root); + } + } + + @Override + protected void update(BoneRef ref, Bone root, int time){ + boolean isObject = ref instanceof ObjectRef; + //Tween bone/object + Bone bone1 = null, bone2 = null, tweenTarget = null; + Timeline t1 = onFirstMainLine() ? anim1.getTimeline(ref.timeline) : anim1.getSimilarTimeline(anim2.getTimeline(ref.timeline)); + Timeline t2 = onFirstMainLine() ? anim2.getSimilarTimeline(t1) : anim2.getTimeline(ref.timeline); + Timeline targetTimeline = super.getTimeline(onFirstMainLine() ? t1.id:t2.id); + if(t1 != null) bone1 = anim1.tweenedKeys[t1.id].object(); + if(t2 != null) bone2 = anim2.tweenedKeys[t2.id].object(); + if(targetTimeline != null) tweenTarget = this.tweenedKeys[targetTimeline.id].object(); + if(isObject && (t2 == null || !tweenSprites)){ + if(!onFirstMainLine()) bone1 = bone2; + else bone2 = bone1; + } + if(bone2 != null && tweenTarget != null && bone1 != null){ + if(isObject) this.tweenObject((Object)bone1, (Object)bone2, (Object)tweenTarget, this.weight, this.curve); + else this.tweenBone(bone1, bone2, tweenTarget, this.weight, this.curve); + this.unmappedTweenedKeys[targetTimeline.id].active = true; + } + //Transform the bone relative to the parent bone or the root + if(this.unmappedTweenedKeys[ref.timeline].active){ + this.unmapTimelineObject(targetTimeline.id, isObject,(ref.parent != null) ? + this.unmappedTweenedKeys[ref.parent.timeline].object(): root); + } + } + + private void tweenBone(Bone bone1, Bone bone2, Bone target, float t, Curve curve){ + target.angle = curve.tweenAngle(bone1.angle, bone2.angle, t); + curve.tweenPoint(bone1.position, bone2.position, t, target.position); + curve.tweenPoint(bone1.scale, bone2.scale, t, target.scale); + curve.tweenPoint(bone1.pivot, bone2.pivot, t, target.pivot); + } + + private void tweenObject(Object object1, Object object2, Object target, float t, Curve curve){ + this.tweenBone(object1, object2, target, t, curve); + target.alpha = curve.tweenAngle(object1.alpha, object2.alpha, t); + target.ref.set(object1.ref); + } + + /** + * Returns whether the current mainline key is the one from the first animation or from the second one. + * @return true if the mainline key is the one from the first animation + */ + public boolean onFirstMainLine(){ + return this.weight < this.spriteThreshold; + } + + private void setUpTimelines(){ + Animation maxAnim = this.entity.getAnimationWithMostTimelines(); + int max = maxAnim.timelines(); + for(int i = 0; i < max; i++){ + Timeline t = new Timeline(i, maxAnim.getTimeline(i).name, maxAnim.getTimeline(i).objectInfo, 1); + addTimeline(t); + } + prepare(); + } + + /** + * Sets the animations to tween. + * @param animation1 the first animation + * @param animation2 the second animation + * @throws SpriterException if {@link #entity} does not contain one of the given animations. + */ + public void setAnimations(Animation animation1, Animation animation2){ + boolean areInterpolated = animation1 instanceof TweenedAnimation || animation2 instanceof TweenedAnimation; + if(animation1 == anim1 && animation2 == anim2) return; + if((!this.entity.containsAnimation(animation1) || !this.entity.containsAnimation(animation2)) && !areInterpolated) + throw new SpriterException("Both animations have to be part of the same entity!"); + this.anim1 = animation1; + this.anim2 = animation2; + } + + /** + * Returns the first animation. + * @return the first animation + */ + public Animation getFirstAnimation(){ + return this.anim1; + } + + /** + * Returns the second animation. + * @return the second animation + */ + public Animation getSecondAnimation(){ + return this.anim2; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/XmlReader.java b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/XmlReader.java new file mode 100644 index 00000000..4a298101 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/com/brashmonkey/spriter/XmlReader.java @@ -0,0 +1,688 @@ +package com.brashmonkey.spriter; + +import com.badlogic.gdx.utils.Array; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map.Entry; + +/** Lightweight XML parser. Supports a subset of XML features: elements, attributes, text, predefined entities, CDATA, mixed + * content. Namespaces are parsed as part of the element or attribute name. Prologs and doctypes are ignored. Only 8-bit character + * encodings are supported. Input is assumed to be well formed.
+ *
+ * The default behavior is to parse the XML into a DOM. Extends this class and override methods to perform event driven parsing. + * When this is done, the parse methods will return null. + * @author Nathan Sweet */ +public class XmlReader { + private final ArrayList elements = new ArrayList(8); + private Element root, current; + private final StringBuilder textBuffer = new StringBuilder(64); + + public Element parse (String xml) { + char[] data = xml.toCharArray(); + return parse(data, 0, data.length); + } + + public Element parse (Reader reader) throws IOException { + char[] data = new char[1024]; + int offset = 0; + while (true) { + int length = reader.read(data, offset, data.length - offset); + if (length == -1) break; + if (length == 0) { + char[] newData = new char[data.length * 2]; + System.arraycopy(data, 0, newData, 0, data.length); + data = newData; + } else + offset += length; + } + return parse(data, 0, offset); + } + + public Element parse (InputStream input) throws IOException { + return parse(new InputStreamReader(input, "ISO-8859-1")); + } + + @SuppressWarnings("unused") + public Element parse (char[] data, int offset, int length) { + int cs, p = offset, pe = length; + + int s = 0; + String attributeName = null; + boolean hasBody = false; + + // line 3 "XmlReader.java" + { + cs = xml_start; + } + + // line 7 "XmlReader.java" + { + int _klen; + int _trans = 0; + int _acts; + int _nacts; + int _keys; + int _goto_targ = 0; + + _goto: + while (true) { + switch (_goto_targ) { + case 0: + if (p == pe) { + _goto_targ = 4; + continue _goto; + } + if (cs == 0) { + _goto_targ = 5; + continue _goto; + } + case 1: + _match: + do { + _keys = _xml_key_offsets[cs]; + _trans = _xml_index_offsets[cs]; + _klen = _xml_single_lengths[cs]; + if (_klen > 0) { + int _lower = _keys; + int _mid; + int _upper = _keys + _klen - 1; + while (true) { + if (_upper < _lower) break; + + _mid = _lower + ((_upper - _lower) >> 1); + if (data[p] < _xml_trans_keys[_mid]) + _upper = _mid - 1; + else if (data[p] > _xml_trans_keys[_mid]) + _lower = _mid + 1; + else { + _trans += (_mid - _keys); + break _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _xml_range_lengths[cs]; + if (_klen > 0) { + int _lower = _keys; + int _mid; + int _upper = _keys + (_klen << 1) - 2; + while (true) { + if (_upper < _lower) break; + + _mid = _lower + (((_upper - _lower) >> 1) & ~1); + if (data[p] < _xml_trans_keys[_mid]) + _upper = _mid - 2; + else if (data[p] > _xml_trans_keys[_mid + 1]) + _lower = _mid + 2; + else { + _trans += ((_mid - _keys) >> 1); + break _match; + } + } + _trans += _klen; + } + } while (false); + + _trans = _xml_indicies[_trans]; + cs = _xml_trans_targs[_trans]; + + if (_xml_trans_actions[_trans] != 0) { + _acts = _xml_trans_actions[_trans]; + _nacts = (int)_xml_actions[_acts++]; + while (_nacts-- > 0) { + switch (_xml_actions[_acts++]) { + case 0: + // line 80 "XmlReader.rl" + { + s = p; + } + break; + case 1: + // line 81 "XmlReader.rl" + { + char c = data[s]; + if (c == '?' || c == '!') { + if (data[s + 1] == '[' && // + data[s + 2] == 'C' && // + data[s + 3] == 'D' && // + data[s + 4] == 'A' && // + data[s + 5] == 'T' && // + data[s + 6] == 'A' && // + data[s + 7] == '[') { + s += 8; + p = s + 2; + while (data[p - 2] != ']' || data[p - 1] != ']' || data[p] != '>') + p++; + text(new String(data, s, p - s - 2)); + } else + while (data[p] != '>') + p++; + { + cs = 15; + _goto_targ = 2; + if (true) continue _goto; + } + } + hasBody = true; + open(new String(data, s, p - s)); + } + break; + case 2: + // line 105 "XmlReader.rl" + { + hasBody = false; + close(); + { + cs = 15; + _goto_targ = 2; + if (true) continue _goto; + } + } + break; + case 3: + // line 110 "XmlReader.rl" + { + close(); + { + cs = 15; + _goto_targ = 2; + if (true) continue _goto; + } + } + break; + case 4: + // line 114 "XmlReader.rl" + { + if (hasBody) { + cs = 15; + _goto_targ = 2; + if (true) continue _goto; + } + } + break; + case 5: + // line 117 "XmlReader.rl" + { + attributeName = new String(data, s, p - s); + } + break; + case 6: + // line 120 "XmlReader.rl" + { + attribute(attributeName, new String(data, s, p - s)); + } + break; + case 7: + // line 123 "XmlReader.rl" + { + int end = p; + while (end != s) { + switch (data[end - 1]) { + case ' ': + case '\t': + case '\n': + case '\r': + end--; + continue; + } + break; + } + int current = s; + boolean entityFound = false; + while (current != end) { + if (data[current++] != '&') continue; + int entityStart = current; + while (current != end) { + if (data[current++] != ';') continue; + textBuffer.append(data, s, entityStart - s - 1); + String name = new String(data, entityStart, current - entityStart - 1); + String value = entity(name); + textBuffer.append(value != null ? value : name); + s = current; + entityFound = true; + break; + } + } + if (entityFound) { + if (s < end) textBuffer.append(data, s, end - s); + text(textBuffer.toString()); + textBuffer.setLength(0); + } else + text(new String(data, s, end - s)); + } + break; + // line 190 "XmlReader.java" + } + } + } + + case 2: + if (cs == 0) { + _goto_targ = 5; + continue _goto; + } + if (++p != pe) { + _goto_targ = 1; + continue _goto; + } + case 4: + case 5: + } + break; + } + } + + // line 170 "XmlReader.rl" + + if (p < pe) { + int lineNumber = 1; + for (int i = 0; i < p; i++) + if (data[i] == '\n') lineNumber++; + throw new SpriterException("Error parsing XML on line " + lineNumber + " near: " + + new String(data, p, Math.min(32, pe - p))); + } else if (!elements.isEmpty()) { + Element element = elements.get(elements.size()-1); + elements.clear(); + throw new SpriterException("Error parsing XML, unclosed element: " + element.getName()); + } + Element root = this.root; + this.root = null; + return root; + } + + // line 210 "XmlReader.java" + private static byte[] init__xml_actions_0 () { + return new byte[] {0, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 2, 0, 6, 2, 1, 4, 2, 2, 4}; + } + + private static final byte _xml_actions[] = init__xml_actions_0(); + + private static byte[] init__xml_key_offsets_0 () { + return new byte[] {0, 0, 4, 9, 14, 20, 26, 30, 35, 36, 37, 42, 46, 50, 51, 52, 56, 57, 62, 67, 73, 79, 83, 88, 89, 90, 95, + 99, 103, 104, 108, 109, 110, 111, 112, 115}; + } + + private static final byte _xml_key_offsets[] = init__xml_key_offsets_0(); + + private static char[] init__xml_trans_keys_0 () { + return new char[] {32, 60, 9, 13, 32, 47, 62, 9, 13, 32, 47, 62, 9, 13, 32, 47, 61, 62, 9, 13, 32, 47, 61, 62, 9, 13, 32, + 61, 9, 13, 32, 34, 39, 9, 13, 34, 34, 32, 47, 62, 9, 13, 32, 62, 9, 13, 32, 62, 9, 13, 39, 39, 32, 60, 9, 13, 60, 32, + 47, 62, 9, 13, 32, 47, 62, 9, 13, 32, 47, 61, 62, 9, 13, 32, 47, 61, 62, 9, 13, 32, 61, 9, 13, 32, 34, 39, 9, 13, 34, + 34, 32, 47, 62, 9, 13, 32, 62, 9, 13, 32, 62, 9, 13, 60, 32, 47, 9, 13, 62, 62, 39, 39, 32, 9, 13, 0}; + } + + private static final char _xml_trans_keys[] = init__xml_trans_keys_0(); + + private static byte[] init__xml_single_lengths_0 () { + return new byte[] {0, 2, 3, 3, 4, 4, 2, 3, 1, 1, 3, 2, 2, 1, 1, 2, 1, 3, 3, 4, 4, 2, 3, 1, 1, 3, 2, 2, 1, 2, 1, 1, 1, 1, 1, + 0}; + } + + private static final byte _xml_single_lengths[] = init__xml_single_lengths_0(); + + private static byte[] init__xml_range_lengths_0 () { + return new byte[] {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, + 0}; + } + + private static final byte _xml_range_lengths[] = init__xml_range_lengths_0(); + + private static short[] init__xml_index_offsets_0 () { + return new short[] {0, 0, 4, 9, 14, 20, 26, 30, 35, 37, 39, 44, 48, 52, 54, 56, 60, 62, 67, 72, 78, 84, 88, 93, 95, 97, + 102, 106, 110, 112, 116, 118, 120, 122, 124, 127}; + } + + private static final short _xml_index_offsets[] = init__xml_index_offsets_0(); + + private static byte[] init__xml_indicies_0 () { + return new byte[] {0, 2, 0, 1, 2, 1, 1, 2, 3, 5, 6, 7, 5, 4, 9, 10, 1, 11, 9, 8, 13, 1, 14, 1, 13, 12, 15, 16, 15, 1, 16, + 17, 18, 16, 1, 20, 19, 22, 21, 9, 10, 11, 9, 1, 23, 24, 23, 1, 25, 11, 25, 1, 20, 26, 22, 27, 29, 30, 29, 28, 32, 31, + 30, 34, 1, 30, 33, 36, 37, 38, 36, 35, 40, 41, 1, 42, 40, 39, 44, 1, 45, 1, 44, 43, 46, 47, 46, 1, 47, 48, 49, 47, 1, + 51, 50, 53, 52, 40, 41, 42, 40, 1, 54, 55, 54, 1, 56, 42, 56, 1, 57, 1, 57, 34, 57, 1, 1, 58, 59, 58, 51, 60, 53, 61, + 62, 62, 1, 1, 0}; + } + + private static final byte _xml_indicies[] = init__xml_indicies_0(); + + private static byte[] init__xml_trans_targs_0 () { + return new byte[] {1, 0, 2, 3, 3, 4, 11, 34, 5, 4, 11, 34, 5, 6, 7, 6, 7, 8, 13, 9, 10, 9, 10, 12, 34, 12, 14, 14, 16, 15, + 17, 16, 17, 18, 30, 18, 19, 26, 28, 20, 19, 26, 28, 20, 21, 22, 21, 22, 23, 32, 24, 25, 24, 25, 27, 28, 27, 29, 31, 35, + 33, 33, 34}; + } + + private static final byte _xml_trans_targs[] = init__xml_trans_targs_0(); + + private static byte[] init__xml_trans_actions_0 () { + return new byte[] {0, 0, 0, 1, 0, 3, 3, 20, 1, 0, 0, 9, 0, 11, 11, 0, 0, 0, 0, 1, 17, 0, 13, 5, 23, 0, 1, 0, 1, 0, 0, 0, + 15, 1, 0, 0, 3, 3, 20, 1, 0, 0, 9, 0, 11, 11, 0, 0, 0, 0, 1, 17, 0, 13, 5, 23, 0, 0, 0, 7, 1, 0, 0}; + } + + private static final byte _xml_trans_actions[] = init__xml_trans_actions_0(); + + static final int xml_start = 1; + static final int xml_first_final = 34; + static final int xml_error = 0; + + static final int xml_en_elementBody = 15; + static final int xml_en_main = 1; + + // line 189 "XmlReader.rl" + + protected void open (String name) { + Element child = new Element(name, current); + Element parent = current; + if (parent != null) parent.addChild(child); + elements.add(child); + current = child; + } + + protected void attribute (String name, String value) { + current.setAttribute(name, value); + } + + protected String entity (String name) { + if (name.equals("lt")) return "<"; + if (name.equals("gt")) return ">"; + if (name.equals("amp")) return "&"; + if (name.equals("apos")) return "'"; + if (name.equals("quot")) return "\""; + return null; + } + + protected void text (String text) { + String existing = current.getText(); + current.setText(existing != null ? existing + text : text); + } + + protected void close () { + root = elements.get(elements.size()-1); + elements.remove(elements.size()-1); + current = !elements.isEmpty() ? elements.get(elements.size()-1) : null; + } + + static public class Element { + private final String name; + private HashMap attributes; + private ArrayList children; + private String text; + private Element parent; + + public Element (String name, Element parent) { + this.name = name; + this.parent = parent; + } + + public String getName () { + return name; + } + + public HashMap getAttributes () { + return attributes; + } + + /** @throws RuntimeException if the attribute was not found. */ + public String getAttribute (String name) { + if (attributes == null) throw new RuntimeException("Element " + name + " doesn't have attribute: " + name); + String value = attributes.get(name); + if (value == null) throw new RuntimeException("Element " + name + " doesn't have attribute: " + name); + return value; + } + + public String getAttribute (String name, String defaultValue) { + if (attributes == null) return defaultValue; + String value = attributes.get(name); + if (value == null) return defaultValue; + return value; + } + + public void setAttribute (String name, String value) { + if (attributes == null) attributes = new HashMap(8); + attributes.put(name, value); + } + + public int getChildCount () { + if (children == null) return 0; + return children.size(); + } + + /** @throws RuntimeException if the element has no children. */ + public Element getChild (int i) { + if (children == null) throw new RuntimeException("Element has no children: " + name); + return children.get(i); + } + + public void addChild (Element element) { + if (children == null) children = new ArrayList(8); + children.add(element); + } + + public String getText () { + return text; + } + + public void setText (String text) { + this.text = text; + } + + public void removeChild (int index) { + if (children != null) children.remove(index); + } + + public void removeChild (Element child) { + if (children != null) children.remove(child); + } + + public void remove () { + parent.removeChild(this); + } + + public Element getParent () { + return parent; + } + + public String toString () { + return toString(""); + } + + public String toString (String indent) { + StringBuilder buffer = new StringBuilder(128); + buffer.append(indent); + buffer.append('<'); + buffer.append(name); + if (attributes != null) { + for (Entry entry : attributes.entrySet()) { + buffer.append(' '); + buffer.append(entry.getKey()); + buffer.append("=\""); + buffer.append(entry.getKey()); + buffer.append('\"'); + } + } + if (children == null && (text == null || text.length() == 0)) + buffer.append("/>"); + else { + buffer.append(">\n"); + String childIndent = indent + '\t'; + if (text != null && text.length() > 0) { + buffer.append(childIndent); + buffer.append(text); + buffer.append('\n'); + } + if (children != null) { + for (Element child : children) { + buffer.append(child.toString(childIndent)); + buffer.append('\n'); + } + } + buffer.append(indent); + buffer.append("'); + } + return buffer.toString(); + } + + /** @param name the name of the child {@link Element} + * @return the first child having the given name or null, does not recurse */ + public Element getChildByName (String name) { + if (children == null) return null; + for (int i = 0; i < children.size(); i++) { + Element element = children.get(i); + if (element.name.equals(name)) return element; + } + return null; + } + + /** @param name the name of the child {@link Element} + * @return the first child having the given name or null, recurses */ + public Element getChildByNameRecursive (String name) { + if (children == null) return null; + for (int i = 0; i < children.size(); i++) { + Element element = children.get(i); + if (element.name.equals(name)) return element; + Element found = element.getChildByNameRecursive(name); + if (found != null) return found; + } + return null; + } + + /** @param name the name of the children + * @return the children with the given name or an empty {@link Array} */ + public ArrayList getChildrenByName (String name) { + ArrayList result = new ArrayList(); + if (children == null) return result; + for (int i = 0; i < children.size(); i++) { + Element child = children.get(i); + if (child.name.equals(name)) result.add(child); + } + return result; + } + + /** @param name the name of the children + * @return the children with the given name or an empty {@link Array} */ + public ArrayList getChildrenByNameRecursively (String name) { + ArrayList result = new ArrayList(); + getChildrenByNameRecursively(name, result); + return result; + } + + private void getChildrenByNameRecursively (String name, ArrayList result) { + if (children == null) return; + for (int i = 0; i < children.size(); i++) { + Element child = children.get(i); + if (child.name.equals(name)) result.add(child); + child.getChildrenByNameRecursively(name, result); + } + } + + /** @throws RuntimeException if the attribute was not found. */ + public float getFloatAttribute (String name) { + return Float.parseFloat(getAttribute(name)); + } + + public float getFloatAttribute (String name, float defaultValue) { + String value = getAttribute(name, null); + if (value == null) return defaultValue; + return Float.parseFloat(value); + } + + /** @throws RuntimeException if the attribute was not found. */ + public int getIntAttribute (String name) { + return Integer.parseInt(getAttribute(name)); + } + + public int getIntAttribute (String name, int defaultValue) { + String value = getAttribute(name, null); + if (value == null) return defaultValue; + return Integer.parseInt(value); + } + + /** @throws RuntimeException if the attribute was not found. */ + public boolean getBooleanAttribute (String name) { + return Boolean.parseBoolean(getAttribute(name)); + } + + public boolean getBooleanAttribute (String name, boolean defaultValue) { + String value = getAttribute(name, null); + if (value == null) return defaultValue; + return Boolean.parseBoolean(value); + } + + /** Returns the attribute value with the specified name, or if no attribute is found, the text of a child with the name. + * @throws RuntimeException if no attribute or child was not found. */ + public String get (String name) { + String value = get(name, null); + if (value == null) throw new RuntimeException("Element " + this.name + " doesn't have attribute or child: " + name); + return value; + } + + /** Returns the attribute value with the specified name, or if no attribute is found, the text of a child with the name. + * @throws RuntimeException if no attribute or child was not found. */ + public String get (String name, String defaultValue) { + if (attributes != null) { + String value = attributes.get(name); + if (value != null) return value; + } + Element child = getChildByName(name); + if (child == null) return defaultValue; + String value = child.getText(); + if (value == null) return defaultValue; + return value; + } + + /** Returns the attribute value with the specified name, or if no attribute is found, the text of a child with the name. + * @throws RuntimeException if no attribute or child was not found. */ + public int getInt (String name) { + String value = get(name, null); + if (value == null) throw new RuntimeException("Element " + this.name + " doesn't have attribute or child: " + name); + return Integer.parseInt(value); + } + + /** Returns the attribute value with the specified name, or if no attribute is found, the text of a child with the name. + * @throws RuntimeException if no attribute or child was not found. */ + public int getInt (String name, int defaultValue) { + String value = get(name, null); + if (value == null) return defaultValue; + return Integer.parseInt(value); + } + + /** Returns the attribute value with the specified name, or if no attribute is found, the text of a child with the name. + * @throws RuntimeException if no attribute or child was not found. */ + public float getFloat (String name) { + String value = get(name, null); + if (value == null) throw new RuntimeException("Element " + this.name + " doesn't have attribute or child: " + name); + return Float.parseFloat(value); + } + + /** Returns the attribute value with the specified name, or if no attribute is found, the text of a child with the name. + * @throws RuntimeException if no attribute or child was not found. */ + public float getFloat (String name, float defaultValue) { + String value = get(name, null); + if (value == null) return defaultValue; + return Float.parseFloat(value); + } + + /** Returns the attribute value with the specified name, or if no attribute is found, the text of a child with the name. + * @throws RuntimeException if no attribute or child was not found. */ + public boolean getBoolean (String name) { + String value = get(name, null); + if (value == null) throw new RuntimeException("Element " + this.name + " doesn't have attribute or child: " + name); + return Boolean.parseBoolean(value); + } + + /** Returns the attribute value with the specified name, or if no attribute is found, the text of a child with the name. + * @throws RuntimeException if no attribute or child was not found. */ + public boolean getBoolean (String name, boolean defaultValue) { + String value = get(name, null); + if (value == null) return defaultValue; + return Boolean.parseBoolean(value); + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/HyperLap2D.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/HyperLap2D.java new file mode 100644 index 00000000..b985a7e8 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/HyperLap2D.java @@ -0,0 +1,8 @@ +package games.rednblack.editor.renderer; + +import java.lang.annotation.Retention; +import static java.lang.annotation.RetentionPolicy.*; + +public @Retention(RUNTIME) @interface HyperLap2D { + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/SceneLoader.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/SceneLoader.java new file mode 100644 index 00000000..d328fa2a --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/SceneLoader.java @@ -0,0 +1,423 @@ +package games.rednblack.editor.renderer; + +import box2dLight.BlendFunc; +import box2dLight.DirectionalLight; +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.Engine; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.EntityListener; +import com.badlogic.ashley.utils.ImmutableArray; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.World; +import com.badlogic.gdx.utils.Scaling; +import com.badlogic.gdx.utils.reflect.ClassReflection; +import com.badlogic.gdx.utils.reflect.ReflectionException; +import com.badlogic.gdx.utils.viewport.ScalingViewport; +import com.badlogic.gdx.utils.viewport.Viewport; +import games.rednblack.editor.renderer.commons.IExternalItemType; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.components.light.LightBodyComponent; +import games.rednblack.editor.renderer.components.light.LightObjectComponent; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; +import games.rednblack.editor.renderer.data.*; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.physics.PhysicsBodyLoader; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.resources.ResourceManager; +import games.rednblack.editor.renderer.scripts.IScript; +import games.rednblack.editor.renderer.systems.*; +import games.rednblack.editor.renderer.systems.action.ActionSystem; +import games.rednblack.editor.renderer.systems.render.HyperLap2dRenderer; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * SceneLoader is important part of runtime that utilizes provided + * IResourceRetriever (or creates default one shipped with runtime) in order to + * load entire scene data into viewable actors provides the functionality to get + * root actor of scene and load scenes. + */ +public class SceneLoader { + + private String curResolution = "orig"; + private SceneVO sceneVO; + private IResourceRetriever rm = null; + + public Engine engine = null; + public RayHandler rayHandler; + public World world; + public Entity rootEntity; + public DirectionalLight sceneDirectionalLight; + + public EntityFactory entityFactory; + + private float pixelsPerWU = 1; + + private HyperLap2dRenderer renderer; + private Entity root; + + public SceneLoader(World world, RayHandler rayHandler, boolean cullingEnabled) { + this.world = world; + this.rayHandler = rayHandler; + + ResourceManager rm = new ResourceManager(); + rm.initAllResources(); + this.rm = rm; + + this.engine = new Engine(); + initSceneLoader(cullingEnabled); + } + + public SceneLoader(IResourceRetriever rm, World world, RayHandler rayHandler, boolean cullingEnabled) { + this.world = world; + this.rayHandler = rayHandler; + this.engine = new Engine(); + this.rm = rm; + initSceneLoader(cullingEnabled); + } + + public SceneLoader() { + this(null, null, true); + } + + public SceneLoader(IResourceRetriever rm) { + this(rm, null, null, true); + } + + /** + * this method is called when rm has loaded all data + */ + private void initSceneLoader(boolean cullingEnabled) { + if (world == null) { + world = new World(new Vector2(0,-10), true); + } else { + PhysicsBodyLoader.getInstance().mul = 1; + } + + if (rayHandler == null) { + RayHandler.setGammaCorrection(true); + RayHandler.useDiffuseLight(true); + + rayHandler = new RayHandler(world); + rayHandler.setAmbientLight(1f, 1f, 1f, 1f); + rayHandler.setCulling(true); + rayHandler.setBlur(true); + rayHandler.setBlurNum(3); + rayHandler.setShadows(true); + } + + addSystems(cullingEnabled); + entityFactory = new EntityFactory(rayHandler, world, rm); + } + + public void setResolution(String resolutionName) { + ResolutionEntryVO resolution = getRm().getProjectVO().getResolution(resolutionName); + if(resolution != null) { + curResolution = resolutionName; + } + } + + + public SceneVO getSceneVO() { + return sceneVO; + } + + public SceneVO loadScene(String sceneName, Viewport viewport, boolean customLight) { + + // this has to be done differently. + engine.removeAllEntities(); + entityFactory.clean(); + + pixelsPerWU = rm.getProjectVO().pixelToWorld; + + sceneVO = rm.getSceneVO(sceneName); + world.setGravity(new Vector2(sceneVO.physicsPropertiesVO.gravityX, sceneVO.physicsPropertiesVO.gravityY)); + PhysicsSystem physicsSystem = engine.getSystem(PhysicsSystem.class); + if (physicsSystem != null) + physicsSystem.setPhysicsOn(sceneVO.physicsPropertiesVO.enabled); + + if(sceneVO.composite == null) { + sceneVO.composite = new CompositeVO(); + } + rootEntity = entityFactory.createRootEntity(sceneVO.composite, viewport); + engine.addEntity(rootEntity); + + if(sceneVO.composite != null) { + entityFactory.initAllChildren(engine, rootEntity, sceneVO.composite); + } + if (!customLight) { + setAmbientInfo(sceneVO); + } + + return sceneVO; + } + + public SceneVO loadScene(String sceneName, Viewport viewport) { + return loadScene(sceneName, viewport, false); + } + + public SceneVO loadScene(String sceneName) { + return loadScene(sceneName, false); + } + + public SceneVO loadScene(String sceneName, boolean customLight) { + ProjectInfoVO projectVO = rm.getProjectVO(); + Viewport viewport = new ScalingViewport(Scaling.stretch, (float)projectVO.originalResolution.width/ pixelsPerWU, (float)projectVO.originalResolution.height/ pixelsPerWU, new OrthographicCamera()); + return loadScene(sceneName, viewport, customLight); + } + + public void injectExternalItemType(IExternalItemType itemType) { + itemType.injectDependencies(rayHandler, world, rm); + itemType.injectMappers(); + entityFactory.addExternalFactory(itemType); + engine.addSystem(itemType.getSystem()); + renderer.addDrawableType(itemType); + } + + private void addSystems(boolean cullingEnabled) { + PhysicsBodyLoader.getInstance().setScaleFromPPWU(pixelsPerWU); + + ParticleSystem particleSystem = new ParticleSystem(); + LightSystem lightSystem = new LightSystem(); + lightSystem.setRayHandler(rayHandler); + SpriteAnimationSystem animationSystem = new SpriteAnimationSystem(); + LayerSystem layerSystem = new LayerSystem(); + PhysicsSystem physicsSystem = new PhysicsSystem(world); + CompositeSystem compositeSystem = new CompositeSystem(); + LabelSystem labelSystem = new LabelSystem(); + ScriptSystem scriptSystem = new ScriptSystem(); + ActionSystem actionSystem = new ActionSystem(); + BoundingBoxSystem boundingBoxSystem = new BoundingBoxSystem(); + CullingSystem cullingSystem = new CullingSystem(); + renderer = new HyperLap2dRenderer(new PolygonSpriteBatch(2000, createDefaultShader())); + renderer.setRayHandler(rayHandler); + //renderer.setBox2dWorld(world); + + engine.addSystem(animationSystem); + engine.addSystem(particleSystem); + engine.addSystem(layerSystem); + engine.addSystem(physicsSystem); + engine.addSystem(lightSystem); + engine.addSystem(compositeSystem); + engine.addSystem(labelSystem); + engine.addSystem(scriptSystem); + engine.addSystem(actionSystem); + + if (cullingEnabled) { + engine.addSystem(boundingBoxSystem); + engine.addSystem(cullingSystem); + } + + engine.addSystem(renderer); + + // additional + engine.addSystem(new ButtonSystem()); + + addEntityRemoveListener(); + } + + private void addEntityRemoveListener() { + engine.addEntityListener(new EntityListener() { + @Override + public void entityAdded(Entity entity) { + // TODO: Gev knows what to do. (do this for all entities) + + // mae sure we assign correct z-index here + /* + ZindexComponent zindexComponent = ComponentRetriever.get(entity, ZindexComponent.class); + ParentNodeComponent parentNodeComponent = ComponentRetriever.get(entity, ParentNodeComponent.class); + if (parentNodeComponent != null) { + NodeComponent nodeComponent = parentNodeComponent.parentEntity.getComponent(NodeComponent.class); + zindexComponent.setZIndex(nodeComponent.children.size); + zindexComponent.needReOrder = false; + }*/ + + // call init for a system + ScriptComponent scriptComponent = entity.getComponent(ScriptComponent.class); + if (scriptComponent != null) { + for (IScript script : scriptComponent.scripts) { + script.init(entity); + } + } + } + + @Override + public void entityRemoved(Entity entity) { + ParentNodeComponent parentComponent = ComponentRetriever.get(entity, ParentNodeComponent.class); + + if (parentComponent == null) { + return; + } + + Entity parentEntity = parentComponent.parentEntity; + NodeComponent parentNodeComponent = ComponentRetriever.get(parentEntity, NodeComponent.class); + parentNodeComponent.removeChild(entity); + + // check if composite and remove all children + NodeComponent nodeComponent = ComponentRetriever.get(entity, NodeComponent.class); + if (nodeComponent != null) { + // it is composite + for (Entity node : nodeComponent.children) { + engine.removeEntity(node); + } + } + + //check for physics + PhysicsBodyComponent physicsBodyComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class); + if (physicsBodyComponent != null && physicsBodyComponent.body != null) { + world.destroyBody(physicsBodyComponent.body); + } + + // check if it is light + LightObjectComponent lightObjectComponent = ComponentRetriever.get(entity, LightObjectComponent.class); + if(lightObjectComponent != null) { + lightObjectComponent.lightObject.remove(true); + } + + LightBodyComponent lightBodyComponent = ComponentRetriever.get(entity, LightBodyComponent.class); + if(lightBodyComponent != null && lightBodyComponent.lightObject != null) { + lightBodyComponent.lightObject.remove(true); + } + } + }); + } + + public Entity loadFromLibrary(String libraryName) { + ProjectInfoVO projectInfoVO = getRm().getProjectVO(); + CompositeItemVO compositeItemVO = projectInfoVO.libraryItems.get(libraryName); + + if(compositeItemVO != null) { + return entityFactory.createEntity(null, compositeItemVO); + } + + return null; + } + + public CompositeItemVO loadVoFromLibrary(String libraryName) { + ProjectInfoVO projectInfoVO = getRm().getProjectVO(); + CompositeItemVO compositeItemVO = projectInfoVO.libraryItems.get(libraryName); + + return compositeItemVO; + } + + public void addComponentsByTagName(String tagName, Class componentClass) { + ImmutableArray entities = engine.getEntities(); + for(Entity entity: entities) { + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + if(mainItemComponent.tags.contains(tagName)) { + try { + entity.add(ClassReflection.newInstance(componentClass)); + } catch (ReflectionException e) { + e.printStackTrace(); + } + } + } + } + + /** + * Sets ambient light to the one specified in scene from editor + * + * @param vo + * - Scene data file to invalidate + */ + public void setAmbientInfo(SceneVO vo) { + if (sceneDirectionalLight != null) { + sceneDirectionalLight.remove(); + sceneDirectionalLight = null; + } + if(!vo.lightsPropertiesVO.enabled) { + RayHandler.useDiffuseLight(true); + rayHandler.setAmbientLight(1f, 1f, 1f, 1f); + return; + } + RayHandler.useDiffuseLight(!vo.lightsPropertiesVO.lightType.equals("BRIGHT")); + + if (vo.lightsPropertiesVO.ambientColor != null) { + Color clr = new Color(vo.lightsPropertiesVO.ambientColor[0], vo.lightsPropertiesVO.ambientColor[1], + vo.lightsPropertiesVO.ambientColor[2], vo.lightsPropertiesVO.ambientColor[3]); + + if (vo.lightsPropertiesVO.lightType.equals("DIRECTIONAL")) { + Color lightColor = new Color(vo.lightsPropertiesVO.directionalColor[0], vo.lightsPropertiesVO.directionalColor[1], + vo.lightsPropertiesVO.directionalColor[2], vo.lightsPropertiesVO.directionalColor[3]); + sceneDirectionalLight = new DirectionalLight(rayHandler, vo.lightsPropertiesVO.directionalRays, + lightColor, vo.lightsPropertiesVO.directionalDegree); + } + rayHandler.setAmbientLight(clr); + rayHandler.setBlurNum(vo.lightsPropertiesVO.blurNum); + } + } + + + public EntityFactory getEntityFactory() { + return entityFactory; + } + + public IResourceRetriever getRm() { + return rm; + } + + public Engine getEngine() { + return engine; + } + + public Entity getRoot() { + return rootEntity; + } + + /** Returns a new instance of the default shader used by SpriteBatch for GL2 when no shader is specified. */ + static public ShaderProgram createDefaultShader () { + String vertexShader = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" // + + "attribute vec4 " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" // + + "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" // + + "uniform mat4 u_projTrans;\n" // + + "varying vec4 v_color;\n" // + + "varying vec2 v_texCoords;\n" // + + "\n" // + + "void main()\n" // + + "{\n" // + + " v_color = " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" // + + " v_color.a = v_color.a * (255.0/254.0);\n" // + + " v_texCoords = " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" // + + " gl_Position = u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" // + + "}\n"; + String fragmentShader = "#ifdef GL_ES\n" // + + "#define LOWP lowp\n" // + + "precision mediump float;\n" // + + "#else\n" // + + "#define LOWP \n" // + + "#endif\n" // + + "varying LOWP vec4 v_color;\n" // + + "varying vec2 v_texCoords;\n" // + + "uniform sampler2D u_texture;\n" // + + "uniform vec2 atlasCoord;\n" // + + "uniform vec2 atlasSize;\n" // + + "uniform int isRepeat;\n" // + + "void main()\n"// + + "{\n" // + + "vec4 textureSample = vec4(0.0,0.0,0.0,0.0);\n"// + + "if(isRepeat == 1)\n"// + + "{\n"// + + "textureSample = v_color * texture2D(u_texture, atlasCoord+mod(v_texCoords, atlasSize));\n"// + + "}\n"// + + "else\n"// + + "{\n"// + + "textureSample = v_color * texture2D(u_texture, v_texCoords);\n"// + + "}\n"// + + " gl_FragColor = textureSample;\n" // + + "}"; + + ShaderProgram shader = new ShaderProgram(vertexShader, fragmentShader); + if (!shader.isCompiled()) throw new IllegalArgumentException("Error compiling shader: " + shader.getLog()); + return shader; + } + + public Batch getBatch() { + return renderer.getBatch(); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/commons/IExternalItemType.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/commons/IExternalItemType.java new file mode 100644 index 00000000..d96b0b43 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/commons/IExternalItemType.java @@ -0,0 +1,39 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.commons; + +import box2dLight.RayHandler; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.factory.component.ComponentFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.systems.render.logic.Drawable; + +/** + * Created by azakhary on 7/20/2015. + */ +public interface IExternalItemType { + + public int getTypeId(); + public Drawable getDrawable(); + public IteratingSystem getSystem(); + public ComponentFactory getComponentFactory(); + public void injectMappers(); + public void injectDependencies(RayHandler rayHandler, World world, IResourceRetriever rm); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ActionComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ActionComponent.java new file mode 100644 index 00000000..3ff5a14e --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ActionComponent.java @@ -0,0 +1,12 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.systems.action.data.ActionData; + +/** + * Created by ZeppLondon on 10/13/2015. + */ +public class ActionComponent implements Component { + public Array dataArray = new Array(true, 0); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/BoundingBoxComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/BoundingBoxComponent.java new file mode 100644 index 00000000..f5342105 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/BoundingBoxComponent.java @@ -0,0 +1,34 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; + +public class BoundingBoxComponent implements Component { + + public Rectangle rectangle = new Rectangle(); + + public Vector2[] points = new Vector2[4]; + public float checksum; + + { + points[0] = new Vector2(); + points[1] = new Vector2(); + points[2] = new Vector2(); + points[3] = new Vector2(); + } + + /** + * Returns a bounding box for this box. + * + * @return the bounding box + */ + public Rectangle getBoundingRect() { + + rectangle.x = Math.min(Math.min(Math.min(points[0].x, points[1].x), points[2].x), points[3].x); + rectangle.width = Math.max(Math.max(Math.max(points[0].x, points[1].x), points[2].x), points[3].x) - rectangle.x; + rectangle.y = Math.min(Math.min(Math.min(points[0].y, points[1].y), points[2].y), points[3].y); + rectangle.height = Math.max(Math.max(Math.max(points[0].y, points[1].y), points[2].y), points[3].y) - rectangle.y; + return rectangle; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/CloneableComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/CloneableComponent.java new file mode 100644 index 00000000..28b0baa4 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/CloneableComponent.java @@ -0,0 +1,28 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.components; + +/** + * Created by azakhary on 6/3/2015. + * TODO: it's either reflection or this.. we got to decide + */ +public interface CloneableComponent { + CloneableComponent get(); + void set(CloneableComponent source); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/CompositeTransformComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/CompositeTransformComponent.java new file mode 100644 index 00000000..03579ca6 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/CompositeTransformComponent.java @@ -0,0 +1,17 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.math.Affine2; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Rectangle; + +public class CompositeTransformComponent implements Component { + public boolean automaticResize = true; + public boolean scissorsEnabled = false; + public boolean transform = false; + public final Affine2 worldTransform = new Affine2(); + public final Matrix4 computedTransform = new Matrix4(); + public final Matrix4 oldTransform = new Matrix4(); + public final Rectangle scissors = new Rectangle(); + public final Rectangle clipBounds = new Rectangle(); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/DimensionsComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/DimensionsComponent.java new file mode 100644 index 00000000..42c3cc53 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/DimensionsComponent.java @@ -0,0 +1,62 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.g2d.PolygonRegion; +import com.badlogic.gdx.graphics.g2d.PolygonSprite; +import com.badlogic.gdx.math.EarClippingTriangulator; +import com.badlogic.gdx.math.Polygon; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.data.ShapeVO; +import games.rednblack.editor.renderer.utils.PolygonUtils; + +public class DimensionsComponent implements Component { + public float width = 0; + public float height = 0; + + public Rectangle boundBox; + public Polygon polygon; + + public boolean hit(float x, float y){ + if(polygon != null) { + return polygon.contains(x, y); + } else if(boundBox != null) { + return (x >= boundBox.x && x < boundBox.x+boundBox.width && y >= boundBox.y && y < boundBox.y+boundBox.height); + } else { + return (x >= 0 && x < width && y >= 0 && y < height); + } + } + + public void setPolygon(PolygonComponent polygonComponent) { + Vector2[] verticesArray = PolygonUtils.mergeTouchingPolygonsToOne(polygonComponent.vertices); + float[] vertices = new float[verticesArray.length*2]; + for(int i = 0; i < verticesArray.length; i++) { + vertices[i*2] = (verticesArray[i].x); + vertices[i*2+1] = (verticesArray[i].y); + } + polygon = new Polygon(vertices); + } + + public void setFromShape(ShapeVO shape) { + Vector2 minPoint = new Vector2(); + Vector2 maxPoint = new Vector2(); + if(shape.polygons != null) { + for(int i = 0; i < shape.polygons.length; i++) { + for(int j = 0; j < shape.polygons[i].length; j++) { + if(i == 0 && j == 0) { + minPoint.x = shape.polygons[i][j].x; + minPoint.y = shape.polygons[i][j].y; + maxPoint.x = shape.polygons[i][j].x; + maxPoint.y = shape.polygons[i][j].y; + } + if(minPoint.x > shape.polygons[i][j].x) minPoint.x = shape.polygons[i][j].x; + if(minPoint.y > shape.polygons[i][j].y) minPoint.y = shape.polygons[i][j].y; + if(maxPoint.x < shape.polygons[i][j].x) maxPoint.x = shape.polygons[i][j].x; + if(maxPoint.y < shape.polygons[i][j].y) maxPoint.y = shape.polygons[i][j].y; + } + } + width = maxPoint.x - minPoint.x; + height = maxPoint.y - minPoint.y; + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/LayerMapComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/LayerMapComponent.java new file mode 100644 index 00000000..ca1019a4 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/LayerMapComponent.java @@ -0,0 +1,76 @@ +package games.rednblack.editor.renderer.components; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +import com.badlogic.ashley.core.Component; +import games.rednblack.editor.renderer.data.LayerItemVO; + +public class LayerMapComponent implements Component { + public boolean autoIndexing = true; + private ArrayList layers = new ArrayList(); + + private HashMap layerMap = new HashMap(); + + public void setLayers(ArrayList layers) { + this.layers = layers; + layerMap.clear(); + for (LayerItemVO vo : layers) { + layerMap.put(vo.layerName, vo); + } + } + + public LayerItemVO getLayer(String name) { + return layerMap.get(name); + } + + public int getIndexByName(String name) { + if(layerMap.containsKey(name)) { + return layers.indexOf(layerMap.get(name)); + } + + return 0; + } + + public boolean isVisible(String name) { + LayerItemVO vo = getLayer(name); + if (vo != null) { + return vo.isVisible; + } + + return true; + } + + public void addLayer(int index, LayerItemVO layerVo) { + layers.add(index, layerVo); + layerMap.put(layerVo.layerName, layerVo); + } + + public void addLayer(LayerItemVO layerVo) { + layers.add(layerVo); + layerMap.put(layerVo.layerName, layerVo); + } + + public ArrayList getLayers() { + return layers; + } + + public void deleteLayer(String layerName) { + layers.remove(getIndexByName(layerName)); + layerMap.remove(layerName); + } + + public void rename(String prevName, String newName) { + LayerItemVO vo = layerMap.get(prevName); + vo.layerName = newName; + layerMap.remove(prevName); + layerMap.put(newName, vo); + } + + public void swap(String source, String target) { + LayerItemVO sourceVO = getLayer(source); + LayerItemVO targetVO = getLayer(target); + Collections.swap(layers, layers.indexOf(sourceVO), layers.indexOf(targetVO)); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/MainItemComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/MainItemComponent.java new file mode 100644 index 00000000..7811a566 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/MainItemComponent.java @@ -0,0 +1,40 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.utils.CustomVariables; + +import java.util.HashSet; +import java.util.Set; + +public class MainItemComponent implements Component { + public int uniqueId = 0; + public String itemIdentifier = ""; + public String libraryLink = ""; + public Set tags = new HashSet(); + private String customVars = ""; + public CustomVariables customVariables = new CustomVariables(); + public int entityType; + public boolean visible = true; + + public void setCustomVars(String key, String value) { + customVariables.setVariable(key, value); + setCustomVarString(customVariables.saveAsString()); + } + + public void removeCustomVars(String key) { + customVariables.removeVariable(key); + setCustomVarString(customVariables.saveAsString()); + } + + public String getCustomVarString() { + return customVars; + } + + public void setCustomVarString(String vars) { + customVars = vars; + if (customVariables.getCount() == 0) { + customVariables.loadFromString(customVars); + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/NinePatchComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/NinePatchComponent.java new file mode 100644 index 00000000..53dfd2bf --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/NinePatchComponent.java @@ -0,0 +1,9 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.g2d.NinePatch; + +public class NinePatchComponent implements Component { + public String textureRegionName; + public NinePatch ninePatch; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/NodeComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/NodeComponent.java new file mode 100644 index 00000000..e2bfbcce --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/NodeComponent.java @@ -0,0 +1,17 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.SnapshotArray; + +public class NodeComponent implements Component { + public SnapshotArray children = new SnapshotArray(true, 1, Entity.class); + + public void removeChild(Entity entity) { + children.removeValue(entity, false); + } + + public void addChild(Entity entity) { + children.add(entity); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ParentNodeComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ParentNodeComponent.java new file mode 100644 index 00000000..15cbc9a6 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ParentNodeComponent.java @@ -0,0 +1,8 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.Entity; + +public class ParentNodeComponent implements Component { + public Entity parentEntity = null; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/PolygonComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/PolygonComponent.java new file mode 100644 index 00000000..3eeacdcc --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/PolygonComponent.java @@ -0,0 +1,52 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.math.Vector2; + +/** + * Created by azakhary on 7/2/2015. + */ +public class PolygonComponent implements Component { + public Vector2[][] vertices; + + public void makeRectangle(float width, float height) { + Vector2[] points = new Vector2[4]; + points[0] = new Vector2(0, 0); + points[1] = new Vector2(0, height); + points[2] = new Vector2(width, height); + points[3] = new Vector2(width, 0); + + vertices = new Vector2[1][4]; + vertices[0] = points; + } + + public void makeRectangle(float x, float y, float width, float height) // Overloaded Function to enable more flexibility when setting polygon + { + Vector2[] points = new Vector2[4]; + points[0] = new Vector2(x, y); + points[1] = new Vector2(x, y+height); + points[2] = new Vector2(x + width, y + height); + points[3] = new Vector2(x + width, y); + + vertices = new Vector2[1][4]; + vertices[0] = points; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/RemovableComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/RemovableComponent.java new file mode 100644 index 00000000..bd3f0a86 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/RemovableComponent.java @@ -0,0 +1,7 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; + +public interface RemovableComponent extends Component { + void onRemove(); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ScissorComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ScissorComponent.java new file mode 100644 index 00000000..7150b25b --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ScissorComponent.java @@ -0,0 +1,10 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; + +public class ScissorComponent implements Component { + public float scissorX; + public float scissorY; + public float scissorWidth; + public float scissorHeight; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ScriptComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ScriptComponent.java new file mode 100644 index 00000000..ab4eb4f2 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ScriptComponent.java @@ -0,0 +1,40 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.reflect.ClassReflection; +import com.badlogic.gdx.utils.reflect.ReflectionException; +import games.rednblack.editor.renderer.scripts.IScript; + +import java.util.Iterator; + +/** + * Created by azakhary on 6/19/2015. + */ +public class ScriptComponent implements Component { + + public Array scripts = new Array(); + + public void addScript(IScript script) { + scripts.add(script); + } + + public void addScript(String className) { + try { + IScript script = (IScript) ClassReflection.newInstance(ClassReflection.forName(className)); + addScript(script); + } catch (ReflectionException e) { + // well, if it's not there, then we don't care + } + } + + public void removeScript(Class className) { + Iterator i = scripts.iterator(); + while (i.hasNext()) { + IScript s = i.next(); + if(s.getClass().getName().equals(className)) { + i.remove(); + } + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ShaderComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ShaderComponent.java new file mode 100644 index 00000000..ae364802 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ShaderComponent.java @@ -0,0 +1,23 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; + +public class ShaderComponent implements Component { + public String shaderName; + private ShaderProgram shaderProgram = null; + + public void setShader(String name, ShaderProgram program) { + shaderName = name; + shaderProgram = program; + } + + public ShaderProgram getShader() { + return shaderProgram; + } + + public void clear() { + shaderName = null; + shaderProgram = null; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/SpineDataComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/SpineDataComponent.java new file mode 100644 index 00000000..d8816aad --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/SpineDataComponent.java @@ -0,0 +1,8 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; + +public class SpineDataComponent implements Component { + public String animationName = ""; + public String currentAnimationName = ""; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/TextureRegionComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/TextureRegionComponent.java new file mode 100644 index 00000000..85b0a4d9 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/TextureRegionComponent.java @@ -0,0 +1,34 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.g2d.PolygonRegion; +import com.badlogic.gdx.graphics.g2d.PolygonSprite; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.EarClippingTriangulator; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.utils.PolygonUtils; + +public class TextureRegionComponent implements Component { + public String regionName = ""; + public TextureRegion region = null; + public boolean isRepeat = false; + public boolean isPolygon = false; + + // optional + public PolygonSprite polygonSprite = null; + + public void setPolygonSprite(PolygonComponent polygonComponent, float pixelToWorld) { + Vector2[] verticesArray = PolygonUtils.mergeTouchingPolygonsToOne(polygonComponent.vertices); + float[] vertices = new float[verticesArray.length*2]; + for(int i = 0; i < verticesArray.length; i++) { + vertices[i*2] = verticesArray[i].x*pixelToWorld; + vertices[i*2+1] = verticesArray[i].y*pixelToWorld; + } + + EarClippingTriangulator triangulator = new EarClippingTriangulator(); + short[] triangles = triangulator.computeTriangles(vertices).toArray(); + + PolygonRegion polygonRegion = new PolygonRegion(region, vertices, triangles); + polygonSprite = new PolygonSprite(polygonRegion); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/TintComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/TintComponent.java new file mode 100644 index 00000000..8d1f98d9 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/TintComponent.java @@ -0,0 +1,8 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.Color; + +public class TintComponent implements Component { + public Color color = new Color(); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/TransformComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/TransformComponent.java new file mode 100644 index 00000000..b7e9253c --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/TransformComponent.java @@ -0,0 +1,50 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; + +public class TransformComponent implements Component { + public float x; + public float y; + public float scaleX = 1f; + public float scaleY = 1f; + public float rotation; + public float originX; + public float originY; + + private TransformComponent backup = null; + + public TransformComponent() { + + } + + public TransformComponent(TransformComponent component) { + x = component.x; + y = component.y; + scaleX = component.scaleX; + scaleY = component.scaleY; + rotation = component.rotation; + originX = component.originX; + originY = component.originY; + } + + public void disableTransform() { + backup = new TransformComponent(this); + x = 0; + y = 0; + scaleX = 1f; + scaleY = 1f; + rotation = 0; + } + + public void enableTransform() { + if(backup == null) return; + x = backup.x; + y = backup.y; + scaleX = backup.scaleX; + scaleY = backup.scaleY; + rotation = backup.rotation; + originX = backup.originX; + originY = backup.originY; + backup = null; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ViewPortComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ViewPortComponent.java new file mode 100644 index 00000000..b11df750 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ViewPortComponent.java @@ -0,0 +1,8 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.utils.viewport.Viewport; + +public class ViewPortComponent implements Component { + public Viewport viewPort; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ZIndexComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ZIndexComponent.java new file mode 100644 index 00000000..71ef94f3 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/ZIndexComponent.java @@ -0,0 +1,23 @@ +package games.rednblack.editor.renderer.components; + +import com.badlogic.ashley.core.Component; + +public class ZIndexComponent implements Component { + private int zIndex = 0; + public boolean needReOrder = false; + public String layerName = ""; + public int layerIndex; + + public int getZIndex() { + return zIndex; + } + + public void setZIndex(int zIndex) { + this.zIndex = zIndex; + needReOrder = true; + } + + public int getGlobalZIndex() { + return layerIndex + zIndex; + } +} \ No newline at end of file diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/additional/ButtonComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/additional/ButtonComponent.java new file mode 100644 index 00000000..7bb979e1 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/additional/ButtonComponent.java @@ -0,0 +1,47 @@ +package games.rednblack.editor.renderer.components.additional; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.utils.Array; + +/** + * Created by azakhary on 8/1/2015. + */ +public class ButtonComponent implements Component { + + public boolean isTouched = false; + + private Array listeners = new Array(); + + public interface ButtonListener { + public void touchUp(); + public void touchDown(); + public void clicked(); + } + + public void addListener(ButtonListener listener) { + listeners.add(listener); + } + + public void removeListener(ButtonListener listener) { + listeners.removeValue(listener, true); + } + + public void clearListeners() { + listeners.clear(); + } + + public void setTouchState(boolean isTouched) { + if(!this.isTouched && isTouched) { + for(int i = 0; i < listeners.size; i++) { + listeners.get(i).touchDown(); + } + } + if(this.isTouched && !isTouched) { + for(int i = 0; i < listeners.size; i++) { + listeners.get(i).touchUp(); + listeners.get(i).clicked(); + } + } + this.isTouched = isTouched; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/label/LabelComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/label/LabelComponent.java new file mode 100644 index 00000000..19b6e458 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/label/LabelComponent.java @@ -0,0 +1,152 @@ +package games.rednblack.editor.renderer.components.label; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.BitmapFontCache; +import com.badlogic.gdx.graphics.g2d.GlyphLayout; +import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.utils.Align; +import com.badlogic.gdx.utils.StringBuilder; + +public class LabelComponent implements Component { + public LabelStyle style; + public final GlyphLayout layout = new GlyphLayout(); + public BitmapFontCache cache; + + public final StringBuilder text = new StringBuilder(); + public String fontName; + public int fontSize; + public int labelAlign = Align.center; + public int lineAlign = Align.center; + public boolean wrap; + public float fontScaleX = 1f; + public float fontScaleY = 1f; + + + public LabelComponent (CharSequence text, Skin skin) { + this(text, skin.get(LabelStyle.class)); + } + + public LabelComponent (CharSequence text, Skin skin, String styleName) { + this(text, skin.get(styleName, LabelStyle.class)); + } + + /** Creates a label, using a {@link LabelStyle} that has a BitmapFont with the specified name from the skin and the specified + * color. */ + public LabelComponent (CharSequence text, Skin skin, String fontName, Color color) { + this(text, new LabelStyle(skin.getFont(fontName), color)); + } + + /** Creates a label, using a {@link LabelStyle} that has a BitmapFont with the specified name and the specified color from the + * skin. */ + public LabelComponent (CharSequence text, Skin skin, String fontName, String colorName) { + this(text, new LabelStyle(skin.getFont(fontName), skin.getColor(colorName))); + } + + public LabelComponent (CharSequence text, LabelStyle style) { + if (text != null) this.text.append(text); + setStyle(style); + } + + public void setStyle (LabelStyle style) { + if (style == null) throw new IllegalArgumentException("style cannot be null."); + if (style.font == null) throw new IllegalArgumentException("Missing LabelStyle font."); + this.style = style; + cache = style.font.newFontCache(); + } + + public LabelStyle getStyle () { + return style; + } + + /** @param newText May be null, "" will be used. */ + public void setText (CharSequence newText) { + if (newText == null) newText = ""; + if (newText instanceof StringBuilder) { + if (text.equals(newText)) return; + text.setLength(0); + text.append((StringBuilder)newText); + } else { + if (textEquals(newText)) return; + text.setLength(0); + text.append(newText); + } + } + + public boolean textEquals (CharSequence other) { + int length = text.length; + char[] chars = text.chars; + if (length != other.length()) return false; + for (int i = 0; i < length; i++) + if (chars[i] != other.charAt(i)) return false; + return true; + } + + public StringBuilder getText () { + return text; + } + + public GlyphLayout getGlyphLayout () { + return layout; + } + + /** If false, the text will only wrap where it contains newlines (\n). The preferred size of the label will be the text bounds. + * If true, the text will word wrap using the width of the label. The preferred width of the label will be 0, it is expected + * that the something external will set the width of the label. Wrapping will not occur when ellipsis is true. Default is + * false. + *

+ * When wrap is enabled, the label's preferred height depends on the width of the label. In some cases the parent of the label + * will need to layout twice: once to set the width of the label and a second time to adjust to the label's new preferred + * height. */ + public void setWrap (boolean wrap) { + this.wrap = wrap; + } + + /** @param alignment Aligns each line of text horizontally and all the text vertically. + * @see Align */ + public void setAlignment (int alignment) { + setAlignment(alignment, alignment); + } + + /** @param labelAlign Aligns all the text with the label widget. + * @param lineAlign Aligns each line of text (left, right, or center). + * @see Align */ + public void setAlignment (int labelAlign, int lineAlign) { + this.labelAlign = labelAlign; + + if ((lineAlign & Align.left) != 0) + this.lineAlign = Align.left; + else if ((lineAlign & Align.right) != 0) + this.lineAlign = Align.right; + else + this.lineAlign = Align.center; + } + + public void setFontScale (float fontScale) { + this.fontScaleX = fontScale; + this.fontScaleY = fontScale; + } + + public void setFontScale (float fontScaleX, float fontScaleY) { + this.fontScaleX = fontScaleX; + this.fontScaleY = fontScaleY; + } + + public float getFontScaleX () { + return fontScaleX; + } + + public void setFontScaleX (float fontScaleX) { + this.fontScaleX = fontScaleX; + } + + public float getFontScaleY () { + return fontScaleY; + } + + public void setFontScaleY (float fontScaleY) { + this.fontScaleY = fontScaleY; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/light/LightBodyComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/light/LightBodyComponent.java new file mode 100644 index 00000000..fa9dcd07 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/light/LightBodyComponent.java @@ -0,0 +1,38 @@ +package games.rednblack.editor.renderer.components.light; + +import box2dLight.ChainLight; +import games.rednblack.editor.renderer.components.RemovableComponent; + +public class LightBodyComponent implements RemovableComponent { + + public float[] color; + public int rays; + public float distance; + public int rayDirection; + public float softnessLength; + public boolean isStatic; + public boolean isXRay; + public boolean isSoft; + public boolean isActive; + + public ChainLight lightObject; + public boolean needToRefreshLight = false; + + public LightBodyComponent() { + color = new float[]{1f, 1f, 1f, 1f}; + rays = 3; + distance = 30; + rayDirection = 1; + softnessLength = 1f; + isStatic = false; + isXRay = false; + isSoft = true; + isActive = true; + } + + @Override + public void onRemove() { + lightObject.remove(); + lightObject = null; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/light/LightObjectComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/light/LightObjectComponent.java new file mode 100644 index 00000000..2d793be6 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/light/LightObjectComponent.java @@ -0,0 +1,50 @@ +package games.rednblack.editor.renderer.components.light; + +import box2dLight.ConeLight; +import box2dLight.Light; + +import box2dLight.PointLight; +import box2dLight.RayHandler; +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.Color; +import games.rednblack.editor.renderer.data.LightVO; +import games.rednblack.editor.renderer.data.LightVO.LightType; +import games.rednblack.editor.renderer.physics.PhysicsBodyLoader; + +public class LightObjectComponent implements Component { + private LightType type; + + public int rays = 12; + public float distance = 300; + public float directionDegree = 0; + public float coneDegree = 30; + public float softnessLength = 1f; + public boolean isStatic = true; + public boolean isXRay = true; + public Light lightObject = null; + public boolean isSoft = true; + public boolean isActive = true; + + public LightObjectComponent(LightType type) { + this.type = type; + } + + public LightType getType(){ + return type; + } + + public Light rebuildRays(RayHandler rayHandler) { + if (rayHandler == null) + return lightObject; + + lightObject.remove(); + + if (getType() == LightVO.LightType.POINT) { + lightObject = new PointLight(rayHandler, rays); + } else { + lightObject = new ConeLight(rayHandler, rays, Color.WHITE, 1, 0, 0, 0, 0); + } + + return lightObject; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/particle/ParticleComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/particle/ParticleComponent.java new file mode 100644 index 00000000..a5f50858 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/particle/ParticleComponent.java @@ -0,0 +1,26 @@ +package games.rednblack.editor.renderer.components.particle; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.g2d.ParticleEffect; + +public class ParticleComponent implements Component { + public String particleName = ""; + public ParticleEffect particleEffect; + public float worldMultiplyer = 1f; + private float scaleFactor = 1f; + + public void scaleEffect(float scale){ + scaleFactor = scale; + particleEffect.scaleEffect(scaleFactor*worldMultiplyer); + } + + public float getScaleFactor(){ + return scaleFactor; + } + + //please use this method to start effects for the scale to be applied + public void startEffect(){ + scaleEffect(scaleFactor); + particleEffect.start(); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/physics/PhysicsBodyComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/physics/PhysicsBodyComponent.java new file mode 100644 index 00000000..b5044f8e --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/physics/PhysicsBodyComponent.java @@ -0,0 +1,56 @@ +package games.rednblack.editor.renderer.components.physics; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Body; +import com.badlogic.gdx.physics.box2d.Filter; +import games.rednblack.editor.renderer.components.RemovableComponent; + +public class PhysicsBodyComponent implements RemovableComponent { + public int bodyType; + + public float mass; + public Vector2 centerOfMass; + public float rotationalInertia; + public float damping; + public float gravityScale; + + public boolean allowSleep; + public boolean awake; + public boolean bullet; + public boolean sensor; + + public float density; + public float friction; + public float restitution; + public Filter filter; + + public float centerX; + public float centerY; + + public Body body; + public boolean needToRefreshBody = false; + + public PhysicsBodyComponent() { + // putting default values + bodyType = 0; + mass = 1; + centerOfMass = new Vector2(0, 0); + rotationalInertia = 0; + damping = 0; + gravityScale = 0; + allowSleep = true; + sensor = false; + awake = true; + bullet = false; + density = 1; + friction = 1; + restitution = 0; + filter = new Filter(); + } + + @Override + public void onRemove() { + body.getWorld().destroyBody(body); + body = null; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/sprite/AnimationComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/sprite/AnimationComponent.java new file mode 100644 index 00000000..68a5fc5a --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/sprite/AnimationComponent.java @@ -0,0 +1,10 @@ +package games.rednblack.editor.renderer.components.sprite; + +import java.util.HashMap; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.g2d.Animation; + +public class AnimationComponent implements Component { + public HashMap animations = new HashMap(); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/sprite/SpriteAnimationComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/sprite/SpriteAnimationComponent.java new file mode 100644 index 00000000..c890312e --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/sprite/SpriteAnimationComponent.java @@ -0,0 +1,18 @@ +package games.rednblack.editor.renderer.components.sprite; + +import java.util.HashMap; +import java.util.Map; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.g2d.Animation; +import games.rednblack.editor.renderer.SceneLoader; +import games.rednblack.editor.renderer.data.FrameRange; + +public class SpriteAnimationComponent implements Component { + public String animationName = ""; + public int fps = 24; + public HashMap frameRangeMap = new HashMap(); + public String currentAnimation; + public Animation.PlayMode playMode = Animation.PlayMode.LOOP; + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/sprite/SpriteAnimationStateComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/sprite/SpriteAnimationStateComponent.java new file mode 100644 index 00000000..12d59c94 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/sprite/SpriteAnimationStateComponent.java @@ -0,0 +1,69 @@ +package games.rednblack.editor.renderer.components.sprite; + +import com.badlogic.ashley.core.Component; +import com.badlogic.gdx.graphics.g2d.Animation; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.data.FrameRange; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SpriteAnimationStateComponent implements Component { + public Array allRegions; + public Animation currentAnimation; + public float time = 0.0f; + + public boolean paused = false; + + public SpriteAnimationStateComponent(Array allRegions) { + this.allRegions = sortAndGetRegions(allRegions); + } + + public Animation get() { + return currentAnimation; + } + + public void set(SpriteAnimationComponent sac) { + set(sac.frameRangeMap.get(sac.currentAnimation), sac.fps, sac.playMode); + } + + public void set(FrameRange range, int fps, Animation.PlayMode playMode) { + Array textureRegions = new Array(range.endFrame - range.startFrame + 1); + for (int r = range.startFrame; r <= range.endFrame; r++) { + textureRegions.add(allRegions.get(r)); + } + currentAnimation = new Animation(1f/fps, textureRegions, playMode); + time = 0.0f; + } + + private Array sortAndGetRegions(Array regions) { + regions.sort(new SortRegionsComparator()); + + return regions; + } + + private class SortRegionsComparator implements Comparator { + @Override + public int compare(TextureAtlas.AtlasRegion o1, TextureAtlas.AtlasRegion o2) { + // int index1 = regNameToFrame(o1.name); + // int index2 = regNameToFrame(o2.name); + return o1.index < o2.index ? -1 : o1.index == o2.index ? 0 : 1; + } + } + + private int regNameToFrame(String name) { + final Pattern lastIntPattern = Pattern.compile("[^0-9]+([0-9]+)$"); + Matcher matcher = lastIntPattern.matcher(name); + if (matcher.find()) { + String someNumberStr = matcher.group(1); + return Integer.parseInt(someNumberStr); + } + throw new RuntimeException( + "Frame name should be something like this '*0001', but not " + + name + "."); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/spriter/SpriterComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/spriter/SpriterComponent.java new file mode 100644 index 00000000..ce85f563 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/spriter/SpriterComponent.java @@ -0,0 +1,21 @@ +package games.rednblack.editor.renderer.components.spriter; + +import java.util.ArrayList; + +import com.badlogic.ashley.core.Component; +import com.brashmonkey.spriter.Data; +import com.brashmonkey.spriter.Player; + +public class SpriterComponent implements Component { + public Player player; + public Data data; + public ArrayList animations = new ArrayList(); + public ArrayList entities = new ArrayList(); + public int currentEntityIndex = 0; + public int currentAnimationIndex; + + public int entity; + public int animation; + public String animationName = ""; + public float scale = 1f; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/spriter/SpriterDrawerComponent.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/spriter/SpriterDrawerComponent.java new file mode 100644 index 00000000..deca7a72 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/components/spriter/SpriterDrawerComponent.java @@ -0,0 +1,8 @@ +package games.rednblack.editor.renderer.components.spriter; + +import com.badlogic.ashley.core.Component; +import games.rednblack.editor.renderer.utils.LibGdxDrawer; + +public class SpriterDrawerComponent implements Component { + public LibGdxDrawer drawer; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ColorPrimitiveVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ColorPrimitiveVO.java new file mode 100644 index 00000000..a20dd395 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ColorPrimitiveVO.java @@ -0,0 +1,33 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.data; + +/** + * Created by azakhary on 10/21/2015. + */ +public class ColorPrimitiveVO extends MainItemVO { + + public ColorPrimitiveVO() { + super(); + } + + public ColorPrimitiveVO(ColorPrimitiveVO vo) { + super(vo); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/CompositeItemVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/CompositeItemVO.java new file mode 100644 index 00000000..522b1b86 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/CompositeItemVO.java @@ -0,0 +1,78 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Rectangle; +import games.rednblack.editor.renderer.components.CompositeTransformComponent; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +import java.util.ArrayList; + +public class CompositeItemVO extends MainItemVO { + + public CompositeVO composite; + + public float width; + public float height; + public boolean automaticResize = true; + public boolean scissorsEnabled = false; + + public CompositeItemVO() { + composite = new CompositeVO(); + } + + public CompositeItemVO(CompositeVO vo) { + composite = new CompositeVO(vo); + } + + public CompositeItemVO(CompositeItemVO vo) { + super(vo); + composite = new CompositeVO(vo.composite); + } + + public void update(CompositeItemVO vo) { + composite = new CompositeVO(vo.composite); + } + + public CompositeItemVO clone() { + CompositeItemVO tmp = new CompositeItemVO(); + tmp.composite = composite; + tmp.itemName = itemName; + tmp.layerName = layerName; + tmp.rotation = rotation; + tmp.tint = tint; + tmp.x = x; + tmp.y = y; + tmp.zIndex = zIndex; + + tmp.width = width; + tmp.height = height; + + return tmp; + } + + @Override + public void loadFromEntity(Entity entity) { + super.loadFromEntity(entity); + + composite = new CompositeVO(); + composite.loadFromEntity(entity); + + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + CompositeTransformComponent compositeTransformComponent = ComponentRetriever.get(entity, CompositeTransformComponent.class); + + width = dimensionsComponent.width; + height = dimensionsComponent.height; + automaticResize = compositeTransformComponent.automaticResize; + scissorsEnabled = compositeTransformComponent.scissorsEnabled; + } + + public void cleanIds() { + uniqueId = -1; + ArrayList items = composite.getAllItems(); + for(MainItemVO subItem: items) { + subItem.uniqueId = -1; + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/CompositeVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/CompositeVO.java new file mode 100644 index 00000000..a6975260 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/CompositeVO.java @@ -0,0 +1,405 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.LayerMapComponent; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.components.NodeComponent; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.resources.FontSizePair; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; + +public class CompositeVO { + + public ArrayList sImages = new ArrayList(1); + public ArrayList sImage9patchs = new ArrayList(1); + public ArrayList sTextBox = new ArrayList(1); + public ArrayList sLabels = new ArrayList(1); + public ArrayList sComposites = new ArrayList(1); + public ArrayList sSelectBoxes = new ArrayList(1); + public ArrayList sParticleEffects = new ArrayList(1); + public ArrayList sLights = new ArrayList(1); + public ArrayList sSpineAnimations = new ArrayList(1); + public ArrayList sSpriteAnimations = new ArrayList(1); + public ArrayList sSpriterAnimations = new ArrayList(1); + public ArrayList sColorPrimitives = new ArrayList(1); + + public ArrayList layers = new ArrayList(); + + public CompositeVO() { + + } + + public CompositeVO(CompositeVO vo) { + + if (vo == null) return; + + update(vo); + } + + public void update(CompositeVO vo) { + clear(); + for (int i = 0; i < vo.sImages.size(); i++) { + sImages.add(new SimpleImageVO(vo.sImages.get(i))); + } + for (int i = 0; i < vo.sImage9patchs.size(); i++) { + sImage9patchs.add(new Image9patchVO(vo.sImage9patchs.get(i))); + } + for (int i = 0; i < vo.sTextBox.size(); i++) { + sTextBox.add(new TextBoxVO(vo.sTextBox.get(i))); + } + for (int i = 0; i < vo.sLabels.size(); i++) { + sLabels.add(new LabelVO(vo.sLabels.get(i))); + } + for (int i = 0; i < vo.sComposites.size(); i++) { + sComposites.add(new CompositeItemVO(vo.sComposites.get(i))); + } + for (int i = 0; i < vo.sSelectBoxes.size(); i++) { + sSelectBoxes.add(new SelectBoxVO(vo.sSelectBoxes.get(i))); + } + + for (int i = 0; i < vo.sParticleEffects.size(); i++) { + sParticleEffects.add(new ParticleEffectVO(vo.sParticleEffects.get(i))); + } + + for (int i = 0; i < vo.sLights.size(); i++) { + sLights.add(new LightVO(vo.sLights.get(i))); + } + + for (int i = 0; i < vo.sSpineAnimations.size(); i++) { + sSpineAnimations.add(new SpineVO(vo.sSpineAnimations.get(i))); + } + + for (int i = 0; i < vo.sSpriteAnimations.size(); i++) { + sSpriteAnimations.add(new SpriteAnimationVO(vo.sSpriteAnimations.get(i))); + } + + for (int i = 0; i < vo.sSpriterAnimations.size(); i++) { + sSpriterAnimations.add(new SpriterVO(vo.sSpriterAnimations.get(i))); + } + + for (int i = 0; i < vo.sColorPrimitives.size(); i++) { + sColorPrimitives.add(new ColorPrimitiveVO(vo.sColorPrimitives.get(i))); + } + + layers.clear(); + for (int i = 0; i < vo.layers.size(); i++) { + layers.add(new LayerItemVO(vo.layers.get(i))); + } + + } + + public void addItem(MainItemVO vo) { + String className = vo.getClass().getSimpleName(); + + if (className.equals("SimpleImageVO")) { + sImages.add((SimpleImageVO) vo); + } + if (className.equals("Image9patchVO")) { + sImage9patchs.add((Image9patchVO) vo); + } + if (className.equals("TextBoxVO")) { + sTextBox.add((TextBoxVO) vo); + } + if (className.equals("LabelVO")) { + sLabels.add((LabelVO) vo); + } + if (className.equals("CompositeItemVO")) { + sComposites.add((CompositeItemVO) vo); + } + if (className.equals("SelectBoxVO")) { + sSelectBoxes.add((SelectBoxVO) vo); + } + if (className.equals("ParticleEffectVO")) { + sParticleEffects.add((ParticleEffectVO) vo); + } + if (className.equals("LightVO")) { + sLights.add((LightVO) vo); + } + if (className.equals("SpineVO")) { + sSpineAnimations.add((SpineVO) vo); + } + if (className.equals("SpriterVO")) { + sSpriterAnimations.add((SpriterVO) vo); + } + if (className.equals("SpriteAnimationVO")) { + sSpriteAnimations.add((SpriteAnimationVO) vo); + } + if(className.equals("ColorPrimitiveVO")) { + sColorPrimitives.add((ColorPrimitiveVO) vo); + } + } + + public void removeItem(MainItemVO vo) { + String className = vo.getClass().getSimpleName(); + if (className.equals("SimpleImageVO")) { + sImages.remove((SimpleImageVO) vo); + } + if (className.equals("Image9patchVO")) { + sImage9patchs.remove((Image9patchVO) vo); + } + if (className.equals("TextBoxVO")) { + sTextBox.remove((TextBoxVO) vo); + } + if (className.equals("LabelVO")) { + sLabels.remove((LabelVO) vo); + } + if (className.equals("CompositeItemVO")) { + sComposites.remove((CompositeItemVO) vo); + } + if (className.equals("SelectBoxVO")) { + sSelectBoxes.remove((SelectBoxVO) vo); + } + if (className.equals("ParticleEffectVO")) { + sParticleEffects.remove((ParticleEffectVO) vo); + } + if (className.equals("LightVO")) { + sLights.remove((LightVO) vo); + } + if (className.equals("SpineVO")) { + sSpineAnimations.remove((SpineVO) vo); + } + if (className.equals("SpriteAnimationVO")) { + sSpriteAnimations.remove((SpriteAnimationVO) vo); + } + if (className.equals("SpriterVO")) { + sSpriterAnimations.remove((SpriterVO) vo); + } + if(className.equals("ColorPrimitiveVO")) { + sColorPrimitives.remove((ColorPrimitiveVO) vo); + } + } + + public void clear() { + sImages.clear(); + sTextBox.clear(); + sLabels.clear(); + sComposites.clear(); + sSelectBoxes.clear(); + sParticleEffects.clear(); + sLights.clear(); + sSpineAnimations.clear(); + sSpriteAnimations.clear(); + sSpriterAnimations.clear(); + sColorPrimitives.clear(); + } + + public boolean isEmpty() { + return sComposites.isEmpty() && + sImage9patchs.isEmpty() && + sImages.isEmpty() && + sSpriteAnimations.isEmpty() && + sLabels.isEmpty() && + sLights.isEmpty() && + sParticleEffects.isEmpty() && + sSpriteAnimations.isEmpty() && + sSpriterAnimations.isEmpty() && + sSpineAnimations.isEmpty() && + sSelectBoxes.isEmpty() && + sTextBox.isEmpty() && + sColorPrimitives.isEmpty(); + } + + public String[] getRecursiveParticleEffectsList() { + HashSet list = new HashSet(); + for (ParticleEffectVO sParticleEffect : sParticleEffects) { + list.add(sParticleEffect.particleName); + } + for (CompositeItemVO sComposite : sComposites) { + String[] additionalList = sComposite.composite.getRecursiveParticleEffectsList(); + Collections.addAll(list, additionalList); + } + String[] finalList = new String[list.size()]; + list.toArray(finalList); + + return finalList; + } + + public String[] getRecursiveSpineAnimationList() { + HashSet list = new HashSet(); + for (SpineVO sSpineAnimation : sSpineAnimations) { + list.add(sSpineAnimation.animationName); + } + for (CompositeItemVO sComposite : sComposites) { + String[] additionalList = sComposite.composite.getRecursiveSpineAnimationList(); + Collections.addAll(list, additionalList); + } + String[] finalList = new String[list.size()]; + list.toArray(finalList); + + return finalList; + } + + public String[] getRecursiveSpriteAnimationList() { + HashSet list = new HashSet(); + for (SpriteAnimationVO sSpriteAnimation : sSpriteAnimations) { + list.add(sSpriteAnimation.animationName); + } + for (CompositeItemVO sComposite : sComposites) { + String[] additionalList = sComposite.composite.getRecursiveSpriteAnimationList(); + Collections.addAll(list, additionalList); + } + String[] finalList = new String[list.size()]; + list.toArray(finalList); + + return finalList; + } + + public String[] getRecursiveSpriterAnimationList() { + HashSet list = new HashSet(); + for (SpriterVO sSpriterAnimation : sSpriterAnimations) { + list.add(sSpriterAnimation.animationName); + } + for (CompositeItemVO sComposite : sComposites) { + String[] additionalList = sComposite.composite.getRecursiveSpriterAnimationList(); + Collections.addAll(list, additionalList); + } + String[] finalList = new String[list.size()]; + list.toArray(finalList); + + return finalList; + } + + public FontSizePair[] getRecursiveFontList() { + HashSet list = new HashSet(); + for (LabelVO sLabel : sLabels) { + list.add(new FontSizePair(sLabel.style.isEmpty() ? "arial" : sLabel.style, sLabel.size == 0 ? 12 : sLabel.size)); + } + for (CompositeItemVO sComposite : sComposites) { + FontSizePair[] additionalList = sComposite.composite.getRecursiveFontList(); + Collections.addAll(list, additionalList); + } + FontSizePair[] finalList = new FontSizePair[list.size()]; + list.toArray(finalList); + + return finalList; + } + + public String[] getRecursiveShaderList() { + HashSet list = new HashSet(); + for (MainItemVO item : getAllItems()) { + if(item.shaderName != null && !item.shaderName.isEmpty()){ + list.add(item.shaderName); + } + } + String[] finalList = new String[list.size()]; + list.toArray(finalList); + return finalList; + } + + public ArrayList getAllItems() { + ArrayList itemsList = new ArrayList(); + itemsList = getAllItemsRecursive(itemsList, this); + + return itemsList; + } + + private ArrayList getAllItemsRecursive(ArrayList itemsList, CompositeVO compositeVo) { + for(MainItemVO vo: compositeVo.sImage9patchs) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sImages) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sLabels) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sLights) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sParticleEffects) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sSelectBoxes) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sSpineAnimations) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sSpriteAnimations) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sSpriterAnimations) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sTextBox) { + itemsList.add(vo); + } + for(MainItemVO vo: compositeVo.sColorPrimitives) { + itemsList.add(vo); + } + for(CompositeItemVO vo: compositeVo.sComposites) { + itemsList = getAllItemsRecursive(itemsList,vo.composite); + itemsList.add(vo); + } + + return itemsList; + } + + public void loadFromEntity(Entity compositeEntity) { + NodeComponent nodeComponent = compositeEntity.getComponent(NodeComponent.class); + ComponentMapper mainItemComponentMapper = ComponentMapper.getFor(MainItemComponent.class); + ComponentMapper layerMainItemComponentComponentMapper = ComponentMapper.getFor(LayerMapComponent.class); + + if(nodeComponent == null) return; + for(Entity entity: nodeComponent.children) { + int entityType = mainItemComponentMapper.get(entity).entityType; + if(entityType == EntityFactory.COMPOSITE_TYPE) { + CompositeItemVO vo = new CompositeItemVO(); + vo.loadFromEntity(entity); + sComposites.add(vo); + } + if(entityType == EntityFactory.IMAGE_TYPE) { + SimpleImageVO vo = new SimpleImageVO(); + vo.loadFromEntity(entity); + sImages.add(vo); + } + if(entityType == EntityFactory.NINE_PATCH) { + Image9patchVO vo = new Image9patchVO(); + vo.loadFromEntity(entity); + sImage9patchs.add(vo); + } + if(entityType == EntityFactory.LABEL_TYPE) { + LabelVO vo = new LabelVO(); + vo.loadFromEntity(entity); + sLabels.add(vo); + } + if(entityType == EntityFactory.PARTICLE_TYPE) { + ParticleEffectVO vo = new ParticleEffectVO(); + vo.loadFromEntity(entity); + sParticleEffects.add(vo); + } + if(entityType == EntityFactory.SPRITE_TYPE) { + SpriteAnimationVO vo = new SpriteAnimationVO(); + vo.loadFromEntity(entity); + sSpriteAnimations.add(vo); + } + if(entityType == EntityFactory.SPRITER_TYPE) { + SpriterVO vo = new SpriterVO(); + vo.loadFromEntity(entity); + sSpriterAnimations.add(vo); + } + if(entityType == EntityFactory.SPINE_TYPE) { + SpineVO vo = new SpineVO(); + vo.loadFromEntity(entity); + sSpineAnimations.add(vo); + } + if(entityType == EntityFactory.LIGHT_TYPE) { + LightVO vo = new LightVO(); + vo.loadFromEntity(entity); + sLights.add(vo); + } + if(entityType == EntityFactory.COLOR_PRIMITIVE) { + ColorPrimitiveVO vo = new ColorPrimitiveVO(); + vo.loadFromEntity(entity); + sColorPrimitives.add(vo); + } + } + + LayerMapComponent layerMapComponent = layerMainItemComponentComponentMapper.get(compositeEntity); + layers = layerMapComponent.getLayers(); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/CoreActorData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/CoreActorData.java new file mode 100644 index 00000000..f161b020 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/CoreActorData.java @@ -0,0 +1,16 @@ +package games.rednblack.editor.renderer.data; + +import games.rednblack.editor.renderer.utils.CustomVariables; + +import java.util.Map; + +/** + * Created by Osman on 20.08.2015. + * + */ +public class CoreActorData { + public String id = null; + public String[] tags = null; + public int layerIndex = 0; + public CustomVariables customVars = null; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/Essentials.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/Essentials.java new file mode 100644 index 00000000..5b5c2bbc --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/Essentials.java @@ -0,0 +1,16 @@ +package games.rednblack.editor.renderer.data; + +import box2dLight.RayHandler; + +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.resources.IResourceRetriever; + +public class Essentials { + + public RayHandler rayHandler; + //public SkeletonRenderer skeletonRenderer; + public IResourceRetriever rm; + public World world; + public boolean physicsStopped = false; + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/FrameRange.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/FrameRange.java new file mode 100644 index 00000000..776cbc37 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/FrameRange.java @@ -0,0 +1,20 @@ +package games.rednblack.editor.renderer.data; + +/** + * Created by CyberJoe on 6/18/2015. + */ +public class FrameRange { + public String name; + public int startFrame; + public int endFrame; + + public FrameRange() { + + } + + public FrameRange(String name, int startFrame, int endFrame) { + this.name = name; + this.startFrame = startFrame; + this.endFrame = endFrame; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/Image9patchVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/Image9patchVO.java new file mode 100644 index 00000000..424c1c33 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/Image9patchVO.java @@ -0,0 +1,36 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.NinePatchComponent; +import games.rednblack.editor.renderer.components.TextureRegionComponent; + +public class Image9patchVO extends MainItemVO { + + public String imageName = ""; + public float width = 0; + public float height = 0; + + public Image9patchVO() { + super(); + } + + public Image9patchVO(Image9patchVO vo) { + super(vo); + imageName = new String(vo.imageName); + width = vo.width; + height = vo.height; + } + + @Override + public void loadFromEntity(Entity entity) { + super.loadFromEntity(entity); + + NinePatchComponent ninePatchComponent = entity.getComponent(NinePatchComponent.class); + DimensionsComponent dimensionsComponent = entity.getComponent(DimensionsComponent.class); + imageName = ninePatchComponent.textureRegionName; + + width = dimensionsComponent.width; + height = dimensionsComponent.height; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LabelVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LabelVO.java new file mode 100644 index 00000000..6d6e4267 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LabelVO.java @@ -0,0 +1,48 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.label.LabelComponent; + +public class LabelVO extends MainItemVO { + + public String text = "Label"; + public String style = ""; + public int size; + public int align; + + public float width = 0; + public float height = 0; + + public boolean wrap = false; + + public LabelVO() { + super(); + } + + public LabelVO(LabelVO vo) { + super(vo); + text = new String(vo.text); + style = new String(vo.style); + size = vo.size; + align = vo.align; + width = vo.width; + height = vo.height; + wrap = vo.wrap; + } + + @Override + public void loadFromEntity(Entity entity) { + super.loadFromEntity(entity); + LabelComponent labelComponent = entity.getComponent(LabelComponent.class); + DimensionsComponent dimensionsComponent = entity.getComponent(DimensionsComponent.class); + text = labelComponent.getText().toString(); + style = labelComponent.fontName; + size = labelComponent.fontSize; + align = labelComponent.labelAlign; + wrap = labelComponent.wrap; + + width = dimensionsComponent.width; + height = dimensionsComponent.height; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LayerItemVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LayerItemVO.java new file mode 100644 index 00000000..ead67ce2 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LayerItemVO.java @@ -0,0 +1,31 @@ +package games.rednblack.editor.renderer.data; + +public class LayerItemVO { + + public String layerName = ""; + public boolean isLocked = false; + public boolean isVisible = false; + + public LayerItemVO() { + + } + + public LayerItemVO(String name) { + layerName = new String(name); + isVisible = true; + } + + public LayerItemVO(LayerItemVO vo) { + layerName = new String(vo.layerName); + isLocked = vo.isLocked; + isVisible = vo.isVisible; + } + + public static LayerItemVO createDefault() { + LayerItemVO layerItemVO = new LayerItemVO(); + layerItemVO.layerName = "Default"; + layerItemVO.isVisible = true; + return layerItemVO; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LightBodyDataVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LightBodyDataVO.java new file mode 100644 index 00000000..537f8914 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LightBodyDataVO.java @@ -0,0 +1,43 @@ +package games.rednblack.editor.renderer.data; + +import games.rednblack.editor.renderer.components.light.LightBodyComponent; + +public class LightBodyDataVO { + public float[] color; + public int rays; + public float distance; + public int rayDirection; + public float softnessLength; + public boolean isStatic; + public boolean isXRay; + public boolean isSoft; + public boolean isActive; + + public LightBodyDataVO() { + color = new float[]{1f, 1f, 1f, 1f}; + } + + public LightBodyDataVO(LightBodyDataVO vo){ + color = vo.color.clone(); + rays = vo.rays; + distance = vo.distance; + rayDirection = vo.rayDirection; + softnessLength = vo.softnessLength; + isStatic = vo.isStatic; + isXRay = vo.isXRay; + isSoft = vo.isSoft; + isActive = vo.isActive; + } + + public void loadFromComponent(LightBodyComponent lightComponent) { + color = lightComponent.color.clone(); + rays = lightComponent.rays; + distance = lightComponent.distance; + rayDirection = lightComponent.rayDirection; + softnessLength = lightComponent.softnessLength; + isStatic = lightComponent.isStatic; + isXRay = lightComponent.isXRay; + isSoft = lightComponent.isSoft; + isActive = lightComponent.isActive; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LightVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LightVO.java new file mode 100644 index 00000000..a541ed0a --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LightVO.java @@ -0,0 +1,59 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.light.LightObjectComponent; +import games.rednblack.editor.renderer.physics.PhysicsBodyLoader; + +public class LightVO extends MainItemVO { + //public int itemId = -1; + public static enum LightType {POINT, CONE} + public LightType type; + public int rays = 12; + public float distance = 300; + public float directionDegree = 0; + public float coneDegree = 30; + public float softnessLength = -1f; + public boolean isStatic = true; + public boolean isXRay = true; + public boolean isSoft = true; + public boolean isActive = true; + + public LightVO() { + tint = new float[4]; + tint[0] = 1f; + tint[1] = 1f; + tint[2] = 1f; + tint[3] = 1f; + } + + public LightVO(LightVO vo) { + super(vo); + type = vo.type; + rays = vo.rays; + distance = vo.distance; + directionDegree = vo.directionDegree; + coneDegree = vo.coneDegree; + isStatic = vo.isStatic; + isXRay = vo.isXRay; + softnessLength = vo.softnessLength; + isActive = vo.isActive; + isSoft = vo.isSoft; + } + + @Override + public void loadFromEntity(Entity entity) { + super.loadFromEntity(entity); + + LightObjectComponent lightObjectComponent = entity.getComponent(LightObjectComponent.class); + type = lightObjectComponent.getType(); + rays = lightObjectComponent.rays; + distance = lightObjectComponent.distance; + directionDegree = lightObjectComponent.directionDegree; + coneDegree = lightObjectComponent.coneDegree; + isStatic = lightObjectComponent.isStatic; + isXRay = lightObjectComponent.isXRay; + softnessLength = lightObjectComponent.softnessLength; + isSoft = lightObjectComponent.isSoft; + isActive = lightObjectComponent.isActive; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LightsPropertiesVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LightsPropertiesVO.java new file mode 100644 index 00000000..2f781a17 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/LightsPropertiesVO.java @@ -0,0 +1,32 @@ +package games.rednblack.editor.renderer.data; + +public class LightsPropertiesVO { + public boolean enabled; + public float[] ambientColor; + public int blurNum; + public String lightType; //DIFFUSE, DIRECTIONAL + + public int directionalRays; + public float directionalDegree; + public float[] directionalColor; + + public LightsPropertiesVO() { + blurNum = 3; + lightType = "DIFFUSE"; + enabled = false; + directionalRays = 12; + directionalDegree = 0; + ambientColor = new float[]{1f, 1f, 1f, 1f}; + directionalColor = new float[]{1f, 1f, 1f, 1f}; + } + + public LightsPropertiesVO(LightsPropertiesVO lightsPropertiesVO) { + this.enabled = lightsPropertiesVO.enabled; + this.blurNum = lightsPropertiesVO.blurNum; + this.lightType = lightsPropertiesVO.lightType; + this.directionalRays = lightsPropertiesVO.directionalRays; + this.directionalDegree = lightsPropertiesVO.directionalDegree; + this.ambientColor = lightsPropertiesVO.ambientColor.clone(); + this.directionalColor = lightsPropertiesVO.directionalColor.clone(); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/MainItemVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/MainItemVO.java new file mode 100644 index 00000000..8058642a --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/MainItemVO.java @@ -0,0 +1,124 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.components.light.LightBodyComponent; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; + +import java.util.Arrays; + + +public class MainItemVO { + public int uniqueId = -1; + public String itemIdentifier = ""; + public String itemName = ""; + public String[] tags = null; + public String customVars = ""; + public float x; + public float y; + public float scaleX = 1f; + public float scaleY = 1f; + public float originX = Float.NaN; + public float originY = Float.NaN; + public float rotation; + public int zIndex = 0; + public String layerName = ""; + public float[] tint = {1, 1, 1, 1}; + + public String shaderName = ""; + + public ShapeVO shape = null; + public PhysicsBodyDataVO physics = null; + public LightBodyDataVO light = null; + + public MainItemVO() { + + } + + public MainItemVO(MainItemVO vo) { + uniqueId = vo.uniqueId; + itemIdentifier = new String(vo.itemIdentifier); + itemName = new String(vo.itemName); + if(vo.tags != null) tags = Arrays.copyOf(vo.tags, vo.tags.length); + customVars = new String(vo.customVars); + x = vo.x; + y = vo.y; + rotation = vo.rotation; + zIndex = vo.zIndex; + layerName = new String(vo.layerName); + if(vo.tint != null) tint = Arrays.copyOf(vo.tint, vo.tint.length); + scaleX = vo.scaleX; + scaleY = vo.scaleY; + originX = vo.originX; + originY = vo.originY; + + if(vo.shape != null) { + shape = vo.shape.clone(); + } + + if(vo.physics != null){ + physics = new PhysicsBodyDataVO(vo.physics); + } + + if(vo.light != null){ + light = new LightBodyDataVO(vo.light); + } + } + + public void loadFromEntity(Entity entity) { + MainItemComponent mainItemComponent = entity.getComponent(MainItemComponent.class); + TransformComponent transformComponent = entity.getComponent(TransformComponent.class); + TintComponent tintComponent = entity.getComponent(TintComponent.class); + ZIndexComponent zindexComponent = entity.getComponent(ZIndexComponent.class); + + uniqueId = mainItemComponent.uniqueId; + itemIdentifier = mainItemComponent.itemIdentifier; + itemName = mainItemComponent.libraryLink; + tags = new String[mainItemComponent.tags.size()]; + tags = mainItemComponent.tags.toArray(tags); + customVars = mainItemComponent.getCustomVarString(); + + x = transformComponent.x; + y = transformComponent.y; + scaleX = transformComponent.scaleX; + scaleY = transformComponent.scaleY; + originX = transformComponent.originX; + originY = transformComponent.originY; + rotation = transformComponent.rotation; + + layerName = zindexComponent.layerName; + + tint = new float[4]; + tint[0] = tintComponent.color.r; + tint[1] = tintComponent.color.g; + tint[2] = tintComponent.color.b; + tint[3] = tintComponent.color.a; + + zIndex = zindexComponent.getZIndex(); + + /** + * Secondary components + */ + PolygonComponent polygonComponent = entity.getComponent(PolygonComponent.class); + if(polygonComponent != null && polygonComponent.vertices != null) { + shape = new ShapeVO(); + shape.polygons = polygonComponent.vertices; + } + PhysicsBodyComponent physicsComponent = entity.getComponent(PhysicsBodyComponent.class); + if(physicsComponent != null) { + physics = new PhysicsBodyDataVO(); + physics.loadFromComponent(physicsComponent); + } + + LightBodyComponent lightBodyComponent = entity.getComponent(LightBodyComponent.class); + if (lightBodyComponent != null) { + light = new LightBodyDataVO(); + light.loadFromComponent(lightBodyComponent); + } + + ShaderComponent shaderComponent = entity.getComponent(ShaderComponent.class); + if(shaderComponent != null && shaderComponent.shaderName != null) { + shaderName = shaderComponent.shaderName; + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ParticleEffectVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ParticleEffectVO.java new file mode 100644 index 00000000..af6ffeb1 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ParticleEffectVO.java @@ -0,0 +1,29 @@ +package games.rednblack.editor.renderer.data; + + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.particle.ParticleComponent; + +public class ParticleEffectVO extends MainItemVO { + public String particleName = ""; + public float particleWidth = 100; + public float particleHeight = 100; + //TODO add other ParticleEffect properties + + public ParticleEffectVO() { + super(); + } + + public ParticleEffectVO(ParticleEffectVO vo) { + super(vo); + particleName = new String(vo.particleName); + } + + @Override + public void loadFromEntity(Entity entity) { + super.loadFromEntity(entity); + + ParticleComponent particleComponent = entity.getComponent(ParticleComponent.class); + particleName = particleComponent.particleName; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/PhysicsBodyDataVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/PhysicsBodyDataVO.java new file mode 100644 index 00000000..d78213e3 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/PhysicsBodyDataVO.java @@ -0,0 +1,59 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; + +public class PhysicsBodyDataVO { + + public int bodyType = 0; + + public float mass; + public Vector2 centerOfMass; + public float rotationalInertia; + public float damping; + public float gravityScale; + public boolean allowSleep; + public boolean awake; + public boolean bullet; + public boolean sensor; + + public float density; + public float friction; + public float restitution; + + public PhysicsBodyDataVO(){ + centerOfMass = new Vector2(); + } + + public PhysicsBodyDataVO(PhysicsBodyDataVO vo){ + bodyType = vo.bodyType; + mass = vo.mass; + centerOfMass = vo.centerOfMass.cpy(); + rotationalInertia = vo.rotationalInertia; + damping = vo.damping; + gravityScale = vo.gravityScale; + allowSleep = vo.allowSleep; + sensor = vo.sensor; + awake = vo.awake; + bullet = vo.bullet; + density = vo.density; + friction = vo.friction; + restitution = vo.restitution; + } + + public void loadFromComponent(PhysicsBodyComponent physicsComponent) { + bodyType = physicsComponent.bodyType; + mass = physicsComponent.mass; + centerOfMass = physicsComponent.centerOfMass.cpy(); + rotationalInertia = physicsComponent.rotationalInertia; + damping = physicsComponent.damping; + gravityScale = physicsComponent.gravityScale; + allowSleep = physicsComponent.allowSleep; + sensor = physicsComponent.sensor; + awake = physicsComponent.awake; + bullet = physicsComponent.bullet; + density = physicsComponent.density; + friction = physicsComponent.friction; + restitution = physicsComponent.restitution; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/PhysicsPropertiesVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/PhysicsPropertiesVO.java new file mode 100644 index 00000000..aa58ba85 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/PhysicsPropertiesVO.java @@ -0,0 +1,25 @@ +package games.rednblack.editor.renderer.data; + +/** + * Created by sargis on 9/18/14. + */ +public class PhysicsPropertiesVO { + public float gravityX; + public float gravityY; + public float sleepVelocity; + public boolean enabled; + + public PhysicsPropertiesVO() { + gravityX = 0; + gravityY = 0; + sleepVelocity = 0; + enabled = false; + } + + public PhysicsPropertiesVO(PhysicsPropertiesVO physicsPropertiesVO) { + this.gravityX = physicsPropertiesVO.gravityX; + this.gravityY = physicsPropertiesVO.gravityY; + this.sleepVelocity = physicsPropertiesVO.sleepVelocity; + this.enabled = physicsPropertiesVO.enabled; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ProjectInfoVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ProjectInfoVO.java new file mode 100644 index 00000000..376df9b3 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ProjectInfoVO.java @@ -0,0 +1,40 @@ +package games.rednblack.editor.renderer.data; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; + +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter.OutputType; + +public class ProjectInfoVO { + + public int pixelToWorld = 1; + + public ResolutionEntryVO originalResolution = new ResolutionEntryVO(); + + public Array resolutions = new Array(); + public ArrayList scenes = new ArrayList(); + + public HashMap libraryItems = new HashMap(); + + public String constructJsonString() { + String str = ""; + Json json = new Json(); + json.setOutputType(OutputType.json); + str = json.toJson(this); + json.prettyPrint(str); + return str; + } + + public ResolutionEntryVO getResolution(String name) { + for (ResolutionEntryVO resolution : resolutions) { + if (resolution.name.equalsIgnoreCase(name)) { + return resolution; + } + } + return null; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ResolutionEntryVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ResolutionEntryVO.java new file mode 100644 index 00000000..f24b0847 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ResolutionEntryVO.java @@ -0,0 +1,40 @@ +package games.rednblack.editor.renderer.data; + +public class ResolutionEntryVO { + + public String name = ""; + + public int width; + public int height; + public int base; + + @Override + public String toString() { + if (width == 0 && height == 0) { + return name; + } + return width + "x" + height + " (" + name + ")"; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ResolutionEntryVO other = (ResolutionEntryVO) obj; + return other.name.equals(name); + } + + public float getMultiplier(ResolutionEntryVO originalResolution) { + float mul; + if(base == 0) { + mul = (float)originalResolution.width/width; + } else { + mul = (float)originalResolution.height/height; + } + return mul; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/RuntimeProjectVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/RuntimeProjectVO.java new file mode 100644 index 00000000..80c87554 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/RuntimeProjectVO.java @@ -0,0 +1,10 @@ +package games.rednblack.editor.renderer.data; + +import java.util.ArrayList; + +public class RuntimeProjectVO { + + public ResolutionEntryVO originalResolution = new ResolutionEntryVO(); + public ArrayList resolutions = new ArrayList(); + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/SceneVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/SceneVO.java new file mode 100644 index 00000000..f5b923d0 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/SceneVO.java @@ -0,0 +1,41 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter.OutputType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + + +public class SceneVO { + + public String sceneName = ""; + + public CompositeVO composite; + + public PhysicsPropertiesVO physicsPropertiesVO = new PhysicsPropertiesVO(); + public LightsPropertiesVO lightsPropertiesVO = new LightsPropertiesVO(); + + public ArrayList verticalGuides = new ArrayList(); + public ArrayList horizontalGuides = new ArrayList(); + + public SceneVO() { + + } + + public SceneVO(SceneVO vo) { + sceneName = new String(vo.sceneName); + composite = new CompositeVO(vo.composite); + physicsPropertiesVO = new PhysicsPropertiesVO(vo.physicsPropertiesVO); + lightsPropertiesVO = vo.lightsPropertiesVO; + } + + public String constructJsonString() { + String str = ""; + Json json = new Json(); + json.setOutputType(OutputType.json); + str = json.toJson(this); + return str; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/SelectBoxVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/SelectBoxVO.java new file mode 100644 index 00000000..62030702 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/SelectBoxVO.java @@ -0,0 +1,21 @@ +package games.rednblack.editor.renderer.data; + +import java.util.ArrayList; + +public class SelectBoxVO extends MainItemVO { + public ArrayList list = new ArrayList(); + public String style = ""; + public float width = 0; + public float height = 0; + + public SelectBoxVO() { + super(); + } + + public SelectBoxVO(SelectBoxVO vo) { + super(vo); + width = vo.width; + height = vo.height; + style = new String(vo.style); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ShapeVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ShapeVO.java new file mode 100644 index 00000000..50b4fd61 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/ShapeVO.java @@ -0,0 +1,37 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.gdx.math.Circle; +import com.badlogic.gdx.math.Vector2; + +public class ShapeVO { + public Vector2 [][] polygons; + public Circle[] circles; + + public ShapeVO clone() { + ShapeVO newVo = new ShapeVO(); + Vector2 [][] target = new Vector2[polygons.length][]; + + for (int i = 0; i < polygons.length; i++) { + target[i] = new Vector2[polygons[i].length]; + for(int j=0;j frameRangeMap = new ArrayList(); + public int playMode = 0; + + public SpriteAnimationVO() { + + } + + public SpriteAnimationVO(SpriteAnimationVO vo) { + super(vo); + animationName = vo.animationName; + fps = vo.fps; + frameRangeMap = vo.frameRangeMap; + } + + @Override + public void loadFromEntity(Entity entity) { + super.loadFromEntity(entity); + + SpriteAnimationComponent spriteAnimationComponent = entity.getComponent(SpriteAnimationComponent.class); + animationName = spriteAnimationComponent.animationName; + fps = spriteAnimationComponent.fps; + frameRangeMap = new ArrayList(); + for(FrameRange fr: spriteAnimationComponent.frameRangeMap.values()) { + frameRangeMap.add(fr); + } + currentAnimation = spriteAnimationComponent.currentAnimation; + if(spriteAnimationComponent.playMode == Animation.PlayMode.NORMAL) playMode = 0; + if(spriteAnimationComponent.playMode == Animation.PlayMode.REVERSED) playMode = 1; + if(spriteAnimationComponent.playMode == Animation.PlayMode.LOOP) playMode = 2; + if(spriteAnimationComponent.playMode == Animation.PlayMode.LOOP_REVERSED) playMode = 3; + if(spriteAnimationComponent.playMode == Animation.PlayMode.LOOP_PINGPONG) playMode = 4; + if(spriteAnimationComponent.playMode == Animation.PlayMode.LOOP_RANDOM) playMode = 5; + if(spriteAnimationComponent.playMode == Animation.PlayMode.NORMAL) playMode = 6; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/SpriterVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/SpriterVO.java new file mode 100644 index 00000000..d5f9bd3b --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/SpriterVO.java @@ -0,0 +1,36 @@ +package games.rednblack.editor.renderer.data; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.spriter.SpriterComponent; + +public class SpriterVO extends MainItemVO { + + public int entity; + public int animation; + public String animationName = ""; + + //wtf is this? + public float scale = 1f; + + public SpriterVO() { + + } + + public SpriterVO(SpriterVO vo) { + super(vo); + entity = vo.entity; + animation = vo.animation; + animationName = vo.animationName; + scale = vo.scale; + } + + @Override + public void loadFromEntity(Entity entity) { + super.loadFromEntity(entity); + + SpriterComponent spriterComponent = entity.getComponent(SpriterComponent.class); + animationName = spriterComponent.animationName; + animation = spriterComponent.animation; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/TextBoxVO.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/TextBoxVO.java new file mode 100644 index 00000000..773b2f9c --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/data/TextBoxVO.java @@ -0,0 +1,21 @@ +package games.rednblack.editor.renderer.data; + +public class TextBoxVO extends MainItemVO { + + public String defaultText = ""; + public float width = 0; + public float height = 0; + public String style = ""; + + public TextBoxVO() { + super(); + } + + public TextBoxVO(TextBoxVO vo) { + super(vo); + defaultText = new String(vo.defaultText); + width = vo.width; + height = vo.height; + style = new String(vo.style); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/EntityFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/EntityFactory.java new file mode 100644 index 00000000..2102188b --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/EntityFactory.java @@ -0,0 +1,306 @@ +package games.rednblack.editor.renderer.factory; + +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Engine; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.physics.box2d.World; +import com.badlogic.gdx.utils.viewport.Viewport; +import games.rednblack.editor.renderer.commons.IExternalItemType; +import games.rednblack.editor.renderer.components.CompositeTransformComponent; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.ViewPortComponent; +import games.rednblack.editor.renderer.data.*; +import games.rednblack.editor.renderer.factory.component.*; +import games.rednblack.editor.renderer.resources.IResourceRetriever; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; + +public class EntityFactory { + + public static final int IMAGE_TYPE = 1; + public static final int LABEL_TYPE = 2; + public static final int SPRITE_TYPE = 3; + public static final int SPINE_TYPE = 4; + public static final int SPRITER_TYPE = 5; + public static final int COMPOSITE_TYPE = 6; + public static final int PARTICLE_TYPE = 7; + public static final int LIGHT_TYPE = 8; + public static final int NINE_PATCH = 9; + public static final int COLOR_PRIMITIVE = 10; + + public RayHandler rayHandler; + public World world; + public IResourceRetriever rm = null; + + public EntityFactory( RayHandler rayHandler, World world, IResourceRetriever rm ) { + + this.rayHandler = rayHandler; + this.world = world; + this.rm = rm; + + compositeComponentFactory = new CompositeComponentFactory(rayHandler, world, rm); + lightComponentFactory = new LightComponentFactory(rayHandler, world, rm); + particleEffectComponentFactory = new ParticleEffectComponentFactory(rayHandler, world, rm); + simpleImageComponentFactory = new SimpleImageComponentFactory(rayHandler, world, rm); + spriteComponentFactory = new SpriteComponentFactory(rayHandler, world, rm); + spriterComponentFactory = new SpriterComponentFactory(rayHandler, world, rm); + labelComponentFactory = new LabelComponentFactory(rayHandler, world, rm); + ninePatchComponentFactory = new NinePatchComponentFactory(rayHandler, world, rm); + colorPrimitiveFactory = new ColorPrimitiveComponentFactory(rayHandler, world, rm); + + } + + protected ComponentFactory compositeComponentFactory, lightComponentFactory, particleEffectComponentFactory, + simpleImageComponentFactory, spriteComponentFactory, spriterComponentFactory, labelComponentFactory, ninePatchComponentFactory, colorPrimitiveFactory; + + private HashMap externalFactories = new HashMap(); + + private HashMap entities = new HashMap(); + + public ComponentFactory getCompositeComponentFactory() { + return compositeComponentFactory; + } + + public SpriteComponentFactory getSpriteComponentFactory() { + return (SpriteComponentFactory) spriteComponentFactory; + } + + public void addExternalFactory(IExternalItemType itemType) { + externalFactories.put(itemType.getTypeId(), itemType.getComponentFactory()); + } + + public Entity createEntity(Entity root, SimpleImageVO vo){ + + Entity entity = new Entity(); + + simpleImageComponentFactory.createComponents(root, entity, vo); + + postProcessEntity(entity); + + return entity; + } + + public Entity createEntity(Entity root, Image9patchVO vo){ + + Entity entity = new Entity(); + + ninePatchComponentFactory.createComponents(root, entity, vo); + + postProcessEntity(entity); + + return entity; + } + + public Entity createEntity(Entity root, LabelVO vo) { + + Entity entity = new Entity(); + + labelComponentFactory.createComponents(root, entity, vo); + + postProcessEntity(entity); + + return entity; + } + + public Entity createEntity(Entity root, ParticleEffectVO vo){ + + Entity entity = new Entity(); + + particleEffectComponentFactory.createComponents(root, entity, vo); + + postProcessEntity(entity); + + return entity; + } + + public Entity createEntity(Entity root, LightVO vo){ + + Entity entity = new Entity(); + + lightComponentFactory.createComponents(root, entity, vo); + + postProcessEntity(entity); + + return entity; + } + + public Entity createEntity(Entity root, SpineVO vo){ + + Entity entity = new Entity(); + + ComponentFactory factory = externalFactories.get(SPINE_TYPE); + if(factory != null) { + factory.createComponents(root, entity, vo); + postProcessEntity(entity); + } + + return entity; + } + + public Entity createEntity(Entity root, SpriteAnimationVO vo){ + + Entity entity = new Entity(); + + spriteComponentFactory.createComponents(root, entity, vo); + + postProcessEntity(entity); + + return entity; + } + + public Entity createEntity(Entity root, SpriterVO vo){ + + Entity entity = new Entity(); + + spriterComponentFactory.createComponents(root, entity, vo); + + postProcessEntity(entity); + + return entity; + } + + public Entity createEntity(Entity root, CompositeItemVO vo){ + + Entity entity = new Entity(); + + compositeComponentFactory.createComponents(root, entity, vo); + + postProcessEntity(entity); + + return entity; + } + + public Entity createEntity(Entity root, ColorPrimitiveVO vo){ + + Entity entity = new Entity(); + + colorPrimitiveFactory.createComponents(root, entity, vo); + + postProcessEntity(entity); + + return entity; + } + + public Entity createRootEntity(CompositeVO compositeVo, Viewport viewport){ + + CompositeItemVO vo = new CompositeItemVO(); + vo.composite = compositeVo; + + Entity entity = new Entity(); + + compositeComponentFactory.createComponents(null, entity, vo); +// CompositeTransformComponent compositeTransform = new CompositeTransformComponent(); + TransformComponent transform = new TransformComponent(); + + ViewPortComponent viewPortComponent = new ViewPortComponent(); + viewPortComponent.viewPort = viewport; + + viewPortComponent.viewPort.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true); + + entity.add(transform); + entity.add(viewPortComponent); + + postProcessEntity(entity); + + return entity; + } + + public Integer postProcessEntity(Entity entity) { + ComponentMapper mainItemComponentComponentMapper = ComponentMapper.getFor(MainItemComponent.class); + MainItemComponent mainItemComponent = mainItemComponentComponentMapper.get(entity); + if(mainItemComponent.uniqueId == -1) mainItemComponent.uniqueId = getFreeId(); + entities.put(mainItemComponent.uniqueId, entity); + + return mainItemComponent.uniqueId; + } + + private int getFreeId() { + if(entities == null || entities.size() == 0) return 1; + ArrayList ids = new ArrayList(entities.keySet()); + Collections.sort(ids); + for(int i = 1; i < ids.size(); i++) { + if(ids.get(i)-ids.get(i-1) > 1) { + return ids.get(i-1)+1; + } + } + return ids.get(ids.size()-1)+1; + } + + public Integer updateMap(Entity entity) { + ComponentMapper mainItemComponentComponentMapper = ComponentMapper.getFor(MainItemComponent.class); + MainItemComponent mainItemComponent = mainItemComponentComponentMapper.get(entity); + entities.put(mainItemComponent.uniqueId, entity); + + return mainItemComponent.uniqueId; + } + + public void initAllChildren(Engine engine, Entity entity, CompositeVO vo) { + for (int i = 0; i < vo.sImages.size(); i++) { + Entity child = createEntity(entity, vo.sImages.get(i)); + engine.addEntity(child); + } + + for (int i = 0; i < vo.sImage9patchs.size(); i++) { + Entity child = createEntity(entity, vo.sImage9patchs.get(i)); + engine.addEntity(child); + } + + for (int i = 0; i < vo.sLabels.size(); i++) { + Entity child = createEntity(entity, vo.sLabels.get(i)); + engine.addEntity(child); + } + + for (int i = 0; i < vo.sParticleEffects.size(); i++) { + Entity child = createEntity(entity, vo.sParticleEffects.get(i)); + engine.addEntity(child); + } + + for (int i = 0; i < vo.sLights.size(); i++) { + Entity child = createEntity(entity, vo.sLights.get(i)); + engine.addEntity(child); + } + + for (int i = 0; i < vo.sSpineAnimations.size(); i++) { + Entity child = createEntity(entity, vo.sSpineAnimations.get(i)); + engine.addEntity(child); + } + + for (int i = 0; i < vo.sSpriteAnimations.size(); i++) { + Entity child = createEntity(entity, vo.sSpriteAnimations.get(i)); + engine.addEntity(child); + } + + for (int i = 0; i < vo.sSpriterAnimations.size(); i++) { + Entity child = createEntity(entity, vo.sSpriterAnimations.get(i)); + engine.addEntity(child); + } + + for (int i = 0; i < vo.sColorPrimitives.size(); i++) { + Entity child = createEntity(entity, vo.sColorPrimitives.get(i)); + engine.addEntity(child); + } + + for (int i = 0; i < vo.sComposites.size(); i++) { + Entity child = createEntity(entity, vo.sComposites.get(i)); + engine.addEntity(child); + initAllChildren(engine, child, vo.sComposites.get(i).composite); + } + } + + public Entity getEntityByUniqueId(Integer id) { + return entities.get(id); + } + + + public void clean() { + entities.clear(); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/ColorPrimitiveComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/ColorPrimitiveComponentFactory.java new file mode 100644 index 00000000..2d45174c --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/ColorPrimitiveComponentFactory.java @@ -0,0 +1,89 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.RayHandler; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.PolygonComponent; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.data.SimpleImageVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by azakhary on 10/21/2015. + */ +public class ColorPrimitiveComponentFactory extends ComponentFactory { + + public ColorPrimitiveComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + } + + @Override + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + createCommonComponents(entity, vo, EntityFactory.COLOR_PRIMITIVE); + createParentNodeComponent(root, entity); + createNodeComponent(root, entity); + + createTextureRegionComponent(entity, vo); + + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + PolygonComponent polygonComponent = ComponentRetriever.get(entity, PolygonComponent.class); + dimensionsComponent.setPolygon(polygonComponent); + float ppwu = dimensionsComponent.width/textureRegionComponent.region.getRegionWidth(); + textureRegionComponent.setPolygonSprite(polygonComponent, 1f/ppwu); + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + component.setFromShape(vo.shape); + + entity.add(component); + + return component; + } + + protected TextureRegionComponent createTextureRegionComponent(Entity entity, MainItemVO vo) { + TextureRegionComponent component = new TextureRegionComponent(); + + Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); + pixmap.setColor(Color.WHITE); + pixmap.fill(); + Texture texture = new Texture(pixmap); + texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest); + TextureRegion textureRegion = new TextureRegion(texture); + component.region = textureRegion; + component.isRepeat = false; + component.isPolygon = true; + entity.add(component); + + return component; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/ComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/ComponentFactory.java new file mode 100644 index 00000000..a0257304 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/ComponentFactory.java @@ -0,0 +1,243 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.components.light.LightBodyComponent; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +import java.util.Arrays; +import java.util.HashSet; + +/** + * Created by azakhary on 5/22/2015. + */ +public abstract class ComponentFactory { + + protected IResourceRetriever rm; + protected RayHandler rayHandler; + protected World world; + + protected ComponentMapper nodeComponentMapper; + + public ComponentFactory() { + nodeComponentMapper = ComponentMapper.getFor(NodeComponent.class); + } + + public ComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + this(); + injectDependencies(rayHandler, world, rm); + } + + public void injectDependencies(RayHandler rayHandler, World world, IResourceRetriever rm) { + this.rayHandler = rayHandler; + this.world = world; + this.rm = rm; + } + + public abstract void createComponents(Entity root, Entity entity, MainItemVO vo); + + protected void createCommonComponents(Entity entity, MainItemVO vo, int entityType) { + DimensionsComponent dimensionsComponent = createDimensionsComponent(entity, vo); + createBoundingBoxComponent(entity, vo); + createMainItemComponent(entity, vo, entityType); + createTransformComponent(entity, vo, dimensionsComponent); + createTintComponent(entity, vo); + createZIndexComponent(entity, vo); + createScriptComponent(entity, vo); + createMeshComponent(entity, vo); + createPhysicsComponents(entity, vo); + createLightComponents(entity, vo); + createShaderComponent(entity, vo); + } + + protected BoundingBoxComponent createBoundingBoxComponent(Entity entity, MainItemVO vo) { + BoundingBoxComponent component = new BoundingBoxComponent(); + entity.add(component); + return component; + } + + protected ShaderComponent createShaderComponent(Entity entity, MainItemVO vo) { + if(vo.shaderName == null || vo.shaderName.isEmpty()){ + return null; + } + ShaderComponent component = new ShaderComponent(); + component.setShader(vo.shaderName, rm.getShaderProgram(vo.shaderName)); + entity.add(component); + return component; + } + + protected MainItemComponent createMainItemComponent(Entity entity, MainItemVO vo, int entityType) { + MainItemComponent component = new MainItemComponent(); + component.setCustomVarString(vo.customVars); + component.uniqueId = vo.uniqueId; + component.itemIdentifier = vo.itemIdentifier; + component.libraryLink = vo.itemName; + if(vo.tags != null) { + component.tags = new HashSet(Arrays.asList(vo.tags)); + } + component.entityType = entityType; + + entity.add(component); + + return component; + } + + protected TransformComponent createTransformComponent(Entity entity, MainItemVO vo, DimensionsComponent dimensionsComponent) { + TransformComponent component = new TransformComponent(); + component.rotation = vo.rotation; + component.scaleX = vo.scaleX; + component.scaleY = vo.scaleY; + component.x = vo.x; + component.y = vo.y; + + if(Float.isNaN(vo.originX)) component.originX = dimensionsComponent.width/2f; + else component.originX = vo.originX; + + if(Float.isNaN(vo.originY)) component.originY = dimensionsComponent.height/2f; + else component.originY = vo.originY; + + entity.add(component); + + return component; + } + + protected abstract DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo); + + protected TintComponent createTintComponent(Entity entity, MainItemVO vo) { + TintComponent component = new TintComponent(); + component.color.set(vo.tint[0], vo.tint[1], vo.tint[2], vo.tint[3]); + + entity.add(component); + + return component; + } + + protected ZIndexComponent createZIndexComponent(Entity entity, MainItemVO vo) { + ZIndexComponent component = new ZIndexComponent(); + + if(vo.layerName == "" || vo.layerName == null) vo.layerName = "Default"; + + component.layerName = vo.layerName; + component.setZIndex(vo.zIndex); + component.needReOrder = false; + entity.add(component); + + return component; + } + + protected ScriptComponent createScriptComponent(Entity entity, MainItemVO vo) { + ScriptComponent component = new ScriptComponent(); + entity.add(component); + return component; + } + + protected ParentNodeComponent createParentNodeComponent(Entity root, Entity entity) { + ParentNodeComponent component = new ParentNodeComponent(); + component.parentEntity = root; + entity.add(component); + + //set visible to true depending on parent + // TODO: I do not likes this part + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + LayerMapComponent layerMapComponent = ComponentRetriever.get(root, LayerMapComponent.class); + ZIndexComponent zIndexComponent = ComponentRetriever.get(root, ZIndexComponent.class); + mainItemComponent.visible = layerMapComponent.isVisible(zIndexComponent.layerName); + + return component; + } + + protected void createNodeComponent(Entity root, Entity entity) { + NodeComponent component = nodeComponentMapper.get(root); + component.children.add(entity); + } + + protected void createPhysicsComponents(Entity entity, MainItemVO vo) { + if(vo.physics == null){ + return; + } + + createPhysicsBodyPropertiesComponent(entity, vo); + } + + protected PhysicsBodyComponent createPhysicsBodyPropertiesComponent(Entity entity, MainItemVO vo) { + PhysicsBodyComponent component = new PhysicsBodyComponent(); + component.allowSleep = vo.physics.allowSleep; + component.sensor = vo.physics.sensor; + component.awake = vo.physics.awake; + component.bodyType = vo.physics.bodyType; + component.bullet = vo.physics.bullet; + component.centerOfMass = vo.physics.centerOfMass; + component.damping = vo.physics.damping; + component.density = vo.physics.density; + component.friction = vo.physics.friction; + component.gravityScale = vo.physics.gravityScale; + component.mass = vo.physics.mass; + component.restitution = vo.physics.restitution; + component.rotationalInertia = vo.physics.rotationalInertia; + + entity.add(component); + + return component; + } + + protected LightBodyComponent createLightComponents(Entity entity, MainItemVO vo) { + if(vo.light == null){ + return null; + } + + LightBodyComponent component = new LightBodyComponent(); + component.rays = vo.light.rays; + component.color = vo.light.color; + component.distance = vo.light.distance; + component.rayDirection = vo.light.rayDirection; + component.softnessLength = vo.light.softnessLength; + component.isXRay = vo.light.isXRay; + component.isStatic = vo.light.isStatic; + component.isSoft = vo.light.isSoft; + component.isActive = vo.light.isActive; + + entity.add(component); + return component; + } + + protected PolygonComponent createMeshComponent(Entity entity, MainItemVO vo) { + PolygonComponent component = new PolygonComponent(); + if(vo.shape != null) { + component.vertices = vo.shape.polygons.clone(); + entity.add(component); + + return component; + } + return null; + } + + public void setResourceManager(IResourceRetriever rm) { + this.rm = rm; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/CompositeComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/CompositeComponentFactory.java new file mode 100644 index 00000000..111f05bc --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/CompositeComponentFactory.java @@ -0,0 +1,93 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.components.CompositeTransformComponent; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.LayerMapComponent; +import games.rednblack.editor.renderer.components.NodeComponent; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.data.CompositeVO; +import games.rednblack.editor.renderer.data.LayerItemVO; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; + +/** + * Created by azakhary on 5/22/2015. + */ +public class CompositeComponentFactory extends ComponentFactory { + + public CompositeComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + } + + @Override + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + createCommonComponents(entity, vo, EntityFactory.COMPOSITE_TYPE); + if(root != null) { + createParentNodeComponent(root, entity); + } + createNodeComponent(root, entity); + createPhysicsComponents(entity, vo); + createLightComponents(entity, vo); + createCompositeComponents(entity, (CompositeItemVO) vo); + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + component.width = ((CompositeItemVO) vo).width; + component.height = ((CompositeItemVO) vo).height; + component.boundBox = new Rectangle(0,0,component.width,component.height); + entity.add(component); + return component; + } + + @Override + protected void createNodeComponent(Entity root, Entity entity) { + if(root != null) { + super.createNodeComponent(root, entity); + } + + NodeComponent node = new NodeComponent(); + entity.add(node); + } + + protected void createCompositeComponents(Entity entity, CompositeItemVO vo) { + CompositeTransformComponent compositeTransform = new CompositeTransformComponent(); + + compositeTransform.automaticResize = vo.automaticResize; + compositeTransform.scissorsEnabled = vo.scissorsEnabled; + + LayerMapComponent layerMap = new LayerMapComponent(); + if(vo.composite.layers.size() == 0) { + vo.composite.layers.add(LayerItemVO.createDefault()); + } + layerMap.setLayers(vo.composite.layers); + + entity.add(compositeTransform); + entity.add(layerMap); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/LabelComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/LabelComponentFactory.java new file mode 100644 index 00000000..e6d9bf09 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/LabelComponentFactory.java @@ -0,0 +1,67 @@ +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.physics.box2d.World; +import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.label.LabelComponent; +import games.rednblack.editor.renderer.data.*; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; + +public class LabelComponentFactory extends ComponentFactory{ + + private static int labelDefaultSize = 12; + + public LabelComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + // TODO Auto-generated constructor stub + } + + @Override + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + createCommonComponents(entity, vo, EntityFactory.LABEL_TYPE); + createParentNodeComponent(root, entity); + createNodeComponent(root, entity); + createLabelComponent(entity, (LabelVO) vo); + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + component.height = ((LabelVO) vo).height; + component.width = ((LabelVO) vo).width; + + entity.add(component); + return component; + } + + protected LabelComponent createLabelComponent(Entity entity, LabelVO vo) { + LabelComponent component = new LabelComponent(vo.text, generateStyle(rm, vo.style, vo.size)); + component.fontName = vo.style; + component.fontSize = vo.size; + component.setAlignment(vo.align); + component.setWrap(vo.wrap); + + ProjectInfoVO projectInfoVO = rm.getProjectVO(); + ResolutionEntryVO resolutionEntryVO = rm.getLoadedResolution(); + float multiplier = resolutionEntryVO.getMultiplier(rm.getProjectVO().originalResolution); + + component.setFontScale(multiplier/projectInfoVO.pixelToWorld); + + entity.add(component); + return component; + } + + + public static LabelStyle generateStyle(IResourceRetriever rManager, String fontName, int size) { + + if (size == 0) { + size = labelDefaultSize; + } + return new LabelStyle(rManager.getBitmapFont(fontName, size), null); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/LightComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/LightComponentFactory.java new file mode 100644 index 00000000..f9b20199 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/LightComponentFactory.java @@ -0,0 +1,93 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.ConeLight; +import box2dLight.PointLight; +import box2dLight.RayHandler; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.components.BoundingBoxComponent; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.light.LightObjectComponent; +import games.rednblack.editor.renderer.data.LightVO; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.physics.PhysicsBodyLoader; +import games.rednblack.editor.renderer.resources.IResourceRetriever; + +public class LightComponentFactory extends ComponentFactory { + + public LightComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + } + + @Override + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + createCommonComponents(entity, vo, EntityFactory.LIGHT_TYPE); + entity.remove(BoundingBoxComponent.class); + createParentNodeComponent(root, entity); + createNodeComponent(root, entity); + createLightObjectComponent(entity, (LightVO) vo); + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + + ProjectInfoVO projectInfoVO = rm.getProjectVO(); + float boundBoxSize = 50f; + component.boundBox = new Rectangle((-boundBoxSize / 2f) / projectInfoVO.pixelToWorld, (-boundBoxSize / 2f) / projectInfoVO.pixelToWorld, boundBoxSize / projectInfoVO.pixelToWorld, boundBoxSize / projectInfoVO.pixelToWorld); + component.width = boundBoxSize / projectInfoVO.pixelToWorld; + component.height = boundBoxSize / projectInfoVO.pixelToWorld; + + entity.add(component); + return component; + } + + protected LightObjectComponent createLightObjectComponent(Entity entity, LightVO vo) { + if(vo.softnessLength == -1f) { + vo.softnessLength = vo.distance * 0.1f * PhysicsBodyLoader.getScale(); + } + LightObjectComponent component = new LightObjectComponent(vo.type); + component.coneDegree = vo.coneDegree; + component.directionDegree = vo.directionDegree; + component.distance = vo.distance; + component.softnessLength = vo.softnessLength; + component.isStatic = vo.isStatic; + component.isXRay = vo.isXRay; + component.rays = vo.rays; + component.isActive = vo.isActive; + component.isSoft = vo.isSoft; + + if (component.getType() == LightVO.LightType.POINT) { + component.lightObject = new PointLight(rayHandler, component.rays); + } else { + component.lightObject = new ConeLight(rayHandler, component.rays, Color.WHITE, 1, 0, 0, 0, 0); + } + + component.lightObject.setSoftnessLength(component.softnessLength); + + entity.add(component); + return component; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/NinePatchComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/NinePatchComponentFactory.java new file mode 100644 index 00000000..ec8aa505 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/NinePatchComponentFactory.java @@ -0,0 +1,73 @@ +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.NinePatchComponent; +import games.rednblack.editor.renderer.data.Image9patchVO; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.data.ResolutionEntryVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; + +public class NinePatchComponentFactory extends ComponentFactory { + + private NinePatchComponent ninePatchComponent; + + public NinePatchComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + } + + @Override + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + ninePatchComponent = createNinePatchComponent(entity, (Image9patchVO) vo); + createCommonComponents(entity, vo, EntityFactory.NINE_PATCH); + createParentNodeComponent(root, entity); + createNodeComponent(root, entity); + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + component.height = ((Image9patchVO) vo).height; + component.width = ((Image9patchVO) vo).width; + if(component.width == 0) { + component.width = ninePatchComponent.ninePatch.getTotalWidth(); + } + + if(component.height == 0) { + component.height = ninePatchComponent.ninePatch.getTotalHeight(); + } + + entity.add(component); + return component; + } + + private NinePatchComponent createNinePatchComponent(Entity entity, Image9patchVO vo) { + NinePatchComponent ninePatchComponent = new NinePatchComponent(); + AtlasRegion atlasRegion = (AtlasRegion) rm.getTextureRegion(vo.imageName); + ninePatchComponent.ninePatch = new NinePatch(atlasRegion, atlasRegion.splits[0], atlasRegion.splits[1], atlasRegion.splits[2], atlasRegion.splits[3]); + + ResolutionEntryVO resolutionEntryVO = rm.getLoadedResolution(); + ProjectInfoVO projectInfoVO = rm.getProjectVO(); + float multiplier = resolutionEntryVO.getMultiplier(rm.getProjectVO().originalResolution); + + ninePatchComponent.ninePatch.scale(multiplier/projectInfoVO.pixelToWorld, multiplier/projectInfoVO.pixelToWorld); + + // This seem to be redundant as "scale" method now takes care of that o_O when did libGDX change that, should look more into this. + //ninePatchComponent.ninePatch.setMiddleWidth(ninePatchComponent.ninePatch.getMiddleWidth()*multiplier/projectInfoVO.pixelToWorld); + //ninePatchComponent.ninePatch.setMiddleHeight(ninePatchComponent.ninePatch.getMiddleHeight()*multiplier/projectInfoVO.pixelToWorld); + + ninePatchComponent.textureRegionName = vo.imageName; + entity.add(ninePatchComponent); + + return ninePatchComponent; + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/ParticleEffectComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/ParticleEffectComponentFactory.java new file mode 100644 index 00000000..e4a0a49d --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/ParticleEffectComponentFactory.java @@ -0,0 +1,76 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.RayHandler; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.ParticleEffect; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.particle.ParticleComponent; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.data.ParticleEffectVO; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; + +/** + * Created by azakhary on 5/22/2015. + */ +public class ParticleEffectComponentFactory extends ComponentFactory { + + + public ParticleEffectComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + } + + @Override + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + createCommonComponents(entity, vo, EntityFactory.PARTICLE_TYPE); + createParentNodeComponent(root, entity); + createNodeComponent(root, entity); + createParticleComponent(entity, (ParticleEffectVO) vo); + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + + ProjectInfoVO projectInfoVO = rm.getProjectVO(); + float boundBoxSize = 70f; + component.boundBox = new Rectangle((-boundBoxSize / 2f) / projectInfoVO.pixelToWorld, (-boundBoxSize / 2f) / projectInfoVO.pixelToWorld, boundBoxSize / projectInfoVO.pixelToWorld, boundBoxSize / projectInfoVO.pixelToWorld); + + entity.add(component); + return component; + } + + protected ParticleComponent createParticleComponent(Entity entity, ParticleEffectVO vo) { + ParticleComponent component = new ParticleComponent(); + component.particleName = vo.particleName; + ParticleEffect particleEffect = new ParticleEffect(rm.getParticleEffect(vo.particleName)); + component.particleEffect = particleEffect; + ProjectInfoVO projectInfoVO = rm.getProjectVO(); + component.worldMultiplyer = 1f/projectInfoVO.pixelToWorld; + component.scaleEffect(1f); + + entity.add(component); + return component; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/SimpleImageComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/SimpleImageComponentFactory.java new file mode 100644 index 00000000..1c11db0d --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/SimpleImageComponentFactory.java @@ -0,0 +1,95 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.PolygonComponent; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.data.ResolutionEntryVO; +import games.rednblack.editor.renderer.data.SimpleImageVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by azakhary on 5/22/2015. + */ +public class SimpleImageComponentFactory extends ComponentFactory { + + private TextureRegionComponent textureRegionComponent; + + public SimpleImageComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + } + + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + textureRegionComponent = createTextureRegionComponent(entity, (SimpleImageVO) vo); + createCommonComponents( entity, vo, EntityFactory.IMAGE_TYPE); + createParentNodeComponent(root, entity); + createNodeComponent(root, entity); + updatePolygons(entity); + } + + private void updatePolygons(Entity entity) { + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + + ProjectInfoVO projectInfoVO = rm.getProjectVO(); + + PolygonComponent polygonComponent = ComponentRetriever.get(entity, PolygonComponent.class); + if(textureRegionComponent.isPolygon && polygonComponent != null && polygonComponent.vertices != null) { + textureRegionComponent.setPolygonSprite(polygonComponent, projectInfoVO.pixelToWorld); + dimensionsComponent.setPolygon(polygonComponent); + } + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + + ResolutionEntryVO resolutionEntryVO = rm.getLoadedResolution(); + ProjectInfoVO projectInfoVO = rm.getProjectVO(); + float multiplier = resolutionEntryVO.getMultiplier(rm.getProjectVO().originalResolution); + + component.width = (float) textureRegionComponent.region.getRegionWidth() * multiplier / projectInfoVO.pixelToWorld; + component.height = (float) textureRegionComponent.region.getRegionHeight() * multiplier / projectInfoVO.pixelToWorld; + entity.add(component); + + return component; + } + + protected TextureRegionComponent createTextureRegionComponent(Entity entity, SimpleImageVO vo) { + TextureRegionComponent component = new TextureRegionComponent(); + component.regionName = vo.imageName; + component.region = rm.getTextureRegion(vo.imageName); + component.isRepeat = vo.isRepeat; + component.isPolygon = vo.isPolygon; + entity.add(component); + + return component; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/SpriteComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/SpriteComponentFactory.java new file mode 100644 index 00000000..ab1e08d8 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/SpriteComponentFactory.java @@ -0,0 +1,138 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.*; +import com.badlogic.gdx.physics.box2d.World; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.SceneLoader; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.components.sprite.AnimationComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationStateComponent; +import games.rednblack.editor.renderer.data.*; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by azakhary on 5/22/2015. + */ +public class SpriteComponentFactory extends ComponentFactory { + + public SpriteComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + } + + @Override + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + createCommonComponents(entity, vo, EntityFactory.SPRITE_TYPE); + createParentNodeComponent(root, entity); + createNodeComponent(root, entity); + createSpriteAnimationDataComponent(entity, (SpriteAnimationVO) vo); + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + + SpriteAnimationVO sVo = (SpriteAnimationVO) vo; + Array regions = getRegions(sVo.animationName); + + ResolutionEntryVO resolutionEntryVO = rm.getLoadedResolution(); + ProjectInfoVO projectInfoVO = rm.getProjectVO(); + float multiplier = resolutionEntryVO.getMultiplier(rm.getProjectVO().originalResolution); + component.width = (float) regions.get(0).getRegionWidth() * multiplier / projectInfoVO.pixelToWorld; + component.height = (float) regions.get(0).getRegionHeight() * multiplier / projectInfoVO.pixelToWorld; + + entity.add(component); + return component; + } + + protected SpriteAnimationComponent createSpriteAnimationDataComponent(Entity entity, SpriteAnimationVO vo) { + SpriteAnimationComponent spriteAnimationComponent = new SpriteAnimationComponent(); + spriteAnimationComponent.animationName = vo.animationName; + + spriteAnimationComponent.frameRangeMap = new HashMap(); + for(int i = 0; i < vo.frameRangeMap.size(); i++) { + spriteAnimationComponent.frameRangeMap.put(vo.frameRangeMap.get(i).name, vo.frameRangeMap.get(i)); + } + spriteAnimationComponent.fps = vo.fps; + spriteAnimationComponent.currentAnimation = vo.currentAnimation; + + if(vo.playMode == 0) spriteAnimationComponent.playMode = Animation.PlayMode.NORMAL; + if(vo.playMode == 1) spriteAnimationComponent.playMode = Animation.PlayMode.REVERSED; + if(vo.playMode == 2) spriteAnimationComponent.playMode = Animation.PlayMode.LOOP; + if(vo.playMode == 3) spriteAnimationComponent.playMode = Animation.PlayMode.LOOP_REVERSED; + if(vo.playMode == 4) spriteAnimationComponent.playMode = Animation.PlayMode.LOOP_PINGPONG; + if(vo.playMode == 5) spriteAnimationComponent.playMode = Animation.PlayMode.LOOP_RANDOM; + if(vo.playMode == 6) spriteAnimationComponent.playMode = Animation.PlayMode.NORMAL; + + // filtering regions by name + Array regions = getRegions(spriteAnimationComponent.animationName); + + AnimationComponent animationComponent = new AnimationComponent(); + SpriteAnimationStateComponent stateComponent = new SpriteAnimationStateComponent(regions); + + if(spriteAnimationComponent.frameRangeMap.isEmpty()) { + spriteAnimationComponent.frameRangeMap.put("Default", new FrameRange("Default", 0, regions.size-1)); + } + if(spriteAnimationComponent.currentAnimation == null) { + spriteAnimationComponent.currentAnimation = (String) spriteAnimationComponent.frameRangeMap.keySet().toArray()[0]; + } + if(spriteAnimationComponent.playMode == null) { + spriteAnimationComponent.playMode = Animation.PlayMode.LOOP; + } + + stateComponent.set(spriteAnimationComponent); + + TextureRegionComponent textureRegionComponent = new TextureRegionComponent(); + textureRegionComponent.region = regions.get(0); + + entity.add(textureRegionComponent); + entity.add(stateComponent); + entity.add(animationComponent); + entity.add(spriteAnimationComponent); + + return spriteAnimationComponent; + } + + private Array getRegions(String filter) { + // filtering regions by name + Array allRegions = rm.getSpriteAnimation(filter).getRegions(); + Array regions = new Array(); + for(TextureAtlas.AtlasRegion region: allRegions) { + if(region.name.contains(filter)) { + regions.add(region); + } + } + + return regions; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/SpriterComponentFactory.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/SpriterComponentFactory.java new file mode 100644 index 00000000..d6b2e666 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/factory/component/SpriterComponentFactory.java @@ -0,0 +1,100 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.factory.component; + +import box2dLight.RayHandler; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.physics.box2d.World; +import com.brashmonkey.spriter.Player; +import com.brashmonkey.spriter.Rectangle; +import com.brashmonkey.spriter.SCMLReader; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.spriter.SpriterComponent; +import games.rednblack.editor.renderer.components.spriter.SpriterDrawerComponent; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.data.SpriterVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.renderer.utils.LibGdxDrawer; +import games.rednblack.editor.renderer.utils.LibGdxLoader; + +/** + * Created by azakhary on 5/22/2015. + */ +public class SpriterComponentFactory extends ComponentFactory { + + public SpriterComponentFactory(RayHandler rayHandler, World world, IResourceRetriever rm) { + super(rayHandler, world, rm); + } + + @Override + public void createComponents(Entity root, Entity entity, MainItemVO vo) { + createSpriterDataComponent(entity, (SpriterVO) vo); + createCommonComponents(entity, vo, EntityFactory.SPRITER_TYPE); + createParentNodeComponent(root, entity); + createNodeComponent(root, entity); + } + + @Override + protected DimensionsComponent createDimensionsComponent(Entity entity, MainItemVO vo) { + DimensionsComponent component = new DimensionsComponent(); + + SpriterComponent spriterComponent = ComponentRetriever.get(entity, SpriterComponent.class); + + Rectangle rect = spriterComponent.player.getBoundingRectangle(null); + component.width = (int) rect.size.width; + component.height = (int) rect.size.height; + + entity.add(component); + return component; + } + + protected SpriterComponent createSpriterDataComponent(Entity entity, SpriterVO vo) { + SpriterComponent component = new SpriterComponent(); + component. entity = vo.entity; + component.animation = vo.animation; + component. animationName = vo.animationName; + component.scale = vo.scale; + + FileHandle handle = rm.getSCMLFile(vo.animationName); + component.data = new SCMLReader(handle.read()).getData(); + LibGdxLoader loader = new LibGdxLoader(component.data); + loader.load(handle.file()); + + component.currentAnimationIndex = vo.animation; + component.currentEntityIndex = vo.entity; + + component.player = new Player(component.data.getEntity(component.currentEntityIndex)); + + component.player.setAnimation(component.currentAnimationIndex); + component.player.setScale(component.scale); + + SpriterDrawerComponent spriterDrawer = new SpriterDrawerComponent(); + + spriterDrawer.drawer = new LibGdxDrawer(loader, null); + + entity.add(component); + entity.add(spriterDrawer); + + return component; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/physics/PhysicsBodyLoader.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/physics/PhysicsBodyLoader.java new file mode 100644 index 00000000..4813b1d6 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/physics/PhysicsBodyLoader.java @@ -0,0 +1,111 @@ +package games.rednblack.editor.renderer.physics; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.*; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; +import games.rednblack.editor.renderer.utils.TransformMathUtils; + +/** + * Created by azakhary on 9/28/2014. + */ +public class PhysicsBodyLoader { + + private static PhysicsBodyLoader instance; + + public float scale; + public float ppWU; + + public float mul; + + private PhysicsBodyLoader() { + mul = 20f; + } + + public static PhysicsBodyLoader getInstance() { + if(instance == null) { + instance = new PhysicsBodyLoader(); + } + + return instance; + } + + public void setScaleFromPPWU(float pixelPerWU) { + ppWU = 1f/pixelPerWU; + scale = 1f/(mul*pixelPerWU); + } + + public static float getScale() { + return getInstance().scale; + } + + public static float getPPWU() { + return getInstance().ppWU; + } + + public Body createBody(World world, Entity entity, PhysicsBodyComponent physicsComponent, Vector2[][] minPolygonData, TransformComponent transformComponent) { + FixtureDef fixtureDef = new FixtureDef(); + + if(physicsComponent != null) { + fixtureDef.density = physicsComponent.density; + fixtureDef.friction = physicsComponent.friction; + fixtureDef.restitution = physicsComponent.restitution; + + fixtureDef.isSensor = physicsComponent.sensor; + + fixtureDef.filter.maskBits = physicsComponent.filter.maskBits; + fixtureDef.filter.groupIndex = physicsComponent.filter.groupIndex; + fixtureDef.filter.categoryBits = physicsComponent.filter.categoryBits; + } + + BodyDef bodyDef = new BodyDef(); + Vector2 sceneCoords = TransformMathUtils.localToSceneCoordinates(entity, new Vector2(0, 0)); + bodyDef.position.set((sceneCoords.x + transformComponent.originX) * PhysicsBodyLoader.getScale() , (sceneCoords.y + transformComponent.originY)* PhysicsBodyLoader.getScale() ); + bodyDef.angle = transformComponent.rotation * MathUtils.degreesToRadians; + + bodyDef.awake = physicsComponent.awake; + bodyDef.allowSleep = physicsComponent.allowSleep; + bodyDef.bullet = physicsComponent.bullet; + + if(physicsComponent.bodyType == 0) { + bodyDef.type = BodyDef.BodyType.StaticBody; + } else if (physicsComponent.bodyType == 1){ + bodyDef.type = BodyDef.BodyType.KinematicBody; + } else { + bodyDef.type = BodyDef.BodyType.DynamicBody; + } + + Body body = world.createBody(bodyDef); + + PolygonShape polygonShape = new PolygonShape(); + + for(int i = 0; i < minPolygonData.length; i++) { + float[] verts = new float[minPolygonData[i].length * 2]; + for(int j=0;j preparedSceneNames = new ArrayList(); + protected HashMap loadedSceneVOs = new HashMap(); + + protected HashSet particleEffectNamesToLoad = new HashSet(); + protected HashSet spineAnimNamesToLoad = new HashSet(); + protected HashSet spriteAnimNamesToLoad = new HashSet(); + protected HashSet spriterAnimNamesToLoad = new HashSet(); + protected HashSet fontsToLoad = new HashSet(); + protected HashSet shaderNamesToLoad = new HashSet(); + + protected TextureAtlas mainPack; + protected HashMap particleEffects = new HashMap(); + + protected HashMap skeletonAtlases = new HashMap(); + protected HashMap skeletonJSON = new HashMap(); + + protected HashMap spriteAnimations = new HashMap(); + protected HashMap spriterAnimations = new HashMap(); + protected HashMap bitmapFonts = new HashMap(); + protected HashMap shaderPrograms = new HashMap(); + + + /** + * Constructor does nothing + */ + public ResourceManager() { + + } + + /** + * Sets working resolution, please set before doing any loading + * @param resolution String resolution name, default is "orig" later use resolution names created in editor + */ + public void setWorkingResolution(String resolution) { + ResolutionEntryVO resolutionObject = getProjectVO().getResolution(resolution); + if(resolutionObject != null) { + packResolutionName = resolution; + } + } + + /** + * Easy use loader + * Iterates through all scenes and schedules all for loading + * Prepares all the assets to be loaded that are used in scheduled scenes + * finally loads all the prepared assets + */ + public void initAllResources() { + loadProjectVO(); + for (int i = 0; i < projectVO.scenes.size(); i++) { + loadSceneVO(projectVO.scenes.get(i).sceneName); + scheduleScene(projectVO.scenes.get(i).sceneName); + } + prepareAssetsToLoad(); + loadAssets(); + } + + /** + * Initializes scene by loading it's VO data object and loading all the assets needed for this particular scene only + * @param sceneName - scene file name without ".dt" extension + */ + public void initScene(String sceneName) { + loadSceneVO(sceneName); + scheduleScene(sceneName); + prepareAssetsToLoad(); + loadAssets(); + } + + /** + * Anloads scene from the memory, and clears all the freed assets + * + * @param sceneName - scene file name without ".dt" extension + */ + public void unLoadScene(String sceneName) { + unScheduleScene(sceneName); + loadedSceneVOs.remove(sceneName); + loadAssets(); + } + + /** + * Schedules scene for later loading + * if later prepareAssetsToLoad function will be called it will only prepare assets that are used in scheduled scene + * + * @param name - scene file name without ".dt" extension + */ + public void scheduleScene(String name) { + if (loadedSceneVOs.containsKey(name)) { + preparedSceneNames.add(name); + } else { + //TODO: Throw exception that scene was not loaded to be prepared for asseting + } + + } + + + /** + * Unschedule scene from later loading + * + * @param name + */ + public void unScheduleScene(String name) { + preparedSceneNames.remove(name); + } + + + /** + * Creates the list of uniqe assets used in all of the scheduled scenes, + * removes all the duplicates, and makes list of assets that are only needed. + * + */ + public void prepareAssetsToLoad() { + particleEffectNamesToLoad.clear(); + spineAnimNamesToLoad.clear(); + spriteAnimNamesToLoad.clear(); + spriterAnimNamesToLoad.clear(); + fontsToLoad.clear(); + shaderPrograms.clear(); + + for (String preparedSceneName : preparedSceneNames) { + CompositeVO composite = loadedSceneVOs.get(preparedSceneName).composite; + if (composite == null) { + continue; + } + // + String[] particleEffects = composite.getRecursiveParticleEffectsList(); + String[] spineAnimations = composite.getRecursiveSpineAnimationList(); + String[] spriteAnimations = composite.getRecursiveSpriteAnimationList(); + String[] spriterAnimations = composite.getRecursiveSpriterAnimationList(); + String[] shaderNames = composite.getRecursiveShaderList(); + FontSizePair[] fonts = composite.getRecursiveFontList(); + for(CompositeItemVO library : projectVO.libraryItems.values()) { + FontSizePair[] libFonts = library.composite.getRecursiveFontList(); + Collections.addAll(fontsToLoad, libFonts); + + // loading particle effects used in library items + String[] libEffects = library.composite.getRecursiveParticleEffectsList(); + Collections.addAll(particleEffectNamesToLoad, libEffects); + } + + // + Collections.addAll(particleEffectNamesToLoad, particleEffects); + Collections.addAll(spineAnimNamesToLoad, spineAnimations); + Collections.addAll(spriteAnimNamesToLoad, spriteAnimations); + Collections.addAll(spriterAnimNamesToLoad, spriterAnimations); + Collections.addAll(fontsToLoad, fonts); + Collections.addAll(shaderNamesToLoad, shaderNames); + } + } + + /** + * Loads all the scheduled assets into memory including + * main atlas pack, particle effects, sprite animations, spine animations and fonts + */ + public void loadAssets() { + loadAtlasPack(); + loadParticleEffects(); + loadSpineAnimations(); + loadSpriteAnimations(); + loadSpriterAnimations(); + loadFonts(); + loadShaders(); + } + + @Override + public void loadAtlasPack() { + FileHandle packFile = Gdx.files.internal(packResolutionName + File.separator + "pack.atlas"); + if (!packFile.exists()) { + return; + } + mainPack = new TextureAtlas(packFile); + } + + @Override + public void loadParticleEffects() { + // empty existing ones that are not scheduled to load + for (String key : particleEffects.keySet()) { + if (!particleEffectNamesToLoad.contains(key)) { + particleEffects.remove(key); + } + } + + // load scheduled + for (String name : particleEffectNamesToLoad) { + ParticleEffect effect = new ParticleEffect(); + effect.load(Gdx.files.internal(particleEffectsPath + File.separator + name), mainPack, ""); + particleEffects.put(name, effect); + } + } + + @Override + public void loadSpriteAnimations() { + // empty existing ones that are not scheduled to load + for (String key : spriteAnimations.keySet()) { + if (!spriteAnimNamesToLoad.contains(key)) { + spriteAnimations.remove(key); + } + } + + for (String name : spriteAnimNamesToLoad) { + TextureAtlas animAtlas = new TextureAtlas(Gdx.files.internal(packResolutionName + File.separator + spriteAnimationsPath + File.separator + name + File.separator + name + ".atlas")); + spriteAnimations.put(name, animAtlas); + } + } + @Override + public void loadSpriterAnimations() { + // empty existing ones that are not scheduled to load + for (String key : spriterAnimations.keySet()) { + if (!spriterAnimNamesToLoad.contains(key)) { + spriterAnimations.remove(key); + } + } + for (String name : spriterAnimNamesToLoad) { + FileHandle animFile = Gdx.files.internal("orig" + File.separator + spriterAnimationsPath + File.separator + name + File.separator + name + ".scml"); + spriterAnimations.put(name, animFile); + } + } + + + public void loadSpineAnimation(String name) { + TextureAtlas animAtlas = new TextureAtlas(Gdx.files.internal(packResolutionName + File.separator + spineAnimationsPath + File.separator + name + File.separator + name + ".atlas")); + skeletonAtlases.put(name, animAtlas); + skeletonJSON.put(name, Gdx.files.internal("orig"+ File.separator + spineAnimationsPath + File.separator + name + File.separator + name + ".json")); + } + + + @Override + public void loadSpineAnimations() { + // empty existing ones that are not scheduled to load + Iterator it = skeletonAtlases.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pairs = (Map.Entry)it.next(); + if(spineAnimNamesToLoad.contains(pairs.getKey())) { + spineAnimNamesToLoad.remove(pairs.getKey()); + } else { + it.remove(); + skeletonJSON.remove(pairs.getKey()); + } + } + + + for (String name : spineAnimNamesToLoad) { + loadSpineAnimation(name); + } + } + + @Override + public void loadFonts() { + //resolution related stuff + ResolutionEntryVO curResolution = getProjectVO().getResolution(packResolutionName); + resMultiplier = 1; + if(!packResolutionName.equals("orig")) { + if(curResolution.base == 0) { + resMultiplier = (float) curResolution.width / (float) getProjectVO().originalResolution.width; + } else{ + resMultiplier = (float) curResolution.height / (float) getProjectVO().originalResolution.height; + } + } + + // empty existing ones that are not scheduled to load + for (FontSizePair pair : bitmapFonts.keySet()) { + if (!fontsToLoad.contains(pair)) { + bitmapFonts.remove(pair); + } + } + + for (FontSizePair pair : fontsToLoad) { + loadFont(pair); + } + } + + public void loadFont(FontSizePair pair) { + FileHandle fontFile; + fontFile = Gdx.files.internal(fontsPath + File.separator + pair.fontName + ".ttf"); + FreeTypeFontGenerator generator = new FreeTypeFontGenerator(fontFile); + FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter(); + parameter.size = Math.round(pair.fontSize * resMultiplier); + BitmapFont font = generator.generateFont(parameter); + font.getRegion().getTexture().setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest); + font.setUseIntegerPositions(false); + bitmapFonts.put(pair, font); + } + + @Override + public SceneVO loadSceneVO(String sceneName) { + FileHandle file = Gdx.files.internal(scenesPath + File.separator + sceneName + ".dt"); + Json json = new Json(); + SceneVO sceneVO = json.fromJson(SceneVO.class, file.readString()); + + loadedSceneVOs.put(sceneName, sceneVO); + + return sceneVO; + } + + public void unLoadSceneVO(String sceneName) { + loadedSceneVOs.remove(sceneName); + } + + @Override + public ProjectInfoVO loadProjectVO() { + + FileHandle file = Gdx.files.internal("project.dt"); + Json json = new Json(); + projectVO = json.fromJson(ProjectInfoVO.class, file.readString()); + + return projectVO; + } + + @Override + public void loadShaders() { + // empty existing ones that are not scheduled to load + for (String key : shaderPrograms.keySet()) { + if (!shaderNamesToLoad.contains(key)) { + shaderPrograms.get(key).dispose(); + shaderPrograms.remove(key); + } + } + + for (String name : shaderNamesToLoad) { + ShaderProgram shaderProgram = new ShaderProgram(Gdx.files.internal(shadersPath + File.separator + name + ".vert"), Gdx.files.internal(shadersPath + File.separator + name + ".frag")); + shaderPrograms.put(name, shaderProgram); + } + } + + /** + * Following methods are for retriever interface, which is intended for runtime internal use + * to retrieve any already loaded into memory asset for rendering + */ + + + + + @Override + public TextureRegion getTextureRegion(String name) { + return mainPack.findRegion(name); + } + + @Override + public ParticleEffect getParticleEffect(String name) { + return new ParticleEffect(particleEffects.get(name)); + } + + @Override + public TextureAtlas getSkeletonAtlas(String name) { + return skeletonAtlases.get(name); + } + + @Override + public FileHandle getSkeletonJSON(String name) { + return skeletonJSON.get(name); + } + + @Override + public TextureAtlas getSpriteAnimation(String name) { + return spriteAnimations.get(name); + } + + @Override + public BitmapFont getBitmapFont(String name, int size) { + return bitmapFonts.get(new FontSizePair(name, size)); + } + + @Override + public MySkin getSkin() { + return null; + } + + @Override + public SceneVO getSceneVO(String sceneName) { + return loadedSceneVOs.get(sceneName); + } + + @Override + public ProjectInfoVO getProjectVO() { + return projectVO; + } + + @Override + public ResolutionEntryVO getLoadedResolution() { + if(packResolutionName.equals("orig")) { + return getProjectVO().originalResolution; + } + return getProjectVO().getResolution(packResolutionName); + } + + public void dispose() { + mainPack.dispose(); + } + + @Override + public FileHandle getSCMLFile(String name) { + return spriterAnimations.get(name); + } + + @Override + public ShaderProgram getShaderProgram(String shaderName) { + return shaderPrograms.get(shaderName); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/resources/ResourceManagerLoader.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/resources/ResourceManagerLoader.java new file mode 100644 index 00000000..206edb0d --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/resources/ResourceManagerLoader.java @@ -0,0 +1,171 @@ +package games.rednblack.editor.renderer.resources; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.assets.AssetDescriptor; +import com.badlogic.gdx.assets.AssetLoaderParameters; +import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.assets.loaders.AsynchronousAssetLoader; +import com.badlogic.gdx.assets.loaders.FileHandleResolver; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.GdxRuntimeException; +import games.rednblack.editor.renderer.data.ProjectInfoVO; + +import java.io.File; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +/** + * Created by socheat on 8/13/15. + */ +public class ResourceManagerLoader extends AsynchronousAssetLoader { + + private AsyncResourceManager asyncResourceManager; + + private ProjectInfoVO projectInfoVO; + + public ResourceManagerLoader(FileHandleResolver resolver) { + super(resolver); + this.asyncResourceManager = new AsyncResourceManager(); + } + + @Override + public void loadAsync(AssetManager manager, String fileName, FileHandle file, AsyncResourceManagerParam parameter) { + } + + @Override + public games.rednblack.editor.renderer.resources.ResourceManager loadSync(AssetManager manager, String fileName, FileHandle file, AsyncResourceManagerParam parameter) { + if (!fileName.equals("project.dt")) { + throw new GdxRuntimeException("fileName must be project.dt"); + } + + FileHandle packFile = Gdx.files.internal(this.asyncResourceManager.packResolutionName + File.separator + "pack.atlas"); + TextureAtlas textureAtlas = manager.get(packFile.path(), TextureAtlas.class); + this.asyncResourceManager.setMainPack(textureAtlas); + this.asyncResourceManager.loadParticleEffects(); + this.asyncResourceManager.loadSpineAnimations(manager); + this.asyncResourceManager.loadSpriteAnimations(manager); + this.asyncResourceManager.loadSpriterAnimations(); + this.asyncResourceManager.loadFonts(); + + return this.asyncResourceManager; + } + + @Override + public Array getDependencies(String fileName, FileHandle file, AsyncResourceManagerParam parameter) { + if (!fileName.equals("project.dt")) { + throw new GdxRuntimeException("fileName must be project.dt"); + } + this.projectInfoVO = this.asyncResourceManager.loadProjectVO(); + for (int i = 0; i < this.projectInfoVO.scenes.size(); i++) { + this.asyncResourceManager.loadSceneVO(this.projectInfoVO.scenes.get(i).sceneName); + this.asyncResourceManager.scheduleScene(this.projectInfoVO.scenes.get(i).sceneName); + } + this.asyncResourceManager.prepareAssetsToLoad(); + + Array deps = new Array(); + { + FileHandle packFile = Gdx.files.internal(this.asyncResourceManager.packResolutionName + File.separator + "pack.atlas"); + if (packFile.exists()) { + deps.add(new AssetDescriptor(packFile, TextureAtlas.class)); + } + } + + for (String name : this.asyncResourceManager.getSpineAnimNamesToLoad()) { + FileHandle packFile = Gdx.files.internal(this.asyncResourceManager + File.separator + this.asyncResourceManager.spineAnimationsPath + File.separator + name + File.separator + name + ".atlas"); + deps.add(new AssetDescriptor(packFile, TextureAtlas.class)); + } + + for (String name : this.asyncResourceManager.getSpriteAnimNamesToLoad()) { + FileHandle packFile = Gdx.files.internal(this.asyncResourceManager.packResolutionName + File.separator + this.asyncResourceManager.spriteAnimationsPath + File.separator + name + File.separator + name + ".atlas"); + deps.add(new AssetDescriptor(packFile, TextureAtlas.class)); + } + + return deps; + } + + public static class AsyncResourceManagerParam extends AssetLoaderParameters { + } + + private static class AsyncResourceManager extends games.rednblack.editor.renderer.resources.ResourceManager { + + @Override + public ProjectInfoVO getProjectVO() { + return super.getProjectVO(); + } + + public void setProjectInfoVO(ProjectInfoVO vo) { + this.projectVO = vo; + } + + public HashSet getSpineAnimNamesToLoad() { + return this.spineAnimNamesToLoad; + } + + public void setMainPack(TextureAtlas mainPack) { + this.mainPack = mainPack; + } + + @Override + public void loadSpineAnimations() { + throw new GdxRuntimeException("see loadSpineAnimations(AssetManager)"); + } + + @Override + public void loadSpineAnimation(String name) { + throw new GdxRuntimeException("see loadSpineAnimation(AssetManager, String)"); + } + + public void loadSpineAnimations(AssetManager manager) { + Iterator it = skeletonAtlases.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pairs = (Map.Entry) it.next(); + if (spineAnimNamesToLoad.contains(pairs.getKey())) { + spineAnimNamesToLoad.remove(pairs.getKey()); + } else { + it.remove(); + skeletonJSON.remove(pairs.getKey()); + } + } + + + for (String name : spineAnimNamesToLoad) { + loadSpineAnimation(manager, name); + } + } + + public void loadSpineAnimation(AssetManager manager, String name) { + FileHandle packFile = Gdx.files.internal(packResolutionName + File.separator + spineAnimationsPath + File.separator + name + File.separator + name + ".atlas"); + TextureAtlas animAtlas = manager.get(packFile.path(), TextureAtlas.class); + skeletonAtlases.put(name, animAtlas); + skeletonJSON.put(name, Gdx.files.internal("orig" + File.separator + spineAnimationsPath + File.separator + name + File.separator + name + ".json")); + } + + + @Override + public void loadSpriteAnimations() { + throw new GdxRuntimeException("see loadSpriteAnimations(AssetManager)"); + } + + public HashSet getSpriteAnimNamesToLoad() { + return this.spriteAnimNamesToLoad; + } + + public void loadSpriteAnimations(AssetManager manager) { + // empty existing ones that are not scheduled to load + for (String key : spriteAnimations.keySet()) { + if (!spriteAnimNamesToLoad.contains(key)) { + spriteAnimations.remove(key); + } + } + + for (String name : spriteAnimNamesToLoad) { + FileHandle packFile = Gdx.files.internal(packResolutionName + File.separator + spriteAnimationsPath + File.separator + name + File.separator + name + ".atlas"); + spriteAnimations.put(name, manager.get(packFile.path(), TextureAtlas.class)); + } + } + } +} + diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scene2d/ButtonClickListener.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scene2d/ButtonClickListener.java new file mode 100644 index 00000000..c6836048 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scene2d/ButtonClickListener.java @@ -0,0 +1,26 @@ +package games.rednblack.editor.renderer.scene2d; + +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; + +/** + * Created by CyberJoe on 8/1/2015. + */ +public class ButtonClickListener extends ClickListener { + + @Override + public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { + CompositeActor compositeActor = (CompositeActor) event.getListenerActor(); + compositeActor.setLayerVisibility("normal", false); + compositeActor.setLayerVisibility("pressed", true); + return true; + } + + @Override + public void touchUp (InputEvent event, float x, float y, int pointer, int button) { + CompositeActor compositeActor = (CompositeActor) event.getListenerActor(); + compositeActor.setLayerVisibility("normal", true); + compositeActor.setLayerVisibility("pressed", false); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scene2d/CompositeActor.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scene2d/CompositeActor.java new file mode 100644 index 00000000..b91cc701 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scene2d/CompositeActor.java @@ -0,0 +1,357 @@ +package games.rednblack.editor.renderer.scene2d; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.Group; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.data.*; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.scripts.IActorScript; +import games.rednblack.editor.renderer.utils.CustomVariables; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + + +/** + * Created by azakhary on 7/26/2015. + */ +public class CompositeActor extends Group { + + protected IResourceRetriever ir; + + private float pixelsPerWU; + private float resMultiplier; + + protected CompositeItemVO vo; + private ArrayList scripts = new ArrayList(3); + private HashMap indexes = new HashMap(); + private HashMap layerMap = new HashMap(); + + public CompositeActor(CompositeItemVO vo, IResourceRetriever ir) { + this(vo, ir, BuiltItemHandler.DEFAULT); + } + + public CompositeActor(CompositeItemVO vo, IResourceRetriever ir, BuiltItemHandler itemHandler) { + this(vo, ir, itemHandler, true); + } + + private CompositeActor(CompositeItemVO vo, IResourceRetriever ir, BuiltItemHandler itemHandler, boolean isRoot) { + this.ir= ir; + this.vo = vo; + + pixelsPerWU = ir.getProjectVO().pixelToWorld; + + ResolutionEntryVO resolutionEntryVO = ir.getLoadedResolution(); + resMultiplier = resolutionEntryVO.getMultiplier(ir.getProjectVO().originalResolution); + + makeLayerMap(vo); + build(vo, itemHandler, isRoot); + } + + private void makeLayerMap(CompositeItemVO vo) { + layerMap.clear(); + for(int i = 0; i < vo.composite.layers.size(); i++) { + layerMap.put(vo.composite.layers.get(i).layerName,vo.composite.layers.get(i)); + } + } + + protected void build(CompositeItemVO vo, BuiltItemHandler itemHandler, boolean isRoot) { + buildImages(vo.composite.sImages, itemHandler); + build9PatchImages(vo.composite.sImage9patchs, itemHandler); + buildLabels(vo.composite.sLabels, itemHandler); + buildComposites(vo.composite.sComposites, itemHandler); + processZIndexes(); + recalculateSize(); + + if(isRoot) { + buildCoreData(this, vo); + itemHandler.onItemBuild(this); + } + } + + protected void buildComposites(ArrayList composites, BuiltItemHandler itemHandler) { + + for(int i = 0; i < composites.size(); i++) { + String className = getClassName(composites.get(i).customVars); + CompositeActor actor; + if(className!=null){ + try { + Class c = Class.forName(className); + actor = (CompositeActor) c.getConstructors()[0].newInstance(composites.get(i), ir, itemHandler); + }catch (Exception ex){ + actor = new CompositeActor(composites.get(i), ir, itemHandler, false); + } + }else { + actor = new CompositeActor(composites.get(i), ir, itemHandler, false); + } + processMain(actor, composites.get(i)); + addActor(actor); + + itemHandler.onItemBuild(actor); + } + } + + private String getClassName(String customVars) { + CustomVariables cv = new CustomVariables(); + cv.loadFromString(customVars); + String className = cv.getStringVariable("className"); + if(className!=null && className.equals("")){ + className = null; + } + return className; + } + + public void addScript(IActorScript iScript) { + scripts.add(iScript); + iScript.init(this); + } + + protected void buildImages(ArrayList images, BuiltItemHandler itemHandler) { + for(int i = 0; i < images.size(); i++) { + Image image = new Image(ir.getTextureRegion(images.get(i).imageName)); + processMain(image, images.get(i)); + addActor(image); + + itemHandler.onItemBuild(image); + } + } + + protected void build9PatchImages(ArrayList patches, BuiltItemHandler itemHandler) { + for(int i = 0; i < patches.size(); i++) { + TextureAtlas.AtlasRegion region = (TextureAtlas.AtlasRegion) ir.getTextureRegion(patches.get(i).imageName); + NinePatch ninePatch = new NinePatch(region, region.splits[0], region.splits[1], region.splits[2], region.splits[3]); + Image image = new Image(ninePatch); + image.setWidth(patches.get(i).width*pixelsPerWU/resMultiplier); + image.setHeight(patches.get(i).height * pixelsPerWU/resMultiplier); + processMain(image, patches.get(i)); + addActor(image); + + itemHandler.onItemBuild(image); + } + } + + protected void buildLabels(ArrayList labels, BuiltItemHandler itemHandler) { + for(int i = 0; i < labels.size(); i++) { + Label.LabelStyle style = new Label.LabelStyle(ir.getBitmapFont(labels.get(i).style, labels.get(i).size), Color.WHITE); + Label label = new Label(labels.get(i).text, style); + label.setAlignment(labels.get(i).align); + label.setWidth(labels.get(i).width * pixelsPerWU / resMultiplier); + label.setHeight(labels.get(i).height * pixelsPerWU / resMultiplier); + processMain(label, labels.get(i)); + addActor(label); + + itemHandler.onItemBuild(label); + } + } + + protected void processMain(Actor actor, MainItemVO vo) { + + actor.setName(vo.itemIdentifier); + buildCoreData(actor, vo); + + //actor properties + actor.setPosition(vo.x * pixelsPerWU/resMultiplier, vo.y * pixelsPerWU/resMultiplier); + actor.setOrigin(vo.originX * pixelsPerWU/resMultiplier, vo.originY * pixelsPerWU/resMultiplier); + actor.setScale(vo.scaleX, vo.scaleY); + actor.setRotation(vo.rotation); + actor.setColor(new Color(vo.tint[0], vo.tint[1], vo.tint[2], vo.tint[3])); + + indexes.put(getLayerIndex(vo.layerName) + vo.zIndex, actor); + + if(layerMap.get(vo.layerName).isVisible) { + actor.setVisible(true); + } else { + actor.setVisible(false); + } + } + + protected void buildCoreData(Actor actor, MainItemVO vo){ + + //custom variables + CustomVariables cv = null; + if(vo.customVars != null && !vo.customVars.isEmpty()) { + cv = new CustomVariables(); + cv.loadFromString(vo.customVars); + } + + //core data + CoreActorData data = new CoreActorData(); + data.id = vo.itemIdentifier; + data.layerIndex = getLayerIndex(vo.layerName); + data.tags = vo.tags; + data.customVars = cv; + + actor.setUserObject(data); + } + + + protected void processZIndexes() { + Object[] indexArray = indexes.keySet().toArray(); + Arrays.sort(indexArray); + + for(int i = 0; i < indexArray.length; i++) { + indexes.get(indexArray[i]).setZIndex(i); + } + } + + public int getLayerIndex(String name) { + return vo.composite.layers.indexOf(layerMap.get(name)); + } + + public Actor getItem(String id) { + for(Actor actor: getChildren()) { + Object userObject = actor.getUserObject(); + if(userObject != null && userObject instanceof CoreActorData + && (id.equals(((CoreActorData) userObject).id))) { + return actor; + } + } + return null; + } + + public void recalculateSize() { + float lowerX = 0, lowerY = 0, upperX = 0, upperY = 0; + for (int i = 0; i < getChildren().size; i++) { + Actor value = getChildren().get(i); + if (i == 0) { + if (value.getScaleX() > 0 && value.getWidth() * value.getScaleX() > 0) { + lowerX = value.getX(); + upperX = value.getX() + value.getWidth() * value.getScaleX(); + } else { + upperX = value.getX(); + lowerX = value.getX() + value.getWidth() * value.getScaleX(); + } + + if (value.getScaleY() > 0 && value.getHeight() * value.getScaleY() > 0) { + lowerY = value.getY(); + upperY = value.getY() + value.getHeight() * value.getScaleY(); + } else { + upperY = value.getY(); + lowerY = value.getY() + value.getHeight() * value.getScaleY(); + } + } + if (value.getScaleX() > 0 && value.getWidth() > 0) { + if (lowerX > value.getX()) lowerX = value.getX(); + if (upperX < value.getX() + value.getWidth() * value.getScaleX()) + upperX = value.getX() + value.getWidth() * value.getScaleX(); + } else { + if (upperX < value.getX()) upperX = value.getX(); + if (lowerX > value.getX() + value.getWidth() * value.getScaleX()) + lowerX = value.getX() + value.getWidth() * value.getScaleX(); + } + if (value.getScaleY() > 0 && value.getHeight() * value.getScaleY() > 0) { + if (lowerY > value.getY()) lowerY = value.getY(); + if (upperY < value.getY() + value.getHeight() * value.getScaleY()) + upperY = value.getY() + value.getHeight() * value.getScaleY(); + } else { + if (upperY < value.getY()) upperY = value.getY(); + if (lowerY > value.getY() + value.getHeight() * value.getScaleY()) + lowerY = value.getY() + value.getHeight() * value.getScaleY(); + } + + } + + setWidth(upperX); + setHeight(upperY); + } + + public void setLayerVisibility(String layerName, boolean isVisible) { + final int layerIndex = getLayerIndex(layerName); + layerMap.get(layerName).isVisible = isVisible; + + for(Actor actor: getChildren()) { + Object userObject = actor.getUserObject(); + if(userObject != null && userObject instanceof CoreActorData + && ((CoreActorData)userObject).layerIndex == layerIndex) { + actor.setVisible(isVisible); + } + } + } + + /** + * get's list of children that contain a specified tag. + * Does not yet go in depth. + * + * @param tag + * @return + */ + public Array getItemsByTag(String tag) { + Array items = new Array(); + for(Actor actor: getChildren()) { + Object userObject = actor.getUserObject(); + if(userObject != null && userObject instanceof CoreActorData) { + CoreActorData data = (CoreActorData) userObject; + if(data.tags != null && Arrays.asList(data.tags).contains(tag)) + items.add(actor); + } + } + + return items; + } + + /** + * returns children of this actor that are on specified layer + * @param layerName + * @return + */ + public Array getItemsByLayer(String layerName) { + final int layerIndex = getLayerIndex(layerName); + Array items = new Array(); + + for(Actor actor: getChildren()) { + Object userObject = actor.getUserObject(); + if(userObject != null && userObject instanceof CoreActorData + && ((CoreActorData)userObject).layerIndex == layerIndex) { + items.add(actor); + } + } + return items; + } + + public ArrayList getScripts() { + return scripts; + } + + public CompositeItemVO getVo() { + return vo; + } + + /** + * Enables customization of the CompositeActor during building. + * Example use cases: tag handling, custom variables handling + */ + public interface BuiltItemHandler { + + BuiltItemHandler DEFAULT = new BuiltItemHandler() { + @Override + public void onItemBuild(Actor item) { + + if(item instanceof CompositeActor) { + CoreActorData data = (CoreActorData) item.getUserObject(); + if(data != null && data.tags != null && Arrays.asList(data.tags).contains("button")) + item.addListener(new ButtonClickListener()); + } + } + }; + + /** + * @param item newly built and added to a parent (in case it's not a root actor) + */ + void onItemBuild(Actor item); + + } + + @Override + public void act(float delta) { + for (int i = 0; i < scripts.size(); i++) { + scripts.get(i).act(delta); + } + super.act(delta); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scripts/BasicScript.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scripts/BasicScript.java new file mode 100644 index 00000000..75622c01 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scripts/BasicScript.java @@ -0,0 +1,20 @@ +package games.rednblack.editor.renderer.scripts; + +import com.badlogic.ashley.core.Entity; + +/** + * Created by CyberJoe on 6/19/2015. + */ +public abstract class BasicScript implements IScript { + + protected Entity entity; + + @Override + public void init(Entity item) { + entity = item; + } + + public Entity getEntity() { + return entity; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scripts/IActorScript.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scripts/IActorScript.java new file mode 100644 index 00000000..d003a867 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scripts/IActorScript.java @@ -0,0 +1,12 @@ +package games.rednblack.editor.renderer.scripts; + +import games.rednblack.editor.renderer.scene2d.CompositeActor; + + +public interface IActorScript { + public void init(CompositeActor entity); + + public void act(float delta); + + public void dispose(); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scripts/IScript.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scripts/IScript.java new file mode 100644 index 00000000..ceaddbb9 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/scripts/IScript.java @@ -0,0 +1,12 @@ +package games.rednblack.editor.renderer.scripts; + +import com.badlogic.ashley.core.Entity; + + +public interface IScript { + public void init(Entity entity); + + public void act(float delta); + + public void dispose(); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/BoundingBoxSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/BoundingBoxSystem.java new file mode 100644 index 00000000..83b8c6d5 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/BoundingBoxSystem.java @@ -0,0 +1,149 @@ +package games.rednblack.editor.renderer.systems; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.components.spriter.SpriterComponent; + +public class BoundingBoxSystem extends IteratingSystem { + + final private ComponentMapper dimensionsMapper; + final private ComponentMapper parentNodeMapper; + final private ComponentMapper boundingBoxMapper; + final private ComponentMapper mainItemMapper; + final private ComponentMapper spriterMapper; + final private ComponentMapper transformMapper; + final private ComponentMapper nodeMapper; + + public BoundingBoxSystem() { + super(Family.all(BoundingBoxComponent.class).get()); + dimensionsMapper = ComponentMapper.getFor(DimensionsComponent.class); + parentNodeMapper = ComponentMapper.getFor(ParentNodeComponent.class); + boundingBoxMapper = ComponentMapper.getFor(BoundingBoxComponent.class); + mainItemMapper = ComponentMapper.getFor(MainItemComponent.class); + spriterMapper = ComponentMapper.getFor(SpriterComponent.class); + transformMapper = ComponentMapper.getFor(TransformComponent.class); + nodeMapper = ComponentMapper.getFor(NodeComponent.class); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + ParentNodeComponent parentNode = parentNodeMapper.get(entity); + BoundingBoxComponent b = boundingBoxMapper.get(entity); + + MainItemComponent m = null; + if (parentNode != null){ + m = mainItemMapper.get(parentNode.parentEntity); + } + + SpriterComponent s = spriterMapper.get(entity); + DimensionsComponent d = dimensionsMapper.get(entity); + TransformComponent t = transformMapper.get(entity); + + if (m != null && !m.visible) + return; + + if (calcCheckSum(entity) != b.checksum) { + + NodeComponent n = nodeMapper.get(entity); + if (s != null) { + com.brashmonkey.spriter.Rectangle r = s.player.getBoudingRectangle(null); + b.points[0].set(r.left, r.bottom); + b.points[1].set(r.right, r.bottom ); + b.points[2].set(r.right, r.top); + b.points[3].set(r.left, r.top); + } else if (t.rotation == 0) { + + float scaleOffsetX; + float scaleOffsetY; + + if (n==null) { + scaleOffsetX = (d.width*t.scaleX - d.width) /2 ; + scaleOffsetY = (d.height*t.scaleY - d.height) /2 ; + } else { + scaleOffsetX = 0; + scaleOffsetY = 0; + } + + b.points[0].set(t.x -scaleOffsetX,t.y -scaleOffsetY); + b.points[1].set(t.x -scaleOffsetX + d.width*t.scaleX,t.y -scaleOffsetY); + b.points[2].set(t.x -scaleOffsetX + d.width*t.scaleX,t.y -scaleOffsetY + d.height*t.scaleY); + b.points[3].set(t.x -scaleOffsetX ,t.y -scaleOffsetY + d.height*t.scaleY); + + } else { + float pivotX, pivotY; + if (n != null) { + pivotX = 0; + pivotY = 0; + } else { + pivotX = (d.width *t.scaleX) / 2; + pivotY = (d.height*t.scaleY) / 2; + } + calcFor (b, t, d, pivotX, pivotY); + } + + while (parentNode != null) { + TransformComponent parentTransform = transformMapper.get(parentNode.parentEntity); + if (parentTransform.rotation != 0) { + for(int i = 0; i < 4; i++) + b.points[i].rotate(parentTransform.rotation); + } + + for(int i = 0; i < 4; i++) { + b.points[i].x = b.points[i].x * parentTransform.scaleX + parentTransform.x; + b.points[i].y = b.points[i].y * parentTransform.scaleY + parentTransform.y; + } + parentNode = parentNodeMapper.get(parentNode.parentEntity); + } + b.checksum = calcCheckSum(entity); + b.getBoundingRect(); + } + } + + private float calcCheckSum(Entity entity) { + + ParentNodeComponent parentNode = parentNodeMapper.get(entity); + TransformComponent t = transformMapper.get(entity); + + float checksum = 0; + checksum = t.rotation + t.scaleX + t.scaleY + t.x + t.y; + while (parentNode != null) { + TransformComponent pt = transformMapper.get(parentNode.parentEntity); + checksum += pt.rotation + pt.scaleX + pt.scaleY + pt.x + pt.y; + parentNode = parentNodeMapper.get(parentNode.parentEntity); + } + return checksum; + } + + private void calcFor(BoundingBoxComponent box, TransformComponent transform, DimensionsComponent dimension, float pivotX, float pivotY) { + + float width = dimension.width*transform.scaleX; + float height = dimension.height*transform.scaleY; + + box.points[0].set(-pivotX,-pivotY); + box.points[1].set(width-pivotX, -pivotY); + box.points[2].set(-pivotX,height-pivotY); + box.points[3].set(width-pivotX,height-pivotY); + + float scaleOffsetX; + float scaleOffsetY; + + if (pivotX == 0 && pivotY == 0) { + scaleOffsetX = 0; + scaleOffsetY = 0; + } else { + scaleOffsetX = (width - dimension.width) /2 ; + scaleOffsetY = (height - dimension.height) /2 ; + } + + for(int i = 0; i < 4; i++) + box.points[i].rotate(transform.rotation); + + for(int i = 0; i < 4; i++) { + box.points[i].x = box.points[i].x + transform.x - scaleOffsetX + pivotX; + box.points[i].y = box.points[i].y + transform.y - scaleOffsetY + pivotY; + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/ButtonSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/ButtonSystem.java new file mode 100644 index 00000000..c7633711 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/ButtonSystem.java @@ -0,0 +1,81 @@ +package games.rednblack.editor.renderer.systems; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.components.additional.ButtonComponent;import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.renderer.utils.TransformMathUtils; + +/** + * Created by azakhary on 8/1/2015. + */ +public class ButtonSystem extends IteratingSystem { + + + public ButtonSystem() { + super(Family.all(ButtonComponent.class).get()); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + NodeComponent nodeComponent = ComponentRetriever.get(entity, NodeComponent.class); + + if(nodeComponent == null) return; + + for (int i = 0; i < nodeComponent.children.size; i++) { + Entity childEntity = nodeComponent.children.get(i); + MainItemComponent childMainItemComponent = ComponentRetriever.get(childEntity, MainItemComponent.class); + childMainItemComponent.visible = true; + } + + ViewPortComponent camera = ComponentRetriever.get(entity, ViewPortComponent.class); + if(camera != null) { + // if camera is on this entity, then it should not be processed + return; + } + + + for (int i = 0; i < nodeComponent.children.size; i++) { + Entity childEntity = nodeComponent.children.get(i); + MainItemComponent childMainItemComponent = ComponentRetriever.get(childEntity, MainItemComponent.class); + ZIndexComponent childZComponent = ComponentRetriever.get(childEntity, ZIndexComponent.class); + if(isTouched(entity)) { + if(childZComponent.layerName.equals("normal")) { + childMainItemComponent.visible = false; + } + if(childZComponent.layerName.equals("pressed")) { + childMainItemComponent.visible = true; + } + } else { + if(childZComponent.layerName.equals("normal")) { + childMainItemComponent.visible = true; + } + if(childZComponent.layerName.equals("pressed")) { + childMainItemComponent.visible = false; + } + } + } + + } + + private boolean isTouched(Entity entity) { + ButtonComponent buttonComponent = entity.getComponent(ButtonComponent.class); + if(Gdx.input.isTouched()) { + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + Vector2 localCoordinates = new Vector2(Gdx.input.getX(), Gdx.input.getY()); + + TransformMathUtils.globalToLocalCoordinates(entity, localCoordinates); + + if(dimensionsComponent.hit(localCoordinates.x, localCoordinates.y)) { + buttonComponent.setTouchState(true); + return true; + } + } + buttonComponent.setTouchState(false); + return false; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/CompositeSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/CompositeSystem.java new file mode 100644 index 00000000..b20e1cb7 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/CompositeSystem.java @@ -0,0 +1,144 @@ +package games.rednblack.editor.renderer.systems; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Matrix3; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.SnapshotArray; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.utils.TransformMathUtils; + +public class CompositeSystem extends IteratingSystem { + + private ComponentMapper dimensionsMapper; + private ComponentMapper transformMapper; + private ComponentMapper nodeMapper; + private ComponentMapper compositeMapper; + + private DimensionsComponent dimensionsComponent; + private NodeComponent nodeComponent; + + private final Vector2 p1 = new Vector2(); + private final Vector2 p2 = new Vector2(); + private final Vector2 p3 = new Vector2(); + private final Vector2 p4 = new Vector2(); + private final Vector2 tmpBoundPoints = new Vector2(); + + public CompositeSystem() { + super(Family.all(CompositeTransformComponent.class).get()); + dimensionsMapper = ComponentMapper.getFor(DimensionsComponent.class); + transformMapper = ComponentMapper.getFor(TransformComponent.class); + nodeMapper = ComponentMapper.getFor(NodeComponent.class); + compositeMapper = ComponentMapper.getFor(CompositeTransformComponent.class); + } + + @Override + public void processEntity(Entity entity, float deltaTime) { + dimensionsComponent = dimensionsMapper.get(entity); + nodeComponent = nodeMapper.get(entity); + TransformComponent transformComponent = transformMapper.get(entity); + + CompositeTransformComponent compositeTransformComponent = compositeMapper.get(entity); + ViewPortComponent viewPortComponent = entity.getComponent(ViewPortComponent.class); + if (compositeTransformComponent != null) { + + if (compositeTransformComponent.automaticResize && viewPortComponent == null) { + recalculateSize(); + } + + compositeTransformComponent.clipBounds.set(transformComponent.x, transformComponent.y, dimensionsComponent.width, dimensionsComponent.height); + } + } + + private void recalculateSize() { + float lowerX = Float.MAX_VALUE; + float lowerY = Float.MAX_VALUE; + float upperX = Float.MIN_VALUE; + float upperY = Float.MIN_VALUE; + SnapshotArray entities = nodeComponent.children; + for (Entity entity : entities) { + TransformComponent transformComponent = transformMapper.get(entity); + DimensionsComponent childDimCom = dimensionsMapper.get(entity); + float x = transformComponent.x; + float y = transformComponent.y; + float width = childDimCom.width; + float height = childDimCom.height; + + Matrix3 transMat = TransformMathUtils.transform(transformComponent); + + p1.set(x, y).mul(transMat); + p2.set(x + width, y).mul(transMat); + p3.set(x + width, y + height).mul(transMat); + p4.set(x, y + height).mul(transMat); + + tmpBoundPoints.set(lowerX, 0); + lowerX = getX(MinMaxOp.MIN, p1, p2, p3, p4, tmpBoundPoints); + + tmpBoundPoints.set(upperX, 0); + upperX = getX(MinMaxOp.MAX, p1, p2, p3, p4, tmpBoundPoints); + + tmpBoundPoints.set(0, lowerY); + lowerY = getY(MinMaxOp.MIN, p1, p2, p3, p4, tmpBoundPoints); + + tmpBoundPoints.set(0, upperY); + upperY = getY(MinMaxOp.MAX, p1, p2, p3, p4, tmpBoundPoints); + } + + for (Entity entity : entities) { + if (lowerX == 0 && lowerY == 0) break; + TransformComponent transformComponent = transformMapper.get(entity); + transformComponent.x -= lowerX; + transformComponent.y -= lowerY; + } + + dimensionsComponent.width = (upperX - lowerX); + dimensionsComponent.height = (upperY - lowerY); + lowerX = 0; + lowerY = 0; + dimensionsComponent.boundBox.set(lowerX, lowerY, dimensionsComponent.width, dimensionsComponent.height); + } + + private float getX(MinMaxOp op, Vector2... points) { + float pointX = points[0].x; + for (Vector2 point : points) { + pointX = op.compare(pointX, point.x); + } + return pointX; + } + + private float getY(MinMaxOp op, Vector2... points) { + float pointY = points[0].y; + for (Vector2 point : points) { + pointY = op.compare(pointY, point.y); + } + return pointY; + } + + private enum MinMaxOp { + MIN("<") { + @Override + public float compare(float a, float b) { + return (a < b) ? a : b; + } + }, + + MAX(">") { + @Override + public float compare(float a, float b) { + return (a > b) ? a : b; + } + }; + + private String minMaxOperator; + + MinMaxOp(String minMaxOperator) { + this.minMaxOperator = minMaxOperator; + } + + public abstract float compare(float a, float b); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/CullingSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/CullingSystem.java new file mode 100644 index 00000000..060454fd --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/CullingSystem.java @@ -0,0 +1,74 @@ +package games.rednblack.editor.renderer.systems; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.math.Rectangle; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; + +public class CullingSystem extends IteratingSystem { + + final private ComponentMapper viewPortMapper; + final private ComponentMapper nodeMapper; + final private ComponentMapper boundingBoxMapper; + final private ComponentMapper mainItemMapper; + final private ComponentMapper physicsBodyMapper; + + Rectangle view = new Rectangle(); + OrthographicCamera camera; + + public CullingSystem() { + super(Family.all(ViewPortComponent.class).get()); + viewPortMapper = ComponentMapper.getFor(ViewPortComponent.class); + nodeMapper = ComponentMapper.getFor(NodeComponent.class); + boundingBoxMapper = ComponentMapper.getFor(BoundingBoxComponent.class); + mainItemMapper = ComponentMapper.getFor(MainItemComponent.class); + physicsBodyMapper = ComponentMapper.getFor(PhysicsBodyComponent.class); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + ViewPortComponent viewPort = viewPortMapper.get(entity); + this.camera = (OrthographicCamera) viewPort.viewPort.getCamera(); + view.width = ( camera.viewportWidth * camera.zoom ) ; + view.height = ( camera.viewportHeight * camera.zoom ) ; + view.x = camera.position.x - ( view.width / 2 ); + view.y = camera.position.y - ( view.height / 2 ); + + NodeComponent node = nodeMapper.get(entity); + Entity[] children = node.children.begin(); + for (int i = 0, n = node.children.size; i < n; i++) { + Entity child = children[i]; + cull(child); + } + node.children.end(); + } + + void cull(Entity entity) { + BoundingBoxComponent b = boundingBoxMapper.get(entity); + if (b==null) return; + PhysicsBodyComponent p = physicsBodyMapper.get(entity); + if (p!= null) + if (p.bodyType > 1) return; + + MainItemComponent m = mainItemMapper.get(entity); + + m.visible = view.overlaps(b.rectangle); + + if (m.visible) { + NodeComponent node = nodeMapper.get(entity); + + if (node != null) { + Entity[] children = node.children.begin(); + for (int i = 0, n = node.children.size; i < n; i++) { + Entity child = children[i]; + cull(child); + } + node.children.end(); + } + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/LabelSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/LabelSystem.java new file mode 100644 index 00000000..2dd17d45 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/LabelSystem.java @@ -0,0 +1,181 @@ +package games.rednblack.editor.renderer.systems; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.GlyphLayout; +import com.badlogic.gdx.scenes.scene2d.utils.Drawable; +import com.badlogic.gdx.utils.Align; +import com.badlogic.gdx.utils.StringBuilder; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.label.LabelComponent; + +public class LabelSystem extends IteratingSystem { + private ComponentMapper labelComponentMapper = ComponentMapper.getFor(LabelComponent.class); + private ComponentMapper transformComponentMapper = ComponentMapper.getFor(TransformComponent.class); + private ComponentMapper dimensionComponentMapper = ComponentMapper.getFor(DimensionsComponent.class); + private TransformComponent transformComponent; + private LabelComponent labelComponent; + private DimensionsComponent dimensionsComponent; + + public LabelSystem() { + super(Family.all(LabelComponent.class).get()); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + + transformComponent = transformComponentMapper.get(entity); + labelComponent = labelComponentMapper.get(entity); + dimensionsComponent = dimensionComponentMapper.get(entity); + + BitmapFont font = labelComponent.cache.getFont(); + + float oldScaleX = font.getScaleX(); + float oldScaleY = font.getScaleY(); + float fontScaleX = labelComponent.fontScaleX; + float fontScaleY = labelComponent.fontScaleY; + if (fontScaleX != 1 || fontScaleY != 1) font.getData().setScale(fontScaleX, fontScaleY); + + //horisontal Align + + float textWidth = labelComponent.layout.width; + float textHeight = labelComponent.layout.height; + float textX = 0; + + /*if (labelComponent.wrap || labelComponent.text.indexOf("\n") != -1) { + // If the text can span multiple lines, determine the text's actual size so it can be aligned within the label. + labelComponent.layout.setText(font, labelComponent.text, 0, labelComponent.text.length, Color.WHITE, dimensionsComponent.width, labelComponent.lineAlign, labelComponent.wrap, null); + textWidth = labelComponent.layout.width; + textHeight = labelComponent.layout.height; + + if ((labelComponent.lineAlign & Align.left) == 0) { + if ((labelComponent.lineAlign & Align.right) != 0) + textX += dimensionsComponent.width - textWidth; + else + textX += (dimensionsComponent.width - textWidth) / 2; + } + }*/ + + //vertical Align + float textY = textHeight; + if ((labelComponent.labelAlign & Align.top) != 0) { + textY += labelComponent.cache.getFont().isFlipped() ? 0 : dimensionsComponent.height - textHeight; + textY += labelComponent.style.font.getDescent(); + } else if ((labelComponent.labelAlign & Align.bottom) != 0) { + textY += labelComponent.cache.getFont().isFlipped() ? dimensionsComponent.height - textHeight : 0; + textY -= labelComponent.style.font.getDescent(); + } else { + textY += (dimensionsComponent.height - textHeight) / 2; + } + + labelComponent.layout.setText(font, labelComponent.text, 0, labelComponent.text.length, Color.WHITE, dimensionsComponent.width, labelComponent.lineAlign, labelComponent.wrap, null); + labelComponent.cache.setText(labelComponent.layout, textX, textY); + + if (fontScaleX != 1 || fontScaleY != 1) font.getData().setScale(oldScaleX, oldScaleY); + } + +// private void scaleAndComputePrefSize () { +// BitmapFont font = labelComponent.cache.getFont(); +// float oldScaleX = font.getScaleX(); +// float oldScaleY = font.getScaleY(); +// float fontScaleX = labelComponent.fontScaleX; +// float fontScaleY = labelComponent.fontScaleY; +// if (fontScaleX != 1 || fontScaleY != 1) font.getData().setScale(fontScaleX, fontScaleY); +// +// computePrefSize(); +// +// if (fontScaleX != 1 || fontScaleY != 1) font.getData().setScale(oldScaleX, oldScaleY); +// } +// +// private void computePrefSize () { +// if (labelComponent.wrap) { +// float width = dimensionsComponent.width; +// if (labelComponent.style.background != null) width -= labelComponent.style.background.getLeftWidth() + labelComponent.style.background.getRightWidth(); +// labelComponent.layout.setText(labelComponent.cache.getFont(), labelComponent.text, Color.WHITE, width, Align.left, true); +// } else +// labelComponent.layout.setText(labelComponent.cache.getFont(), labelComponent.text); +// labelComponent.prefSize.set(labelComponent.layout.width, labelComponent.layout.height); +// } +// +// public float getPrefWidth () { +// if (labelComponent.wrap) return 0; +// scaleAndComputePrefSize(); +// float width = labelComponent.prefSize.x; +// Drawable background = labelComponent.style.background; +// if (background != null) width += background.getLeftWidth() + background.getRightWidth(); +// return width; +// } +// +// public float getPrefHeight () { +// scaleAndComputePrefSize(); +// float height = labelComponent.prefSize.y - labelComponent.style.font.getDescent() * labelComponent.fontScaleY * 2; +// Drawable background = labelComponent.style.background; +// if (background != null) height += background.getTopHeight() + background.getBottomHeight(); +// return height; +// } +// +// public void layout () { +// BitmapFont font = labelComponent.cache.getFont(); +// float oldScaleX = font.getScaleX(); +// float oldScaleY = font.getScaleY(); +// float fontScaleX = labelComponent.fontScaleX; +// float fontScaleY = labelComponent.fontScaleY; +// if (fontScaleX != 1 || fontScaleY != 1) font.getData().setScale(fontScaleX, fontScaleY); +// +// boolean wrap = labelComponent.wrap; +// +// float width = dimensionsComponent.width, height = dimensionsComponent.height; +// Drawable background = labelComponent.style.background; +// float x = 0, y = 0; +// if (background != null) { +// x = background.getLeftWidth(); +// y = background.getBottomHeight(); +// width -= background.getLeftWidth() + background.getRightWidth(); +// height -= background.getBottomHeight() + background.getTopHeight(); +// } +// +// GlyphLayout layout = labelComponent.layout; +// float textWidth, textHeight; +// StringBuilder text = labelComponent.text; +// int labelAlign = labelComponent.labelAlign; +// int lineAlign = labelComponent.lineAlign; +// if (wrap || text .indexOf("\n") != -1) { +// // If the text can span multiple lines, determine the text's actual size so it can be aligned within the label. +// layout.setText(font, text, 0, text.length, Color.WHITE, width, lineAlign , wrap, null); +// textWidth = layout.width; +// textHeight = layout.height; +// +// if ((labelAlign & Align.left) == 0) { +// if ((labelAlign & Align.right) != 0) +// x += width - textWidth; +// else +// x += (width - textWidth) / 2; +// } +// } else { +// textWidth = width; +// textHeight = font.getData().capHeight; +// } +// +// if ((labelAlign & Align.top) != 0) { +// y += labelComponent.cache.getFont().isFlipped() ? 0 : height - textHeight; +// y += labelComponent.style.font.getDescent(); +// } else if ((labelAlign & Align.bottom) != 0) { +// y += labelComponent.cache.getFont().isFlipped() ? height - textHeight : 0; +// y -= labelComponent.style.font.getDescent(); +// } else { +// y += (height - textHeight) / 2; +// } +// if (!labelComponent.cache.getFont().isFlipped()) y += textHeight; +// +// layout.setText(font, text, 0, text.length, Color.WHITE, textWidth, lineAlign, wrap, null); +// labelComponent.cache.setText(layout, x, y); +// +// if (fontScaleX != 1 || fontScaleY != 1) font.getData().setScale(oldScaleX, oldScaleY); +// } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/LayerSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/LayerSystem.java new file mode 100644 index 00000000..2df5ae2d --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/LayerSystem.java @@ -0,0 +1,95 @@ +package games.rednblack.editor.renderer.systems; + +import java.util.ArrayList; +import java.util.Comparator; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.utils.SnapshotArray; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.data.LayerItemVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +public class LayerSystem extends IteratingSystem { + + private Comparator comparator = new ZComparator(); + + private ComponentMapper zIndexMapper; + private ComponentMapper layerMapper; + private ComponentMapper nodeMapper; + + public LayerSystem() { + super(Family.all(CompositeTransformComponent.class).get()); + zIndexMapper = ComponentMapper.getFor(ZIndexComponent.class); + layerMapper = ComponentMapper.getFor(LayerMapComponent.class); + nodeMapper = ComponentMapper.getFor(NodeComponent.class); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + NodeComponent nodeComponent = nodeMapper.get(entity); + LayerMapComponent layerMapComponent = layerMapper.get(entity); + updateLayers(nodeComponent.children, layerMapComponent); + + sort(nodeComponent.children); + + if(layerMapComponent.autoIndexing){ + updateZindexes(nodeComponent.children); + } + } + + private void updateLayers(SnapshotArray children, LayerMapComponent layerMapComponent) { + for (int i = 0; i < children.size; i++) { + Entity entity = children.get(i); + ZIndexComponent zindexComponent = zIndexMapper.get(entity); + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + zindexComponent.layerIndex = getlayerIndexByName(zindexComponent.layerName,layerMapComponent); + if(zindexComponent.needReOrder && layerMapComponent.autoIndexing){ + if (zindexComponent.getZIndex() < 0) throw new IllegalArgumentException("ZIndex cannot be < 0."); + if (children.size == 1){ + zindexComponent.setZIndex(0); + zindexComponent.needReOrder = false; + return; + } + if (!children.removeValue(entity, true)) return; + if (zindexComponent.getZIndex() >= children.size) + children.add(entity); + else + children.insert(zindexComponent.getZIndex(), entity); + } + } + } + + private void updateZindexes(SnapshotArray children) { + for (int i = 0; i < children.size; i++) { + Entity entity = children.get(i); + ZIndexComponent zindexComponent = zIndexMapper.get(entity); + zindexComponent.setZIndex(i); + zindexComponent.needReOrder = false; + } + } + + private void sort(SnapshotArray children) { + children.sort(comparator); + } + + private int getlayerIndexByName(String layerName, LayerMapComponent layerMapComponent) { + if(layerMapComponent == null){ + return 0; + } + return layerMapComponent.getIndexByName(layerName); + } + + private class ZComparator implements Comparator { + @Override + public int compare(Entity e1, Entity e2) { + ZIndexComponent zIndexComponent1 = zIndexMapper.get(e1); + ZIndexComponent zIndexComponent2 = zIndexMapper.get(e2); + return zIndexComponent1.layerIndex == zIndexComponent2.layerIndex ? Integer.signum(zIndexComponent1.getZIndex() - zIndexComponent2.getZIndex()) : Integer.signum(zIndexComponent1.layerIndex - zIndexComponent2.layerIndex); + //return (int)Math.signum(pm.get(e1).z - pm.get(e2).z); + } + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/LightSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/LightSystem.java new file mode 100644 index 00000000..4aacda13 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/LightSystem.java @@ -0,0 +1,177 @@ +package games.rednblack.editor.renderer.systems; + +import box2dLight.ChainLight; +import box2dLight.ConeLight; +import box2dLight.Light; + +import box2dLight.RayHandler; +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.components.ParentNodeComponent; +import games.rednblack.editor.renderer.components.PolygonComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.light.LightBodyComponent; +import games.rednblack.editor.renderer.components.light.LightObjectComponent; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; +import games.rednblack.editor.renderer.data.LightVO; +import games.rednblack.editor.renderer.data.LightVO.LightType; +import games.rednblack.editor.renderer.physics.PhysicsBodyLoader; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +public class LightSystem extends IteratingSystem { + final private ComponentMapper lightObjectComponentMapper = ComponentMapper.getFor(LightObjectComponent.class); + final private ComponentMapper transformComponentMapper = ComponentMapper.getFor(TransformComponent.class); + final private ComponentMapper parentNodeComponentMapper = ComponentMapper.getFor(ParentNodeComponent.class); + final private ComponentMapper lightBodyComponentMapper = ComponentMapper.getFor(LightBodyComponent.class); + + private RayHandler rayHandler; + + public LightSystem() { + super(Family.one(LightObjectComponent.class, LightBodyComponent.class).get()); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + if (lightBodyComponentMapper.get(entity) != null) { + processLightBody(entity); + return; + } + + LightObjectComponent lightObjectComponent = lightObjectComponentMapper.get(entity); + TransformComponent transformComponent = transformComponentMapper.get(entity); + + Light light = lightObjectComponent.lightObject; + if (light.getRayNum() != lightObjectComponent.rays) { + light = lightObjectComponent.rebuildRays(rayHandler); + } + + ParentNodeComponent parentNodeComponent = parentNodeComponentMapper.get(entity); + + float relativeX = transformComponent.x; + float relativeY = transformComponent.y; + float relativeRotation = 0; + + Entity parentEntity = parentNodeComponent.parentEntity; + TransformComponent parentTransformComponent; + + while (parentEntity != null) { + parentTransformComponent = transformComponentMapper.get(parentEntity); + relativeX+=parentTransformComponent.x; + relativeY+=parentTransformComponent.y; + relativeRotation+=parentTransformComponent.rotation; + parentNodeComponent = parentNodeComponentMapper.get(parentEntity); + if(parentNodeComponent == null){ + break; + } + parentEntity = parentNodeComponent.parentEntity; + } + + if(light != null){ + float yy = 0; + float xx = 0; + + if(relativeRotation != 0){ + xx = transformComponent.x*MathUtils.cosDeg(relativeRotation) - transformComponent.y*MathUtils.sinDeg(relativeRotation); + yy = transformComponent.y*MathUtils.cosDeg(relativeRotation) + transformComponent.x*MathUtils.sinDeg(relativeRotation); + yy=transformComponent.y-yy; + xx=transformComponent.x-xx; + } + + light.setPosition((relativeX-xx)*PhysicsBodyLoader.getScale(), (relativeY-yy)*PhysicsBodyLoader.getScale()); + light.setSoftnessLength(lightObjectComponent.softnessLength); + light.setActive(lightObjectComponent.isActive); + light.setSoft(lightObjectComponent.isSoft); + } + + if(light != null && lightObjectComponent.getType() == LightType.CONE){ + light.setDirection(lightObjectComponent.directionDegree+relativeRotation); + } + + if (lightObjectComponent.getType() == LightVO.LightType.POINT) { + lightObjectComponent.lightObject.setColor(Color.CLEAR); + // TODO Physics and resolution part + lightObjectComponent.lightObject.setDistance(lightObjectComponent.distance * PhysicsBodyLoader.getPPWU()); + lightObjectComponent.lightObject.setStaticLight(lightObjectComponent.isStatic); + lightObjectComponent.lightObject.setXray(lightObjectComponent.isXRay); + } else { + lightObjectComponent.lightObject.setColor(Color.CLEAR); + lightObjectComponent.lightObject.setDistance(lightObjectComponent.distance * PhysicsBodyLoader.getPPWU()); + lightObjectComponent.lightObject.setStaticLight(lightObjectComponent.isStatic); + lightObjectComponent.lightObject.setDirection(lightObjectComponent.directionDegree); + ((ConeLight) lightObjectComponent.lightObject).setConeDegree(lightObjectComponent.coneDegree); + lightObjectComponent.lightObject.setXray(lightObjectComponent.isXRay); + } + } + + Vector2 tmp = new Vector2(); + + private void processLightBody(Entity entity) { + LightBodyComponent lightBodyComponent = ComponentRetriever.get(entity, LightBodyComponent.class); + PolygonComponent polygonComponent = ComponentRetriever.get(entity, PolygonComponent.class); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + PhysicsBodyComponent physicsComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class); + + if((polygonComponent == null || physicsComponent == null) && lightBodyComponent.lightObject != null) { + lightBodyComponent.lightObject.remove(); + lightBodyComponent.lightObject = null; + return; + } + + if (lightBodyComponent.lightObject != null && + (lightBodyComponent.lightObject.getRayNum() != lightBodyComponent.rays || + lightBodyComponent.needToRefreshLight)) { + lightBodyComponent.lightObject.remove(); + lightBodyComponent.lightObject = null; + lightBodyComponent.needToRefreshLight = false; + } + + if (lightBodyComponent.lightObject == null && polygonComponent != null && physicsComponent != null) { + if(polygonComponent.vertices == null) return; + + Array chainArray = new Array<>(); + + for (int i = 0; i < polygonComponent.vertices.length; i++) { + for (int j = 0; j < polygonComponent.vertices[i].length; j++) { + Vector2 point = polygonComponent.vertices[i][j]; + tmp.set(point).sub(transformComponent.originX, transformComponent.originY); + chainArray.add(tmp.x, tmp.y); + } + } + Vector2 point = polygonComponent.vertices[0][0]; + tmp.set(point).sub(transformComponent.originX, transformComponent.originY); + chainArray.add(tmp.x, tmp.y); + + int i = 0; + float[] chain = new float[chainArray.size]; + for (Float f : chainArray) { + chain[i++] = (f != null ? f*PhysicsBodyLoader.getScale() : Float.NaN); + } + + Color lightColor = new Color(lightBodyComponent.color[0], lightBodyComponent.color[1], lightBodyComponent.color[2], lightBodyComponent.color[3]); + lightBodyComponent.lightObject = new ChainLight(rayHandler, lightBodyComponent.rays, + lightColor, lightBodyComponent.distance * PhysicsBodyLoader.getPPWU(), lightBodyComponent.rayDirection, chain); + lightBodyComponent.lightObject.attachToBody(physicsComponent.body); + } + + if (lightBodyComponent.lightObject != null) { + lightBodyComponent.lightObject.setSoftnessLength(lightBodyComponent.softnessLength); + lightBodyComponent.lightObject.setDistance(lightBodyComponent.distance * PhysicsBodyLoader.getPPWU()); + lightBodyComponent.lightObject.setActive(lightBodyComponent.isActive); + lightBodyComponent.lightObject.setSoft(lightBodyComponent.isSoft); + lightBodyComponent.lightObject.setStaticLight(false);//TODO Figure out why static lights does not change position + lightBodyComponent.lightObject.setXray(lightBodyComponent.isXRay); + lightBodyComponent.lightObject.setColor(lightBodyComponent.color[0], lightBodyComponent.color[1], lightBodyComponent.color[2], lightBodyComponent.color[3]); + lightBodyComponent.lightObject.update(); + } + } + + public void setRayHandler(RayHandler rayHandler){ + this.rayHandler = rayHandler; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/ParticleSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/ParticleSystem.java new file mode 100644 index 00000000..2e4e7747 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/ParticleSystem.java @@ -0,0 +1,39 @@ +package games.rednblack.editor.renderer.systems; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.graphics.g2d.ParticleEffect; +import games.rednblack.editor.renderer.components.particle.ParticleComponent; + +public class ParticleSystem extends IteratingSystem { + + private ComponentMapper particleComponentMapper = ComponentMapper.getFor(ParticleComponent.class); + //private ComponentMapper transformComponentMapper = ComponentMapper.getFor(TransformComponent.class); + //private ComponentMapper parentNodeComponentMapper = ComponentMapper.getFor(ParentNodeComponent.class); + //private ComponentMapper nodeComponentMapper = ComponentMapper.getFor(NodeComponent.class); + + public ParticleSystem() { + super(Family.all(ParticleComponent.class).get()); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + //System.out.println("DELTAING " + entity.getId() +" " +deltaTime); + ParticleComponent particleComponent = particleComponentMapper.get(entity); + + //DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + ParticleEffect particleEffect = particleComponent.particleEffect; + particleEffect.update(deltaTime); + //ParentNodeComponent parentNodeComponent = parentNodeComponentMapper.get(entity); + +// Entity parentEntity = parentNodeComponent.parentEntity; +// while (parentEntity != null) { +// parentNodeComponent = nodeComponentMapper.get(parentEntity); +// parentEntity = parentNodeComponent.parentEntity; +// } + + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/PhysicsSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/PhysicsSystem.java new file mode 100644 index 00000000..3392d265 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/PhysicsSystem.java @@ -0,0 +1,173 @@ +package games.rednblack.editor.renderer.systems; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.ashley.utils.ImmutableArray; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.*; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.PolygonComponent; +import games.rednblack.editor.renderer.components.ScriptComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; +import games.rednblack.editor.renderer.physics.PhysicsBodyLoader; +import games.rednblack.editor.renderer.physics.PhysicsContact; +import games.rednblack.editor.renderer.scripts.IScript; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.renderer.utils.TransformMathUtils; + +public class PhysicsSystem extends IteratingSystem implements ContactListener { + + protected ComponentMapper transformComponentMapper = ComponentMapper.getFor(TransformComponent.class); + + private final float TIME_STEP = 1f/60; + private World world; + private boolean isPhysicsOn = true; + private float accumulator = 0; + + public PhysicsSystem(World world) { + super(Family.all(PhysicsBodyComponent.class).get()); + this.world = world; + } + + @Override + public void update (float deltaTime) { + for (int i = 0; i < getEntities().size(); ++i) { + processEntity(getEntities().get(i), deltaTime); + } + + if (world != null && isPhysicsOn) { + doPhysicsStep(deltaTime); + } + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + TransformComponent transformComponent = transformComponentMapper.get(entity); + + processBody(entity); + + PhysicsBodyComponent physicsBodyComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class); + Body body = physicsBodyComponent.body; + transformComponent.x = 0; + transformComponent.y = 0; + transformComponent.rotation = 0; + Vector2 localCoords = TransformMathUtils.sceneToLocalCoordinates(entity, body.getPosition().cpy().scl(1 / PhysicsBodyLoader.getScale())); + transformComponent.x = localCoords.x - transformComponent.originX; + transformComponent.y = localCoords.y - transformComponent.originY; + transformComponent.rotation = body.getAngle() * MathUtils.radiansToDegrees; + } + + protected void processBody(Entity entity) { + PhysicsBodyComponent physicsBodyComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class); + PolygonComponent polygonComponent = ComponentRetriever.get(entity, PolygonComponent.class); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + + if(polygonComponent == null && physicsBodyComponent.body != null) { + world.destroyBody(physicsBodyComponent.body); + physicsBodyComponent.body = null; + } + + if((physicsBodyComponent.body == null && polygonComponent != null) || physicsBodyComponent.needToRefreshBody) { + if(polygonComponent == null || polygonComponent.vertices == null) return; + + if (physicsBodyComponent.needToRefreshBody && physicsBodyComponent.body != null) { + world.destroyBody(physicsBodyComponent.body); + physicsBodyComponent.body = null; + physicsBodyComponent.needToRefreshBody = false; + } + + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + + physicsBodyComponent.centerX = dimensionsComponent.width/2; + physicsBodyComponent.centerY = dimensionsComponent.height/2; + + PhysicsBodyComponent bodyPropertiesComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class); + physicsBodyComponent.body = PhysicsBodyLoader.getInstance().createBody(world, entity, bodyPropertiesComponent, polygonComponent.vertices, transformComponent); + + physicsBodyComponent.body.setUserData(entity); + } + } + + private void doPhysicsStep(float deltaTime) { + // fixed time step + // max frame time to avoid spiral of death (on slow devices) + float frameTime = Math.min(deltaTime, 0.25f); + accumulator += frameTime; + while (accumulator >= TIME_STEP) { + world.step(TIME_STEP, 6, 2); + accumulator -= TIME_STEP; + } + } + + public void setPhysicsOn(boolean isPhysicsOn) { + this.isPhysicsOn = isPhysicsOn; + } + + private void processCollision(Contact contact, boolean in) { + // Get both fixtures + Fixture f1 = contact.getFixtureA(); + Fixture f2 = contact.getFixtureB(); + // Get both bodies + Body b1 = f1.getBody(); + Body b2 = f2.getBody(); + + // Get our objects that reference these bodies + Object o1 = b1.getUserData(); + Object o2 = b2.getUserData(); + + if (!(o1 instanceof Entity) || !(o2 instanceof Entity)) + return; + + // cast to entity + Entity et1 = (Entity) o1; + Entity et2 = (Entity) o2; + // get script comp + ScriptComponent ic1 = ComponentRetriever.get(et1, ScriptComponent.class); + ScriptComponent ic2 = ComponentRetriever.get(et2, ScriptComponent.class); + + // cast script to contacts, if scripts implement contacts + for (IScript sc : ic1.scripts) { + if (sc instanceof PhysicsContact) { + PhysicsContact ct = (PhysicsContact) sc; + if (in) + ct.beginContact(et2); + else + ct.endContact(et2); + } + } + + for (IScript sc : ic2.scripts) { + if (sc instanceof PhysicsContact) { + PhysicsContact ct = (PhysicsContact) sc; + if (in) + ct.beginContact(et1); + else + ct.endContact(et1); + } + } + } + + @Override + public void beginContact(Contact contact) { + processCollision(contact, true); + } + + @Override + public void endContact(Contact contact) { + processCollision(contact, false); + } + + @Override + public void preSolve(Contact contact, Manifold oldManifold) { + + } + + @Override + public void postSolve(Contact contact, ContactImpulse impulse) { + + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/ScriptSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/ScriptSystem.java new file mode 100644 index 00000000..22780837 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/ScriptSystem.java @@ -0,0 +1,27 @@ +package games.rednblack.editor.renderer.systems; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import games.rednblack.editor.renderer.components.ScriptComponent; +import games.rednblack.editor.renderer.scripts.IScript; + +/** + * Created by azakhary on 6/19/2015. + */ +public class ScriptSystem extends IteratingSystem { + + private ComponentMapper scriptComponentComponentMapper = ComponentMapper.getFor(ScriptComponent.class); + + public ScriptSystem() { + super(Family.all(ScriptComponent.class).get()); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + for(IScript script: scriptComponentComponentMapper.get(entity).scripts) { + script.act(deltaTime); + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/SpriteAnimationSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/SpriteAnimationSystem.java new file mode 100644 index 00000000..dc196bf5 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/SpriteAnimationSystem.java @@ -0,0 +1,35 @@ +package games.rednblack.editor.renderer.systems; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationStateComponent; + +public class SpriteAnimationSystem extends IteratingSystem { + private ComponentMapper tm; + private ComponentMapper sm; + private ComponentMapper sa; + + public SpriteAnimationSystem() { + super(Family.all(SpriteAnimationStateComponent.class).get()); + + tm = ComponentMapper.getFor(TextureRegionComponent.class); + sm = ComponentMapper.getFor(SpriteAnimationStateComponent.class); + sa = ComponentMapper.getFor(SpriteAnimationComponent.class); + } + + @Override + public void processEntity(Entity entity, float deltaTime) { + TextureRegionComponent tex = tm.get(entity); + SpriteAnimationStateComponent state = sm.get(entity); + state.currentAnimation.setFrameDuration(1f/sa.get(entity).fps); + tex.region = state.currentAnimation.getKeyFrame(state.time); + + if(!state.paused) { + state.time += deltaTime; + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/ActionSystem.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/ActionSystem.java new file mode 100644 index 00000000..f1fd616b --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/ActionSystem.java @@ -0,0 +1,39 @@ +package games.rednblack.editor.renderer.systems.action; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.components.ActionComponent; +import games.rednblack.editor.renderer.systems.action.data.ActionData; +import games.rednblack.editor.renderer.systems.action.logic.ActionLogic; + +/** + * Created by ZeppLondon on 10/13/2015. + */ +public class ActionSystem extends IteratingSystem { + private final ComponentMapper actionMapper; + + public ActionSystem() { + super(Family.all(ActionComponent.class).get()); + actionMapper = ComponentMapper.getFor(ActionComponent.class); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + ActionComponent actionComponent = actionMapper.get(entity); + Array dataArray = actionComponent.dataArray; + for (int i = 0; i < dataArray.size; i++) { + ActionData data = dataArray.get(i); + ActionLogic actionLogic = Actions.actionLogicMap.get(data.logicClassName); + if (actionLogic.act(deltaTime, entity, data)) { + dataArray.removeValue(data, true); + } + } + + if (dataArray.size == 0) { + entity.remove(ActionComponent.class); + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/Actions.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/Actions.java new file mode 100644 index 00000000..0d982ab2 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/Actions.java @@ -0,0 +1,280 @@ +package games.rednblack.editor.renderer.systems.action; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.Interpolation; +import games.rednblack.editor.renderer.components.ActionComponent; +import games.rednblack.editor.renderer.systems.action.data.*; +import games.rednblack.editor.renderer.systems.action.logic.*; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +import java.util.HashMap; + +/** + * Created by Eduard on 10/13/2015. + */ +public class Actions { + + public static HashMap actionLogicMap = new HashMap(); + private static boolean initialized; + + private static void initialize() throws InstantiationException, IllegalAccessException { + registerActionClass(MoveToAction.class); + registerActionClass(MoveByAction.class); + registerActionClass(SizeToAction.class); + registerActionClass(SizeByAction.class); + registerActionClass(ScaleToAction.class); + registerActionClass(ScaleByAction.class); + registerActionClass(RotateToAction.class); + registerActionClass(RotateByAction.class); + registerActionClass(ColorAction.class); + registerActionClass(AlphaAction.class); + + registerActionClass(RunnableAction.class); + registerActionClass(DelayAction.class); + + registerActionClass(ParallelAction.class); + registerActionClass(SequenceAction.class); + + initialized = true; + } + + public static void registerActionClass(Class type) throws IllegalAccessException, InstantiationException { + if (!actionLogicMap.containsKey(type.getName())) { + actionLogicMap.put(type.getName(), type.newInstance()); + } + } + + private static void checkInit() { + if (!initialized) try { + initialize(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + public static ActionData moveTo(float x, float y, float duration) { + return moveTo(x, y, duration, null); + } + + public static ActionData moveTo(float x, float y, float duration, Interpolation interpolation) { + MoveToData actionData = new MoveToData( + interpolation, + duration, + x, + y + ); + actionData.logicClassName = MoveToAction.class.getName(); + return (actionData); + } + + public static ActionData moveBy(float x, float y, float duration) { + return moveBy(x, y, duration, null); + } + + public static ActionData moveBy(float x, float y, float duration, Interpolation interpolation) { + MoveByData actionData = new MoveByData( + interpolation, + duration, + x, + y + ); + actionData.logicClassName = MoveByAction.class.getName(); + return actionData; + } + + static public ActionData run(Runnable runnable) { + RunnableData actionData = new RunnableData( + runnable + ); + actionData.logicClassName = RunnableAction.class.getName(); + return actionData; + } + + static public RotateToData rotateTo(float end, float duration) { + return rotateTo(end, duration, null); + } + + static public RotateToData rotateTo(float end, float duration, Interpolation interpolation) { + RotateToData actionData = new RotateToData( + interpolation, + duration, + end + ); + actionData.logicClassName = RotateToAction.class.getName(); + return actionData; + } + + + static public RotateByData rotateBy(float amount, float duration) { + return rotateBy(amount, duration, null); + } + + static public RotateByData rotateBy(float amount, float duration, Interpolation interpolation) { + RotateByData actionData = new RotateByData( + interpolation, + duration, + amount + ); + actionData.logicClassName = RotateByAction.class.getName(); + return actionData; + } + + public static SizeToData sizeTo(float width, float height, float duration) { + return sizeTo(width, height, duration, null); + } + + public static SizeToData sizeTo(float width, float height, float duration, Interpolation interpolation) { + SizeToData actionData = new SizeToData( + interpolation, + duration, + width, + height + ); + actionData.logicClassName = SizeToAction.class.getName(); + return actionData; + } + + public static SizeByData sizeBy(float width, float height, float duration) { + return sizeBy(width, height, duration, null); + } + + public static SizeByData sizeBy(float width, float height, float duration, Interpolation interpolation) { + SizeByData actionData = new SizeByData( + interpolation, + duration, + width, + height + ); + actionData.logicClassName = SizeByAction.class.getName(); + return actionData; + } + + public static ScaleToData scaleTo(float width, float height, float duration) { + return scaleTo(width, height, duration, null); + } + + public static ScaleToData scaleTo(float width, float height, float duration, Interpolation interpolation) { + ScaleToData actionData = new ScaleToData( + interpolation, + duration, + width, + height + ); + actionData.logicClassName = ScaleToAction.class.getName(); + return actionData; + } + + public static ScaleByData scaleBy(float width, float height, float duration) { + return scaleBy(width, height, duration, null); + } + + public static ScaleByData scaleBy(float width, float height, float duration, Interpolation interpolation) { + ScaleByData actionData = new ScaleByData( + interpolation, + duration, + width, + height + ); + actionData.logicClassName = ScaleByAction.class.getName(); + return actionData; + } + + + public static ColorData color(Color color, float duration) { + return color(color, duration, null); + } + + public static ColorData color(Color color, float duration, Interpolation interpolation) { + ColorData colorData = new ColorData( + interpolation, + duration, + color + ); + colorData.logicClassName = ColorAction.class.getName(); + return colorData; + } + + public static AlphaData alpha(float alpha, float duration) { + return alpha(alpha, duration, null); + } + + public static AlphaData alpha(float alpha, float duration, Interpolation interpolation) { + AlphaData alphaData = new AlphaData( + interpolation, + duration, + alpha + ); + alphaData.logicClassName = AlphaAction.class.getName(); + return alphaData; + } + + public static AlphaData fadeIn(float duration) { + return alpha(1, duration, null); + } + + public static AlphaData fadeIn(float duration, Interpolation interpolation) { + return alpha(1, duration, interpolation); + } + + + public static AlphaData fadeOut(float duration) { + return alpha(0, duration, null); + } + + public static AlphaData fadeOut(float duration, Interpolation interpolation) { + return alpha(0, duration, interpolation); + } + + public static DelayData delay(float duration) { + DelayData delayData = new DelayData( + duration + ); + delayData.logicClassName = DelayAction.class.getName(); + return delayData; + } + + + static public ParallelData parallel(ActionData... actionDatas) { + ParallelData actionData = new ParallelData(actionDatas); + actionData.logicClassName = ParallelAction.class.getName(); + return actionData; + } + + static public SequenceData sequence(ActionData... actionDatas) { + SequenceData actionData = new SequenceData(actionDatas); + actionData.logicClassName = SequenceAction.class.getName(); + return actionData; + } + + public static void addAction(final Entity entity, ActionData data) { + checkInit(); + ActionComponent actionComponent; + actionComponent = ComponentRetriever.get(entity, ActionComponent.class); + + if (actionComponent == null) { + actionComponent = new ActionComponent(); + entity.add(actionComponent); + } + + actionComponent.dataArray.add(data); + } + + public static void removeActions(Entity entity) { + ActionComponent actionComponent = ComponentRetriever.get(entity, ActionComponent.class); + if (actionComponent != null) { + actionComponent.dataArray.clear(); // action component with empty data array will be removed later by ActionSystem + } + } + + public static void removeAction(Entity entity, ActionData data) { + ActionComponent actionComponent = ComponentRetriever.get(entity, ActionComponent.class); + if (actionComponent != null) { + if (actionComponent.dataArray.contains(data, true)) { + actionComponent.dataArray.removeValue(data, true); + } + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/PhysicsActions.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/PhysicsActions.java new file mode 100644 index 00000000..a3beda6f --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/PhysicsActions.java @@ -0,0 +1,69 @@ +package games.rednblack.editor.renderer.systems.action; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.systems.action.data.ForceData; +import games.rednblack.editor.renderer.systems.action.logic.ActionLogic; +import games.rednblack.editor.renderer.systems.action.logic.ForceAction; + +/** + * Created by aurel on 02/04/16. + */ +public class PhysicsActions { + + + private static void initialize(Class type) { + try { + Actions.registerActionClass(type); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + /** + * Apply a force to an entity with physics component. The force is applied as long as + * the corresponding entity as a physics component. + * @param force The world force vector, usually in Newtons (N) + * @return The games.rednblack.editor.renderer.systems.action.data.ForceData object + */ + public static ForceData force(Vector2 force) { + initialize(ForceAction.class); + ForceData forceData = new ForceData(force); + + forceData.logicClassName = ForceAction.class.getName(); + return forceData; + } + + /** + * Apply a force to an entity with physics component. The force is applied as long as + * the corresponding entity as a physics component. + * @param force The world force vector, usually in Newtons (N) + * @param relativePoint The point where the force is applied relative to the body origin + * @return The games.rednblack.editor.renderer.systems.action.data.ForceData object + */ + public static ForceData force(Vector2 force, Vector2 relativePoint) { + initialize(ForceAction.class); + ForceData forceData = new ForceData(force, relativePoint); + + forceData.logicClassName = ForceAction.class.getName(); + return forceData; + } + + /** + * Apply a force to an entity with physics component. + * @param force The world force vector, usually in Newtons (N) + * @param relativePoint The point where the force is applied relative to the body origin + * @param linkedComponent The force is applied as long as the corresponding entity + * has this component + * @return The games.rednblack.editor.renderer.systems.action.data.ForceData object + */ + public static ForceData force(Vector2 force, Vector2 relativePoint, Class linkedComponent) { + ForceData forceData = force(force, relativePoint); + + forceData.linkedComponentMapper = ComponentMapper.getFor(linkedComponent); + return forceData; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ActionData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ActionData.java new file mode 100644 index 00000000..6cd4e4b1 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ActionData.java @@ -0,0 +1,9 @@ +package games.rednblack.editor.renderer.systems.action.data; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class ActionData { + public String logicClassName; + public boolean detached; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/AlphaData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/AlphaData.java new file mode 100644 index 00000000..f6068ea0 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/AlphaData.java @@ -0,0 +1,15 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/29/15. + */ +public class AlphaData extends TemporalData { + public float start, end; + + public AlphaData(Interpolation interpolation, float duration, float end) { + super(interpolation, duration); + this.end = end; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ColorData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ColorData.java new file mode 100644 index 00000000..61c44a71 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ColorData.java @@ -0,0 +1,17 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class ColorData extends TemporalData { + public float startR, startG, startB, startA; + public Color endColor = new Color(); + + public ColorData(Interpolation interpolation, float duration, Color color) { + super(interpolation, duration); + this.endColor = color; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ComponentData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ComponentData.java new file mode 100644 index 00000000..fb30cadf --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ComponentData.java @@ -0,0 +1,10 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.ashley.core.ComponentMapper; + +/** + * Created by aurel on 19/02/16. + */ +public class ComponentData extends DelegateData { + public ComponentMapper linkedComponentMapper; +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/DelayData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/DelayData.java new file mode 100644 index 00000000..9f46aaea --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/DelayData.java @@ -0,0 +1,14 @@ +package games.rednblack.editor.renderer.systems.action.data; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class DelayData extends DelegateData { + public float duration; + public float passedTime; + + public DelayData(float duration) { + super(); + this.duration = duration; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/DelegateData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/DelegateData.java new file mode 100644 index 00000000..ab3c1794 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/DelegateData.java @@ -0,0 +1,10 @@ +package games.rednblack.editor.renderer.systems.action.data; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class DelegateData extends ActionData { + public DelegateData() { + super(); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ForceData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ForceData.java new file mode 100644 index 00000000..5d40949c --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ForceData.java @@ -0,0 +1,21 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Vector2; + +/** + * Created by aurel on 19/02/16. + */ +public class ForceData extends ComponentData { + public Vector2 force; + public Vector2 relativePoint; + + public ForceData(Vector2 force) { + this(force, new Vector2(0, 0)); + } + + public ForceData(Vector2 force, Vector2 relativePoint) { + super(); + this.force = force; + this.relativePoint = relativePoint; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/MoveByData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/MoveByData.java new file mode 100644 index 00000000..fb12cb13 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/MoveByData.java @@ -0,0 +1,18 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class MoveByData extends RelativeTemporalData { + public float amountX; + public float amountY; + + + public MoveByData(Interpolation interpolation, float duration, float amountX, float amountY) { + super(interpolation, duration); + this.amountX = amountX; + this.amountY = amountY; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/MoveToData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/MoveToData.java new file mode 100644 index 00000000..804fa555 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/MoveToData.java @@ -0,0 +1,19 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class MoveToData extends TemporalData{ + public float startX; + public float startY; + public float endX; + public float endY; + + public MoveToData(Interpolation interpolation, float duration, float endX, float endY) { + super(interpolation, duration); + this.endX = endX; + this.endY = endY; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ParallelData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ParallelData.java new file mode 100644 index 00000000..c01b00d1 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ParallelData.java @@ -0,0 +1,13 @@ +package games.rednblack.editor.renderer.systems.action.data; + +/** + * Created by ZeppLondon on 10/23/15. + */ +public class ParallelData extends ActionData { + public ActionData[] actionDatas; + public boolean complete; + + public ParallelData(ActionData[] actionDatas) { + this.actionDatas = actionDatas; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RelativeTemporalData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RelativeTemporalData.java new file mode 100644 index 00000000..e9f8f753 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RelativeTemporalData.java @@ -0,0 +1,14 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class RelativeTemporalData extends TemporalData { + public float lastPercent; + + public RelativeTemporalData(Interpolation interpolation, float duration) { + super(interpolation, duration); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RotateByData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RotateByData.java new file mode 100644 index 00000000..c41938a1 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RotateByData.java @@ -0,0 +1,15 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/16/2015. + */ +public class RotateByData extends RelativeTemporalData { + public float amount; + + public RotateByData(Interpolation interpolation, float duration, float amount) { + super(interpolation, duration); + this.amount = amount; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RotateToData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RotateToData.java new file mode 100644 index 00000000..34556f48 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RotateToData.java @@ -0,0 +1,16 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/16/2015. + */ +public class RotateToData extends TemporalData { + public float start; + public float end; + + public RotateToData(Interpolation interpolation,float duration, float end) { + super(interpolation, duration); + this.end = end; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RunnableData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RunnableData.java new file mode 100644 index 00000000..8b04ba0c --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/RunnableData.java @@ -0,0 +1,14 @@ +package games.rednblack.editor.renderer.systems.action.data; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class RunnableData extends ActionData { + public Runnable runnable; + public boolean ran; + + public RunnableData(Runnable runnable) { + super(); + this.runnable = runnable; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ScaleByData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ScaleByData.java new file mode 100644 index 00000000..5feff6f4 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ScaleByData.java @@ -0,0 +1,16 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class ScaleByData extends RelativeTemporalData { + public float amountX, amountY; + + public ScaleByData(Interpolation interpolation, float duration, float amountX, float amountY) { + super(interpolation, duration); + this.amountX = amountX; + this.amountY = amountY; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ScaleToData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ScaleToData.java new file mode 100644 index 00000000..325ad1bb --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/ScaleToData.java @@ -0,0 +1,17 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class ScaleToData extends TemporalData { + public float startX, startY; + public float endX, endY; + + public ScaleToData(Interpolation interpolation, float duration, float endX, float endY) { + super(interpolation, duration); + this.endX = endX; + this.endY = endY; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/SequenceData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/SequenceData.java new file mode 100644 index 00000000..586332be --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/SequenceData.java @@ -0,0 +1,13 @@ +package games.rednblack.editor.renderer.systems.action.data; + +/** + * Created by ZeppLondon on 10/23/15. + */ +public class SequenceData extends ParallelData { + public int index; + + + public SequenceData(ActionData[] actionDatas) { + super(actionDatas); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/SizeByData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/SizeByData.java new file mode 100644 index 00000000..dd87b8e7 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/SizeByData.java @@ -0,0 +1,16 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class SizeByData extends RelativeTemporalData { + public float amountWidth, amountHeight; + + public SizeByData(Interpolation interpolation, float duration, float amountWidth, float amountHeight) { + super(interpolation, duration); + this.amountWidth = amountWidth; + this.amountHeight = amountHeight; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/SizeToData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/SizeToData.java new file mode 100644 index 00000000..419e0f4a --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/SizeToData.java @@ -0,0 +1,17 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class SizeToData extends TemporalData{ + public float startWidth, startHeight; + public float endWidth, endHeight; + + public SizeToData(Interpolation interpolation, float duration, float endWidth, float endHeight) { + super(interpolation, duration); + this.endWidth = endWidth; + this.endHeight = endHeight; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/TemporalData.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/TemporalData.java new file mode 100644 index 00000000..948a0894 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/data/TemporalData.java @@ -0,0 +1,20 @@ +package games.rednblack.editor.renderer.systems.action.data; + +import com.badlogic.gdx.math.Interpolation; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class TemporalData extends ActionData{ + public float duration; + public float passedTime; + public boolean began; + public boolean complete; + public Interpolation interpolation; + + public TemporalData(Interpolation interpolation, float duration) { + super(); + this.interpolation = interpolation; + this.duration = duration; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ActionLogic.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ActionLogic.java new file mode 100644 index 00000000..6c83f009 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ActionLogic.java @@ -0,0 +1,12 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.systems.action.data.ActionData; + +/** + * Created by ZeppLondon on 10/14/2015. + */ +abstract public class ActionLogic { + + abstract public boolean act(float delta, Entity entity, T actionData); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/AlphaAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/AlphaAction.java new file mode 100644 index 00000000..26d722cb --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/AlphaAction.java @@ -0,0 +1,23 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.TintComponent; +import games.rednblack.editor.renderer.systems.action.data.AlphaData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/29/15. + */ +public class AlphaAction extends TemporalAction { + @Override + protected void update(float percent, Entity entity, T actionData) { + TintComponent tintComponent = ComponentRetriever.get(entity, TintComponent.class); + tintComponent.color.a = actionData.start + (actionData.end - actionData.start) * percent; + } + + @Override + public void begin(Entity entity, T actionData) { + TintComponent tintComponent = ComponentRetriever.get(entity, TintComponent.class); + actionData.start = tintComponent.color.a; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ColorAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ColorAction.java new file mode 100644 index 00000000..115573c1 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ColorAction.java @@ -0,0 +1,30 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.TintComponent; +import games.rednblack.editor.renderer.systems.action.data.ColorData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class ColorAction extends TemporalAction { + @Override + protected void update(float percent, Entity entity, T actionData) { + TintComponent tintComponent = ComponentRetriever.get(entity, TintComponent.class); + float r = actionData.startR + (actionData.endColor.r - actionData.startR) * percent; + float g = actionData.startG + (actionData.endColor.g - actionData.startG) * percent; + float b = actionData.startB + (actionData.endColor.b - actionData.startB) * percent; + float a = actionData.startA + (actionData.endColor.a - actionData.startA) * percent; + tintComponent.color.set(r, g, b, a); + } + + @Override + public void begin(Entity entity, T actionData) { + TintComponent tintComponent = ComponentRetriever.get(entity, TintComponent.class); + actionData.startR = tintComponent.color.r; + actionData.startG = tintComponent.color.g; + actionData.startB = tintComponent.color.b; + actionData.startA = tintComponent.color.a; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ComponentAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ComponentAction.java new file mode 100644 index 00000000..ee6c1710 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ComponentAction.java @@ -0,0 +1,20 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.systems.action.data.ComponentData; + +/** + * Created by aurel on 19/02/16. + */ +public abstract class ComponentAction extends DelegateAction { + + @Override + public boolean act(float delta, Entity entity, T actionData) { + if (actionData.linkedComponentMapper == null || actionData.linkedComponentMapper.has(entity)) { + return delegate(delta, entity, actionData); + } + else { + return true; + } + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/DelayAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/DelayAction.java new file mode 100644 index 00000000..8f5503d3 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/DelayAction.java @@ -0,0 +1,21 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.systems.action.data.ActionData; +import games.rednblack.editor.renderer.systems.action.data.DelayData; +import games.rednblack.editor.renderer.systems.action.data.DelegateData; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class DelayAction extends DelegateAction{ + + @Override + protected boolean delegate(float delta, Entity entity, T actionData) { + if (actionData.passedTime < actionData.duration) { + actionData.passedTime += delta; + if (actionData.passedTime < actionData.duration) return false; + } + return true; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/DelegateAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/DelegateAction.java new file mode 100644 index 00000000..1d9dbf2e --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/DelegateAction.java @@ -0,0 +1,16 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.systems.action.data.DelegateData; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public abstract class DelegateAction extends ActionLogic { + @Override + public boolean act(float delta, Entity entity, T actionData) { + return delegate(delta, entity, actionData); + } + + abstract protected boolean delegate (float delta, Entity entity, T actionData); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ForceAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ForceAction.java new file mode 100644 index 00000000..fe9bf13b --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ForceAction.java @@ -0,0 +1,33 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; +import games.rednblack.editor.renderer.systems.action.data.ForceData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.renderer.utils.ForceUtils; + +/** + * Created by aurel on 19/02/16. + */ +public class ForceAction extends ComponentAction { + + private ComponentMapper physicsBodyComponentMapper; + + public ForceAction() { + this.physicsBodyComponentMapper = ComponentMapper.getFor(PhysicsBodyComponent.class); + } + + @Override + protected boolean delegate(float delta, Entity entity, ForceData actionData) { + if (physicsBodyComponentMapper.has(entity)) { + PhysicsBodyComponent physicsBodyComponent = physicsBodyComponentMapper.get(entity); + + ForceUtils.applyForce(actionData.force, physicsBodyComponent.body, actionData.relativePoint); + return false; + } + + return true; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/MoveByAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/MoveByAction.java new file mode 100644 index 00000000..586b484a --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/MoveByAction.java @@ -0,0 +1,22 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.systems.action.data.MoveByData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class MoveByAction extends RelativeTemporalAction { + @Override + protected void updateRelative(float percentDelta, Entity entity, T actionData) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + + float amountX = actionData.amountX*percentDelta; + float amountY = actionData.amountY*percentDelta; + + transformComponent.x += amountX; + transformComponent.y += amountY; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/MoveToAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/MoveToAction.java new file mode 100644 index 00000000..6f1a20d5 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/MoveToAction.java @@ -0,0 +1,34 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.systems.action.data.MoveToData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/13/2015. + */ +public class MoveToAction extends TemporalAction { + @Override + public void update(float percent, Entity entity, T actionData) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + + float x = actionData.startX + (actionData.endX - actionData.startX) * percent; + float y = actionData.startY + (actionData.endY - actionData.startY) * percent; + + transformComponent.x = x; + transformComponent.y = y; + } + + @Override + public void begin(Entity entity, T actionData) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + actionData.startX = transformComponent.x; + actionData.startY = transformComponent.y; + } + + @Override + public void end(Entity entity, MoveToData actionData) { + + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ParallelAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ParallelAction.java new file mode 100644 index 00000000..55ce997e --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ParallelAction.java @@ -0,0 +1,27 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.systems.action.Actions; +import games.rednblack.editor.renderer.systems.action.data.ActionData; +import games.rednblack.editor.renderer.systems.action.data.ParallelData; + +/** + * Created by ZeppLondon on 10/23/15. + */ +public class ParallelAction extends ActionLogic { + @Override + public boolean act(float delta, Entity entity, T actionData) { + actionData.complete = true; + for (int i = 0; i < actionData.actionDatas.length; i++) { + ActionData data = actionData.actionDatas[i]; + ActionLogic logic = Actions.actionLogicMap.get(actionData.actionDatas[i].logicClassName); + if (!data.detached) { + actionData.complete = false; + if (logic.act(delta, entity, data)) { + data.detached = true; + } + } + } + return actionData.complete; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RelativeTemporalAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RelativeTemporalAction.java new file mode 100644 index 00000000..90870ed6 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RelativeTemporalAction.java @@ -0,0 +1,23 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.systems.action.data.RelativeTemporalData; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public abstract class RelativeTemporalAction extends TemporalAction { + @Override + protected void update(float percent, Entity entity, T actionData) { + updateRelative(percent - actionData.lastPercent, entity, actionData); + actionData.lastPercent = percent; + } + + @Override + public void begin(Entity entity, T actionData) { + RelativeTemporalData data = actionData; + data.lastPercent = 0; + } + + abstract protected void updateRelative (float percentDelta, Entity entity, T actionData); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RotateByAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RotateByAction.java new file mode 100644 index 00000000..5ef87bfc --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RotateByAction.java @@ -0,0 +1,18 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.systems.action.data.ActionData; +import games.rednblack.editor.renderer.systems.action.data.RotateByData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/16/2015. + */ +public class RotateByAction extends RelativeTemporalAction { + @Override + protected void updateRelative(float percentDelta, Entity entity, T actionData) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.rotation += actionData.amount * percentDelta; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RotateToAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RotateToAction.java new file mode 100644 index 00000000..771ad311 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RotateToAction.java @@ -0,0 +1,23 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.systems.action.data.RotateToData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/16/2015. + */ +public class RotateToAction extends TemporalAction { + @Override + protected void update(float percent, Entity entity, T actionData) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.rotation = (actionData.start + (actionData.end - actionData.start) * percent); + } + + @Override + public void begin(Entity entity, T actionData) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + actionData.start = transformComponent.rotation; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RunnableAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RunnableAction.java new file mode 100644 index 00000000..2c2819b4 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/RunnableAction.java @@ -0,0 +1,22 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.systems.action.data.RunnableData; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public class RunnableAction extends ActionLogic { + @Override + public boolean act(float delta, Entity entity, T actionData) { + if (!actionData.ran) { + actionData.ran = true; + run(entity, actionData); + } + return true; + } + + public void run(Entity entity, T actionData) { + actionData.runnable.run(); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ScaleByAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ScaleByAction.java new file mode 100644 index 00000000..7aff0518 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ScaleByAction.java @@ -0,0 +1,18 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.systems.action.data.ScaleByData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class ScaleByAction extends RelativeTemporalAction { + @Override + protected void updateRelative(float percent, Entity entity, T actionData) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.scaleX += actionData.amountX * percent; + transformComponent.scaleY += actionData.amountY * percent; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ScaleToAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ScaleToAction.java new file mode 100644 index 00000000..ac550194 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/ScaleToAction.java @@ -0,0 +1,25 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.systems.action.data.ScaleToData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class ScaleToAction extends TemporalAction { + @Override + protected void update(float percent, Entity entity, T actionData) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.scaleX = actionData.startX + (actionData.endX - actionData.startX) * percent; + transformComponent.scaleY = actionData.startY + (actionData.endY - actionData.startY) * percent; + } + + @Override + public void begin(Entity entity, T actionData) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + actionData.startX = transformComponent.scaleX; + actionData.startY = transformComponent.scaleY; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/SequenceAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/SequenceAction.java new file mode 100644 index 00000000..438edf84 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/SequenceAction.java @@ -0,0 +1,21 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.systems.action.Actions; +import games.rednblack.editor.renderer.systems.action.data.SequenceData; + +/** + * Created by ZeppLondon on 10/23/15. + */ +public class SequenceAction extends ParallelAction { + @Override + public boolean act(float delta, Entity entity, T actionData) { + if (actionData.index >= actionData.actionDatas.length) return true; + ActionLogic logic = Actions.actionLogicMap.get(actionData.actionDatas[actionData.index].logicClassName); + if (logic.act(delta, entity, actionData.actionDatas[actionData.index])) { + actionData.index++; + if (actionData.index >= actionData.actionDatas.length) return true; + } + return false; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/SizeByAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/SizeByAction.java new file mode 100644 index 00000000..9497943b --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/SizeByAction.java @@ -0,0 +1,18 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.systems.action.data.SizeByData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class SizeByAction extends RelativeTemporalAction { + @Override + protected void updateRelative(float percentDelta, Entity entity, T actionData) { + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + dimensionsComponent.width += actionData.amountWidth * percentDelta; + dimensionsComponent.height += actionData.amountHeight * percentDelta; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/SizeToAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/SizeToAction.java new file mode 100644 index 00000000..362c08d7 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/SizeToAction.java @@ -0,0 +1,25 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.systems.action.data.SizeToData; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by ZeppLondon on 10/28/15. + */ +public class SizeToAction extends TemporalAction { + @Override + protected void update(float percent, Entity entity, T actionData) { + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + dimensionsComponent.width = actionData.startWidth + (actionData.endHeight - actionData.startWidth) * percent; + dimensionsComponent.height = actionData.startHeight + (actionData.endHeight - actionData.startHeight) * percent; + } + + @Override + public void begin(Entity entity, T actionData) { + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + actionData.startWidth = dimensionsComponent.width; + actionData.startHeight = dimensionsComponent.height; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/TemporalAction.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/TemporalAction.java new file mode 100644 index 00000000..8da0ac61 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/action/logic/TemporalAction.java @@ -0,0 +1,42 @@ +package games.rednblack.editor.renderer.systems.action.logic; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.systems.action.data.TemporalData; + +/** + * Created by ZeppLondon on 10/15/2015. + */ +public abstract class TemporalAction extends ActionLogic { + @Override + public boolean act(float delta, Entity entity, T actionData) { + if (actionData.complete) return true; + + if (!actionData.began) { + begin(entity, actionData); + actionData.began = true; + } + + actionData.passedTime += delta; + actionData.complete = actionData.passedTime >= actionData.duration; + float percent; + if (actionData.complete) { + percent = 1; + } else { + percent = actionData.passedTime / actionData.duration; + if (actionData.interpolation != null) percent = actionData.interpolation.apply(percent); + } + update(percent, entity, actionData); + if (actionData.complete) end(entity, actionData); + return actionData.complete; + } + + abstract protected void update (float percent, Entity entity, T actionData); + + public void begin(Entity entity, T actionData) { + + } + + public void end(Entity entity, T actionData) { + + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/HyperLap2dRenderer.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/HyperLap2dRenderer.java new file mode 100644 index 00000000..2a0b92e9 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/HyperLap2dRenderer.java @@ -0,0 +1,322 @@ +package games.rednblack.editor.renderer.systems.render; + +import box2dLight.RayHandler; +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.systems.IteratingSystem; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.*; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder; +import com.badlogic.gdx.graphics.glutils.FrameBuffer; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; +import com.badlogic.gdx.math.Affine2; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack; +import com.badlogic.gdx.utils.viewport.Viewport; +import games.rednblack.editor.renderer.SceneLoader; +import games.rednblack.editor.renderer.commons.IExternalItemType; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.physics.PhysicsBodyLoader; +import games.rednblack.editor.renderer.systems.render.logic.DrawableLogicMapper; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +import java.util.Map; + + +public class HyperLap2dRenderer extends IteratingSystem { + private final float TIME_STEP = 1f/60; + + private ComponentMapper viewPortMapper = ComponentMapper.getFor(ViewPortComponent.class); + private ComponentMapper compositeTransformMapper = ComponentMapper.getFor(CompositeTransformComponent.class); + private ComponentMapper nodeMapper = ComponentMapper.getFor(NodeComponent.class); + private ComponentMapper parentNodeMapper = ComponentMapper.getFor(ParentNodeComponent.class); + private ComponentMapper transformMapper = ComponentMapper.getFor(TransformComponent.class); + private ComponentMapper mainItemComponentMapper = ComponentMapper.getFor(MainItemComponent.class); + private ComponentMapper shaderComponentMapper = ComponentMapper.getFor(ShaderComponent.class); + private ComponentMapper dimensionsComponentComponentMapper = ComponentMapper.getFor(DimensionsComponent.class); + + private DrawableLogicMapper drawableLogicMapper; + private RayHandler rayHandler; + private Camera camera; +// private World world; + + //private Box2DDebugRenderer debugRenderer = new Box2DDebugRenderer(); + + public static float timeRunning = 0; + + public Batch batch; + //ShaderManager shaderManager = new ShaderManager(); + + public HyperLap2dRenderer(Batch batch) { + super(Family.all(ViewPortComponent.class).get()); + this.batch = batch; + drawableLogicMapper = new DrawableLogicMapper(); + //shaderManager.createFrameBuffer("main"); + } + + public void addDrawableType(IExternalItemType itemType) { + drawableLogicMapper.addDrawableToMap(itemType.getTypeId(), itemType.getDrawable()); + } + + @Override + public void processEntity(Entity entity, float deltaTime) { + timeRunning+=deltaTime; + + ViewPortComponent ViewPortComponent = viewPortMapper.get(entity); + Viewport viewport = ViewPortComponent.viewPort; + camera = viewport.getCamera(); + + camera.update(); + batch.setProjectionMatrix(camera.combined); + + //shaderManager.beginFrameBuffer("main"); + batch.begin(); + drawRecursively(entity, 1f); + batch.end(); + + /*shaderManager.endFrameBuffer(); + shaderManager.begin(SceneLoader.createDefaultShader()); + shaderManager.renderFrameBuffer("main"); + shaderManager.end();*/ + + if (rayHandler != null) { + rayHandler.setCulling(true); + OrthographicCamera orthoCamera = (OrthographicCamera) camera; + + rayHandler.setCombinedMatrix(camera.combined.scl(1f/PhysicsBodyLoader.getScale()), + camera.position.x * PhysicsBodyLoader.getScale(), + camera.position.y * PhysicsBodyLoader.getScale(), + 2 * camera.viewportWidth * orthoCamera.zoom * PhysicsBodyLoader.getScale(), + 2 * camera.viewportHeight * orthoCamera.zoom * PhysicsBodyLoader.getScale()); + rayHandler.updateAndRender(); + } + //debugRenderer.render(world, camera.combined); + } + + private void drawRecursively(Entity rootEntity, float parentAlpha) { + CompositeTransformComponent curCompositeTransformComponent = compositeTransformMapper.get(rootEntity); + TransformComponent transform = transformMapper.get(rootEntity); + + boolean scissors = false; + + if (curCompositeTransformComponent.transform || transform.rotation != 0 || transform.scaleX !=1 || transform.scaleY !=1){ + computeTransform(rootEntity); + applyTransform(rootEntity, batch); + } + + if (curCompositeTransformComponent.scissorsEnabled) { + batch.flush(); + //TODO Scissors rectangle does not rotate.. why? Uhm + ScissorStack.calculateScissors(camera, curCompositeTransformComponent.oldTransform, curCompositeTransformComponent.clipBounds, curCompositeTransformComponent.scissors); + if (ScissorStack.pushScissors(curCompositeTransformComponent.scissors)) { + scissors = true; + } + } + + applyShader(rootEntity, batch); + + TintComponent tintComponent = ComponentRetriever.get(rootEntity, TintComponent.class); + parentAlpha *= tintComponent.color.a; + + drawChildren(rootEntity, batch, curCompositeTransformComponent, parentAlpha); + + if (curCompositeTransformComponent.transform || transform.rotation != 0 || transform.scaleX !=1 || transform.scaleY !=1) + resetTransform(rootEntity, batch); + + resetShader(rootEntity, batch); + + if (scissors) { + batch.flush(); + ScissorStack.popScissors(); + } + } + + private void drawChildren(Entity rootEntity, Batch batch, CompositeTransformComponent curCompositeTransformComponent, float parentAlpha) { + NodeComponent nodeComponent = nodeMapper.get(rootEntity); + Entity[] children = nodeComponent.children.begin(); + TransformComponent transform = transformMapper.get(rootEntity); + if (curCompositeTransformComponent.transform || transform.rotation != 0 || transform.scaleX !=1 || transform.scaleY !=1) { + for (int i = 0, n = nodeComponent.children.size; i < n; i++) { + Entity child = children[i]; + + LayerMapComponent rootLayers = ComponentRetriever.get(rootEntity, LayerMapComponent.class); + ZIndexComponent childZIndexComponent = ComponentRetriever.get(child, ZIndexComponent.class); + + if(!rootLayers.isVisible(childZIndexComponent.layerName)) { + continue; + } + + MainItemComponent childMainItemComponent = mainItemComponentMapper.get(child); + if(!childMainItemComponent.visible){ + continue; + } + + int entityType = childMainItemComponent.entityType; + + NodeComponent childNodeComponent = nodeMapper.get(child); + + if(childNodeComponent ==null){ + drawEntity(entityType, batch, child, parentAlpha); + }else{ + //Step into Composite + drawRecursively(child, parentAlpha); + } + } + } else { + // No transform for this group, offset each child. + TransformComponent compositeTransform = transformMapper.get(rootEntity); + + float offsetX = compositeTransform.x, offsetY = compositeTransform.y; + + if(viewPortMapper.has(rootEntity)){ + offsetX = 0; + offsetY = 0; + } + + for (int i = 0, n = nodeComponent.children.size; i < n; i++) { + Entity child = children[i]; + + LayerMapComponent rootLayers = ComponentRetriever.get(rootEntity, LayerMapComponent.class); + ZIndexComponent childZIndexComponent = ComponentRetriever.get(child, ZIndexComponent.class); + + if(!rootLayers.isVisible(childZIndexComponent.layerName)) { + continue; + } + + MainItemComponent childMainItemComponent = mainItemComponentMapper.get(child); + if(!childMainItemComponent.visible){ + continue; + } + + TransformComponent childTransformComponent = transformMapper.get(child); + float cx = childTransformComponent.x, cy = childTransformComponent.y; + childTransformComponent.x = cx + offsetX; + childTransformComponent.y = cy + offsetY; + + NodeComponent childNodeComponent = nodeMapper.get(child); + int entityType = mainItemComponentMapper.get(child).entityType; + + if(childNodeComponent ==null){ + drawEntity(entityType, batch, child, parentAlpha); + }else{ + //Step into Composite + drawRecursively(child, parentAlpha); + } + childTransformComponent.x = cx; + childTransformComponent.y = cy; + } + } + nodeComponent.children.end(); + } + + private void drawEntity(int entityType, Batch batch, Entity child, float parentAlpha) { + applyShader(child, batch); + //Find the logic from mapper and draw it + drawableLogicMapper.getDrawable(entityType).draw(batch, child, parentAlpha); + + resetShader(child, batch); + } + + /** Returns the transform for this group's coordinate system. + * @param rootEntity */ + protected Matrix4 computeTransform(Entity rootEntity) { + CompositeTransformComponent curCompositeTransformComponent = compositeTransformMapper.get(rootEntity); + ParentNodeComponent parentNodeComponent = parentNodeMapper.get(rootEntity); + TransformComponent curTransform = transformMapper.get(rootEntity); + Affine2 worldTransform = curCompositeTransformComponent.worldTransform; + + float originX = curTransform.originX; + float originY = curTransform.originY; + float x = curTransform.x; + float y = curTransform.y; + float rotation = curTransform.rotation; + float scaleX = curTransform.scaleX; + float scaleY = curTransform.scaleY; + + worldTransform.setToTrnRotScl(x + originX, y + originY, rotation, scaleX, scaleY); + if (originX != 0 || originY != 0) worldTransform.translate(-originX, -originY); + + // Find the parent that transforms. + + CompositeTransformComponent parentTransformComponent = null; + + Entity parentEntity = null; + if(parentNodeComponent != null){ + parentEntity = parentNodeComponent.parentEntity; + } + + if (parentEntity != null){ + parentTransformComponent = compositeTransformMapper.get(parentEntity); + TransformComponent transform = transformMapper.get(parentEntity); + if(curCompositeTransformComponent.transform || transform.rotation != 0 || transform.scaleX !=1 || transform.scaleY !=1) + worldTransform.preMul(parentTransformComponent.worldTransform); + } + + curCompositeTransformComponent.computedTransform.set(worldTransform); + return curCompositeTransformComponent.computedTransform; + } + + protected void applyTransform (Entity rootEntity, Batch batch) { + CompositeTransformComponent curCompositeTransformComponent = compositeTransformMapper.get(rootEntity); + curCompositeTransformComponent.oldTransform.set(batch.getTransformMatrix()); + batch.setTransformMatrix(curCompositeTransformComponent.computedTransform); + } + + protected void resetTransform (Entity rootEntity, Batch batch) { + CompositeTransformComponent curCompositeTransformComponent = compositeTransformMapper.get(rootEntity); + batch.setTransformMatrix(curCompositeTransformComponent.oldTransform); + } + + protected void applyShader(Entity entity, Batch batch) { + if(shaderComponentMapper.has(entity)){ + ShaderComponent shaderComponent = shaderComponentMapper.get(entity); + if(shaderComponent.getShader() != null) { + batch.setShader(shaderComponent.getShader()); + + batch.getShader().setUniformf("deltaTime", Gdx.graphics.getDeltaTime()); + batch.getShader().setUniformf("time", HyperLap2dRenderer.timeRunning); + batch.getShader().setUniformf("screen_size", dimensionsComponentComponentMapper.get(entity).width, + dimensionsComponentComponentMapper.get(entity).height); + + for (Map.Entry entry : mainItemComponentMapper.get(entity).customVariables.getHashMap().entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + if (key.startsWith("_shader_")) { + batch.getShader().setUniformf(key.replace("_shader_", ""), Float.parseFloat(value)); + } + } + + GL20 gl = Gdx.gl20; + int error; + if ((error = gl.glGetError()) != GL20.GL_NO_ERROR) { + Gdx.app.log("opengl", "Error: " + error); + Gdx.app.log("opengl", shaderComponent.getShader().getLog()); + //throw new RuntimeException( ": glError " + error); + } + } + } + } + + protected void resetShader(Entity entity, Batch batch) { + if(shaderComponentMapper.has(entity)){ + batch.setShader(null); + } + } + + public void setRayHandler(RayHandler rayHandler){ + this.rayHandler = rayHandler; + } + +// public void setBox2dWorld(World world) { +// this.world = world; +// } + + public Batch getBatch() { + return batch; + } +} + diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/ShaderManager.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/ShaderManager.java new file mode 100644 index 00000000..de76caf3 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/ShaderManager.java @@ -0,0 +1,254 @@ +package games.rednblack.editor.renderer.systems.render; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.*; +import com.badlogic.gdx.graphics.glutils.FrameBuffer; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.utils.ArrayMap; +import com.badlogic.gdx.utils.GdxRuntimeException; + +import java.util.Stack; + +public class ShaderManager { + private final ArrayMap shaders; + private final ArrayMap frameBuffers; + private final Stack activeFrameBuffers; + private final Camera screenCamera; + private final Mesh screenMesh; + private ShaderProgram currentShader; + private int currentTextureId; + + public ShaderManager() { + shaders = new ArrayMap<>(); + + frameBuffers = new ArrayMap<>(); + activeFrameBuffers = new Stack<>(); + + screenCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + screenMesh = new Mesh(true, 4, 6, + new VertexAttribute(VertexAttributes.Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE), + new VertexAttribute(VertexAttributes.Usage.ColorUnpacked, 4, ShaderProgram.COLOR_ATTRIBUTE), + new VertexAttribute(VertexAttributes.Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE + "0")); + + Vector3 vec0 = new Vector3(0, 0, 0); + screenCamera.unproject(vec0); + Vector3 vec1 = new Vector3(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 0); + screenCamera.unproject(vec1); + screenMesh.setVertices(new float[]{ + vec0.x, vec0.y, 0, 1, 1, 1, 1, 0, 1, + vec1.x, vec0.y, 0, 1, 1, 1, 1, 1, 1, + vec1.x, vec1.y, 0, 1, 1, 1, 1, 1, 0, + vec0.x, vec1.y, 0, 1, 1, 1, 1, 0, 0}); + screenMesh.setIndices(new short[]{0, 1, 2, 2, 3, 0}); + screenCamera.translate(0f, -1f, 0f); + screenCamera.update(); + } + + public void begin(String shaderName) { + // check if we have a shader that has not been end()ed + if (currentShader != null) { + throw new IllegalArgumentException("Before calling begin() for a new shader please call end() for the current one!"); + } + // check if we have a program for that name + ShaderProgram program = shaders.get(shaderName); + + begin(program); + } + + public void begin(ShaderProgram program) { + // check if we have a shader that has not been end()ed + if (currentShader != null) { + throw new IllegalArgumentException("Before calling begin() for a new shader please call end() for the current one!"); + } + + currentTextureId = 0; + + currentShader = program; + currentShader.begin(); + } + + public void end() { + currentShader.end(); + currentShader = null; + } + + /** + * Creates a new FrameBuffer with the format RGBA8888 and Gdx.graphics.getWidth() and Gdx.graphics.getHeight() + * + * @param frameBufferName name of the new FrameBuffer + */ + public void createFrameBuffer(String frameBufferName) { + createFrameBuffer(frameBufferName, Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + } + + /** + * Creates a new FrameBuffer with the format RGBA8888 and the given width and height + * + * @param frameBufferName name of the new FrameBuffer + * @param width of the FrameBuffer + * @param height of the FrameBuffer + */ + public void createFrameBuffer(String frameBufferName, int width, int height) { + createFrameBuffer(frameBufferName, Pixmap.Format.RGBA8888, width, height); + } + + /** + * Creates a new FrameBuffer with the format RGBA8888 and the given width and height + * + * @param frameBufferName name of the new FrameBuffer + * @param format of the FrameBuffer, see Pixmap.Format for valid values + * @param width of the FrameBuffer + * @param height of the FrameBuffer + */ + public void createFrameBuffer(String frameBufferName, Pixmap.Format format, int width, int height) { + if (frameBuffers.containsKey(frameBufferName)) { + throw new IllegalArgumentException("A framebuffer with the name '" + frameBufferName + "' already exists"); + } + FrameBuffer frameBuffer = new FrameBuffer(format, width, height, false, false); + frameBuffers.put(frameBufferName, frameBuffer); + } + + /** + * Start rendering into the given FrameBuffer + * + * @param frameBufferName name of the FrameBuffer + */ + public void beginFrameBuffer(String frameBufferName) { + beginFrameBuffer(frameBufferName, 0f, 0f, 0f, 0f); + } + + /** + * Start rendering into the given FrameBuffer with the specified clear color. + * + * @param frameBufferName name of the FrameBuffer + */ + public void beginFrameBuffer(String frameBufferName, float clearColorRed, float clearColorGreen, float clearColorBlue, float clearColorAlpha) { + if (!frameBuffers.containsKey(frameBufferName)) { + throw new IllegalArgumentException("A framebuffer with the name '" + frameBufferName + "' has not been created"); + } + final FrameBuffer frameBuffer = frameBuffers.get(frameBufferName); + frameBuffer.begin(); + activeFrameBuffers.push(frameBuffer); + + //Gdx.graphics.getGL20().glClearColor(clearColorRed, clearColorGreen, clearColorBlue, clearColorAlpha); + initInitialFrameBufferState(frameBuffer); + } + + /** + * Sets the initial state when a FrameBuffer starts. Override to set your own state. + * + * @param frameBuffer the FrameBuffer for which the state is initialized + */ + protected void initInitialFrameBufferState(FrameBuffer frameBuffer) { + Gdx.graphics.getGL20().glViewport(0, 0, frameBuffer.getWidth(), frameBuffer.getHeight()); + Gdx.graphics.getGL20().glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); + Gdx.graphics.getGL20().glEnable(GL20.GL_TEXTURE_2D); + Gdx.graphics.getGL20().glEnable(GL20.GL_BLEND); + Gdx.graphics.getGL20().glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); + } + + /** + * Stops rendering to the current FrameBuffer + */ + public void endFrameBuffer() { + if (activeFrameBuffers.empty()) { + throw new GdxRuntimeException("There is no active frame buffer that can be ended"); + } + final FrameBuffer frameBuffer = activeFrameBuffers.pop(); + frameBuffer.end(); + } + + /** + * Renders the given FrameBuffer to the screen using the current ShaderProgram + * + * @param frameBufferName name of the FrameBuffer to render + */ + public void renderFrameBuffer(String frameBufferName) { + renderFrameBuffer(frameBufferName, screenMesh); + } + + /** + * Renders the given FrameBuffer onto a Mesh using the current ShaderProgram + * + * @param frameBufferName name of the FrameBuffer to render + * @param target Mesh to render onto + */ + public void renderFrameBuffer(String frameBufferName, Mesh target) { + if (currentShader == null) { + throw new GdxRuntimeException("Rendering the frame buffers needs an active shader"); + } + FrameBuffer frameBuffer = frameBuffers.get(frameBufferName); + if (frameBuffer == null) { + throw new GdxRuntimeException("A framebuffer with the name '" + frameBufferName + "' could not be found"); + } + frameBuffer.getColorBufferTexture().bind(0); + currentShader.setUniformMatrix("u_projTrans", screenCamera.combined); + currentShader.setUniformi("u_texture", 0); + target.render(currentShader, GL20.GL_TRIANGLES); + } + + /** + * Return the FrameBuffer with the given name + * + * @param frameBufferName Name of the FrameBuffer to return + * @return a FrameBuffer or null if there is no such FrameBuffer + */ + public FrameBuffer getFrameBuffer(String frameBufferName) { + return frameBuffers.get(frameBufferName); + } + + /** + * Returns the currently active shader. + * + * @return a valid ShaderProgram or null + */ + public ShaderProgram getCurrentShader() { + return currentShader; + } + + public void setUniformMatrix(String uniformName, Matrix4 matrix) { + if (currentShader == null) { + throw new GdxRuntimeException("Please call begin() before setting uniforms"); + } + currentShader.setUniformMatrix(uniformName, matrix); + } + + public void setUniformf(String uniformName, float value) { + if (currentShader == null) { + throw new GdxRuntimeException("Please call begin() before setting uniforms"); + } + currentShader.setUniformf(uniformName, value); + } + + public void setUniform2fv(String uniformName, float[] values) { + if (currentShader == null) { + throw new GdxRuntimeException("Please call begin() before setting uniforms"); + } + currentShader.setUniform2fv(uniformName, values, 0, 2); + } + + public void setUniformTexture(String uniformName, Texture texture) { + if (currentShader == null) { + throw new GdxRuntimeException("Please call begin() before setting uniforms"); + } + + int textureId = ++currentTextureId; + texture.bind(textureId); + currentShader.setUniformi(uniformName, textureId); + } + + /** + * ShaderManager needs to be disposed if not used anymore. + */ + public void dispose() { + for (ShaderProgram program : shaders.values()) { + program.dispose(); + } + shaders.clear(); + + screenMesh.dispose(); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/Drawable.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/Drawable.java new file mode 100644 index 00000000..740c2b21 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/Drawable.java @@ -0,0 +1,8 @@ +package games.rednblack.editor.renderer.systems.render.logic; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Batch; + +public interface Drawable { + public abstract void draw(Batch batch, Entity entity, float parentAlpha); +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/DrawableLogicMapper.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/DrawableLogicMapper.java new file mode 100644 index 00000000..c911d6ad --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/DrawableLogicMapper.java @@ -0,0 +1,32 @@ +package games.rednblack.editor.renderer.systems.render.logic; + +import java.util.HashMap; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Batch; +import games.rednblack.editor.renderer.factory.EntityFactory; + +public class DrawableLogicMapper { + + private HashMap logicClassMap; + + public DrawableLogicMapper() { + logicClassMap = new HashMap<>(); + logicClassMap.put(EntityFactory.IMAGE_TYPE, new TextureRegionDrawLogic()); + logicClassMap.put(EntityFactory.LABEL_TYPE, new LabelDrawableLogic()); + logicClassMap.put(EntityFactory.NINE_PATCH, new NinePatchDrawableLogic()); + logicClassMap.put(EntityFactory.PARTICLE_TYPE, new ParticleDrawableLogic()); + logicClassMap.put(EntityFactory.SPRITE_TYPE, new SpriteDrawableLogic()); + logicClassMap.put(EntityFactory.SPRITER_TYPE, new SpriterDrawableLogic()); + logicClassMap.put(EntityFactory.COLOR_PRIMITIVE,new TextureRegionDrawLogic()); + logicClassMap.put(EntityFactory.LIGHT_TYPE, new LightDrawableLogic()); + } + + public void addDrawableToMap(int type, Drawable drawable) { + logicClassMap.put(type, drawable); + } + + public Drawable getDrawable(int type){ + return logicClassMap.get(type); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/LabelDrawableLogic.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/LabelDrawableLogic.java new file mode 100644 index 00000000..8be9021a --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/LabelDrawableLogic.java @@ -0,0 +1,53 @@ +package games.rednblack.editor.renderer.systems.render.logic; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.Batch; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.components.label.LabelComponent; +import games.rednblack.editor.renderer.components.spriter.SpriterComponent; +import games.rednblack.editor.renderer.components.spriter.SpriterDrawerComponent; + +public class LabelDrawableLogic implements Drawable { + + private ComponentMapper labelComponentMapper; + private ComponentMapper tintComponentMapper; + private ComponentMapper dimensionsComponentMapper; + private ComponentMapper transformMapper; + private ComponentMapper parentNodeComponentComponentMapper; + + private final Color tmpColor = new Color(); + + public LabelDrawableLogic() { + labelComponentMapper = ComponentMapper.getFor(LabelComponent.class); + tintComponentMapper = ComponentMapper.getFor(TintComponent.class); + dimensionsComponentMapper = ComponentMapper.getFor(DimensionsComponent.class); + transformMapper = ComponentMapper.getFor(TransformComponent.class); + parentNodeComponentComponentMapper = ComponentMapper.getFor(ParentNodeComponent.class); + } + + @Override + public void draw(Batch batch, Entity entity, float parentAlpha) { + TransformComponent entityTransformComponent = transformMapper.get(entity); + LabelComponent labelComponent = labelComponentMapper.get(entity); + DimensionsComponent dimenstionsComponent = dimensionsComponentMapper.get(entity); + TintComponent tint = tintComponentMapper.get(entity); + + tmpColor.set(tint.color); + + if (labelComponent.style.background != null) { + batch.setColor(tmpColor); + labelComponent.style.background.draw(batch, entityTransformComponent.x, entityTransformComponent.y, dimenstionsComponent.width, dimenstionsComponent.height); + //System.out.println("LAbel BG"); + } + + if(labelComponent.style.fontColor != null) tmpColor.mul(labelComponent.style.fontColor); + tmpColor.a *= tintComponentMapper.get(parentNodeComponentComponentMapper.get(entity).parentEntity).color.a; + + labelComponent.cache.tint(tmpColor); + labelComponent.cache.setPosition(entityTransformComponent.x, entityTransformComponent.y); + labelComponent.cache.draw(batch); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/LightDrawableLogic.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/LightDrawableLogic.java new file mode 100644 index 00000000..adbf9624 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/LightDrawableLogic.java @@ -0,0 +1,37 @@ +package games.rednblack.editor.renderer.systems.render.logic; + + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.Batch; +import games.rednblack.editor.renderer.components.ParentNodeComponent; +import games.rednblack.editor.renderer.components.TintComponent; +import games.rednblack.editor.renderer.components.light.LightObjectComponent; + +public class LightDrawableLogic implements Drawable { + + private ComponentMapper lightComponentMapper; + private ComponentMapper tintComponentMapper; + private ComponentMapper parentNodeComponentComponentMapper; + + private final Color tmpColor = new Color(); + + public LightDrawableLogic() { + lightComponentMapper = ComponentMapper.getFor(LightObjectComponent.class); + tintComponentMapper = ComponentMapper.getFor(TintComponent.class); + parentNodeComponentComponentMapper = ComponentMapper.getFor(ParentNodeComponent.class); + } + + @Override + public void draw(Batch batch, Entity entity, float parentAlpha) { + LightObjectComponent lightObjectComponent = lightComponentMapper.get(entity); + TintComponent tint = tintComponentMapper.get(entity); + + tmpColor.set(tint.color); + tmpColor.a *= tintComponentMapper.get(parentNodeComponentComponentMapper.get(entity).parentEntity).color.a; + + lightObjectComponent.lightObject.setColor(tmpColor); + } + +} \ No newline at end of file diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/NinePatchDrawableLogic.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/NinePatchDrawableLogic.java new file mode 100644 index 00000000..1ffdc48e --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/NinePatchDrawableLogic.java @@ -0,0 +1,35 @@ +package games.rednblack.editor.renderer.systems.render.logic; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.math.Matrix4; +import games.rednblack.editor.renderer.components.*; + +public class NinePatchDrawableLogic implements Drawable { + + private ComponentMapper tintComponentComponentMapper; + private ComponentMapper transformMapper; + private ComponentMapper dimensionsMapper; + private ComponentMapper ninePatchMapper; + + + public NinePatchDrawableLogic() { + tintComponentComponentMapper = ComponentMapper.getFor(TintComponent.class); + transformMapper = ComponentMapper.getFor(TransformComponent.class); + dimensionsMapper = ComponentMapper.getFor(DimensionsComponent.class); + ninePatchMapper = ComponentMapper.getFor(NinePatchComponent.class); + } + + @Override + public void draw(Batch batch, Entity entity, float parentAlpha) { + TintComponent tintComponent = tintComponentComponentMapper.get(entity); + TransformComponent entityTransformComponent = transformMapper.get(entity); + DimensionsComponent entityDimensionsComponent = dimensionsMapper.get(entity); + NinePatchComponent entityNinePatchComponent = ninePatchMapper.get(entity); + batch.setColor(tintComponent.color); + + entityNinePatchComponent.ninePatch.draw(batch, entityTransformComponent.x, entityTransformComponent.y, entityDimensionsComponent.width, entityDimensionsComponent.height); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/ParticleDrawableLogic.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/ParticleDrawableLogic.java new file mode 100644 index 00000000..96536a36 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/ParticleDrawableLogic.java @@ -0,0 +1,29 @@ +package games.rednblack.editor.renderer.systems.render.logic; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Batch; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.particle.ParticleComponent; + +public class ParticleDrawableLogic implements Drawable { + + private ComponentMapper particleComponentMapper = ComponentMapper.getFor(ParticleComponent.class); + private ComponentMapper transformComponentMapper = ComponentMapper.getFor(TransformComponent.class); + + public ParticleDrawableLogic() { + } + + @Override + public void draw(Batch batch, Entity entity, float parentAlpha) { + ParticleComponent particleComponent = particleComponentMapper.get(entity); + //Matrix4 matrix = batch.getTransformMatrix().scl(particleComponent.worldMultiplyer); + //batch.setTransformMatrix(matrix); + TransformComponent transformComponent = transformComponentMapper.get(entity); + //particleEffect.setPosition(transformComponent.x/particleComponent.worldMultiplyer, transformComponent.y/particleComponent.worldMultiplyer); + particleComponent.particleEffect.setPosition(transformComponent.x, transformComponent.y); + particleComponent.particleEffect.draw(batch); + //batch.setTransformMatrix(batch.getTransformMatrix().scl(1f/particleComponent.worldMultiplyer)); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/SpriteDrawableLogic.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/SpriteDrawableLogic.java new file mode 100644 index 00000000..cb55d539 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/SpriteDrawableLogic.java @@ -0,0 +1,14 @@ +package games.rednblack.editor.renderer.systems.render.logic; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Batch; + +public class SpriteDrawableLogic extends TextureRegionDrawLogic { + + @Override + public void draw(Batch batch, Entity entity, float parentAlpha) { + super.draw(batch, entity, parentAlpha); + //TODO in case we need specific things + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/SpriterDrawableLogic.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/SpriterDrawableLogic.java new file mode 100644 index 00000000..15e46ef3 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/SpriterDrawableLogic.java @@ -0,0 +1,39 @@ +package games.rednblack.editor.renderer.systems.render.logic; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.brashmonkey.spriter.Player; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.spriter.SpriterComponent; +import games.rednblack.editor.renderer.components.spriter.SpriterDrawerComponent; + +public class SpriterDrawableLogic implements Drawable { + + private ComponentMapper spriterDrawerMapper; + private ComponentMapper spriterMapper; + private ComponentMapper transformMapper; + + public SpriterDrawableLogic() { + spriterDrawerMapper = ComponentMapper.getFor(SpriterDrawerComponent.class); + spriterMapper = ComponentMapper.getFor(SpriterComponent.class); + transformMapper = ComponentMapper.getFor(TransformComponent.class); + } + + @Override + public void draw(Batch batch, Entity entity, float parentAlpha) { + TransformComponent entityTransformComponent = transformMapper.get(entity); + SpriterDrawerComponent spriterDrawerComponent = spriterDrawerMapper.get(entity); + SpriterComponent spriter = spriterMapper.get(entity); + Player player = spriter.player; + + player.setPosition(entityTransformComponent.x, entityTransformComponent.y); + //TODO dimentions + //player.setPivot(getWidth() / 2, getHeight() / 2); + player.setScale(spriter.scale ); + player.rotate(entityTransformComponent.rotation - player.getAngle()); + player.update(); + spriterDrawerComponent.drawer.beforeDraw(player, batch); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/TextureRegionDrawLogic.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/TextureRegionDrawLogic.java new file mode 100644 index 00000000..a5b143da --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/systems/render/logic/TextureRegionDrawLogic.java @@ -0,0 +1,93 @@ +package games.rednblack.editor.renderer.systems.render.logic; + +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.components.*; + +public class TextureRegionDrawLogic implements Drawable { + + final private ComponentMapper tintComponentComponentMapper; + final private ComponentMapper textureRegionMapper; + final private ComponentMapper transformMapper; + final private ComponentMapper dimensionsComponentComponentMapper; + + public TextureRegionDrawLogic() { + tintComponentComponentMapper = ComponentMapper.getFor(TintComponent.class); + textureRegionMapper = ComponentMapper.getFor(TextureRegionComponent.class); + transformMapper = ComponentMapper.getFor(TransformComponent.class); + dimensionsComponentComponentMapper = ComponentMapper.getFor(DimensionsComponent.class); + } + + @Override + public void draw(Batch batch, Entity entity, float parentAlpha) { + TextureRegionComponent entityTextureRegionComponent = textureRegionMapper.get(entity); + + if(entityTextureRegionComponent.polygonSprite != null) { + drawPolygonSprite(batch, entity); + } else { + drawSprite(batch, entity, parentAlpha); + } + } + + public void drawSprite(Batch batch, Entity entity, float parentAlpha) { + TintComponent tintComponent = tintComponentComponentMapper.get(entity); + TransformComponent entityTransformComponent = transformMapper.get(entity); + TextureRegionComponent entityTextureRegionComponent = textureRegionMapper.get(entity); + DimensionsComponent dimensionsComponent = dimensionsComponentComponentMapper.get(entity); + batch.setColor(tintComponent.color.r, tintComponent.color.g, tintComponent.color.b, tintComponent.color.a * parentAlpha); + + batch.draw(entityTextureRegionComponent.region, + entityTransformComponent.x, entityTransformComponent.y, + entityTransformComponent.originX, entityTransformComponent.originY, + dimensionsComponent.width, dimensionsComponent.height, + entityTransformComponent.scaleX, entityTransformComponent.scaleY, + entityTransformComponent.rotation); + } + + public void drawPolygonSprite(Batch batch, Entity entity) { + TintComponent tintComponent = tintComponentComponentMapper.get(entity); + TransformComponent entityTransformComponent = transformMapper.get(entity); + TextureRegionComponent entityTextureRegionComponent = textureRegionMapper.get(entity); + + DimensionsComponent dimensionsComponent = dimensionsComponentComponentMapper.get(entity); + + entityTextureRegionComponent.polygonSprite.setBounds(entityTransformComponent.x, entityTransformComponent.y, dimensionsComponent.width, dimensionsComponent.height); + entityTextureRegionComponent.polygonSprite.setRotation(entityTransformComponent.rotation); + entityTextureRegionComponent.polygonSprite.setOrigin(entityTransformComponent.originX, entityTransformComponent.originY); + entityTextureRegionComponent.polygonSprite.setColor(tintComponent.color); + entityTextureRegionComponent.polygonSprite.setScale(entityTransformComponent.scaleX, entityTransformComponent.scaleY); + entityTextureRegionComponent.polygonSprite.draw((PolygonSpriteBatch) batch); + } + + public void drawTiledPolygonSprite(Batch batch, Entity entity) { + batch.flush(); + TintComponent tintComponent = tintComponentComponentMapper.get(entity); + TransformComponent entityTransformComponent = transformMapper.get(entity); + TextureRegionComponent entityTextureRegionComponent = textureRegionMapper.get(entity); + + DimensionsComponent dimensionsComponent = dimensionsComponentComponentMapper.get(entity); + float ppwu = dimensionsComponent.width/entityTextureRegionComponent.region.getRegionWidth(); + + Vector2 atlasCoordsVector = new Vector2(entityTextureRegionComponent.region.getU(), entityTextureRegionComponent.region.getV()); + Vector2 atlasSizeVector = new Vector2(entityTextureRegionComponent.region.getU2()-entityTextureRegionComponent.region.getU(), entityTextureRegionComponent.region.getV2()-entityTextureRegionComponent.region.getV()); + + batch.getShader().setUniformi("isRepeat", 1); + batch.getShader().setUniformf("atlasCoord", atlasCoordsVector); + batch.getShader().setUniformf("atlasSize", atlasSizeVector); + //System.out.println(entityTransformComponent.originX); + //batch.setColor(tintComponent.color); + entityTextureRegionComponent.polygonSprite.setColor(tintComponent.color); + entityTextureRegionComponent.polygonSprite.setOrigin(entityTransformComponent.originX * ppwu, entityTransformComponent.originY * ppwu); + entityTextureRegionComponent.polygonSprite.setPosition(entityTransformComponent.x, entityTransformComponent.y); + entityTextureRegionComponent.polygonSprite.setRotation(entityTransformComponent.rotation); + entityTextureRegionComponent.polygonSprite.setScale(ppwu); + entityTextureRegionComponent.polygonSprite.draw((PolygonSpriteBatch) batch); + batch.flush(); + batch.getShader().setUniformi("isRepeat", 0); + + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/ComponentRetriever.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/ComponentRetriever.java new file mode 100644 index 00000000..e18f7613 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/ComponentRetriever.java @@ -0,0 +1,167 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.utils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.ComponentMapper; +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.components.label.LabelComponent; +import games.rednblack.editor.renderer.components.light.LightBodyComponent; +import games.rednblack.editor.renderer.components.light.LightObjectComponent; +import games.rednblack.editor.renderer.components.particle.ParticleComponent; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; +import games.rednblack.editor.renderer.components.sprite.AnimationComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationStateComponent; +import games.rednblack.editor.renderer.components.spriter.SpriterComponent; +import games.rednblack.editor.renderer.components.spriter.SpriterDrawerComponent; + +/** + * Component Retriever is a singleton single instance class that initialises list of + * all component mappers on first access, and provides a retrieval methods to get {@link Component} + * with provided class from provided {@link Entity} object + * + * @author azakhary on 5/19/2015. + */ +public class ComponentRetriever { + + /** + * single static instance of this class + */ + private static ComponentRetriever instance; + + /** + * Unique map of mappers that can be accessed by component class + */ + private Map> mappers = new HashMap>(); + + /** + * Private constructor + */ + private ComponentRetriever() { + + } + + /** + * This is called only during first initialisation and populates map of mappers of all known Component mappers + * it might be a good idea to use Reflections library later to create this list from all classes in components package of runtime, all in favour? + */ + private void init() { + mappers.put(LightObjectComponent.class, ComponentMapper.getFor(LightObjectComponent.class)); + + mappers.put(ParticleComponent.class, ComponentMapper.getFor(ParticleComponent.class)); + + mappers.put(LabelComponent.class, ComponentMapper.getFor(LabelComponent.class)); + + mappers.put(PolygonComponent.class, ComponentMapper.getFor(PolygonComponent.class)); + mappers.put(PhysicsBodyComponent.class, ComponentMapper.getFor(PhysicsBodyComponent.class)); + mappers.put(LightBodyComponent.class, ComponentMapper.getFor(LightBodyComponent.class)); + + mappers.put(AnimationComponent.class, ComponentMapper.getFor(AnimationComponent.class)); + mappers.put(SpriteAnimationComponent.class, ComponentMapper.getFor(SpriteAnimationComponent.class)); + mappers.put(SpriteAnimationStateComponent.class, ComponentMapper.getFor(SpriteAnimationStateComponent.class)); + + mappers.put(SpriterDrawerComponent.class, ComponentMapper.getFor(SpriterDrawerComponent.class)); + mappers.put(SpriterComponent.class, ComponentMapper.getFor(SpriterComponent.class)); + + mappers.put(CompositeTransformComponent.class, ComponentMapper.getFor(CompositeTransformComponent.class)); + mappers.put(DimensionsComponent.class, ComponentMapper.getFor(DimensionsComponent.class)); + mappers.put(LayerMapComponent.class, ComponentMapper.getFor(LayerMapComponent.class)); + mappers.put(MainItemComponent.class, ComponentMapper.getFor(MainItemComponent.class)); + mappers.put(NinePatchComponent.class, ComponentMapper.getFor(NinePatchComponent.class)); + mappers.put(NodeComponent.class, ComponentMapper.getFor(NodeComponent.class)); + mappers.put(ParentNodeComponent.class, ComponentMapper.getFor(ParentNodeComponent.class)); + mappers.put(ScissorComponent.class, ComponentMapper.getFor(ScissorComponent.class)); + mappers.put(TextureRegionComponent.class, ComponentMapper.getFor(TextureRegionComponent.class)); + mappers.put(TintComponent.class, ComponentMapper.getFor(TintComponent.class)); + mappers.put(TransformComponent.class, ComponentMapper.getFor(TransformComponent.class)); + mappers.put(ViewPortComponent.class, ComponentMapper.getFor(ViewPortComponent.class)); + mappers.put(ZIndexComponent.class, ComponentMapper.getFor(ZIndexComponent.class)); + mappers.put(ScriptComponent.class, ComponentMapper.getFor(ScriptComponent.class)); + + mappers.put(ShaderComponent.class, ComponentMapper.getFor(ShaderComponent.class)); + + mappers.put(ActionComponent.class, ComponentMapper.getFor(ActionComponent.class)); + } + + /** + * Short version of getInstance singleton variation, but with private access, + * as there is no reason to get instance of this class, but only use it's public methods + * + * @return ComponentRetriever only instance + */ + private static synchronized ComponentRetriever self() { + if(instance == null) { + instance = new ComponentRetriever(); + + // Important to initialize during first creation, to populate mappers map + instance.init(); + } + + return instance; + } + + /** + * @return returns Map of mappers, for internal use only + */ + private Map> getMappers() { + return mappers; + } + + /** + * Retrieves Component of provided type from a provided entity + * @param entity of type Entity to retrieve component from + * @param type of the component + * @param + * + * @return Component subclass instance + */ + @SuppressWarnings("unchecked") + public static T get(Entity entity, Class type) { + return (T)self().getMappers().get(type).get(entity); + } + + + @SuppressWarnings("unchecked") + public static Collection getComponents(Entity entity) { + Collection components = new ArrayList(); + for (ComponentMapper mapper : self().getMappers().values()) { + if(mapper.get(entity) != null) components.add(mapper.get(entity)); + } + + return components; + } + + /** + * This is to add a new mapper type externally, in case of for example implementing the plugin system, + * where components might be initialized on the fly + * + * @param type + */ + @SuppressWarnings("unchecked") + public static void addMapper(Class type) { + self().getMappers().put(type, ComponentMapper.getFor(type)); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/CustomVariables.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/CustomVariables.java new file mode 100644 index 00000000..29586c29 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/CustomVariables.java @@ -0,0 +1,80 @@ +package games.rednblack.editor.renderer.utils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by azakhary on 8/28/2014. + */ +public class CustomVariables { + + private HashMap variables = new HashMap(); + + public CustomVariables() { + + } + + public void loadFromString(String varString) { + variables.clear(); + String[] vars = varString.split(";"); + for(int i = 0; i < vars.length; i++) { + String[] tmp = vars[i].split(":"); + if(tmp.length > 1) { + setVariable(tmp[0], tmp[1]); + } + } + } + + public String saveAsString() { + String result = ""; + for (Map.Entry entry : variables.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + result += key + ":" + value + ";"; + } + if(result.length() > 0) { + result = result.substring(0, result.length()-1); + } + + return result; + } + + public void setVariable(String key, String value) { + variables.put(key, value); + } + + public void removeVariable(String key) { + variables.remove(key); + } + + public String getStringVariable(String key) { + return variables.get(key); + } + + public Integer getIntegerVariable(String key) { + Integer result = null; + try { + result = Integer.parseInt(variables.get(key)); + } catch(Exception e) {} + + return result; + } + + public Float getFloatVariable(String key) { + Float result = null; + try { + result = Float.parseFloat(variables.get(key)); + } catch(Exception e) {} + + return result; + } + + public HashMap getHashMap() { + return variables; + } + + public int getCount() { + return variables.size(); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/ForceUtils.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/ForceUtils.java new file mode 100644 index 00000000..dc18ba5a --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/ForceUtils.java @@ -0,0 +1,39 @@ +package games.rednblack.editor.renderer.utils; + +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Body; + +/** + * Created by aurel on 19/02/16. + */ +public class ForceUtils { + + + + public static void applyImpulse(Vector2 impulsePosition, float strength, float influenceArea, Body body) { + Vector2 v = body.getPosition().cpy().sub(impulsePosition); + + float length = MathUtils.clamp(v.len(), 0, influenceArea); + v.nor().scl(influenceArea - length).scl(strength); + + applyForce(v, body, false, false, new Vector2(0, 0)); + } + + public static void applyForce(Vector2 force, Body body) { + applyForce(force, body, false, false, new Vector2(0, 0)); + } + + public static void applyForce(Vector2 force, Body body, Vector2 relativePoint) { + applyForce(force, body, false, false, relativePoint); + } + + public static void applyForce(Vector2 force, Body body, boolean relativeToVelocity, boolean relativeToMass, Vector2 relativePoint) { + Vector2 forceToApply = force.cpy(); + + if (relativeToVelocity) forceToApply.sub(body.getLinearVelocity()); + if (relativeToMass) forceToApply.scl(body.getMass()); + + body.applyForce(forceToApply, relativePoint.cpy().add(body.getPosition()), true); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/ItemWrapper.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/ItemWrapper.java new file mode 100644 index 00000000..22c9da51 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/ItemWrapper.java @@ -0,0 +1,99 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.renderer.utils; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.components.NodeComponent; +import games.rednblack.editor.renderer.components.ParentNodeComponent; +import games.rednblack.editor.renderer.components.ScriptComponent; +import games.rednblack.editor.renderer.scripts.IScript; + +import java.util.HashMap; + +/** + * Created by azakhary on 7/8/2015. + */ +public class ItemWrapper { + + private Entity entity; + + private NodeComponent nodeComponent; + private HashMap childMap = new HashMap(); + + public ItemWrapper() { + // empty wrapper is better then null pointer + } + + public ItemWrapper(Entity entity) { + this.entity = entity; + nodeComponent = ComponentRetriever.get(entity, NodeComponent.class); + if(nodeComponent != null) { + for (Entity child : nodeComponent.children) { + MainItemComponent mainItemComponent = ComponentRetriever.get(child, MainItemComponent.class); + childMap.put(mainItemComponent.itemIdentifier, child); + } + } + } + + public ItemWrapper getChild(String id) { + Entity entity = childMap.get(id); + if(entity == null) return new ItemWrapper(); + + return new ItemWrapper(entity); + } + + public T getComponent(Class clazz) { + return ComponentRetriever.get(entity, clazz); + } + + public ItemWrapper addChild(Entity child) { + if(nodeComponent != null) { + ParentNodeComponent parentNodeComponent = child.getComponent(ParentNodeComponent.class); + parentNodeComponent.parentEntity = entity; + nodeComponent.children.add(child); + + return new ItemWrapper(child); + } + + return new ItemWrapper(); + } + + public int getType() { + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + return mainItemComponent.entityType; + } + + public Entity getEntity() { + return entity; + } + + public IScript addScript(IScript script) { + ScriptComponent component = ComponentRetriever.get(entity, ScriptComponent.class); + if(component == null) { + component = new ScriptComponent(); + entity.add(component); + } + component.addScript(script); + script.init(entity); + + return script; + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/LibGdxDrawer.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/LibGdxDrawer.java new file mode 100644 index 00000000..75f546f2 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/LibGdxDrawer.java @@ -0,0 +1,64 @@ +package games.rednblack.editor.renderer.utils; + +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.brashmonkey.spriter.Drawer; +import com.brashmonkey.spriter.Loader; +import com.brashmonkey.spriter.Player; +import com.brashmonkey.spriter.Timeline.Key.Object; + +public class LibGdxDrawer extends Drawer{ + + private Batch batch; + private ShapeRenderer renderer; + + public LibGdxDrawer(Loader loader, ShapeRenderer renderer){ + super(loader); + this.renderer = renderer; + } + + @Override + public void setColor(float r, float g, float b, float a) { + renderer.setColor(r, g, b, a); + } + + @Override + public void rectangle(float x, float y, float width, float height) { + renderer.rect(x, y, width, height); + } + + @Override + public void line(float x1, float y1, float x2, float y2) { + renderer.line(x1, y1, x2, y2); + } + + @Override + public void circle(float x, float y, float radius) { + renderer.circle(x, y, radius); + } + + public void beforeDraw(Player player, Batch batch) { + this.batch = batch; + draw(player); + } + @Override + public void draw(Object object) { + Sprite sprite = loader.get(object.ref); + + float newPivotX = (sprite.getWidth() * object.pivot.x); + float newX = object.position.x - newPivotX; + float newPivotY = (sprite.getHeight() * object.pivot.y); + float newY = object.position.y - newPivotY; + + sprite.setX(newX); + sprite.setY(newY); + sprite.setOrigin(newPivotX, newPivotY); + sprite.setRotation(object.angle); + + sprite.setColor(1f, 1f, 1f, object.alpha); + sprite.setScale(object.scale.x, object.scale.y); + sprite.draw(batch); + } +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/LibGdxLoader.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/LibGdxLoader.java new file mode 100644 index 00000000..6ec5f834 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/LibGdxLoader.java @@ -0,0 +1,138 @@ +package games.rednblack.editor.renderer.utils; + +import java.io.File; +import java.util.HashMap; +import java.util.Set; +import java.util.Map.Entry; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.Texture.TextureFilter; +import com.badlogic.gdx.graphics.g2d.PixmapPacker; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.utils.Disposable; +import com.badlogic.gdx.utils.GdxRuntimeException; +import com.brashmonkey.spriter.Data; +import com.brashmonkey.spriter.FileReference; +import com.brashmonkey.spriter.Loader; + +public class LibGdxLoader extends Loader implements Disposable{ + + public static int standardAtlasWidth = 2048, standardAtlasHeight = 2048; + + private PixmapPacker packer; + private HashMap pixmaps; + private HashMap pixmapsToDispose; + private boolean pack; + private int atlasWidth, atlasHeight; + + public LibGdxLoader(Data data){ + this(data, true); + } + + public LibGdxLoader(Data data, boolean pack){ + this(data, standardAtlasWidth, standardAtlasHeight); + this.pack = pack; + } + + public LibGdxLoader(Data data, int atlasWidth, int atlasHeight) { + super(data); + this.pack = true; + this.atlasWidth = atlasWidth; + this.atlasHeight = atlasHeight; + this.pixmaps = new HashMap(); + this.pixmapsToDispose = new HashMap(); + } + + @Override + protected Sprite loadResource(FileReference ref) { + FileHandle f; + + String filename = new File(data.getFile(ref).name).getName(); + //String path = super.root+"/"+data.getFile(ref).name; + String path = super.root+"/"+filename; + switch(Gdx.app.getType()){ + case iOS: f = Gdx.files.absolute(path); break; + default: f = Gdx.files.internal(path); break; + } + + if(!f.exists()) throw new GdxRuntimeException("Could not find file handle "+ path + "! Please check your paths."); + if(this.packer == null && this.pack) + this.packer = new PixmapPacker(this.atlasWidth, this.atlasHeight, Pixmap.Format.RGBA8888, 2, true); + final Pixmap pix = new Pixmap(f); + this.pixmaps.put(ref, pix); + return null; + } + + /** + * Packs all loaded sprites into an atlas. Has to called after loading all sprites. + */ + protected void generatePackedSprites(){ + if(this.packer == null) return; + TextureAtlas tex = this.packer.generateTextureAtlas(TextureFilter.Linear, TextureFilter.Linear, false); + Set keys = this.resources.keySet(); + this.disposeNonPackedTextures(); + for(FileReference ref: keys){ + TextureRegion texReg = tex.findRegion(data.getFile(ref).name); + texReg.setRegionWidth((int) data.getFile(ref).size.width); + texReg.setRegionHeight((int) data.getFile(ref).size.height); + super.resources.put(ref, new Sprite(texReg)); + } + } + + private void disposeNonPackedTextures(){ + for(Entry entry: super.resources.entrySet()) + entry.getValue().getTexture().dispose(); + } + + @Override + public void dispose() { + if(this.pack && this.packer != null) this.packer.dispose(); + else this.disposeNonPackedTextures(); + super.dispose(); + } + + protected void finishLoading() { + Set refs = this.resources.keySet(); + for(FileReference ref: refs){ + Pixmap pix = this.pixmaps.get(ref); + this.pixmapsToDispose.put(pix, false); + this.createSprite(ref, pix); + + if(this.packer != null) packer.pack(data.getFile(ref).name, pix); + } + if(this.pack) generatePackedSprites(); + this.disposePixmaps(); + } + + protected void createSprite(FileReference ref, Pixmap image){ + Texture tex = new Texture(image); + tex.setFilter(TextureFilter.Linear, TextureFilter.Linear); + int width = (int) data.getFile(ref.folder, ref.file).size.width; + int height = (int) data.getFile(ref.folder, ref.file).size.height; + TextureRegion texRegion = new TextureRegion(tex, width, height); + super.resources.put(ref, new Sprite(texRegion)); + pixmapsToDispose.put(image, true); + } + + protected void disposePixmaps(){ + Pixmap[] maps = new Pixmap[this.pixmapsToDispose.size()]; + this.pixmapsToDispose.keySet().toArray(maps); + for(Pixmap pix: maps){ + try{ + while(pixmapsToDispose.get(pix)){ + pix.dispose(); + pixmapsToDispose.put(pix, false); + } + } catch(GdxRuntimeException e){ + System.err.println("Pixmap was already disposed!"); + } + } + pixmapsToDispose.clear(); + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/MySkin.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/MySkin.java new file mode 100644 index 00000000..bfd30b12 --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/MySkin.java @@ -0,0 +1,514 @@ +package games.rednblack.editor.renderer.utils; + +import java.util.ArrayList; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.Texture.TextureFilter; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.Sprite; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasSprite; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.utils.Drawable; +import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable; +import com.badlogic.gdx.scenes.scene2d.utils.SpriteDrawable; +import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.scenes.scene2d.utils.TiledDrawable; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Disposable; +import com.badlogic.gdx.utils.GdxRuntimeException; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.Json.ReadOnlySerializer; +import com.badlogic.gdx.utils.JsonValue; +import com.badlogic.gdx.utils.ObjectMap; +import com.badlogic.gdx.utils.SerializationException; +import com.badlogic.gdx.utils.reflect.ClassReflection; +import com.badlogic.gdx.utils.reflect.Method; +import com.badlogic.gdx.utils.reflect.ReflectionException; + +/** A skin stores resources for UI widgets to use (texture regions, ninepatches, fonts, colors, etc). Resources are named and can + * be looked up by name and type. Resources can be described in JSON. Skin provides useful conversions, such as allowing access to + * regions in the atlas as ninepatches, sprites, drawables, etc. The get* methods return an instance of the object in the skin. + * The new* methods return a copy of an instance in the skin. + *

+ * See the documentation for more. + * @author Nathan Sweet */ +public class MySkin extends Skin { + private ObjectMap> resources = new ObjectMap(); + private TextureAtlas atlas; + public ArrayList fontFiles = new ArrayList(); + /** Creates an empty skin. */ + public MySkin () { + } + + /** Creates a skin containing the resources in the specified skin JSON file. If a file in the same directory with a ".atlas" + * extension exists, it is loaded as a {@link TextureAtlas} and the texture regions added to the skin. The atlas is + * automatically disposed when the skin is disposed. */ + public MySkin (FileHandle skinFile) { + FileHandle atlasFile = skinFile.sibling(skinFile.nameWithoutExtension() + ".atlas"); + if (atlasFile.exists()) { + atlas = new TextureAtlas(atlasFile); + addRegions(atlas); + } + + load(skinFile); + } + + /** Creates a skin containing the resources in the specified skin JSON file and the texture regions from the specified atlas. + * The atlas is automatically disposed when the skin is disposed. */ + public MySkin (FileHandle skinFile, TextureAtlas atlas) { + this.atlas = atlas; + addRegions(atlas); + load(skinFile); + } + + /** Creates a skin containing the texture regions from the specified atlas. The atlas is automatically disposed when the skin is + * disposed. */ + public MySkin (TextureAtlas atlas) { + this.atlas = atlas; + addRegions(atlas); + } + + /** Adds all resources in the specified skin JSON file. */ + public void load (FileHandle skinFile) { + try { + getJsonLoader(skinFile).fromJson(Skin.class, skinFile); + } catch (SerializationException ex) { + throw new SerializationException("Error reading file: " + skinFile, ex); + } + } + + /** Adds all named texture regions from the atlas. The atlas will not be automatically disposed when the skin is disposed. */ + public void addRegions (TextureAtlas atlas) { + Array regions = atlas.getRegions(); + for (int i = 0, n = regions.size; i < n; i++) { + AtlasRegion region = regions.get(i); + add(region.name, region, TextureRegion.class); + } + } + + public void add (String name, Object resource) { + add(name, resource, resource.getClass()); + } + + public void add (String name, Object resource, Class type) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + if (resource == null) throw new IllegalArgumentException("resource cannot be null."); + ObjectMap typeResources = resources.get(type); + if (typeResources == null) { + typeResources = new ObjectMap(); + resources.put(type, typeResources); + } + typeResources.put(name, resource); + } + + public void remove (String name, Class type) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + ObjectMap typeResources = resources.get(type); + typeResources.remove(name); + } + + + public T get (Class type) { + return get("default", type); + } + + public T get (String name, Class type) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + if (type == null) throw new IllegalArgumentException("type cannot be null."); + + if (type == Drawable.class) return (T)getDrawable(name); + if (type == TextureRegion.class) return (T)getRegion(name); + if (type == NinePatch.class) return (T)getPatch(name); + if (type == Sprite.class) return (T)getSprite(name); + + ObjectMap typeResources = resources.get(type); + if (typeResources == null) throw new GdxRuntimeException("No " + type.getName() + " registered with name: " + name); + Object resource = typeResources.get(name); + if (resource == null) throw new GdxRuntimeException("No " + type.getName() + " registered with name: " + name); + return (T)resource; + } + + public T optional (String name, Class type) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + if (type == null) throw new IllegalArgumentException("type cannot be null."); + ObjectMap typeResources = resources.get(type); + if (typeResources == null) return null; + return (T)typeResources.get(name); + } + + public boolean has (String name, Class type) { + ObjectMap typeResources = resources.get(type); + if (typeResources == null) return false; + return typeResources.containsKey(name); + } + + /** Returns the name to resource mapping for the specified type, or null if no resources of that type exist. */ + public ObjectMap getAll (Class type) { + return (ObjectMap)resources.get(type); + } + + public Color getColor (String name) { + return get(name, Color.class); + } + + public BitmapFont getFont (String name) { + return get(name, BitmapFont.class); + } + + /** Returns a registered texture region. If no region is found but a texture exists with the name, a region is created from the + * texture and stored in the skin. */ + public TextureRegion getRegion (String name) { + TextureRegion region = optional(name, TextureRegion.class); + if (region != null) return region; + + Texture texture = optional(name, Texture.class); + if (texture == null) throw new GdxRuntimeException("No TextureRegion or Texture registered with name: " + name); + region = new TextureRegion(texture); + add(name, region, TextureRegion.class); + return region; + } + + /** Returns a registered tiled drawable. If no tiled drawable is found but a region exists with the name, a tiled drawable is + * created from the region and stored in the skin. */ + public TiledDrawable getTiledDrawable (String name) { + TiledDrawable tiled = optional(name, TiledDrawable.class); + if (tiled != null) return tiled; + + Drawable drawable = optional(name, Drawable.class); + if (drawable != null) { + if (!(drawable instanceof TiledDrawable)) { + throw new GdxRuntimeException("Drawable found but is not a TiledDrawable: " + name + ", " + + drawable.getClass().getName()); + } + return (TiledDrawable)drawable; + } + + tiled = new TiledDrawable(getRegion(name)); + add(name, tiled, TiledDrawable.class); + return tiled; + } + + /** Returns a registered ninepatch. If no ninepatch is found but a region exists with the name, a ninepatch is created from the + * region and stored in the skin. If the region is an {@link AtlasRegion} then the {@link AtlasRegion#splits} are used, + * otherwise the ninepatch will have the region as the center patch. */ + public NinePatch getPatch (String name) { + NinePatch patch = optional(name, NinePatch.class); + if (patch != null) return patch; + + try { + TextureRegion region = getRegion(name); + if (region instanceof AtlasRegion) { + int[] splits = ((AtlasRegion)region).splits; + if (splits != null) { + patch = new NinePatch(region, splits[0], splits[1], splits[2], splits[3]); + int[] pads = ((AtlasRegion)region).pads; + if (pads != null) patch.setPadding(pads[0], pads[1], pads[2], pads[3]); + } + } + if (patch == null) patch = new NinePatch(region); + add(name, patch, NinePatch.class); + return patch; + } catch (GdxRuntimeException ex) { + throw new GdxRuntimeException("No NinePatch, TextureRegion, or Texture registered with name: " + name); + } + } + + /** Returns a registered sprite. If no sprite is found but a region exists with the name, a sprite is created from the region + * and stored in the skin. If the region is an {@link AtlasRegion} then an {@link AtlasSprite} is used if the region has been + * whitespace stripped or packed rotated 90 degrees. */ + public Sprite getSprite (String name) { + Sprite sprite = optional(name, Sprite.class); + if (sprite != null) return sprite; + + try { + TextureRegion textureRegion = getRegion(name); + if (textureRegion instanceof AtlasRegion) { + AtlasRegion region = (AtlasRegion)textureRegion; + if (region.rotate || region.packedWidth != region.originalWidth || region.packedHeight != region.originalHeight) + sprite = new AtlasSprite(region); + } + if (sprite == null) sprite = new Sprite(textureRegion); + add(name, sprite, NinePatch.class); + return sprite; + } catch (GdxRuntimeException ex) { + throw new GdxRuntimeException("No NinePatch, TextureRegion, or Texture registered with name: " + name); + } + } + + /** Returns a registered drawable. If no drawable is found but a region, ninepatch, or sprite exists with the name, then the + * appropriate drawable is created and stored in the skin. */ + public Drawable getDrawable (String name) { + Drawable drawable = optional(name, Drawable.class); + if (drawable != null) return drawable; + + drawable = optional(name, TiledDrawable.class); + if (drawable != null) return drawable; + + // Use texture or texture region. If it has splits, use ninepatch. If it has rotation or whitespace stripping, use sprite. + try { + TextureRegion textureRegion = getRegion(name); + if (textureRegion instanceof AtlasRegion) { + AtlasRegion region = (AtlasRegion)textureRegion; + if (region.splits != null) + drawable = new NinePatchDrawable(getPatch(name)); + else if (region.rotate || region.packedWidth != region.originalWidth || region.packedHeight != region.originalHeight) + drawable = new SpriteDrawable(getSprite(name)); + } + if (drawable == null) drawable = new TextureRegionDrawable(textureRegion); + } catch (GdxRuntimeException ignored) { + } + + // Check for explicit registration of ninepatch, sprite, or tiled drawable. + if (drawable == null) { + NinePatch patch = optional(name, NinePatch.class); + if (patch != null) + drawable = new NinePatchDrawable(patch); + else { + Sprite sprite = optional(name, Sprite.class); + if (sprite != null) + drawable = new SpriteDrawable(sprite); + else + throw new GdxRuntimeException("No Drawable, NinePatch, TextureRegion, Texture, or Sprite registered with name: " + + name); + } + } + + add(name, drawable, Drawable.class); + return drawable; + } + + /** Returns the name of the specified style object, or null if it is not in the skin. This compares potentially every style + * object in the skin of the same type as the specified style, which may be a somewhat expensive operation. */ + public String find (Object resource) { + if (resource == null) throw new IllegalArgumentException("style cannot be null."); + ObjectMap typeResources = resources.get(resource.getClass()); + if (typeResources == null) return null; + return typeResources.findKey(resource, true); + } + + /** Returns a copy of a drawable found in the skin via {@link #getDrawable(String)}. */ + public Drawable newDrawable (String name) { + return newDrawable(getDrawable(name)); + } + + /** Returns a tinted copy of a drawable found in the skin via {@link #getDrawable(String)}. */ + public Drawable newDrawable (String name, float r, float g, float b, float a) { + return newDrawable(getDrawable(name), new Color(r, g, b, a)); + } + + /** Returns a tinted copy of a drawable found in the skin via {@link #getDrawable(String)}. */ + public Drawable newDrawable (String name, Color tint) { + return newDrawable(getDrawable(name), tint); + } + + /** Returns a copy of the specified drawable. */ + public Drawable newDrawable (Drawable drawable) { + if (drawable instanceof TextureRegionDrawable) return new TextureRegionDrawable((TextureRegionDrawable)drawable); + if (drawable instanceof NinePatchDrawable) return new NinePatchDrawable((NinePatchDrawable)drawable); + if (drawable instanceof SpriteDrawable) return new SpriteDrawable((SpriteDrawable)drawable); + throw new GdxRuntimeException("Unable to copy, unknown drawable type: " + drawable.getClass()); + } + + /** Returns a tinted copy of a drawable found in the skin via {@link #getDrawable(String)}. */ + public Drawable newDrawable (Drawable drawable, float r, float g, float b, float a) { + return newDrawable(drawable, new Color(r, g, b, a)); + } + + /** Returns a tinted copy of a drawable found in the skin via {@link #getDrawable(String)}. */ + public Drawable newDrawable (Drawable drawable, Color tint) { + if (drawable instanceof TextureRegionDrawable) { + TextureRegion region = ((TextureRegionDrawable)drawable).getRegion(); + Sprite sprite; + if (region instanceof AtlasRegion) + sprite = new AtlasSprite((AtlasRegion)region); + else + sprite = new Sprite(region); + sprite.setColor(tint); + return new SpriteDrawable(sprite); + } + if (drawable instanceof NinePatchDrawable) { + NinePatchDrawable patchDrawable = new NinePatchDrawable((NinePatchDrawable)drawable); + patchDrawable.setPatch(new NinePatch(patchDrawable.getPatch(), tint)); + return patchDrawable; + } + if (drawable instanceof SpriteDrawable) { + SpriteDrawable spriteDrawable = new SpriteDrawable((SpriteDrawable)drawable); + Sprite sprite = spriteDrawable.getSprite(); + if (sprite instanceof AtlasSprite) + sprite = new AtlasSprite((AtlasSprite)sprite); + else + sprite = new Sprite(sprite); + sprite.setColor(tint); + spriteDrawable.setSprite(sprite); + return spriteDrawable; + } + throw new GdxRuntimeException("Unable to copy, unknown drawable type: " + drawable.getClass()); + } + + /** Sets the style on the actor to disabled or enabled. This is done by appending "-disabled" to the style name when enabled is + * false, and removing "-disabled" from the style name when enabled is true. A method named "getStyle" is called the actor via + * reflection and the name of that style is found in the skin. If the actor doesn't have a "getStyle" method or the style was + * not found in the skin, no exception is thrown and the actor is left unchanged. */ + public void setEnabled (Actor actor, boolean enabled) { + // Get current style. + Method method = findMethod(actor.getClass(), "getStyle"); + if (method == null) return; + Object style; + try { + style = method.invoke(actor); + } catch (Exception ignored) { + return; + } + // Determine new style. + String name = find(style); + if (name == null) return; + name = name.replace("-disabled", "") + (enabled ? "" : "-disabled"); + style = get(name, style.getClass()); + // Set new style. + method = findMethod(actor.getClass(), "setStyle"); + if (method == null) return; + try { + method.invoke(actor, style); + } catch (Exception ignored) { + } + } + + /** Returns the {@link TextureAtlas} that resources in this skin reference, or null. */ + public TextureAtlas getAtlas () { + return atlas; + } + + /** Disposes the {@link TextureAtlas} and all {@link Disposable} resources in the skin. */ + public void dispose () { + if (atlas != null) atlas.dispose(); + for (ObjectMap entry : resources.values()) { + for (Object resource : entry.values()) + if (resource instanceof Disposable) ((Disposable)resource).dispose(); + } + } + + protected Json getJsonLoader (final FileHandle skinFile) { + final Skin skin = this; + + final Json json = new Json() { + public T readValue (Class type, Class elementType, JsonValue jsonData) { + // If the JSON is a string but the type is not, look up the actual value by name. + if (jsonData.isString() && !ClassReflection.isAssignableFrom(CharSequence.class, type)) + return get(jsonData.asString(), type); + return super.readValue(type, elementType, jsonData); + } + }; + json.setTypeName(null); + json.setUsePrototypes(false); + + json.setSerializer(Skin.class, new ReadOnlySerializer() { + public Skin read (Json json, JsonValue typeToValueMap, Class ignored) { + for (JsonValue valueMap = typeToValueMap.child; valueMap != null; valueMap = valueMap.next) { + try { + readNamedObjects(json, ClassReflection.forName(valueMap.name()), valueMap); + } catch (ReflectionException ex) { + throw new SerializationException(ex); + } + } + return skin; + } + + private void readNamedObjects (Json json, Class type, JsonValue valueMap) { + Class addType = type == TintedDrawable.class ? Drawable.class : type; + for (JsonValue valueEntry = valueMap.child; valueEntry != null; valueEntry = valueEntry.next) { + Object object = json.readValue(type, valueEntry); + if (object == null) continue; + try { + add(valueEntry.name(), object, addType); + } catch (Exception ex) { + throw new SerializationException("Error reading " + ClassReflection.getSimpleName(type) + ": " + + valueEntry.name(), ex); + } + } + } + }); + + json.setSerializer(BitmapFont.class, new ReadOnlySerializer() { + public BitmapFont read (Json json, JsonValue jsonData, Class type) { + String path = json.readValue("file", String.class, jsonData); + int scaledSize = json.readValue("scaledSize", int.class, -1, jsonData); + Boolean flip = json.readValue("flip", Boolean.class, false, jsonData); + + FileHandle fontFile = skinFile.parent().child(path); + if (!fontFile.exists()) fontFile = Gdx.files.internal(path); + if (!fontFile.exists()) throw new SerializationException("Font file not found: " + fontFile); + + // Use a region with the same name as the font, else use a PNG file in the same directory as the FNT file. + String regionName = fontFile.nameWithoutExtension(); + fontFiles.add(regionName); + try { + BitmapFont font; + TextureRegion region = skin.optional(regionName, TextureRegion.class); + if (region != null) + font = new BitmapFont(fontFile, region, flip); + else { + FileHandle imageFile = fontFile.parent().child(regionName + ".png"); + if (imageFile.exists()){ + Texture texture = new Texture(imageFile, true); + texture.setFilter(TextureFilter.MipMapLinearNearest, TextureFilter.Linear); + font = new BitmapFont(fontFile, new TextureRegion(texture), flip); + } + else + font = new BitmapFont(fontFile, flip); + } + // Scaled size is the desired cap height to scale the font to. + if (scaledSize != -1) font.getData().setScale(scaledSize / font.getCapHeight()); + return font; + } catch (RuntimeException ex) { + throw new SerializationException("Error loading bitmap font: " + fontFile, ex); + } + } + }); + + json.setSerializer(Color.class, new ReadOnlySerializer() { + public Color read (Json json, JsonValue jsonData, Class type) { + if (jsonData.isString()) return get(jsonData.asString(), Color.class); + String hex = json.readValue("hex", String.class, (String)null, jsonData); + if (hex != null) return Color.valueOf(hex); + float r = json.readValue("r", float.class, 0f, jsonData); + float g = json.readValue("g", float.class, 0f, jsonData); + float b = json.readValue("b", float.class, 0f, jsonData); + float a = json.readValue("a", float.class, 1f, jsonData); + return new Color(r, g, b, a); + } + }); + + json.setSerializer(TintedDrawable.class, new ReadOnlySerializer() { + public Object read (Json json, JsonValue jsonData, Class type) { + String name = json.readValue("name", String.class, jsonData); + Color color = json.readValue("color", Color.class, jsonData); + return newDrawable(name, color); + } + }); + + return json; + } + + static private Method findMethod (Class type, String name) { + Method[] methods = ClassReflection.getMethods(type); + for (int i = 0, n = methods.length; i < n; i++) { + Method method = methods[i]; + if (method.getName().equals(name)) return method; + } + return null; + } + + /** @author Nathan Sweet */ + static public class TintedDrawable { + public String name; + public Color color; + } +} \ No newline at end of file diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/PolygonUtils.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/PolygonUtils.java new file mode 100644 index 00000000..95d38fff --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/PolygonUtils.java @@ -0,0 +1,215 @@ +package games.rednblack.editor.renderer.utils; + +import com.badlogic.gdx.math.Intersector; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +/** + * Created by CyberJoe on 7/4/2015. + */ +public class PolygonUtils { + + public static Array mergeTouchingPolygons(Vector2[][] polys) { + + Set uniqueEdges = new HashSet(); + Set duplicateEdges = new HashSet(); + + for(int i = 0; i < polys.length; i++) { + for(int j = 0; j < polys[i].length; j++) { + Edge edge = null; + if(j < polys[i].length - 1) { + edge = new Edge(polys[i][j].x, polys[i][j].y, polys[i][j+1].x, polys[i][j+1].y); + } else if(j == polys[i].length - 1) { + edge = new Edge(polys[i][j].x, polys[i][j].y, polys[i][0].x, polys[i][0].y); + } + if(uniqueEdges.contains(edge)) { + duplicateEdges.add(edge); + } else { + uniqueEdges.add(edge); + } + } + } + + uniqueEdges.removeAll(duplicateEdges); + + Array result = new Array(); + while(!uniqueEdges.isEmpty()) { + Vector2[] mesh = extractClosedLoop(uniqueEdges); + mesh = clearUnnecessaryVertices(mesh); + result.add(mesh); + } + + return result; + } + + public static Vector2[] mergeTouchingPolygonsToOne(Vector2[][] polys) { + Array result = mergeTouchingPolygons(polys); + + return result.get(0); + } + + public static Vector2[] clearUnnecessaryVertices(Vector2[] points) { + Array result = new Array(); + if(points.length < 3) return points; + for(int i = 0; i < points.length; i++) { + Vector2 currPoint = points[i]; + Vector2 prevPoint = points[points.length-1]; + Vector2 nextPoint = points[0]; + if (i > 0) prevPoint = points[i-1]; + if( i < points.length-1) nextPoint = points[i+1]; + if(Intersector.pointLineSide(prevPoint, nextPoint, currPoint) != 0) { + result.add(currPoint); + } + } + + return result.toArray(Vector2.class); + } + + public static Vector2[] extractClosedLoop(Set edges) { + ArrayList sortedList = new ArrayList(); + Edge edge = (Edge) edges.toArray()[0]; + edges.remove(edge); + sortedList.add(edge); + while(!edges.isEmpty()) { + boolean result2 = false; + boolean result1 = appendNextEdge(sortedList, edges); + if(!edges.isEmpty()) { + result2 = appendPrevEdge(sortedList, edges); + } + if(!result1 && !result2) { + break; + } + } + + Vector2[] result = new Vector2[sortedList.size()]; + int iterator = 0; + for(Edge tmp: sortedList) { + result[iterator++] = tmp.start; + } + + return result; + } + + public static boolean appendNextEdge(ArrayList sortedList, Set edges) { + Edge lastEdge = sortedList.get(sortedList.size()-1); + Vector2 point = lastEdge.end; + for(Edge edge: edges) { + if(edge.linkedTo(point)) { + if(edge.end.equals(lastEdge.end)) { + edge.reverse(); + } + edges.remove(edge); + sortedList.add(edge); + return true; + } + } + + return false; + } + + public static boolean appendPrevEdge(ArrayList sortedList, Set edges) { + Edge prevEdge = sortedList.get(0); + Vector2 point = prevEdge.start; + for(Edge edge: edges) { + if(edge.linkedTo(point)) { + if(edge.start.equals(prevEdge.start)) { + edge.reverse(); + } + edges.remove(edge); + sortedList.add(0, edge); + return true; + } + } + + return false; + } + + @Deprecated + public static Vector2[] extractClosedLoopOld(Set edges) { + ArrayList sortedList = new ArrayList(); + Edge nextEdge = (Edge) edges.toArray()[0]; + sortedList.add(nextEdge); + sortedList = recursivelySortChainPoints(edges, nextEdge, sortedList); + edges.removeAll(sortedList); + + Vector2[] result = new Vector2[sortedList.size()]; + int iterator = 0; + for(Edge edge: sortedList) { + result[iterator++] = edge.start; + } + + return result; + } + + @Deprecated + private static ArrayList recursivelySortChainPoints(Set edges, Edge edge, ArrayList sortedList) { + Edge nextEdge = findLink(edges, edge, edge.end); + if(!edge.end.equals(nextEdge.start)) nextEdge.reverse(); + sortedList.add(nextEdge); + if(sortedList.get(0).linkedTo(sortedList.get(sortedList.size() - 1)) && sortedList.size() >= 3) { + //loop is closed + return sortedList; + } + return recursivelySortChainPoints(edges, nextEdge, sortedList); + } + + public static Edge findLink(Set edges, Edge edge, Vector2 point) { + for(Edge linkedEdge: edges) { + if(!linkedEdge.equals(edge) && linkedEdge.linkedTo(point)) { + return linkedEdge; + } + } + + return null; + } + + public static class Edge { + public Vector2 start; + public Vector2 end; + + public Edge(float startX, float startY, float endX, float endY) { + start = new Vector2(startX, startY); + end = new Vector2(endX, endY); + } + + public Edge(Vector2 start, Vector2 end) { + this.start = start; + this.end = end; + } + + public boolean linkedTo(Vector2 point) { + if(start.equals(point) || end.equals(point)) return true; + return false; + } + + public boolean linkedTo(Edge edge) { + if(!this.equals(edge) && (start.equals(edge.end) || end.equals(edge.start) || end.equals(edge.end) || start.equals(edge.start))) return true; + return false; + } + + public void reverse() { + Vector2 tmp = new Vector2(start); + start = end; + end = tmp; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Edge other = (Edge)obj; + return hashCode() == other.hashCode(); + } + + @Override + public int hashCode () { + return start.hashCode() + end.hashCode(); + } + } + +} diff --git a/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/TransformMathUtils.java b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/TransformMathUtils.java new file mode 100644 index 00000000..7965d51b --- /dev/null +++ b/hyperlap2d-runtime-libgdx/src/main/java/games/rednblack/editor/renderer/utils/TransformMathUtils.java @@ -0,0 +1,148 @@ +package games.rednblack.editor.renderer.utils; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Camera; +import com.badlogic.gdx.math.*; +import games.rednblack.editor.renderer.components.ParentNodeComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.ViewPortComponent; + +public class TransformMathUtils { + + private static final Matrix3 tmpMat = new Matrix3(); + + /** Transforms the specified point in the scene's coordinates to the entity's local coordinate system. */ + public static Vector2 sceneToLocalCoordinates (Entity entity, Vector2 sceneCoords) { + ParentNodeComponent parentNodeComponent = entity.getComponent(ParentNodeComponent.class); + Entity parentEntity = null; + if(parentNodeComponent != null){ + parentEntity = parentNodeComponent.parentEntity; + } + if (parentEntity != null) sceneToLocalCoordinates(parentEntity, sceneCoords); + parentToLocalCoordinates(entity, sceneCoords); + return sceneCoords; + } + + public static Vector2 globalToLocalCoordinates (Entity entity, Vector2 sceneCoords) { + ParentNodeComponent parentNodeComponent = entity.getComponent(ParentNodeComponent.class); + Entity parentEntity = null; + if(parentNodeComponent != null){ + ViewPortComponent viewPortComponent = ComponentRetriever.get(parentNodeComponent.parentEntity, ViewPortComponent.class); + if(viewPortComponent == null) { + parentEntity = parentNodeComponent.parentEntity; + } else { + Vector3 worldCoordinates = viewPortComponent.viewPort.getCamera().unproject(new Vector3(sceneCoords.x, sceneCoords.y,0)); + sceneCoords.x = worldCoordinates.x; + sceneCoords.y = worldCoordinates.y; + } + } + if (parentEntity != null) { + globalToLocalCoordinates(parentEntity, sceneCoords); + } + parentToLocalCoordinates(entity, sceneCoords); + return sceneCoords; + } + + + /** Converts the coordinates given in the parent's coordinate system to this entity's coordinate system. */ + public static Vector2 parentToLocalCoordinates (Entity childEntity, Vector2 parentCoords) { + TransformComponent transform = childEntity.getComponent(TransformComponent.class); + + final float rotation = transform.rotation; + final float scaleX = transform.scaleX; + final float scaleY = transform.scaleY; + final float childX = transform.x; + final float childY = transform.y; + if (rotation == 0) { + if (scaleX == 1 && scaleY == 1) { + parentCoords.x -= childX; + parentCoords.y -= childY; + } else { + //TODO origin + final float originX = 0; + final float originY = 0; + parentCoords.x = (parentCoords.x - childX - originX) / scaleX + originX; + parentCoords.y = (parentCoords.y - childY - originY) / scaleY + originY; + } + } else { + final float cos = (float)Math.cos(rotation * MathUtils.degreesToRadians); + final float sin = (float)Math.sin(rotation * MathUtils.degreesToRadians); + //TODO origin + final float originX = 0; + final float originY = 0; + final float tox = parentCoords.x - childX - originX; + final float toy = parentCoords.y - childY - originY; + parentCoords.x = (tox * cos + toy * sin) / scaleX + originX; + parentCoords.y = (tox * -sin + toy * cos) / scaleY + originY; + } + return parentCoords; + } + + /** Transforms the specified point in the entity's coordinates to be in the scene's coordinates.*/ + public static Vector2 localToSceneCoordinates (Entity entity, Vector2 localCoords) { + return localToAscendantCoordinates(null, entity, localCoords); + } + + /** Converts coordinates for this entity to those of a parent entity. The ascendant does not need to be a direct parent. */ + public static Vector2 localToAscendantCoordinates (Entity ascendant, Entity entity, Vector2 localCoords) { + while (entity != null) { + localToParentCoordinates(entity, localCoords); + ParentNodeComponent parentNode = entity.getComponent(ParentNodeComponent.class); + if(parentNode == null){ + break; + } + entity = parentNode.parentEntity; + if (entity == ascendant) break; + } + return localCoords; + } + + /** Transforms the specified point in the actor's coordinates to be in the parent's coordinates. */ + public static Vector2 localToParentCoordinates (Entity entity, Vector2 localCoords) { + TransformComponent transform = entity.getComponent(TransformComponent.class); + + final float rotation = -transform.rotation; + final float scaleX = transform.scaleX; + final float scaleY = transform.scaleY; + final float x = transform.x; + final float y = transform.y; + if (rotation == 0) { + if (scaleX == 1 && scaleY == 1) { + localCoords.x += x; + localCoords.y += y; + } else { + final float originX = transform.originX; + final float originY = transform.originY; + localCoords.x = (localCoords.x - originX) * scaleX + originX + x; + localCoords.y = (localCoords.y - originY) * scaleY + originY + y; + } + } else { + final float cos = (float)Math.cos(rotation * MathUtils.degreesToRadians); + final float sin = (float)Math.sin(rotation * MathUtils.degreesToRadians); + final float originX = transform.originX; + final float originY = transform.originY; + final float tox = (localCoords.x - originX) * scaleX; + final float toy = (localCoords.y - originY) * scaleY; + localCoords.x = (tox * cos + toy * sin) + originX + x; + localCoords.y = (tox * -sin + toy * cos) + originY + y; + } + return localCoords; + } + + public static Matrix3 transform(TransformComponent transformComponent) { + float translationX = transformComponent.x + transformComponent.originX; + float translationY = transformComponent.y + transformComponent.originY; + float scaleX = transformComponent.scaleX; + float scaleY = transformComponent.scaleY; + float angle = transformComponent.rotation; + tmpMat.idt(); + return tmpMat + .translate(translationX, translationY) + .rotate(angle) + .scale(scaleX, scaleY) + .translate(-translationX, -translationY); + + } + +} diff --git a/plugin-9patch/build.gradle b/plugin-9patch/build.gradle new file mode 100644 index 00000000..6ab5e692 --- /dev/null +++ b/plugin-9patch/build.gradle @@ -0,0 +1,35 @@ +plugins { + id 'java' +} + +group 'games.rednblack' +version '0.0.1' + +ext { + gdxVersion = '1.9.10' + box2DLightsVersion = '1.5' + ashleyVersion = '1.7.3' + visUIVersion = '1.4.4' +} + +repositories { + mavenCentral() +} + +dependencies { + implementation "com.badlogicgames.gdx:gdx:$gdxVersion" + implementation "com.badlogicgames.ashley:ashley:$ashleyVersion" + implementation "com.kotcrab.vis:vis-ui:$visUIVersion" + + implementation 'net.mountainblade:modular:1.0' + + implementation project(":hyperlap2d-common-api") + implementation project(":hyperlap2d-runtime-libgdx") + + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +task dist(type: Jar) { + from files(sourceSets.main.output.classesDirs) + from files(sourceSets.main.output.resourcesDir) +} \ No newline at end of file diff --git a/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/EditingZone.java b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/EditingZone.java new file mode 100644 index 00000000..40d008c3 --- /dev/null +++ b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/EditingZone.java @@ -0,0 +1,265 @@ +package games.rednblack.editor.plugin.ninepatch; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Circle; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputListener; +import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack; + +/** + * Created by azakhary on 8/18/2015. + */ +public class EditingZone extends Actor { + + private ShapeRenderer shapeRenderer; + private TextureRegion texture; + + private static final Color BG = new Color(43f / 255f, 43f / 255f, 43f / 255f, 1f); + private static final Color GUIDE_COLOR = new Color(255f/255f, 94f/255f, 0f/255f, 0.5f); + private static final Color OVER_GUIDE_COLOR = new Color(255f/255f, 173f/255f, 125f/255f, 1f); + + private float currZoom = 1f; + private Vector2 shift = new Vector2(0, 0); + + private int mouseOverSplit = -1; + + private float[] splitPositions = new float[4]; + private int[] splits = new int[4]; + + public interface PatchChangeListener { + public void changed(int[] splits); + } + + private PatchChangeListener listener; + + public EditingZone() { + shapeRenderer = new ShapeRenderer(); + + addListener(new InputListener() { + private Vector2 lastPoint; + private int selectedSplit = -1; + + public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { + selectedSplit = splitCollision(x, y); + if(selectedSplit >= 0) { + + } else { + lastPoint = new Vector2(x, y); + } + return true; + } + + public void touchDragged(InputEvent event, float x, float y, int pointer) { + if (selectedSplit >= 0) { + if(selectedSplit == 0) { //left + splits[0] = (int) ((x-shift.x-getWidth()/2f)/currZoom+texture.getRegionWidth()/2f); + if(splits[0] > texture.getRegionWidth()-splits[1]) { + int tmp = splits[1]; splits[1] = texture.getRegionWidth()-splits[0]; splits[0] = texture.getRegionWidth() - tmp; + selectedSplit = 1; + mouseOverSplit = selectedSplit; + } + splitUpdate(); + return; + } + if(selectedSplit == 1) { + splits[1] = -(int) ((x-shift.x-getWidth()/2f)/currZoom-texture.getRegionWidth()/2f); + if(texture.getRegionWidth()-splits[1] < splits[0]) { + int tmp = splits[0]; splits[0] = texture.getRegionWidth() - splits[1]; splits[1] = texture.getRegionWidth() - tmp; + selectedSplit = 0; + mouseOverSplit = selectedSplit; + } + splitUpdate(); + return; + } + if(selectedSplit == 2) { // top + splits[2] = -(int) ((y-shift.y-getHeight()/2f)/currZoom-texture.getRegionHeight()/2f); + if(texture.getRegionHeight()-splits[2] < splits[3]) { + int tmp = splits[2]; splits[2] = texture.getRegionHeight()-splits[3]; splits[3] = texture.getRegionHeight()-tmp; + selectedSplit = 3; + mouseOverSplit = selectedSplit; + } + splitUpdate(); + return; + } + if(selectedSplit == 3) { + splits[3] = (int) ((y-shift.y-getHeight()/2f)/currZoom+texture.getRegionHeight()/2f); + if(splits[3] > texture.getRegionHeight()-splits[2]) { + int tmp = splits[3]; splits[3] = texture.getRegionHeight()-splits[2]; splits[2] = texture.getRegionHeight()-tmp; + selectedSplit = 2; + mouseOverSplit = selectedSplit; + } + splitUpdate(); + return; + } + } else { + Vector2 diff = new Vector2(x - lastPoint.x, y - lastPoint.y); + shiftBy(diff); + lastPoint = new Vector2(x, y); + } + } + + public void touchUp(InputEvent event, float x, float y, int pointer, int button) { + selectedSplit = -1; + + if(listener != null) { + listener.changed(splits.clone()); + } + } + + public boolean mouseMoved(InputEvent event, float x, float y) { + mouseOverSplit = splitCollision(x, y); + return false; + } + }); + } + + public void setListener(PatchChangeListener listener) { + this.listener = listener; + } + + public void splitUpdate() { + if(splits[0] < 0) splits[0] = 0; + if(splits[1] < 0) splits[1] = 0; + if(splits[2] < 0) splits[2] = 0; + if(splits[3] < 0) splits[3] = 0; + } + + public int[] getSplits() { + return splits.clone(); + } + + public void setTexture(TextureRegion texture) { + this.texture = texture; + + splits[0] = ((TextureAtlas.AtlasRegion)texture).splits[0]; + splits[1] = ((TextureAtlas.AtlasRegion)texture).splits[1]; + splits[2] = ((TextureAtlas.AtlasRegion)texture).splits[2]; + splits[3] = ((TextureAtlas.AtlasRegion)texture).splits[3]; + } + + @Override + public void draw (Batch batch, float parentAlpha) { + Rectangle scissors = new Rectangle(); + Rectangle clipBounds = new Rectangle(getX(),getY(),getWidth(),getHeight()); + ScissorStack.calculateScissors(getStage().getCamera(), batch.getTransformMatrix(), clipBounds, scissors); + ScissorStack.pushScissors(scissors); + + drawBg(batch, parentAlpha); + + batch.draw(texture, + getX() + getWidth() / 2 - texture.getRegionWidth() / 2 + shift.x, + getY() + getHeight() / 2 - texture.getRegionHeight() / 2 + shift.y, + texture.getRegionWidth() / 2f, + texture.getRegionHeight() / 2f, + texture.getRegionWidth(), texture.getRegionHeight(), + currZoom, currZoom, 0); + + drawSplits(batch, parentAlpha); + + batch.flush(); + ScissorStack.popScissors(); + } + + public void drawBg(Batch batch, float parentAlpha) { + batch.end(); + Gdx.gl.glLineWidth(1.0f); + Gdx.gl.glEnable(GL20.GL_BLEND); + Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); + + shapeRenderer.setProjectionMatrix(getStage().getCamera().combined); + Matrix4 matrix = batch.getTransformMatrix(); + shapeRenderer.setTransformMatrix(matrix); + + shapeRenderer.begin(ShapeRenderer.ShapeType.Filled); + BG.a = parentAlpha; + shapeRenderer.setColor(BG); + shapeRenderer.rect(getX(), getY(), getWidth(), getHeight()); + shapeRenderer.end(); + + Gdx.gl.glDisable(GL20.GL_BLEND); + batch.begin(); + batch.setColor(Color.WHITE.r, Color.WHITE.g, Color.WHITE.b, Color.WHITE.a * parentAlpha); + } + + public void drawSplits(Batch batch, float parentAlpha) { + batch.end(); + Gdx.gl.glLineWidth(1.0f); + Gdx.gl.glEnable(GL20.GL_BLEND); + Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); + + shapeRenderer.setProjectionMatrix(getStage().getCamera().combined); + Matrix4 matrix = batch.getTransformMatrix(); + shapeRenderer.setTransformMatrix(matrix); + + shapeRenderer.begin(ShapeRenderer.ShapeType.Line); + + // left, right, top , bottom + Color guideColor = new Color(GUIDE_COLOR); + guideColor.a*=parentAlpha; + Color overColor = new Color(OVER_GUIDE_COLOR); + overColor.a*=parentAlpha; + + splitPositions[0] = shift.x + getWidth() / 2f + (-texture.getRegionWidth() / 2f + splits[0]) * currZoom; + splitPositions[1] = shift.x + getWidth() / 2f + (texture.getRegionWidth() / 2f - splits[1]) * currZoom; + splitPositions[2] = shift.y + getHeight()/2f + (texture.getRegionHeight()/2 - splits[2])*currZoom; + splitPositions[3] = shift.y + getHeight() / 2f + (-texture.getRegionHeight() / 2 + splits[3]) * currZoom; + + + if(mouseOverSplit == 0) shapeRenderer.setColor(overColor); else shapeRenderer.setColor(guideColor); + shapeRenderer.line(getX() + splitPositions[0], getY(), getX() + splitPositions[0], getY() + getHeight()); + + if(mouseOverSplit == 1) shapeRenderer.setColor(overColor); else shapeRenderer.setColor(guideColor); + shapeRenderer.line(getX() + splitPositions[1], getY(), getX() + splitPositions[1], getY() + getHeight()); + + if(mouseOverSplit == 2) shapeRenderer.setColor(overColor); else shapeRenderer.setColor(guideColor); + shapeRenderer.line(getX(), getY() + splitPositions[2], getX() + getWidth(), getY() + splitPositions[2]); + + if(mouseOverSplit == 3) shapeRenderer.setColor(overColor); else shapeRenderer.setColor(guideColor); + shapeRenderer.line(getX(), getY() + splitPositions[3], getX() + getWidth(), getY() + splitPositions[3]); + + shapeRenderer.end(); + Gdx.gl.glDisable(GL20.GL_BLEND); + batch.begin(); + batch.setColor(Color.WHITE.r, Color.WHITE.g, Color.WHITE.b, Color.WHITE.a * parentAlpha); + } + + public void zoomBy(int amount) { + float defaultSize = 1.0f - amount*0.12f; + currZoom*=defaultSize; + } + + public void shiftBy(Vector2 diff) { + shift.add(diff); + } + + public int splitCollision(float x, float y) { + Circle touchCircle = new Circle(); + touchCircle.radius = 5f; + touchCircle.setPosition(x, y); + + if(touchCircle.contains(splitPositions[0], touchCircle.y)) { + return 0; + } + if(touchCircle.contains(splitPositions[1], touchCircle.y)) { + return 1; + } + if(touchCircle.contains(touchCircle.x, splitPositions[2])) { + return 2; + } + if(touchCircle.contains(touchCircle.x, splitPositions[3])) { + return 3; + } + + return -1; + } +} \ No newline at end of file diff --git a/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/ImageUtils.java b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/ImageUtils.java new file mode 100644 index 00000000..ecadb9b3 --- /dev/null +++ b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/ImageUtils.java @@ -0,0 +1,232 @@ +package games.rednblack.editor.plugin.ninepatch; + +import com.badlogic.gdx.graphics.g2d.TextureAtlas; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.awt.image.WritableRaster; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +/** + * Created by various artists on 8/18/2015. + */ +public class ImageUtils { + private static final int NINEPATCH_PADDING = 1; + private static final String OUTPUT_TYPE = "png"; + + + /** Returns the pads, or null if the image had no pads or the pads match the splits. Pads are an int[4] that has left, right, + * top, bottom. */ + public int[] getPads (BufferedImage image, String name, int[] splits) { + WritableRaster raster = image.getRaster(); + + int bottom = raster.getHeight() - 1; + int right = raster.getWidth() - 1; + + int startX = getSplitPoint(raster, name, 1, bottom, true, true); + int startY = getSplitPoint(raster, name, right, 1, true, false); + + // No need to hunt for the end if a start was never found. + int endX = 0; + int endY = 0; + if (startX != 0) endX = getSplitPoint(raster, name, startX + 1, bottom, false, true); + if (startY != 0) endY = getSplitPoint(raster, name, right, startY + 1, false, false); + + // Ensure pixels after the end are not invalid. + getSplitPoint(raster, name, endX + 1, bottom, true, true); + getSplitPoint(raster, name, right, endY + 1, true, false); + + // No pads. + if (startX == 0 && endX == 0 && startY == 0 && endY == 0) { + return null; + } + + // -2 here is because the coordinates were computed before the 1px border was stripped. + if (startX == 0 && endX == 0) { + startX = -1; + endX = -1; + } else { + if (startX > 0) { + startX--; + endX = raster.getWidth() - 2 - (endX - 1); + } else { + // If no start point was ever found, we assume full stretch. + endX = raster.getWidth() - 2; + } + } + if (startY == 0 && endY == 0) { + startY = -1; + endY = -1; + } else { + if (startY > 0) { + startY--; + endY = raster.getHeight() - 2 - (endY - 1); + } else { + // If no start point was ever found, we assume full stretch. + endY = raster.getHeight() - 2; + } + } + + int[] pads = new int[] {startX, endX, startY, endY}; + + if (splits != null && Arrays.equals(pads, splits)) { + return null; + } + + return pads; + } + + /** Returns the splits, or null if the image had no splits or the splits were only a single region. Splits are an int[4] that + * has left, right, top, bottom. */ + public int[] getSplits (BufferedImage image, String name) { + WritableRaster raster = image.getRaster(); + + int startX = getSplitPoint(raster, name, 1, 0, true, true); + int endX = getSplitPoint(raster, name, startX, 0, false, true); + int startY = getSplitPoint(raster, name, 0, 1, true, false); + int endY = getSplitPoint(raster, name, 0, startY, false, false); + + // Ensure pixels after the end are not invalid. + getSplitPoint(raster, name, endX + 1, 0, true, true); + getSplitPoint(raster, name, 0, endY + 1, true, false); + + // No splits, or all splits. + if (startX == 0 && endX == 0 && startY == 0 && endY == 0) return null; + + // Subtraction here is because the coordinates were computed before the 1px border was stripped. + if (startX != 0) { + startX--; + endX = raster.getWidth() - 2 - (endX - 1); + } else { + // If no start point was ever found, we assume full stretch. + endX = raster.getWidth() - 2; + } + if (startY != 0) { + startY--; + endY = raster.getHeight() - 2 - (endY - 1); + } else { + // If no start point was ever found, we assume full stretch. + endY = raster.getHeight() - 2; + } + + return new int[] {startX, endX, startY, endY}; + } + + /** Hunts for the start or end of a sequence of split pixels. Begins searching at (startX, startY) then follows along the x or y + * axis (depending on value of xAxis) for the first non-transparent pixel if startPoint is true, or the first transparent pixel + * if startPoint is false. Returns 0 if none found, as 0 is considered an invalid split point being in the outer border which + * will be stripped. */ + static private int getSplitPoint (WritableRaster raster, String name, int startX, int startY, boolean startPoint, boolean xAxis) { + int[] rgba = new int[4]; + + int next = xAxis ? startX : startY; + int end = xAxis ? raster.getWidth() : raster.getHeight(); + int breakA = startPoint ? 255 : 0; + + int x = startX; + int y = startY; + while (next != end) { + if (xAxis) + x = next; + else + y = next; + + raster.getPixel(x, y, rgba); + if (rgba[3] == breakA) return next; + + if (!startPoint && (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0 || rgba[3] != 255)) { + // error + } + + next++; + } + + return 0; + } + + public BufferedImage extractImage(TextureAtlas.TextureAtlasData atlas, String regionName, int[] splits) { + for (TextureAtlas.TextureAtlasData.Region region : atlas.getRegions()) { + if(region.name.equals(regionName)) { + TextureAtlas.TextureAtlasData.Page page = region.page; + BufferedImage img = null; + try { + img = ImageIO.read(page.textureFile.file()); + } catch (IOException e) { + + } + region.splits = splits; + return extractNinePatch(img, region); + } + } + return null; + } + + private BufferedImage extractImage (BufferedImage page, TextureAtlas.TextureAtlasData.Region region, int padding) { + BufferedImage splitImage = null; + + // get the needed part of the page and rotate if needed + if (region.rotate) { + BufferedImage srcImage = page.getSubimage(region.left, region.top, region.height, region.width); + splitImage = new BufferedImage(region.width, region.height, page.getType()); + + AffineTransform transform = new AffineTransform(); + transform.rotate(Math.toRadians(90.0)); + transform.translate(0, -region.width); + AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR); + op.filter(srcImage, splitImage); + } else { + splitImage = page.getSubimage(region.left, region.top, region.width, region.height); + } + + // draw the image to a bigger one if padding is needed + if (padding > 0) { + BufferedImage paddedImage = new BufferedImage(splitImage.getWidth() + padding * 2, splitImage.getHeight() + padding * 2, + page.getType()); + Graphics2D g2 = paddedImage.createGraphics(); + g2.drawImage(splitImage, padding, padding, null); + g2.dispose(); + return paddedImage; + } else { + return splitImage; + } + } + + + private BufferedImage extractNinePatch (BufferedImage page, TextureAtlas.TextureAtlasData.Region region) { + BufferedImage splitImage = extractImage(page, region, NINEPATCH_PADDING); + Graphics2D g2 = splitImage.createGraphics(); + g2.setColor(Color.BLACK); + + // Draw the four lines to save the ninepatch's padding and splits + int startX = region.splits[0] + NINEPATCH_PADDING; + int endX = region.width - region.splits[1] + NINEPATCH_PADDING - 1; + int startY = region.splits[2] + NINEPATCH_PADDING; + int endY = region.height - region.splits[3] + NINEPATCH_PADDING - 1; + if (endX >= startX) g2.drawLine(startX, 0, endX, 0); + if (endY >= startY) g2.drawLine(0, startY, 0, endY); + if (region.pads != null) { + int padStartX = region.pads[0] + NINEPATCH_PADDING; + int padEndX = region.width - region.pads[1] + NINEPATCH_PADDING - 1; + int padStartY = region.pads[2] + NINEPATCH_PADDING; + int padEndY = region.height - region.pads[3] + NINEPATCH_PADDING - 1; + g2.drawLine(padStartX, splitImage.getHeight() - 1, padEndX, splitImage.getHeight() - 1); + g2.drawLine(splitImage.getWidth() - 1, padStartY, splitImage.getWidth() - 1, padEndY); + } + g2.dispose(); + + return splitImage; + } + + public void saveImage(BufferedImage image, String path) { + try { + ImageIO.write(image, OUTPUT_TYPE, new File(path)); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/MainPanel.java b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/MainPanel.java new file mode 100644 index 00000000..76c03b83 --- /dev/null +++ b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/MainPanel.java @@ -0,0 +1,113 @@ +package games.rednblack.editor.plugin.ninepatch; + +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputListener; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.utils.Align; +import com.kotcrab.vis.ui.widget.VisLabel; +import com.kotcrab.vis.ui.widget.VisTable; +import com.kotcrab.vis.ui.widget.VisTextButton; +import com.puremvc.patterns.facade.SimpleFacade; +import games.rednblack.h2d.common.H2DDialog; + +/** + * Created by azakhary on 8/18/2015. + */ +public class MainPanel extends H2DDialog { + public static final String CLASS_NAME = "ames.rednblack.editor.plugin.ninepatch.MainPanel"; + + public static final String SAVE_CLICKED = CLASS_NAME + ".SAVE_CLICKED"; + + private SimpleFacade facade; + + private VisTable mainTable; + private TextureRegion texture; + + private VisTable editingTable; + private VisTable previewTable; + + private EditingZone editingZone; + private PreviewWidget previewWidget; + + public MainPanel() { + super("Nine Patch"); + addCloseButton(); + + facade = SimpleFacade.getInstance(); + + mainTable = new VisTable(); + add(mainTable).width(520).height(310).padBottom(7); + editingTable = new VisTable(); + previewTable = new VisTable(); + + mainTable.add(editingTable).width(310).expandY(); + mainTable.add(previewTable).expandX().expandY(); + mainTable.row(); + } + + private void initView() { + editingTable.clear(); + editingZone = new EditingZone(); + editingZone.setTexture(texture); + editingTable.add(editingZone); + + editingZone.setWidth(310); + editingZone.setHeight(310); + + editingZone.setListener(new EditingZone.PatchChangeListener() { + @Override + public void changed(int[] splits) { + previewWidget.update((TextureAtlas.AtlasRegion) texture, splits); + } + }); + } + + private void initPreView() { + previewTable.clear(); + previewWidget = new PreviewWidget(); + previewWidget.setHeight(205); + previewTable.add(previewWidget).width(200).height(205).top(); + previewTable.row(); + previewWidget.update((TextureAtlas.AtlasRegion) texture, ((TextureAtlas.AtlasRegion) texture).splits); + + VisLabel label = new VisLabel("Note: after saving, your \n scene will reload to \n apply changes."); + label.setAlignment(Align.center); + previewTable.add(label).pad(10).fillY().expandY(); + previewTable.row(); + + VisTextButton saveBtn = new VisTextButton("apply and save"); + previewTable.add(saveBtn).pad(5); + previewTable.row(); + + saveBtn.addListener(new ClickListener() { + public void clicked (InputEvent event, float x, float y) { + facade.sendNotification(SAVE_CLICKED); + } + }); + } + + public void setTexture(TextureRegion texture) { + this.texture = texture; + + initView(); + initPreView(); + } + + public void setListeners(Stage stage) { + stage.addListener(new InputListener() { + @Override + public boolean scrolled(InputEvent event, float x, float y, int amount) { + editingZone.zoomBy(amount); + return false; + } + }); + } + + public int[] getSplits() { + return editingZone.getSplits(); + } + +} \ No newline at end of file diff --git a/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/MainPanelMediator.java b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/MainPanelMediator.java new file mode 100644 index 00000000..5d3edabc --- /dev/null +++ b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/MainPanelMediator.java @@ -0,0 +1,155 @@ +package games.rednblack.editor.plugin.ninepatch; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.puremvc.patterns.mediator.SimpleMediator; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.components.NinePatchComponent; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +import java.awt.image.BufferedImage; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +/** + * Created by azakhary on 8/18/2015. + */ +public class MainPanelMediator extends SimpleMediator { + private static final String TAG = MainPanelMediator.class.getCanonicalName(); + public static final String NAME = TAG; + + private NinePatchPlugin plugin; + + private ImageUtils imageUtils = new ImageUtils(); + + public MainPanelMediator(NinePatchPlugin plugin) { + super(NAME, new MainPanel()); + this.plugin = plugin; + } + + @Override + public String[] listNotificationInterests() { + return new String[]{ + NinePatchPlugin.EDIT_NINE_PATCH, + NinePatchPlugin.CONVERT_TO_NINE_PATCH, + MainPanel.SAVE_CLICKED + }; + } + + @Override + public void handleNotification(Notification notification) { + super.handleNotification(notification); + switch (notification.getName()) { + case NinePatchPlugin.EDIT_NINE_PATCH: + loadNinePatch(); + break; + case NinePatchPlugin.CONVERT_TO_NINE_PATCH: + convertImageToNinePatch(); + loadNinePatch(); + break; + case MainPanel.SAVE_CLICKED: + Entity entity = plugin.currEditingEntity; + NinePatchComponent ninePatchComponent = ComponentRetriever.get(entity, NinePatchComponent.class); + applyNewSplits(ninePatchComponent.textureRegionName, viewComponent.getSplits()); + viewComponent.hide(); + break; + } + } + + private void convertImageToNinePatch() { + Entity entity = plugin.currEditingEntity; + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + mainItemComponent.entityType = EntityFactory.NINE_PATCH; + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + String regionName = textureRegionComponent.regionName; + NinePatchComponent ninePatchComponent = new NinePatchComponent(); + ninePatchComponent.textureRegionName = regionName; + TextureAtlas.AtlasRegion newRegion = (TextureAtlas.AtlasRegion) textureRegionComponent.region; + int[] splits = {0, 0, 0, 0}; + newRegion.splits = splits; + ninePatchComponent.ninePatch = new NinePatch(textureRegionComponent.region, 0, 0, 0, 0); + entity.add(ninePatchComponent); + + //remove original image + File originalImg = new File(plugin.getAPI().getProjectPath() + "/assets/orig/images/"+regionName+".png"); + originalImg.delete(); + + //save project + plugin.getAPI().saveProject(); + + //save split data + addSplitsToImageInAtlas(regionName, splits); + applyNewSplits(regionName, splits); + } + + private void loadNinePatch() { + Entity entity = plugin.currEditingEntity; + NinePatchComponent ninePatchComponent = ComponentRetriever.get(entity, NinePatchComponent.class); + loadRegion(ninePatchComponent.textureRegionName); + viewComponent.show(plugin.getAPI().getUIStage()); + } + + private void addSplitsToImageInAtlas(String textureRegionName, int[] splits) { + FileHandle packAtlas = Gdx.files.internal(plugin.getAPI().getProjectPath() + "/assets/orig/pack/pack.atlas"); + String content = packAtlas.readString(); + int regionIndex = content.indexOf(textureRegionName); + int splitEnd = content.indexOf("orig: ", regionIndex); + String splitStr = "split: "+splits[0]+", "+splits[1]+", "+splits[2]+", "+splits[3]+"\n "; + String newContent = content.substring(0, splitEnd) + splitStr + content.substring(splitEnd, content.length()); + File test = new File(plugin.getAPI().getProjectPath() + "/assets/orig/pack/pack.atlas"); + writeFile(newContent, test); + } + + private void applyNewSplits(String textureRegionName, int[] splits) { + // first need to modify original image + FileHandle packAtlas = Gdx.files.internal(plugin.getAPI().getProjectPath() + "/assets/orig/pack/pack.atlas"); + FileHandle imagesDir = Gdx.files.internal(plugin.getAPI().getProjectPath() + "/assets/orig/pack/"); + TextureAtlas.TextureAtlasData atlas = new TextureAtlas.TextureAtlasData(packAtlas, imagesDir, false); + BufferedImage finalImage = imageUtils.extractImage(atlas, textureRegionName, splits); + imageUtils.saveImage(finalImage, plugin.getAPI().getProjectPath() + "/assets/orig/images/"+textureRegionName+".9.png"); + + // now need to modify the pack + String content = packAtlas.readString(); + int regionIndex = content.indexOf(textureRegionName); + int splitStart = content.indexOf("split: ", regionIndex) + "split: ".length(); + int splitEnd = content.indexOf("orig: ", splitStart); + String splitStr = splits[0]+", "+splits[1]+", "+splits[2]+", "+splits[3]+"\n "; + String newContent = content.substring(0, splitStart) + splitStr + content.substring(splitEnd, content.length()); + File test = new File(plugin.getAPI().getProjectPath() + "/assets/orig/pack/pack.atlas"); + writeFile(newContent, test); + + // reload + plugin.getAPI().reLoadProject(); + } + + private void writeFile(String content, File file) { + BufferedWriter output = null; + try { + output = new BufferedWriter(new FileWriter(file)); + output.write(content); + } catch ( IOException e ) { + e.printStackTrace(); + } finally { + if ( output != null ) try { + output.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private void loadRegion(String name) { + TextureAtlas atlas = plugin.getAPI().getProjectTextureAtlas(); + viewComponent.setTexture(atlas.findRegion(name)); + + viewComponent.setListeners(plugin.getAPI().getUIStage()); + } +} diff --git a/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/NinePatchPlugin.java b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/NinePatchPlugin.java new file mode 100644 index 00000000..3e8dbca7 --- /dev/null +++ b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/NinePatchPlugin.java @@ -0,0 +1,57 @@ +package games.rednblack.editor.plugin.ninepatch; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.h2d.common.plugins.H2DPluginAdapter; +import net.mountainblade.modular.annotations.Implementation; + +import java.util.Set; + +/** + * Created by azakhary on 8/18/2015. + * Plugin to edit Nine Patch data on imported texture region + */ +@Implementation(authors = "azakhary", version = "0.0.1") +public class NinePatchPlugin extends H2DPluginAdapter { + public static final String CLASS_NAME = "games.rednblack.editor.plugin.ninepatch.NinePatchPlugin"; + + public static final String EDIT_NINE_PATCH = CLASS_NAME + ".EDIT_NINE_PATCH"; + public static final String CONVERT_TO_NINE_PATCH = CLASS_NAME + ".CONVERT_TO_NINE_PATCH"; + + private MainPanelMediator performancePanelMediator; + + public Entity currEditingEntity; + + public NinePatchPlugin() { + performancePanelMediator = new MainPanelMediator(this); + } + + @Override + public void initPlugin() { + facade.registerMediator(performancePanelMediator); + pluginAPI.setDropDownItemName(EDIT_NINE_PATCH, "Edit NinePatch"); + pluginAPI.setDropDownItemName(CONVERT_TO_NINE_PATCH, "Convert to NinePatch"); + } + + @Override + public void onDropDownOpen(Set selectedEntities, Array actionsSet) { + if(selectedEntities.size() == 1) { + Entity entity = selectedEntities.stream().findFirst().get(); + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + + if(mainItemComponent.entityType == EntityFactory.NINE_PATCH) { + // it's our guy + currEditingEntity = entity; + actionsSet.add(EDIT_NINE_PATCH); + } + if(mainItemComponent.entityType == EntityFactory.IMAGE_TYPE) { + // it's our guy + currEditingEntity = entity; + actionsSet.add(CONVERT_TO_NINE_PATCH); + } + } + } +} diff --git a/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/PreviewWidget.java b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/PreviewWidget.java new file mode 100644 index 00000000..d0aeacec --- /dev/null +++ b/plugin-9patch/src/main/java/games/rednblack/editor/plugin/ninepatch/PreviewWidget.java @@ -0,0 +1,79 @@ +package games.rednblack.editor.plugin.ninepatch; + +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.scenes.scene2d.Group; +import com.badlogic.gdx.scenes.scene2d.ui.Image; + +/** + * Created by azakhary on 8/19/2015. + */ +public class PreviewWidget extends Group { + + private TextureAtlas.AtlasRegion region; + + float horizontalHeight, horizontalWidth; + float verticalHeight, verticalWidth; + float squareWidth, squareHeight; + + private Image horizontal, vertical, square; + + public PreviewWidget() { + horizontalWidth = 200f; + horizontalHeight = 50f; + + verticalWidth = 50f; + verticalHeight = 150f; + + squareWidth = 145f; + squareHeight = 150f; + } + + public void update(TextureAtlas.AtlasRegion region, int[] splits) { + this.region = region; + clear(); + NinePatch horizontalPatch = new NinePatch(region, splits[0], splits[1], splits[2], splits[3]); + NinePatch verticalPatch = new NinePatch(region, splits[0], splits[1], splits[2], splits[3]); + NinePatch squarePatch = new NinePatch(region, splits[0], splits[1], splits[2], splits[3]); + + float minSclH = getMinScale(horizontalPatch, horizontalWidth, horizontalHeight); + float minSclV = getMinScale(verticalPatch, verticalWidth, verticalHeight); + float minSclS = getMinScale(squarePatch, squareWidth, squareHeight); + + float minScl = Math.min(minSclH, minSclV); + minScl = Math.min(minScl, minSclS); + + horizontal = fitNinePatch(horizontalPatch, horizontalWidth, horizontalHeight, minScl); + addActor(horizontal); + + vertical = fitNinePatch(verticalPatch, verticalWidth, verticalHeight, minScl); + addActor(vertical); + + square = fitNinePatch(squarePatch, squareWidth, squareHeight, minScl); + addActor(square); + + horizontal.setY(getHeight() - horizontalHeight); + vertical.setY(horizontal.getY() - verticalHeight - 5); + square.setX(verticalWidth + 5); + square.setY(vertical.getY()); + } + + private float getMinScale(NinePatch horizontalPatch, float width, float height) { + float scaleX = width/horizontalPatch.getTotalWidth(); + float scaleY = height/horizontalPatch.getTotalHeight(); + float scl = Math.min(scaleX, scaleY); + if(scl > 1f) scl = 1f; + + return scl; + } + + private Image fitNinePatch(NinePatch horizontalPatch, float width, float height, float scl) { + horizontalPatch.scale(scl, scl); + + Image img = new Image(horizontalPatch); + img.setScaleX(width / horizontalPatch.getTotalWidth()); + img.setScaleY(height / horizontalPatch.getTotalHeight()); + + return img; + } +} diff --git a/plugin-performance/build.gradle b/plugin-performance/build.gradle new file mode 100644 index 00000000..c00e8e0c --- /dev/null +++ b/plugin-performance/build.gradle @@ -0,0 +1,35 @@ +plugins { + id 'java' +} + +group 'games.rednblack' +version '0.0.1' + +repositories { + mavenCentral() +} + +ext { + gdxVersion = '1.9.10' + box2DLightsVersion = '1.5' + ashleyVersion = '1.7.3' + visUIVersion = '1.4.4' +} + +dependencies { + implementation "com.badlogicgames.gdx:gdx:$gdxVersion" + implementation "com.badlogicgames.ashley:ashley:$ashleyVersion" + implementation "com.kotcrab.vis:vis-ui:$visUIVersion" + + implementation 'net.mountainblade:modular:1.0' + + implementation project(":hyperlap2d-common-api") + implementation project(":hyperlap2d-runtime-libgdx") + + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +task dist(type: Jar) { + from files(sourceSets.main.output.classesDirs) + from files(sourceSets.main.output.resourcesDir) +} \ No newline at end of file diff --git a/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanel.java b/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanel.java new file mode 100644 index 00000000..d46df27e --- /dev/null +++ b/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanel.java @@ -0,0 +1,67 @@ +package games.rednblack.editor.plugin.performance; + +import com.badlogic.ashley.core.Engine; +import com.badlogic.gdx.Gdx; +import com.kotcrab.vis.ui.widget.VisLabel; +import com.kotcrab.vis.ui.widget.VisTable; +import com.puremvc.patterns.facade.SimpleFacade; +import games.rednblack.h2d.common.UIDraggablePanel; + +public class PerformancePanel extends UIDraggablePanel { + + private SimpleFacade facade; + + private VisTable mainTable; + + private VisLabel entitiesCount; + private VisLabel fpsLbl; + + private Engine engine; + + public PerformancePanel() { + super("Performance"); + addCloseButton(); + + facade = SimpleFacade.getInstance(); + + mainTable = new VisTable(); + + add(mainTable).width(222); + } + + public void initView() { + mainTable.clear(); + + entitiesCount = new VisLabel(); + fpsLbl = new VisLabel(); + + + mainTable.add(new VisLabel("Entity count: ")).right(); + mainTable.add(entitiesCount).left().padLeft(4); + mainTable.row(); + + mainTable.add(new VisLabel("FPS: ")).right(); + mainTable.add(fpsLbl).left().padLeft(4); + mainTable.row(); + pack(); + } + + public void initLockView() { + mainTable.clear(); + + mainTable.add(new VisLabel("no scenes open")).right(); + } + + @Override + public void act(float delta) { + super.act(delta); + if(entitiesCount != null && fpsLbl != null) { + entitiesCount.setText(engine.getEntities().size() + ""); + fpsLbl.setText(Gdx.graphics.getFramesPerSecond() + ""); + } + } + + public void setEngine(Engine engine) { + this.engine = engine; + } +} \ No newline at end of file diff --git a/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanelMediator.java b/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanelMediator.java new file mode 100644 index 00000000..4f29931c --- /dev/null +++ b/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePanelMediator.java @@ -0,0 +1,48 @@ +package games.rednblack.editor.plugin.performance; + +import com.badlogic.ashley.core.Engine; +import com.puremvc.patterns.mediator.SimpleMediator; +import com.puremvc.patterns.observer.Notification; + +public class PerformancePanelMediator extends SimpleMediator { + private static final String TAG = PerformancePanelMediator.class.getCanonicalName(); + public static final String NAME = TAG; + + public static final String SCENE_LOADED = "games.rednblack.editor.proxy.SceneDataManager.SCENE_LOADED"; + public static final String NEW_ITEM_ADDED = "games.rednblack.editor.factory.ItemFactory.NEW_ITEM_ADDED"; + public static final String ACTION_DELETE = "games.rednblack.editor.controller.commands.DeleteItemsCommandDONE"; + + private PerformancePlugin performancePlugin; + + public PerformancePanelMediator(PerformancePlugin performancePlugin) { + super(NAME, new PerformancePanel()); + this.performancePlugin = performancePlugin; + + viewComponent.initLockView(); + } + + @Override + public String[] listNotificationInterests() { + return new String[]{ + SCENE_LOADED, + NEW_ITEM_ADDED, + ACTION_DELETE, + PerformancePlugin.PANEL_OPEN + }; + } + + @Override + public void handleNotification(Notification notification) { + super.handleNotification(notification); + switch (notification.getName()) { + case SCENE_LOADED: + viewComponent.initView(); + Engine engine = performancePlugin.getAPI().getEngine(); + viewComponent.setEngine(engine); + break; + case PerformancePlugin.PANEL_OPEN: + viewComponent.show(performancePlugin.getAPI().getUIStage()); + break; + } + } +} diff --git a/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePlugin.java b/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePlugin.java new file mode 100644 index 00000000..a73561c6 --- /dev/null +++ b/plugin-performance/src/main/java/games/rednblack/editor/plugin/performance/PerformancePlugin.java @@ -0,0 +1,24 @@ +package games.rednblack.editor.plugin.performance; + +import games.rednblack.h2d.common.plugins.H2DPluginAdapter; +import net.mountainblade.modular.annotations.Implementation; + +@Implementation(authors = "azakhary", version = "0.0.1") +public class PerformancePlugin extends H2DPluginAdapter { + public static final String CLASS_NAME = "games.rednblack.editor.plugin.performance"; + + public static final String PANEL_OPEN = CLASS_NAME + ".PANEL_OPEN"; + public static final String WINDOWS_MENU = "games.rednblack.editor.view.HyperLap2DMenuBar.WINDOW_MENU"; + + private PerformancePanelMediator performancePanelMediator; + + public PerformancePlugin() { + performancePanelMediator = new PerformancePanelMediator(this); + } + + @Override + public void initPlugin() { + facade.registerMediator(performancePanelMediator); + pluginAPI.addMenuItem(WINDOWS_MENU, "Performance", PANEL_OPEN); + } +} diff --git a/plugin-tiled/assets/pack/tiled.atlas b/plugin-tiled/assets/pack/tiled.atlas new file mode 100644 index 00000000..ef9579e6 --- /dev/null +++ b/plugin-tiled/assets/pack/tiled.atlas @@ -0,0 +1,88 @@ + +tiled.png +size: 512,128 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +image-Box-active + rotate: false + xy: 87, 22 + size: 4, 4 + split: 1, 1, 1, 1 + orig: 4, 4 + offset: 0, 0 + index: -1 +image-Box-inactive + rotate: false + xy: 436, 31 + size: 4, 4 + split: 1, 1, 1, 1 + orig: 4, 4 + offset: 0, 0 + index: -1 +plugin-tab-active + rotate: false + xy: 436, 105 + size: 73, 21 + split: 4, 4, 3, 0 + orig: 73, 21 + offset: 0, 0 + index: -1 +plugin-tab-inactive + rotate: false + xy: 2, 5 + size: 83, 21 + split: 3, 3, 2, 1 + orig: 83, 21 + offset: 0, 0 + index: -1 +tab-back-line + rotate: false + xy: 2, 2 + size: 2, 1 + split: 0, 0, 0, 0 + orig: 2, 1 + offset: 0, 0 + index: -1 +tile + rotate: false + xy: 436, 71 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +tile-eraser + rotate: false + xy: 436, 37 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +tiles-drop-here-normal + rotate: false + xy: 2, 28 + size: 215, 98 + orig: 215, 98 + offset: 0, 0 + index: -1 +tiles-drop-here-over + rotate: false + xy: 219, 28 + size: 215, 98 + orig: 215, 98 + offset: 0, 0 + index: -1 +tool-tilebrush + rotate: false + xy: 470, 80 + size: 22, 23 + orig: 22, 23 + offset: 0, 0 + index: -1 +tool-tileeraser + rotate: false + xy: 470, 55 + size: 22, 23 + orig: 22, 23 + offset: 0, 0 + index: -1 diff --git a/plugin-tiled/assets/pack/tiled.png b/plugin-tiled/assets/pack/tiled.png new file mode 100644 index 00000000..38cdf5ef Binary files /dev/null and b/plugin-tiled/assets/pack/tiled.png differ diff --git a/plugin-tiled/assets/textures/image-Box-active.9.png b/plugin-tiled/assets/textures/image-Box-active.9.png new file mode 100644 index 00000000..798a4e5f Binary files /dev/null and b/plugin-tiled/assets/textures/image-Box-active.9.png differ diff --git a/plugin-tiled/assets/textures/image-Box-inactive.9.png b/plugin-tiled/assets/textures/image-Box-inactive.9.png new file mode 100644 index 00000000..199d9812 Binary files /dev/null and b/plugin-tiled/assets/textures/image-Box-inactive.9.png differ diff --git a/plugin-tiled/assets/textures/plugin-tab-active.9.png b/plugin-tiled/assets/textures/plugin-tab-active.9.png new file mode 100644 index 00000000..44df0daf Binary files /dev/null and b/plugin-tiled/assets/textures/plugin-tab-active.9.png differ diff --git a/plugin-tiled/assets/textures/plugin-tab-inactive.9.png b/plugin-tiled/assets/textures/plugin-tab-inactive.9.png new file mode 100644 index 00000000..25b6f1c4 Binary files /dev/null and b/plugin-tiled/assets/textures/plugin-tab-inactive.9.png differ diff --git a/plugin-tiled/assets/textures/tab-back-line.9.png b/plugin-tiled/assets/textures/tab-back-line.9.png new file mode 100644 index 00000000..b0057876 Binary files /dev/null and b/plugin-tiled/assets/textures/tab-back-line.9.png differ diff --git a/plugin-tiled/assets/textures/tile-eraser.png b/plugin-tiled/assets/textures/tile-eraser.png new file mode 100644 index 00000000..fa55300f Binary files /dev/null and b/plugin-tiled/assets/textures/tile-eraser.png differ diff --git a/plugin-tiled/assets/textures/tile.png b/plugin-tiled/assets/textures/tile.png new file mode 100644 index 00000000..781353e0 Binary files /dev/null and b/plugin-tiled/assets/textures/tile.png differ diff --git a/plugin-tiled/assets/textures/tiles-drop-here-normal.png b/plugin-tiled/assets/textures/tiles-drop-here-normal.png new file mode 100644 index 00000000..88dcf425 Binary files /dev/null and b/plugin-tiled/assets/textures/tiles-drop-here-normal.png differ diff --git a/plugin-tiled/assets/textures/tiles-drop-here-over.png b/plugin-tiled/assets/textures/tiles-drop-here-over.png new file mode 100644 index 00000000..1065d3ee Binary files /dev/null and b/plugin-tiled/assets/textures/tiles-drop-here-over.png differ diff --git a/plugin-tiled/assets/textures/tool-tilebrush.png b/plugin-tiled/assets/textures/tool-tilebrush.png new file mode 100644 index 00000000..f9f8bf8c Binary files /dev/null and b/plugin-tiled/assets/textures/tool-tilebrush.png differ diff --git a/plugin-tiled/assets/textures/tool-tileeraser.png b/plugin-tiled/assets/textures/tool-tileeraser.png new file mode 100644 index 00000000..fdf9ff70 Binary files /dev/null and b/plugin-tiled/assets/textures/tool-tileeraser.png differ diff --git a/plugin-tiled/build.gradle b/plugin-tiled/build.gradle new file mode 100644 index 00000000..5700c386 --- /dev/null +++ b/plugin-tiled/build.gradle @@ -0,0 +1,48 @@ +plugins { + id 'java' +} + +group 'games.rednblack' +version '0.0.1' + +ext { + gdxVersion = '1.9.10' + box2DLightsVersion = '1.5' + ashleyVersion = '1.7.3' + visUIVersion = '1.4.4' + + pack = ["assets/textures", "assets/pack/", "tiled"] +} + +repositories { + mavenCentral() +} + +dependencies { + implementation "com.badlogicgames.gdx:gdx:$gdxVersion" + implementation "com.badlogicgames.ashley:ashley:$ashleyVersion" + implementation "com.kotcrab.vis:vis-ui:$visUIVersion" + + implementation 'net.mountainblade:modular:1.0' + + implementation project(":hyperlap2d-common-api") + implementation project(":hyperlap2d-runtime-libgdx") + + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +import com.badlogic.gdx.tools.texturepacker.TexturePacker +task packTextures { + if (project.ext.has('pack')) { + logger.info "Calling TexturePacker: " + pack + TexturePacker.processIfModified(file(pack[0]).absolutePath, file(pack[1]).absolutePath, pack[2] as String) + } +} + +project.ext.assetsDir = new File("assets/pack"); + +task dist(type: Jar) { + from files(sourceSets.main.output.classesDirs) + from files(sourceSets.main.output.resourcesDir) + from files(project.assetsDir); +} \ No newline at end of file diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanel.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanel.java new file mode 100644 index 00000000..62c7f9ea --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanel.java @@ -0,0 +1,233 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.plugin.tiled; + +import com.badlogic.ashley.core.Engine; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.kotcrab.vis.ui.VisUI; +import com.kotcrab.vis.ui.widget.VisLabel; +import com.kotcrab.vis.ui.widget.VisTable; +import com.kotcrab.vis.ui.widget.VisTextButton; +import com.kotcrab.vis.ui.widget.tabbedpane.Tab; +import com.kotcrab.vis.ui.widget.tabbedpane.TabbedPane; +import com.kotcrab.vis.ui.widget.tabbedpane.TabbedPaneListener; +import com.puremvc.patterns.facade.Facade; +import com.puremvc.patterns.facade.SimpleFacade; +import games.rednblack.editor.plugin.tiled.data.TileVO; +import games.rednblack.editor.plugin.tiled.manager.ResourcesManager; +import games.rednblack.editor.plugin.tiled.view.tabs.GridTilesTab; +import games.rednblack.editor.plugin.tiled.view.tabs.SettingsTab; +import games.rednblack.h2d.common.UIDraggablePanel; + +/** + * Created by mariam on 2/2/2016. + */ +public class TiledPanel extends UIDraggablePanel { + + public static final float GRID_WIDTH = 200f; + public static final float GRID_HEIGHT = 250f; + public static final float DROP_WIDTH = 210f; + public static final float DROP_HEIGHT = 140f; + public static final float SETTINGS_WIDTH = 200f; + public static final float SETTINGS_HEIGHT = 150f; + public static final float BOTTOM_BAR_X = 177f; + public static final float BOTTOM_BAR_DELTA_Y = 6f; + + public TiledPlugin tiledPlugin; + public Facade facade; + + protected TabbedPane tabbedPane; + protected VisTable tabTable; //table inside of each tab + protected Table paneTable; //table for 'tabs' row + + private GridTilesTab tilesTab; + private SettingsTab settingsTab; + private Image bottomBar; + private VisTable mainTable; + private Engine engine; + private ResourcesManager resourcesManager; + + public TiledPanel(TiledPlugin tiledPlugin) { + super("Tiles"); + this.tiledPlugin = tiledPlugin; + + facade = SimpleFacade.getInstance(); + + mainTable = new VisTable(); + add(mainTable) + .padLeft(-2) + .padRight(2); + + tabTable = new VisTable(); + } + + public void initView() { + if (bottomBar == null) { + this.resourcesManager = tiledPlugin.pluginRM; + bottomBar = new Image(resourcesManager.getTextureRegion("tab-back-line")); + bottomBar.setWidth(80); + addActorBefore(mainTable, bottomBar); + } + + mainTable.clear(); + + TabbedPane.TabbedPaneStyle style = new TabbedPane.TabbedPaneStyle(); + VisTextButton.VisTextButtonStyle btnStyle = new VisTextButton.VisTextButtonStyle(); + btnStyle.up = new TextureRegionDrawable(resourcesManager.getTextureRegion("plugin-tab-inactive")); + btnStyle.checked = new TextureRegionDrawable(resourcesManager.getTextureRegion("plugin-tab-active")); + btnStyle.font = VisUI.getSkin().getFont("default-font"); + btnStyle.fontColor = VisUI.getSkin().getColor("white"); + style.buttonStyle = btnStyle; + tabbedPane = new TabbedPane(style); + paneTable = tabbedPane.getTable(); + + mainTable.add(paneTable) + .left() + .top() + .expandX() + .row(); + + tabTable.clear(); + paneTable.row(); + paneTable.add(tabTable) + .left() + .top() + .row(); + + tabbedPane.addListener(new TabbedPaneListener() { + + @Override + public void switchedTab (Tab tab) { + if (tab == null) { + return; + } + + float WIDTH = 0; + float HEIGHT = 0; + if (tab instanceof SettingsTab) { + WIDTH = SETTINGS_WIDTH; + HEIGHT = SETTINGS_HEIGHT; + } else if (tab instanceof GridTilesTab) { + if (GridTilesTab.isDrop) { + WIDTH = DROP_WIDTH; + HEIGHT = DROP_HEIGHT; + } else { + WIDTH = GRID_WIDTH; + HEIGHT = GRID_HEIGHT; + } + } + + Table content = tab.getContentTable(); + + tabTable.clearChildren(); + tabTable.add(content) + .width(WIDTH) + .height(HEIGHT) + .row(); + pack(); + + setBottomBarPosition(HEIGHT); + setFixedPosition(); + } + + @Override + public void removedTab(Tab tab) { + + } + + @Override + public void removedAllTabs() { + + } + + }); + + initTabs(); + + pack(); + } + + public void setBottomBarPosition(float panelHeight) { + bottomBar.setX(BOTTOM_BAR_X); + bottomBar.setY(panelHeight + BOTTOM_BAR_DELTA_Y); + } + + public void setFixedPosition() { + setPosition(56f, 765f - getPrefHeight()); + } + + public Table getDropTable() { + return tilesTab.getContentTable(); + } + + public void reInitGridSettings() { + settingsTab.resetGridCategory(); + } + + public void addTile(String tileName) { + tilesTab.addTile(tileName); + } + + public void selectTile(TileVO tileVO) { + tilesTab.selectTile(tileVO); + } + + public void removeTile() { + tilesTab.removeTile(); + reInitTabTable(); + setFixedPosition(); + tilesTab.scrollTiles(); + } + + private void initTabs() { + tilesTab = new GridTilesTab(this, 0); + tilesTab.initView(); + tabbedPane.insert(tilesTab.getTabIndex(), tilesTab); + + settingsTab = new SettingsTab(this, "Settings", 1); + settingsTab.initView(); + tabbedPane.insert(settingsTab.getTabIndex(), settingsTab); + + reInitTabTable(); + } + + public void reInitTabTable() { + float width = GridTilesTab.isDrop ? DROP_WIDTH : GRID_WIDTH; + float height = GridTilesTab.isDrop ? DROP_HEIGHT : GRID_HEIGHT; + tabTable.clear(); + tabTable.add(tilesTab.getContentTable()) + .width(width) + .height(height); + tabTable.pack(); + setBottomBarPosition(height); + pack(); + } + + public void initLockView() { + mainTable.clear(); + + mainTable.add(new VisLabel("no scenes open")).right(); + } + + public void setEngine(Engine engine) { + this.engine = engine; + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanelMediator.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanelMediator.java new file mode 100644 index 00000000..87e3e1fe --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPanelMediator.java @@ -0,0 +1,210 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.plugin.tiled; + +import com.badlogic.ashley.core.Engine; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.scenes.scene2d.utils.DragAndDrop; +import com.puremvc.patterns.mediator.SimpleMediator; +import com.puremvc.patterns.observer.Notification; +import com.vo.CursorData; +import games.rednblack.editor.plugin.tiled.data.TileVO; +import games.rednblack.editor.plugin.tiled.tools.DeleteTileTool; +import games.rednblack.editor.plugin.tiled.tools.DrawTileTool; +import games.rednblack.editor.plugin.tiled.view.tabs.SettingsTab; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.h2d.common.ResourcePayloadObject; + +import java.util.HashMap; + +/** + * Created by mariam on 2/2/2016. + */ +public class TiledPanelMediator extends SimpleMediator { + private static final String TAG = TiledPanelMediator.class.getCanonicalName(); + public static final String NAME = TAG; + + private TiledPlugin tiledPlugin; + + public TiledPanelMediator(TiledPlugin tiledPlugin) { + super(NAME, new TiledPanel(tiledPlugin)); + this.tiledPlugin = tiledPlugin; + + viewComponent.initLockView(); + } + + @Override + public String[] listNotificationInterests() { + return new String[]{ + MsgAPI.SCENE_LOADED, + TiledPlugin.TILE_ADDED, + TiledPlugin.TILE_SELECTED, + TiledPlugin.ACTION_DELETE_TILE, + TiledPlugin.ACTION_SET_GRID_SIZE_FROM_LIST, + TiledPlugin.ACTION_SET_OFFSET, + TiledPlugin.PANEL_OPEN, + TiledPlugin.OPEN_DROP_DOWN, + TiledPlugin.GRID_CHANGED, + SettingsTab.OK_BTN_CLICKED, + TiledPlugin.ACTION_SET_GRID_SIZE_FROM_ITEM, + MsgAPI.ACTION_DELETE_IMAGE_RESOURCE, + MsgAPI.ITEM_DATA_UPDATED, + MsgAPI.TOOL_SELECTED + }; + } + + @Override + public void handleNotification(Notification notification) { + super.handleNotification(notification); + + String tileName; + + switch (notification.getName()) { + case MsgAPI.SCENE_LOADED: + tiledPlugin.isSceneLoaded = true; + + tiledPlugin.initSaveData(); + viewComponent.initView(); + + DragAndDrop.Target target = new DragAndDrop.Target(viewComponent.getDropTable()) { + @Override + public boolean drag(DragAndDrop.Source source, DragAndDrop.Payload payload, float x, float y, int pointer) { + return true; + } + + @Override + public void drop(DragAndDrop.Source source, DragAndDrop.Payload payload, float x, float y, int pointer) { + + ResourcePayloadObject resourcePayloadObject = (ResourcePayloadObject) payload.getObject(); + if (!resourcePayloadObject.className.endsWith(".ImageResource")) return; //only image resource can become a tile! + + String tileName = resourcePayloadObject.name; + if (tiledPlugin.dataToSave.containsTile(tileName)) return; + + tiledPlugin.facade.sendNotification(TiledPlugin.TILE_ADDED, tileName); + + } + }; + tiledPlugin.facade.sendNotification(MsgAPI.ADD_TARGET, target); + Engine engine = tiledPlugin.getAPI().getEngine(); + viewComponent.setEngine(engine); + viewComponent.setFixedPosition(); + break; + case TiledPlugin.TILE_ADDED: + tileName = notification.getBody(); + viewComponent.addTile(tileName); + viewComponent.setFixedPosition(); + + tiledPlugin.dataToSave.addTile(tileName); + tiledPlugin.saveDataManager.save(); + break; + case TiledPlugin.TILE_SELECTED: + viewComponent.selectTile(notification.getBody()); + break; + case TiledPlugin.OPEN_DROP_DOWN: + tileName = notification.getBody(); + HashMap actionsSet = new HashMap<>(); + actionsSet.put(TiledPlugin.ACTION_SET_GRID_SIZE_FROM_LIST, "Set grid size"); + actionsSet.put(TiledPlugin.ACTION_DELETE_TILE, "Delete"); + actionsSet.put(TiledPlugin.ACTION_OPEN_OFFSET_PANEL, "Set offset"); + tiledPlugin.facade.sendNotification(TiledPlugin.TILE_SELECTED, tiledPlugin.dataToSave.getTile(tileName)); + tiledPlugin.getAPI().showPopup(actionsSet, tileName); + break; + case MsgAPI.ACTION_DELETE_IMAGE_RESOURCE: + tileName = notification.getBody(); + tiledPlugin.facade.sendNotification(TiledPlugin.ACTION_DELETE_TILE, tileName); + break; + case TiledPlugin.ACTION_SET_GRID_SIZE_FROM_LIST: + TextureRegion r = tiledPlugin.pluginRM.getTextureRegion(notification.getBody()); + tiledPlugin.dataToSave.setGrid(r.getRegionWidth() / tiledPlugin.getPixelToWorld(), r.getRegionHeight() / tiledPlugin.getPixelToWorld()); + tiledPlugin.facade.sendNotification(TiledPlugin.GRID_CHANGED); + break; + case TiledPlugin.ACTION_DELETE_TILE: + String tn = notification.getBody(); + if (!tiledPlugin.dataToSave.containsTile(tn)) return; + tiledPlugin.dataToSave.removeTile(tn); + tiledPlugin.saveDataManager.save(); + tiledPlugin.setSelectedTileVO(new TileVO()); + + viewComponent.removeTile(); + break; + case TiledPlugin.PANEL_OPEN: + if(viewComponent.isOpen) { + break; + } + + viewComponent.show(tiledPlugin.getAPI().getUIStage()); + + if(tiledPlugin.isSceneLoaded) { + viewComponent.setFixedPosition(); + } + break; + case MsgAPI.TOOL_SELECTED: + String body = notification.getBody(); + String cursorName = null; + switch (body.toString()) { + case DrawTileTool.NAME: + cursorName = "tile"; + tiledPlugin.facade.sendNotification(TiledPlugin.PANEL_OPEN); + tiledPlugin.facade.sendNotification(MsgAPI.HIDE_GRID); + break; + case DeleteTileTool.NAME: + cursorName = "tile-eraser"; + tiledPlugin.facade.sendNotification(MsgAPI.HIDE_GRID); + break; + default: + tiledPlugin.facade.sendNotification(MsgAPI.SHOW_GRID); + viewComponent.hide(); + break; + } + if (cursorName != null) { + CursorData cursorData = new CursorData(cursorName, 14, 14); + TextureRegion region = tiledPlugin.pluginRM.getTextureRegion(cursorName); + //tiledPlugin.getAPI().setCursor(cursorData, region); + } + break; + case SettingsTab.OK_BTN_CLICKED: + tiledPlugin.dataToSave.setParameterVO(notification.getBody()); + tiledPlugin.saveDataManager.save(); + break; + case TiledPlugin.GRID_CHANGED: + viewComponent.reInitGridSettings(); + tiledPlugin.saveDataManager.save(); + break; + case TiledPlugin.ACTION_SET_GRID_SIZE_FROM_ITEM: + Entity observable = notification.getBody(); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(observable, DimensionsComponent.class); + tiledPlugin.dataToSave.setGrid(dimensionsComponent.width, dimensionsComponent.height); + tiledPlugin.facade.sendNotification(TiledPlugin.GRID_CHANGED); + break; + case MsgAPI.ITEM_DATA_UPDATED: + Entity item = notification.getBody(); + if (tiledPlugin.isTile(item)) { + ComponentRetriever.get(item, MainItemComponent.class).tags.remove(TiledPlugin.TILE_TAG); + } + break; + } + } + + +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPlugin.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPlugin.java new file mode 100644 index 00000000..e4059b7a --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/TiledPlugin.java @@ -0,0 +1,232 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.plugin.tiled; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Array; +import com.kotcrab.vis.ui.VisUI; +import com.kotcrab.vis.ui.widget.VisImageButton; +import games.rednblack.editor.plugin.tiled.data.TileVO; +import games.rednblack.editor.plugin.tiled.manager.ResourcesManager; +import games.rednblack.editor.plugin.tiled.offset.OffsetPanel; +import games.rednblack.editor.plugin.tiled.offset.OffsetPanelMediator; +import games.rednblack.editor.plugin.tiled.save.DataToSave; +import games.rednblack.editor.plugin.tiled.save.SaveDataManager; +import games.rednblack.editor.plugin.tiled.tools.DeleteTileTool; +import games.rednblack.editor.plugin.tiled.tools.DrawTileTool; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.ZIndexComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.renderer.utils.CustomVariables; +import games.rednblack.h2d.common.plugins.H2DPluginAdapter; +import net.mountainblade.modular.annotations.Implementation; + +import java.util.Set; + + +/** + * Created by mariam on 2/2/2016. + */ +@Implementation(authors = "azakhary", version = "0.0.1") +public class TiledPlugin extends H2DPluginAdapter { + + //-------notifications---------// + public static final String CLASS_NAME = "games.rednblack.editor.plugin.tiled"; + public static final String TILE_ADDED = CLASS_NAME + ".TILE_ADDED"; + public static final String TILE_SELECTED = CLASS_NAME + ".TILE_SELECTED"; + public static final String PANEL_OPEN = CLASS_NAME + ".PANEL_OPEN"; + public static final String OPEN_DROP_DOWN = CLASS_NAME + ".OPEN_DROP_DOWN"; + public static final String GRID_CHANGED = CLASS_NAME + ".GRID_CHANGED"; + public static final String ACTION_DELETE_TILE = CLASS_NAME + ".ACTION_DELETE_TILE"; + public static final String ACTION_SET_OFFSET = CLASS_NAME + ".ACTION_SET_OFFSET"; + public static final String ACTION_OPEN_OFFSET_PANEL = CLASS_NAME + ".ACTION_OPEN_OFFSET_PANEL"; + public static final String TILE_GRID_OFFSET_ADDED = CLASS_NAME + ".TILE_GRID_OFFSET_ADDED"; + public static final String ACTION_SET_GRID_SIZE_FROM_ITEM = CLASS_NAME + ".ACTION_SET_GRID_SIZE_FROM_ITEM"; + public static final String ACTION_SET_GRID_SIZE_FROM_LIST = CLASS_NAME + ".ACTION_SET_GRID_SIZE_FROM_LIST"; + //-------end--------// + + public static final String TILE_TAG = "TILE"; + public static final String ROW = "ROW"; + public static final String COLUMN = "COLUMN"; + + public DataToSave dataToSave; + public SaveDataManager saveDataManager; + public boolean isSceneLoaded = false; + public DrawTileTool drawTileTool; + public DeleteTileTool deleteTileTool; + public ResourcesManager pluginRM; + public OffsetPanel offsetPanel; + + private TileVO selectedTileVO; + private CustomVariables currentEntityCustomVariables; + private MainItemComponent currentEntityMainItemComponent; + private TransformComponent currentEntityTransformComponent; + + public TiledPlugin() { + selectedTileVO = new TileVO(); + currentEntityCustomVariables = new CustomVariables(); + } + + @Override + public void initPlugin() { + facade.registerMediator(new TiledPanelMediator(this)); + + pluginRM = new ResourcesManager(this); + offsetPanel = new OffsetPanel(this); + + facade.registerMediator(new OffsetPanelMediator(this)); + + initTools(); + + Skin skin = VisUI.getSkin(); + VisImageButton.VisImageButtonStyle tileAddButtonStyle = new VisImageButton.VisImageButtonStyle(); + tileAddButtonStyle.up = skin.getDrawable("toolbar-normal"); + tileAddButtonStyle.down = skin.getDrawable("toolbar-down"); + tileAddButtonStyle.checked = skin.getDrawable("toolbar-down"); + tileAddButtonStyle.over = skin.getDrawable("toolbar-over"); + tileAddButtonStyle.imageUp = new TextureRegionDrawable(pluginRM.getTextureRegion("tool-tilebrush")); + pluginAPI.addTool(DrawTileTool.NAME, tileAddButtonStyle, true, drawTileTool); + + VisImageButton.VisImageButtonStyle tileDeleteButtonStyle = new VisImageButton.VisImageButtonStyle(); + tileDeleteButtonStyle.up = skin.getDrawable("toolbar-normal"); + tileDeleteButtonStyle.down = skin.getDrawable("toolbar-down"); + tileDeleteButtonStyle.checked = skin.getDrawable("toolbar-down"); + tileDeleteButtonStyle.over = skin.getDrawable("toolbar-over"); + tileDeleteButtonStyle.imageUp = new TextureRegionDrawable(pluginRM.getTextureRegion("tool-tileeraser")); + pluginAPI.addTool(DeleteTileTool.NAME, tileDeleteButtonStyle, false, deleteTileTool); + + pluginAPI.setDropDownItemName(ACTION_SET_GRID_SIZE_FROM_ITEM, "Set tile grid size"); + } + + @Override + public void onDropDownOpen(Set selectedEntities, Array actionsSet) { + if(selectedEntities.size() == 1) { + actionsSet.add(ACTION_SET_GRID_SIZE_FROM_ITEM); + } + } + + public void initSaveData() { + saveDataManager = new SaveDataManager(pluginAPI.getProjectPath()); + dataToSave = saveDataManager.dataToSave; + } + + private void initTools() { + drawTileTool = new DrawTileTool(this); + deleteTileTool = new DeleteTileTool(this); + } + + public Entity getPluginEntityWithParams(int row, int column) { + for (Entity entity : pluginAPI.getProjectEntities()) { + if(!isTile(entity)) continue; + boolean isEntityVisible = pluginAPI.isEntityVisible(entity); + if (!isEntityVisible || !isOnCurrentSelectedLayer(entity)) continue; + + currentEntityMainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + currentEntityCustomVariables = currentEntityMainItemComponent.customVariables; + if (currentEntityCustomVariables.getIntegerVariable(ROW) == row + && currentEntityCustomVariables.getIntegerVariable(COLUMN) == column) { + return entity; + } + } + return null; + } + + public Entity getPluginEntityWithCoords(float x, float y) { + for (Entity entity : pluginAPI.getProjectEntities()) { + if (!isTile(entity)) continue; + boolean isEntityVisible = pluginAPI.isEntityVisible(entity); + if (!isEntityVisible || !isOnCurrentSelectedLayer(entity)) continue; + + currentEntityTransformComponent = ComponentRetriever.get(entity, TransformComponent.class); + Rectangle tmp = new Rectangle( + currentEntityTransformComponent.x, + currentEntityTransformComponent.y, + dataToSave.getParameterVO().gridWidth, + dataToSave.getParameterVO().gridHeight); + + if (tmp.contains(x, y)) { + return entity; + } + } + return null; + } + + public float getPixelToWorld() { + return pluginAPI.getSceneLoader().getRm().getProjectVO().pixelToWorld; + } + + public boolean isTile(Entity entity) { + if (entity == null) + return false; + return ComponentRetriever.get(entity, MainItemComponent.class).tags.contains(TILE_TAG); + } + + public boolean isOnCurrentSelectedLayer(Entity entity) { + ZIndexComponent entityZComponent = ComponentRetriever.get(entity, ZIndexComponent.class); + return entityZComponent.layerName.equals(pluginAPI.getCurrentSelectedLayerName()); + } + + public void setSelectedTileName (String regionName) { + selectedTileVO.regionName = regionName; + } + + public String getSelectedTileName() { + return selectedTileVO.regionName; + } + + public Vector2 getSelectedTileGridOffset() { + return selectedTileVO.gridOffset; + } + + public void setSelectedTileGridOffset (Vector2 gridOffset) { + selectedTileVO.gridOffset = gridOffset; + } + + public TileVO getSelectedTileVO() { + return selectedTileVO; + } + + public void setSelectedTileVO(TileVO selectedTileVO) { + this.selectedTileVO = selectedTileVO; + } + + public void applySelectedTileGridOffset() { + pluginAPI.getProjectEntities().forEach(entity -> { + if (!(isTile(entity))) return; + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + if (selectedTileVO.regionName.equals(textureRegionComponent.regionName)) { + transformComponent.x -= selectedTileVO.gridOffset.x; + transformComponent.y -= selectedTileVO.gridOffset.y; + } + }); + saveOffsetChanges(); + } + + private void saveOffsetChanges() { + dataToSave.setTileGridOffset(selectedTileVO); + saveDataManager.save(); + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/AttributeVO.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/AttributeVO.java new file mode 100644 index 00000000..2fa36482 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/AttributeVO.java @@ -0,0 +1,34 @@ +package games.rednblack.editor.plugin.tiled.data; + +/** + * Created by mariam on 3/31/16. + */ +public class AttributeVO { + + public String title; + public float value; + public boolean acceptNegativeValues; + + public AttributeVO() { + } + + public AttributeVO(String title) { + this.title = title+": "; + } + + public AttributeVO(String title, boolean acceptNegativeValues) { + this.title = title+": "; + this.acceptNegativeValues = acceptNegativeValues; + } + + public AttributeVO(String title, float value) { + this.value = value; + this.title = title+": "; + } + + public AttributeVO(String title, float value, boolean acceptNegativeValues) { + this.title = title+": "; + this.value = value; + this.acceptNegativeValues = acceptNegativeValues; + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/CategoryVO.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/CategoryVO.java new file mode 100644 index 00000000..cbe18491 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/CategoryVO.java @@ -0,0 +1,17 @@ +package games.rednblack.editor.plugin.tiled.data; + +import com.badlogic.gdx.utils.Array; + +/** + * Created by mariam on 2/5/16. + */ +public class CategoryVO { + + public String title = "size"; + public Array attributes; + + public CategoryVO(String title, Array attributes) { + this.title = title; + this.attributes = attributes; + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/ParameterVO.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/ParameterVO.java new file mode 100644 index 00000000..0688bd78 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/ParameterVO.java @@ -0,0 +1,13 @@ +package games.rednblack.editor.plugin.tiled.data; + +/** + * Created by mariam on 3/31/16. + */ +public class ParameterVO { + + public float gridWidth; //in world units + public float gridHeight; //in world units + + public ParameterVO() { + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/TileVO.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/TileVO.java new file mode 100644 index 00000000..66b92a9d --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/data/TileVO.java @@ -0,0 +1,26 @@ +package games.rednblack.editor.plugin.tiled.data; + +import com.badlogic.gdx.math.Vector2; + +/** + * Created by mariam on 5/13/16. + */ +public class TileVO { + + public String regionName = ""; + public Vector2 gridOffset; + + public TileVO() { + gridOffset = new Vector2(); + } + + public TileVO(String regionName) { + this.regionName = regionName; + gridOffset = new Vector2(); + } + + public TileVO(String regionName, Vector2 offset) { + this.regionName = regionName; + this.gridOffset = offset; + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/manager/ResourcesManager.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/manager/ResourcesManager.java new file mode 100644 index 00000000..9abda795 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/manager/ResourcesManager.java @@ -0,0 +1,70 @@ +package games.rednblack.editor.plugin.tiled.manager; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.google.common.io.ByteStreams; +import games.rednblack.editor.plugin.tiled.TiledPlugin; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Created by mariam on 4/21/16. + */ +public class ResourcesManager { + + private final String RESOURCES_FILE_NAME = "tiled"; + + private TiledPlugin tiledPlugin; + private TextureAtlas textureAtlas; + + public ResourcesManager(TiledPlugin tiledPlugin) { + this.tiledPlugin = tiledPlugin; + + init(); + } + + private void init() { + File atlasTempFile = getResourceFileFromJar(".atlas"); + File pngTempFile = getResourceFileFromJar(".png"); + textureAtlas = new TextureAtlas(new FileHandle(atlasTempFile)); + atlasTempFile.deleteOnExit(); + pngTempFile.deleteOnExit(); + } + + private File getResourceFileFromJar(String extension) { + String fileName = "/"+RESOURCES_FILE_NAME+extension; + File tempFile = new File (System.getProperty("user.dir")+fileName); + try { + InputStream in = getClass().getResourceAsStream(fileName); + FileOutputStream out = new FileOutputStream(tempFile); + ByteStreams.copy(in, out); + in.close(); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return tempFile; + } + + public TextureRegion getTextureRegion(String name) { + TextureRegion region = textureAtlas.findRegion(name); // try to get region from plugin assets + if (region != null) { +// System.out.println("region: "+name+", "+region.getRegionWidth()+" "+region.getRegionHeight()); + } + if (region == null) { // take the region from hyperlap assets + region = tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(name); + } + return region; + } + + public NinePatch getPluginNinePatch(String name) { + TextureAtlas.AtlasRegion region = textureAtlas.findRegion(name); + if(region == null) return null; + return new NinePatch(region, region.splits[0], region.splits[1], region.splits[2], region.splits[3]); + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/offset/OffsetPanel.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/offset/OffsetPanel.java new file mode 100644 index 00000000..9736dc8a --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/offset/OffsetPanel.java @@ -0,0 +1,76 @@ +package games.rednblack.editor.plugin.tiled.offset; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.utils.Array; +import com.kotcrab.vis.ui.widget.VisTextButton; +import games.rednblack.editor.plugin.tiled.TiledPlugin; +import games.rednblack.editor.plugin.tiled.data.AttributeVO; +import games.rednblack.editor.plugin.tiled.data.CategoryVO; +import games.rednblack.editor.plugin.tiled.view.Category; +import games.rednblack.h2d.common.UIDraggablePanel; + +/** + * Created by mariam on 5/12/16. + */ +public class OffsetPanel extends UIDraggablePanel { + + private final String TILE_OFFSET_X = "Tile offset x"; + private final String TILE_OFFSET_Y = "Tile offset y"; + + private TiledPlugin tiledPlugin; + private Table mainTable; + private Category offsetCategory; + private AttributeVO offsetAttributeX; + private AttributeVO offsetAttributeY; + + + public OffsetPanel(TiledPlugin tiledPlugin) { + super("Offset"); + + this.tiledPlugin = tiledPlugin; + addCloseButton(); + + mainTable = new Table(); + add(mainTable).pad(3); + + initView(); + } + + private void initView() { + + offsetAttributeX = new AttributeVO(TILE_OFFSET_X, true); + offsetAttributeY = new AttributeVO(TILE_OFFSET_Y, true); + + Array attributeVOs = new Array<>(); + attributeVOs.add(offsetAttributeX); + attributeVOs.add(offsetAttributeY); + offsetCategory = new Category(new CategoryVO("", attributeVOs)); + mainTable.add(offsetCategory) + .pad(7) + .row(); + + VisTextButton addButton = new VisTextButton("Set"); + addButton.addListener(new ClickListener() { + @Override + public void clicked(InputEvent event, float x, float y) { + Vector2 offset = new Vector2(offsetAttributeX.value, offsetAttributeY.value); + tiledPlugin.facade.sendNotification(TiledPlugin.TILE_GRID_OFFSET_ADDED, offset); + super.clicked(event, x, y); + } + }); + mainTable.add(addButton); + } + + public void refreshOffsetValues() { + offsetAttributeX = new AttributeVO(TILE_OFFSET_X, tiledPlugin.getSelectedTileGridOffset().x, true); + offsetAttributeY = new AttributeVO(TILE_OFFSET_Y, tiledPlugin.getSelectedTileGridOffset().y, true); + + Array attributeVOs = new Array<>(); + attributeVOs.add(offsetAttributeX); + attributeVOs.add(offsetAttributeY); + offsetCategory.reInitView(attributeVOs); + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/offset/OffsetPanelMediator.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/offset/OffsetPanelMediator.java new file mode 100644 index 00000000..a1f90a88 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/offset/OffsetPanelMediator.java @@ -0,0 +1,56 @@ +package games.rednblack.editor.plugin.tiled.offset; + +import com.badlogic.gdx.math.Vector2; +import com.puremvc.patterns.mediator.SimpleMediator; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.plugin.tiled.TiledPlugin; + +/** + * Created by mariam on 5/12/16. + */ +public class OffsetPanelMediator extends SimpleMediator { + + private static final String TAG = OffsetPanelMediator.class.getCanonicalName(); + public static final String NAME = TAG; + + private TiledPlugin tiledPlugin; + + + public OffsetPanelMediator(TiledPlugin tiledPlugin) { + super(NAME, tiledPlugin.offsetPanel); + + this.tiledPlugin = tiledPlugin; + } + + @Override + public String[] listNotificationInterests() { + return new String[] { + TiledPlugin.ACTION_OPEN_OFFSET_PANEL, + TiledPlugin.TILE_GRID_OFFSET_ADDED, + TiledPlugin.TILE_SELECTED + }; + } + + @Override + public void handleNotification(Notification notification) { + super.handleNotification(notification); + + switch (notification.getName()) { + case TiledPlugin.ACTION_OPEN_OFFSET_PANEL: + viewComponent.refreshOffsetValues(); + viewComponent.show(tiledPlugin.getAPI().getUIStage()); + break; + case TiledPlugin.TILE_GRID_OFFSET_ADDED: + Vector2 offsetValue = notification.getBody(); + tiledPlugin.setSelectedTileGridOffset(offsetValue); + tiledPlugin.applySelectedTileGridOffset(); + break; + case TiledPlugin.TILE_SELECTED: + if (viewComponent.isOpen) { + viewComponent.refreshOffsetValues(); + } + break; + } + + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/DataToSave.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/DataToSave.java new file mode 100644 index 00000000..539f6ffc --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/DataToSave.java @@ -0,0 +1,81 @@ +package games.rednblack.editor.plugin.tiled.save; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.plugin.tiled.data.ParameterVO; +import games.rednblack.editor.plugin.tiled.data.TileVO; + +import java.util.stream.StreamSupport; + +/** + * Created by mariam on 3/23/16. + */ +public class DataToSave { + + private Array tiles; + private ParameterVO parameterVO; + + public DataToSave() { + tiles = new Array<>(); + parameterVO = new ParameterVO(); + } + + public void addTile(String tileDrawableName) { + TileVO newTile = new TileVO(tileDrawableName); + if (!tiles.contains(newTile, false)) { + tiles.add(newTile); + } + } + + public void removeTile(String tileDrawableName) { + tiles.forEach(tile -> { + if (tile.regionName.equals(tileDrawableName)) { + tiles.removeValue(tile, false); + } + }); + + } + + public void setTileGridOffset(TileVO tileVO) { + StreamSupport.stream(tiles.spliterator(), false) + .filter(tile -> tile.regionName.equals(tileVO.regionName)) + .findFirst() + .ifPresent(t -> t.gridOffset = tileVO.gridOffset); + } + + public Vector2 getTileGridOffset(String regionName) { + return StreamSupport.stream(tiles.spliterator(), false) + .filter(tile -> tile.regionName.equals(regionName)) + .findFirst() + .get() + .gridOffset; + } + + public TileVO getTile(String regionName) { + return StreamSupport.stream(tiles.spliterator(), false) + .filter(tile -> tile.regionName.equals(regionName)) + .findFirst() + .get(); + } + + public Array getTiles() { + return tiles; + } + + public boolean containsTile(String regionName) { + return StreamSupport.stream(tiles.spliterator(), false).anyMatch(tile -> tile.regionName.equals(regionName)); + } + + public ParameterVO getParameterVO() { + return parameterVO; + } + + public void setParameterVO(ParameterVO parameterVO) { + this.parameterVO = parameterVO; + } + + public void setGrid(float gridWidth, float gridHeight) { + parameterVO.gridWidth = gridWidth; + parameterVO.gridHeight = gridHeight; + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/SaveDataManager.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/SaveDataManager.java new file mode 100644 index 00000000..d1f9429e --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/save/SaveDataManager.java @@ -0,0 +1,38 @@ +package games.rednblack.editor.plugin.tiled.save; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Json; + +/** + * Created by mariam on 3/24/16. + */ +public class SaveDataManager { + + public DataToSave dataToSave; + + private Json json; + private FileHandle fileHandle; + + + public SaveDataManager(String projectPath) { + json = new Json(); + fileHandle = Gdx.files.absolute(projectPath + "/tiled_plugin.dt"); + load(); + } + + private void load() { + if (!fileHandle.exists()) { + dataToSave = new DataToSave(); + return; + } + + String jsonString = fileHandle.readString(); + dataToSave = json.fromJson(DataToSave.class, jsonString); + } + + public void save() { + String dataString = json.toJson(dataToSave); + fileHandle.writeString(dataString, false); + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DeleteTileTool.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DeleteTileTool.java new file mode 100644 index 00000000..933757d2 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DeleteTileTool.java @@ -0,0 +1,127 @@ +package games.rednblack.editor.plugin.tiled.tools; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.Input; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.plugin.tiled.TiledPlugin; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.h2d.common.view.tools.Tool; + +/** + * Created by mariam on 4/5/16. + */ +public class DeleteTileTool implements Tool { + + public static final String NAME = "TILE_DELETE_TOOL"; + + private TiledPlugin tiledPlugin; + + private boolean isHotswapped = false; + + public DeleteTileTool(TiledPlugin tiledPlugin) { + this.tiledPlugin = tiledPlugin; + } + + @Override + public void initTool() { + } + + @Override + public String getShortcut() { + return null; + } + + @Override + public String getTitle() { + return "Delete Tile Tool"; + } + + @Override + public boolean stageMouseDown(float x, float y) { + return true; + } + + @Override + public void stageMouseUp(float x, float y) { + } + + @Override + public void stageMouseDragged(float x, float y) { + deleteEntityWithCoordinate(x, y); + } + + @Override + public void stageMouseDoubleClick(float x, float y) { + + } + + @Override + public void stageMouseScrolled(int amount) { + + } + + @Override + public boolean itemMouseDown(Entity entity, float x, float y) { + deleteEntityWithCoordinate(x, y); + return true; + } + + @Override + public void itemMouseUp(Entity entity, float x, float y) { + + } + + @Override + public void itemMouseDragged(Entity entity, float x, float y) { + deleteEntityWithCoordinate(x, y); + } + + @Override + public void itemMouseDoubleClick(Entity entity, float x, float y) { + + } + + @Override + public String getName() { + return NAME; + } + + @Override + public void handleNotification(Notification notification) { + + } + + @Override + public void keyDown(Entity entity, int keycode) { + + } + + @Override + public void keyUp(Entity entity, int keycode) { + if(isHotswapped) { + if(keycode == Input.Keys.SHIFT_LEFT) { + isHotswapped = false; + tiledPlugin.getAPI().toolHotSwapBack(); + } + } + } + + private void deleteEntity(Entity entity) { + if (tiledPlugin.isTile(entity) && tiledPlugin.isOnCurrentSelectedLayer(entity)) { + tiledPlugin.getAPI().removeFollower(entity); + tiledPlugin.getAPI().getEngine().removeEntity(entity); + tiledPlugin.facade.sendNotification(MsgAPI.DELETE_ITEMS_COMMAND_DONE); + } + } + + private void deleteEntityWithCoordinate (float x, float y) { + Entity entity = tiledPlugin.getPluginEntityWithCoords(x, y); + if (entity != null) { + deleteEntity(entity); + } + } + + public void setHotSwapped() { + isHotswapped = true; + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DrawTileTool.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DrawTileTool.java new file mode 100644 index 00000000..9a346129 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/tools/DrawTileTool.java @@ -0,0 +1,197 @@ +package games.rednblack.editor.plugin.tiled.tools; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Vector2; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.plugin.tiled.TiledPlugin; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.h2d.common.view.tools.Tool; + +/** + * Created by mariam on 3/29/16. + */ +public class DrawTileTool implements Tool { + + public static final String NAME = "TILE_ADD_TOOL"; + + private TiledPlugin tiledPlugin; + private float gridWidth; + private float gridHeight; + + public DrawTileTool(TiledPlugin tiledPlugin) { + this.tiledPlugin = tiledPlugin; + } + + @Override + public void initTool() { + + } + + @Override + public String getShortcut() { + return null; + } + + @Override + public String getTitle() { + return "Draw Tile Tool"; + } + + @Override + public boolean stageMouseDown(float x, float y) { + initGridThings(); + drawImage(x, y); + return true; + } + + @Override + public void stageMouseUp(float x, float y) { + } + + @Override + public void stageMouseDragged(float x, float y) { + drawImage(x, y); + } + + @Override + public void stageMouseDoubleClick(float x, float y) { + + } + + @Override + public void stageMouseScrolled(int amount) { + + } + + @Override + public boolean itemMouseDown(Entity entity, float x, float y) { + initGridThings(); + drawOnEntity(entity, x, y); + return true; + } + + @Override + public void itemMouseUp(Entity entity, float x, float y) { + } + + @Override + public void itemMouseDragged(Entity entity, float x, float y) { + drawImage(x, y); + } + + @Override + public void itemMouseDoubleClick(Entity entity, float x, float y) { + if (!tiledPlugin.isOnCurrentSelectedLayer(entity)) return; + if (entity != null) { + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + // there is already other tile under this one + if (textureRegionComponent.regionName.equals(tiledPlugin.getSelectedTileName())) { + //rotate + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + if (transformComponent.scaleX > 0 && transformComponent.scaleY > 0) { + transformComponent.scaleX *= -1f; + return; + } + if (transformComponent.scaleX < 0 && transformComponent.scaleY > 0) { + transformComponent.scaleY *= -1f; + return; + } + if (transformComponent.scaleX < 0 && transformComponent.scaleY < 0) { + transformComponent.scaleX *= -1f; + return; + } + if (transformComponent.scaleX > 0 && transformComponent.scaleY < 0) { + transformComponent.scaleY *= -1f; + return; + } + } + } + } + + @Override + public String getName() { + return NAME; + } + + @Override + public void handleNotification(Notification notification) { + + } + + @Override + public void keyDown(Entity entity, int keycode) { + if(keycode == Input.Keys.SHIFT_LEFT) { + tiledPlugin.getAPI().toolHotSwap(tiledPlugin.deleteTileTool); + tiledPlugin.deleteTileTool.setHotSwapped(); + } + } + + @Override + public void keyUp(Entity entity, int keycode) { + + } + + private void initGridThings() { + gridWidth = tiledPlugin.dataToSave.getParameterVO().gridWidth; + gridHeight = tiledPlugin.dataToSave.getParameterVO().gridHeight; + } + + private void drawImage(float x, float y) { + if (tiledPlugin.getSelectedTileName().equals("")) return; + + float newX = MathUtils.floor(x / gridWidth) * gridWidth + tiledPlugin.getSelectedTileGridOffset().x; + float newY = MathUtils.floor(y / gridHeight) * gridHeight + tiledPlugin.getSelectedTileGridOffset().y; + int row = MathUtils.floor(newY / gridHeight); + int column = MathUtils.round(newX / gridWidth); + + Entity underneathTile = tiledPlugin.getPluginEntityWithParams(row, column); + if (underneathTile != null) { + updateRegion(underneathTile, tiledPlugin.getSelectedTileName()); + return; + } + + Entity imageEntity = tiledPlugin.getAPI().drawImage(tiledPlugin.getSelectedTileName(), new Vector2(newX, newY)); + MainItemComponent mainItemComponent = ComponentRetriever.get(imageEntity, MainItemComponent.class); + mainItemComponent.tags.add(TiledPlugin.TILE_TAG); + + mainItemComponent.setCustomVars(TiledPlugin.ROW, Integer.toString(row)); + mainItemComponent.setCustomVars(TiledPlugin.COLUMN, Integer.toString(column)); + } + + private void drawOnEntity(Entity entity, float x, float y) { + if (!tiledPlugin.isOnCurrentSelectedLayer(entity)) return; + if (entity != null) { + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + if (textureRegionComponent != null && textureRegionComponent.regionName != null) { + // there is already other tile under this one + if(textureRegionComponent.regionName.equals(tiledPlugin.getSelectedTileName())) { + return; + } else { + //replace + updateRegion(entity, tiledPlugin.getSelectedTileName()); + } + } + return; + } + drawImage(x, y); + } + + private void updateRegion(Entity entity, String region) { + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + DimensionsComponent size = ComponentRetriever.get(entity, DimensionsComponent.class); + textureRegionComponent.regionName = tiledPlugin.getSelectedTileName(); + textureRegionComponent.region = tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(region); + ProjectInfoVO projectInfoVO = tiledPlugin.getAPI().getSceneLoader().getRm().getProjectVO(); + float ppwu = projectInfoVO.pixelToWorld; + size.width = textureRegionComponent.region.getRegionWidth() / ppwu; + size.height = textureRegionComponent.region.getRegionHeight() / ppwu; + } + +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/Attribute.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/Attribute.java new file mode 100644 index 00000000..bc4adc63 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/Attribute.java @@ -0,0 +1,29 @@ +package games.rednblack.editor.plugin.tiled.view; + +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.kotcrab.vis.ui.util.FloatDigitsOnlyFilter; +import com.kotcrab.vis.ui.widget.VisLabel; +import com.kotcrab.vis.ui.widget.VisTextField; +import games.rednblack.editor.plugin.tiled.data.AttributeVO; + +/** + * Created by mariam on 2/5/16. + */ +public class Attribute extends Table { + + public Attribute(AttributeVO attributeVO) { + add(new VisLabel(attributeVO.title)); + VisTextField visTextField = new VisTextField(); + visTextField.setTextFieldFilter(new FloatDigitsOnlyFilter(attributeVO.acceptNegativeValues)); + visTextField.setMaxLength(5); + visTextField.setText(attributeVO.value+""); + visTextField.setTextFieldListener((VisTextField textField, char c) -> { + if (!textField.getText().equals("")) { + attributeVO.value = Float.parseFloat(textField.getText()); + } + }); + add(visTextField) + .width(50) + .padLeft(5); + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/Category.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/Category.java new file mode 100644 index 00000000..f7563b70 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/Category.java @@ -0,0 +1,62 @@ +package games.rednblack.editor.plugin.tiled.view; + +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.utils.Array; +import com.kotcrab.vis.ui.widget.VisLabel; +import games.rednblack.editor.plugin.tiled.data.AttributeVO; +import games.rednblack.editor.plugin.tiled.data.CategoryVO; + +/** + * Created by mariam on 2/5/16. + */ +public class Category extends Table { + + private CategoryVO categoryVO; + private Array attributes; + private Table attrTable; + + public Category(CategoryVO categoryVO) { + this.categoryVO = categoryVO; + + attributes = categoryVO.attributes; + +// setDebug(true); + + VisLabel title = new VisLabel(categoryVO.title); + add(title) + .padTop(2) + .left() + .top(); + + attrTable = new Table(); + add(attrTable) + .padLeft(5); + + attributes.forEach(attributeVO -> addAttribute(attributeVO)); + } + + public void reInitView(Array attributes) { + attrTable.clear(); + this.attributes = attributes; + attributes.forEach(attributeVO -> addAttribute(attributeVO)); + attrTable.pack(); + } + + private void addAttribute(AttributeVO attributeVO) { + Attribute attr = new Attribute(attributeVO); + attrTable.add(attr) + .top() + .right() + .padBottom(5) + .row(); + } + + public AttributeVO getAttributeVO(String title) { + for (AttributeVO attributeVO : attributes) { + if (attributeVO.title.equals(title)) { + return attributeVO; + } + } + return new AttributeVO(); + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/DefaultTab.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/DefaultTab.java new file mode 100644 index 00000000..4a9777a6 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/DefaultTab.java @@ -0,0 +1,42 @@ +package games.rednblack.editor.plugin.tiled.view.tabs; + +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.kotcrab.vis.ui.widget.VisLabel; +import com.kotcrab.vis.ui.widget.tabbedpane.Tab; +import games.rednblack.editor.plugin.tiled.TiledPanel; + +/** + * Created by mariam on 10/30/15. + */ +public class DefaultTab extends Tab { + + protected TiledPanel panel; + protected int tabIndex; + protected Table content = new Table(); + protected String tabTitle = ""; + + public DefaultTab(TiledPanel panel, String tabTitle, int tabIndex) { + super(false, false); //tab is not savable, tab is not closeable by user + this.panel = panel; + this.tabTitle = tabTitle; + this.tabIndex = tabIndex; + } + + public void initView() { + content.add(new VisLabel(tabTitle+" example")); + } + + @Override + public String getTabTitle () { + return tabTitle; + } + + @Override + public Table getContentTable () { + return content; + } + + public int getTabIndex() { + return tabIndex; + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/GridTilesTab.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/GridTilesTab.java new file mode 100644 index 00000000..514ca25e --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/GridTilesTab.java @@ -0,0 +1,202 @@ +package games.rednblack.editor.plugin.tiled.view.tabs; + +import com.badlogic.gdx.Input; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputListener; +import com.badlogic.gdx.scenes.scene2d.utils.Drawable; +import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable; +import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; +import com.badlogic.gdx.utils.Array; +import com.kotcrab.vis.ui.widget.VisImageButton; +import com.kotcrab.vis.ui.widget.VisLabel; +import com.kotcrab.vis.ui.widget.VisScrollPane; +import com.kotcrab.vis.ui.widget.VisTable; +import games.rednblack.editor.plugin.tiled.TiledPanel; +import games.rednblack.editor.plugin.tiled.TiledPlugin; +import games.rednblack.editor.plugin.tiled.data.TileVO; +import games.rednblack.editor.plugin.tiled.manager.ResourcesManager; + +/** + * Created by mariam on 2/11/16. + */ +public class GridTilesTab extends DefaultTab { + + public static boolean isDrop; + + private int tilesCount = 19; + private Array tiles; + private Array savedTiles; + private int tileIndex; + private VisScrollPane pane; + private boolean isBottomEdge; + + private TiledPlugin tiledPlugin; + private ResourcesManager resourcesManager; + + public GridTilesTab(TiledPanel panel, int tabIndex) { + super(panel, "Tiles", tabIndex); + + tiledPlugin = panel.tiledPlugin; + resourcesManager = tiledPlugin.pluginRM; + tiles = new Array<>(); + savedTiles = tiledPlugin.dataToSave.getTiles(); + tileIndex = savedTiles.size; + } + + @Override + public void initView() { + if (isDrop = savedTiles.size == 0) { + VisImageButton.VisImageButtonStyle dropBoxStyle = new VisImageButton.VisImageButtonStyle(); + dropBoxStyle.up = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-normal")); + dropBoxStyle.imageOver = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-over")); + VisImageButton dropRegion = new VisImageButton(dropBoxStyle); + content.clear(); + content.add(dropRegion) + .center() + .padRight(6) + .padBottom(6) + .padTop(10) + .row(); + content.add(new VisLabel("Drop an image from resources box")) + .expandX() + .center() + .padBottom(5); + content.pack(); + } else { + if (tileIndex > tilesCount) { + tilesCount = tileIndex; + } + initTiles(); + } + } + + public void addTile(String tileName) { + if (pane != null) isBottomEdge = pane.isBottomEdge(); + if (tileIndex == 0) { + setGridSizeToFirstTileSize(tileName); + isDrop = false; + panel.reInitTabTable(); + } + initTiles(tileName); + panel.pack(); + scrollTiles(); + tiles.get(tileIndex).setChecked(true); + tiledPlugin.facade.sendNotification(TiledPlugin.TILE_SELECTED, new TileVO(tileName)); + tileIndex++; + } + + public void selectTile(TileVO tileVO) { + tiledPlugin.setSelectedTileVO(tileVO); + } + + public void removeTile() { + if (pane != null) isBottomEdge = pane.isBottomEdge(); + tileIndex = --tileIndex < 0 ? 0 : tileIndex; + tilesCount = --tilesCount < 19 ? 19 : tilesCount; + tiles.clear(); + initView(); + } + + public void scrollTiles() { + if(savedTiles.size + 1 >= tilesCount) { + pane.layout(); + pane.setSmoothScrolling(!isBottomEdge); + pane.setScrollY(100); + } + } + + private void setGridSizeToFirstTileSize(String tileName) { + float gridWidth = resourcesManager.getTextureRegion(tileName).getRegionWidth() / tiledPlugin.getPixelToWorld(); + float gridHeight = resourcesManager.getTextureRegion(tileName).getRegionHeight() / tiledPlugin.getPixelToWorld(); + tiledPlugin.dataToSave.setGrid(gridWidth, gridHeight); + tiledPlugin.facade.sendNotification(TiledPlugin.GRID_CHANGED); + } + + private void initTiles(String tileName) { + content.clear(); + tiles.clear(); + + VisTable listTable = new VisTable(); + pane = new VisScrollPane(listTable); + content.add(pane) + .padTop(10); + listTable.top(); + + if(tileIndex >= tilesCount && !tileName.equals("")) { + tilesCount = tileIndex + 1; + } + + for (int i=0; i= savedTiles.size) return true; + + for (VisImageButton tile : tiles) { + if (tile.isChecked()) { + tile.setChecked(false); + } + } + + return true; + } + + @Override + public void touchUp(InputEvent event, float x, float y, int pointer, int button) { + super.touchUp(event, x, y, pointer, button); + + if(button == Input.Buttons.RIGHT) { + tiledPlugin.facade.sendNotification(TiledPlugin.OPEN_DROP_DOWN, savedTiles.get(index).regionName); + return; + } + + if (index >= savedTiles.size) { + tiles.get(index).setChecked(false); + return; + } + + tiledPlugin.facade.sendNotification(TiledPlugin.TILE_SELECTED, savedTiles.get(index)); + } + }); + listTable.add(ct) + .width(40) + .height(40) + .pad(3); + if((i+1) % 4 == 0) { + listTable.row(); + } + tiles.add(ct); + } + + content.pack(); + } + + private void initTiles() { + initTiles(""); + } +} diff --git a/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/SettingsTab.java b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/SettingsTab.java new file mode 100644 index 00000000..3abd4d95 --- /dev/null +++ b/plugin-tiled/src/main/java/games/rednblack/editor/plugin/tiled/view/tabs/SettingsTab.java @@ -0,0 +1,74 @@ +package games.rednblack.editor.plugin.tiled.view.tabs; + +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.utils.Array; +import com.kotcrab.vis.ui.widget.VisTextButton; +import games.rednblack.editor.plugin.tiled.TiledPanel; +import games.rednblack.editor.plugin.tiled.data.AttributeVO; +import games.rednblack.editor.plugin.tiled.data.CategoryVO; +import games.rednblack.editor.plugin.tiled.data.ParameterVO; +import games.rednblack.editor.plugin.tiled.view.Category; + +/** + * Created by mariam on 2/4/16. + */ +public class SettingsTab extends DefaultTab { + + private static final String CLASS_NAME = "com.overlap2d.plugins.tiled.view.tabs.SettingsTab"; + public static final String OK_BTN_CLICKED = CLASS_NAME+".OK_BTN_CLICKED"; + + private ParameterVO currentParameters; + private Category grid; + + public SettingsTab(TiledPanel panel, String tabTitle, int tabIndex) { + super(panel, tabTitle, tabIndex); + + currentParameters = panel.tiledPlugin.dataToSave.getParameterVO(); + } + + @Override + public void initView() { + Array gridAttributes = new Array<>(); + gridAttributes.add(new AttributeVO("Width", currentParameters.gridWidth)); + gridAttributes.add(new AttributeVO("Height", currentParameters.gridHeight)); + CategoryVO gridVO = new CategoryVO("Grid size: ", gridAttributes); + grid = new Category(gridVO); + content.add(grid) + .expandX() + .colspan(2) + .padTop(10) + .left() + .top() + .row(); + panel.tiledPlugin.dataToSave.setParameterVO(currentParameters); + + VisTextButton okBtn = new VisTextButton("Save"); + content.add(okBtn) + .width(70) + .pad(20) + .colspan(2) + .expandX() + .center() + .bottom() + .row(); + + okBtn.addListener(new ClickListener() { + @Override + public void clicked(InputEvent event, float x, float y) { + super.clicked(event, x, y); + + currentParameters.gridWidth = grid.getAttributeVO("Width: ").value; + currentParameters.gridHeight = grid.getAttributeVO("Height: ").value; + panel.facade.sendNotification(OK_BTN_CLICKED, currentParameters); + } + }); + } + + public void resetGridCategory() { + Array gridAttributes = new Array<>(); + gridAttributes.add(new AttributeVO("Width", currentParameters.gridWidth)); + gridAttributes.add(new AttributeVO("Height", currentParameters.gridHeight)); + grid.reInitView(gridAttributes); + } +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..e9c20eac --- /dev/null +++ b/settings.gradle @@ -0,0 +1,8 @@ +rootProject.name = 'HyperLap2D' +include 'hyperlap2d-runtime-libgdx' +include 'h2d-libgdx-spine-extension' +include 'hyperlap2d-common-api' +include 'plugin-performance' +include 'plugin-9patch' +include 'plugin-tiled' + diff --git a/src/main/java/games/rednblack/editor/CustomExceptionHandler.java b/src/main/java/games/rednblack/editor/CustomExceptionHandler.java new file mode 100644 index 00000000..36d43e78 --- /dev/null +++ b/src/main/java/games/rednblack/editor/CustomExceptionHandler.java @@ -0,0 +1,126 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor; + +import java.awt.EventQueue; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.Thread.UncaughtExceptionHandler; +import java.util.HashMap; + +import javax.swing.JOptionPane; + +import org.apache.commons.lang3.SystemUtils; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Net.HttpMethods; +import com.badlogic.gdx.Net.HttpRequest; +import com.badlogic.gdx.Net.HttpResponse; +import com.badlogic.gdx.Net.HttpResponseListener; +import com.badlogic.gdx.net.HttpParametersUtils; +import games.rednblack.editor.utils.AppConfig; + + +public class CustomExceptionHandler implements UncaughtExceptionHandler { + + //private UncaughtExceptionHandler defaultUEH; + private final static String sendURL = "https://hyperlap.rednblack.games/error_report"; + + /* + * if any of the parameters is null, the respective functionality + * will not be used + */ + public CustomExceptionHandler() { + //this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); + } + + public static void showErrorDialog() { + new Thread(new Runnable() { + public void run() { + EventQueue.invokeLater(new Runnable() { + + @Override + public void run() { + JOptionPane.showMessageDialog(null, "HyperLap2D just crashed, see stacktrace in hyperlog.txt file", "Error", JOptionPane.ERROR_MESSAGE); + } + + }); + } + }).start(); + } + + public static void sendError(String stacktrace) { + HashMap parameters = new HashMap(); + parameters.put("error", stacktrace); + parameters.put("system", SystemUtils.OS_NAME + " " + SystemUtils.OS_VERSION); + parameters.put("version", AppConfig.getInstance().version); + HttpRequest httpGet = new HttpRequest(HttpMethods.GET); + httpGet.setUrl(sendURL); + httpGet.setContent(HttpParametersUtils.convertHttpParameters(parameters)); + Gdx.net.sendHttpRequest(httpGet, new HttpResponseListener() { + public void handleHttpResponse(HttpResponse httpResponse) { + //showErrorDialog(); + } + + public void failed(Throwable t) { + + } + + @Override + public void cancelled() { + + } + }); + + + } + + public void uncaughtException(Thread t, Throwable e) { + final Writer result = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(result); + e.printStackTrace(printWriter); + String stacktrace = result.toString(); + String filename = "hyperlog.txt"; + writeToFile(stacktrace, filename); + printWriter.close(); + + sendError(stacktrace); + + showErrorDialog(); + //defaultUEH.uncaughtException(t, e); + } + + private void writeToFile(String stacktrace, String filename) { + try { + //String localPath = DataManager.getMyDocumentsLocation(); + String localPath = "";//DataManager.getInstance().getRootPath(); + System.out.println(localPath + File.separator + filename); + BufferedWriter bos = new BufferedWriter(new FileWriter(localPath + File.separator + filename)); + bos.write(stacktrace); + bos.flush(); + bos.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/games/rednblack/editor/HyperLap2D.java b/src/main/java/games/rednblack/editor/HyperLap2D.java new file mode 100644 index 00000000..45b81dc1 --- /dev/null +++ b/src/main/java/games/rednblack/editor/HyperLap2D.java @@ -0,0 +1,188 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor; + +import com.badlogic.gdx.ApplicationListener; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.assets.AssetManager; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Graphics; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.utils.Align; +import games.rednblack.editor.proxy.CommandManager; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.splash.SplashScreenAdapter; +import games.rednblack.editor.view.frame.FileDropListener; +import games.rednblack.editor.view.ui.dialog.ImportDialog; +import games.rednblack.h2d.common.MsgAPI; +import com.kotcrab.vis.ui.VisUI; +import com.puremvc.patterns.proxy.Proxy; +import games.rednblack.editor.proxy.EditorTextureManager; +import org.lwjgl.BufferUtils; +import org.lwjgl.PointerBuffer; +import org.lwjgl.glfw.GLFWDropCallback; + +import org.lwjgl.glfw.GLFW; +import org.lwjgl.system.MemoryUtil; + +import java.nio.IntBuffer; + +public class HyperLap2D implements Proxy, ApplicationListener { + private static final String TAG = HyperLap2D.class.getCanonicalName(); + public static final String NAME = TAG; + + public EditorTextureManager textureManager; + private HyperLap2DFacade facade; + private Object data; + private boolean isStartup = false; + private AssetManager assetManager; + + public HyperLap2DFacade getFacade() { + return facade; + } + + private final Sync sync = new Sync(); + + public HyperLap2D() { + } + + @Override + public void create() { + isStartup = false; + assetManager = new AssetManager(); + assetManager.load("style/uiskin.json", Skin.class); + + facade = HyperLap2DFacade.getInstance(); + } + + private void startup() { + isStartup = true; + VisUI.load((Skin) assetManager.get("style/uiskin.json")); + VisUI.setDefaultTitleAlign(Align.center); + + facade.startup(this); + sendNotification(MsgAPI.CREATE); + facade.sendNotification(SplashScreenAdapter.CLOSE_SPLASH, "Initializing..."); + Lwjgl3Graphics graphics = (Lwjgl3Graphics)Gdx.graphics; + GLFW.glfwSetDropCallback(graphics.getWindow().getWindowHandle(), new GLFWDropCallback() { + @Override + public void invoke (long window, int count, long names) { + PointerBuffer nameBuffer = MemoryUtil.memPointerBuffer(names, count); + String[] filesPaths = new String[count]; + for (int i = 0; i < count; i++) { + String pathToObject = MemoryUtil.memUTF8(MemoryUtil.memByteBufferNT1(nameBuffer.get(i))); + filesPaths[i] = pathToObject; + } + + ImportDialog.DropBundle bundle = new ImportDialog.DropBundle(); + bundle.pos = new Vector2(Gdx.input.getX(), Gdx.input.getY()); + bundle.paths = filesPaths; + + facade.sendNotification(FileDropListener.ACTION_DROP, bundle); + } + }); + + IntBuffer w = BufferUtils.createIntBuffer(1); + IntBuffer h = BufferUtils.createIntBuffer(1); + GLFW.glfwGetWindowSize(graphics.getWindow().getWindowHandle(), w, h); + int width = w.get(0); + int height = h.get(0); + + sendNotification(MsgAPI.RESIZE, new int[]{width, height}); + } + + @Override + public void pause() { + sendNotification(MsgAPI.PAUSE); + } + + @Override + public void resume() { + sendNotification(MsgAPI.RESUME); + } + + @Override + public void render() { + if(!isStartup && assetManager.update()) { + startup(); + } else { + sync.sync(60); + sendNotification(MsgAPI.RENDER, Gdx.graphics.getDeltaTime()); + } + } + + @Override + public void resize(int width, int height) { + sendNotification(MsgAPI.RESIZE, new int[]{width, height}); + } + + @Override + public void dispose() { + sendNotification(MsgAPI.DISPOSE); + VisUI.dispose(); + facade.sendNotification(MsgAPI.APP_EXIT); + } + + @Override + public void sendNotification(String notificationName, Object body, String type) { + System.out.println("sendNotification: " + System.currentTimeMillis() + " " + type); + facade.sendNotification(notificationName, body, type); + } + + @Override + public void sendNotification(String notificationName, Object body) { + facade.sendNotification(notificationName, body); + } + + @Override + public void sendNotification(String notificationName) { + facade.sendNotification(notificationName); + } + + @Override + public String getProxyName() { + return NAME; + } + + @Override + public Object getData() { + return data; + } + + @Override + public void setData(Object data) { + this.data = data; + } + + @Override + public void onRegister() { + + } + + @Override + public void onRemove() { + + } + + public boolean hasUnsavedStuff() { + CommandManager commandManager = facade.retrieveProxy(CommandManager.NAME); + return commandManager.isModified(); + } + +} \ No newline at end of file diff --git a/src/main/java/games/rednblack/editor/HyperLap2DApp.java b/src/main/java/games/rednblack/editor/HyperLap2DApp.java new file mode 100644 index 00000000..799803c2 --- /dev/null +++ b/src/main/java/games/rednblack/editor/HyperLap2DApp.java @@ -0,0 +1,117 @@ +package games.rednblack.editor; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Window; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3WindowListener; +import games.rednblack.editor.splash.SplashScreenAdapter; +import games.rednblack.editor.utils.AppConfig; +import games.rednblack.h2d.common.MsgAPI; +import org.apache.commons.lang3.SystemUtils; +import org.lwjgl.glfw.GLFW; + +public class HyperLap2DApp extends ApplicationAdapter { + private static HyperLap2DApp sInstance = null; + + public static HyperLap2DApp initInstance(double width, double height) { + if (sInstance == null) { + sInstance = new HyperLap2DApp(width, height); + } + return sInstance; + } + + public static HyperLap2DApp getInstance() { + return sInstance; + } + + public HyperLap2D hyperlap2D; + public Lwjgl3Window splashWindow, mainWindow; + final private double windowWidth, windowHeight; + + private HyperLap2DApp(double width, double height) { + windowWidth = width; + windowHeight = height; + } + + @Override + public void create() { + Lwjgl3Application app = (Lwjgl3Application) Gdx.app; + + Lwjgl3ApplicationConfiguration config2 = new Lwjgl3ApplicationConfiguration(); + config2.setWindowedMode(467, 415); + config2.setTitle("HyperLap2D"); + config2.setResizable(false); + config2.setDecorated(false); + config2.useVsync(false); + config2.setIdleFPS(60); + config2.setWindowIcon("hyperlap_icon_96.png"); + + splashWindow = app.newWindow(new SplashScreenAdapter(), config2); + + hyperlap2D = new HyperLap2D(); + + Gdx.app.postRunnable(new Runnable() { + @Override + public void run() { + hyperlap2D = new HyperLap2D(); + + Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); + config.setTitle("HyperLap2D - Public Alpha v" + AppConfig.getInstance().version); + config.setResizable(true); + config.setWindowedMode((int) (windowWidth), (int) (windowHeight)); + config.setIdleFPS(60); + config.setInitialVisible(false); + config.setMaximized(true); + config.setWindowIcon("hyperlap_icon_96.png"); + if (SystemUtils.IS_OS_WINDOWS) + config.setWindowPosition(0, (int) (windowHeight * .04)); + + mainWindow = app.newWindow(hyperlap2D, config); + mainWindow.setWindowListener(new Lwjgl3WindowListener() { + @Override + public void created(Lwjgl3Window window) { + + } + + @Override + public void iconified(boolean isIconified) { + + } + + @Override + public void maximized(boolean isMaximized) { + + } + + @Override + public void focusLost() { + + } + + @Override + public void focusGained() { + + } + + @Override + public boolean closeRequested() { + hyperlap2D.sendNotification(MsgAPI.APP_EXIT); + return false; + } + + @Override + public void filesDropped(String[] files) { + + } + + @Override + public void refreshRequested() { + + } + }); + } + }); + } +} diff --git a/src/main/java/games/rednblack/editor/HyperLap2DFacade.java b/src/main/java/games/rednblack/editor/HyperLap2DFacade.java new file mode 100644 index 00000000..b529d94b --- /dev/null +++ b/src/main/java/games/rednblack/editor/HyperLap2DFacade.java @@ -0,0 +1,77 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor; + +import com.puremvc.patterns.facade.SimpleFacade; +import com.puremvc.patterns.observer.BaseNotification; +import games.rednblack.editor.controller.StartupCommand; +import games.rednblack.editor.splash.SplashMediator; + +/** + * Created by sargis on 3/30/15. + */ +public class HyperLap2DFacade extends SimpleFacade { + public static final String STARTUP = "startup"; + private static HyperLap2DFacade instance = null; + private HyperLap2D hyperlap2D; + + protected HyperLap2DFacade() { + super(); + } + + /** + * Facade Singleton Factory method + * + * @return The Singleton instance of the Facade + */ + public synchronized static HyperLap2DFacade getInstance() { + if (instance == null) { + instance = new HyperLap2DFacade(); + instance.registerMediator(new SplashMediator()); + } + return instance; + } + + public void startup(HyperLap2D hyperlap2D) { + this.hyperlap2D = hyperlap2D; + registerProxy(this.hyperlap2D); + notifyObservers(new BaseNotification(STARTUP, null, null)); + } + + @Override + protected void initializeFacade() { + super.initializeFacade(); + } + + @Override + protected void initializeController() { + super.initializeController(); + registerCommand(STARTUP, StartupCommand.class); + } + + @Override + protected void initializeModel() { + super.initializeModel(); + } + + @Override + protected void initializeView() { + super.initializeView(); + } +} diff --git a/src/main/java/games/rednblack/editor/Main.java b/src/main/java/games/rednblack/editor/Main.java new file mode 100644 index 00000000..a76dafcb --- /dev/null +++ b/src/main/java/games/rednblack/editor/Main.java @@ -0,0 +1,42 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor; + +import com.badlogic.gdx.Graphics; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application; +import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration; + +public class Main { + + public static void main(String[] argv) { + Graphics.DisplayMode dm = Lwjgl3ApplicationConfiguration.getDisplayMode(); + + Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); + config.setWindowedMode(467,415); + config.setResizable(false); + config.setDecorated(false); + config.setInitialVisible(false); + config.useVsync(false); + config.setIdleFPS(60); + config.setTitle("HyperLap2D"); + config.setWindowIcon("hyperlap_icon_96.png"); + + new Lwjgl3Application(HyperLap2DApp.initInstance(dm.width, dm.height), config); + } +} diff --git a/src/main/java/games/rednblack/editor/Sync.java b/src/main/java/games/rednblack/editor/Sync.java new file mode 100644 index 00000000..ac198388 --- /dev/null +++ b/src/main/java/games/rednblack/editor/Sync.java @@ -0,0 +1,147 @@ +package games.rednblack.editor; + +import static org.lwjgl.glfw.GLFW.*; + +/** + * A highly accurate sync method that continually adapts to the system + * it runs on to provide reliable results. + * + * @author Riven + * @author kappaOne + */ +public class Sync { + + /** number of nano seconds in a second */ + private static final long NANOS_IN_SECOND = 1000L * 1000L * 1000L; + + /** The time to sleep/yield until the next frame */ + private long nextFrame = 0; + + /** whether the initialisation code has run */ + private boolean initialised = false; + + /** for calculating the averages the previous sleep/yield times are stored */ + private RunningAvg sleepDurations = new RunningAvg(10); + private RunningAvg yieldDurations = new RunningAvg(10); + + public Sync() { + + } + + /** + * An accurate sync method that will attempt to run at a constant frame rate. + * It should be called once every frame. + * + * @param fps - the desired frame rate, in frames per second + */ + public void sync(int fps) { + if (fps <= 0) return; + if (!initialised) initialise(); + + try { + // sleep until the average sleep time is greater than the time remaining till nextFrame + for (long t0 = getTime(), t1; (nextFrame - t0) > sleepDurations.avg(); t0 = t1) { + Thread.sleep(1); + sleepDurations.add((t1 = getTime()) - t0); // update average sleep time + } + + // slowly dampen sleep average if too high to avoid yielding too much + sleepDurations.dampenForLowResTicker(); + + // yield until the average yield time is greater than the time remaining till nextFrame + for (long t0 = getTime(), t1; (nextFrame - t0) > yieldDurations.avg(); t0 = t1) { + Thread.yield(); + yieldDurations.add((t1 = getTime()) - t0); // update average yield time + } + } catch (InterruptedException e) { + + } + + // schedule next frame, drop frame(s) if already too late for next frame + nextFrame = Math.max(nextFrame + NANOS_IN_SECOND / fps, getTime()); + } + + /** + * This method will initialise the sync method by setting initial + * values for sleepDurations/yieldDurations and nextFrame. + * + * If running on windows it will start the sleep timer fix. + */ + private void initialise() { + initialised = true; + + sleepDurations.init(1000 * 1000); + yieldDurations.init((int) (-(getTime() - getTime()) * 1.333)); + + nextFrame = getTime(); + + String osName = System.getProperty("os.name"); + + if (osName.startsWith("Win")) { + // On windows the sleep functions can be highly inaccurate by + // over 10ms making in unusable. However it can be forced to + // be a bit more accurate by running a separate sleeping daemon + // thread. + Thread timerAccuracyThread = new Thread(new Runnable() { + public void run() { + try { + Thread.sleep(Long.MAX_VALUE); + } catch (Exception e) {} + } + }); + + timerAccuracyThread.setName("LWJGL3 Timer"); + timerAccuracyThread.setDaemon(true); + timerAccuracyThread.start(); + } + } + + /** + * Get the system time in nano seconds + * + * @return will return the current time in nano's + */ + private long getTime() { + return (long)(glfwGetTime() * NANOS_IN_SECOND); + } + + private class RunningAvg { + private final long[] slots; + private int offset; + + private static final long DAMPEN_THRESHOLD = 10 * 1000L * 1000L; // 10ms + private static final float DAMPEN_FACTOR = 0.9f; // don't change: 0.9f is exactly right! + + public RunningAvg(int slotCount) { + this.slots = new long[slotCount]; + this.offset = 0; + } + + public void init(long value) { + while (this.offset < this.slots.length) { + this.slots[this.offset++] = value; + } + } + + public void add(long value) { + this.slots[this.offset++ % this.slots.length] = value; + this.offset %= this.slots.length; + } + + public long avg() { + long sum = 0; + for (int i = 0; i < this.slots.length; i++) { + sum += this.slots[i]; + } + return sum / this.slots.length; + } + + public void dampenForLowResTicker() { + if (this.avg() > DAMPEN_THRESHOLD) { + for (int i = 0; i < this.slots.length; i++) { + this.slots[i] *= DAMPEN_FACTOR; + } + } + } + } +} diff --git a/src/main/java/games/rednblack/editor/controller/BootstrapCommand.java b/src/main/java/games/rednblack/editor/controller/BootstrapCommand.java new file mode 100644 index 00000000..01b0dadb --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/BootstrapCommand.java @@ -0,0 +1,93 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller; + +import games.rednblack.editor.controller.commands.component.*; +import games.rednblack.editor.splash.SplashScreenAdapter; +import games.rednblack.h2d.common.MsgAPI; +import com.puremvc.patterns.command.SimpleCommand; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.*; +import games.rednblack.editor.controller.commands.resource.*; + +/** + * Created by azakhary on 4/28/2015. + */ +public class BootstrapCommand extends SimpleCommand { + + public void execute(Notification notification) { + super.execute(notification); + facade = HyperLap2DFacade.getInstance(); + facade.sendNotification(SplashScreenAdapter.UPDATE_SPLASH, "Loading Commands..."); + + facade.registerCommand(MsgAPI.ACTION_CUT, CutItemsCommand.class); + facade.registerCommand(MsgAPI.ACTION_COPY, CopyItemsCommand.class); + facade.registerCommand(MsgAPI.ACTION_PASTE, PasteItemsCommand.class); + facade.registerCommand(MsgAPI.ACTION_DELETE, DeleteItemsCommand.class); + facade.registerCommand(MsgAPI.ACTION_CREATE_ITEM, CreateItemCommand.class); + facade.registerCommand(MsgAPI.ACTION_CAMERA_CHANGE_COMPOSITE, CompositeCameraChangeCommand.class); + facade.registerCommand(MsgAPI.ACTION_CREATE_PRIMITIVE, CreatePrimitiveCommand.class); + + facade.registerCommand(MsgAPI.ACTION_DELETE_LAYER, DeleteLayerCommand.class); + facade.registerCommand(MsgAPI.ACTION_NEW_LAYER, NewLayerCommand.class); + facade.registerCommand(MsgAPI.ACTION_SWAP_LAYERS, LayerSwapCommand.class); + facade.registerCommand(MsgAPI.ACTION_RENAME_LAYER, RenameLayerCommand.class); + + facade.registerCommand(MsgAPI.ACTION_ADD_COMPONENT, AddComponentToItemCommand.class); + facade.registerCommand(MsgAPI.ACTION_REMOVE_COMPONENT, RemoveComponentFromItemCommand.class); + facade.registerCommand(MsgAPI.CUSTOM_VARIABLE_MODIFY, CustomVariableModifyCommand.class); + + facade.registerCommand(MsgAPI.ACTION_ITEMS_MOVE_TO, ItemsMoveCommand.class); + + facade.registerCommand(MsgAPI.ACTION_ITEM_AND_CHILDREN_TO, ItemChildrenTransformCommand.class); + + facade.registerCommand(MsgAPI.ACTION_ITEM_TRANSFORM_TO, ItemTransformCommand.class); + facade.registerCommand(MsgAPI.ACTION_ADD_TO_LIBRARY, AddToLibraryCommand.class); + facade.registerCommand(MsgAPI.ACTION_CONVERT_TO_BUTTON, ConvertToButtonCommand.class); + facade.registerCommand(MsgAPI.ACTION_GROUP_ITEMS, ConvertToCompositeCommand.class); + + facade.registerCommand(MsgAPI.ACTION_SET_SELECTION, SetSelectionCommand.class); + facade.registerCommand(MsgAPI.ACTION_ADD_SELECTION, AddSelectionCommand.class); + facade.registerCommand(MsgAPI.ACTION_RELEASE_SELECTION, ReleaseSelectionCommand.class); + + facade.registerCommand(MsgAPI.ACTION_UPDATE_RULER_POSITION, ChangeRulerPositionCommand.class); + // DATA MODIFY by components + facade.registerCommand(MsgAPI.ACTION_UPDATE_ITEM_DATA, UpdateEntityComponentsCommand.class); + facade.registerCommand(MsgAPI.ACTION_UPDATE_LABEL_DATA, UpdateLabelDataCommand.class); + facade.registerCommand(MsgAPI.ACTION_UPDATE_LIGHT_DATA, UpdateLightDataCommand.class); + facade.registerCommand(MsgAPI.ACTION_UPDATE_BODY_LIGHT_DATA, UpdateLightBodyDataCommand.class); + facade.registerCommand(MsgAPI.ACTION_UPDATE_SPRITE_ANIMATION_DATA, UpdateSpriteAnimationDataCommand.class); + + facade.registerCommand(MsgAPI.ACTION_UPDATE_MESH_DATA, UpdatePolygonComponentCommand.class); + + facade.registerCommand(MsgAPI.ACTION_EXPORT_PROJECT, ExportProjectCommand.class); + facade.registerCommand(MsgAPI.SAVE_EXPORT_PATH, SaveExportPathCommand.class); + + facade.registerCommand(MsgAPI.ACTION_PLUGIN_PROXY_COMMAND, PluginItemCommand.class); + + // Resources + facade.registerCommand(MsgAPI.ACTION_DELETE_IMAGE_RESOURCE, DeleteImageResource.class); + facade.registerCommand(MsgAPI.ACTION_DELETE_LIBRARY_ITEM, DeleteLibraryItem.class); + facade.registerCommand(MsgAPI.ACTION_DELETE_PARTICLE_EFFECT, DeleteParticleEffect.class); + facade.registerCommand(MsgAPI.ACTION_DELETE_SPINE_ANIMATION_RESOURCE, DeleteSpineAnimation.class); + facade.registerCommand(MsgAPI.ACTION_DELETE_SPRITE_ANIMATION_RESOURCE, DeleteSpriteAnimation.class); + facade.registerCommand(MsgAPI.ACTION_DELETE_SPRITER_ANIMATION_RESOURCE, DeleteSpriterAnimation.class); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/BootstrapPlugins.java b/src/main/java/games/rednblack/editor/controller/BootstrapPlugins.java new file mode 100644 index 00000000..f1bfa6a5 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/BootstrapPlugins.java @@ -0,0 +1,68 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller; + +import games.rednblack.editor.splash.SplashScreenAdapter; +import games.rednblack.h2d.common.plugins.H2DPlugin; +import com.puremvc.patterns.command.SimpleCommand; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.proxy.PluginManager; +import games.rednblack.editor.proxy.ProjectManager; +import net.mountainblade.modular.Module; +import net.mountainblade.modular.ModuleManager; +import net.mountainblade.modular.impl.DefaultModuleManager; + +import java.io.File; +import java.util.Collection; + + +/** + * Created by azakhary on 7/24/2015. + */ +public class BootstrapPlugins extends SimpleCommand { + + public void execute(Notification notification) { + super.execute(notification); + facade = HyperLap2DFacade.getInstance(); + + facade.sendNotification(SplashScreenAdapter.UPDATE_SPLASH, "Loading Plugins..."); + + PluginManager pluginManager = new PluginManager(); + facade.registerProxy(pluginManager); + + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + File pluginDir = new File(projectManager.getRootPath() + File.separator + "plugins"); + + ModuleManager manager = new DefaultModuleManager(); + Collection loadedPlugins = manager.loadModules(pluginDir); + + pluginManager.setPluginDir(pluginDir.getAbsolutePath()); + System.out.println(pluginDir.getAbsolutePath()); + System.out.println(loadedPlugins.size()); + + for(Module module: loadedPlugins) { + try { + pluginManager.initPlugin((H2DPlugin) module.getClass().newInstance()); + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/games/rednblack/editor/controller/BootstrapProxyCommand.java b/src/main/java/games/rednblack/editor/controller/BootstrapProxyCommand.java new file mode 100644 index 00000000..389b35e1 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/BootstrapProxyCommand.java @@ -0,0 +1,53 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller; + +import com.puremvc.patterns.command.SimpleCommand; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.proxy.CommandManager; +import games.rednblack.editor.proxy.CursorManager; +import games.rednblack.editor.proxy.EditorTextureManager; +import games.rednblack.editor.proxy.FontManager; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.proxy.ResolutionManager; +import games.rednblack.editor.proxy.ResourceManager; +import games.rednblack.editor.proxy.SceneDataManager; +import games.rednblack.editor.splash.SplashScreenAdapter; + +/** + * Created by sargis on 4/1/15. + */ +public class BootstrapProxyCommand extends SimpleCommand { + @Override + public void execute(Notification notification) { + super.execute(notification); + facade = HyperLap2DFacade.getInstance(); + facade.sendNotification(SplashScreenAdapter.UPDATE_SPLASH, "Loading Proxies..."); + + facade.registerProxy(new FontManager()); + facade.registerProxy(new CommandManager()); + facade.registerProxy(new CursorManager()); + facade.registerProxy(new ProjectManager()); + facade.registerProxy(new ResolutionManager()); + facade.registerProxy(new SceneDataManager()); + facade.registerProxy(new EditorTextureManager()); + facade.registerProxy(new ResourceManager()); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/BootstrapViewCommand.java b/src/main/java/games/rednblack/editor/controller/BootstrapViewCommand.java new file mode 100644 index 00000000..5555a16c --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/BootstrapViewCommand.java @@ -0,0 +1,89 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller; + +import com.puremvc.patterns.command.SimpleCommand; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.splash.SplashScreenAdapter; +import games.rednblack.editor.view.ui.FollowersUIMediator; +import games.rednblack.editor.view.menu.HyperLap2DMenuBarMediator; +import games.rednblack.editor.view.HyperLap2DScreenMediator; +import games.rednblack.editor.view.stage.SandboxMediator; +import games.rednblack.editor.view.stage.UIStageMediator; +import games.rednblack.editor.view.ui.RulersUIMediator; +import games.rednblack.editor.view.ui.UIDropDownMenuMediator; +import games.rednblack.editor.view.ui.box.UIAlignBoxMediator; +import games.rednblack.editor.view.ui.box.UICompositeHierarchyMediator; +import games.rednblack.editor.view.ui.box.UIGridBoxMediator; +import games.rednblack.editor.view.ui.box.UIItemsTreeBoxMediator; +import games.rednblack.editor.view.ui.box.UILayerBoxMediator; +import games.rednblack.editor.view.ui.box.UIMultiPropertyBoxMediator; +import games.rednblack.editor.view.ui.box.UIResolutionBoxMediator; +import games.rednblack.editor.view.ui.box.UIResourcesBoxMediator; +import games.rednblack.editor.view.ui.box.UIToolBoxMediator; +import games.rednblack.editor.view.ui.box.UIZoomBoxMediator; +import games.rednblack.editor.view.ui.dialog.*; +import games.rednblack.editor.view.ui.panel.CustomVariablesPanelMediator; +import games.rednblack.editor.view.ui.panel.EditSpriteAnimationPanelMediator; +import games.rednblack.editor.view.ui.panel.TagsPanelMediator; + +/** + * Created by sargis on 4/1/15. + */ +public class BootstrapViewCommand extends SimpleCommand { + @Override + public void execute(Notification notification) { + super.execute(notification); + facade = HyperLap2DFacade.getInstance(); + facade.sendNotification(SplashScreenAdapter.UPDATE_SPLASH, "Loading Views..."); + + facade.registerMediator(new HyperLap2DScreenMediator()); + facade.registerMediator(new HyperLap2DMenuBarMediator()); + facade.registerMediator(new UICompositeHierarchyMediator()); + facade.registerMediator(new UIGridBoxMediator()); + facade.registerMediator(new UIResolutionBoxMediator()); + facade.registerMediator(new UIZoomBoxMediator()); + facade.registerMediator(new UIToolBoxMediator()); + + // Dialogs + facade.registerMediator(new NewProjectDialogMediator()); + facade.registerMediator(new ImportDialogMediator()); + facade.registerMediator(new ExportSettingsDialogMediator()); + facade.registerMediator(new CreateNewResolutionDialogMediator()); + facade.registerMediator(new CustomVariablesPanelMediator()); + facade.registerMediator(new TagsPanelMediator()); + facade.registerMediator(new EditSpriteAnimationPanelMediator()); + facade.registerMediator(new AboutDialogMediator()); + + facade.registerMediator(new RulersUIMediator()); + facade.registerMediator(new FollowersUIMediator()); + + facade.registerMediator(new UIAlignBoxMediator()); + facade.registerMediator(new UIItemsTreeBoxMediator()); + facade.registerMediator(new UIMultiPropertyBoxMediator()); + facade.registerMediator(new UILayerBoxMediator()); + facade.registerMediator(new UIResourcesBoxMediator()); + facade.registerMediator(new UIStageMediator()); + facade.registerMediator(new SandboxMediator()); + facade.registerMediator(new UIDropDownMenuMediator()); + + facade.registerMediator(new SaveDocumentDialogMediator()); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/SandboxCommand.java b/src/main/java/games/rednblack/editor/controller/SandboxCommand.java new file mode 100644 index 00000000..9c7a399a --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/SandboxCommand.java @@ -0,0 +1,36 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller; + +import com.puremvc.patterns.command.SimpleCommand; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by azakhary on 4/28/2015. + */ +public class SandboxCommand extends SimpleCommand { + + protected Sandbox sandbox; + + public SandboxCommand() { + sandbox = Sandbox.getInstance(); + facade = HyperLap2DFacade.getInstance(); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/StartupCommand.java b/src/main/java/games/rednblack/editor/controller/StartupCommand.java new file mode 100644 index 00000000..79b6647c --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/StartupCommand.java @@ -0,0 +1,36 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller; + +import com.puremvc.patterns.command.MacroCommand; + +/** + * Created by sargis on 3/30/15. + */ +public class StartupCommand extends MacroCommand { + @Override + protected void initializeMacroCommand() { + super.initializeMacroCommand(); + + addSubCommand(BootstrapProxyCommand.class); + addSubCommand(BootstrapViewCommand.class); + addSubCommand(BootstrapCommand.class); + addSubCommand(BootstrapPlugins.class); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/AddComponentToItemCommand.java b/src/main/java/games/rednblack/editor/controller/commands/AddComponentToItemCommand.java new file mode 100644 index 00000000..33326d30 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/AddComponentToItemCommand.java @@ -0,0 +1,49 @@ +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.Entity; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by CyberJoe on 7/2/2015. + */ +public class AddComponentToItemCommand extends EntityModifyRevertableCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.AddComponentToItemCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + private Entity entity; + private Component component; + + private void collectData() { + Object[] payload = getNotification().getBody(); + entity = (Entity) payload[0]; + component = (Component) payload[1]; + } + + @Override + public void doAction() { + collectData(); + + entity.add(component); + + HyperLap2DFacade.getInstance().sendNotification(DONE, entity); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + @Override + public void undoAction() { + entity.remove(component.getClass()); + + HyperLap2DFacade.getInstance().sendNotification(DONE, entity); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + public static Object[] payload(Entity entity, Component component) { + Object[] payload = new Object[2]; + payload[0] = entity; + payload[1] = component; + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/AddSelectionCommand.java b/src/main/java/games/rednblack/editor/controller/commands/AddSelectionCommand.java new file mode 100644 index 00000000..35761ae5 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/AddSelectionCommand.java @@ -0,0 +1,57 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import java.util.Set; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.utils.runtime.EntityUtils; + +/** + * Created by azakhary on 5/14/2015. + */ +public class AddSelectionCommand extends RevertableCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.AddSelectionCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + private Array entityIds; + + @Override + public void doAction() { + if(entityIds == null) { + Set items = getNotification().getBody(); + entityIds = EntityUtils.getEntityId(items); + } + + Set items = EntityUtils.getByUniqueId(entityIds); + Sandbox.getInstance().getSelector().addSelections(items); + facade.sendNotification(DONE); + } + + @Override + public void undoAction() { + Set items = EntityUtils.getByUniqueId(entityIds); + Sandbox.getInstance().getSelector().releaseSelections(items); + facade.sendNotification(DONE); + } + +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/AddToLibraryCommand.java b/src/main/java/games/rednblack/editor/controller/commands/AddToLibraryCommand.java new file mode 100644 index 00000000..6bf9a0e7 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/AddToLibraryCommand.java @@ -0,0 +1,111 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.HashMap; + +/** + * Created by azakhary on 4/28/2015. + */ +public class AddToLibraryCommand extends RevertableCommand { + + private String createdLibraryItemName; + private CompositeItemVO overwritten; + private String prevName; + private Integer entityId; + + @Override + public void doAction() { + Object[] payload = getNotification().getBody(); + + Entity item = ((Entity) payload[0]); + entityId = EntityUtils.getEntityId(item); + createdLibraryItemName = (String) payload[1]; + + MainItemComponent mainItemComponent = ComponentRetriever.get(item, MainItemComponent.class); + + if(createdLibraryItemName.length() > 0) { + ProjectManager projectManager = HyperLap2DFacade.getInstance().retrieveProxy(ProjectManager.NAME); + HashMap libraryItems = projectManager.currentProjectInfoVO.libraryItems; + + if (libraryItems.containsKey(createdLibraryItemName)) { + overwritten = libraryItems.get(createdLibraryItemName); + } + + CompositeItemVO newVO = new CompositeItemVO(); + newVO.loadFromEntity(item); + newVO.cleanIds(); + libraryItems.put(createdLibraryItemName, newVO); + + //mark this entity as belonging to library + mainItemComponent.libraryLink = createdLibraryItemName; + facade.sendNotification(MsgAPI.LIBRARY_LIST_UPDATED); + } else { + prevName = mainItemComponent.libraryLink; + // unlink it + mainItemComponent.libraryLink = ""; + } + facade.sendNotification(MsgAPI.ITEM_DATA_UPDATED); + } + + @Override + public void undoAction() { + ProjectManager projectManager = HyperLap2DFacade.getInstance().retrieveProxy(ProjectManager.NAME); + HashMap libraryItems = projectManager.currentProjectInfoVO.libraryItems; + + if(createdLibraryItemName.length() > 0) { + libraryItems.remove(createdLibraryItemName); + + if (overwritten != null) { + libraryItems.put(createdLibraryItemName, overwritten); + } + facade.sendNotification(MsgAPI.LIBRARY_LIST_UPDATED); + } else { + Entity entity = EntityUtils.getByUniqueId(entityId); + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + mainItemComponent.libraryLink = prevName; + facade.sendNotification(MsgAPI.ITEM_DATA_UPDATED); + } + } + + public static Object payloadUnLink(Entity entity) { + Object[] payload = new Object[2]; + payload[0] = entity; + payload[1] = ""; + + return payload; + } + + public static Object payloadLink(Entity entity, String link) { + Object[] payload = new Object[2]; + payload[0] = entity; + payload[1] = link; + + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/ChangeRulerPositionCommand.java b/src/main/java/games/rednblack/editor/controller/commands/ChangeRulerPositionCommand.java new file mode 100644 index 00000000..6ec8351b --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/ChangeRulerPositionCommand.java @@ -0,0 +1,56 @@ +package games.rednblack.editor.controller.commands; + +import com.kotcrab.vis.ui.util.InputValidator; +import com.kotcrab.vis.ui.util.dialog.Dialogs; +import com.kotcrab.vis.ui.util.dialog.InputDialogListener; +import games.rednblack.editor.utils.Guide; +import games.rednblack.editor.view.ui.RulersUI; + +/** + * Created by billzo on 12/22/2015. + */ +public class ChangeRulerPositionCommand extends RevertableCommand { + + private float previousPosition; + private String direction; + + @Override + public void doAction() { + previousPosition = RulersUI.getPreviousGuide().pos; + direction = RulersUI.getPreviousGuide().isVertical ? "Y" : "X"; + + Dialogs.showInputDialog(sandbox.getUIStage(), "Manual " + direction + " Position", direction + " : ", new MyInputValidator(), new InputDialogListener() { + @Override + public void finished(String input) { + RulersUI.updateGuideManually(Float.parseFloat(input)); + } + + @Override + public void canceled() { + + } + }); + } + + @Override + public void undoAction() { + System.out.println(previousPosition); + RulersUI.updateGuideManually(previousPosition); + } + + private class MyInputValidator implements InputValidator { + @Override + public boolean validateInput(String input) { + try + { + Float.parseFloat(input); + return true; + } catch (NumberFormatException ex) + { + return false; + } + } + + } + +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/CompositeCameraChangeCommand.java b/src/main/java/games/rednblack/editor/controller/commands/CompositeCameraChangeCommand.java new file mode 100644 index 00000000..3f3a1bf3 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/CompositeCameraChangeCommand.java @@ -0,0 +1,89 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.ViewPortComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +/** + * Created by azakhary on 4/28/2015. + */ +public class CompositeCameraChangeCommand extends RevertableCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.CompositeCameraChangeCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + private Integer previousViewEntityId; + private Integer enteringInto; + + private boolean wasPrevSelected = false; + + @Override + public void doAction() { + Entity entity = getNotification().getBody(); + Entity oldEntity = sandbox.getCurrentViewingEntity(); + + // check if entity is selected + wasPrevSelected = sandbox.getSelector().isSelected(entity); + + if(enteringInto == null) enteringInto = EntityUtils.getEntityId(entity); + if(previousViewEntityId == null) previousViewEntityId = EntityUtils.getEntityId(oldEntity); + + ViewPortComponent viewPortComponent = ComponentRetriever.get(oldEntity, ViewPortComponent.class); + oldEntity.remove(ViewPortComponent.class); + entity.add(viewPortComponent); + sandbox.setCurrentViewingEntity(entity); + + sandbox.getSelector().clearSelections(); + + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + TransformComponent previousTransformComponent = ComponentRetriever.get(oldEntity, TransformComponent.class); + previousTransformComponent.enableTransform(); + transformComponent.disableTransform(); + + facade.sendNotification(DONE, enteringInto); + facade.sendNotification(MsgAPI.EMPTY_SPACE_CLICKED); + } + + @Override + public void undoAction() { + Entity oldEntity = EntityUtils.getByUniqueId(previousViewEntityId); + Entity currEntity = sandbox.getCurrentViewingEntity(); + + ViewPortComponent viewPortComponent = ComponentRetriever.get(currEntity, ViewPortComponent.class); + currEntity.remove(ViewPortComponent.class); + oldEntity.add(viewPortComponent); + sandbox.setCurrentViewingEntity(oldEntity); + + facade.sendNotification(DONE, previousViewEntityId); + + TransformComponent transformComponent = ComponentRetriever.get(currEntity, TransformComponent.class); + TransformComponent previousTransformComponent = ComponentRetriever.get(oldEntity, TransformComponent.class); + previousTransformComponent.disableTransform(); + transformComponent.enableTransform(); + + if(wasPrevSelected) { + sandbox.getSelector().setSelection(EntityUtils.getByUniqueId(enteringInto), true); + } + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/ConvertToButtonCommand.java b/src/main/java/games/rednblack/editor/controller/commands/ConvertToButtonCommand.java new file mode 100644 index 00000000..262f2800 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/ConvertToButtonCommand.java @@ -0,0 +1,67 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.LayerMapComponent; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.components.additional.ButtonComponent; +import games.rednblack.editor.renderer.data.LayerItemVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.HashSet; + +/** + * Created by azakhary on 4/28/2015. + */ +public class ConvertToButtonCommand extends ConvertToCompositeCommand { + + + @Override + public void doAction() { + Entity entity; + + HashSet entities = (HashSet) sandbox.getSelector().getSelectedItems(); + Entity item = entities.iterator().next(); + + if(entities.size() == 1 && EntityUtils.getType(item) == EntityFactory.COMPOSITE_TYPE) { + entity = item; + } else { + super.doAction(); + entity = EntityUtils.getByUniqueId(entityId); + } + + //create layers + LayerMapComponent layerMapComponent = ComponentRetriever.get(entity, LayerMapComponent.class); + layerMapComponent.addLayer(new LayerItemVO("normal")); + layerMapComponent.addLayer(new LayerItemVO("pressed")); + + // adding button logic + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + mainItemComponent.tags.add("button"); + entity.add(new ButtonComponent()); + } + + @Override + public void undoAction() { + super.undoAction(); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/ConvertToCompositeCommand.java b/src/main/java/games/rednblack/editor/controller/commands/ConvertToCompositeCommand.java new file mode 100644 index 00000000..aa7399a6 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/ConvertToCompositeCommand.java @@ -0,0 +1,142 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.factory.ItemFactory; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.ZIndexComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.editor.view.ui.FollowersUIMediator; +import games.rednblack.editor.view.ui.box.UILayerBoxMediator; + +import java.util.HashMap; +import java.util.HashSet; + +/** + * Created by azakhary on 4/28/2015. + */ +public class ConvertToCompositeCommand extends EntityModifyRevertableCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.ConvertToCompositeCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + protected Integer entityId; + protected Integer parentEntityId; + + protected HashMap layersBackup; + + @Override + public void doAction() { + // get entity list + HashSet entities = (HashSet) sandbox.getSelector().getSelectedItems(); + UILayerBoxMediator layerBoxMediator = facade.retrieveMediator(UILayerBoxMediator.NAME); + + if(layersBackup == null) { + // backup layer data + layersBackup = new HashMap<>(); + for(Entity entity: entities) { + ZIndexComponent zIndexComponent = ComponentRetriever.get(entity, ZIndexComponent.class); + int tmpId = EntityUtils.getEntityId(entity); + layersBackup.put(tmpId, zIndexComponent.layerName); + } + } + + // what will be the position of new composite? + Vector2 position = EntityUtils.getLeftBottomPoint(entities); + + //create new entity + Entity entity = ItemFactory.get().createCompositeItem(position); + entityId = EntityUtils.getEntityId(entity); + sandbox.getEngine().addEntity(entity); + + // what was the parent component of entities + parentEntityId = EntityUtils.getEntityId(sandbox.getCurrentViewingEntity()); + + // rebase children + EntityUtils.changeParent(entities, entity); + + //reposition children + for(Entity childEntity: entities) { + TransformComponent transformComponent = ComponentRetriever.get(childEntity, TransformComponent.class); + transformComponent.x -= position.x; + transformComponent.y -=position.y; + + // put it on default layer + ZIndexComponent zIndexComponent = ComponentRetriever.get(childEntity, ZIndexComponent.class); + zIndexComponent.layerName = "Default"; + + } + // recalculate composite size + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + Vector2 newSize = EntityUtils.getRightTopPoint(entities); + dimensionsComponent.width = newSize.x; + dimensionsComponent.height = newSize.y; + dimensionsComponent.boundBox.set(0, 0, newSize.x, newSize.y); + + ZIndexComponent zIndexComponent = ComponentRetriever.get(entity, ZIndexComponent.class); + zIndexComponent.layerName = layerBoxMediator.getCurrentSelectedLayerName(); + + //let everyone know + HyperLap2DFacade.getInstance().sendNotification(DONE); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.NEW_ITEM_ADDED, entity); + sandbox.getSelector().setSelection(entity, true); + + } + + @Override + public void undoAction() { + FollowersUIMediator followersUIMediator = HyperLap2DFacade.getInstance().retrieveMediator(FollowersUIMediator.NAME); + + //get the entity + Entity entity = EntityUtils.getByUniqueId(entityId); + Entity oldParentEntity = EntityUtils.getByUniqueId(parentEntityId); + HashSet children = EntityUtils.getChildren(entity); + + // what will be the position diff of children? + Vector2 positionDiff = EntityUtils.getPosition(entity); + + //rebase children back to root + EntityUtils.changeParent(children, oldParentEntity); + + //reposition children + for(Entity tmpEntity: children) { + TransformComponent transformComponent = ComponentRetriever.get(tmpEntity, TransformComponent.class); + transformComponent.x+=positionDiff.x; + transformComponent.y+=positionDiff.y; + + // put layer data back + ZIndexComponent zIndexComponent = ComponentRetriever.get(entity, ZIndexComponent.class); + zIndexComponent.layerName = layersBackup.get(EntityUtils.getEntityId(tmpEntity)); + } + + // remove composite + followersUIMediator.removeFollower(entity); + sandbox.getEngine().removeEntity(entity); + + HyperLap2DFacade.getInstance().sendNotification(DONE); + + sandbox.getSelector().setSelections(children, true); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/CopyItemsCommand.java b/src/main/java/games/rednblack/editor/controller/commands/CopyItemsCommand.java new file mode 100644 index 00000000..67d0f549 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/CopyItemsCommand.java @@ -0,0 +1,113 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import java.util.Set; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Json; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.data.*; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.view.stage.Sandbox; + +/** + * Created by azakhary on 4/28/2015. + */ +public class CopyItemsCommand extends RevertableCommand { + + @Override + public void doAction() { + String data = getJsonStringFromEntities(sandbox.getSelector().getSelectedItems()); + + Object[] payload = new Object[2]; + payload[0] = new Vector2(Sandbox.getInstance().getCamera().position.x,Sandbox.getInstance().getCamera().position.y); + payload[1] = data; + Sandbox.getInstance().copyToClipboard(payload); + } + + @Override + public void undoAction() { + // we do not restore clipboard at this time, as it is not a string but a reference, which honestly sucks ass + } + + public static String getJsonStringFromEntities(Set entities) { + CompositeVO holderComposite = new CompositeVO(); + for(Entity entity : entities) { + int entityType = ComponentRetriever.get(entity, MainItemComponent.class).entityType; + if(entityType == EntityFactory.COMPOSITE_TYPE) { + CompositeItemVO vo = new CompositeItemVO(); + vo.loadFromEntity(entity); + holderComposite.sComposites.add(vo); + } + if(entityType == EntityFactory.IMAGE_TYPE) { + SimpleImageVO vo = new SimpleImageVO(); + vo.loadFromEntity(entity); + holderComposite.sImages.add(vo); + } + if(entityType == EntityFactory.NINE_PATCH) { + Image9patchVO vo = new Image9patchVO(); + vo.loadFromEntity(entity); + holderComposite.sImage9patchs.add(vo); + } + if(entityType == EntityFactory.LABEL_TYPE) { + LabelVO vo = new LabelVO(); + vo.loadFromEntity(entity); + holderComposite.sLabels.add(vo); + } + if(entityType == EntityFactory.PARTICLE_TYPE) { + ParticleEffectVO vo = new ParticleEffectVO(); + vo.loadFromEntity(entity); + holderComposite.sParticleEffects.add(vo); + } + if(entityType == EntityFactory.SPRITE_TYPE) { + SpriteAnimationVO vo = new SpriteAnimationVO(); + vo.loadFromEntity(entity); + holderComposite.sSpriteAnimations.add(vo); + } + if(entityType == EntityFactory.SPRITER_TYPE) { + SpriterVO vo = new SpriterVO(); + vo.loadFromEntity(entity); + holderComposite.sSpriterAnimations.add(vo); + } + if(entityType == EntityFactory.SPINE_TYPE) { + SpineVO vo = new SpineVO(); + vo.loadFromEntity(entity); + holderComposite.sSpineAnimations.add(vo); + } + if(entityType == EntityFactory.COLOR_PRIMITIVE) { + ColorPrimitiveVO vo = new ColorPrimitiveVO(); + vo.loadFromEntity(entity); + holderComposite.sColorPrimitives.add(vo); + } + if(entityType == EntityFactory.LIGHT_TYPE) { + LightVO vo = new LightVO(); + vo.loadFromEntity(entity); + holderComposite.sLights.add(vo); + } + } + + Json json = new Json(); + String result = json.toJson(holderComposite); + + return result; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/CreateItemCommand.java b/src/main/java/games/rednblack/editor/controller/commands/CreateItemCommand.java new file mode 100644 index 00000000..2b89efdb --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/CreateItemCommand.java @@ -0,0 +1,74 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.components.NodeComponent; +import games.rednblack.editor.renderer.components.ZIndexComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.view.ui.FollowersUIMediator; + +import java.util.HashSet; + +/** + * Created by azakhary on 6/9/2015. + */ +public class CreateItemCommand extends EntityModifyRevertableCommand { + + private Integer entityId; + private Array previousSelectionIds; + + @Override + public void doAction() { + Entity entity = getNotification().getBody(); + + entityId = EntityUtils.getEntityId(entity); + + sandbox.getEngine().addEntity(entity); + + // z-index + NodeComponent nodeComponent = ComponentRetriever.get(Sandbox.getInstance().getCurrentViewingEntity(), NodeComponent.class); + ZIndexComponent zindexComponent = ComponentRetriever.get(entity, ZIndexComponent.class); + zindexComponent.setZIndex(nodeComponent.children.size); + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.NEW_ITEM_ADDED, entity); + + // select newly created item + // get current selection + HashSet previousSelection = new HashSet<>(Sandbox.getInstance().getSelector().getSelectedItems()); + previousSelectionIds = EntityUtils.getEntityId(previousSelection); + sandbox.getSelector().setSelection(entity, true); + } + + @Override + public void undoAction() { + Entity entity = EntityUtils.getByUniqueId(entityId); + + FollowersUIMediator followersUIMediator = HyperLap2DFacade.getInstance().retrieveMediator(FollowersUIMediator.NAME); + followersUIMediator.removeFollower(entity); + sandbox.getEngine().removeEntity(entity); + + Sandbox.getInstance().getSelector().setSelections(EntityUtils.getByUniqueId(previousSelectionIds), true); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/CreatePrimitiveCommand.java b/src/main/java/games/rednblack/editor/controller/commands/CreatePrimitiveCommand.java new file mode 100644 index 00000000..9d2d9f0f --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/CreatePrimitiveCommand.java @@ -0,0 +1,43 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.factory.ItemFactory; +import games.rednblack.editor.renderer.data.ColorPrimitiveVO; +import games.rednblack.editor.renderer.data.ShapeVO; + +/** + * Created by azakhary on 10/21/2015. + */ +public class CreatePrimitiveCommand extends EntityModifyRevertableCommand { + + @Override + public void doAction() { + Vector2 position = new Vector2(0, 0); + ShapeVO shape = ShapeVO.createRect(100f / sandbox.getPixelPerWU(), 100f / sandbox.getPixelPerWU()); + + ItemFactory.get().createPrimitive(position, shape); + } + + @Override + public void undoAction() { + + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/CustomVariableModifyCommand.java b/src/main/java/games/rednblack/editor/controller/commands/CustomVariableModifyCommand.java new file mode 100644 index 00000000..9e7ea0c8 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/CustomVariableModifyCommand.java @@ -0,0 +1,91 @@ +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.renderer.utils.CustomVariables; +import games.rednblack.editor.utils.runtime.EntityUtils; + +/** + * Created by CyberJoe on 11/6/2015. + */ +public class CustomVariableModifyCommand extends EntityModifyRevertableCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.CustomVariableModifyCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + private Integer entityId; + + private boolean isAdding; + private String key; + private String value; + + @Override + public void doAction() { + process(); + if(isAdding) { + addVariable(key, value); + } else { + removeVariable(key); + } + sendNotification(DONE); + } + + @Override + public void undoAction() { + if(isAdding) { + removeVariable(key); + } else { + addVariable(key, value); + } + sendNotification(DONE); + } + + private void addVariable(String key, String value) { + Entity entity = EntityUtils.getByUniqueId(entityId); + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + mainItemComponent.setCustomVars(key, value); + } + + private void removeVariable(String key) { + Entity entity = EntityUtils.getByUniqueId(entityId); + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + value = mainItemComponent.customVariables.getStringVariable(key); //storing the backup + mainItemComponent.removeCustomVars(key); + } + + private void process() { + if(entityId == null) { + // First time call, need to prepare the data and fetch payload + Object[] payload = getNotification().getBody(); + Entity item = (Entity) payload[0]; + entityId = EntityUtils.getEntityId(item); + key = (String) payload[2]; + isAdding = false; + if(((boolean) payload[1])) { + value = (String) payload[3]; + isAdding = true; + } + } + } + + public static Object addCustomVariable(Entity entity, String key, String value) { + Object[] payload = new Object[4]; + payload[0] = entity; + payload[1] = true; // is adding type + payload[2] = key; + payload[3] = value; + + return payload; + } + + public static Object removeCustomVariable(Entity entity, String key) { + Object[] payload = new Object[3]; + payload[0] = entity; + payload[1] = true; + payload[1] = false; // is adding type (removing) + payload[2] = key; + + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/CutItemsCommand.java b/src/main/java/games/rednblack/editor/controller/commands/CutItemsCommand.java new file mode 100644 index 00000000..27199842 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/CutItemsCommand.java @@ -0,0 +1,64 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Json; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.data.CompositeVO; +import games.rednblack.editor.view.stage.Sandbox; + +import java.util.Set; + +/** + * Created by azakhary on 4/28/2015. + */ +public class CutItemsCommand extends EntityModifyRevertableCommand { + + private String backup; + + @Override + public void doAction() { + backup = CopyItemsCommand.getJsonStringFromEntities(sandbox.getSelector().getSelectedItems()); + String data = CopyItemsCommand.getJsonStringFromEntities(sandbox.getSelector().getSelectedItems()); + + Object[] payload = new Object[2]; + payload[0] = new Vector2(Sandbox.getInstance().getCamera().position.x,Sandbox.getInstance().getCamera().position.y); + payload[1] = data; + Sandbox.getInstance().copyToClipboard(payload); + sandbox.getSelector().removeCurrentSelectedItems(); + + facade.sendNotification(MsgAPI.DELETE_ITEMS_COMMAND_DONE); + } + + @Override + public void undoAction() { + Json json = new Json(); + CompositeVO compositeVO = json.fromJson(CompositeVO.class, backup); + Set newEntitiesList = PasteItemsCommand.createEntitiesFromVO(compositeVO); + + for (Entity entity : newEntitiesList) { + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.NEW_ITEM_ADDED, entity); + } + + sandbox.getSelector().setSelections(newEntitiesList, true); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/DeleteItemsCommand.java b/src/main/java/games/rednblack/editor/controller/commands/DeleteItemsCommand.java new file mode 100644 index 00000000..2f0a8035 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/DeleteItemsCommand.java @@ -0,0 +1,93 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.data.CompositeVO; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.editor.view.ui.FollowersUIMediator; + +import java.util.HashSet; +import java.util.Set; + +/** + * Created by azakhary on 4/28/2015. + */ +public class DeleteItemsCommand extends EntityModifyRevertableCommand { + + private String backup; + private Array entityIdsToDelete; + + private void backup() { + Set entitySet = new HashSet<>(); + if(entityIdsToDelete == null) { + entityIdsToDelete = new Array<>(); + entitySet = sandbox.getSelector().getSelectedItems(); + for(Entity entity: entitySet) { + entityIdsToDelete.add(EntityUtils.getEntityId(entity)); + } + } else { + for(Integer entityId: entityIdsToDelete) { + entitySet.add(EntityUtils.getByUniqueId(entityId)); + } + } + + backup = CopyItemsCommand.getJsonStringFromEntities(entitySet); + } + + @Override + public void doAction() { + backup(); + + FollowersUIMediator followersUIMediator = HyperLap2DFacade.getInstance().retrieveMediator(FollowersUIMediator.NAME); + for (Integer entityId : entityIdsToDelete) { + Entity item = EntityUtils.getByUniqueId(entityId); + followersUIMediator.removeFollower(item); + sandbox.getEngine().removeEntity(item); + } + + sandbox.getSelector().getCurrentSelection().clear(); + + facade.sendNotification(MsgAPI.DELETE_ITEMS_COMMAND_DONE); + } + + @Override + public void undoAction() { + Json json = new Json(); + CompositeVO compositeVO = json.fromJson(CompositeVO.class, backup); + Set newEntitiesList = PasteItemsCommand.createEntitiesFromVO(compositeVO); + + for (Entity entity : newEntitiesList) { + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.NEW_ITEM_ADDED, entity); + } + + sandbox.getSelector().setSelections(newEntitiesList, true); + } + + public void setItemsToDelete(Set entities) { + entityIdsToDelete = new Array<>(); + for(Entity entity: entities) { + entityIdsToDelete.add(EntityUtils.getEntityId(entity)); + } + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/DeleteLayerAtomCommand.java b/src/main/java/games/rednblack/editor/controller/commands/DeleteLayerAtomCommand.java new file mode 100644 index 00000000..e6b613b0 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/DeleteLayerAtomCommand.java @@ -0,0 +1,50 @@ +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.LayerMapComponent; +import games.rednblack.editor.renderer.data.LayerItemVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.view.stage.Sandbox; + +/** + * Created by CyberJoe on 7/25/2015. + * This command marked as "atom" meaning it cannot be called outside the transaction + * TODO: make this an annotation + */ +public class DeleteLayerAtomCommand extends EntityModifyRevertableCommand { + + private String layerName; + + private LayerItemVO layerItemVO; + private int layerIndex; + + public DeleteLayerAtomCommand(String layerName) { + this.layerName = layerName; + } + + @Override + public void doAction() { + Entity viewingEntity = Sandbox.getInstance().getCurrentViewingEntity(); + LayerMapComponent layerMapComponent = ComponentRetriever.get(viewingEntity, LayerMapComponent.class); + + + + if(layerMapComponent.getLayers().size() > 1) { + layerMapComponent.deleteLayer(layerName); + } else { + cancel(); + } + } + + @Override + public void undoAction() { + Entity viewingEntity = Sandbox.getInstance().getCurrentViewingEntity(); + LayerMapComponent layerMapComponent = ComponentRetriever.get(viewingEntity, LayerMapComponent.class); + + layerMapComponent.addLayer(layerIndex, layerItemVO); + } + + public int getLayerIndex() { + return layerIndex; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/DeleteLayerCommand.java b/src/main/java/games/rednblack/editor/controller/commands/DeleteLayerCommand.java new file mode 100644 index 00000000..3e7d95a7 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/DeleteLayerCommand.java @@ -0,0 +1,58 @@ +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.NodeComponent; +import games.rednblack.editor.renderer.components.ZIndexComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.view.stage.Sandbox; + +import java.util.HashSet; +import java.util.Set; + +/** + * Created by CyberJoe on 7/25/2015. + */ +public class DeleteLayerCommand extends TransactiveCommand { + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.DeleteLayerCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + public static final String UNDONE = CLASS_NAME + "UNDONE"; + + private String layerName; + private DeleteLayerAtomCommand deleteLayerAtomCommand; + + @Override + public void transaction() { + layerName = getNotification().getBody(); + deleteLayerAtomCommand = new DeleteLayerAtomCommand(layerName); + addInnerCommand(deleteLayerAtomCommand); + DeleteItemsCommand deleteItemsCommand = new DeleteItemsCommand(); + deleteItemsCommand.setItemsToDelete(getItemsByLayerName(layerName)); + addInnerCommand(deleteItemsCommand); + } + + @Override + public void onFinish() { + facade.sendNotification(DONE, deleteLayerAtomCommand.getLayerIndex()); + } + + @Override + public void onFinishUndo() { + facade.sendNotification(UNDONE, layerName); + } + + public Set getItemsByLayerName(String layerName) { + Set result = new HashSet<>(); + Entity viewingEntity = Sandbox.getInstance().getCurrentViewingEntity(); + NodeComponent nodeComponent = ComponentRetriever.get(viewingEntity, NodeComponent.class); + for(int i = 0; i < nodeComponent.children.size; i++) { + Entity child = nodeComponent.children.get(i); + ZIndexComponent zIndexComponent = ComponentRetriever.get(child, ZIndexComponent.class); + if(zIndexComponent.layerName.equals(layerName)) { + result.add(child); + } + } + + return result; + } + +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/EntityModifyRevertableCommand.java b/src/main/java/games/rednblack/editor/controller/commands/EntityModifyRevertableCommand.java new file mode 100644 index 00000000..56f6e239 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/EntityModifyRevertableCommand.java @@ -0,0 +1,84 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Engine; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.components.NodeComponent; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.HashMap; + +/** + * Created by azakhary on 6/15/2015. + */ +public abstract class EntityModifyRevertableCommand extends RevertableCommand { + + @Override + public void callDoAction() { + super.callDoAction(); + postChange(); + } + @Override + public void callUndoAction() { + super.callUndoAction(); + postChange(); + } + + protected void postChange() { + Integer parentId = EntityUtils.getEntityId(sandbox.getCurrentViewingEntity()); + Entity entity = EntityUtils.getByUniqueId(parentId); + + // Update item library data if it was in library + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + String link = mainItemComponent.libraryLink; + + if(link != null && link.length() > 0) { + ProjectManager projectManager = HyperLap2DFacade.getInstance().retrieveProxy(ProjectManager.NAME); + HashMap libraryItems = projectManager.currentProjectInfoVO.libraryItems; + if (libraryItems.containsKey(mainItemComponent.libraryLink)) { + CompositeItemVO itemVO = new CompositeItemVO(); + itemVO.loadFromEntity(entity); + itemVO.cleanIds(); + libraryItems.put(mainItemComponent.libraryLink, itemVO); + } + + Array linkedEntities = EntityUtils.getByLibraryLink(link); + for (Entity dependable : linkedEntities) { + if(dependable == entity) continue; + NodeComponent nodeComponent = ComponentRetriever.get(dependable, NodeComponent.class); + for(Entity child: nodeComponent.children) { + sandbox.getEngine().removeEntity(child); + } + nodeComponent.children.clear(); + + Engine engine = sandbox.getSceneControl().sceneLoader.engine; + EntityFactory factory = sandbox.getSceneControl().sceneLoader.entityFactory; + factory.initAllChildren(engine, dependable, libraryItems.get(link).composite); + } + } + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/ExportProjectCommand.java b/src/main/java/games/rednblack/editor/controller/commands/ExportProjectCommand.java new file mode 100644 index 00000000..80efee5f --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/ExportProjectCommand.java @@ -0,0 +1,35 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.controller.SandboxCommand; +import games.rednblack.editor.proxy.ProjectManager; + +/** + * Created by azakhary on 11/3/2015. + */ +public class ExportProjectCommand extends SandboxCommand { @Override + public void execute(Notification notification) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + projectManager.exportProject(); +} + + +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/ItemChildrenTransformCommand.java b/src/main/java/games/rednblack/editor/controller/commands/ItemChildrenTransformCommand.java new file mode 100644 index 00000000..3c8318bd --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/ItemChildrenTransformCommand.java @@ -0,0 +1,126 @@ +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by Sasun Poghosyan on 4/29/2016. + */ +public class ItemChildrenTransformCommand extends EntityModifyRevertableCommand { + + private HashMap prevPosMap = new HashMap<>(); + private HashMap parentPositionAndSizeMap = new HashMap<>(); + private Entity entity; + + private Vector2 prevLo; + + private void doActionOnParent() { + Array objects = getNotification().getBody(); + Object[] itemData = objects.get(0); + Entity entity = (Entity) itemData[0]; + Vector2 newPos = (Vector2) itemData[1]; + Vector2 newSize = (Vector2) itemData[2]; + + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + Vector2 prevLocation = new Vector2(transformComponent.x, transformComponent.y); + Vector2 prevSize = new Vector2(dimensionsComponent.width, dimensionsComponent.height); + PositionSize positionSize = new PositionSize(prevLocation, prevSize); + this.parentPositionAndSizeMap.put(EntityUtils.getEntityId(entity), positionSize); + setState(transformComponent, newPos, dimensionsComponent, newSize); +// transformComponent.x = newPos.x; +// transformComponent.y = newPos.y; +// +// dimensionsComponent.width = newSize.x; +// dimensionsComponent.height = newSize.y; +// if (dimensionsComponent.boundBox != null) { +// dimensionsComponent.boundBox.width = newSize.x; +// dimensionsComponent.boundBox.height = newSize.y; +// } + } + + private void undoActionOnParent() { + Map.Entry entry = parentPositionAndSizeMap.entrySet().iterator().next(); + Integer entityUniqueId = entry.getKey(); + PositionSize positionSize = entry.getValue(); + Vector2 prevLocation = positionSize.position; + Vector2 prevSize = positionSize.size; + entity = EntityUtils.getByUniqueId(entityUniqueId); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + setState(transformComponent, prevLocation, dimensionsComponent, prevSize); +// transformComponent.x = prevLocation.x; +// transformComponent.y = prevLocation.y; +// +// +// dimensionsComponent.width = prevSize.x; +// dimensionsComponent.height = prevSize.y; +// if (dimensionsComponent.boundBox != null) { +// dimensionsComponent.boundBox.width = prevSize.x; +// dimensionsComponent.boundBox.height = prevSize.y; +// } + } + + @Override + public void doAction() { + doActionOnParent(); + Array payload = notification.getBody(); + for (int i = 1; i < payload.size; i++) { + Object[] objectData = payload.get(i); + Entity entity = (Entity) objectData[0]; + Vector2 newPos = (Vector2) objectData[1]; + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + Vector2 prevPos = new Vector2(transformComponent.x, transformComponent.y); + prevPosMap.put(EntityUtils.getEntityId(entity), prevPos); +// EntityUtils.setPosition(entity, newPos); + transformComponent.x = newPos.x; + transformComponent.y = newPos.y; + } + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + @Override + public void undoAction() { + undoActionOnParent(); + for (Map.Entry entry : prevPosMap.entrySet()) { + Integer entityUniqueId = entry.getKey(); + Vector2 oldPosition = entry.getValue(); + Entity entity = EntityUtils.getByUniqueId(entityUniqueId); + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.x = oldPosition.x; + transformComponent.y = oldPosition.y; + } + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + private void setState(TransformComponent tC, Vector2 position, DimensionsComponent dC, Vector2 size) { + tC.x = position.x; + tC.y = position.y; + dC.width = size.x; + dC.height = size.y; + if (dC.boundBox != null) { + dC.boundBox.width = size.x; + dC.boundBox.height = size.y; + } + } + + private class PositionSize { + Vector2 position; + Vector2 size; + + public PositionSize(Vector2 position, Vector2 size) { + this.position = position; + this.size = size; + } + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/ItemTransformCommand.java b/src/main/java/games/rednblack/editor/controller/commands/ItemTransformCommand.java new file mode 100644 index 00000000..647e3b9a --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/ItemTransformCommand.java @@ -0,0 +1,77 @@ +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +/** + * Created by Osman on 01.08.2015. + */ +public class ItemTransformCommand extends EntityModifyRevertableCommand { + + private Array payload; + + private Integer entityId; + + @Override + public void doAction() { + payload = getNotification().getBody(); + Entity entity = (Entity) payload.get(0); + Object[] newData = (Object[]) payload.get(2); + + entityId = EntityUtils.getEntityId(entity); + + Vector2 newPos = (Vector2) newData[0]; + Vector2 newSize = (Vector2) newData[1]; + Vector2 newScale = (Vector2) newData[2]; + Float newRotation = (Float) newData[3]; + + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + + if(newPos != null) transformComponent.x = newPos.x; + if(newPos != null) transformComponent.y = newPos.y; + if(newSize != null) dimensionsComponent.width = newSize.x; + if(newSize != null) dimensionsComponent.height = newSize.y; + if(newScale != null) transformComponent.scaleX = newScale.x; + if(newScale != null) transformComponent.scaleY = newScale.y; + if(newRotation != null) transformComponent.rotation = newRotation; + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + @Override + public void undoAction() { + + Entity entity = EntityUtils.getByUniqueId(entityId); + Object[] prevData = (Object[]) payload.get(1); + + Vector2 prevPos = (Vector2) prevData[0]; + Vector2 prevSize = (Vector2) prevData[1]; + Vector2 prevScale = (Vector2) prevData[2]; + Float prevRotation = (Float) prevData[3]; + + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + + transformComponent.x = prevPos.x; + transformComponent.y = prevPos.y; + dimensionsComponent.width = prevSize.x; + dimensionsComponent.height = prevSize.y; + if (dimensionsComponent.boundBox != null) { + dimensionsComponent.boundBox.width = dimensionsComponent.width; + dimensionsComponent.boundBox.height = dimensionsComponent.height; + } + transformComponent.scaleX = prevScale.x; + transformComponent.scaleY = prevScale.y; + transformComponent.rotation = prevRotation; + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/ItemsMoveCommand.java b/src/main/java/games/rednblack/editor/controller/commands/ItemsMoveCommand.java new file mode 100644 index 00000000..fb77f76b --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/ItemsMoveCommand.java @@ -0,0 +1,84 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by azakhary on 6/4/2015. + */ +public class ItemsMoveCommand extends EntityModifyRevertableCommand { + + private HashMap prevLocations = new HashMap<>(); + + @Override + public void doAction() { + + Array payload = getNotification().getBody(); + + for(int i = 0; i < payload.size; i++) { + Object[] itemData = payload.get(i); + + Entity entity = (Entity) itemData[0]; + Vector2 newLocation = (Vector2) itemData[1]; + + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + + Vector2 prevLocation = new Vector2(transformComponent.x, transformComponent.y); + if(itemData.length > 2) { + prevLocation = (Vector2) itemData[2]; + } + prevLocations.put(EntityUtils.getEntityId(entity), prevLocation); + + transformComponent.x = newLocation.x; + transformComponent.y = newLocation.y; + + // pining UI to update current item properties tools + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + } + + @Override + public void undoAction() { + for (Map.Entry entry : prevLocations.entrySet()) { + Integer entityUniqueId = entry.getKey(); + Vector2 prevLocation = entry.getValue(); + + Entity entity = EntityUtils.getByUniqueId(entityUniqueId); + + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.x = prevLocation.x; + transformComponent.y = prevLocation.y; + + // pining UI to update current item properties tools + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/LayerSwapCommand.java b/src/main/java/games/rednblack/editor/controller/commands/LayerSwapCommand.java new file mode 100644 index 00000000..7f5947c1 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/LayerSwapCommand.java @@ -0,0 +1,68 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.LayerMapComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.editor.view.stage.Sandbox; + +/** + * Created by azakhary on 8/18/2015. + */ +public class LayerSwapCommand extends EntityModifyRevertableCommand { + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.LayerSwapCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + private Integer entityId; + + private String sourceName; + private String targetName; + + private void backup() { + if(entityId == null) { + Object[] payload = getNotification().getBody(); + sourceName = (String) payload[0]; + targetName = (String) payload[1]; + entityId = EntityUtils.getEntityId(Sandbox.getInstance().getCurrentViewingEntity()); + } + } + + @Override + public void doAction() { + backup(); + + Entity viewingEntity = EntityUtils.getByUniqueId(entityId); + LayerMapComponent layerMapComponent = ComponentRetriever.get(viewingEntity, LayerMapComponent.class); + layerMapComponent.swap(sourceName, targetName); + + facade.sendNotification(DONE); + + } + + @Override + public void undoAction() { + Entity viewingEntity = EntityUtils.getByUniqueId(entityId); + LayerMapComponent layerMapComponent = ComponentRetriever.get(viewingEntity, LayerMapComponent.class); + layerMapComponent.swap(targetName, sourceName); + + facade.sendNotification(DONE); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/NewLayerCommand.java b/src/main/java/games/rednblack/editor/controller/commands/NewLayerCommand.java new file mode 100644 index 00000000..8e85abb3 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/NewLayerCommand.java @@ -0,0 +1,51 @@ +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.LayerMapComponent; +import games.rednblack.editor.renderer.data.LayerItemVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.view.stage.Sandbox; + +/** + * Created by CyberJoe on 7/25/2015. + */ +public class NewLayerCommand extends EntityModifyRevertableCommand { + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.NewLayerCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + private String layerName; + + @Override + public void doAction() { + Object[] payload = getNotification().getBody(); + int index = (int) payload[0]; + layerName = (String) payload[1]; + + Entity viewingEntity = Sandbox.getInstance().getCurrentViewingEntity(); + LayerMapComponent layerMapComponent = ComponentRetriever.get(viewingEntity, LayerMapComponent.class); + + LayerItemVO vo = new LayerItemVO(layerName); + vo.isVisible = true; + layerMapComponent.addLayer(index, vo); + + facade.sendNotification(DONE, layerName); + } + + @Override + public void undoAction() { + Entity viewingEntity = Sandbox.getInstance().getCurrentViewingEntity(); + LayerMapComponent layerMapComponent = ComponentRetriever.get(viewingEntity, LayerMapComponent.class); + + layerMapComponent.deleteLayer(layerName); + + facade.sendNotification(DONE, layerName); + } + + public static Object[] payload(int index, String name) { + Object[] payload = new Object[2]; + payload[0] = index; + payload[1] = name; + + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/NonRevertibleCommand.java b/src/main/java/games/rednblack/editor/controller/commands/NonRevertibleCommand.java new file mode 100644 index 00000000..0db607dc --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/NonRevertibleCommand.java @@ -0,0 +1,45 @@ +package games.rednblack.editor.controller.commands; + +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.controller.SandboxCommand; +import games.rednblack.editor.proxy.CommandManager; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.renderer.data.CompositeItemVO; + +import java.util.HashMap; + +/** + * Created by azakhary on 11/29/2015. + */ +public abstract class NonRevertibleCommand extends SandboxCommand { + + protected CommandManager commandManager; + protected Notification notification; + + protected boolean isCancelled = false; + protected final HashMap libraryItems; + protected final ProjectManager projectManager; + + public NonRevertibleCommand() { + this.projectManager = facade.retrieveProxy(ProjectManager.NAME); + this.libraryItems = projectManager.getCurrentProjectInfoVO().libraryItems; + } + + @Override + public void execute(Notification notification) { + commandManager = facade.retrieveProxy(CommandManager.NAME); + this.notification = notification; + callDoAction(); + if (!isCancelled) commandManager.clearHistory(); + } + + public abstract void doAction(); + + public void callDoAction() { + doAction(); + } + + public void cancel() { + isCancelled = true; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/PasteItemsCommand.java b/src/main/java/games/rednblack/editor/controller/commands/PasteItemsCommand.java new file mode 100644 index 00000000..e05642c6 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/PasteItemsCommand.java @@ -0,0 +1,159 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.ZIndexComponent; +import games.rednblack.editor.renderer.data.CompositeVO; +import games.rednblack.editor.renderer.data.MainItemVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.view.ui.FollowersUIMediator; +import games.rednblack.editor.view.ui.box.UILayerBoxMediator; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +/** + * Created by azakhary on 4/28/2015. + */ +public class PasteItemsCommand extends EntityModifyRevertableCommand { + + private Array pastedEntityIds = new Array<>(); + + @Override + public void doAction() { + Object[] payload = (Object[]) Sandbox.getInstance().retrieveFromClipboard(); + + UILayerBoxMediator layerBoxMediator = facade.retrieveMediator(UILayerBoxMediator.NAME); + if(layerBoxMediator.getCurrentSelectedLayerName() == null || payload == null) { + cancel(); + return; + } + + Vector2 cameraPrevPosition = (Vector2) payload[0]; + Vector2 cameraCurrPosition = new Vector2(Sandbox.getInstance().getCamera().position.x,Sandbox.getInstance().getCamera().position.y); + + Vector2 diff = cameraCurrPosition.sub(cameraPrevPosition); + + Json json = new Json(); + CompositeVO compositeVO = json.fromJson(CompositeVO.class, (String) payload[1]); + forceIdChange(compositeVO); + Set newEntitiesList = createEntitiesFromVO(compositeVO); + for (Entity entity : newEntitiesList) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.x += diff.x; + transformComponent.y += diff.y; + ZIndexComponent zIndexComponent = ComponentRetriever.get(entity, ZIndexComponent.class); +// UILayerBoxMediator layerBoxMediator = facade.retrieveMediator(UILayerBoxMediator.NAME); + zIndexComponent.layerName = layerBoxMediator.getCurrentSelectedLayerName(); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.NEW_ITEM_ADDED, entity); + pastedEntityIds.add(EntityUtils.getEntityId(entity)); + } + sandbox.getSelector().setSelections(newEntitiesList, true); + } + + @Override + public void undoAction() { + FollowersUIMediator followersUIMediator = HyperLap2DFacade.getInstance().retrieveMediator(FollowersUIMediator.NAME); + for (Integer entityId : pastedEntityIds) { + Entity entity = EntityUtils.getByUniqueId(entityId); + followersUIMediator.removeFollower(entity); + sandbox.getEngine().removeEntity(entity); + } + } + + public static void forceIdChange(CompositeVO compositeVO) { + ArrayList items = compositeVO.getAllItems(); + for(MainItemVO item: items) { + item.uniqueId = -1; + } + } + + + public static Set createEntitiesFromVO(CompositeVO compositeVO) { + Set entities = new HashSet<>(); + + EntityFactory factory = Sandbox.getInstance().sceneControl.sceneLoader.entityFactory; + Entity parentEntity = Sandbox.getInstance().getCurrentViewingEntity(); + + for (int i = 0; i < compositeVO.sImages.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sImages.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + } + for (int i = 0; i < compositeVO.sImage9patchs.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sImage9patchs.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + } + for (int i = 0; i < compositeVO.sLabels.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sLabels.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + } + for (int i = 0; i < compositeVO.sParticleEffects.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sParticleEffects.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + } + for (int i = 0; i < compositeVO.sLights.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sLights.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + } + for (int i = 0; i < compositeVO.sSpineAnimations.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sSpineAnimations.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + } + for (int i = 0; i < compositeVO.sSpriteAnimations.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sSpriteAnimations.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + } + for (int i = 0; i < compositeVO.sSpriterAnimations.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sSpriterAnimations.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + } + for (int i = 0; i < compositeVO.sColorPrimitives.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sColorPrimitives.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + } + for (int i = 0; i < compositeVO.sComposites.size(); i++) { + Entity child = factory.createEntity(parentEntity, compositeVO.sComposites.get(i)); + Sandbox.getInstance().getEngine().addEntity(child); + entities.add(child); + factory.initAllChildren(Sandbox.getInstance().getEngine(), child, compositeVO.sComposites.get(i).composite); + } + + return entities; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/PluginItemCommand.java b/src/main/java/games/rednblack/editor/controller/commands/PluginItemCommand.java new file mode 100644 index 00000000..d6c04886 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/PluginItemCommand.java @@ -0,0 +1,53 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import games.rednblack.h2d.common.IItemCommand; + +/** + * Created by azakhary on 10/23/2015. + */ +public class PluginItemCommand extends EntityModifyRevertableCommand { + + private IItemCommand command; + private Object body; + + @Override + public void doAction() { + if(command == null) { + Object[] payload = notification.getBody(); + command = (IItemCommand) payload[0]; + body = payload[1]; + } + + command.doAction(body); + } + + @Override + public void undoAction() { + command.undoAction(body); + } + + public static Object build(IItemCommand command, Object body) { + Object[] payload = new Object[2]; + payload[0] = command; + payload[1] = body; + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/ReleaseSelectionCommand.java b/src/main/java/games/rednblack/editor/controller/commands/ReleaseSelectionCommand.java new file mode 100644 index 00000000..136c79c1 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/ReleaseSelectionCommand.java @@ -0,0 +1,57 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.utils.runtime.EntityUtils; + +/** + * Created by azakhary on 5/14/2015. + */ +public class ReleaseSelectionCommand extends RevertableCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.ReleaseSelectionCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + private Array entityIds; + + @Override + public void doAction() { + Set items = new HashSet<>(getNotification().>getBody()); + Sandbox.getInstance().getSelector().releaseSelections(items); + + entityIds = EntityUtils.getEntityId(items); + + facade.sendNotification(DONE); + } + + @Override + public void undoAction() { + Set items = EntityUtils.getByUniqueId(entityIds); + Sandbox.getInstance().getSelector().addSelections(items); + + facade.sendNotification(DONE); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/RemoveComponentFromItemCommand.java b/src/main/java/games/rednblack/editor/controller/commands/RemoveComponentFromItemCommand.java new file mode 100644 index 00000000..a5bcdb55 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/RemoveComponentFromItemCommand.java @@ -0,0 +1,55 @@ +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.RemovableComponent; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by CyberJoe on 7/2/2015. + */ +public class RemoveComponentFromItemCommand extends EntityModifyRevertableCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.RemoveComponentFromItemCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + private Entity entity; + private Component component; + + private void collectData() { + Object[] payload = getNotification().getBody(); + entity = (Entity) payload[0]; + Class componentClass = (Class) payload[1]; + component = entity.getComponent(componentClass); + } + + @Override + public void doAction() { + collectData(); + if (component instanceof RemovableComponent) { + ((RemovableComponent) component).onRemove(); + } + entity.remove(component.getClass()); + + HyperLap2DFacade.getInstance().sendNotification(DONE, entity); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + @Override + public void undoAction() { + if (entity.getComponent(component.getClass()) == null) { + entity.add(component); + } + + HyperLap2DFacade.getInstance().sendNotification(DONE, entity); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + public static Object[] payload(Entity entity, Class componentClass) { + Object[] payload = new Object[2]; + payload[0] = entity; + payload[1] = componentClass; + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/RenameLayerCommand.java b/src/main/java/games/rednblack/editor/controller/commands/RenameLayerCommand.java new file mode 100644 index 00000000..6a49e1b9 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/RenameLayerCommand.java @@ -0,0 +1,81 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.LayerMapComponent; +import games.rednblack.editor.renderer.components.NodeComponent; +import games.rednblack.editor.renderer.components.ZIndexComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.view.stage.Sandbox; + +/** + * Created by azakhary on 9/7/2015. + */ +public class RenameLayerCommand extends EntityModifyRevertableCommand { + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.RenameLayerCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + @Override + public void doAction() { + String[] payload = getNotification().getBody(); + String oldName = payload[0]; + String newName = payload[1]; + + if(oldName.equals(newName)) cancel(); + + renameLayer(oldName, newName); + + facade.sendNotification(DONE); + } + + @Override + public void undoAction() { + String[] payload = getNotification().getBody(); + String oldName = payload[0]; + String newName = payload[1]; + + renameLayer(newName, oldName); + + facade.sendNotification(DONE); + } + + private void renameLayer(String fromName, String toName) { + Entity viewEntity = Sandbox.getInstance().getCurrentViewingEntity(); + NodeComponent nodeComponent = ComponentRetriever.get(viewEntity, NodeComponent.class); + LayerMapComponent layerMapComponent = ComponentRetriever.get(viewEntity, LayerMapComponent.class); + + layerMapComponent.rename(fromName, toName); + + for(Entity childEntity: nodeComponent.children) { + ZIndexComponent zIndexComponent = ComponentRetriever.get(childEntity, ZIndexComponent.class); + if(zIndexComponent.layerName.equals(fromName)) { + zIndexComponent.layerName = toName; + } + } + } + + public static String[] payload(String oldName, String newName) { + String[] payload = new String[2]; + payload[0] = oldName; + payload[1] = newName; + + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/RevertableCommand.java b/src/main/java/games/rednblack/editor/controller/commands/RevertableCommand.java new file mode 100644 index 00000000..7ef10d8e --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/RevertableCommand.java @@ -0,0 +1,71 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.controller.SandboxCommand; +import games.rednblack.editor.proxy.CommandManager; + +/** + * Created by azakhary on 5/14/2015. + */ +public abstract class RevertableCommand extends SandboxCommand { + + protected CommandManager commandManager; + protected Notification notification; + + protected boolean isCancelled = false; + protected boolean stateDone = false; + + @Override + public void execute(Notification notification) { + commandManager = facade.retrieveProxy(CommandManager.NAME); + this.notification = notification; + callDoAction(); + stateDone = true; + if(!isCancelled) commandManager.addCommand(this); + } + + public abstract void doAction(); + public abstract void undoAction(); + + public void callDoAction() { + doAction(); + } + + public void callUndoAction() { + undoAction(); + } + + public Notification getNotification() { + return notification; + } + + public void setStateDone(boolean state) { + stateDone = state; + } + + public boolean isStateDone() { + return stateDone; + } + + public void cancel() { + isCancelled = true; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/SaveExportPathCommand.java b/src/main/java/games/rednblack/editor/controller/commands/SaveExportPathCommand.java new file mode 100644 index 00000000..f93c6bd6 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/SaveExportPathCommand.java @@ -0,0 +1,38 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.controller.SandboxCommand; +import games.rednblack.editor.proxy.ProjectManager; + +/** + * Created by azakhary on 11/12/2015. + */ +public class SaveExportPathCommand extends SandboxCommand { + + @Override + public void execute(Notification notification) { + String path = notification.getBody(); + + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + projectManager.setExportPaths(path); + projectManager.saveCurrentProject(); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/SetSelectionCommand.java b/src/main/java/games/rednblack/editor/controller/commands/SetSelectionCommand.java new file mode 100644 index 00000000..036c0bc5 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/SetSelectionCommand.java @@ -0,0 +1,78 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.renderer.components.NodeComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +/** + * Created by azakhary on 5/14/2015. + */ +public class SetSelectionCommand extends RevertableCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.SetSelectionCommand"; + public static final String DONE = CLASS_NAME + "DONE"; + + private Array previousSelectionIds; + + @Override + public void doAction() { + HashSet previousSelection = new HashSet<>(Sandbox.getInstance().getSelector().getSelectedItems()); + previousSelectionIds = EntityUtils.getEntityId(previousSelection); + + Set items = getNotification().getBody(); + + if(items == null) { + // deselect all + sandbox.getSelector().setSelections(items, true); + facade.sendNotification(DONE); + return; + } + + // check if items are in viewable element, if no - cancel + NodeComponent nodeComponent = ComponentRetriever.get(sandbox.getCurrentViewingEntity(), NodeComponent.class); + for (Iterator iterator = items.iterator(); iterator.hasNext();) { + Entity item = iterator.next(); + if(!nodeComponent.children.contains(item, true)) { + iterator.remove(); + } + } + + if(items.size() == 0) { + cancel(); + } else { + sandbox.getSelector().setSelections(items, true); + } + facade.sendNotification(DONE); + } + + @Override + public void undoAction() { + Sandbox.getInstance().getSelector().setSelections(EntityUtils.getByUniqueId(previousSelectionIds), true); + facade.sendNotification(DONE); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/TransactiveCommand.java b/src/main/java/games/rednblack/editor/controller/commands/TransactiveCommand.java new file mode 100644 index 00000000..71dd85ac --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/TransactiveCommand.java @@ -0,0 +1,53 @@ +package games.rednblack.editor.controller.commands; + +import com.badlogic.gdx.utils.Array; +import com.puremvc.patterns.observer.Notification; + +/** + * Created by CyberJoe on 7/25/2015. + */ +public abstract class TransactiveCommand extends RevertableCommand { + + protected Array commands = new Array(); + + @Override + public void execute(Notification notification) { + this.notification = notification; + transaction(); + super.execute(notification); + } + + @Override + public void doAction() { + for(int i = 0; i < commands.size; i++) { + commands.get(i).callDoAction(); + if(commands.get(i).isCancelled) { + // reverting + for(int j = i-1; j >= 0; j--) { + commands.get(j).callUndoAction(); + } + cancel(); + return; + } + } + + onFinish(); + } + + @Override + public void undoAction() { + for(int i = commands.size-1; i >= 0; i--) { + commands.get(i).callUndoAction(); + } + + onFinishUndo(); + } + + public abstract void transaction(); + public abstract void onFinish(); + public abstract void onFinishUndo(); + + protected void addInnerCommand(RevertableCommand command) { + commands.add(command); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/UpdateEntityComponentsCommand.java b/src/main/java/games/rednblack/editor/controller/commands/UpdateEntityComponentsCommand.java new file mode 100644 index 00000000..9599bc39 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/UpdateEntityComponentsCommand.java @@ -0,0 +1,68 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.ComponentCloner; +import games.rednblack.editor.utils.runtime.EntityUtils; + +/** + * Created by azakhary on 6/3/2015. + */ +public class UpdateEntityComponentsCommand extends EntityModifyRevertableCommand { + + private Array backupComponents = new Array<>(); + private Integer entityId; + + @Override + public void doAction() { + Object[] payload = getNotification().getBody(); + + Entity entity = (Entity) payload[0]; + entityId = EntityUtils.getEntityId(entity); + Array components = (Array) payload[1]; + + for(int i = 0; i < components.size; i++) { + //backup the original component + Component originalComponent = ComponentRetriever.get(entity, components.get(i).getClass()); + backupComponents.add(ComponentCloner.get(originalComponent)); + + //now modify the entity component from provided data + ComponentCloner.set(originalComponent, components.get(i)); + } + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + @Override + public void undoAction() { + Entity entity = EntityUtils.getByUniqueId(entityId); + for(int i = 0; i < backupComponents.size; i++) { + Component entityComponent = ComponentRetriever.get(entity, backupComponents.get(i).getClass()); + ComponentCloner.set(entityComponent, backupComponents.get(i)); + } + + facade.sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/component/UpdateLabelDataCommand.java b/src/main/java/games/rednblack/editor/controller/commands/component/UpdateLabelDataCommand.java new file mode 100644 index 00000000..83a4576d --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/component/UpdateLabelDataCommand.java @@ -0,0 +1,98 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands.component; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.controller.commands.EntityModifyRevertableCommand; +import games.rednblack.editor.renderer.components.label.LabelComponent; +import games.rednblack.editor.renderer.factory.component.LabelComponentFactory; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.editor.view.stage.Sandbox; + +/** + * Created by azakhary on 6/11/2015. + * + */ +public class UpdateLabelDataCommand extends EntityModifyRevertableCommand { + + Integer entityId; + + String prevFontName; + int prevFontSize; + int prevLabelAlign; + int prevLineAlign; + String prevText; + Label.LabelStyle prevStyle; + boolean prevWrap; + + @Override + public void doAction() { + Object[] payload = getNotification().getBody(); + Entity entity = (Entity) payload[0]; + entityId = EntityUtils.getEntityId(entity); + + LabelComponent labelComponent = ComponentRetriever.get(entity, LabelComponent.class); + + this.prevFontName = labelComponent.fontName; + this.prevFontSize = labelComponent.fontSize; + this.prevLabelAlign = labelComponent.labelAlign; + this.prevLineAlign = labelComponent.lineAlign; + this.prevStyle = labelComponent.getStyle(); + this.prevText = (String) payload[5]; + this.prevWrap = labelComponent.wrap; + + labelComponent.fontName = (String) payload[1]; + labelComponent.fontSize = (int) payload[2]; + labelComponent.setAlignment((Integer) payload[3]); + labelComponent.setText((String) payload[4]); + labelComponent.setStyle(getNewStyle(labelComponent.fontName, labelComponent.fontSize)); + labelComponent.setWrap((Boolean) payload[6]); + + facade.sendNotification(MsgAPI.ITEM_PROPERTY_DATA_FINISHED_MODIFYING, entity); + } + + private Label.LabelStyle getNewStyle(String fontName, int fontSize) { + + IResourceRetriever rm = Sandbox.getInstance().getSceneControl().sceneLoader.getRm(); + final boolean hasBitmapFont = rm.getBitmapFont(fontName, fontSize) != null; + + if(!hasBitmapFont) { + games.rednblack.editor.proxy.ResourceManager resourceManager = facade.retrieveProxy(games.rednblack.editor.proxy.ResourceManager.NAME); + resourceManager.prepareEmbeddingFont(fontName, fontSize); + } + return LabelComponentFactory.generateStyle(rm, fontName, fontSize); + } + + @Override + public void undoAction() { + final Entity entity = EntityUtils.getByUniqueId(entityId); + final LabelComponent labelComponent = ComponentRetriever.get(entity, LabelComponent.class); + + labelComponent.fontName = prevFontName; + labelComponent.fontSize = prevFontSize; + labelComponent.setAlignment(prevLabelAlign, prevLineAlign); + labelComponent.setText(prevText); + labelComponent.setStyle(prevStyle); + labelComponent.setWrap(prevWrap); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/component/UpdateLightBodyDataCommand.java b/src/main/java/games/rednblack/editor/controller/commands/component/UpdateLightBodyDataCommand.java new file mode 100644 index 00000000..722d3957 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/component/UpdateLightBodyDataCommand.java @@ -0,0 +1,73 @@ +package games.rednblack.editor.controller.commands.component; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.EntityModifyRevertableCommand; +import games.rednblack.editor.renderer.components.light.LightBodyComponent; +import games.rednblack.editor.renderer.data.LightBodyDataVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.h2d.common.MsgAPI; + +public class UpdateLightBodyDataCommand extends EntityModifyRevertableCommand { + + private Integer entityId; + private LightBodyDataVO backup; + + @Override + public void doAction() { + Object[] payload = getNotification().getBody(); + Entity entity = (Entity) payload[0]; + LightBodyDataVO vo = (LightBodyDataVO) payload[1]; + entityId = EntityUtils.getEntityId(entity); + + LightBodyComponent lightComponent = ComponentRetriever.get(entity, LightBodyComponent.class); + + backup = new LightBodyDataVO(); + backup.loadFromComponent(lightComponent); + + lightComponent.rayDirection = vo.rayDirection; + lightComponent.distance = vo.distance; + lightComponent.softnessLength = vo.softnessLength; + lightComponent.rays = vo.rays; + lightComponent.isSoft = vo.isSoft; + lightComponent.isStatic = vo.isStatic; + lightComponent.isXRay = vo.isXRay; + lightComponent.color[0] = vo.color[0]; + lightComponent.color[1] = vo.color[1]; + lightComponent.color[2] = vo.color[2]; + lightComponent.color[3] = vo.color[3]; + lightComponent.isActive = vo.isActive; + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + @Override + public void undoAction() { + Entity entity = EntityUtils.getByUniqueId(entityId); + LightBodyComponent lightComponent = ComponentRetriever.get(entity, LightBodyComponent.class); + + lightComponent.rayDirection = backup.rayDirection; + lightComponent.distance = backup.distance; + lightComponent.softnessLength = backup.softnessLength; + lightComponent.rays = backup.rays; + lightComponent.isSoft = backup.isSoft; + lightComponent.isStatic = backup.isStatic; + lightComponent.isXRay = backup.isXRay; + lightComponent.color[0] = backup.color[0]; + lightComponent.color[1] = backup.color[1]; + lightComponent.color[2] = backup.color[2]; + lightComponent.color[3] = backup.color[3]; + lightComponent.isActive = backup.isActive; + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + public static Object payload(Entity entity, LightBodyDataVO vo) { + Object[] payload = new Object[2]; + payload[0] = entity; + payload[1] = vo; + + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/component/UpdateLightDataCommand.java b/src/main/java/games/rednblack/editor/controller/commands/component/UpdateLightDataCommand.java new file mode 100644 index 00000000..d1b34c28 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/component/UpdateLightDataCommand.java @@ -0,0 +1,85 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands.component; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.EntityModifyRevertableCommand; +import games.rednblack.editor.renderer.components.light.LightObjectComponent; +import games.rednblack.editor.renderer.data.LightVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.h2d.common.MsgAPI; + +public class UpdateLightDataCommand extends EntityModifyRevertableCommand { + + private Integer entityId; + private LightVO backup; + + @Override + public void doAction() { + Object[] payload = getNotification().getBody(); + Entity entity = (Entity) payload[0]; + LightVO vo = (LightVO) payload[1]; + entityId = EntityUtils.getEntityId(entity); + + backup = new LightVO(); + backup.loadFromEntity(entity); + + LightObjectComponent lightObjectComponent = ComponentRetriever.get(entity, LightObjectComponent.class); + + lightObjectComponent.rays = vo.rays; + lightObjectComponent.isStatic = vo.isStatic; + lightObjectComponent.isXRay = vo.isXRay; + lightObjectComponent.coneDegree = vo.coneDegree; + lightObjectComponent.distance = vo.distance; + lightObjectComponent.softnessLength = vo.softnessLength; + lightObjectComponent.directionDegree = vo.directionDegree; + lightObjectComponent.isSoft = vo.isSoft; + lightObjectComponent.isActive = vo.isActive; + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + @Override + public void undoAction() { + Entity entity = EntityUtils.getByUniqueId(entityId); + LightObjectComponent lightObjectComponent = ComponentRetriever.get(entity, LightObjectComponent.class); + + lightObjectComponent.rays = backup.rays; + lightObjectComponent.isStatic = backup.isStatic; + lightObjectComponent.isXRay = backup.isXRay; + lightObjectComponent.coneDegree = backup.coneDegree; + lightObjectComponent.distance = backup.distance; + lightObjectComponent.softnessLength = backup.softnessLength; + lightObjectComponent.directionDegree = backup.directionDegree; + lightObjectComponent.isActive = backup.isActive; + lightObjectComponent.isSoft = backup.isSoft; + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + public static Object payload(Entity entity, LightVO vo) { + Object[] payload = new Object[2]; + payload[0] = entity; + payload[1] = vo; + + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/component/UpdatePolygonComponentCommand.java b/src/main/java/games/rednblack/editor/controller/commands/component/UpdatePolygonComponentCommand.java new file mode 100644 index 00000000..df252682 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/component/UpdatePolygonComponentCommand.java @@ -0,0 +1,139 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.controller.commands.component; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.components.light.LightBodyComponent; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.EntityModifyRevertableCommand; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.PolygonComponent; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +/** + * Created by azakhary on 7/3/2015. + */ +public class UpdatePolygonComponentCommand extends EntityModifyRevertableCommand { + + private Integer entityId; + private Vector2[][] dataFrom; + private Vector2[][] dataTo; + + private void collectData() { + Object[] payload = getNotification().getBody(); + entityId = EntityUtils.getEntityId((Entity) payload[0]); + dataFrom = (Vector2[][]) payload[1]; + dataTo = (Vector2[][]) payload[2]; + dataFrom = dataFrom.clone(); + dataTo = dataTo.clone(); + } + + @Override + public void doAction() { + collectData(); + + Entity entity = EntityUtils.getByUniqueId(entityId); + + PolygonComponent polygonComponent = ComponentRetriever.get(entity, PolygonComponent.class); + polygonComponent.vertices = dataTo; + + // if it's image update polygon sprite data + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + if(textureRegionComponent != null && textureRegionComponent.isPolygon) { + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + float ppwu = dimensionsComponent.width/textureRegionComponent.region.getRegionWidth(); + dimensionsComponent.setPolygon(polygonComponent); + textureRegionComponent.setPolygonSprite(polygonComponent,1f/ppwu); + } + + PhysicsBodyComponent physicsBodyComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class); + if (physicsBodyComponent != null) { + physicsBodyComponent.needToRefreshBody = true; + } + + LightBodyComponent lightBodyComponent = ComponentRetriever.get(entity, LightBodyComponent.class); + if (lightBodyComponent != null) { + lightBodyComponent.needToRefreshLight = true; + } + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + + } + + @Override + public void undoAction() { + Entity entity = EntityUtils.getByUniqueId(entityId); + + PolygonComponent polygonComponent = ComponentRetriever.get(entity, PolygonComponent.class); + polygonComponent.vertices = dataFrom; + + // if it's image update polygon sprite data + TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class); + if(textureRegionComponent != null && textureRegionComponent.isPolygon) { + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + float ppwu = dimensionsComponent.width/textureRegionComponent.region.getRegionWidth(); + dimensionsComponent.setPolygon(polygonComponent); + textureRegionComponent.setPolygonSprite(polygonComponent, 1f/ppwu); + } + + PhysicsBodyComponent physicsBodyComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class); + if (physicsBodyComponent != null) { + physicsBodyComponent.needToRefreshBody = true; + } + + LightBodyComponent lightBodyComponent = ComponentRetriever.get(entity, LightBodyComponent.class); + if (lightBodyComponent != null) { + lightBodyComponent.needToRefreshLight = true; + } + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ITEM_DATA_UPDATED, entity); + } + + public static Object[] payloadInitialState(Entity entity) { + PolygonComponent polygonComponent = ComponentRetriever.get(entity, PolygonComponent.class); + Object[] payload = new Object[3]; + payload[0] = entity; + payload[1] = cloneData(polygonComponent.vertices); + + return payload; + } + + public static Object[] payload(Object[] payload, Vector2[][] vertices) { + payload[2] = cloneData(vertices); + + return payload; + } + + private static Vector2[][] cloneData(Vector2[][] data) { + Vector2[][] newData = new Vector2[data.length][]; + for(int i = 0; i < data.length; i++) { + newData[i] = new Vector2[data[i].length]; + for(int j = 0; j < data[i].length; j++) { + newData[i][j] = data[i][j].cpy(); + } + } + + return newData; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/component/UpdateSpriteAnimationDataCommand.java b/src/main/java/games/rednblack/editor/controller/commands/component/UpdateSpriteAnimationDataCommand.java new file mode 100644 index 00000000..2eaf5b6d --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/component/UpdateSpriteAnimationDataCommand.java @@ -0,0 +1,61 @@ +package games.rednblack.editor.controller.commands.component; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.graphics.g2d.Animation; +import games.rednblack.editor.controller.commands.EntityModifyRevertableCommand; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationComponent; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationStateComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +/** + * Created by CyberJoe on 6/18/2015. + */ +public class UpdateSpriteAnimationDataCommand extends EntityModifyRevertableCommand { + + private Integer entityId; + + private int previousFps; + private String previousAnimationName; + + @Override + public void doAction() { + Object[] payload = getNotification().getBody(); + Entity entity = (Entity) payload[0]; + entityId = EntityUtils.getEntityId(entity); + + int fps = (int) payload[1]; + String animName = (String) payload[2]; + Animation.PlayMode playMode = (Animation.PlayMode) payload[3]; + + SpriteAnimationComponent spriteAnimationComponent = ComponentRetriever.get(entity, SpriteAnimationComponent.class); + SpriteAnimationStateComponent spriteAnimationStateComponent = ComponentRetriever.get(entity, SpriteAnimationStateComponent.class); + previousFps = spriteAnimationComponent.fps; + previousAnimationName = spriteAnimationComponent.currentAnimation; + spriteAnimationComponent.fps = fps; + spriteAnimationComponent.currentAnimation = animName; + spriteAnimationComponent.playMode = playMode; + spriteAnimationStateComponent.set(spriteAnimationComponent); + } + + @Override + public void undoAction() { + Entity entity = EntityUtils.getByUniqueId(entityId); + + SpriteAnimationComponent spriteAnimationComponent = ComponentRetriever.get(entity, SpriteAnimationComponent.class); + SpriteAnimationStateComponent spriteAnimationStateComponent = ComponentRetriever.get(entity, SpriteAnimationStateComponent.class); + spriteAnimationComponent.fps = previousFps; + spriteAnimationComponent.currentAnimation = previousAnimationName; + spriteAnimationStateComponent.set(spriteAnimationComponent); + } + + public static Object payload(Entity entity, int fps, String animName, Animation.PlayMode playMode) { + Object[] payload = new Object[4]; + payload[0] = entity; + payload[1] = fps; + payload[2] = animName; + payload[3] = playMode; + + return payload; + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteImageResource.java b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteImageResource.java new file mode 100644 index 00000000..23d7f099 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteImageResource.java @@ -0,0 +1,79 @@ +package games.rednblack.editor.controller.commands.resource; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.controller.commands.NonRevertibleCommand; +import games.rednblack.editor.proxy.ResolutionManager; +import games.rednblack.editor.renderer.components.TextureRegionComponent; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.data.SceneVO; +import games.rednblack.editor.renderer.data.SimpleImageVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.ArrayList; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * Created by azakhary on 11/29/2015. + */ +public class DeleteImageResource extends NonRevertibleCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.resource.DeleteImageResource"; + public static final String DONE = CLASS_NAME + "DONE"; + + private final ArrayList tmpEntityList = new ArrayList<>(); + private final ArrayList tmpImageList = new ArrayList<>(); + + @Override + public void doAction() { + String imageName = notification.getBody(); + if (projectManager.deleteSingleImage(imageName)) { + deleteEntitiesWithImages(sandbox.getRootEntity(), imageName); + deleteAllItemsImages(imageName); + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + resolutionManager.rePackProjectImagesForAllResolutions(); + projectManager.loadProjectData(projectManager.getCurrentProjectPath()); + sendNotification(DONE, imageName); + SceneVO vo = sandbox.sceneVoFromItems(); + projectManager.saveCurrentProject(vo); + } else { + cancel(); + } + } + + private void deleteAllItemsImages(String imageName) { + for (CompositeItemVO compositeItemVO : libraryItems.values()) { + deleteAllImagesOfItem(compositeItemVO, imageName); + } + } + + private void deleteAllImagesOfItem(CompositeItemVO compositeItemVO, String imageName) { + Consumer action = (rootItemVo) -> deleteCurrentItemImage(rootItemVo, imageName); + EntityUtils.applyActionRecursivelyOnLibraryItems(compositeItemVO, action); + } + + private void deleteCurrentItemImage(CompositeItemVO compositeItemVO, String imageName) { + if (compositeItemVO.composite != null && compositeItemVO.composite.sImages.size() != 0) { + ArrayList simpleImageVOs = compositeItemVO.composite.sImages; + tmpImageList.addAll(simpleImageVOs + .stream() + .filter(simpleImageVO -> simpleImageVO.imageName.equals(imageName)) + .collect(Collectors.toList())); + simpleImageVOs.removeAll(tmpImageList); + tmpImageList.clear(); + } + } + + private void deleteEntitiesWithImages(Entity rootEntity, String regionName) { + tmpEntityList.clear(); + Consumer action = (root) -> { + TextureRegionComponent regionComponent = ComponentRetriever.get(root, TextureRegionComponent.class); + if (regionComponent != null && regionComponent.regionName.equals(regionName)) { + tmpEntityList.add(root); + } + }; + EntityUtils.applyActionRecursivelyOnEntities(rootEntity, action); + EntityUtils.removeEntities(tmpEntityList); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteLibraryItem.java b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteLibraryItem.java new file mode 100644 index 00000000..717eda5a --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteLibraryItem.java @@ -0,0 +1,39 @@ +package games.rednblack.editor.controller.commands.resource; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.NonRevertibleCommand; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.HashMap; + +/** + * Created by azakhary on 11/29/2015. + */ +public class DeleteLibraryItem extends NonRevertibleCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.resource.DeleteLibraryItem"; + public static final String DONE = CLASS_NAME + "DONE"; + + @Override + public void doAction() { + String libraryItemName = notification.getBody(); + + ProjectManager projectManager = HyperLap2DFacade.getInstance().retrieveProxy(ProjectManager.NAME); + HashMap libraryItems = projectManager.currentProjectInfoVO.libraryItems; + + libraryItems.remove(libraryItemName); + + Array linkedEntities = EntityUtils.getByLibraryLink(libraryItemName); + for (Entity entity : linkedEntities) { + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + mainItemComponent.libraryLink = ""; + } + facade.sendNotification(DONE, libraryItemName); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteParticleEffect.java b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteParticleEffect.java new file mode 100644 index 00000000..6540e6be --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteParticleEffect.java @@ -0,0 +1,76 @@ +package games.rednblack.editor.controller.commands.resource; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.controller.commands.NonRevertibleCommand; +import games.rednblack.editor.renderer.components.particle.ParticleComponent; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.data.ParticleEffectVO; +import games.rednblack.editor.renderer.data.SceneVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.ArrayList; +import java.util.function.Consumer; + +/** + * Created by Sasun Poghosyan on 5/10/2016. + */ +public class DeleteParticleEffect extends NonRevertibleCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.resource.DeleteParticleEffect"; + public static final String DONE = CLASS_NAME + "DONE"; + + private final ArrayList entityList = new ArrayList<>(); + private final ArrayList tmpParticleEffectList = new ArrayList<>(); + + @Override + public void doAction() { + String particleName = notification.getBody(); + if (projectManager.deleteParticle(particleName)) { + deleteEntitiesWithParticleEffects(sandbox.getRootEntity(), particleName); // delete entities from scene + deleteAllItemsWithParticleName(particleName); + projectManager.loadProjectData(projectManager.getCurrentProjectPath()); + sendNotification(DONE, particleName); + SceneVO vo = sandbox.sceneVoFromItems(); + projectManager.saveCurrentProject(vo); + } else { + cancel(); + } + } + + private void deleteAllItemsWithParticleName(String name) { + for (CompositeItemVO compositeItemVO : libraryItems.values()) { + deleteAllParticles(compositeItemVO, name); + } + } + + private void deleteAllParticles(CompositeItemVO compositeItemVO, String name) { + Consumer action = (rootItemVo) -> getParticles(rootItemVo, name); + EntityUtils.applyActionRecursivelyOnLibraryItems(compositeItemVO, action); + } + + private void getParticles(CompositeItemVO compositeItemVO, String name) { + if (compositeItemVO.composite != null && compositeItemVO.composite.sParticleEffects.size() != 0) { + ArrayList particleEffectList = compositeItemVO.composite.sParticleEffects; + for (ParticleEffectVO particleEffectVO : particleEffectList) { + if (particleEffectVO.particleName.equals(name)) { + tmpParticleEffectList.add(particleEffectVO); + } + } + particleEffectList.removeAll(tmpParticleEffectList); + tmpParticleEffectList.clear(); + } + } + + private void deleteEntitiesWithParticleEffects(Entity rootEntity, String particleName) { + entityList.clear(); + Consumer action = (root) -> { + ParticleComponent particleComponent = ComponentRetriever.get(root, ParticleComponent.class); + if (particleComponent != null && particleComponent.particleName.equals(particleName)) { + entityList.add(root); + } + }; + EntityUtils.applyActionRecursivelyOnEntities(rootEntity, action); + EntityUtils.removeEntities(entityList); + } +} diff --git a/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteSpineAnimation.java b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteSpineAnimation.java new file mode 100644 index 00000000..e8a2b399 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteSpineAnimation.java @@ -0,0 +1,78 @@ +package games.rednblack.editor.controller.commands.resource; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.controller.commands.NonRevertibleCommand; +import games.rednblack.editor.renderer.components.SpineDataComponent; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.data.SceneVO; +import games.rednblack.editor.renderer.data.SpineVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.ArrayList; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * Created by Sasun Poghosyan on 5/10/2016. + */ +public class DeleteSpineAnimation extends NonRevertibleCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.resource.DeleteSpineAnimation"; + public static final String DONE = CLASS_NAME + "DONE"; + + private final ArrayList entityList = new ArrayList<>(); + private final ArrayList tmpSpineAnimList = new ArrayList<>(); + + @Override + public void doAction() { + String spineItemName = notification.getBody(); + if (projectManager.deleteSpineAnimation(spineItemName)) { + deleteEntitiesWithParticleEffects(sandbox.getRootEntity(), spineItemName); + deleteAllItemsSpineAnimations(spineItemName); + projectManager.loadProjectData(projectManager.getCurrentProjectPath()); + sendNotification(DONE, spineItemName); + SceneVO vo = sandbox.sceneVoFromItems(); + projectManager.saveCurrentProject(vo); + } else { + cancel(); + } + } + + private void deleteAllItemsSpineAnimations(String spineAnimationName) { + for (CompositeItemVO compositeItemVO : libraryItems.values()) { + deleteAllSpineAnimationsOfItem(compositeItemVO, spineAnimationName); + } + } + + private void deleteAllSpineAnimationsOfItem(CompositeItemVO compositeItemVO, String spineAnimationName) { + Consumer action = (rootItemVo) -> deleteCurrentItemSpineAnimations(rootItemVo, spineAnimationName); + EntityUtils.applyActionRecursivelyOnLibraryItems(compositeItemVO, action); + } + + private void deleteCurrentItemSpineAnimations(CompositeItemVO compositeItemVO, String spineAnimationName) { + if (compositeItemVO.composite != null && compositeItemVO.composite.sSpineAnimations.size() != 0) { + ArrayList spineAnimations = compositeItemVO.composite.sSpineAnimations; + tmpSpineAnimList.addAll(spineAnimations + .stream() + .filter(spineVO -> spineVO.animationName.equals(spineAnimationName)) + .collect(Collectors.toList())); + spineAnimations.removeAll(tmpSpineAnimList); + tmpSpineAnimList.clear(); + } + } + + private void deleteEntitiesWithParticleEffects(Entity rootEntity, String particleName) { + entityList.clear(); + Consumer action = (root) -> { + SpineDataComponent spineDataComponent = ComponentRetriever.get(root, SpineDataComponent.class); + if (spineDataComponent != null && spineDataComponent.animationName.equals(particleName)) { + entityList.add(root); + } + }; + EntityUtils.applyActionRecursivelyOnEntities(rootEntity, action); + EntityUtils.removeEntities(entityList); + } +} + + diff --git a/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteSpriteAnimation.java b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteSpriteAnimation.java new file mode 100644 index 00000000..84d54ba5 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteSpriteAnimation.java @@ -0,0 +1,80 @@ +package games.rednblack.editor.controller.commands.resource; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.controller.commands.NonRevertibleCommand; +import games.rednblack.editor.renderer.components.sprite.SpriteAnimationComponent; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.data.SceneVO; +import games.rednblack.editor.renderer.data.SpriteAnimationVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.ArrayList; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * Created by Sasun Poghosyan on 5/12/2016. + */ +public class DeleteSpriteAnimation extends NonRevertibleCommand { + + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.resource.DeleteSpriteAnimation"; + public static final String DONE = CLASS_NAME + "DONE"; + + private final ArrayList entityList = new ArrayList<>(); + private final ArrayList tmpSpriteAnimVoList = new ArrayList<>(); + + @Override + public void doAction() { + String spriteAnimationName = notification.getBody(); + if (projectManager.deleteSpriteAnimation(spriteAnimationName)) { + deleteEntitiesWithSpriteAnimation(sandbox.getRootEntity(), spriteAnimationName); + deleteAllItemsSpriteAnimations(spriteAnimationName); + projectManager.loadProjectData(projectManager.getCurrentProjectPath()); + facade.sendNotification(DONE, spriteAnimationName); + SceneVO vo = sandbox.sceneVoFromItems(); + projectManager.saveCurrentProject(vo); + } else { + cancel(); + } + } + + private void deleteAllItemsSpriteAnimations(String spriteAnimationName) { + for (CompositeItemVO compositeItemVO : libraryItems.values()) { + deleteAllSpriteAnimationsOfItem(compositeItemVO, spriteAnimationName); + } + } + + private void deleteAllSpriteAnimationsOfItem(CompositeItemVO rootItemVo, String spriteAnimationName) { + Consumer action = (currentItemVo) -> deleteCurrentItemSpriteAnimations(currentItemVo, spriteAnimationName); + EntityUtils.applyActionRecursivelyOnLibraryItems(rootItemVo, action); + } + + private void deleteCurrentItemSpriteAnimations(CompositeItemVO compositeItemVO, String spriteAnimationName) { + if (compositeItemVO.composite != null && compositeItemVO.composite.sSpriteAnimations.size() != 0) { + ArrayList spriteAnimations = compositeItemVO.composite.sSpriteAnimations; + + tmpSpriteAnimVoList.addAll(spriteAnimations + .stream() + .filter(spriteVO -> spriteVO.animationName.equals(spriteAnimationName)) + .collect(Collectors.toList())); + + spriteAnimations.removeAll(tmpSpriteAnimVoList); + tmpSpriteAnimVoList.clear(); + } + } + + private void deleteEntitiesWithSpriteAnimation(Entity rootEntity, String spriteAnimationName) { + entityList.clear(); + Consumer action = (root) -> { + SpriteAnimationComponent spriteAnimationComponent = ComponentRetriever.get(root, SpriteAnimationComponent.class); + if (spriteAnimationComponent != null && spriteAnimationComponent.animationName.equals(spriteAnimationName)) { + entityList.add(root); + } + }; + EntityUtils.applyActionRecursivelyOnEntities(rootEntity, action); + EntityUtils.removeEntities(entityList); + } +} + + diff --git a/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteSpriterAnimation.java b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteSpriterAnimation.java new file mode 100644 index 00000000..1d0c97d5 --- /dev/null +++ b/src/main/java/games/rednblack/editor/controller/commands/resource/DeleteSpriterAnimation.java @@ -0,0 +1,77 @@ +package games.rednblack.editor.controller.commands.resource; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.controller.commands.NonRevertibleCommand; +import games.rednblack.editor.renderer.components.spriter.SpriterComponent; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.data.SceneVO; +import games.rednblack.editor.renderer.data.SpriterVO; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.utils.runtime.EntityUtils; + +import java.util.ArrayList; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * Created by Sasun Poghosyan on 5/12/2016. + */ +public class DeleteSpriterAnimation extends NonRevertibleCommand { + private static final String CLASS_NAME = "games.rednblack.editor.controller.commands.resource.DeleteSpriterAnimation"; + public static final String DONE = CLASS_NAME + "DONE"; + + private final ArrayList entityList = new ArrayList<>(); + private final ArrayList tmpSpriterAnimList = new ArrayList<>(); + + @Override + public void doAction() { + String spriterAnimName = notification.getBody(); + if (projectManager.deleteSpriterAnimation(spriterAnimName)) { + deleteEntitiesWithSpriterAnimation(sandbox.getRootEntity(), spriterAnimName); + deleteAllItemsSpriterAnimations(spriterAnimName); + projectManager.loadProjectData(projectManager.getCurrentProjectPath()); + facade.sendNotification(DONE, spriterAnimName); + SceneVO vo = sandbox.sceneVoFromItems(); + projectManager.saveCurrentProject(vo); + } else { + cancel(); + } + + } + + private void deleteAllItemsSpriterAnimations(String spriterAnimationName) { + for (CompositeItemVO compositeItemVO : libraryItems.values()) { + deleteAllSpriterAnimationsOfItem(compositeItemVO, spriterAnimationName); + } + } + + private void deleteAllSpriterAnimationsOfItem(CompositeItemVO rootItemVo, String spriterAnimationName) { + Consumer action = (currentItemVo) -> deleteCurrentItemSpriterAnimations(currentItemVo, spriterAnimationName); + EntityUtils.applyActionRecursivelyOnLibraryItems(rootItemVo, action); + } + + private void deleteCurrentItemSpriterAnimations(CompositeItemVO compositeItemVO, String spriterAnimationName) { + if (compositeItemVO.composite != null && compositeItemVO.composite.sSpriterAnimations.size() != 0) { + ArrayList spriterAnimations = compositeItemVO.composite.sSpriterAnimations; + tmpSpriterAnimList.addAll(spriterAnimations + .stream() + .filter(spriterVO -> spriterVO.animationName.equals(spriterAnimationName)) + .collect(Collectors.toList())); + + spriterAnimations.removeAll(tmpSpriterAnimList); + tmpSpriterAnimList.clear(); + } + } + + private void deleteEntitiesWithSpriterAnimation(Entity rootEntity, String spriterAnimationName) { + entityList.clear(); + Consumer action = (root) -> { + SpriterComponent spriterAnimationComponent = ComponentRetriever.get(root, SpriterComponent.class); + if (spriterAnimationComponent != null && spriterAnimationComponent.animationName.equals(spriterAnimationName)) { + entityList.add(root); + } + }; + EntityUtils.applyActionRecursivelyOnEntities(rootEntity, action); + EntityUtils.removeEntities(entityList); + } +} diff --git a/src/main/java/games/rednblack/editor/data/JarUtils.java b/src/main/java/games/rednblack/editor/data/JarUtils.java new file mode 100644 index 00000000..3f4e764d --- /dev/null +++ b/src/main/java/games/rednblack/editor/data/JarUtils.java @@ -0,0 +1,118 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.data; + +//package com.google.doclava; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class JarUtils { + /** + * Returns the jar file used to load class clazz, or defaultJar if clazz was not loaded from a + * jar. + */ + public static JarFile jarForClass(Class clazz, JarFile defaultJar) { + String path = "/" + clazz.getName().replace('.', '/') + ".class"; + URL jarUrl = clazz.getResource(path); + if (jarUrl == null) { + return defaultJar; + } + + String url = jarUrl.toString(); + int bang = url.indexOf("!"); + String JAR_URI_PREFIX = "jar:file:"; + if (url.startsWith(JAR_URI_PREFIX) && bang != -1) { + try { + return new JarFile(url.substring(JAR_URI_PREFIX.length(), bang)); + } catch (IOException e) { + throw new IllegalStateException("Error loading jar file.", e); + } + } else { + return defaultJar; + } + } + + + public static JarFile getThisJar(Class clazz) { + + String path = "/" + clazz.getName().replace('.', '/') + ".class"; + URL jarUrl = clazz.getResource(path); + + String url = jarUrl.toString(); + int bang = url.indexOf("!"); + String JAR_URI_PREFIX = "jar:file:"; + if (url.startsWith(JAR_URI_PREFIX) && bang != -1) { + try { + return new JarFile(url.substring(JAR_URI_PREFIX.length(), bang)); + } catch (IOException e) { + throw new IllegalStateException("Error loading jar file.", e); + } + } + + return null; + } + + /** + * Copies a directory from a jar file to an external directory. + */ + public static void copyResourcesToDirectory(JarFile fromJar, String jarDir, String destDir) + throws IOException { + for (Enumeration entries = fromJar.entries(); entries.hasMoreElements();) { + JarEntry entry = entries.nextElement(); + if (entry.getName().startsWith(jarDir + "/") && !entry.isDirectory()) { + File dest = new File(destDir + "/" + entry.getName().substring(jarDir.length() + 1)); + File parent = dest.getParentFile(); + if (parent != null) { + parent.mkdirs(); + } + + FileOutputStream out = new FileOutputStream(dest); + InputStream in = fromJar.getInputStream(entry); + + try { + byte[] buffer = new byte[8 * 1024]; + + int s = 0; + while ((s = in.read(buffer)) > 0) { + out.write(buffer, 0, s); + } + } catch (IOException e) { + throw new IOException("Could not copy asset from jar file", e); + } finally { + try { + in.close(); + } catch (IOException ignored) {} + try { + out.close(); + } catch (IOException ignored) {} + } + } + } + + } + + private JarUtils() {} // non-instantiable +} diff --git a/src/main/java/games/rednblack/editor/data/SpineAnimData.java b/src/main/java/games/rednblack/editor/data/SpineAnimData.java new file mode 100644 index 00000000..d7299f18 --- /dev/null +++ b/src/main/java/games/rednblack/editor/data/SpineAnimData.java @@ -0,0 +1,31 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.data; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; + +/** + * Created by azakhary on 7/3/2014. + */ +public class SpineAnimData { + public TextureAtlas atlas; + public FileHandle jsonFile; + public String animName; +} diff --git a/src/main/java/games/rednblack/editor/data/manager/PreferencesManager.java b/src/main/java/games/rednblack/editor/data/manager/PreferencesManager.java new file mode 100644 index 00000000..7d3ba2d8 --- /dev/null +++ b/src/main/java/games/rednblack/editor/data/manager/PreferencesManager.java @@ -0,0 +1,159 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.data.manager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Preferences; +import com.badlogic.gdx.utils.Array; +import org.apache.commons.io.FilenameUtils; + +public class PreferencesManager { + private static final String TAG = PreferencesManager.class.getCanonicalName(); + private static PreferencesManager instance = null; + private final Preferences prefs; + + public PreferencesManager() { + prefs = Gdx.app.getPreferences("HyperLap2DPrefs"); + initPrefs(); + } + + private void initPrefs() { + if (!contains("recentHistory")) { + putInteger("recentHistory",10); + flush(); + } + } + + public static PreferencesManager getInstance() { + if (instance == null) + instance = new PreferencesManager(); + + return instance; + } + + // Map to Prefs + public boolean contains(String key) { return prefs.contains(key); } + public void flush() { prefs.flush(); } + public Map get() { return prefs.get(); } + public boolean getBoolean(String key) { return prefs.getBoolean(key); } + public boolean getBoolean(String key, boolean defVal) { return prefs.getBoolean(key,defVal); } + public float getFloat(String key) { return prefs.getFloat(key); } + public float getFloat(String key, float defVal) { return prefs.getFloat(key,defVal); } + public int getInteger(String key) { return prefs.getInteger(key); } + public int getInteger(String key, int defVal) { return prefs.getInteger(key,defVal); } + public long getLong(String key) { return prefs.getLong(key); } + public long getLong(String key, long defVal) { return prefs.getLong(key,defVal); } + public String getString(String key) { return prefs.getString(key); } + public String getString(String key, String defVal) { return prefs.getString(key,defVal); } + public Preferences put(Map vals) { return prefs.put(vals); } + public Preferences putBoolean(String key, boolean val) { return prefs.putBoolean(key, val); } + public Preferences putFloat(String key, float val) { return prefs.putFloat(key, val); } + public Preferences putInteger(String key, int val) { return prefs.putInteger(key, val); } + public Preferences putLong(String key, int val) { return prefs.putLong(key, val); } + public Preferences putString(String key, String val) { return prefs.putString(key, val); } + public void remove(String key) { prefs.remove(key); } + + // Custom Functions + + // Recent Project Manager + // Count: recentHistory + // Array: recent.0, recent.1, recent.2, etc, etc. + private ArrayList recentHistory; + + public void buildRecentHistory() { + recentHistory = new ArrayList(); + for (int i = 0; i < getInteger("recentHistory"); i++) { + if (!contains(String.format("recent.%d",i))) { + break; + } + String project = getString(String.format("recent.%d", i)); + java.io.File file = new java.io.File(project); + if (file.exists() && file.isFile() && file.canRead()) { + recentHistory.add(project); + } + } + } + + public ArrayList getRecentHistory() { + return recentHistory; + } + + public void storeRecentHistory() { + cleanDuplicates(recentHistory); + for (int i = 0; i < recentHistory.size(); i++) + { + if (i > getInteger("recentHistory")) + break; + prefs.remove(String.format("recent.%d",i)); + prefs.putString(String.format("recent.%d",i), recentHistory.get(i)); + } + flush(); + } + + private void cleanDuplicates(ArrayList paths) { + Array duplicates = new Array<>(); + for(int i = 0; i < paths.size()-1; i++) { + if(duplicates.contains(i, false)) continue; + for(int j = i + 1; j < paths.size(); j++) { + if(FilenameUtils.equalsNormalized(paths.get(i), paths.get(j))) { + duplicates.add(j); + } + } + } + duplicates.sort(); + duplicates.reverse(); + for(int i = 0; i < duplicates.size; i++) { + paths.remove((int)duplicates.get(i)); + } + } + + public void pushHistory(String file) { + if (recentHistory.contains(file)) + popHistory(file); + recentHistory.add(0,file); + storeRecentHistory(); + } + + public void popHistory(String file) { + if (recentHistory.contains(file)) { + recentHistory.remove(file); + storeRecentHistory(); + } + } + + public void popHistory() { + recentHistory.remove(-1); + storeRecentHistory(); + } + + public void clearHistory() { + for (int i = 0; i < recentHistory.size(); i++) + { + if (i > getInteger("recentHistory")) + break; + prefs.remove(String.format("recent.%d",i)); + } + flush(); + recentHistory.clear(); + } +} diff --git a/src/main/java/games/rednblack/editor/data/migrations/IVersionMigrator.java b/src/main/java/games/rednblack/editor/data/migrations/IVersionMigrator.java new file mode 100644 index 00000000..aa5cd1c2 --- /dev/null +++ b/src/main/java/games/rednblack/editor/data/migrations/IVersionMigrator.java @@ -0,0 +1,29 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.data.migrations; + +/** + * Created by azakhary on 9/28/2014. + */ +public interface IVersionMigrator { + + public void setProject(String path); + + public boolean doMigration(); +} diff --git a/src/main/java/games/rednblack/editor/data/migrations/ProjectVersionMigrator.java b/src/main/java/games/rednblack/editor/data/migrations/ProjectVersionMigrator.java new file mode 100644 index 00000000..1f3981f7 --- /dev/null +++ b/src/main/java/games/rednblack/editor/data/migrations/ProjectVersionMigrator.java @@ -0,0 +1,110 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.data.migrations; + +import java.io.IOException; + +import games.rednblack.editor.data.migrations.migrators.VersionMigTo009; +import com.vo.ProjectVO; +import org.apache.commons.io.FileUtils; + +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonWriter; +import games.rednblack.editor.data.migrations.migrators.DummyMig; +import games.rednblack.editor.data.migrations.migrators.VersionMigTo005; + +/** + * Created by azakhary on 9/28/2014. + */ +public class ProjectVersionMigrator { + + private String projectPath; + private ProjectVO projectVo; + + private int safetyIterator = 0; + + /** + * this is the current supported version, change when data format is changed, and add migration script + */ + public static String dataFormatVersion = "0.0.9"; + + private Json json = new Json(); + + public ProjectVersionMigrator(String projectPath, ProjectVO projectVo) { + this.projectPath = projectPath; + this.projectVo = projectVo; + + json.setOutputType(JsonWriter.OutputType.json); + } + + public void start() { + + if (projectVo.projectVersion == null || projectVo.projectVersion.equals("")) { + projectVo.projectVersion = "0.0.4"; + } + + migrationIterator(); + } + + private void migrationIterator() { + if (projectVo.projectVersion.equals(dataFormatVersion)) return; + + if (safetyIterator > 100) { + System.out.println("Emergency exit from version migration process due to safety lock"); + return; + } + safetyIterator++; + + if (projectVo.projectVersion.equals("0.0.4")) { + VersionMigTo005 vmt = new VersionMigTo005(); + doMigartion(vmt, "0.0.5"); + } + if (projectVo.projectVersion.equals("0.0.5") || projectVo.projectVersion.equals("0.0.6") || projectVo.projectVersion.equals("0.0.7")) { + DummyMig vmt = new DummyMig(); + doMigartion(vmt, "0.0.8"); + } + if (projectVo.projectVersion.equals("0.0.8")) { + VersionMigTo009 vmt = new VersionMigTo009(); + doMigartion(vmt, "0.0.9"); + } + } + + private void doMigartion(IVersionMigrator vmt, String nextVersion) { + vmt.setProject(projectPath); + + boolean successs = vmt.doMigration(); + + if (successs) { + setVersion(nextVersion); + migrationIterator(); + } else { + return; + } + } + + private void setVersion(String version) { + projectVo.projectVersion = version; + String projectVoJson = json.toJson(projectVo, ProjectVO.class); + try { + FileUtils.writeStringToFile(new java.io.File(projectPath + "/project.pit"), projectVoJson, "utf-8"); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/games/rednblack/editor/data/migrations/migrators/DummyMig.java b/src/main/java/games/rednblack/editor/data/migrations/migrators/DummyMig.java new file mode 100644 index 00000000..55d10132 --- /dev/null +++ b/src/main/java/games/rednblack/editor/data/migrations/migrators/DummyMig.java @@ -0,0 +1,36 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.data.migrations.migrators; + +import games.rednblack.editor.data.migrations.IVersionMigrator; + +/** + * Created by azakhary on 1/29/2015. + */ +public class DummyMig implements IVersionMigrator { + @Override + public void setProject(String path) { + + } + + @Override + public boolean doMigration() { + return true; + } +} diff --git a/src/main/java/games/rednblack/editor/data/migrations/migrators/VersionMigTo005.java b/src/main/java/games/rednblack/editor/data/migrations/migrators/VersionMigTo005.java new file mode 100644 index 00000000..888536e2 --- /dev/null +++ b/src/main/java/games/rednblack/editor/data/migrations/migrators/VersionMigTo005.java @@ -0,0 +1,103 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.data.migrations.migrators; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonReader; +import com.badlogic.gdx.utils.JsonWriter; +import games.rednblack.editor.data.migrations.IVersionMigrator; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.proxy.ResolutionManager; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.data.ResolutionEntryVO; + +/** + * Created by azakhary on 9/28/2014. + */ +public class VersionMigTo005 implements IVersionMigrator { + + private String projectPath; + + private Json json = new Json(); + private JsonReader jsonReader = new JsonReader(); + private HyperLap2DFacade facade; + private ProjectManager projectManager; + + @Override + public void setProject(String path) { + facade = HyperLap2DFacade.getInstance(); + projectManager = facade.retrieveProxy(ProjectManager.NAME); + projectPath = path; + json.setOutputType(JsonWriter.OutputType.json); + } + + @Override + public boolean doMigration() { + + // Rename folder animations to spine-animations in orig (if exist); + File animationsDir = new File(projectPath + File.separator + "assets" + File.separator + "orig" + File.separator + "animations"); + if (animationsDir.exists() && animationsDir.isDirectory()) { + File spineAnimationsDir = new File(projectPath + File.separator + "assets" + File.separator + "orig" + File.separator + "spine-animations"); + animationsDir.renameTo(spineAnimationsDir); + } + + // get list of resolutions + String prjInfoFilePath = projectPath + "/project.dt"; + FileHandle projectInfoFile = Gdx.files.internal(prjInfoFilePath); + String projectInfoContents = null; + try { + projectInfoContents = FileUtils.readFileToString(projectInfoFile.file()); + ProjectInfoVO currentProjectInfoVO = json.fromJson(ProjectInfoVO.class, projectInfoContents); + projectManager.currentProjectInfoVO = currentProjectInfoVO; + + // run through all resolutions and remake animations for all + for (ResolutionEntryVO resolutionEntryVO : currentProjectInfoVO.resolutions) { + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + resolutionManager.createResizedAnimations(resolutionEntryVO); + } + } catch (IOException e) { + e.printStackTrace(); + } + + // change sLights to sLights + File scenesDir = new File(projectPath + File.separator + "scenes"); + for (File entry : scenesDir.listFiles()) { + if (!entry.isDirectory()) { + try { + String content = FileUtils.readFileToString(new FileHandle(entry).file()); + content = content.replaceAll("\"slights\":", "\"sLights\":"); + FileUtils.writeStringToFile(new File(entry.getAbsolutePath()), content, "utf-8"); + } catch (IOException e) { + e.printStackTrace(); + } + + } + } + + return true; + } +} diff --git a/src/main/java/games/rednblack/editor/data/migrations/migrators/VersionMigTo009.java b/src/main/java/games/rednblack/editor/data/migrations/migrators/VersionMigTo009.java new file mode 100644 index 00000000..ce25f6ff --- /dev/null +++ b/src/main/java/games/rednblack/editor/data/migrations/migrators/VersionMigTo009.java @@ -0,0 +1,174 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.data.migrations.migrators; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Json; +import com.badlogic.gdx.utils.JsonReader; +import com.badlogic.gdx.utils.JsonValue; +import com.badlogic.gdx.utils.JsonWriter; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.data.migrations.IVersionMigrator; +import games.rednblack.editor.proxy.ProjectManager; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +/** + * Created by azakhary on 6/29/2015. + */ +public class VersionMigTo009 implements IVersionMigrator { + + private String projectPath; + + private Json json = new Json(); + private JsonReader jsonReader = new JsonReader(); + private HyperLap2DFacade facade; + private ProjectManager projectManager; + + @Override + public void setProject(String path) { + facade = HyperLap2DFacade.getInstance(); + projectManager = facade.retrieveProxy(ProjectManager.NAME); + projectPath = path; + json.setOutputType(JsonWriter.OutputType.json); + } + + @Override + public boolean doMigration() { + // run through scene files and modify their content to new one + + // this is list of libraryItems for later + HashMap libraryItems = new HashMap<>(); + + // fixing animations format (frameRange) and moving library items + File scenesDir = new File(projectPath + File.separator + "scenes"); + for (File entry : scenesDir.listFiles()) { + if (!entry.isDirectory()) { + try { + String content = FileUtils.readFileToString(new FileHandle(entry).file()); + JsonValue value = jsonReader.parse(content); + fixAnimations(value.get("composite")); + if(value.get("libraryItems") != null) { + JsonValue.JsonIterator libraryArr = value.get("libraryItems").iterator(); + while (libraryArr.hasNext()) { + JsonValue libItem = libraryArr.next(); + fixAnimations(libItem.get("composite")); + libraryItems.put(libItem.name, libItem); + } + value.remove("libraryItems"); + } + + content = value.prettyPrint(JsonWriter.OutputType.json, 1); + FileUtils.writeStringToFile(new File(entry.getAbsolutePath()), content, "utf-8"); + } catch (IOException e) { + e.printStackTrace(); + } + + } + } + + fixLibraryItemsLocation(libraryItems); + + return true; + } + + private void fixLibraryItemsLocation(HashMap libraryItems) { + if(libraryItems.size() == 0) return; + //creating libraryArrayJsonString + String libraryArrayJsonString = "{"; + for (JsonValue entry : libraryItems.values()) { + libraryArrayJsonString += "\""+entry.name+"\": " + entry.prettyPrint(JsonWriter.OutputType.json, 1) + ", "; + } + libraryArrayJsonString = libraryArrayJsonString.substring(0,libraryArrayJsonString.length()-2) + "}"; + + //ProjectInfo data + String prjInfoFilePath = projectPath + "/project.dt"; + FileHandle projectInfoFile = Gdx.files.internal(prjInfoFilePath); + try { + String projectInfoContents = FileUtils.readFileToString(projectInfoFile.file()); + JsonValue value = jsonReader.parse(projectInfoContents); + JsonValue newVal = jsonReader.parse(libraryArrayJsonString); + newVal.name = "libraryItems"; + newVal.prev = value.get("scenes"); + newVal.next = newVal.prev.next; + newVal.prev.next = newVal; + + String content = value.prettyPrint(JsonWriter.OutputType.json, 1); + FileUtils.writeStringToFile(new File(prjInfoFilePath), content, "utf-8"); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void fixAnimations(JsonValue value) { + if(value.get("sComposites") == null) return; + + if(value.get("sComposites") != null) { + JsonValue.JsonIterator compositeArray = value.get("sComposites").iterator(); + while (compositeArray.hasNext()) { + JsonValue composite = compositeArray.next(); + if (composite != null) { + fixAnimations(composite.get("composite")); + } + } + } + + if(value.get("sSpriteAnimations") != null) { + JsonValue.JsonIterator spriteArray = value.get("sSpriteAnimations").iterator(); + while (spriteArray.hasNext()) { + JsonValue valAnim = spriteArray.next(); + if (valAnim.get("animations") != null) { + String val = valAnim.get("animations").asString(); + JsonValue animationsInnerJson = jsonReader.parse(val); + JsonValue.JsonIterator innerArray = animationsInnerJson.iterator(); + String cnt = "["; + while (innerArray.hasNext()) { + JsonValue innerVal = innerArray.next(); + int startFrame = innerVal.get("startFrame").asInt(); + int endFrame = innerVal.get("endFrame").asInt(); + String currName = innerVal.get("name").asString(); + cnt += "{\"name\":\""+currName+"\", \"startFrame\":"+startFrame+", \"endFrame\":"+endFrame+"}, "; + } + if(cnt.length() == 1) { + cnt = "[]"; + } else { + cnt = cnt.substring(0, cnt.length() - 2) + "]"; + } + JsonValue newVal = jsonReader.parse(cnt); + setNewKeyToJson(valAnim, "frameRangeMap", "animations", newVal); + } + } + } + } + + private void setNewKeyToJson(JsonValue container, String newKey, String oldKey, JsonValue newVal) { + JsonValue oldVal = container.get(oldKey); + if(oldVal.prev != null) oldVal.prev.setNext(newVal); + if(oldVal.next != null) oldVal.next.setPrev(newVal); + newVal.setPrev(oldVal.prev); + newVal.setNext(oldVal.next); + newVal.name = newKey; + } + +} diff --git a/src/main/java/games/rednblack/editor/event/ButtonToNotificationListener.java b/src/main/java/games/rednblack/editor/event/ButtonToNotificationListener.java new file mode 100644 index 00000000..44b17877 --- /dev/null +++ b/src/main/java/games/rednblack/editor/event/ButtonToNotificationListener.java @@ -0,0 +1,22 @@ +package games.rednblack.editor.event; + +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by azakhary on 7/2/2015. + */ +public class ButtonToNotificationListener extends ClickListener{ + + private String notificationName; + + public ButtonToNotificationListener(String notificationName) { + this.notificationName = notificationName; + } + + public void touchUp(InputEvent event, float x, float y, int pointer, int button) { + super.touchUp(event, x, y, pointer, button); + HyperLap2DFacade.getInstance().sendNotification(notificationName); + } +} diff --git a/src/main/java/games/rednblack/editor/event/CheckBoxChangeListener.java b/src/main/java/games/rednblack/editor/event/CheckBoxChangeListener.java new file mode 100644 index 00000000..561a5a8d --- /dev/null +++ b/src/main/java/games/rednblack/editor/event/CheckBoxChangeListener.java @@ -0,0 +1,42 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.event; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.kotcrab.vis.ui.widget.VisCheckBox; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by azakhary on 4/16/2015. + */ +public class CheckBoxChangeListener extends ChangeListener { + + private final String eventName; + + public CheckBoxChangeListener(String eventName) { + this.eventName = eventName; + } + + @Override + public void changed(ChangeEvent changeEvent, Actor actor) { + HyperLap2DFacade facade = HyperLap2DFacade.getInstance(); + facade.sendNotification(eventName, ((VisCheckBox) actor).isChecked()); + } +} \ No newline at end of file diff --git a/src/main/java/games/rednblack/editor/event/ClickNotifier.java b/src/main/java/games/rednblack/editor/event/ClickNotifier.java new file mode 100644 index 00000000..b774bf3e --- /dev/null +++ b/src/main/java/games/rednblack/editor/event/ClickNotifier.java @@ -0,0 +1,41 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.event; + +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by azakhary on 4/29/2015. + */ +public class ClickNotifier extends ClickListener { + + private final String eventName; + + public ClickNotifier(String eventName) { + this.eventName = eventName; + } + + @Override + public void clicked(InputEvent event, float x, float y) { + HyperLap2DFacade facade = HyperLap2DFacade.getInstance(); + facade.sendNotification(eventName); + } +} diff --git a/src/main/java/games/rednblack/editor/event/EditableSelectBoxChangeListener.java b/src/main/java/games/rednblack/editor/event/EditableSelectBoxChangeListener.java new file mode 100644 index 00000000..13451454 --- /dev/null +++ b/src/main/java/games/rednblack/editor/event/EditableSelectBoxChangeListener.java @@ -0,0 +1,48 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.event; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.view.ui.widget.EditableSelectBox; + +/** + * Created by azakhary on 4/30/2015. + */ +public class EditableSelectBoxChangeListener extends ChangeListener { + + private final String eventName; + + private String lastSelected = ""; + + public EditableSelectBoxChangeListener(String eventName) { + this.eventName = eventName; + } + + @Override + public void changed(ChangeEvent changeEvent, Actor actor) { + HyperLap2DFacade facade = HyperLap2DFacade.getInstance(); + String selected = ((EditableSelectBox) actor).getSelected(); + if(!lastSelected.equals(selected)) { + lastSelected = selected; + facade.sendNotification(eventName, selected); + } + } +} \ No newline at end of file diff --git a/src/main/java/games/rednblack/editor/event/KeyboardListener.java b/src/main/java/games/rednblack/editor/event/KeyboardListener.java new file mode 100644 index 00000000..256761a1 --- /dev/null +++ b/src/main/java/games/rednblack/editor/event/KeyboardListener.java @@ -0,0 +1,97 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.event; + +import com.badlogic.gdx.Input; +import com.badlogic.gdx.scenes.scene2d.Event; +import com.badlogic.gdx.scenes.scene2d.EventListener; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.utils.FocusListener; +import com.kotcrab.vis.ui.widget.VisTextField; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by azakhary on 4/15/2015. + */ +public class KeyboardListener implements EventListener { + + private final String eventName; + + private String lastValue; + + public KeyboardListener(String eventName) { + this.eventName = eventName; + } + + @Override + public boolean handle(Event event) { + if (event instanceof FocusListener.FocusEvent) { + handleFocusListener((FocusListener.FocusEvent) event); + return true; + } + if (event instanceof InputEvent) { + handleInputListener((InputEvent) event); + return true; + } + return false; + } + + private void handleInputListener(InputEvent event) { + switch (event.getType()) { + case keyUp: + if (event.getKeyCode() == Input.Keys.ENTER) { + keyboardHandler((VisTextField) event.getTarget()); + VisTextField field = (VisTextField) event.getTarget(); + lastValue = field.getText(); + } + break; + } + } + + private void handleFocusListener(FocusListener.FocusEvent event) { + VisTextField field = (VisTextField) event.getTarget(); + if(event.isFocused()) { + //it was a focus in event, which is no change + lastValue = field.getText(); + return; + } + switch (event.getType()) { + case keyboard: + keyboardHandler(field); + break; + case scroll: + break; + } + + } + + private void keyboardHandler(VisTextField target) { + if(!target.isInputValid()) { + return; + } + // check for change + if(lastValue.equals(target.getText())) { + // no change = no event; + return; + } + + HyperLap2DFacade facade = HyperLap2DFacade.getInstance(); + facade.sendNotification(eventName, target.getText()); + } +} \ No newline at end of file diff --git a/src/main/java/games/rednblack/editor/event/MenuItemListener.java b/src/main/java/games/rednblack/editor/event/MenuItemListener.java new file mode 100644 index 00000000..f11a0a5f --- /dev/null +++ b/src/main/java/games/rednblack/editor/event/MenuItemListener.java @@ -0,0 +1,48 @@ +package games.rednblack.editor.event; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by CyberJoe on 4/21/2015. + */ + +public class MenuItemListener extends ChangeListener { + + private final String menuCommand; + private final String menuType; + private final Object data; + + private HyperLap2DFacade facade; + + public MenuItemListener(String menuCommand) { + this(menuCommand, null, null); + } + + public MenuItemListener(String menuCommand, String data) { + this(menuCommand, data, null); + } + + public MenuItemListener(String menuCommand, Object data, String menuType) { + this.menuCommand = menuCommand; + this.data = data; + this.menuType = menuType; + + facade = HyperLap2DFacade.getInstance(); + } + + @Override + public void changed(ChangeEvent event, Actor actor) { + if(menuType == null) { + if(data == null) { + facade.sendNotification(menuCommand); + } else { + facade.sendNotification(menuCommand, data); + } + } else { + facade.sendNotification(menuCommand, data, menuType); + } + + } +} \ No newline at end of file diff --git a/src/main/java/games/rednblack/editor/event/NumberSelectorOverlapListener.java b/src/main/java/games/rednblack/editor/event/NumberSelectorOverlapListener.java new file mode 100644 index 00000000..2d1a4652 --- /dev/null +++ b/src/main/java/games/rednblack/editor/event/NumberSelectorOverlapListener.java @@ -0,0 +1,42 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.event; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.kotcrab.vis.ui.widget.spinner.Spinner; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by azakhary on 6/12/2015. + */ +public class NumberSelectorOverlapListener extends ChangeListener { + + private final String eventName; + + public NumberSelectorOverlapListener(String eventName) { + this.eventName = eventName; + } + + @Override + public void changed(ChangeEvent event, Actor actor) { + HyperLap2DFacade facade = HyperLap2DFacade.getInstance(); + facade.sendNotification(eventName, ((Spinner)actor).getTextField().getText()); + } +} diff --git a/src/main/java/games/rednblack/editor/event/SelectBoxChangeListener.java b/src/main/java/games/rednblack/editor/event/SelectBoxChangeListener.java new file mode 100644 index 00000000..94ad52e6 --- /dev/null +++ b/src/main/java/games/rednblack/editor/event/SelectBoxChangeListener.java @@ -0,0 +1,48 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.event; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.kotcrab.vis.ui.widget.VisSelectBox; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by azakhary on 4/16/2015. + */ +public class SelectBoxChangeListener extends ChangeListener { + + private final String eventName; + + private String lastSelected = ""; + + public SelectBoxChangeListener(String eventName) { + this.eventName = eventName; + } + + @Override + public void changed(ChangeEvent changeEvent, Actor actor) { + HyperLap2DFacade facade = HyperLap2DFacade.getInstance(); + String selected = (String) ((VisSelectBox) actor).getSelected(); + if(!lastSelected.equals(selected)) { + lastSelected = selected; + facade.sendNotification(eventName, selected); + } + } +} diff --git a/src/main/java/games/rednblack/editor/factory/ItemFactory.java b/src/main/java/games/rednblack/editor/factory/ItemFactory.java new file mode 100644 index 00000000..59d55e0b --- /dev/null +++ b/src/main/java/games/rednblack/editor/factory/ItemFactory.java @@ -0,0 +1,259 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.factory; + +import com.badlogic.ashley.core.Engine; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.PasteItemsCommand; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.proxy.ResourceManager; +import games.rednblack.editor.renderer.SceneLoader; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.MainItemComponent; +import games.rednblack.editor.renderer.data.*; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.view.stage.tools.TextTool; +import games.rednblack.editor.view.ui.box.UILayerBoxMediator; + +import java.util.HashMap; + +/** + * Created by azakhary on 6/5/2015. + * + */ +public class ItemFactory { + + private EntityFactory entityFactory; + private SceneLoader sceneLoader; + private Sandbox sandbox; + private Entity imageEntity; + + private static ItemFactory instance; + + private ItemFactory(SceneLoader sceneLoader) { + this.sceneLoader = sceneLoader; + entityFactory = sceneLoader.getEntityFactory(); + sandbox = Sandbox.getInstance(); + } + + public static ItemFactory get() { + if(instance == null) { + instance = new ItemFactory(Sandbox.getInstance().sceneControl.sceneLoader); + } + + return instance; + } + + private boolean setEssentialData(MainItemVO vo, Vector2 position) { + UILayerBoxMediator layerBoxMediator = HyperLap2DFacade.getInstance().retrieveMediator(UILayerBoxMediator.NAME); + String layerName = layerBoxMediator.getCurrentSelectedLayerName(); + + if(layerName == null) return false; + + vo.layerName = layerName; + + // This is for grid + position.x = MathUtils.floor(position.x / sandbox.getWorldGridSize()) * sandbox.getWorldGridSize(); + position.y = MathUtils.floor(position.y / sandbox.getWorldGridSize()) * sandbox.getWorldGridSize(); + + vo.x = position.x; + vo.y = position.y; + + return true; + } + + public boolean createSimpleImage(String regionName, Vector2 position) { + SimpleImageVO vo = new SimpleImageVO(); + vo.imageName = regionName; + + if(!setEssentialData(vo, position)) return false; + imageEntity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, imageEntity); + + return true; + } + + public Entity getImageEntity() { + return imageEntity; + } + + public boolean create9Patch(String regionName, Vector2 position) { + Image9patchVO vo = new Image9patchVO(); + vo.imageName = regionName; + + if(!setEssentialData(vo, position)) return false; + Entity entity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, entity); + + return true; + } + + public boolean createSpriteAnimation(String animationName, Vector2 position) { + SpriteAnimationVO vo = new SpriteAnimationVO(); + vo.animationName = animationName; + vo.playMode = 2; + + if(!setEssentialData(vo, position)) return false; + Entity entity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, entity); + + return true; + } + + public boolean createSpineAnimation(String animationName, Vector2 position) { + SpineVO vo = new SpineVO(); + vo.animationName = animationName; + + if(!setEssentialData(vo, position)) return false; + Entity entity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, entity); + + return true; + } + + public boolean createSpriterAnimation(String animationName, Vector2 position) { + SpriterVO vo = new SpriterVO(); + vo.animationName = animationName; + + if(!setEssentialData(vo, position)) return false; + Entity entity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, entity); + + return true; + } + + public boolean createPrimitive(Vector2 position, ShapeVO shape) { + ColorPrimitiveVO vo = new ColorPrimitiveVO(); + vo.shape = shape.clone(); + vo.originX = 0; + vo.originY = 0; + + if(!setEssentialData(vo, position)) return false; + Entity entity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, entity); + + return true; + } + + public boolean createItemFromLibrary(String libraryName, Vector2 position) { + ProjectManager projectManager = HyperLap2DFacade.getInstance().retrieveProxy(ProjectManager.NAME); + HashMap libraryItems = projectManager.currentProjectInfoVO.libraryItems; + + CompositeItemVO itemVO = libraryItems.get(libraryName); + itemVO.uniqueId = -1; + PasteItemsCommand.forceIdChange(itemVO.composite); + Entity entity = createCompositeItem(itemVO, position); + + if (entity == null) return false; + + //adding library name + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + mainItemComponent.libraryLink = libraryName; + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, entity); + + return true; + } + + public Entity createCompositeItem(CompositeItemVO vo, Vector2 position) { + if(!setEssentialData(vo, position)) return null; + + Entity entity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + Engine engine = sceneLoader.engine; + EntityFactory factory = sceneLoader.entityFactory; + factory.initAllChildren(engine, entity, vo.composite); + + return entity; + } + + public Entity createCompositeItem(Vector2 position) { + CompositeItemVO vo = new CompositeItemVO(); + Entity entity = createCompositeItem(vo, position); + return entity; + } + + public Entity createLightItem(LightVO vo, Vector2 position) { + if(!setEssentialData(vo, position)) return null; + Entity entity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, entity); +/* + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + float boundBoxSize = 10f; + dimensionsComponent.boundBox = new Rectangle(-boundBoxSize / 2f, -boundBoxSize / 2f, boundBoxSize, boundBoxSize);*/ + + + return entity; + } + + public boolean tryCreateParticleItem(String particleName, Vector2 position) { + Entity entity = createParticleItem(particleName, position); + + /* DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + float boundBoxSize = 10f; + dimensionsComponent.boundBox = new Rectangle(-boundBoxSize / 2f, -boundBoxSize / 2f, boundBoxSize, boundBoxSize);*/ + + if(entity == null) return false; + + return true; + } + + public Entity createParticleItem(String particleName, Vector2 position) { + ParticleEffectVO vo = new ParticleEffectVO(); + vo.particleName = particleName; + + if(!setEssentialData(vo, position)) return null; + Entity entity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, entity); + + return entity; + } + + public Entity createLabel(TextTool textSettings, Vector2 position) { + LabelVO vo = new LabelVO(); + if(!setEssentialData(vo, position)) return null; + + HyperLap2DFacade facade = HyperLap2DFacade.getInstance(); + ResourceManager resourceManager = facade.retrieveProxy(ResourceManager.NAME); + + resourceManager.prepareEmbeddingFont(textSettings.getFontFamily(), textSettings.getFontSize()); + + // using long unique name + vo.style = textSettings.getFontFamily(); + vo.text = "LABEL"; + vo.size = textSettings.getFontSize(); + + // need to calculate minimum bounds size here + vo.width = 120f/Sandbox.getInstance().getPixelPerWU(); + vo.height = 50f/Sandbox.getInstance().getPixelPerWU(); + + Entity entity = entityFactory.createEntity(sandbox.getCurrentViewingEntity(), vo); + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_CREATE_ITEM, entity); + + return entity; + } +} diff --git a/src/main/java/games/rednblack/editor/proxy/CommandManager.java b/src/main/java/games/rednblack/editor/proxy/CommandManager.java new file mode 100644 index 00000000..cbc85d76 --- /dev/null +++ b/src/main/java/games/rednblack/editor/proxy/CommandManager.java @@ -0,0 +1,112 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.proxy; + +import java.util.ArrayList; + +import com.puremvc.patterns.proxy.BaseProxy; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.EntityModifyRevertableCommand; +import games.rednblack.editor.controller.commands.RevertableCommand; +import games.rednblack.editor.controller.commands.TransactiveCommand; +import games.rednblack.editor.view.stage.Sandbox; + +/** + * Created by azakhary on 5/14/2015. + */ +public class CommandManager extends BaseProxy { + private static final String TAG = CommandManager.class.getCanonicalName(); + public static final String NAME = TAG; + + private int cursor = -1; + private int modifiedCursor = 0; + + private ArrayList commands = new ArrayList<>(); + + public CommandManager() { + super(NAME); + } + + @Override + public void onRegister() { + super.onRegister(); + facade = HyperLap2DFacade.getInstance(); + } + + public void addCommand(RevertableCommand revertableCommand) { + //remove all commands after the cursor + for(int i = commands.size()-1; i > cursor; i--) { + commands.remove(i); + } + commands.add(revertableCommand); + cursor = commands.indexOf(revertableCommand); + if (revertableCommand instanceof EntityModifyRevertableCommand + || revertableCommand instanceof TransactiveCommand) { + modifiedCursor++; + } + + updateWindowTitle(); + } + + public void undoCommand() { + updateWindowTitle(); + + if(cursor < 0) return; + RevertableCommand command = commands.get(cursor); + if(command.isStateDone()) { + command.callUndoAction(); + command.setStateDone(false); + } + cursor--; + + if (command instanceof EntityModifyRevertableCommand + || command instanceof TransactiveCommand) { + modifiedCursor--; + } + } + + public void saveEvent() { + modifiedCursor = 0; + updateWindowTitle(); + } + + public void updateWindowTitle() { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + projectManager.appendSaveHintTitle(modifiedCursor > 0); + } + + public boolean isModified() { + return modifiedCursor > 0; + } + + public void redoCommand() { + if(cursor + 1 >= commands.size()) return; + RevertableCommand command = commands.get(cursor+1); + if(!command.isStateDone()) { + cursor++; + command.callDoAction(); + command.setStateDone(true); + } + } + + public void clearHistory() { + cursor = -1; + commands.clear(); + } +} diff --git a/src/main/java/games/rednblack/editor/proxy/CursorManager.java b/src/main/java/games/rednblack/editor/proxy/CursorManager.java new file mode 100644 index 00000000..d2986b0a --- /dev/null +++ b/src/main/java/games/rednblack/editor/proxy/CursorManager.java @@ -0,0 +1,108 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.proxy; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Cursor; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.puremvc.patterns.proxy.BaseProxy; +import com.vo.CursorData; + +/** + * Created by azakhary on 5/15/2015. + */ +public class CursorManager extends BaseProxy { + private static final String TAG = CursorManager.class.getCanonicalName(); + public static final String NAME = TAG; + + public static CursorData NORMAL = new CursorData(Cursor.SystemCursor.Arrow); + public static CursorData CROSS = new CursorData("cross", 14, 14); + public static CursorData TEXT = new CursorData(Cursor.SystemCursor.Ibeam); + public static CursorData TEXT_TOOL = new CursorData("label-tool", 15, 17); + public static CursorData FINGER = new CursorData("fingerpoint", 16, 9); + public static CursorData EYEDROPPER = new CursorData("eyedropper", 10, 23); + public static CursorData HAND = new CursorData(Cursor.SystemCursor.Hand); + + public static CursorData ROTATION_LB = new CursorData("left-rotate-down", 15, 18); + public static CursorData ROTATION_LT = new CursorData("left-rotate-up", 15, 15); + public static CursorData ROTATION_RT = new CursorData("right-rotate-up", 18, 15); + public static CursorData ROTATION_RB = new CursorData("right-rotate-down", 18, 18); + + public static CursorData TRANSFORM_LEFT_RIGHT = new CursorData("left-down-up", 17, 16); + public static CursorData TRANSFORM_RIGHT_LEFT = new CursorData("right-down-up", 17, 16); + public static CursorData TRANSFORM_HORIZONTAL = new CursorData("left-right", 17, 16); + public static CursorData TRANSFORM_VERTICAL = new CursorData("up-down", 17, 16); + + private CursorData cursor; + private CursorData overrideCursor = null; + + public CursorManager() { + super(NAME); + + setCursor(NORMAL); + } + + public void setCursor(CursorData cursor, TextureRegion region) { + this.cursor = cursor; + + setCursorPixmap(region); + } + + public void setCursor(CursorData cursor) { + setCursor(cursor, null); + } + + public void setOverrideCursor(CursorData cursor) { + overrideCursor = cursor; + setCursorPixmap(null); + } + + public void removeOverrideCursor() { + setOverrideCursor(null); + } + + private void setCursorPixmap(TextureRegion region) { + CursorData currentCursor = overrideCursor; + if(currentCursor == null) { + currentCursor = cursor; + } + + if (currentCursor.systemCursor != null) { + Gdx.graphics.setSystemCursor(currentCursor.systemCursor); + return; + } + + Pixmap cursorPm; + if (region == null) { + cursorPm = new Pixmap(Gdx.files.internal("cursors/" + currentCursor.region + ".png")); + } else { + Texture texture = region.getTexture(); + if (!texture.getTextureData().isPrepared()) { + texture.getTextureData().prepare(); + } + cursorPm = texture.getTextureData().consumePixmap(); + } + + Cursor cursorObj = Gdx.graphics.newCursor(cursorPm, currentCursor.getHotspotX(), currentCursor.getHotspotY()); + Gdx.graphics.setCursor(cursorObj); + cursorPm.dispose(); + } +} diff --git a/src/main/java/games/rednblack/editor/proxy/EditorTextureManager.java b/src/main/java/games/rednblack/editor/proxy/EditorTextureManager.java new file mode 100644 index 00000000..e3b7b08a --- /dev/null +++ b/src/main/java/games/rednblack/editor/proxy/EditorTextureManager.java @@ -0,0 +1,70 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.proxy; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.puremvc.patterns.proxy.BaseProxy; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.utils.MySkin; + + +public class EditorTextureManager extends BaseProxy { + private static final String TAG = EditorTextureManager.class.getCanonicalName(); + public static final String NAME = TAG; + + private Texture pixel; + + public MySkin editorSkin; + private TextureAtlas editorAtlas; + + public EditorTextureManager() { + super(NAME); + } + + @Override + public void onRegister() { + super.onRegister(); + facade = HyperLap2DFacade.getInstance(); + loadEditorAssets(); + } + + public void loadEditorAssets() { + Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888); + pixmap.setColor(Color.WHITE); + pixmap.fill(); + pixel = new Texture(pixmap); + } + + public Texture getEditorAsset(String name) { + return pixel; + } + + public TextureAtlas getEditorAssetsList() { + return editorAtlas; + } + + public void dispose() { + + } + + +} diff --git a/src/main/java/games/rednblack/editor/proxy/FontManager.java b/src/main/java/games/rednblack/editor/proxy/FontManager.java new file mode 100644 index 00000000..c406c41d --- /dev/null +++ b/src/main/java/games/rednblack/editor/proxy/FontManager.java @@ -0,0 +1,196 @@ +package games.rednblack.editor.proxy; + +import java.awt.Font; +import java.awt.FontFormatException; +//import java.awt.GraphicsEnvironment; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.SystemUtils; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Preferences; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.utils.Array; +import com.puremvc.patterns.proxy.BaseProxy; +import games.rednblack.editor.HyperLap2DFacade; + +/** + * Created by azakhary on 4/24/2015. + */ +public class FontManager extends BaseProxy { + + private static final String TAG = FontManager.class.getCanonicalName(); + public static final String NAME = TAG; + + private static final String cache_name = "hyperlap2d-fonts-cache"; + + private Preferences prefs; + + private HashMap systemFontMap = new HashMap<>(); + + public FontManager() { + super(NAME); + } + + @Override + public void onRegister() { + super.onRegister(); + facade = HyperLap2DFacade.getInstance(); + prefs = Gdx.app.getPreferences(cache_name); + generateFontsMap(); + } + + /*public String[] getSystemFontNames() { + return GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); + }*/ + + public String[] getSystemFontsPaths() { + String[] result; + if (SystemUtils.IS_OS_WINDOWS) { + result = new String[1]; + String path = System.getenv("WINDIR"); + result[0] = path + "\\" + "Fonts"; + return result; + } else if (SystemUtils.IS_OS_MAC_OSX || SystemUtils.IS_OS_MAC) { + result = new String[3]; + result[0] = System.getProperty("user.home") + File.separator + "Library/Fonts"; + result[1] = "/Library/Fonts"; + result[2] = "/System/Library/Fonts"; + return result; + } else if (SystemUtils.IS_OS_LINUX) { + String[] pathsToCheck = { + System.getProperty("user.home") + File.separator + ".fonts", + "/usr/share/fonts/truetype", + "/usr/share/fonts/TTF" + }; + ArrayList resultList = new ArrayList<>(); + + for (int i = pathsToCheck.length - 1; i >= 0; i--) { + String path = pathsToCheck[i]; + File tmp = new File(path); + if (tmp.exists() && tmp.isDirectory() && tmp.canRead()) { + resultList.add(path); + } + } + + if (resultList.isEmpty()) { + // TODO: show user warning, TextTool will be crash editor, because system font directories not found + result = new String[0]; + } + else { + result = new String[resultList.size()]; + result = resultList.toArray(result); + } + + return result; + } + + return null; + } + + public List getSystemFontFiles() { + // only retrieving ttf files + String[] extensions = new String[]{"ttf", "TTF"}; + String[] paths = getSystemFontsPaths(); + + ArrayList files = new ArrayList<>(); + + for (int i = 0; i < paths.length; i++) { + File fontDirectory = new File(paths[i]); + if (!fontDirectory.exists()) break; + files.addAll(FileUtils.listFiles(fontDirectory, extensions, true)); + } + + return files; + } + + public void preCacheSystemFontsMap() { + List fontFiles = getSystemFontFiles(); + + for (File file : fontFiles) { + Font f = null; + try { + if (!systemFontMap.containsValue(file.getAbsolutePath())) { + f = Font.createFont(Font.TRUETYPE_FONT, new FileInputStream(file.getAbsolutePath())); + String name = f.getFamily(); + systemFontMap.put(name, file.getAbsolutePath()); + } + } catch (FontFormatException e) { + //e.printStackTrace(); + } catch (IOException e) { + //e.printStackTrace(); + } + } + + prefs.put(systemFontMap); + prefs.flush(); + } + + public void loadCachedSystemFontMap() { + systemFontMap = (HashMap) prefs.get(); + } + + /*public void invalidateFontMap() { + Array names = new Array<>(getSystemFontNames()); + for (Iterator> it = systemFontMap.entrySet().iterator(); it.hasNext(); ) { + Map.Entry entry = it.next(); + if (!names.contains(entry.getKey(), false)) { + it.remove(); + } + } + }*/ + + public void generateFontsMap() { + loadCachedSystemFontMap(); + preCacheSystemFontsMap(); + //invalidateFontMap(); + } + + public HashMap getFontsMap() { + return systemFontMap; + } + + public Array getFontNamesFromMap() { + AlphabeticalComparator comparator = new AlphabeticalComparator(); + Array fontNames = new Array<>(); + + for (Map.Entry entry : systemFontMap.entrySet()) { + fontNames.add(entry.getKey()); + } + fontNames.sort(comparator); + + return fontNames; + } + + public FileHandle getTTFByName(String fontName) { + return new FileHandle(systemFontMap.get(fontName)); + } + + public String getShortName(String longName) { + String path = systemFontMap.get(longName); + return FilenameUtils.getBaseName(path); + } + + public String getFontFilePath(String fontFaily) { + return systemFontMap.get(fontFaily); + } + + + public class AlphabeticalComparator implements Comparator { + + @Override + public int compare(String o1, String o2) { + return o1.compareTo(o2); + } + } +} diff --git a/src/main/java/games/rednblack/editor/proxy/PluginManager.java b/src/main/java/games/rednblack/editor/proxy/PluginManager.java new file mode 100644 index 00000000..44b43126 --- /dev/null +++ b/src/main/java/games/rednblack/editor/proxy/PluginManager.java @@ -0,0 +1,258 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.proxy; + +import com.badlogic.ashley.core.Engine; +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.utils.Array; +import games.rednblack.h2d.common.IItemCommand; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.h2d.common.plugins.H2DPlugin; +import games.rednblack.h2d.common.plugins.PluginAPI; +import games.rednblack.h2d.common.view.tools.Tool; +import com.kotcrab.vis.ui.widget.VisImageButton; +import com.puremvc.patterns.facade.Facade; +import com.puremvc.patterns.proxy.BaseProxy; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.controller.commands.PluginItemCommand; +import games.rednblack.editor.factory.ItemFactory; +import games.rednblack.editor.renderer.SceneLoader; +import games.rednblack.editor.renderer.data.LayerItemVO; +import games.rednblack.editor.renderer.data.SceneVO; +import games.rednblack.editor.utils.runtime.EntityUtils; +import games.rednblack.editor.view.menu.HyperLap2DMenuBarMediator; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.view.stage.SandboxMediator; +import games.rednblack.editor.view.ui.FollowersUIMediator; +import games.rednblack.editor.view.ui.UIDropDownMenu; +import games.rednblack.editor.view.ui.UIDropDownMenuMediator; +import games.rednblack.editor.view.ui.box.UILayerBoxMediator; +import games.rednblack.editor.view.ui.box.UIToolBoxMediator; +import com.vo.CursorData; + +import java.util.*; + +/** + * Created by azakhary on 7/24/2015. + */ +public class PluginManager extends BaseProxy implements PluginAPI { + private static final String TAG = PluginManager.class.getCanonicalName(); + public static final String NAME = TAG; + + private ArrayList plugins = new ArrayList<>(); + private String pluginDir; + + private HashSet pluginEntities; + + public PluginManager() { + super(NAME); + facade = HyperLap2DFacade.getInstance(); + } + + public H2DPlugin registerPlugin(H2DPlugin plugin) { + plugins.add(plugin); + + return plugin; + } + + public void initPlugin(H2DPlugin plugin) { + if(plugins.contains(plugin)) return; + + registerPlugin(plugin); + plugin.setAPI(this); + plugin.initPlugin(); + } + + public void dropDownActionSets(Set selectedEntities, Array actionsSet) { + for(H2DPlugin plugin: plugins) { + plugin.onDropDownOpen(selectedEntities, actionsSet); + } + } + + public void setDropDownItemName(String action, String name) { + UIDropDownMenuMediator dropDownMenuMediator = facade.retrieveMediator(UIDropDownMenuMediator.NAME); + dropDownMenuMediator.getViewComponent().setActionName(action, name); + } + + @Override + public String getProjectPath() { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + return projectManager.getCurrentProjectPath(); + } + + @Override + public TextureAtlas getProjectTextureAtlas() { + ResourceManager resourceManager = facade.retrieveProxy(ResourceManager.NAME); + return resourceManager.getTextureAtlas(); + } + + @Override + public void reLoadProject() { + Sandbox sandbox = Sandbox.getInstance(); + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + projectManager.openProjectAndLoadAllData(projectManager.getCurrentProjectPath()); + sandbox.loadCurrentProject(); + facade.sendNotification(ProjectManager.PROJECT_DATA_UPDATED); + } + + @Override + public void saveProject() { + Sandbox sandbox = Sandbox.getInstance(); + SceneDataManager sceneDataManager = facade.retrieveProxy(SceneDataManager.NAME); + SceneVO vo = sandbox.sceneVoFromItems(); + sceneDataManager.saveScene(vo); + } + + @Override + public void revertableCommand(IItemCommand command, Object body) { + Object payload = PluginItemCommand.build(command, body); + facade.sendNotification(MsgAPI.ACTION_PLUGIN_PROXY_COMMAND, payload); + } + + @Override + public void removeFollower(Entity entity) { + FollowersUIMediator followersUIMediator = HyperLap2DFacade.getInstance().retrieveMediator(FollowersUIMediator.NAME); + followersUIMediator.removeFollower(entity); + } + + public void addMenuItem(String menu, String subMenuName, String notificationName) { + HyperLap2DMenuBarMediator hyperlap2DMenuBarMediator = facade.retrieveMediator(HyperLap2DMenuBarMediator.NAME); + hyperlap2DMenuBarMediator.addMenuItem(menu, subMenuName, notificationName); + } + + @Override + public void addTool(String toolName, VisImageButton.VisImageButtonStyle toolBtnStyle, boolean addSeparator, Tool tool) { + UIToolBoxMediator uiToolBoxMediator = facade.retrieveMediator(UIToolBoxMediator.NAME); + uiToolBoxMediator.addTool(toolName, toolBtnStyle, addSeparator, tool); + Map.Entry toolPair = new Map.Entry() { + @Override + public String getKey() { + return toolName; + } + + @Override + public Tool getValue() { + return tool; + } + + @Override + public Tool setValue(Tool value) { + Tool old = getValue(); + setValue(value); + return old; + } + }; + facade.sendNotification(MsgAPI.NEW_TOOL_ADDED, toolPair); + } + + @Override + public void toolHotSwap(Tool tool) { + SandboxMediator sandboxMediator = facade.retrieveMediator(SandboxMediator.NAME); + sandboxMediator.toolHotSwap(tool); + } + + @Override + public void toolHotSwapBack() { + SandboxMediator sandboxMediator = facade.retrieveMediator(SandboxMediator.NAME); + sandboxMediator.toolHotSwapBack(); + } + + public void setPluginDir(String pluginDir) { + this.pluginDir = pluginDir; + } + + + @Override + public String getPluginDir() { + return pluginDir; + } + + @Override + public SceneLoader getSceneLoader() { + return Sandbox.getInstance().getSceneControl().sceneLoader; + } + + @Override + public Facade getFacade() { + return facade; + } + + @Override + public Engine getEngine() { + return getSceneLoader().getEngine(); + } + + @Override + public Stage getUIStage() { + return Sandbox.getInstance().getUIStage(); + } + + @Override + public Entity drawImage(String regionName, Vector2 position) { + ItemFactory itemFactory = ItemFactory.get(); + itemFactory.createSimpleImage(regionName, position); + return itemFactory.getImageEntity(); + } + + public boolean isEntityVisible(Entity e) { + LayerItemVO layer = EntityUtils.getEntityLayer(e); + return layer != null && layer.isVisible; + } + + @Override + public HashSet getProjectEntities() { + Sandbox sandbox = Sandbox.getInstance(); + return sandbox.getSelector().getAllFreeItems(); + } + + @Override + public void showPopup(HashMap actionsSet, Object observable) { + UIDropDownMenu uiDropDownMenu = new UIDropDownMenu(); + actionsSet.entrySet().forEach(entry -> uiDropDownMenu.setActionName(entry.getKey(), entry.getValue())); + + Array actions = new Array<>(); + actionsSet.keySet().forEach(key -> actions.add(key)); + uiDropDownMenu.setActionList(actions); + + Vector2 coordinates = new Vector2(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY()); + uiDropDownMenu.setX(coordinates.x); + uiDropDownMenu.setY(coordinates.y - uiDropDownMenu.getHeight()); + getUIStage().addActor(uiDropDownMenu); + + UIDropDownMenuMediator dropDownMenuMediator = facade.retrieveMediator(UIDropDownMenuMediator.NAME); + dropDownMenuMediator.setCurrentObservable(observable); + } + + @Override + public void setCursor(CursorData cursorData, TextureRegion region) { + CursorManager cursorManager = HyperLap2DFacade.getInstance().retrieveProxy(CursorManager.NAME); + cursorManager.setCursor(cursorData, region); + } + + @Override + public String getCurrentSelectedLayerName() { + UILayerBoxMediator uiLayerBoxMediator = facade.retrieveMediator(UILayerBoxMediator.NAME); + return uiLayerBoxMediator.getViewComponent().getCurrentSelectedLayer().getLayerName(); + } +} diff --git a/src/main/java/games/rednblack/editor/proxy/ProjectManager.java b/src/main/java/games/rednblack/editor/proxy/ProjectManager.java new file mode 100755 index 00000000..3018388d --- /dev/null +++ b/src/main/java/games/rednblack/editor/proxy/ProjectManager.java @@ -0,0 +1,1323 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.proxy; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.tools.texturepacker.TexturePacker; +import com.badlogic.gdx.tools.texturepacker.TexturePacker.Settings; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Json; +import com.google.common.collect.Lists; +import com.kotcrab.vis.ui.util.dialog.Dialogs; +import com.puremvc.patterns.proxy.BaseProxy; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.data.manager.PreferencesManager; +import games.rednblack.editor.data.migrations.ProjectVersionMigrator; +import games.rednblack.editor.renderer.data.*; +import games.rednblack.editor.renderer.utils.MySkin; +import games.rednblack.editor.utils.HyperLap2DUtils; +import games.rednblack.editor.view.menu.HyperLap2DMenuBar; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.view.ui.widget.ProgressHandler; +import com.vo.EditorConfigVO; +import com.vo.ProjectVO; +import com.vo.SceneConfigVO; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.imageio.ImageIO; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + + +public class ProjectManager extends BaseProxy { + private static final String TAG = ProjectManager.class.getCanonicalName(); + public static final String NAME = TAG; + private static final String EVENT_PREFIX = "games.rednblack.editor.proxy.ProjectManager"; + + public static final String PROJECT_OPENED = EVENT_PREFIX + ".PROJECT_OPENED"; + public static final String PROJECT_DATA_UPDATED = EVENT_PREFIX + ".PROJECT_DATA_UPDATED"; + + public static final String IMAGE_DIR_PATH = "assets/orig/images"; + public static final String SPINE_DIR_PATH = "assets/orig/spine-animations"; + public static final String SPRITE_DIR_PATH = "assets/orig/sprite-animations"; + public static final String SPRITER_DIR_PATH = "assets/orig/animations"; + public static final String PARTICLE_DIR_PATH = "assets/orig/particles"; + public static final String SHADER_DIR_PATH = "assets/shaders"; + + public ProjectVO currentProjectVO; + public ProjectInfoVO currentProjectInfoVO; + private String currentProjectPath; + + private String defaultWorkspacePath; + + private String DEFAULT_FOLDER = "HyperLap2D"; + private float currentPercent = 0.0f; + private ProgressHandler handler; + private EditorConfigVO editorConfigVO; + + private String currentWindowTitle = ""; + + public ProjectManager() { + super(NAME); + } + + + @Override + public void onRegister() { + super.onRegister(); + facade = HyperLap2DFacade.getInstance(); + initWorkspace(); + } + + @Override + public void onRemove() { + super.onRemove(); + } + + public ProjectVO getCurrentProjectVO() { + return currentProjectVO; + } + + public ProjectInfoVO getCurrentProjectInfoVO() { + return currentProjectInfoVO; + } + + private void initWorkspace() { + try { + editorConfigVO = getEditorConfig(); + String myDocPath = HyperLap2DUtils.MY_DOCUMENTS_PATH; + defaultWorkspacePath = myDocPath + File.separator + DEFAULT_FOLDER; + FileUtils.forceMkdir(new File(defaultWorkspacePath)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void changePercentBy(float value) { + currentPercent += value; + handler.progressChanged(currentPercent); + } + + public void createEmptyProject(String projectPath, int width, int height, int pixelPerWorldUnit) throws IOException { + + /* + if (workspacePath.endsWith(File.separator)) { + workspacePath = workspacePath.substring(0, workspacePath.length() - 1); + } + + String projPath = workspacePath + File.separator + projectName; + */ + String projectName = new File(projectPath).getName(); + String projPath = FilenameUtils.normalize(projectPath); + + FileUtils.forceMkdir(new File(projPath)); + FileUtils.forceMkdir(new File(projPath + File.separator + "export")); + FileUtils.forceMkdir(new File(projPath + File.separator + "assets")); + FileUtils.forceMkdir(new File(projPath + File.separator + "scenes")); + FileUtils.forceMkdir(new File(projPath + File.separator + "assets/orig")); + FileUtils.forceMkdir(new File(projPath + File.separator + "assets/orig/images")); + FileUtils.forceMkdir(new File(projPath + File.separator + "assets/orig/particles")); + FileUtils.forceMkdir(new File(projPath + File.separator + "assets/orig/animations")); + FileUtils.forceMkdir(new File(projPath + File.separator + "assets/orig/pack")); + + + // create project file + ProjectVO projVo = new ProjectVO(); + projVo.projectName = projectName; + projVo.projectVersion = ProjectVersionMigrator.dataFormatVersion; + + // create project info file + ProjectInfoVO projInfoVo = new ProjectInfoVO(); + projInfoVo.originalResolution.name = "orig"; + projInfoVo.originalResolution.width = width; + projInfoVo.originalResolution.height = height; + projInfoVo.pixelToWorld = pixelPerWorldUnit; + + //TODO: add project orig resolution setting + currentProjectVO = projVo; + currentProjectInfoVO = projInfoVo; + currentProjectPath = projPath; + SceneDataManager sceneDataManager = facade.retrieveProxy(SceneDataManager.NAME); + sceneDataManager.createNewScene("MainScene"); + FileUtils.writeStringToFile(new File(projPath + "/project.pit"), projVo.constructJsonString(), "utf-8"); + FileUtils.writeStringToFile(new File(projPath + "/project.dt"), projInfoVo.constructJsonString(), "utf-8"); + + } + + public void setLastOpenedPath(String path) { + editorConfigVO.lastOpenedSystemPath = path; + saveEditorConfig(); + } + + public void setLastImportedPath(String path) { + editorConfigVO.lastImportedSystemPath = path; + saveEditorConfig(); + } + + private void saveEditorConfig() { + try { + String configFilePath = getRootPath() + File.separator + "configs" + File.separator + EditorConfigVO.EDITOR_CONFIG_FILE; + FileUtils.writeStringToFile(new File(configFilePath), editorConfigVO.constructJsonString(), "utf-8"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void openProjectAndLoadAllData(String projectPath) { + openProjectAndLoadAllData(projectPath, null); + } + + public void openProjectAndLoadAllData(String projectPath, String resolution) { + String prjFilePath = projectPath + "/project.pit"; + + PreferencesManager prefs = PreferencesManager.getInstance(); + prefs.buildRecentHistory(); + prefs.pushHistory(prjFilePath); + facade.sendNotification(HyperLap2DMenuBar.RECENT_LIST_MODIFIED); + + File prjFile = new File(prjFilePath); + if (!prjFile.isDirectory()) { + if (!prjFile.exists()) { + + ProjectVO projVoEmpty = new ProjectVO(); + projVoEmpty.projectName = prjFile.getName(); + projVoEmpty.projectVersion = ProjectVersionMigrator.dataFormatVersion; + + try { + FileUtils.writeStringToFile(prjFile, projVoEmpty.constructJsonString(), "utf-8"); + } catch (IOException e) { + e.printStackTrace(); + } + } + FileHandle projectFile = Gdx.files.internal(prjFilePath); + String projectContents = null; + try { + projectContents = FileUtils.readFileToString(projectFile.file()); + Json json = new Json(); + json.setIgnoreUnknownFields(true); + ProjectVO vo = json.fromJson(ProjectVO.class, projectContents); + goThroughVersionMigrationProtocol(projectPath, vo); + currentProjectVO = vo; + String prjInfoFilePath = projectPath + "/project.dt"; + FileHandle projectInfoFile = Gdx.files.internal(prjInfoFilePath); + String projectInfoContents = FileUtils.readFileToString(projectInfoFile.file()); + ProjectInfoVO voInfo = json.fromJson(ProjectInfoVO.class, projectInfoContents); + currentProjectInfoVO = voInfo; + + } catch (IOException e) { + e.printStackTrace(); + } + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + if (resolution == null) { + resolutionManager.currentResolutionName = currentProjectVO.lastOpenResolution.isEmpty() ? "orig" : currentProjectVO.lastOpenResolution; + } else { + resolutionManager.currentResolutionName = resolution; + currentProjectVO.lastOpenResolution = resolutionManager.currentResolutionName; + saveCurrentProject(); + + } + currentProjectPath = projectPath; + checkForConsistency(projectPath); + loadProjectData(projectPath); + } + } + + private void goThroughVersionMigrationProtocol(String projectPath, ProjectVO projectVo) { + ProjectVersionMigrator pvm = new ProjectVersionMigrator(projectPath, projectVo); + pvm.start(); + } + + private void checkForConsistency(String projectPath) { + // check if current project requires cleanup + + FileHandle sourceDir = new FileHandle(projectPath + "/scenes/"); + for (FileHandle entry : sourceDir.list(HyperLap2DUtils.DT_FILTER)) { + if (!entry.file().isDirectory()) { + Json json = new Json(); + json.setIgnoreUnknownFields(true); + SceneVO sceneVO = json.fromJson(SceneVO.class, entry); + if (sceneVO.composite == null) continue; + ArrayList items = sceneVO.composite.getAllItems(); + + for (CompositeItemVO libraryItem : currentProjectInfoVO.libraryItems.values()) { + if (libraryItem.composite == null) continue; + items = libraryItem.composite.getAllItems(); + } + } + } + } + + public void reLoadProjectAssets() { + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + ResourceManager resourceManager = facade.retrieveProxy(ResourceManager.NAME); + resourceManager.loadCurrentProjectAssets(currentProjectPath + "/assets/" + resolutionManager.currentResolutionName + "/pack/pack.atlas"); + } + + public void loadProjectData(String projectPath) { + // All legit loading assets + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + ResourceManager resourceManager = facade.retrieveProxy(ResourceManager.NAME); + resourceManager.loadCurrentProjectData(projectPath, resolutionManager.currentResolutionName); + } + + public void saveCurrentProject() { + try { + FileUtils.writeStringToFile(new File(currentProjectPath + "/project.pit"), currentProjectVO.constructJsonString(), "utf-8"); + FileUtils.writeStringToFile(new File(currentProjectPath + "/project.dt"), currentProjectInfoVO.constructJsonString(), "utf-8"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void saveCurrentProject(SceneVO vo) { + saveCurrentProject(); + SceneDataManager sceneDataManager = facade.retrieveProxy(SceneDataManager.NAME); + sceneDataManager.saveScene(vo); + } + + + private ArrayList getScmlFileImagesList(FileHandle fileHandle) { + ArrayList images = new ArrayList(); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = null; + try { + db = dbf.newDocumentBuilder(); + org.w3c.dom.Document document = db.parse(fileHandle.file()); + NodeList nodeList = document.getElementsByTagName("file"); + for (int x = 0, size = nodeList.getLength(); x < size; x++) { + String absolutePath = fileHandle.path(); + String path = absolutePath.substring(0, FilenameUtils.indexOfLastSeparator(fileHandle.path())) + File.separator + nodeList.item(x).getAttributes().getNamedItem("name").getNodeValue(); + File imgFile = new File(path); + images.add(imgFile); + } + } catch (SAXException | IOException | ParserConfigurationException e) { + e.printStackTrace(); + } + return images; + } + + + public void importSpineAnimationsIntoProject(final Array fileHandles, ProgressHandler progressHandler) { + if (fileHandles == null) { + return; + } + handler = progressHandler; + currentPercent = 0; + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + for (FileHandle handle : fileHandles) { + File copiedFile = importExternalAnimationIntoProject(handle); + if (copiedFile.getName().toLowerCase().endsWith(".atlas")) { + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + resolutionManager.resizeSpineAnimationForAllResolutions(copiedFile, currentProjectInfoVO); + } else if (copiedFile.getName().toLowerCase().endsWith(".scml")) { + //resizeSpriterAnimationForAllResolutions(copiedFile, currentProjectInfoVO); + } + } + + }); + executor.execute(() -> { + changePercentBy(100 - currentPercent); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + handler.progressComplete(); + }); + executor.shutdown(); + + } + + public File importExternalAnimationIntoProject(FileHandle animationFileSource) { + try { + String fileName = animationFileSource.name(); + if (!HyperLap2DUtils.JSON_FILTER.accept(null, fileName) && + !HyperLap2DUtils.SCML_FILTER.accept(null, fileName)) { + //showError("Spine animation should be a .json file with atlas in same folder \n Spriter animation should be a .scml file with images in same folder"); + return null; + } + + String fileNameWithOutExt = FilenameUtils.removeExtension(fileName); + String sourcePath; + String animationDataPath; + String targetPath; + if (HyperLap2DUtils.JSON_FILTER.accept(null, fileName)) { + sourcePath = animationFileSource.path(); + + animationDataPath = FilenameUtils.getFullPathNoEndSeparator(sourcePath); + targetPath = currentProjectPath + "/assets/orig/spine-animations" + File.separator + fileNameWithOutExt; + FileHandle atlasFileSource = new FileHandle(animationDataPath + File.separator + fileNameWithOutExt + ".atlas"); + if (!atlasFileSource.exists()) { + //showError("the atlas file needs to have same name and location as the json file"); + return null; + } + + FileUtils.forceMkdir(new File(targetPath)); + File jsonFileTarget = new File(targetPath + File.separator + fileNameWithOutExt + ".json"); + File atlasFileTarget = new File(targetPath + File.separator + fileNameWithOutExt + ".atlas"); + Array imageFiles = getAtlasPages(atlasFileSource); + + FileUtils.copyFile(animationFileSource.file(), jsonFileTarget); + FileUtils.copyFile(atlasFileSource.file(), atlasFileTarget); + + for (File imageFile : imageFiles) { + FileHandle imgFileTarget = new FileHandle(targetPath + File.separator + imageFile.getName()); + FileUtils.copyFile(imageFile, imgFileTarget.file()); + } + + return atlasFileTarget; + + + } else if (HyperLap2DUtils.SCML_FILTER.accept(null, fileName)) { + targetPath = currentProjectPath + "/assets/orig/spriter-animations" + File.separator + fileNameWithOutExt; + File scmlFileTarget = new File(targetPath + File.separator + fileNameWithOutExt + ".scml"); + ArrayList imageFiles = getScmlFileImagesList(animationFileSource); + + FileUtils.copyFile(animationFileSource.file(), scmlFileTarget); + for (File imageFile : imageFiles) { + File imgFileTarget = new File(targetPath + File.separator + imageFile.getName()); + FileUtils.copyFile(imageFile, imgFileTarget); + } + return scmlFileTarget; + + + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + + public void importSpriteAnimationsIntoProject(final Array fileHandles, ProgressHandler progressHandler) { + if (fileHandles == null) { + return; + } + handler = progressHandler; + + ExecutorService executor = Executors.newSingleThreadExecutor(); + + executor.execute(() -> { + + String newAnimName = null; + + String rawFileName = fileHandles.get(0).name(); + String fileExtension = FilenameUtils.getExtension(rawFileName); + if (fileExtension.equals("png")) { + Settings settings = new Settings(); + settings.square = true; + settings.flattenPaths = true; + settings.maxWidth = Integer.parseInt(getCurrentProjectVO().texturepackerWidth); + settings.maxHeight = Integer.parseInt(getCurrentProjectVO().texturepackerHeight); + settings.duplicatePadding = getCurrentProjectVO().texturepackerDuplicate; + TexturePacker texturePacker = new TexturePacker(settings); + + String fileNameWithoutExt = FilenameUtils.removeExtension(rawFileName); + String fileNameWithoutFrame = fileNameWithoutExt.replaceAll("\\d*$", "").replace("_", ""); + + boolean noFileNameWithoutFrame = false; + if (Objects.equals(fileNameWithoutFrame, "")) { + fileNameWithoutFrame = fileHandles.get(0).parent().name(); + noFileNameWithoutFrame = true; + } + + String targetPath = currentProjectPath + "/assets/orig/sprite-animations" + File.separator + fileNameWithoutFrame; + + for (FileHandle file : fileHandles) { + File src = file.file(); + + String destName; + if (noFileNameWithoutFrame) { + destName = targetPath + "Tmp" + File.separator + fileNameWithoutFrame + src.getName(); + } else { + destName = targetPath + "Tmp" + File.separator + src.getName(); + } + + File dest = new File(destName); + try { + FileUtils.copyFile(src, dest); + } catch (IOException e) { + e.printStackTrace(); + handler.progressFailed(); + return; + } + } + + FileHandle pngsDir = new FileHandle(targetPath + "Tmp"); + for (FileHandle entry : pngsDir.list(HyperLap2DUtils.PNG_FILTER)) { + texturePacker.addImage(entry.file()); + } + + File targetDir = new File(targetPath); + if (targetDir.exists()) { + try { + FileUtils.deleteDirectory(targetDir); + } catch (IOException e) { + e.printStackTrace(); + handler.progressFailed(); + return; + } + } + + try { + texturePacker.pack(targetDir, fileNameWithoutFrame); + } catch (Exception e) { + handler.progressFailed(); + return; + } + + //delete newly created directory and images + try { + FileUtils.deleteDirectory(pngsDir.file()); + } catch (IOException e) { + e.printStackTrace(); + handler.progressFailed(); + return; + } + + newAnimName = fileNameWithoutFrame; + } else { + for (FileHandle fileHandle : fileHandles) { + try { + Array imgs = getAtlasPages(fileHandle); + String fileNameWithoutExt = getAtlasName(fileHandle); + + String targetPath = currentProjectPath + "/assets/orig/sprite-animations" + File.separator + fileNameWithoutExt; + File targetDir = new File(targetPath); + if (targetDir.exists()) { + FileUtils.deleteDirectory(targetDir); + } + for (File img : imgs) { + FileUtils.copyFileToDirectory(img, targetDir); + } + File atlasTargetPath = new File(targetPath + File.separator + fileNameWithoutExt + ".atlas"); + FileUtils.copyFile(fileHandle.file(), atlasTargetPath); + newAnimName = fileNameWithoutExt; + } catch (IOException e) { + e.printStackTrace(); + handler.progressFailed(); + return; + } + } + } + + if (newAnimName != null) { + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + resolutionManager.resizeSpriteAnimationForAllResolutions(newAnimName, currentProjectInfoVO); + } + }); + executor.execute(() -> { + changePercentBy(100 - currentPercent); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + handler.progressComplete(); + }); + executor.shutdown(); + } + + private Array getAtlasPages(FileHandle fileHandle) { + Array imgs = new Array<>(); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(fileHandle.read()), 64); + while (true) { + String line = reader.readLine(); + if (line == null) break; + if (line.trim().length() == 0) { + line = reader.readLine(); + imgs.add(new File(FilenameUtils.getFullPath(fileHandle.path()) + line)); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return imgs; + } + + private String getAtlasName(FileHandle fileHandle) { + String name = "atlas"; + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(fileHandle.read()), 64); + while (true) { + String line = reader.readLine(); + if (line == null) break; + if (line.trim().contains("repeat:")) { + line = reader.readLine(); + name = line; + break; + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return name; + } + + private Array getAtlasPageHandles(FileHandle fileHandle) { + Array imgs = getAtlasPages(fileHandle); + + Array imgHandles = new Array<>(); + for (int i = 0; i < imgs.size; i++) { + imgHandles.add(new FileHandle(imgs.get(i))); + } + + return imgHandles; + } + + private boolean addParticleEffectImages(FileHandle fileHandle, Array imgs) { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(fileHandle.read()), 64); + while (true) { + String line = reader.readLine(); + if (line == null) break; + if (line.trim().equals("- Image Paths -")) { + line = reader.readLine(); + while (line != null && !line.equals("")) { + System.out.println(line); + if (line.contains("\\") || line.contains("/")) { + // then it's a path let's see if exists. + File tmp = new File(line); + if (tmp.exists()) { + imgs.add(new FileHandle(tmp)); + } else { + line = FilenameUtils.getBaseName(line) + ".png"; + File file = new File(FilenameUtils.getFullPath(fileHandle.path()) + line); + if (file.exists()) { + imgs.add(new FileHandle(file)); + } else { + return false; + } + } + } else { + File file = new File(FilenameUtils.getFullPath(fileHandle.path()) + line); + if (file.exists()) { + imgs.add(new FileHandle(file)); + } else { + return false; + } + } + line = reader.readLine(); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + + return true; + } + + public void importParticlesIntoProject(final Array fileHandles, ProgressHandler progressHandler) { + if (fileHandles == null) { + return; + } + final String targetPath = currentProjectPath + "/assets/orig/particles"; + handler = progressHandler; + currentPercent = 0; + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + Array images = new Array<>(); + for (FileHandle fileHandle : fileHandles) { + if (!fileHandle.isDirectory() && fileHandle.exists()) { + try { + //copy images + boolean allImagesFound = addParticleEffectImages(fileHandle, images); + if (allImagesFound) { + // copy the fileHandle + String newName = fileHandle.name(); + File target = new File(targetPath + "/" + newName); + FileUtils.copyFile(fileHandle.file(), target); + } + } catch (IllegalArgumentException e) { + System.out.println("Error importing particles."); + throw e; + + } catch (IOException e) { + System.out.println("Error importing particles."); + e.printStackTrace(); + } + } + } + if (images.size > 0) { + copyImageFilesForAllResolutionsIntoProject(images, false); + } + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + resolutionManager.rePackProjectImagesForAllResolutions(); + }); + executor.execute(() -> { + changePercentBy(100 - currentPercent); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + handler.progressComplete(); + }); + executor.shutdown(); + } + + public void importAtlasesIntoProject(final Array files, ProgressHandler progressHandler) { + handler = progressHandler; + currentPercent = 0; + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + for (FileHandle fileHandle : files) { + // TODO: logic goes here + } + }); + executor.execute(() -> { + changePercentBy(100 - currentPercent); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + handler.progressComplete(); + }); + executor.shutdown(); + } + + + public void importImagesIntoProject(final Array files, ProgressHandler progressHandler) { + if (files == null) { + return; + } + handler = progressHandler; + currentPercent = 0; + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + copyImageFilesForAllResolutionsIntoProject(files, true); + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + resolutionManager.rePackProjectImagesForAllResolutions(); + }); + executor.execute(() -> { + changePercentBy(100 - currentPercent); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + handler.progressComplete(); + }); + executor.shutdown(); + } + + private void copyImageFilesForAllResolutionsIntoProject(Array files, Boolean performResize) { + copyImageFilesIntoProject(files, currentProjectInfoVO.originalResolution, performResize); + int totalWarnings = 0; + for (ResolutionEntryVO resolutionEntryVO : currentProjectInfoVO.resolutions) { + totalWarnings += copyImageFilesIntoProject(files, resolutionEntryVO, performResize); + } + if (totalWarnings > 0) { + Dialogs.showOKDialog(Sandbox.getInstance().getUIStage(), "Warning", totalWarnings + " images were not resized for smaller resolutions due to already small size ( < 3px )"); + } + } + + /** + * @param files + * @param resolution + * @param performResize + * @return number of images that did needed to be resized but failed + */ + private int copyImageFilesIntoProject(Array files, ResolutionEntryVO resolution, Boolean performResize) { + float ratio = ResolutionManager.getResolutionRatio(resolution, currentProjectInfoVO.originalResolution); + String targetPath = currentProjectPath + "/assets/" + resolution.name + "/images"; + float perCopyPercent = 95.0f / files.size; + + int resizeWarningsCount = 0; + + for (FileHandle handle : files) { + if (!HyperLap2DUtils.PNG_FILTER.accept(null, handle.name())) { + continue; + } + try { + BufferedImage bufferedImage; + if (performResize) { + bufferedImage = ResolutionManager.imageResize(handle.file(), ratio); + if (bufferedImage == null) { + bufferedImage = ImageIO.read(handle.file()); + resizeWarningsCount++; + } + } else { + bufferedImage = ImageIO.read(handle.file()); + } + + File target = new File(targetPath); + if (!target.exists()) { + File newFile = new File(targetPath); + newFile.mkdir(); + } + + // The filename should not be changed because the particle effects contain the name in their + // configuration. Unfortunately though, the texture packer does not support the underscore because + // any underscore in the texture packer is considered an image index. More info here: + // https://github.com/libgdx/libgdx/wiki/Texture-packer#image-indexes + // So, long story short, we MUST remove the underscore. + ImageIO.write(bufferedImage, "png", new File(targetPath + "/" + handle.name().replace("_", ""))); + } catch (IOException e) { + e.printStackTrace(); + } + changePercentBy(perCopyPercent); + } + + return resizeWarningsCount; + } + + public void importFontIntoProject(Array fileHandles, ProgressHandler progressHandler) { + if (fileHandles == null) { + return; + } + String targetPath = currentProjectPath + "/assets/orig/freetypefonts"; + handler = progressHandler; + float perCopyPercent = 95.0f / fileHandles.size; + for (FileHandle fileHandle : fileHandles) { + if (!HyperLap2DUtils.TTF_FILTER.accept(null, fileHandle.name())) { + continue; + } + try { + File target = new File(targetPath); + if (!target.exists()) { + File newFile = new File(targetPath); + newFile.mkdir(); + } + File fileTarget = new File(targetPath + "/" + fileHandle.name()); + FileUtils.copyFile(fileHandle.file(), fileTarget); + } catch (IOException e) { + e.printStackTrace(); + } + System.out.println(perCopyPercent); + changePercentBy(perCopyPercent); + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + changePercentBy(100 - currentPercent); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + handler.progressComplete(); + }); + executor.shutdown(); + } + } + + public void importStyleIntoProject(final FileHandle handle, ProgressHandler progressHandler) { + if (handle == null) { + return; + } + final String targetPath = currentProjectPath + "/assets/orig/styles"; + FileHandle fileHandle = Gdx.files.absolute(handle.path()); + final MySkin skin = new MySkin(fileHandle); + handler = progressHandler; + currentPercent = 0; + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + for (int i = 0; i < skin.fontFiles.size(); i++) { + File copyFontFile = new File(handle.path(), skin.fontFiles.get(i) + ".fnt"); + File copyImageFile = new File(handle.path(), skin.fontFiles.get(i) + ".png"); + if (!handle.isDirectory() && handle.exists() && copyFontFile.isFile() && copyFontFile.exists() && copyImageFile.isFile() && copyImageFile.exists()) { + File fileTarget = new File(targetPath + "/" + handle.name()); + File fontTarget = new File(targetPath + "/" + copyFontFile.getName()); + File imageTarget = new File(targetPath + "/" + copyImageFile.getName()); + try { + FileUtils.copyFile(handle.file(), fileTarget); + FileUtils.copyFile(copyFontFile, fontTarget); + FileUtils.copyFile(copyImageFile, imageTarget); + } catch (IOException e) { + // TODO Auto-generated catch block + System.err.println(e.getMessage()); + e.printStackTrace(); + } + } else { + System.err.println("SOME FILES ARE MISSING"); + } + } + }); + executor.execute(new Runnable() { + @Override + public void run() { + changePercentBy(100 - currentPercent); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + handler.progressComplete(); + } + }); + executor.shutdown(); + } + + /** + * @depricated + */ + public void copyDefaultStyleIntoProject() { + /* + String targetPath = currentWorkingPath + "/" + currentProjectVO.projectName + "/assets/orig/styles"; + ResourceManager textureManager = facade.retrieveProxy(ResourceManager.NAME); + File source = new File("assets/ui"); + if (!(source.exists() && source.isDirectory())) { + try { + JarUtils.copyResourcesToDirectory(JarUtils.getThisJar(getClass()), "ui", targetPath); + textureManager.loadCurrentProjectSkin(targetPath); + return; + } catch (Exception e) { + e.printStackTrace(); + } + } + File fileTarget = new File(targetPath); + try { + FileUtils.copyDirectory(source, fileTarget); + textureManager.loadCurrentProjectSkin(targetPath); + } catch (IOException e) { + // TODO Auto-generated catch block + System.err.println(e.getMessage()); + e.printStackTrace(); + } + */ + } + + public String getFreeTypeFontPath() { + return currentProjectPath + "/assets/orig/freetypefonts"; + } + + public void exportProject() { + + String defaultBuildPath = currentProjectPath + "/export"; + exportPacks(defaultBuildPath); + if (!currentProjectVO.projectMainExportPath.isEmpty()) { + exportPacks(currentProjectVO.projectMainExportPath); + } + exportAnimations(defaultBuildPath); + if (!currentProjectVO.projectMainExportPath.isEmpty()) { + exportAnimations(currentProjectVO.projectMainExportPath); + } + exportParticles(defaultBuildPath); + if (!currentProjectVO.projectMainExportPath.isEmpty()) { + exportParticles(currentProjectVO.projectMainExportPath); + } + exportShaders(defaultBuildPath); + if (!currentProjectVO.projectMainExportPath.isEmpty()) { + exportShaders(currentProjectVO.projectMainExportPath); + } + exportFonts(defaultBuildPath); + if (!currentProjectVO.projectMainExportPath.isEmpty()) { + exportFonts(currentProjectVO.projectMainExportPath); + } + exportStyles(defaultBuildPath); + SceneDataManager sceneDataManager = facade.retrieveProxy(SceneDataManager.NAME); + sceneDataManager.buildScenes(defaultBuildPath); + if (!currentProjectVO.projectMainExportPath.isEmpty()) { + sceneDataManager.buildScenes(currentProjectVO.projectMainExportPath); + } + } + + + private void exportStyles(String targetPath) { + String srcPath = currentProjectPath + "/assets/orig"; + FileHandle origDirectoryHandle = Gdx.files.absolute(srcPath); + FileHandle stylesDirectory = origDirectoryHandle.child("styles"); + File fileTarget = new File(targetPath + "/" + stylesDirectory.name()); + try { + FileUtils.copyDirectory(stylesDirectory.file(), fileTarget); + } catch (IOException e) { + //e.printStackTrace(); + } + } + + private void exportShaders(String targetPath) { + String srcPath = currentProjectPath + "/assets"; + FileHandle origDirectoryHandle = Gdx.files.absolute(srcPath); + FileHandle shadersDirectory = origDirectoryHandle.child("shaders"); + File fileTarget = new File(targetPath + "/" + shadersDirectory.name()); + try { + FileUtils.copyDirectory(shadersDirectory.file(), fileTarget); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void exportParticles(String targetPath) { + String srcPath = currentProjectPath + "/assets/orig"; + FileHandle origDirectoryHandle = Gdx.files.absolute(srcPath); + FileHandle particlesDirectory = origDirectoryHandle.child("particles"); + File fileTarget = new File(targetPath + "/" + particlesDirectory.name()); + try { + FileUtils.copyDirectory(particlesDirectory.file(), fileTarget); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void exportFonts(String targetPath) { + String srcPath = currentProjectPath + "/assets/orig"; + FileHandle origDirectoryHandle = Gdx.files.absolute(srcPath); + FileHandle fontsDirectory = origDirectoryHandle.child("freetypefonts"); + File fileTarget = new File(targetPath + "/" + fontsDirectory.name()); + try { + FileUtils.copyDirectory(fontsDirectory.file(), fileTarget); + } catch (IOException e) { + //e.printStackTrace(); + } + } + + + private void exportAnimations(String targetPath) { + exportSpineAnimationForResolution("orig", targetPath); + exportSpriteAnimationForResolution("orig", targetPath); + exportSpriterAnimationForResolution("orig", targetPath); + for (ResolutionEntryVO resolutionEntryVO : currentProjectInfoVO.resolutions) { + exportSpineAnimationForResolution(resolutionEntryVO.name, targetPath); + exportSpriteAnimationForResolution(resolutionEntryVO.name, targetPath); + exportSpriterAnimationForResolution(resolutionEntryVO.name, targetPath); + } + } + + private void exportSpineAnimationForResolution(String res, String targetPath) { + String spineSrcPath = currentProjectPath + "/assets/" + res + File.separator + "spine-animations"; + try { + FileUtils.forceMkdir(new File(targetPath + File.separator + res + File.separator + "spine_animations")); + File fileSrc = new File(spineSrcPath); + String finalTarget = targetPath + File.separator + res + File.separator + "spine_animations"; + + File fileTargetSpine = new File(finalTarget); + + FileUtils.copyDirectory(fileSrc, fileTargetSpine); + } catch (IOException e) { + //e.printStackTrace(); + } + } + + private void exportSpriteAnimationForResolution(String res, String targetPath) { + String spineSrcPath = currentProjectPath + "/assets/" + res + File.separator + "sprite-animations"; + try { + FileUtils.forceMkdir(new File(targetPath + File.separator + res + File.separator + "sprite_animations")); + File fileSrc = new File(spineSrcPath); + String finalTarget = targetPath + File.separator + res + File.separator + "sprite_animations"; + + File fileTargetSprite = new File(finalTarget); + + FileUtils.copyDirectory(fileSrc, fileTargetSprite); + } catch (IOException e) { + //e.printStackTrace(); + } + } + + private void exportSpriterAnimationForResolution(String res, String targetPath) { + String spineSrcPath = currentProjectPath + "/assets/" + res + File.separator + "spriter-animations"; + try { + FileUtils.forceMkdir(new File(targetPath + File.separator + res + File.separator + "spriter_animations")); + File fileSrc = new File(spineSrcPath); + String finalTarget = targetPath + File.separator + res + File.separator + "spriter_animations"; + File fileTargetSpriter = new File(finalTarget); + FileUtils.copyDirectory(fileSrc, fileTargetSpriter); + } catch (IOException e) { + //e.printStackTrace(); + } + } + + private void exportPacks(String targetPath) { + String srcPath = currentProjectPath + "/assets"; + FileHandle assetDirectoryHandle = Gdx.files.absolute(srcPath); + FileHandle[] assetDirectories = assetDirectoryHandle.list(); + for (FileHandle assetDirectory : assetDirectories) { + if (assetDirectory.isDirectory()) { + FileHandle assetDirectoryFileHandle = Gdx.files.absolute(assetDirectory.path()); + FileHandle[] packFiles = assetDirectoryFileHandle.child("pack").list(); + for (FileHandle packFile : packFiles) { + File fileTarget = new File(targetPath + "/" + assetDirectory.name() + "/" + packFile.name()); + try { + FileUtils.copyFile(packFile.file(), fileTarget); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + } + } + + public void setExportPaths(String path) { + currentProjectVO.projectMainExportPath = path; + } + + public String getExportPath() { + if (currentProjectVO == null || currentProjectVO.projectMainExportPath == null) { + return ""; + } + return currentProjectVO.projectMainExportPath; + } + + public void setTexturePackerSizes(int width, int height) { + currentProjectVO.texturepackerWidth = String.valueOf(width); + currentProjectVO.texturepackerHeight = String.valueOf(height); + } + + public void setTexturePackerDuplicate(boolean duplicate) { + currentProjectVO.texturepackerDuplicate = duplicate; + } + + public String getRootPath() { + File root = new File(new File(".").getAbsolutePath()).getParentFile(); + return root.getAbsolutePath(); + } + + private EditorConfigVO getEditorConfig() { + EditorConfigVO editorConfig = new EditorConfigVO(); + String configFilePath = getRootPath() + File.separator + "configs" + File.separator + EditorConfigVO.EDITOR_CONFIG_FILE; + File configFile = new File(configFilePath); + if (!configFile.exists()) { + try { + FileUtils.writeStringToFile(new File(configFilePath), editorConfig.constructJsonString(), "utf-8"); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + Json gson = new Json(); + String editorConfigJson = null; + try { + editorConfigJson = FileUtils.readFileToString(Gdx.files.absolute(configFilePath).file()); + editorConfig = gson.fromJson(EditorConfigVO.class, editorConfigJson); + } catch (IOException e) { + e.printStackTrace(); + } + } + return editorConfig; + } + + public void createNewProject(String projectPath, int originWidth, int originHeight, int pixelPerWorldUnit) { + if (projectPath == null || projectPath.equals("")) { + return; + } + String projectName = new File(projectPath).getName(); + + if (projectName.equals("")) { + return; + } + + try { + createEmptyProject(projectPath, originWidth, originHeight, pixelPerWorldUnit); + openProjectAndLoadAllData(projectPath); + String workSpacePath = projectPath.substring(0, projectPath.lastIndexOf(projectName)); + if (workSpacePath.length() > 0) { + setLastOpenedPath(workSpacePath); + } + Sandbox.getInstance().loadCurrentProject(); + facade.sendNotification(PROJECT_OPENED); + + //Set title with opened file path + setWindowTitle(getFormattedTitle(projectPath)); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void openProjectFromPath(String path) { + File projectFile = new File(path); + File projectFolder = projectFile.getParentFile(); + String projectName = projectFolder.getName(); + editorConfigVO.lastOpenedSystemPath = projectFolder.getParentFile().getPath(); + saveEditorConfig(); + + // here we load all data + openProjectAndLoadAllData(projectFolder.getPath()); + Sandbox.getInstance().loadCurrentProject(); + + facade.sendNotification(ProjectManager.PROJECT_OPENED); + + //Set title with opened file path + setWindowTitle(getFormattedTitle(path)); + } + + + private String getFormattedTitle(String path) { + //App Name + path to opened file + return currentProjectVO.projectName + " [ " + getCurrentSceneConfigVO().sceneName + " ] - " + path; + } + + private void setWindowTitle(String title) { + currentWindowTitle = title; + Gdx.graphics.setTitle(currentWindowTitle); + } + + public void appendSaveHintTitle(boolean isModified) { + if (!isModified) { + Gdx.graphics.setTitle(currentWindowTitle); + } else { + Gdx.graphics.setTitle(currentWindowTitle + "*"); + } + } + + public void changeSceneWindowTitle() { + setWindowTitle(getFormattedTitle(currentProjectPath)); + } + + public SceneConfigVO getCurrentSceneConfigVO() { + for (int i = 0; i < currentProjectVO.sceneConfigs.size(); i++) { + if (currentProjectVO.sceneConfigs.get(i).sceneName.equals(Sandbox.getInstance().getSceneControl().getCurrentSceneVO().sceneName)) { + return currentProjectVO.sceneConfigs.get(i); + } + } + + SceneConfigVO newConfig = new SceneConfigVO(); + newConfig.sceneName = Sandbox.getInstance().getSceneControl().getCurrentSceneVO().sceneName; + currentProjectVO.sceneConfigs.add(newConfig); + + return newConfig; + } + + public void importShaderIntoProject(Array files, ProgressHandler progressHandler) { + if (files == null) { + return; + } + handler = progressHandler; + currentPercent = 0; + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + for (FileHandle handle : files) { + // check if shaders folder exists + String shadersPath = currentProjectPath + "/assets/shaders"; + File destination = new File(currentProjectPath + "/assets/shaders/" + handle.name()); + try { + FileUtils.forceMkdir(new File(shadersPath)); + FileUtils.copyFile(handle.file(), destination); + } catch (IOException e) { + e.printStackTrace(); + } + } + + }); + executor.execute(() -> { + changePercentBy(100 - currentPercent); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + handler.progressComplete(); + }); + executor.shutdown(); + } + + public String getCurrentProjectPath() { + return currentProjectPath; + } + + public FileHandle getWorkspacePath() { + if (!editorConfigVO.lastOpenedSystemPath.isEmpty()) { + return new FileHandle(editorConfigVO.lastOpenedSystemPath); + } + return new FileHandle(defaultWorkspacePath); + } + + public FileHandle getImportPath() { + if (!editorConfigVO.lastImportedSystemPath.isEmpty()) { + return new FileHandle(editorConfigVO.lastImportedSystemPath); + } + return null; + } + + public boolean deleteImage(String imageName) { + Path path = Paths.get(currentProjectPath, "/assets/orig/images/", imageName); + + ArrayList possibleFiles = Lists.newArrayList( + path.resolveSibling(path.getFileName() + ".png"), + path.resolveSibling(path.getFileName() + ".9.png")); + + for(Path p : possibleFiles) { + if (p.toFile().exists()) + return p.toFile().delete(); + } + + throw new IllegalStateException(String.format("The file %s is not found",path.toString())); + + } + + public boolean deleteSingleImage(String imageName) { + String imagesPath = currentProjectPath + File.separator + IMAGE_DIR_PATH + File.separator; + String filePath = imagesPath + imageName + ".png"; + if (!(new File(filePath)).delete()) { + filePath = imagesPath + imageName + ".9.png"; + return (new File(filePath)).delete(); + } + return true; + } + + public boolean deleteParticle(String particleName) { + String particlePath = currentProjectPath + File.separator + PARTICLE_DIR_PATH + File.separator; + String filePath = particlePath + particleName; + return (new File(filePath)).delete(); + } + + public boolean deleteSpineAnimation(String spineName) { + String spinePath = currentProjectPath + File.separator + SPINE_DIR_PATH + File.separator; + String filePath = spinePath + spineName; + return deleteDirectory(filePath); + } + + public boolean deleteSpriteAnimation(String spineName) { + String spritePath = currentProjectPath + File.separator + SPRITE_DIR_PATH + File.separator; + String filePath = spritePath + spineName; + return deleteDirectory(filePath); + } + + public boolean deleteSpriterAnimation(String spineName) { + String spriterPath = currentProjectPath + File.separator + SPRITER_DIR_PATH + File.separator; + String filePath = spriterPath + spineName; + return deleteDirectory(filePath); + } + + private boolean deleteDirectory(String path) { + File file = new File(path); + if (file.exists()) { + try { + FileUtils.deleteDirectory(file); + } catch (IOException e) { + e.printStackTrace(); + } + if (!file.exists()) { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/games/rednblack/editor/proxy/ResolutionManager.java b/src/main/java/games/rednblack/editor/proxy/ResolutionManager.java new file mode 100644 index 00000000..2d13b58b --- /dev/null +++ b/src/main/java/games/rednblack/editor/proxy/ResolutionManager.java @@ -0,0 +1,509 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.proxy; + +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.imageio.ImageIO; + +import com.kotcrab.vis.ui.util.dialog.Dialogs; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.tools.texturepacker.TexturePacker; +import com.badlogic.gdx.tools.texturepacker.TextureUnpacker; +import com.badlogic.gdx.utils.Array; +import com.mortennobel.imagescaling.ResampleOp; +import com.puremvc.patterns.proxy.BaseProxy; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.view.ui.widget.ProgressHandler; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.data.ResolutionEntryVO; +import games.rednblack.editor.utils.NinePatchUtils; +import games.rednblack.editor.utils.HyperLap2DUtils; + +public class ResolutionManager extends BaseProxy { + private static final String TAG = ResolutionManager.class.getCanonicalName(); + public static final String NAME = TAG; + + public static final String RESOLUTION_LIST_CHANGED = "games.rednblack.editor.proxy.ResolutionManager" + ".RESOLUTION_LIST_CHANGED"; + + private static final String EXTENSION_9PATCH = ".9.png"; + public String currentResolutionName; + private float currentPercent = 0.0f; + + private ProgressHandler handler; + + + public ResolutionManager() { + super(NAME); + } + + public static BufferedImage imageResize(File file, float ratio) { + BufferedImage destinationBufferedImage = null; + try { + BufferedImage sourceBufferedImage = ImageIO.read(file); + if (ratio == 1.0) { + return sourceBufferedImage; + } + // When image has to be resized smaller then 3 pixels we should leave it as is, as to ResampleOP limitations + // But it should also trigger a warning dialog at the and of the import, to notify the user of non resized images. + if (sourceBufferedImage.getWidth() * ratio < 3 || sourceBufferedImage.getHeight() * ratio < 3) { + return null; + } + int newWidth = Math.max(3, Math.round(sourceBufferedImage.getWidth() * ratio)); + int newHeight = Math.max(3, Math.round(sourceBufferedImage.getHeight() * ratio)); + String name = file.getName(); + Integer[] patches = null; + if (name.endsWith(EXTENSION_9PATCH)) { + patches = NinePatchUtils.findPatches(sourceBufferedImage); + sourceBufferedImage = NinePatchUtils.removePatches(sourceBufferedImage); + + newWidth = Math.round(sourceBufferedImage.getWidth() * ratio); + newHeight = Math.round(sourceBufferedImage.getHeight() * ratio); + System.out.println(sourceBufferedImage.getWidth()); + + destinationBufferedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = destinationBufferedImage.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); + g2.drawImage(sourceBufferedImage, 0, 0, newWidth, newHeight, null); + g2.dispose(); + } else { + // resize with bilinear filter + ResampleOp resampleOp = new ResampleOp(newWidth, newHeight); + destinationBufferedImage = resampleOp.filter(sourceBufferedImage, null); + } + + if (patches != null) { + destinationBufferedImage = NinePatchUtils.convertTo9Patch(destinationBufferedImage, patches, ratio); + } + + } catch (IOException ignored) { + + } + + return destinationBufferedImage; + } + + public static float getResolutionRatio(ResolutionEntryVO resolution, ResolutionEntryVO originalResolution) { + float a; + float b; + switch (resolution.base) { + default: + case 0: + a = resolution.width; + b = originalResolution.width; + break; + case 1: + a = resolution.height; + b = originalResolution.height; + break; + } + return a / b; + } + + public static int getMinSquareNum(int num) { + + // if (num < 1024) return 1024; + + // if (num < 2048) return 2048; + + // if (num < 4096) return 4096; + + + return 4096; + } + + @Override + public void onRegister() { + super.onRegister(); + facade = HyperLap2DFacade.getInstance(); + } + +// private static BufferedImage convertTo9Patch(BufferedImage image) { + + // } + public void createNewResolution(ResolutionEntryVO resolutionEntryVO) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + projectManager.getCurrentProjectInfoVO().resolutions.add(resolutionEntryVO); + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(() -> { + // create new folder structure + String projPath = projectManager.getCurrentProjectPath(); + String sourcePath = projPath + "/" + "assets/orig/images"; + String targetPath = projPath + "/" + "assets/" + resolutionEntryVO.name + "/images"; + createIfNotExist(sourcePath); + createIfNotExist(projPath + "/" + "assets/" + resolutionEntryVO.name + "/pack"); + copyTexturesFromTo(sourcePath, targetPath); + int resizeWarnings = resizeTextures(targetPath, resolutionEntryVO); + rePackProjectImages(resolutionEntryVO); + createResizedAnimations(resolutionEntryVO); + changePercentBy(5); + if (resizeWarnings > 0) { + Dialogs.showOKDialog(Sandbox.getInstance().getUIStage(), "Warning", resizeWarnings + " images were not resized for smaller resolutions due to already small size ( < 3px )"); + } + HyperLap2DFacade.getInstance().sendNotification(RESOLUTION_LIST_CHANGED); + }); + executor.execute(() -> { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + projectManager.saveCurrentProject(); +// handler.progressComplete(); + }); + executor.shutdown(); + } + + + private void changePercentBy(float value) { + currentPercent += value; + //handler.progressChanged(currentPercent); + } + + public void createResizedAnimations(ResolutionEntryVO resolution) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + String currProjectPath = projectManager.getCurrentProjectPath(); + + // Unpack spine orig + File spineSourceDir = new File(currProjectPath + File.separator + "assets/orig/spine-animations"); + if (spineSourceDir.exists()) { + for (File entry : spineSourceDir.listFiles()) { + if (entry.isDirectory()) { + String animName = FilenameUtils.removeExtension(entry.getName()); + createResizedSpineAnimation(animName, resolution); + } + } + } + + //Unpack sprite orig + File spriteSourceDir = new File(currProjectPath + File.separator + "assets/orig/sprite-animations"); + if (spriteSourceDir.exists()) { + for (File entry : spriteSourceDir.listFiles()) { + if (entry.isDirectory()) { + String animName = FilenameUtils.removeExtension(entry.getName()); + createResizedSpriteAnimation(animName, resolution); + } + } + } + } + + public void createResizedSpriteAnimation(String animName, ResolutionEntryVO resolution) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + String currProjectPath = projectManager.getCurrentProjectPath(); + File animAtlasFile = new File(currProjectPath + File.separator + "assets/orig/sprite-animations/" + animName + "/" + animName + ".atlas"); + + String tmpPath = currProjectPath + File.separator + "assets/orig/sprite-animations/" + animName + "/tmp"; + File tmpFolder = new File(tmpPath); + try { + FileUtils.forceMkdir(new File(currProjectPath + File.separator + "assets/" + resolution.name + "/sprite-animations/")); + FileUtils.forceMkdir(new File(currProjectPath + File.separator + "assets/" + resolution.name + "/spine-animations/" + animName)); + + String targetPath = currProjectPath + File.separator + "assets/" + resolution.name + "/sprite-animations/" + animName; + File targetFolder = new File(targetPath); + + unpackAtlasIntoTmpFolder(animAtlasFile, tmpPath); + resizeImagesTmpDirToResolution(animName, tmpFolder, resolution, targetFolder); + + + FileUtils.deleteDirectory(tmpFolder); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void unpackAtlasIntoTmpFolder(File atlasFile, String tmpDir) { + FileHandle atlasFileHandle = new FileHandle(atlasFile); + TextureAtlas.TextureAtlasData atlasData = new TextureAtlas.TextureAtlasData(atlasFileHandle, atlasFileHandle.parent(), false); + TextureUnpacker unpacker = new TextureUnpacker(); + unpacker.splitAtlas(atlasData, tmpDir); + } + + public void createResizedSpineAnimation(String animName, ResolutionEntryVO resolution) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + String currProjectPath = projectManager.getCurrentProjectPath(); + + File animAtlasFile = new File(currProjectPath + File.separator + "assets/orig/spine-animations/" + animName + "/" + animName + ".atlas"); + + String tmpPath = currProjectPath + File.separator + "assets/orig/spine-animations/" + animName + "/tmp"; + File tmpFolder = new File(tmpPath); + try { + FileUtils.forceMkdir(new File(currProjectPath + File.separator + "assets/" + resolution.name + "/spine-animations/")); + FileUtils.forceMkdir(new File(currProjectPath + File.separator + "assets/" + resolution.name + "/spine-animations/" + animName)); + + String targetPath = currProjectPath + File.separator + "assets/" + resolution.name + "/spine-animations/" + animName; + File targetFolder = new File(targetPath); + + unpackAtlasIntoTmpFolder(animAtlasFile, tmpPath); + resizeImagesTmpDirToResolution(animName, tmpFolder, resolution, targetFolder); + + FileUtils.deleteDirectory(tmpFolder); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void resizeSpriteAnimationForAllResolutions(String animName, ProjectInfoVO currentProjectInfoVO) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + String currProjectPath = projectManager.getCurrentProjectPath(); + + File atlasFile = new File(currProjectPath + File.separator + "assets" + File.separator + "orig" + File.separator + "sprite-animations" + File.separator + animName + File.separator + animName + ".atlas"); + + String tmpDir = currProjectPath + File.separator + "assets" + File.separator + "orig" + File.separator + "sprite-animations" + File.separator + animName + File.separator + "tmp"; + File sourceFolder = new File(tmpDir); + + unpackAtlasIntoTmpFolder(atlasFile, tmpDir); + try { + for (ResolutionEntryVO resolutionEntryVO : currentProjectInfoVO.resolutions) { + String spriteAnimationsRoot = currProjectPath + File.separator + "assets" + File.separator + resolutionEntryVO.name + File.separator + "sprite-animations"; + FileUtils.forceMkdir(new File(spriteAnimationsRoot)); + String targetPath = spriteAnimationsRoot + File.separator + animName; + File targetFolder = new File(targetPath); + + resizeImagesTmpDirToResolution(animName, sourceFolder, resolutionEntryVO, targetFolder); + } + + FileUtils.deleteDirectory(sourceFolder); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void resizeSpineAnimationForAllResolutions(File atlasFile, ProjectInfoVO currentProjectInfoVO) { + + String fileNameWithOutExt = FilenameUtils.removeExtension(atlasFile.getName()); + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + String tmpDir = projectManager.getCurrentProjectPath() + "/assets/orig/spine-animations" + File.separator + fileNameWithOutExt + File.separator + "tmp"; + File sourceFolder = new File(tmpDir); + + unpackAtlasIntoTmpFolder(atlasFile, tmpDir); + try { + for (ResolutionEntryVO resolutionEntryVO : currentProjectInfoVO.resolutions) { + FileUtils.forceMkdir(new File(projectManager.getCurrentProjectPath() + File.separator + + "assets" + File.separator + resolutionEntryVO.name + File.separator + "spine-animations")); + String targetPath = projectManager.getCurrentProjectPath() + File.separator + "assets" + + File.separator + resolutionEntryVO.name + File.separator + "spine-animations" + File.separator + fileNameWithOutExt; + FileUtils.forceMkdir(new File(targetPath)); + File targetFolder = new File(targetPath); + resizeImagesTmpDirToResolution(atlasFile.getName(), sourceFolder, resolutionEntryVO, targetFolder); + } + FileUtils.deleteDirectory(sourceFolder); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void rePackProjectImages(ResolutionEntryVO resEntry) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + TexturePacker.Settings settings = new TexturePacker.Settings(); + + settings.flattenPaths = true; + settings.maxHeight = Integer.parseInt(projectManager.getCurrentProjectVO().texturepackerHeight); + settings.maxWidth = Integer.parseInt(projectManager.getCurrentProjectVO().texturepackerWidth); + settings.filterMag = Texture.TextureFilter.Linear; + settings.filterMin = Texture.TextureFilter.Linear; + settings.duplicatePadding = projectManager.getCurrentProjectVO().texturepackerDuplicate; + + TexturePacker tp = new TexturePacker(settings); + + String sourcePath = projectManager.getCurrentProjectPath() + "/assets/" + resEntry.name + "/images"; + String outputPath = projectManager.getCurrentProjectPath() + "/assets/" + resEntry.name + "/pack"; + + FileHandle sourceDir = new FileHandle(sourcePath); + File outputDir = new File(outputPath); + + try { + FileUtils.forceMkdir(outputDir); + FileUtils.cleanDirectory(outputDir); + } catch (IOException e) { + e.printStackTrace(); + } + + for (FileHandle entry : sourceDir.list()) { + String filename = entry.file().getName(); + String extension = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase(); + if (extension.equals("png")) { + tp.addImage(entry.file()); + } + } + + tp.pack(outputDir, "pack"); + } + + private int resizeTextures(String path, ResolutionEntryVO resolution) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + float ratio = getResolutionRatio(resolution, projectManager.getCurrentProjectInfoVO().originalResolution); + FileHandle targetDir = new FileHandle(path); + FileHandle[] entries = targetDir.list(HyperLap2DUtils.PNG_FILTER); + float perResizePercent = 95.0f / entries.length; + + int resizeWarnings = 0; + + for (FileHandle entry : entries) { + try { + File file = entry.file(); + File destinationFile = new File(path + "/" + file.getName()); + BufferedImage resizedImage = ResolutionManager.imageResize(file, ratio); + if (resizedImage == null) { + resizeWarnings++; + ImageIO.write(ImageIO.read(file), "png", destinationFile); + } else { + ImageIO.write(ResolutionManager.imageResize(file, ratio), "png", destinationFile); + } + } catch (IOException e) { + e.printStackTrace(); + } + changePercentBy(perResizePercent); + } + + return resizeWarnings; + } + + private void copyTexturesFromTo(String fromPath, String toPath) { + FileHandle sourceDir = new FileHandle(fromPath); + FileHandle[] entries = sourceDir.list(HyperLap2DUtils.PNG_FILTER); + float perCopyPercent = 10.0f / entries.length; + for (FileHandle entry : entries) { + File file = entry.file(); + String filename = file.getName(); + File target = new File(toPath + "/" + filename); + try { + FileUtils.copyFile(file, target); + } catch (IOException e) { + e.printStackTrace(); + } + } + changePercentBy(perCopyPercent); + } + + private File createIfNotExist(String dirPath) { + File theDir = new File(dirPath); + boolean result = false; + // if the directory does not exist, create it + if (!theDir.exists()) { + result = theDir.mkdir(); + } + + if (result) + return theDir; + else return null; + } + + public void resizeImagesTmpDirToResolution(String packName, File sourceFolder, ResolutionEntryVO resolution, File targetFolder) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + float ratio = ResolutionManager.getResolutionRatio(resolution, projectManager.getCurrentProjectInfoVO().originalResolution); + + if (targetFolder.exists()) { + try { + FileUtils.cleanDirectory(targetFolder); + } catch (IOException e) { + e.printStackTrace(); + } + } + // now pack + TexturePacker.Settings settings = new TexturePacker.Settings(); + + settings.flattenPaths = true; + settings.maxHeight = Integer.parseInt(projectManager.getCurrentProjectVO().texturepackerHeight); + settings.maxWidth = Integer.parseInt(projectManager.getCurrentProjectVO().texturepackerWidth); + settings.filterMag = Texture.TextureFilter.Linear; + settings.filterMin = Texture.TextureFilter.Linear; + + TexturePacker tp = new TexturePacker(settings); + for (final File fileEntry : sourceFolder.listFiles()) { + if (!fileEntry.isDirectory()) { + BufferedImage bufferedImage = ResolutionManager.imageResize(fileEntry, ratio); + tp.addImage(bufferedImage, FilenameUtils.removeExtension(fileEntry.getName())); + } + } + + tp.pack(targetFolder, packName); + } + + public float getCurrentMul() { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + ResolutionEntryVO curRes = projectManager.getCurrentProjectInfoVO().getResolution(currentResolutionName); + float mul = 1f; + if (!currentResolutionName.equals("orig")) { + if (curRes.base == 0) { + mul = (float) curRes.width / (float) projectManager.getCurrentProjectInfoVO().originalResolution.width; + } else { + mul = (float) curRes.height / (float) projectManager.getCurrentProjectInfoVO().originalResolution.height; + } + } + + return mul; + } + + public void rePackProjectImagesForAllResolutions() { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + rePackProjectImages(projectManager.getCurrentProjectInfoVO().originalResolution); + for (ResolutionEntryVO resolutionEntryVO : projectManager.getCurrentProjectInfoVO().resolutions) { + rePackProjectImages(resolutionEntryVO); + } + } + + public void deleteResolution(ResolutionEntryVO resolutionEntryVO) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + try { + FileUtils.deleteDirectory(new File(projectManager.getCurrentProjectPath() + "/assets/" + resolutionEntryVO.name)); + } catch (IOException ignored) { + ignored.printStackTrace(); + } + + currentResolutionName = getOriginalResolution().name; + + ProjectInfoVO projectInfo = projectManager.getCurrentProjectInfoVO(); + projectInfo.resolutions.removeValue(resolutionEntryVO, false); + HyperLap2DFacade.getInstance().sendNotification(RESOLUTION_LIST_CHANGED); + projectManager.saveCurrentProject(); + projectManager.openProjectAndLoadAllData(projectManager.getCurrentProjectPath(), "orig"); + } + + public Array getResolutions() { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + return projectManager.getCurrentProjectInfoVO().resolutions; + } + + public ResolutionEntryVO getOriginalResolution() { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + return projectManager.getCurrentProjectInfoVO().originalResolution; + } + + public ResolutionEntryVO getCurrentResolution() { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + for (ResolutionEntryVO res : projectManager.getCurrentProjectInfoVO().resolutions) { + if (res.name.equals(currentResolutionName)) { + return res; + } + } + return getOriginalResolution(); + } +} diff --git a/src/main/java/games/rednblack/editor/proxy/ResourceManager.java b/src/main/java/games/rednblack/editor/proxy/ResourceManager.java new file mode 100644 index 00000000..5b3f1e59 --- /dev/null +++ b/src/main/java/games/rednblack/editor/proxy/ResourceManager.java @@ -0,0 +1,426 @@ +package games.rednblack.editor.proxy; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map.Entry; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import games.rednblack.editor.renderer.data.*; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; + +import com.badlogic.gdx.Files; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.ParticleEffect; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; +import com.badlogic.gdx.utils.Json; +import com.puremvc.patterns.proxy.BaseProxy; +import games.rednblack.editor.data.SpineAnimData; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.resources.FontSizePair; +import games.rednblack.editor.renderer.resources.IResourceRetriever; +import games.rednblack.editor.renderer.utils.MySkin; + +/** + * Created by azakhary on 4/26/2015. + */ +public class ResourceManager extends BaseProxy implements IResourceRetriever { + + public String packResolutionName = "orig"; + + private static final String TAG = ResourceManager.class.getCanonicalName(); + public static final String NAME = TAG; + + private HashMap particleEffects = new HashMap(1); + private TextureAtlas currentProjectAtlas; + + private HashMap spineAnimAtlases = new HashMap(); + private HashMap spriteAnimAtlases = new HashMap(); + private HashMap spriterAnimFiles = new HashMap(); + private HashMap bitmapFonts = new HashMap<>(); + private HashMap shaderPrograms = new HashMap(1); + + private TextureRegion defaultRegion; + + private ResolutionManager resolutionManager; + + public ResourceManager() { + super(NAME); + } + + @Override + public void onRegister() { + super.onRegister(); + facade = HyperLap2DFacade.getInstance(); + resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + + // TODO: substitute this with "NO IMAGE" icon + Pixmap pixmap = new Pixmap(50, 50, Pixmap.Format.RGBA8888); + pixmap.setColor(new Color(1, 1, 1, 0.4f)); + pixmap.fill(); + defaultRegion = new TextureRegion(new Texture(pixmap)); + } + + @Override + public TextureRegion getTextureRegion(String name) { + TextureRegion reg = currentProjectAtlas.findRegion(name); + + if(reg == null) { + reg = defaultRegion; + } + + return reg; + } + + public TextureAtlas getTextureAtlas() { + return currentProjectAtlas; + } + + @Override + public ParticleEffect getParticleEffect(String name) { + return new ParticleEffect(particleEffects.get(name)); + } + + + @Override + public TextureAtlas getSkeletonAtlas(String animationName) { + SpineAnimData animData = spineAnimAtlases.get(animationName); + return animData.atlas; + } + + /** + * Sets working resolution, please set before doing any loading + * @param resolution String resolution name, default is "orig" later use resolution names created in editor + */ + public void setWorkingResolution(String resolution) { + ResolutionEntryVO resolutionObject = getProjectVO().getResolution("resolutionName"); + if(resolutionObject != null) { + packResolutionName = resolution; + } + } + + + @Override + public FileHandle getSkeletonJSON(String animationName) { + SpineAnimData animData = spineAnimAtlases.get(animationName); + return animData.jsonFile; + } + + @Override + public FileHandle getSCMLFile(String name) { + return spriterAnimFiles.get(name); + } + + + @Override + public TextureAtlas getSpriteAnimation(String animationName) { + return spriteAnimAtlases.get(animationName); + } + + + @Override + public BitmapFont getBitmapFont(String fontName, int fontSize) { + FontSizePair pair = new FontSizePair(fontName, fontSize); + return bitmapFonts.get(pair); + } + + + @Override + public MySkin getSkin() { + //return textureManager.projectSkin; + // not sure if we are going to use skins for labels + return null; + } + + @Override + public ProjectInfoVO getProjectVO() { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + return projectManager.getCurrentProjectInfoVO(); + } + + + @Override + public SceneVO getSceneVO(String name) { + SceneDataManager sceneDataManager = facade.retrieveProxy(SceneDataManager.NAME); + // TODO: this should be cached + FileHandle file = Gdx.files.internal(sceneDataManager.getCurrProjectScenePathByName(name)); + Json json = new Json(); + json.setIgnoreUnknownFields(true); + return json.fromJson(SceneVO.class, file.readString()); + } + + public void loadCurrentProjectData(String projectPath, String curResolution) { + packResolutionName = curResolution; + loadCurrentProjectAssets(projectPath + "/assets/" + curResolution + "/pack/pack.atlas"); + loadCurrentProjectSkin(projectPath + "/assets/orig/styles"); + loadCurrentProjectParticles(projectPath + "/assets/orig/particles"); + loadCurrentProjectSpineAnimations(projectPath + "/assets/", curResolution); + loadCurrentProjectSpriteAnimations(projectPath + "/assets/", curResolution); + loadCurrentProjectSpriterAnimations(projectPath + "/assets/", curResolution); + loadCurrentProjectBitmapFonts(projectPath, curResolution); + loadCurrentProjectShaders(projectPath + "/assets/shaders/"); + } + + private void loadCurrentProjectParticles(String path) { + particleEffects.clear(); + FileHandle sourceDir = new FileHandle(path); + for (FileHandle entry : sourceDir.list()) { + File file = entry.file(); + String filename = file.getName(); + if (file.isDirectory() || filename.endsWith(".DS_Store")) continue; + + ParticleEffect particleEffect = new ParticleEffect(); + particleEffect.load(Gdx.files.internal(file.getAbsolutePath()), currentProjectAtlas, ""); + particleEffects.put(filename, particleEffect); + } + + } + + + private void loadCurrentProjectSpineAnimations(String path, String curResolution) { + spineAnimAtlases.clear(); + FileHandle sourceDir = new FileHandle(path + "orig/spine-animations"); + for (FileHandle entry : sourceDir.list()) { + if (entry.file().isDirectory()) { + String animName = FilenameUtils.removeExtension(entry.file().getName()); + TextureAtlas atlas = new TextureAtlas(Gdx.files.internal(path + curResolution + "/spine-animations/" + File.separator + animName + File.separator + animName + ".atlas")); + FileHandle animJsonFile = Gdx.files.internal(entry.file().getAbsolutePath() + File.separator + animName + ".json"); + SpineAnimData data = new SpineAnimData(); + data.atlas = atlas; + data.jsonFile = animJsonFile; + data.animName = animName; + spineAnimAtlases.put(animName, data); + } + } + + } + + private void loadCurrentProjectSpriteAnimations(String path, String curResolution) { + spriteAnimAtlases.clear(); + FileHandle sourceDir = new FileHandle(path + curResolution + "/sprite-animations"); + for (FileHandle entry : sourceDir.list()) { + if (entry.file().isDirectory()) { + String animName = FilenameUtils.removeExtension(entry.file().getName()); + try { + TextureAtlas atlas = new TextureAtlas(Gdx.files.internal(entry.file().getAbsolutePath() + File.separator + animName + ".atlas")); + spriteAnimAtlases.put(animName, atlas); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + private void loadCurrentProjectSpriterAnimations(String path, String curResolution) { + spriterAnimFiles.clear(); + FileHandle sourceDir = new FileHandle(path + "orig" + "/spriter-animations"); + for (FileHandle entry : sourceDir.list()) { + if (entry.file().isDirectory()) { + String animName = entry.file().getName(); + FileHandle scmlFile = new FileHandle(path + "orig" + "/spriter-animations/" + animName + "/" + animName + ".scml"); + spriterAnimFiles.put(animName, scmlFile); + } + } + } + + public void loadCurrentProjectAssets(String packPath) { + try { + currentProjectAtlas = new TextureAtlas(Gdx.files.getFileHandle(packPath, Files.FileType.Internal)); + } catch (Exception e) { + currentProjectAtlas = new TextureAtlas(); + } + } + + public ArrayList getProjectRequiredFontsList() { + HashSet fontsToLoad = new HashSet<>(); + + for (int i = 0; i < getProjectVO().scenes.size(); i++) { + SceneVO scene = getSceneVO(getProjectVO().scenes.get(i).sceneName); + CompositeVO composite = scene.composite; + if (composite == null) { + continue; + } + FontSizePair[] fonts = composite.getRecursiveFontList(); + for (CompositeItemVO library : getProjectVO().libraryItems.values()) { + FontSizePair[] libFonts = library.composite.getRecursiveFontList(); + Collections.addAll(fontsToLoad, libFonts); + } + Collections.addAll(fontsToLoad, fonts); + } + + return new ArrayList<>(fontsToLoad); + } + + public void loadCurrentProjectBitmapFonts(String path, String curResolution) { + bitmapFonts.clear(); + + ArrayList requiredFonts = getProjectRequiredFontsList(); + for (int i = 0; i < requiredFonts.size(); i++) { + FontSizePair pair = requiredFonts.get(i); + FileHandle fontFile; + try { + fontFile = getTTFSafely(pair.fontName); + FreeTypeFontGenerator generator = new FreeTypeFontGenerator(fontFile); + FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter(); + parameter.size = Math.round(pair.fontSize * resolutionManager.getCurrentMul()); + BitmapFont font = generator.generateFont(parameter); + font.setUseIntegerPositions(false); + bitmapFonts.put(pair, font); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private void loadCurrentProjectShaders(String path) { + Iterator> it = shaderPrograms.entrySet().iterator(); + while (it.hasNext()) { + Entry pair = it.next(); + pair.getValue().dispose(); + it.remove(); + } + shaderPrograms.clear(); + FileHandle sourceDir = new FileHandle(path); + for (FileHandle entry : sourceDir.list()) { + File file = entry.file(); + String filename = file.getName().replace(".vert", "").replace(".frag", ""); + if (file.isDirectory() || filename.endsWith(".DS_Store") || shaderPrograms.containsKey(filename)) continue; + // check if pair exists. + if(Gdx.files.internal(path + filename + ".vert").exists() && Gdx.files.internal(path + filename + ".frag").exists()) { + ShaderProgram shaderProgram = new ShaderProgram(Gdx.files.internal(path + filename + ".vert"), Gdx.files.internal(path + filename + ".frag")); + System.out.println(shaderProgram.getLog()); + shaderPrograms.put(filename, shaderProgram); + } + } + + } + + /** + * @param fontPath + * @deprecated + */ + private void loadCurrentProjectSkin(String fontPath) { + /* + File styleFile = new File(fontPath, "styles.dt"); + FileHandle f = new FileHandle(styleFile); + + if (styleFile.isFile() && styleFile.exists()) { + projectSkin = new MySkin(f); + ObjectMap map = projectSkin.getAll(BitmapFont.class); + for (ObjectMap.Entry entry : map.entries()) { + projectSkin.getFont(entry.key).getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); + } + } + */ + } + + public FileHandle getTTFSafely(String fontName) throws IOException { + FontManager fontManager = facade.retrieveProxy(FontManager.NAME); + + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + String expectedPath = projectManager.getFreeTypeFontPath() + File.separator + fontName + ".ttf"; + FileHandle expectedFile = Gdx.files.internal(expectedPath); + if (!expectedFile.exists()) { + // let's check if system fonts fot it + HashMap fonts = fontManager.getFontsMap(); + if (fonts.containsKey(fontName)) { + File source = new File(fonts.get(fontName)); + FileUtils.copyFile(source, expectedFile.file()); + expectedFile = Gdx.files.internal(expectedPath); + } else { + throw new FileNotFoundException(); + } + } + + return expectedFile; + } + + public void addBitmapFont(String name, int size, BitmapFont font) { + bitmapFonts.put(new FontSizePair(name, size), font); + } + + public void flushAllUnusedFonts() { + //List of fonts that are required to be in memory + ArrayList requiredFonts = getProjectRequiredFontsList(); + ArrayList fontsInMemory = new ArrayList<>(bitmapFonts.keySet()); + + for (FontSizePair font : fontsInMemory) { + if (!requiredFonts.contains(font)) { + bitmapFonts.remove(font); + } + } + } + + public boolean isFontLoaded(String shortName, int fontSize) { + return bitmapFonts.containsKey(new FontSizePair(shortName, fontSize)); + } + + public void prepareEmbeddingFont(String fontfamily, int fontSize) { + flushAllUnusedFonts(); + + if (isFontLoaded(fontfamily, fontSize)) { + return; + } + + FontManager fontManager = facade.retrieveProxy(FontManager.NAME); + + FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter(); + parameter.size = fontSize; + + FreeTypeFontGenerator generator = new FreeTypeFontGenerator(fontManager.getTTFByName(fontfamily)); + BitmapFont font = generator.generateFont(parameter); + font.setUseIntegerPositions(false); + addBitmapFont(fontfamily, parameter.size, font); + } + + public HashMap getProjectSpineAnimationsList() { + return spineAnimAtlases; + } + + public HashMap getProjectSpriteAnimationsList() { + return spriteAnimAtlases; + } + + public HashMap getProjectSpriterAnimationsList() { + return spriterAnimFiles; + } + + public TextureAtlas getProjectAssetsList() { + return currentProjectAtlas; + } + + public HashMap getProjectParticleList() { + return particleEffects; + } + + @Override + public ResolutionEntryVO getLoadedResolution() { + if(packResolutionName.equals("orig")) { + return getProjectVO().originalResolution; + } + return getProjectVO().getResolution(packResolutionName); + } + + @Override + public ShaderProgram getShaderProgram(String shaderName) { + return shaderPrograms.get(shaderName); + } + + public HashMap getShaders() { + return shaderPrograms; + } +} diff --git a/src/main/java/games/rednblack/editor/proxy/SceneDataManager.java b/src/main/java/games/rednblack/editor/proxy/SceneDataManager.java new file mode 100644 index 00000000..959b8097 --- /dev/null +++ b/src/main/java/games/rednblack/editor/proxy/SceneDataManager.java @@ -0,0 +1,144 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.proxy; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.puremvc.patterns.proxy.BaseProxy; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.data.SceneVO; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +/** + * Created by sargis on 3/23/15. + */ +public class SceneDataManager extends BaseProxy { + + private static final String TAG = SceneDataManager.class.getCanonicalName(); + public static final String NAME = TAG; + + public SceneDataManager() { + super(NAME); + } + + @Override + public void onRegister() { + super.onRegister(); + facade = HyperLap2DFacade.getInstance(); + } + + public SceneVO createNewScene(String name) { + SceneVO vo = new SceneVO(); + vo.sceneName = name; + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + try { + String projPath = projectManager.getCurrentProjectPath(); + FileUtils.writeStringToFile(new File(projPath + "/project.dt"), projectManager.currentProjectInfoVO.constructJsonString(), "utf-8"); + FileUtils.writeStringToFile(new File(projPath + "/scenes/" + vo.sceneName + ".dt"), vo.constructJsonString(), "utf-8"); + projectManager.currentProjectInfoVO.scenes.add(vo); + } catch (IOException e) { + e.printStackTrace(); + } + return vo; + } + + public void loadScene(SceneVO sceneVO, String resolution) { + /* + if (sceneVO == null || sceneVO.composite == null) return; + + FontSizePair[] fonts = sceneVO.composite.getRecursiveFontList(); + TextureManager textureManager = facade.retrieveProxy(TextureManager.NAME); + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + textureManager.loadBitmapFonts(fonts, resolutionManager.getCurrentMul());*/ + + // Apparently all was loaded when project was loaded + } + + public String getCurrProjectScenePathByName(String sceneName) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + return projectManager.getCurrentProjectPath() + "/scenes/" + sceneName + ".dt"; + } + + public void saveScene(SceneVO vo) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + try { + FileUtils.writeStringToFile(new File(projectManager.getCurrentProjectPath() + "/scenes/" + vo.sceneName + ".dt"), + vo.constructJsonString(), "utf-8"); + CommandManager commandManager = facade.retrieveProxy(CommandManager.NAME); + commandManager.saveEvent(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + public void deleteCurrentScene() { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + if (projectManager.currentProjectVO.lastOpenScene.equals("MainScene")) { + return; + } + deleteScene(projectManager.currentProjectVO.lastOpenScene); + } + + private void deleteScene(String sceneName) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + ArrayList scenes = projectManager.currentProjectInfoVO.scenes; + SceneVO sceneToDelete = null; + for (SceneVO scene : scenes) { + if (scene.sceneName.equals(sceneName)) { + sceneToDelete = scene; + break; + } + } + if (sceneToDelete != null) { + scenes.remove(sceneToDelete); + } + projectManager.currentProjectInfoVO.scenes = scenes; + String projPath = projectManager.getCurrentProjectPath(); + try { + FileUtils.writeStringToFile(new File(projPath + "/project.dt"), projectManager.currentProjectInfoVO.constructJsonString(), "utf-8"); + FileUtils.forceDelete(new File(projPath + "/scenes/" + sceneName + ".dt")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void buildScenes(String targetPath) { + ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME); + String srcPath = projectManager.getCurrentProjectPath() + "/scenes"; + FileHandle scenesDirectoryHandle = Gdx.files.absolute(srcPath); + File fileTarget = new File(targetPath + "/" + scenesDirectoryHandle.name()); + try { + FileUtils.copyDirectory(scenesDirectoryHandle.file(), fileTarget); + } catch (IOException e) { + e.printStackTrace(); + } + //copy project dt + try { + FileUtils.copyFile(new File(projectManager.getCurrentProjectPath() + "/project.dt"), new File(targetPath + "/project.dt")); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/games/rednblack/editor/splash/SplashMediator.java b/src/main/java/games/rednblack/editor/splash/SplashMediator.java new file mode 100644 index 00000000..bc8c3c36 --- /dev/null +++ b/src/main/java/games/rednblack/editor/splash/SplashMediator.java @@ -0,0 +1,47 @@ +package games.rednblack.editor.splash; + +import com.puremvc.patterns.mediator.SimpleMediator; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.HyperLap2DApp; +import games.rednblack.editor.HyperLap2DFacade; + +public class SplashMediator extends SimpleMediator { + + private static final String TAG = SplashMediator.class.getCanonicalName(); + private static final String NAME = TAG; + + public SplashMediator() { + super(NAME, new Object()); + } + + @Override + public void onRegister() { + super.onRegister(); + facade = HyperLap2DFacade.getInstance(); + } + + @Override + public String[] listNotificationInterests() { + return new String[]{ + SplashScreenAdapter.UPDATE_SPLASH, + SplashScreenAdapter.CLOSE_SPLASH + }; + } + + @Override + public void handleNotification(Notification notification) { + super.handleNotification(notification); + System.out.println(notification.getBody().toString()); + + if (HyperLap2DApp.getInstance().splashWindow != null && HyperLap2DApp.getInstance().mainWindow != null) { + ((SplashScreenAdapter)(HyperLap2DApp.getInstance().splashWindow.getListener())).setProgressStatus(notification.getBody().toString()); + + if (notification.getName().equals(SplashScreenAdapter.CLOSE_SPLASH)) { + ((SplashScreenAdapter)(HyperLap2DApp.getInstance().splashWindow.getListener())).loadedData(); + HyperLap2DApp.getInstance().mainWindow.setVisible(true); + } + + HyperLap2DApp.getInstance().splashWindow.focusWindow(); + } + } +} diff --git a/src/main/java/games/rednblack/editor/splash/SplashScreen.java b/src/main/java/games/rednblack/editor/splash/SplashScreen.java new file mode 100644 index 00000000..d934680b --- /dev/null +++ b/src/main/java/games/rednblack/editor/splash/SplashScreen.java @@ -0,0 +1,33 @@ +package games.rednblack.editor.splash; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.ScreenAdapter; +import com.badlogic.gdx.graphics.GL20; + +public class SplashScreen extends ScreenAdapter { + + private SplashStage stage; + + public SplashScreen() { + stage = new SplashStage(); + } + + @Override + public void render(float delta) { + super.render(delta); + + Gdx.gl.glClearColor(0, 0, 0, 0); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + stage.act(delta); + stage.draw(); + } + + public void loadedData() { + stage.loadedData(); + } + + public void setProgressStatus(String status) { + stage.setProgressStatus(status); + } +} diff --git a/src/main/java/games/rednblack/editor/splash/SplashScreenAdapter.java b/src/main/java/games/rednblack/editor/splash/SplashScreenAdapter.java new file mode 100644 index 00000000..89ed7b2b --- /dev/null +++ b/src/main/java/games/rednblack/editor/splash/SplashScreenAdapter.java @@ -0,0 +1,62 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.splash; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Game; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.NinePatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.actions.Actions; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import games.rednblack.editor.HyperLap2DApp; +import games.rednblack.editor.Sync; +import games.rednblack.editor.utils.AppConfig; +import org.lwjgl.glfw.GLFW; + +/** + * Created by azakhary on 5/15/2015. + */ +public class SplashScreenAdapter extends Game { + + private static final String prefix = "games.rednblack.editor.splash"; + public static final String UPDATE_SPLASH = prefix + ".UPDATE"; + public static final String CLOSE_SPLASH = prefix + ".CLOSE"; + + private SplashScreen screen; + + @Override + public void create () { + screen = new SplashScreen(); + setScreen(screen); + } + + public void loadedData() { + screen.loadedData(); + } + + public void setProgressStatus(String status) { + screen.setProgressStatus(status); + } +} diff --git a/src/main/java/games/rednblack/editor/splash/SplashStage.java b/src/main/java/games/rednblack/editor/splash/SplashStage.java new file mode 100644 index 00000000..1b53394f --- /dev/null +++ b/src/main/java/games/rednblack/editor/splash/SplashStage.java @@ -0,0 +1,79 @@ +package games.rednblack.editor.splash; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.actions.Actions; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import games.rednblack.editor.HyperLap2DApp; +import games.rednblack.editor.utils.AppConfig; + +public class SplashStage extends Stage { + private TextureAtlas atlas; + private Image logoText; + private Label progress; + + public SplashStage() { + atlas = new TextureAtlas(Gdx.files.internal("splash/splash.atlas")); + BitmapFont robotFont = new BitmapFont(Gdx.files.internal("splash/myriad.fnt")); + Label.LabelStyle labelStyle = new Label.LabelStyle(robotFont, new Color(0, 0, 0, 1f)); + + Image bg = new Image(atlas.findRegion("bg_color")); + bg.setX(0); + bg.setY(0); + bg.setWidth(getWidth()); + bg.setHeight(getHeight()); + addActor(bg); + + Image imageBg = new Image(atlas.findRegion("splash_bg")); + imageBg.setX(0); + imageBg.setY(getHeight() - imageBg.getHeight()); + addActor(imageBg); + + Image logo = new Image(atlas.findRegion("splash_logo")); + logo.setX(25); + logo.setY(getHeight() - logo.getHeight() - 20); + addActor(logo); + + logoText = new Image(atlas.findRegion("splash_logo_text")); + logoText.setX(200); + logoText.setY(logo.getY() + 30); + addActor(logoText); + + progress = new Label("Loading fonts", labelStyle); + progress.setX(logoText.getX() + ((logoText.getWidth() - progress.getWidth() )/ 2)); + progress.setY(logo.getY() + 5); + addActor(progress); + + Label companyName = new Label("Red & Black Games", labelStyle); + companyName.setX(13); + companyName.setY(55 - companyName.getHeight() - 7); + addActor(companyName); + + Label copyright = new Label("Copyright (c) 2020. All rights reserved.", labelStyle); + copyright.setX(13); + copyright.setY(companyName.getY() - 20); + addActor(copyright); + + Label version = new Label(AppConfig.getInstance().version, labelStyle); + version.setX(getWidth() - 13 - version.getWidth()); + version.setY(companyName.getY()); + addActor(version); + + setProgressStatus("Initializing"); + } + + public void setProgressStatus(String status) { + progress.setText(status); + progress.setX(logoText.getX() + ((logoText.getWidth() - progress.getWidth()) / 2)); + } + + public void loadedData() { + addAction(Actions.sequence(Actions.delay(0.8f), Actions.run(() -> { + HyperLap2DApp.getInstance().splashWindow.closeWindow(); + }))); + } +} diff --git a/src/main/java/games/rednblack/editor/system/PhysicsAdjustSystem.java b/src/main/java/games/rednblack/editor/system/PhysicsAdjustSystem.java new file mode 100644 index 00000000..ca72a2ba --- /dev/null +++ b/src/main/java/games/rednblack/editor/system/PhysicsAdjustSystem.java @@ -0,0 +1,38 @@ +package games.rednblack.editor.system; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.World; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.physics.PhysicsBodyComponent; +import games.rednblack.editor.renderer.physics.PhysicsBodyLoader; +import games.rednblack.editor.renderer.systems.PhysicsSystem; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +public class PhysicsAdjustSystem extends PhysicsSystem { + + private Vector2 transformVec = new Vector2(); + + public PhysicsAdjustSystem(World world) { + super(world); + setPhysicsOn(false); + } + + @Override + protected void processEntity(Entity entity, float deltaTime) { + + TransformComponent transformComponent = transformComponentMapper.get(entity); + processBody(entity); + + PhysicsBodyComponent physicsBodyComponent = ComponentRetriever.get(entity, PhysicsBodyComponent.class); + + if(physicsBodyComponent.body == null) return; + + transformVec.x = (transformComponent.x + transformComponent.originX) * PhysicsBodyLoader.getScale(); + transformVec.y = (transformComponent.y + transformComponent.originY) * PhysicsBodyLoader.getScale(); + physicsBodyComponent.body.setTransform(transformVec, transformComponent.rotation * MathUtils.degreesToRadians); + + } + +} diff --git a/src/main/java/games/rednblack/editor/utils/AppConfig.java b/src/main/java/games/rednblack/editor/utils/AppConfig.java new file mode 100644 index 00000000..b23868eb --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/AppConfig.java @@ -0,0 +1,72 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils; + +import games.rednblack.editor.Main; + +import java.io.*; +import java.util.Properties; + +public class AppConfig { + + public static AppConfig instance; + + public String version; + + public Properties properties; + + private AppConfig() {} + + public static AppConfig getInstance() { + if(instance == null) { + instance = new AppConfig(); + instance.loadProperties(); + } + + return instance; + } + + private void loadProperties() { + File root = new File(new File(".").getAbsolutePath()).getParentFile(); + File configDir = new File(root.getAbsolutePath() + File.separator + "configs"); + + properties = new Properties(); + InputStream propertiesInput = null; + + File file = new File(configDir.getAbsolutePath() + File.separator + "app.properties"); + if (file.exists()) { + try { + propertiesInput = new FileInputStream(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } else { + propertiesInput = Main.class.getClassLoader().getResourceAsStream("configs/app.properties"); + } + + if (propertiesInput != null) { + try { + properties.load(propertiesInput); + version = properties.getProperty("version"); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/games/rednblack/editor/utils/Constants.java b/src/main/java/games/rednblack/editor/utils/Constants.java new file mode 100644 index 00000000..c7edee66 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/Constants.java @@ -0,0 +1,12 @@ +package games.rednblack.editor.utils; + +/** + * Created by Sasun Poghosyan on 5/6/2016. + */ +public class Constants { + + public static final float FLOAT_MIN = -1000000f; + public static final float FLOAT_MAX = 1000000f; + + +} diff --git a/src/main/java/games/rednblack/editor/utils/EntityBounds.java b/src/main/java/games/rednblack/editor/utils/EntityBounds.java new file mode 100644 index 00000000..e464069c --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/EntityBounds.java @@ -0,0 +1,193 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Matrix3; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.light.LightObjectComponent; +import games.rednblack.editor.renderer.components.particle.ParticleComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by azakhary on 6/5/2015. + */ +public class EntityBounds extends Rectangle { + + private float scaleX; + private float scaleY; + + /** + * points winding order is counterclockwise (p1 -> p2 -> p3 -> p4) + * * **p3 + * p4 ** * + * * * + * * * + * * **p2 + * p1 ** + */ + private final Vector2 p1 = new Vector2(); + private final Vector2 p2 = new Vector2(); + private final Vector2 p3 = new Vector2(); + private final Vector2 p4 = new Vector2(); + private final Array boundPointList = new Array<>(); + private final float[] boundPoints = new float[8]; + + public EntityBounds(Entity entity) { + setEntity(entity); + } + + public EntityBounds() { + + } + + public void setEntity(Entity entity) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + x = transformComponent.x; + y = transformComponent.y; + scaleX = transformComponent.scaleX; + scaleY = transformComponent.scaleY; + width = dimensionsComponent.width; + height = dimensionsComponent.height; + + if (entity.getComponent(LightObjectComponent.class) != null) { + x += dimensionsComponent.boundBox.x; + y += dimensionsComponent.boundBox.y; + scaleX = 1; + scaleY = 1; + width = dimensionsComponent.boundBox.width; + height = dimensionsComponent.boundBox.height; + } + + if (ComponentRetriever.get(entity, ParticleComponent.class) != null) { + width = dimensionsComponent.boundBox.width; + height = dimensionsComponent.boundBox.height; + dimensionsComponent.width = width; + dimensionsComponent.height = height; + x += dimensionsComponent.boundBox.x; + y += dimensionsComponent.boundBox.y; + } + + Matrix3 transMat = TransformUtils.identity(); + + if ((scaleX != 1 || scaleY != 1) && transformComponent.rotation != 0) { + transMat = TransformUtils.scaleRotMat(transformComponent); + } else if (scaleX != 1 || scaleY != 1) { + transMat = TransformUtils.scalingMat(transformComponent); + } else if (transformComponent.rotation != 0) { + transMat = TransformUtils.rotationMat(transformComponent); + } + + p1.set(x, y).mul(transMat); + p2.set(x + width, y).mul(transMat); + p3.set(x + width, y + height).mul(transMat); + p4.set(x, y + height).mul(transMat); + + boundPoints[0] = p1.x; + boundPoints[1] = p1.y; + boundPoints[2] = p2.x; + boundPoints[3] = p2.y; + boundPoints[4] = p3.x; + boundPoints[5] = p3.y; + boundPoints[6] = p4.x; + boundPoints[7] = p4.y; + } + + public float getVisualWidth() { + return Math.abs(getWidth() * scaleX); + } + + public float getVisualHeight() { + return Math.abs(getHeight() * scaleY); + } + + public float getVisualX() { + return Math.min(getP1x(), getP3x()); + } + + public float getVisualY() { + return Math.min(getP1y(), getP3y()); + } + + public float getVisualRightX() { + return Math.max(getP1x(), getP3x()); + } + + public float getVisualTopY() { + return Math.max(getP1y(), getP3y()); + } + + public float getP1x() { + return p1.x; + } + + public float getP1y() { + return p1.y; + } + + public float getP2x() { + return p2.x; + } + + public float getP2y() { + return p2.y; + } + + public float getP3x() { + return p3.x; + } + + public float getP3y() { + return p3.y; + } + + public float getP4x() { + return p4.x; + } + + public float getP4y() { + return p4.y; + } + + public float[] getBoundPoints() { + return boundPoints; + } + + public float[] getBoundPoints(Entity entity) { + setEntity(entity); + return boundPoints; + } + + public Array getBoundPointsList() { + boundPointList.clear(); + boundPointList.addAll(p1, p2, p3, p4); + return boundPointList; + } + + public Array getBoundPointsList(Entity entity) { + setEntity(entity); + return getBoundPointsList(); + + } +} diff --git a/src/main/java/games/rednblack/editor/utils/Guide.java b/src/main/java/games/rednblack/editor/utils/Guide.java new file mode 100644 index 00000000..17dd4ee8 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/Guide.java @@ -0,0 +1,13 @@ +package games.rednblack.editor.utils; + +/** + * Created by azakhary on 7/18/2015. + */ +public class Guide { + public boolean isVertical; + public float pos; + + public Guide(boolean isVertical) { + this.isVertical = isVertical; + } +} \ No newline at end of file diff --git a/src/main/java/games/rednblack/editor/utils/HyperLap2DUtils.java b/src/main/java/games/rednblack/editor/utils/HyperLap2DUtils.java new file mode 100644 index 00000000..b4cfe450 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/HyperLap2DUtils.java @@ -0,0 +1,70 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.InputStream; + +import org.apache.commons.io.filefilter.SuffixFileFilter; +import org.apache.commons.lang3.SystemUtils; + +/** + * Created by sargis on 4/1/15. + */ +public class HyperLap2DUtils { + public static final FilenameFilter PNG_FILTER = new SuffixFileFilter(".png"); + public static final FilenameFilter TTF_FILTER = new SuffixFileFilter(".ttf"); + public static final FilenameFilter JSON_FILTER = new SuffixFileFilter(".json"); + public static final FilenameFilter SCML_FILTER = new SuffixFileFilter(".scml"); + public static final FilenameFilter DT_FILTER = new SuffixFileFilter(".dt"); + public static final String MY_DOCUMENTS_PATH = getMyDocumentsLocation(); + + + private static String getMyDocumentsLocation() { + String myDocuments = null; + try { + if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_MAC_OSX) { + myDocuments = System.getProperty("user.home") + File.separator + "Documents"; + } + if (SystemUtils.IS_OS_WINDOWS) { + Process p = Runtime.getRuntime().exec("reg query \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\" /v personal"); + p.waitFor(); + + InputStream in = p.getInputStream(); + byte[] b = new byte[in.available()]; + in.read(b); + in.close(); + + myDocuments = new String(b); + myDocuments = myDocuments.split("\\s\\s+")[4]; + } + if (SystemUtils.IS_OS_LINUX) { + myDocuments = System.getProperty("user.home") + File.separator + "Documents"; + } + + + } catch (Throwable t) { + t.printStackTrace(); + } + + return myDocuments; + } + +} diff --git a/src/main/java/games/rednblack/editor/utils/ImportUtils.java b/src/main/java/games/rednblack/editor/utils/ImportUtils.java new file mode 100644 index 00000000..afc44c5a --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/ImportUtils.java @@ -0,0 +1,288 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.utils.Array; +import com.kotcrab.vis.ui.widget.file.FileTypeFilter; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.proxy.ProjectManager; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Created by azakhary on 7/22/2015. + */ +public class ImportUtils { + + private static ImportUtils instance; + + public static final int TYPE_FAILED = -3; + public static final int TYPE_MIXED = -2; + public static final int TYPE_UNKNOWN = -1; + public static final int TYPE_UNSUPPORTED = 0; + public static final int TYPE_IMAGE = 1; + public static final int TYPE_ANIMATION_PNG_SEQUENCE = 2; + public static final int TYPE_SPRITE_ANIMATION_ATLAS = 3; + public static final int TYPE_SPINE_ANIMATION = 4; + public static final int TYPE_SPRITER_ANIMATION = 5; + public static final int TYPE_TTF_FONT = 6; + public static final int TYPE_BITMAP_FONT = 7; + public static final int TYPE_PARTICLE_EFFECT = 8; + public static final int TYPE_TEXTURE_ATLAS = 9; + public static final int TYPE_SHADER = 10; + + private final ArrayList supportedTypes = new ArrayList<>(); + private final FileTypeFilter fileTypeFilter; + + private ImportUtils() { + supportedTypes.add(TYPE_IMAGE); + supportedTypes.add(TYPE_ANIMATION_PNG_SEQUENCE); + supportedTypes.add(TYPE_SPRITE_ANIMATION_ATLAS); + supportedTypes.add(TYPE_SPINE_ANIMATION); + supportedTypes.add(TYPE_SPRITER_ANIMATION); + supportedTypes.add(TYPE_PARTICLE_EFFECT); + supportedTypes.add(TYPE_SHADER); + // TODO: not yet supported + //supportedTypes.add(TYPE_TEXTURE_ATLAS); + //supportedTypes.add(TYPE_TTF_FONT); + //supportedTypes.add(TYPE_BITMAP_FONT); + + fileTypeFilter = new FileTypeFilter(false); + + fileTypeFilter.addRule("All Supported (*.png, *.atlas, *.p, *.json, *.scml, *.vert, *.frag)", "png", "atlas", "p", "json", "vert", "frag"); + fileTypeFilter.addRule("PNG File (*.png)", "png"); + fileTypeFilter.addRule("Sprite Animation Atlas File (*.atlas)", "atlas"); + fileTypeFilter.addRule("Particle Effect (*.p)", "p"); + fileTypeFilter.addRule("Spine Animation (*.json)", "json"); + fileTypeFilter.addRule("Spriter Animation (*.scml)", "scml"); + fileTypeFilter.addRule("Shader (*.vert, *.frag)", "vert", "frag"); + } + + public static ImportUtils getInstance() { + if(instance == null) { + instance = new ImportUtils(); + } + + return instance; + } + + public FileTypeFilter getFileTypeFilter() { + return fileTypeFilter; + } + + public static int getImportType(String[] paths) { + int mainType = TYPE_MIXED; + String[] names = new String[paths.length]; + for(int i = 0; i < paths.length; i++) { + String path = paths[i]; + int type = getFileType(path); + if(i == 0) mainType = type; + if(mainType != type) { + return TYPE_MIXED; + } + names[i] = FilenameUtils.getBaseName(path); + } + + if(mainType == TYPE_IMAGE) { + // check they are a PNG sequence; + boolean isSequence = isAnimationSequence(names); + if(isSequence) { + mainType = TYPE_ANIMATION_PNG_SEQUENCE; + } + } + + if(mainType > 0 && !ImportUtils.getInstance().supportedTypes.contains(mainType)) { + mainType = TYPE_UNSUPPORTED; + } + + return mainType; + } + + public static int getFileType(String path) { + int type = checkFileTypeByExtension(path); + if(type == TYPE_UNKNOWN) { + // we have to check by getting into the file + type = checkFileTypeByContent(path); + } + + return type; + } + + public static int checkFileTypeByExtension(String path) { + String ext = FilenameUtils.getExtension(path).toLowerCase(); + if(ext.equals("png")) { + return TYPE_IMAGE; + } + if(ext.equals("ttf")) { + return TYPE_TTF_FONT; + } + if(ext.equals("scml")) { + return TYPE_SPRITER_ANIMATION; + } + if(ext.equals("vert") || ext.equals("frag")) { + return TYPE_SHADER; + } + + return TYPE_UNKNOWN; + } + + public static int checkFileTypeByContent(String path) { + File file = new File(path); + long fileSizeInBytes = file.length(); + // Convert the bytes to Kilobytes (1 KB = 1024 Bytes) + long fileSizeInKB = fileSizeInBytes / 1024; + + if(fileSizeInKB > 1000) { + return TYPE_UNKNOWN; + } + + int type = TYPE_UNKNOWN; + + try { + String contents = FileUtils.readFileToString(file); + + // checking for atlas file + if(contents.contains("format: ") && contents.contains("filter: ") && contents.contains("xy: ")) { + type = TYPE_TEXTURE_ATLAS; + // need to figure out if atlas is animation or just files. + TextureAtlas atlas = new TextureAtlas(new FileHandle(file)); + + boolean isSequence = isAtlasAnimationSequence(atlas.getRegions()); + if(isSequence) { + type = TYPE_SPRITE_ANIMATION_ATLAS; + } + + return type; + } + System.out.println("is spine?"); + + // checking for spine animation + if(contents.contains("\"skeleton\":{") || contents.contains("\"skeleton\": {") || contents.contains("{\"bones\":[")) { + type = TYPE_SPINE_ANIMATION; + System.out.println("is spine"); + return type; + } + + // checking for particle effect + if(contents.contains("- Options - ") && contents.contains("- Image Paths -") && contents.contains("- Duration -")) { + type = TYPE_PARTICLE_EFFECT; + return type; + } + + } catch (IOException e) { + } + + return type; + } + + public static boolean isAnimationSequence(String[] names) { + if(names.length < 2) return false; + int[] sequenceArray = new int[names.length]; + for(int i = 0; i < names.length; i++) { + String name = names[i]; + // try to remove extension if any + if(name.indexOf(".") > 0) name = name.substring(0, name.indexOf(".")); + try { + int intValue = Integer.parseInt(name.replaceAll("(.+)_", "")); + sequenceArray[i] = intValue; + } catch (Exception e) { + sequenceArray[i] = -10; + } + } + Arrays.sort(sequenceArray); + if(sequenceArray[0] == 0 && sequenceArray[sequenceArray.length-1] == sequenceArray.length-1) { + return true; + } + + return sequenceArray[0] == 1 && sequenceArray[sequenceArray.length - 1] == sequenceArray.length; + } + + public static boolean isAtlasAnimationSequence(Array regions) { + if(regions.size < 2) return false; + + //Check old .atlas format + String[] regionNames = new String[regions.size]; + for(int i = 0; i < regions.size; i++) { + regionNames[i] = regions.get(i).name; + } + + if (isAnimationSequence(regionNames)) + return true; + + //New .atlas format + String animName = regions.get(0).name; + for (int i = 1; i < regions.size; i++) { + if (!animName.equals(regions.get(i).name)) { + return false; + } + } + + return regions.get(regions.size - 1).index == regions.size - 1; + } + + public boolean checkAssetExistence(int type, Array fileHandles) { + boolean exists = false; + ProjectManager projectManager = HyperLap2DFacade.getInstance().retrieveProxy(ProjectManager.NAME); + + String dir = ProjectManager.IMAGE_DIR_PATH; + String ext = "png"; + switch (type) { + case ImportUtils.TYPE_IMAGE: + case ImportUtils.TYPE_TEXTURE_ATLAS: + dir = ProjectManager.IMAGE_DIR_PATH; + ext = "png"; + break; + case ImportUtils.TYPE_PARTICLE_EFFECT: + dir = ProjectManager.PARTICLE_DIR_PATH; + ext = "p"; + break; + case ImportUtils.TYPE_SPRITER_ANIMATION: + case ImportUtils.TYPE_SPINE_ANIMATION: + dir = ProjectManager.SPINE_DIR_PATH; + ext = "json"; + break; + case ImportUtils.TYPE_SPRITE_ANIMATION_ATLAS: + case ImportUtils.TYPE_ANIMATION_PNG_SEQUENCE: + dir = ProjectManager.SPRITE_DIR_PATH; + ext = "atlas"; + break; + case ImportUtils.TYPE_SHADER: + dir = ProjectManager.SHADER_DIR_PATH; + ext = "frag"; + break; + } + + for (FileHandle file : fileHandles) { + File f = new File(projectManager.getCurrentProjectPath() + File.separator + dir + File.separator + file.nameWithoutExtension() + "." + ext); + System.out.println(f.getAbsolutePath()); + exists = f.exists(); + if (exists) + break; + } + + return exists; + } +} diff --git a/src/main/java/games/rednblack/editor/utils/InputFilters.java b/src/main/java/games/rednblack/editor/utils/InputFilters.java new file mode 100644 index 00000000..932e3fcd --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/InputFilters.java @@ -0,0 +1,16 @@ +package games.rednblack.editor.utils; + +import com.kotcrab.vis.ui.widget.VisTextField; + +public class InputFilters { + public static final VisTextField.TextFieldFilter ALPHANUMERIC = new VisTextField.TextFieldFilter() { + @Override + public boolean acceptChar(VisTextField textField, char c) { + + if(Character.isAlphabetic(c) || Character.isDigit(c)) + return true; + + return false; + } + }; +} diff --git a/src/main/java/games/rednblack/editor/utils/MoveCommandBuilder.java b/src/main/java/games/rednblack/editor/utils/MoveCommandBuilder.java new file mode 100644 index 00000000..d2492d79 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/MoveCommandBuilder.java @@ -0,0 +1,65 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by azakhary on 6/5/2015. + */ +public class MoveCommandBuilder { + + Array payload; + + public MoveCommandBuilder() { + payload = new Array<>(); + } + + public void setX(Entity entity, float x) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + setXY(entity, x, transformComponent.y); + } + + public void setY(Entity entity, float y) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + setXY(entity, transformComponent.x, y); + } + + public void setXY(Entity entity, float x, float y) { + Object[] data = new Object[2]; + data[0] = entity; + data[1] = new Vector2(x, y); + payload.add(data); + } + + public void clear() { + payload = new Array<>(); + } + + public void execute() { + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_ITEMS_MOVE_TO, payload); + } + +} diff --git a/src/main/java/games/rednblack/editor/utils/NinePatchUtils.java b/src/main/java/games/rednblack/editor/utils/NinePatchUtils.java new file mode 100644 index 00000000..c33fe639 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/NinePatchUtils.java @@ -0,0 +1,191 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils; + +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Transparency; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.util.ArrayList; + +/** + * Created by sargis on 8/29/14. + */ +public class NinePatchUtils { + + public static Integer[] findPatches(BufferedImage image) { + int width = image.getWidth(); + int height = image.getHeight(); + int[] row = new int[width]; + int[] column = new int[height]; + row = getPixels(image, 0, 0, width, 1, row); + column = getPixels(image, 0, 0, 1, height, column); + + boolean[] result = new boolean[1]; + //row = getPixels(image, 0, height - 1, width, 1, row); + //column = getPixels(image, width - 1, 0, 1, height, column); + + Pair>> top = getPatches(row, result); + Pair>> left = getPatches(column, result); + + Pair topPadding = getPadding(top.first); + Pair leftPadding = getPadding(left.first); + + return new Integer[]{topPadding.first, topPadding.second, leftPadding.first, leftPadding.second}; + } + + public static BufferedImage removePatches(BufferedImage image) { + BufferedImage buffer = createTranslucentCompatibleImage( + image.getWidth() - 2, image.getHeight() - 2); + + Graphics2D g2 = buffer.createGraphics(); + g2.drawImage(image, -1, -1, null); + g2.dispose(); + return buffer; + } + + public static BufferedImage convertTo9Patch(BufferedImage image, Integer[] patches, float ratio) { + BufferedImage buffer = createTranslucentCompatibleImage(image.getWidth() + 2, image.getHeight() + 2); + Graphics2D g2 = buffer.createGraphics(); + g2.drawImage(image, 1, 1, null); + g2.dispose(); + draw9Patch(buffer, patches, ratio); + return buffer; + } + + private static GraphicsConfiguration getGraphicsConfiguration() { + GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); + return environment.getDefaultScreenDevice().getDefaultConfiguration(); + } + + private static BufferedImage createTranslucentCompatibleImage(int width, int height) { + return getGraphicsConfiguration().createCompatibleImage(width, height, + Transparency.TRANSLUCENT); + } + + private static Pair getPadding(java.util.List> pairs) { + if (pairs.size() == 0) { + return new Pair<>(0, 0); + } else if (pairs.size() == 1) { + if (pairs.get(0).first == 1) { + return new Pair<>(pairs.get(0).second - pairs.get(0).first, 0); + } else { + return new Pair<>(0, pairs.get(0).second - pairs.get(0).first); + } + } else { + int index = pairs.size() - 1; + return new Pair<>(pairs.get(0).second - pairs.get(0).first, + pairs.get(index).second - pairs.get(index).first); + } + } + + private static int[] getPixels(BufferedImage img, int x, int y, int w, int h, int[] pixels) { + if (w == 0 || h == 0) { + return new int[0]; + } + + if (pixels == null) { + pixels = new int[w * h]; + } else if (pixels.length < w * h) { + throw new IllegalArgumentException("Pixels array must have a length >= w * h"); + } + + int imageType = img.getType(); + if (imageType == BufferedImage.TYPE_INT_ARGB || imageType == BufferedImage.TYPE_INT_RGB) { + Raster raster = img.getRaster(); + return (int[]) raster.getDataElements(x, y, w, h, pixels); + } + + // Unmanages the image + return img.getRGB(x, y, w, h, pixels, 0, w); + } + + private static Pair>> getPatches(int[] pixels, boolean[] startWithPatch) { + int lastIndex = 1; + int lastPixel = pixels[1]; + boolean first = true; + + java.util.List> fixed = new ArrayList<>(); + java.util.List> patches = new ArrayList<>(); + + for (int i = 1; i < pixels.length - 1; i++) { + int pixel = pixels[i]; + if (pixel != lastPixel) { + if (lastPixel == 0xFF000000) { + if (first) startWithPatch[0] = true; + patches.add(new Pair(lastIndex, i)); + } else { + fixed.add(new Pair(lastIndex, i)); + } + first = false; + + lastIndex = i; + lastPixel = pixel; + } + } + if (lastPixel == 0xFF000000) { + if (first) startWithPatch[0] = true; + patches.add(new Pair<>(lastIndex, pixels.length - 1)); + } else { + fixed.add(new Pair<>(lastIndex, pixels.length - 1)); + } + + if (patches.size() == 0) { + patches.add(new Pair<>(1, pixels.length - 1)); + startWithPatch[0] = true; + fixed.clear(); + } + + return new Pair<>(fixed, patches); + } + + private static void draw9Patch(BufferedImage image, Integer[] patches, float ratio) { + int width = image.getWidth(); + int height = image.getHeight(); + int wStart = (int) (patches[0] * ratio) + 1; // this number should be rounded UP + int wEnd = (int) (width - patches[1] * ratio) - 1; + int hStart = (int) (patches[2] * ratio) + 1; // this number should be rounded UP + int hEnd = (int) (height - patches[3] * ratio) - 1; + for (int i = wStart; i < wEnd; i++) { + image.setRGB(i, 0, 0xFF000000); + image.setRGB(i, height - 1, 0xFF000000); + } + for (int i = hStart; i < hEnd; i++) { + image.setRGB(0, i, 0xFF000000); + image.setRGB(width - 1, i, 0xFF000000); + } + } + + static class Pair { + E first; + E second; + + Pair(E first, E second) { + this.first = first; + this.second = second; + } + + @Override + public String toString() { + return "Pair[" + first + ", " + second + "]"; + } + } +} diff --git a/src/main/java/games/rednblack/editor/utils/RoundUtils.java b/src/main/java/games/rednblack/editor/utils/RoundUtils.java new file mode 100644 index 00000000..ff424f31 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/RoundUtils.java @@ -0,0 +1,12 @@ +package games.rednblack.editor.utils; + +public class RoundUtils { + + public static float round(float number, int scale) { + int pow = 10; + for (int i = 1; i < scale; i++) + pow *= 10; + float tmp = number * pow; + return ( (float) ( (int) ((tmp - (int) tmp) >= 0.5f ? tmp + 1 : tmp) ) ) / pow; + } +} diff --git a/src/main/java/games/rednblack/editor/utils/StandardWidgetsFactory.java b/src/main/java/games/rednblack/editor/utils/StandardWidgetsFactory.java new file mode 100644 index 00000000..80f97b1d --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/StandardWidgetsFactory.java @@ -0,0 +1,191 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.ui.TextTooltip; +import com.badlogic.gdx.scenes.scene2d.ui.TooltipManager; +import com.badlogic.gdx.utils.Align; +import com.kotcrab.vis.ui.VisUI; +import com.kotcrab.vis.ui.util.InputValidator; +import com.kotcrab.vis.ui.widget.*; +import com.kotcrab.vis.ui.widget.spinner.IntSpinnerModel; +import com.kotcrab.vis.ui.widget.spinner.Spinner; +import games.rednblack.editor.proxy.CursorManager; +import games.rednblack.editor.view.ui.widget.CursorListener; +import games.rednblack.editor.view.ui.widget.ScrollFocusListener; +import games.rednblack.editor.view.ui.widget.components.TintButton; + +/** + * Creates standard widgets like labels or text fields with provided standard HyperLap2D specific visual style. + * Singleton helper class + */ +public class StandardWidgetsFactory { + + private static StandardWidgetsFactory instance; + + private StandardWidgetsFactory() { + + } + + public static StandardWidgetsFactory getInstance() { + if(instance == null) { + instance = new StandardWidgetsFactory(); + } + + return instance; + } + + public static VisLabel createLabel(String text, int alignment) { + Skin skin = VisUI.getSkin(); + VisLabel visLabel = new VisLabel(text, alignment); + visLabel.setStyle(skin.get("small", Label.LabelStyle.class)); + return visLabel; + } + + public static VisLabel createLabel(String text) { + return createLabel(text, Align.right); + } + + + public static VisTextField createTextField() { + return createTextField("default"); + } + + public static VisTextField createTextField(String style) { + VisTextField visTextField = new VisTextField("", style); + visTextField.addListener(new CursorListener(CursorManager.TEXT)); + return visTextField; + } + + public static VisTextField createTextField(String style, boolean textCursor) { + VisTextField visTextField = new VisTextField(); + Skin skin = VisUI.getSkin(); + visTextField.setStyle(skin.get(style, VisTextField.VisTextFieldStyle.class)); + if(textCursor) + visTextField.addListener(new CursorListener(CursorManager.TEXT)); + return visTextField; + } + + public static VisTextField createTextField(String style, VisTextField.TextFieldFilter textFieldFilter) { + VisTextField visTextField = createTextField(style); + visTextField.setTextFieldFilter(textFieldFilter); + return visTextField; + } + + public static VisValidatableTextField createValidableTextField(InputValidator inputValidator) { + VisValidatableTextField visTextField = createValidableTextField("default", inputValidator); + return visTextField; + } + + public static VisValidatableTextField createValidableTextField(String style, InputValidator inputValidator) { + VisValidatableTextField visTextField = new VisValidatableTextField(inputValidator); + Skin skin = VisUI.getSkin(); + visTextField.setStyle(skin.get(style, VisTextField.VisTextFieldStyle.class)); + visTextField.addListener(new CursorListener(CursorManager.TEXT)); + return visTextField; + } + + public static VisValidatableTextField createValidableTextField(String style, InputValidator inputValidator, VisTextField.TextFieldFilter textFieldFilter) { + VisValidatableTextField visTextField = createValidableTextField(style, inputValidator); + visTextField.setTextFieldFilter(textFieldFilter); + visTextField.addListener(new CursorListener(CursorManager.TEXT)); + return visTextField; + } + + public static Spinner createNumberSelector(int min, int max) { + return createNumberSelector(0, min, max); + } + + public static Spinner createNumberSelector(int initialValue, int min, int max) { + return createNumberSelector("default", initialValue, min, max, 1); + } + + public static Spinner createNumberSelector(String style, int min, int max) { + return createNumberSelector(style, 0, min, max, 1); + } + + public static Spinner createNumberSelector(String style, int initialValue, int min, int max, int step) { + Spinner selector = new Spinner(style, "", new IntSpinnerModel(initialValue, min, max, step)); + selector.addListener(new CursorListener(CursorManager.TEXT)); + return selector; + } + + public static VisTextArea createTextArea() { + return createTextArea("default"); + } + + public static VisTextArea createTextArea(String style) { + VisTextArea visTextArea = new VisTextArea("", style); + visTextArea.addListener(new CursorListener(CursorManager.TEXT)); + return visTextArea; + } + + public static VisCheckBox createCheckBox() { + return createCheckBox(""); + } + + public static VisCheckBox createCheckBox(String text) { + VisCheckBox visCheckBox = new VisCheckBox(text); + visCheckBox.addListener(new CursorListener(CursorManager.FINGER)); + return visCheckBox; + } + + public static VisSelectBox createSelectBox(Class type) { + return createSelectBox("default", type); + } + + public static VisSelectBox createSelectBox(String style, Class type) { + VisSelectBox visSelectBox = new VisSelectBox(style); + visSelectBox.addListener(new CursorListener(CursorManager.FINGER)); + return visSelectBox; + } + + public static TintButton createTintButton() { + return createTintButton(29,21); + } + + public static TintButton createTintButton(int width, int height) { + TintButton visCheckBox = new TintButton(width, height); + visCheckBox.addListener(new CursorListener(CursorManager.EYEDROPPER)); + return visCheckBox; + } + + public static VisScrollPane createScrollPane(Actor actor) { + VisScrollPane scrollPane = new VisScrollPane(actor); + scrollPane.addListener(new ScrollFocusListener()); + scrollPane.setFlickScroll(false); + return scrollPane; + } + + public static void addVisTooltip(Actor actor, String text) { + new Tooltip.Builder(text).target(actor).build(); + } + + public static void addTooltip(Actor actor, String text) { + TooltipManager.getInstance().initialTime = 1; + TooltipManager.getInstance().hideAll(); + + TextTooltip tooltip = new TextTooltip(text, VisUI.getSkin()); + tooltip.getContainer().pad(5); + actor.addListener(tooltip); + } +} diff --git a/src/main/java/games/rednblack/editor/utils/TransformCommandBuilder.java b/src/main/java/games/rednblack/editor/utils/TransformCommandBuilder.java new file mode 100644 index 00000000..85d6c082 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/TransformCommandBuilder.java @@ -0,0 +1,79 @@ +package games.rednblack.editor.utils; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.components.DimensionsComponent; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by Osman on 01.08.2015. + */ +public class TransformCommandBuilder { + + Array payload; + + public void begin(Entity forEntity) { + + TransformComponent transformComponent = ComponentRetriever.get(forEntity, TransformComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(forEntity, DimensionsComponent.class); + Object[] prevData = new Object[4]; + + payload = new Array<>(3); + payload.add(forEntity); + payload.add(prevData); + payload.add(new Object[4]); + + setPos(1, transformComponent.x, transformComponent.y); + setSize(1, dimensionsComponent.width, dimensionsComponent.height); + setScale(1, transformComponent.scaleX, transformComponent.scaleY); + setRotation(1, transformComponent.rotation); + + } + + private void setPos(int pIndex, float x, float y) { + ((Object[])payload.get(pIndex))[0] = new Vector2(x, y); + } + + private void setSize(int pIndex, float width, float height) { + ((Object[])payload.get(pIndex))[1] = new Vector2(width, height); + } + + private void setScale(int pIndex, float x, float y) { + ((Object[])payload.get(pIndex))[2] = new Vector2(x, y); + } + + private void setRotation(int pIndex, float rotation) { + ((Object[])payload.get(pIndex))[3] = rotation; + } + + public void setPos(float x, float y) { + setPos(2, x, y); + } + + public void setSize(float width, float height) { + setSize(2, width, height); + } + + public void setScale(float x, float y) { + setScale(2, x, y); + } + + public void setRotation(float rotation) { + setRotation(2, rotation); + } + + public void execute() { + // check if payload is worth sending + Object[] newData = (Object[]) payload.get(2); + for(Object o : newData) { + if (o != null) { + HyperLap2DFacade.getInstance().sendNotification(MsgAPI.ACTION_ITEM_TRANSFORM_TO, payload); + return; + } + } + } +} diff --git a/src/main/java/games/rednblack/editor/utils/TransformUtils.java b/src/main/java/games/rednblack/editor/utils/TransformUtils.java new file mode 100644 index 00000000..b63adf84 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/TransformUtils.java @@ -0,0 +1,73 @@ +package games.rednblack.editor.utils; + +import com.badlogic.gdx.math.Matrix3; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.renderer.components.TransformComponent; + +/** + * Created by Sasun Poghosyan on 4/18/2016. + */ +public class TransformUtils { + + private static final Matrix3 tempMat = new Matrix3(); + + + public static Matrix3 scaleRotMat(TransformComponent transformComponent) { + float translationX = transformComponent.x + transformComponent.originX; + float translationY = transformComponent.y + transformComponent.originY; + float scaleX = transformComponent.scaleX; + float scaleY = transformComponent.scaleY; + float angle = transformComponent.rotation; + tempMat.idt(); + tempMat.translate(translationX, translationY).rotate(angle).scale(scaleX, scaleY).translate(-translationX, -translationY); + return tempMat; + } + + public static Matrix3 scaleRotMat(float translationX, float translationY, float scaleX, float scaleY, float angle) { + tempMat.idt(); + tempMat.translate(translationX, translationY).rotate(angle).scale(scaleX, scaleY).translate(-translationX, -translationY); + return tempMat; + } + + public static Matrix3 scalingMat(TransformComponent transformComponent) { + float translationX = transformComponent.x + transformComponent.originX; + float translationY = transformComponent.y + transformComponent.originY; + float scaleX = transformComponent.scaleX; + float scaleY = transformComponent.scaleY; + tempMat.idt(); + tempMat.translate(translationX, translationY).scale(scaleX, scaleY).translate(-translationX, -translationY); + return tempMat; + } + + public static Matrix3 scalingMat(float translationX, float translationY, float scaleX, float scaleY) { + tempMat.idt(); + tempMat.translate(translationX, translationY).scale(scaleX, scaleY).translate(-translationX, -translationY); + return tempMat; + } + + public static Matrix3 rotationMat(TransformComponent transformComponent) { + float translationX = transformComponent.x + transformComponent.originX; + float translationY = transformComponent.y + transformComponent.originY; + float angle = transformComponent.rotation; + tempMat.idt(); + tempMat.translate(translationX, translationY).rotate(angle).translate(-translationX, -translationY); + return tempMat; + } + + public static Matrix3 rotationMat(float translationX, float translationY, float angle) { + tempMat.idt(); + tempMat.translate(translationX, translationY).rotate(angle).translate(-translationX, -translationY); + return tempMat; + } + + public static Matrix3 identity() { + return tempMat.idt(); + } + + public static Matrix3 copy(Matrix3 matrix3) { + Matrix3 copy = new Matrix3(); + copy.set(matrix3.getValues()); + return copy; + } + +} diff --git a/src/main/java/games/rednblack/editor/utils/poly/Clipper.java b/src/main/java/games/rednblack/editor/utils/poly/Clipper.java new file mode 100644 index 00000000..8da63b71 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/poly/Clipper.java @@ -0,0 +1,105 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils.poly; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.utils.poly.earclipping.bayazit.BayazitDecomposer; +import games.rednblack.editor.utils.poly.earclipping.ewjordan.EwjordanDecomposer; + +/** + * + * @author Aurelien Ribon | http://www.aurelienribon.com/ + */ +public class Clipper { + public enum Polygonizer {EWJORDAN, BAYAZIT} + + public static Vector2[][] polygonize(Polygonizer polygonizer, Vector2[] points) { + Vector2[][] polygons = null; + + if (PolygonUtils.isPolygonCCW(points)) { + List vertices = Arrays.asList(points); + Collections.reverse(vertices); + points = vertices.toArray(new Vector2[0]); + } + + switch (polygonizer) { + case EWJORDAN: + polygons = EwjordanDecomposer.decompose(points); + break; + + case BAYAZIT: + Array tmpPoints = new Array(points.length); + tmpPoints.addAll(points); + + Array> tmpPolygons; + + try { + tmpPolygons = BayazitDecomposer.ConvexPartition(tmpPoints); + } catch (Exception ex) { + tmpPolygons = null; + } + + if (tmpPolygons != null) { + polygons = new Vector2[tmpPolygons.size][]; + for (int i = 0; i < tmpPolygons.size; i++) { + polygons[i] = new Vector2[tmpPolygons.get(i).size]; + for (int ii = 0; ii < tmpPolygons.get(i).size; ii++) + polygons[i][ii] = new Vector2(tmpPolygons.get(i).get(ii)); + } + } + break; + } + + if (polygons != null) polygons = sliceForMax8Vertices(polygons); + return polygons; + } + + private static Vector2[][] sliceForMax8Vertices(Vector2[][] polygons) { + for (int i = 0; i < polygons.length; i++) { + Vector2[] poly = polygons[i]; + if (poly.length > 8) { + int limit = poly.length < 15 ? poly.length / 2 + 1 : 8; + Vector2[] newPoly1 = new Vector2[limit]; + Vector2[] newPoly2 = new Vector2[poly.length - limit + 2]; + System.arraycopy(poly, 0, newPoly1, 0, limit); + System.arraycopy(poly, limit - 1, newPoly2, 0, poly.length - limit + 1); + newPoly2[newPoly2.length - 1] = poly[0].cpy(); + + Vector2[][] newPolys = new Vector2[polygons.length + 1][]; + if (i > 0) { + System.arraycopy(polygons, 0, newPolys, 0, i); + } + if (i < polygons.length - 1) { + System.arraycopy(polygons, i + 1, newPolys, i + 2, polygons.length - i - 1); + } + newPolys[i] = newPoly1; + newPolys[i + 1] = newPoly2; + polygons = newPolys; + + i -= 1; + } + } + return polygons; + } +} diff --git a/src/main/java/games/rednblack/editor/utils/poly/PolygonUtils.java b/src/main/java/games/rednblack/editor/utils/poly/PolygonUtils.java new file mode 100644 index 00000000..93b03b87 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/poly/PolygonUtils.java @@ -0,0 +1,48 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils.poly; + +import com.badlogic.gdx.math.Vector2; + +/** + * + * @author Aurelien Ribon | http://www.aurelienribon.com/ + */ +public class PolygonUtils { + public static float getPolygonSignedArea(Vector2[] points) { + if (points.length < 3) + return 0; + + float sum = 0; + for (int i = 0; i < points.length; i++) { + Vector2 p1 = points[i]; + Vector2 p2 = i != points.length-1 ? points[i+1] : points[0]; + sum += (p1.x * p2.y) - (p1.y * p2.x); + } + return 0.5f * sum; + } + + public static float getPolygonArea(Vector2[] points) { + return Math.abs(getPolygonSignedArea(points)); + } + + public static boolean isPolygonCCW(Vector2[] points) { + return getPolygonSignedArea(points) > 0; + } +} diff --git a/src/main/java/games/rednblack/editor/utils/poly/TextureUtils.java b/src/main/java/games/rednblack/editor/utils/poly/TextureUtils.java new file mode 100644 index 00000000..e2a5148f --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/poly/TextureUtils.java @@ -0,0 +1,126 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils.poly; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureRegion; + +/** + * @author Aurelien Ribon | http://www.aurelienribon.com/ + */ +public class TextureUtils { + private static final int[] potWidths = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 5096}; + + // ------------------------------------------------------------------------- + + public static TextureRegion getPOTTexture(String path) { + if (path == null) return null; + + FileHandle file = Gdx.files.absolute(path); + if (!file.exists()) return null; + + Pixmap pixmap = new Pixmap(file); + int origW = pixmap.getWidth(); + int origH = pixmap.getHeight(); + int w = getNearestPOT(origW); + int h = getNearestPOT(origH); + int len = Math.max(w, h); + + Pixmap potPixmap = new Pixmap(len, len, pixmap.getFormat()); + potPixmap.drawPixmap(pixmap, 0, 0, 0, 0, origW, origH); + pixmap.dispose(); + + Texture texture = new Texture(potPixmap); + texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear); + + return new TextureRegion(texture, 0, 0, origW, origH); + } + + public static Pixmap getPOTPixmap(String path) { + if (path == null) return null; + + FileHandle file = Gdx.files.absolute(path); + if (!file.exists()) return null; + + Pixmap pixmap = new Pixmap(file); + int origW = pixmap.getWidth(); + int origH = pixmap.getHeight(); + int w = getNearestPOT(origW); + int h = getNearestPOT(origH); + int len = Math.max(w, h); + + Pixmap potPixmap = new Pixmap(len, len, pixmap.getFormat()); + potPixmap.drawPixmap(pixmap, 0, 0, 0, 0, origW, origH); + pixmap.dispose(); + + return potPixmap; + } + + // ------------------------------------------------------------------------- + + private static int getNearestPOT(int d) { + for (int i=0; i +/// Convex decomposition algorithm created by Mark Bayazit (http://mnbayazit.com/) +/// For more information about this algorithm, see http://mnbayazit.com/406/bayazit +/// +public class BayazitDecomposer { + + public static final float Epsilon = 1.192092896e-07f; + public static int MaxPolygonVertices = 8; + + public static Vector2 Cross(Vector2 a, float s) { + return new Vector2(s * a.y, -s * a.x); + } + + private static Vector2 At(int i, Array vertices) { + int s = vertices.size; + return vertices.get(i < 0 ? s - (-i % s) : i % s); + } + + private static Array Copy(int i, int j, Array vertices) { + Array p = new Array(); + while (j < i) + j += vertices.size; + // p.reserve(j - i + 1); + for (; i <= j; ++i) { + p.add(At(i, vertices)); + } + return p; + } + + public static float GetSignedArea(Array vect) { + int i; + float area = 0; + for (i = 0; i < vect.size; i++) { + int j = (i + 1) % vect.size; + area += vect.get(i).x * vect.get(j).y; + area -= vect.get(i).y * vect.get(j).x; + } + area /= 2.0f; + return area; + } + + public static float GetSignedArea(Vector2[] vect) { + int i; + float area = 0; + for (i = 0; i < vect.length; i++) { + int j = (i + 1) % vect.length; + area += vect[i].x * vect[j].y; + area -= vect[i].y * vect[j].x; + } + area /= 2.0f; + return area; + } + + public static Boolean IsCounterClockWise(Array vect) { + // We just return true for lines + if (vect.size < 3) + return true; + return (GetSignedArea(vect) > 0.0f); + } + + public static Boolean IsCounterClockWise(Vector2[] vect) { + // We just return true for lines + if (vect.length < 3) + return true; + return (GetSignedArea(vect) > 0.0f); + } + + // / + // / Decompose the polygon into several smaller non-concave polygon. + // / If the polygon is already convex, it will return the original polygon, + // unless it is over Settings.MaxPolygonVertices. + // / Precondition: Counter Clockwise polygon + // / + // / + // / + public static Array> ConvexPartition(Array vertices) { + // We force it to CCW as it is a precondition in this algorithm. + // vertices.ForceCounterClockWise(); + if (!IsCounterClockWise(vertices)) { + // Collections.reverse(vertices); + vertices.reverse(); + // Array reversed = new Array(vertices.size); + // for (int i = vertices.size - 1; i <= 0; i--) { + // reversed.add(vertices.get(i)); + // } + // vertices = reversed; + } + Array> list = new Array>(); + float d, lowerDist, upperDist; + Vector2 p; + Vector2 lowerInt = new Vector2(); + Vector2 upperInt = new Vector2(); // intersection points + int lowerIndex = 0, upperIndex = 0; + Array lowerPoly, upperPoly; + for (int i = 0; i < vertices.size; ++i) { + if (Reflex(i, vertices)) { + lowerDist = upperDist = Float.MAX_VALUE; // std::numeric_limits::max(); + for (int j = 0; j < vertices.size; ++j) { + // if line intersects with an edge + if (Left(At(i - 1, vertices), At(i, vertices), + At(j, vertices)) + && RightOn(At(i - 1, vertices), At(i, vertices), + At(j - 1, vertices))) { + // find the point of intersection + p = LineIntersect(At(i - 1, vertices), At(i, vertices), + At(j, vertices), At(j - 1, vertices)); + if (Right(At(i + 1, vertices), At(i, vertices), p)) { + // make sure it's inside the poly + d = SquareDist(At(i, vertices), p); + if (d < lowerDist) { + // keep only the closest intersection + lowerDist = d; + lowerInt = p; + lowerIndex = j; + } + } + } + if (Left(At(i + 1, vertices), At(i, vertices), + At(j + 1, vertices)) + && RightOn(At(i + 1, vertices), At(i, vertices), + At(j, vertices))) { + p = LineIntersect(At(i + 1, vertices), At(i, vertices), + At(j, vertices), At(j + 1, vertices)); + if (Left(At(i - 1, vertices), At(i, vertices), p)) { + d = SquareDist(At(i, vertices), p); + if (d < upperDist) { + upperDist = d; + upperIndex = j; + upperInt = p; + } + } + } + } + // if there are no vertices to connect to, choose a point in the + // middle + if (lowerIndex == (upperIndex + 1) % vertices.size) { + Vector2 sp = new Vector2((lowerInt.x + upperInt.x) / 2, + (lowerInt.y + upperInt.y) / 2); + lowerPoly = Copy(i, upperIndex, vertices); + lowerPoly.add(sp); + upperPoly = Copy(lowerIndex, i, vertices); + upperPoly.add(sp); + } else { + double highestScore = 0, bestIndex = lowerIndex; + while (upperIndex < lowerIndex) + upperIndex += vertices.size; + for (int j = lowerIndex; j <= upperIndex; ++j) { + if (CanSee(i, j, vertices)) { + double score = 1 / (SquareDist(At(i, vertices), + At(j, vertices)) + 1); + if (Reflex(j, vertices)) { + if (RightOn(At(j - 1, vertices), + At(j, vertices), At(i, vertices)) + && LeftOn(At(j + 1, vertices), + At(j, vertices), + At(i, vertices))) { + score += 3; + } else { + score += 2; + } + } else { + score += 1; + } + if (score > highestScore) { + bestIndex = j; + highestScore = score; + } + } + } + lowerPoly = Copy(i, (int) bestIndex, vertices); + upperPoly = Copy((int) bestIndex, i, vertices); + } + list.addAll(ConvexPartition(lowerPoly)); + list.addAll(ConvexPartition(upperPoly)); + return list; + } + } + // polygon is already convex + if (vertices.size > MaxPolygonVertices) { + lowerPoly = Copy(0, vertices.size / 2, vertices); + upperPoly = Copy(vertices.size / 2, 0, vertices); + list.addAll(ConvexPartition(lowerPoly)); + list.addAll(ConvexPartition(upperPoly)); + } else + list.add(vertices); + // The polygons are not guaranteed to be with collinear points. We + // remove + // them to be sure. + for (int i = 0; i < list.size; i++) { + list.set(i, SimplifyTools.CollinearSimplify(list.get(i), 0)); + } + // Remove empty vertice collections + for (int i = list.size - 1; i >= 0; i--) { + if (list.get(i).size == 0) + list.removeIndex(i); + } + return list; + } + + private static Boolean CanSee(int i, int j, Array vertices) { + if (Reflex(i, vertices)) { + if (LeftOn(At(i, vertices), At(i - 1, vertices), At(j, vertices)) + && RightOn(At(i, vertices), At(i + 1, vertices), + At(j, vertices))) + return false; + } else { + if (RightOn(At(i, vertices), At(i + 1, vertices), At(j, vertices)) + || LeftOn(At(i, vertices), At(i - 1, vertices), + At(j, vertices))) + return false; + } + if (Reflex(j, vertices)) { + if (LeftOn(At(j, vertices), At(j - 1, vertices), At(i, vertices)) + && RightOn(At(j, vertices), At(j + 1, vertices), + At(i, vertices))) + return false; + } else { + if (RightOn(At(j, vertices), At(j + 1, vertices), At(i, vertices)) + || LeftOn(At(j, vertices), At(j - 1, vertices), + At(i, vertices))) + return false; + } + for (int k = 0; k < vertices.size; ++k) { + if ((k + 1) % vertices.size == i || k == i + || (k + 1) % vertices.size == j || k == j) { + continue; // ignore incident edges + } + Vector2 intersectionPoint = new Vector2(); + if (LineIntersect(At(i, vertices), At(j, vertices), + At(k, vertices), At(k + 1, vertices), true, true, + intersectionPoint)) { + return false; + } + } + return true; + } + + public static Vector2 LineIntersect(Vector2 p1, Vector2 p2, Vector2 q1, + Vector2 q2) { + Vector2 i = new Vector2(); + float a1 = p2.y - p1.y; + float b1 = p1.x - p2.x; + float c1 = a1 * p1.x + b1 * p1.y; + float a2 = q2.y - q1.y; + float b2 = q1.x - q2.x; + float c2 = a2 * q1.x + b2 * q1.y; + float det = a1 * b2 - a2 * b1; + if (!FloatEquals(det, 0)) { + // lines are not parallel + i.x = (b2 * c1 - b1 * c2) / det; + i.y = (a1 * c2 - a2 * c1) / det; + } + return i; + } + + public static Boolean FloatEquals(float value1, float value2) { + return Math.abs(value1 - value2) <= Epsilon; + } + + // / + // / This method detects if two line segments (or lines) intersect, + // / and, if so, the point of intersection. Use the + // and + // / parameters to set whether the + // intersection point + // / must be on the first and second line segments. Setting these + // / both to true means you are doing a line-segment to line-segment + // / intersection. Setting one of them to true means you are doing a + // / line to line-segment intersection test, and so on. + // / Note: If two line segments are coincident, then + // / no intersection is detected (there are actually + // / infinite intersection points). + // / Author: Jeremy Bell + // / + // / The first point of the first line segment. + // / The second point of the first line + // segment. + // / The first point of the second line + // segment. + // / The second point of the second line + // segment. + // / This is set to the intersection + // / point if an intersection is detected. + // / Set this to true to require that the + // / intersection point be on the first line segment. + // / Set this to true to require that the + // / intersection point be on the second line segment. + // / True if an intersection is detected, false + // otherwise. + public static Boolean LineIntersect(Vector2 point1, Vector2 point2, + Vector2 point3, Vector2 point4, Boolean firstIsSegment, + Boolean secondIsSegment, Vector2 point) { + point = new Vector2(); + // these are reused later. + // each lettered sub-calculation is used twice, except + // for b and d, which are used 3 times + float a = point4.y - point3.y; + float b = point2.x - point1.x; + float c = point4.x - point3.x; + float d = point2.y - point1.y; + // denominator to solution of linear system + float denom = (a * b) - (c * d); + // if denominator is 0, then lines are parallel + if (!(denom >= -Epsilon && denom <= Epsilon)) { + float e = point1.y - point3.y; + float f = point1.x - point3.x; + float oneOverDenom = 1.0f / denom; + // numerator of first equation + float ua = (c * e) - (a * f); + ua *= oneOverDenom; + // check if intersection point of the two lines is on line segment 1 + if (!firstIsSegment || ua >= 0.0f && ua <= 1.0f) { + // numerator of second equation + float ub = (b * e) - (d * f); + ub *= oneOverDenom; + // check if intersection point of the two lines is on line + // segment 2 + // means the line segments intersect, since we know it is on + // segment 1 as well. + if (!secondIsSegment || ub >= 0.0f && ub <= 1.0f) { + // check if they are coincident (no collision in this case) + if (ua != 0f || ub != 0f) { + // There is an intersection + point.x = point1.x + ua * b; + point.y = point1.y + ua * d; + return true; + } + } + } + } + return false; + } + + // precondition: ccw + private static Boolean Reflex(int i, Array vertices) { + return Right(i, vertices); + } + + private static Boolean Right(int i, Array vertices) { + return Right(At(i - 1, vertices), At(i, vertices), At(i + 1, vertices)); + } + + private static Boolean Left(Vector2 a, Vector2 b, Vector2 c) { + return Area(a, b, c) > 0; + } + + private static Boolean LeftOn(Vector2 a, Vector2 b, Vector2 c) { + return Area(a, b, c) >= 0; + } + + private static Boolean Right(Vector2 a, Vector2 b, Vector2 c) { + return Area(a, b, c) < 0; + } + + private static Boolean RightOn(Vector2 a, Vector2 b, Vector2 c) { + return Area(a, b, c) <= 0; + } + + public static float Area(Vector2 a, Vector2 b, Vector2 c) { + return a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y); + } + + private static float SquareDist(Vector2 a, Vector2 b) { + float dx = b.x - a.x; + float dy = b.y - a.y; + return dx * dx + dy * dy; + } +} + +class SimplifyTools { + private static Boolean[] _usePt; + private static double _distanceTolerance; + + // / + // / Removes all collinear points on the polygon. + // / + // / The polygon that needs simplification. + // / The collinearity tolerance. + // / A simplified polygon. + public static Array CollinearSimplify(Array vertices, + float collinearityTolerance) { + // We can't simplify polygons under 3 vertices + if (vertices.size < 3) + return vertices; + Array simplified = new Array(); + for (int i = 0; i < vertices.size; i++) { + int prevId = i - 1; + if (prevId < 0) + prevId = vertices.size - 1; + int nextId = i + 1; + if (nextId >= vertices.size) + nextId = 0; + Vector2 prev = vertices.get(prevId); + Vector2 current = vertices.get(i); + Vector2 next = vertices.get(nextId); + // If they collinear, continue + if (Collinear(prev, current, next, collinearityTolerance)) + continue; + simplified.add(current); + } + return simplified; + } + + public static Boolean Collinear(Vector2 a, Vector2 b, Vector2 c, + float tolerance) { + return FloatInRange(BayazitDecomposer.Area(a, b, c), -tolerance, + tolerance); + } + + public static Boolean FloatInRange(float value, float min, float max) { + return (value >= min && value <= max); + } + + // / + // / Removes all collinear points on the polygon. + // / Has a default bias of 0 + // / + // / The polygon that needs simplification. + // / A simplified polygon. + public static Array CollinearSimplify(Array vertices) { + return CollinearSimplify(vertices, 0); + } + + // / + // / Ramer-Douglas-Peucker polygon simplification algorithm. This is the + // general recursive version that does not use the + // / speed-up technique by using the Melkman convex hull. + // / + // / If you pass in 0, it will remove all collinear points + // / + // / The simplified polygon + public static Array DouglasPeuckerSimplify( + Array vertices, float distanceTolerance) { + _distanceTolerance = distanceTolerance; + _usePt = new Boolean[vertices.size]; + for (int i = 0; i < vertices.size; i++) + _usePt[i] = true; + SimplifySection(vertices, 0, vertices.size - 1); + Array result = new Array(); + for (int i = 0; i < vertices.size; i++) + if (_usePt[i]) + result.add(vertices.get(i)); + return result; + } + + private static void SimplifySection(Array vertices, int i, int j) { + if ((i + 1) == j) + return; + Vector2 A = vertices.get(i); + Vector2 B = vertices.get(j); + double maxDistance = -1.0; + int maxIndex = i; + for (int k = i + 1; k < j; k++) { + double distance = DistancePointLine(vertices.get(k), A, B); + if (distance > maxDistance) { + maxDistance = distance; + maxIndex = k; + } + } + if (maxDistance <= _distanceTolerance) + for (int k = i + 1; k < j; k++) + _usePt[k] = false; + else { + SimplifySection(vertices, i, maxIndex); + SimplifySection(vertices, maxIndex, j); + } + } + + private static double DistancePointPoint(Vector2 p, Vector2 p2) { + double dx = p.x - p2.x; + double dy = p.y - p2.x; + return Math.sqrt(dx * dx + dy * dy); + } + + private static double DistancePointLine(Vector2 p, Vector2 A, Vector2 B) { + // if start == end, then use point-to-point distance + if (A.x == B.x && A.y == B.y) + return DistancePointPoint(p, A); + // otherwise use comp.graphics.algorithms Frequently Asked Questions + // method + /* + * (1) AC dot AB r = --------- ||AB||^2 r has the following meaning: r=0 + * Point = A r=1 Point = B r<0 Point is on the backward extension of AB + * r>1 Point is on the forward extension of AB 0= 1.0) + return DistancePointPoint(p, B); + /* + * (2) (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) s = ----------------------------- + * Curve^2 Then the distance from C to Point = |s|*Curve. + */ + double s = ((A.y - p.y) * (B.x - A.x) - (A.x - p.x) * (B.y - A.y)) + / ((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y)); + return Math.abs(s) + * Math.sqrt(((B.x - A.x) * (B.x - A.x) + (B.y - A.y) + * (B.y - A.y))); + } + + // From physics2d.net + public static Array ReduceByArea(Array vertices, + float areaTolerance) { + if (vertices.size <= 3) + return vertices; + if (areaTolerance < 0) { + throw new InvalidParameterException( + "areaTolerance: must be equal to or greater then zero."); + } + Array result = new Array(); + Vector2 v1, v2, v3; + float old1, old2, new1; + v1 = vertices.get(vertices.size - 2); + v2 = vertices.get(vertices.size - 1); + areaTolerance *= 2; + for (int index = 0; index < vertices.size; ++index, v2 = v3) { + if (index == vertices.size - 1) { + if (result.size == 0) { + throw new InvalidParameterException( + "areaTolerance: The tolerance is too high!"); + } + v3 = result.get(0); + } else { + v3 = vertices.get(index); + } + old1 = Cross(v1, v2); + old2 = Cross(v2, v3); + new1 = Cross(v1, v3); + if (Math.abs(new1 - (old1 + old2)) > areaTolerance) { + result.add(v2); + v1 = v2; + } + } + return result; + } + + public static Float Cross(Vector2 a, Vector2 b) { + return a.x * b.y - a.y * b.x; + } + + // From Eric Jordan's convex decomposition library + // / + // / Merges all parallel edges in the list of vertices + // / + // / The vertices. + // / The tolerance. + public static void MergeParallelEdges(Array vertices, + float tolerance) { + if (vertices.size <= 3) + return; // Can't do anything useful here to a triangle + Boolean[] mergeMe = new Boolean[vertices.size]; + int newNVertices = vertices.size; + // Gather points to process + for (int i = 0; i < vertices.size; ++i) { + int lower = (i == 0) ? (vertices.size - 1) : (i - 1); + int middle = i; + int upper = (i == vertices.size - 1) ? (0) : (i + 1); + float dx0 = vertices.get(middle).x - vertices.get(lower).x; + float dy0 = vertices.get(middle).y - vertices.get(lower).y; + float dx1 = vertices.get(upper).y - vertices.get(middle).x; + float dy1 = vertices.get(upper).y - vertices.get(middle).y; + float norm0 = (float) Math.sqrt(dx0 * dx0 + dy0 * dy0); + float norm1 = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1); + if (!(norm0 > 0.0f && norm1 > 0.0f) && newNVertices > 3) { + // Merge identical points + mergeMe[i] = true; + --newNVertices; + } + dx0 /= norm0; + dy0 /= norm0; + dx1 /= norm1; + dy1 /= norm1; + float cross = dx0 * dy1 - dx1 * dy0; + float dot = dx0 * dx1 + dy0 * dy1; + if (Math.abs(cross) < tolerance && dot > 0 && newNVertices > 3) { + mergeMe[i] = true; + --newNVertices; + } else + mergeMe[i] = false; + } + if (newNVertices == vertices.size || newNVertices == 0) + return; + int currIndex = 0; + // Copy the vertices to a new list and clear the old + Array oldVertices = new Array(vertices); + vertices.clear(); + for (int i = 0; i < oldVertices.size; ++i) { + if (mergeMe[i] || newNVertices == 0 || currIndex == newNVertices) + continue; + // Debug.Assert(currIndex < newNVertices); + vertices.add(oldVertices.get(i)); + ++currIndex; + } + } + + // Misc + // / + // / Merges the identical points in the polygon. + // / + // / The vertices. + // / + public static Array MergeIdenticalPoints(Array vertices) { + Array results = new Array(); + for (int i = 0; i < vertices.size; i++) { + Vector2 vOriginal = vertices.get(i); + + boolean alreadyExists = false; + for (int j = 0; j < results.size; j++) { + Vector2 v = results.get(j); + if (vOriginal.equals(v)) { + alreadyExists = true; + break; + } + } + if (!alreadyExists) + results.add(vertices.get(i)); + } + return results; + } + + // / + // / Reduces the polygon by distance. + // / + // / The vertices. + // / The distance between points. Points closer than + // this will be 'joined'. + // / + public static Array ReduceByDistance(Array vertices, + float distance) { + // We can't simplify polygons under 3 vertices + if (vertices.size < 3) + return vertices; + Array simplified = new Array(); + for (int i = 0; i < vertices.size; i++) { + Vector2 current = vertices.get(i); + int ii = i + 1; + if (ii >= vertices.size) + ii = 0; + Vector2 next = vertices.get(ii); + Vector2 diff = new Vector2(next.x - current.x, next.y - current.y); + // If they are closer than the distance, continue + if (diff.len2() <= distance) + continue; + simplified.add(current); + } + return simplified; + } + + // / + // / Reduces the polygon by removing the Nth vertex in the vertices list. + // / + // / The vertices. + // / The Nth point to remove. Example: 5. + // / + public static Array ReduceByNth(Array vertices, int nth) { + // We can't simplify polygons under 3 vertices + if (vertices.size < 3) + return vertices; + if (nth == 0) + return vertices; + Array result = new Array(vertices.size); + for (int i = 0; i < vertices.size; i++) { + if (i % nth == 0) + continue; + result.add(vertices.get(i)); + } + return result; + } +} diff --git a/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/EwjordanDecomposer.java b/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/EwjordanDecomposer.java new file mode 100644 index 00000000..565960f9 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/EwjordanDecomposer.java @@ -0,0 +1,206 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils.poly.earclipping.ewjordan; + +import com.badlogic.gdx.math.Vector2; + +/** + * Original code from EwJordan (http://www.ewjordan.com/earClip/) + */ +public class EwjordanDecomposer { + public static Vector2[][] decompose(Vector2[] points) { + int vNum = points.length; + float[] xv = new float[vNum]; + float[] yv = new float[vNum]; + + for (int i = 0; i < vNum; i++) { + xv[i] = points[i].x; + yv[i] = points[i].y; + } + + Triangle[] tempTriangles = triangulatePolygon(xv, yv, vNum); + Polygon[] tempPolygons = polygonizeTriangles(tempTriangles); + + if (tempPolygons == null) + return null; + + Vector2[][] polygons = new Vector2[tempPolygons.length][]; + for (int i = 0; i < tempPolygons.length; i++) { + polygons[i] = new Vector2[tempPolygons[i].nVertices]; + for (int ii = 0; ii < tempPolygons[i].nVertices; ii++) + polygons[i][ii] = new Vector2(tempPolygons[i].x[ii], tempPolygons[i].y[ii]); + } + + return polygons; + } + + // ------------------------------------------------------------------------- + + private static Triangle[] triangulatePolygon(float[] xv, float[] yv, int vNum) { + if (vNum < 3) + return null; + + Triangle[] buffer = new Triangle[vNum]; + int bufferSize = 0; + float[] xrem = new float[vNum]; + float[] yrem = new float[vNum]; + for (int i = 0; i < vNum; ++i) { + xrem[i] = xv[i]; + yrem[i] = yv[i]; + } + + while (vNum > 3) { + int earIndex = -1; + for (int i = 0; i < vNum; ++i) { + if (isEar(i, xrem, yrem)) { + earIndex = i; + break; + } + } + + if (earIndex == -1) + return null; + + --vNum; + float[] newx = new float[vNum]; + float[] newy = new float[vNum]; + int currDest = 0; + for (int i = 0; i < vNum; ++i) { + if (currDest == earIndex) { + ++currDest; + } + newx[i] = xrem[currDest]; + newy[i] = yrem[currDest]; + ++currDest; + } + + int under = (earIndex == 0) ? (xrem.length - 1) : (earIndex - 1); + int over = (earIndex == xrem.length - 1) ? 0 : (earIndex + 1); + + Triangle toAdd = new Triangle(xrem[earIndex], yrem[earIndex], xrem[over], yrem[over], xrem[under], yrem[under]); + buffer[bufferSize] = toAdd; + ++bufferSize; + + xrem = newx; + yrem = newy; + } + Triangle toAdd = new Triangle(xrem[1], yrem[1], xrem[2], yrem[2], xrem[0], yrem[0]); + buffer[bufferSize] = toAdd; + ++bufferSize; + + Triangle[] res = new Triangle[bufferSize]; + System.arraycopy(buffer, 0, res, 0, bufferSize); + return res; + } + + private static Polygon[] polygonizeTriangles(Triangle[] triangulated) { + Polygon[] polys; + int polyIndex = 0; + + if (triangulated == null) + return null; + + polys = new Polygon[triangulated.length]; + boolean[] covered = new boolean[triangulated.length]; + for (int i = 0; i < triangulated.length; i++) + covered[i] = false; + + boolean notDone = true; + + while (notDone) { + int currTri = -1; + for (int i = 0; i < triangulated.length; i++) { + if (!covered[i]) { + currTri = i; + break; + } + } + + if (currTri == -1) { + notDone = false; + } else { + Polygon poly = new Polygon(triangulated[currTri]); + covered[currTri] = true; + for (int i = 0; i < triangulated.length; i++) { + if (covered[i]) + continue; + + Polygon newP = poly.add(triangulated[i]); + if (newP == null) + continue; + + if (newP.isConvex()) { + poly = newP; + covered[i] = true; + } + } + polys[polyIndex] = poly; + polyIndex++; + } + } + + Polygon[] ret = new Polygon[polyIndex]; + System.arraycopy(polys, 0, ret, 0, polyIndex); + return ret; + } + + private static boolean isEar(int i, float[] xv, float[] yv) { + float dx0, dy0, dx1, dy1; + dx0 = dy0 = dx1 = dy1 = 0; + + if (i >= xv.length || i < 0 || xv.length < 3) + return false; + + int upper = i + 1; + int lower = i - 1; + + if (i == 0) { + dx0 = xv[0] - xv[xv.length - 1]; + dy0 = yv[0] - yv[yv.length - 1]; + dx1 = xv[1] - xv[0]; + dy1 = yv[1] - yv[0]; + lower = xv.length - 1; + } else if (i == xv.length - 1) { + dx0 = xv[i] - xv[i - 1]; + dy0 = yv[i] - yv[i - 1]; + dx1 = xv[0] - xv[i]; + dy1 = yv[0] - yv[i]; + upper = 0; + } else { + dx0 = xv[i] - xv[i - 1]; + dy0 = yv[i] - yv[i - 1]; + dx1 = xv[i + 1] - xv[i]; + dy1 = yv[i + 1] - yv[i]; + } + + float cross = dx0 * dy1 - dx1 * dy0; + if (cross > 0) + return false; + + Triangle myTri = new Triangle(xv[i], yv[i], xv[upper], yv[upper], xv[lower], yv[lower]); + for (int j = 0; j < xv.length; ++j) { + if (j == i || j == lower || j == upper) + continue; + if (myTri.isInside(xv[j], yv[j])) + return false; + } + + return true; + } +} diff --git a/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Polygon.java b/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Polygon.java new file mode 100644 index 00000000..2bc44026 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Polygon.java @@ -0,0 +1,150 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils.poly.earclipping.ewjordan; + +/** + * + * @author EwJordan (http://www.ewjordan.com/earClip/) + */ +public class Polygon { + public float[] x; + public float[] y; + public int nVertices; + + public Polygon(float[] _x, float[] _y) { + nVertices = _x.length; + x = new float[nVertices]; + y = new float[nVertices]; + for (int i = 0; i < nVertices; ++i) { + x[i] = _x[i]; + y[i] = _y[i]; + } + } + + public Polygon(Triangle t) { + this(t.x, t.y); + } + + public void set(Polygon p) { + nVertices = p.nVertices; + x = new float[nVertices]; + y = new float[nVertices]; + for (int i = 0; i < nVertices; ++i) { + x[i] = p.x[i]; + y[i] = p.y[i]; + } + } + + public boolean isConvex() { + boolean isPositive = false; + for (int i = 0; i < nVertices; ++i) { + int lower = (i == 0) ? (nVertices - 1) : (i - 1); + int middle = i; + int upper = (i == nVertices - 1) ? (0) : (i + 1); + float dx0 = x[middle] - x[lower]; + float dy0 = y[middle] - y[lower]; + float dx1 = x[upper] - x[middle]; + float dy1 = y[upper] - y[middle]; + float cross = dx0 * dy1 - dx1 * dy0; + //Cross product should have same sign + //for each vertex if poly is convex. + boolean newIsP = (cross > 0) ? true : false; + if (i == 0) { + isPositive = newIsP; + } else if (isPositive != newIsP) { + return false; + } + } + return true; + } + + /* + * Tries to add a triangle to the polygon. + * Returns null if it can't connect properly. + * Assumes bitwise equality of join vertices. + */ + public Polygon add(Triangle t) { + //First, find vertices that connect + int firstP = -1; + int firstT = -1; + int secondP = -1; + int secondT = -1; + for (int i = 0; i < nVertices; i++) { + if (t.x[0] == x[i] && t.y[0] == y[i]) { + if (firstP == -1) { + firstP = i; + firstT = 0; + } else { + secondP = i; + secondT = 0; + } + } else if (t.x[1] == x[i] && t.y[1] == y[i]) { + if (firstP == -1) { + firstP = i; + firstT = 1; + } else { + secondP = i; + secondT = 1; + } + } else if (t.x[2] == x[i] && t.y[2] == y[i]) { + if (firstP == -1) { + firstP = i; + firstT = 2; + } else { + secondP = i; + secondT = 2; + } + } + } + //Fix ordering if first should be last vertex of poly + if (firstP == 0 && secondP == nVertices - 1) { + firstP = nVertices - 1; + secondP = 0; + } + + //Didn't find it + if (secondP == -1) { + return null; + } + + //Find tip index on triangle + int tipT = 0; + if (tipT == firstT || tipT == secondT) { + tipT = 1; + } + if (tipT == firstT || tipT == secondT) { + tipT = 2; + } + + float[] newx = new float[nVertices + 1]; + float[] newy = new float[nVertices + 1]; + int currOut = 0; + for (int i = 0; i < nVertices; i++) { + newx[currOut] = x[i]; + newy[currOut] = y[i]; + if (i == firstP) { + ++currOut; + newx[currOut] = t.x[tipT]; + newy[currOut] = t.y[tipT]; + } + ++currOut; + } + return new Polygon(newx, newy); + } +} diff --git a/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Triangle.java b/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Triangle.java new file mode 100644 index 00000000..c06c822e --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Triangle.java @@ -0,0 +1,74 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils.poly.earclipping.ewjordan; + +/** + * + * @author EwJordan (http://www.ewjordan.com/earClip/) + */ +public class Triangle { + public float[] x; + public float[] y; + + public Triangle(float x1, float y1, float x2, float y2, float x3, float y3) { + x = new float[3]; + y = new float[3]; + float dx1 = x2 - x1; + float dx2 = x3 - x1; + float dy1 = y2 - y1; + float dy2 = y3 - y1; + float cross = dx1 * dy2 - dx2 * dy1; + boolean ccw = (cross > 0); + if (ccw) { + x[0] = x1; + x[1] = x2; + x[2] = x3; + y[0] = y1; + y[1] = y2; + y[2] = y3; + } else { + x[0] = x1; + x[1] = x3; + x[2] = x2; + y[0] = y1; + y[1] = y3; + y[2] = y2; + } + } + + public boolean isInside(float _x, float _y) { + float vx2 = _x - x[0]; + float vy2 = _y - y[0]; + float vx1 = x[1] - x[0]; + float vy1 = y[1] - y[0]; + float vx0 = x[2] - x[0]; + float vy0 = y[2] - y[0]; + + float dot00 = vx0 * vx0 + vy0 * vy0; + float dot01 = vx0 * vx1 + vy0 * vy1; + float dot02 = vx0 * vx2 + vy0 * vy2; + float dot11 = vx1 * vx1 + vy1 * vy1; + float dot12 = vx1 * vx2 + vy1 * vy2; + float invDenom = 1f / (dot00 * dot11 - dot01 * dot01); + float u = (dot11 * dot02 - dot01 * dot12) * invDenom; + float v = (dot00 * dot12 - dot01 * dot02) * invDenom; + + return ((u > 0) && (v > 0) && (u + v < 1)); + } +} diff --git a/src/main/java/games/rednblack/editor/utils/poly/tracer/TextureConverter.java b/src/main/java/games/rednblack/editor/utils/poly/tracer/TextureConverter.java new file mode 100644 index 00000000..b36911aa --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/poly/tracer/TextureConverter.java @@ -0,0 +1,964 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils.poly.tracer; + +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; + +/** +* http://astroboid.x50.cc/blog/2010/06/mapping-box2d-shapes-from-textures/ A +* mostly "blind" C# conversion of the TextureConverter code from Farseer, I +* even left the original german comments in place. Seems to work. +*/ +public class TextureConverter { + // User contribution from Sickbattery + // / + // / TODO: + // / 1.) Das Array welches ich bekomme am besten in einen boolean array + // verwandeln. Wurde die Geschwindigkeit verbessern + // / + private static int[][] ClosePixels = new int[][] { { -1, -1 }, { 0, -1 }, + { 1, -1 }, { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 } }; + + public static Array createPolygon(int[] data, int width, int height) + throws Exception { + PolygonCreationAssistance pca = new PolygonCreationAssistance(data, + width, height); + Array> verts = createPolygon(pca); + return verts.get(0); + } + + public static Array createPolygon(int[] data, int width, + int height, boolean holeDetection) throws Exception { + PolygonCreationAssistance pca = new PolygonCreationAssistance(data, + width, height); + pca.HoleDetection = holeDetection; + Array> verts = createPolygon(pca); + return verts.get(0); + } + + public static Array> createPolygon(int[] data, int width, + int height, float hullTolerance, int alphaTolerance, + boolean multiPartDetection, boolean holeDetection) throws Exception { + PolygonCreationAssistance pca = new PolygonCreationAssistance(data, + width, height); + pca.setHullTolerance(hullTolerance); + pca.setAlphaTolerance(alphaTolerance); + pca.MultipartDetection = multiPartDetection; + pca.HoleDetection = holeDetection; + return createPolygon(pca); + } + + private static Array> createPolygon( + PolygonCreationAssistance pca) throws Exception { + Array> polygons = new Array>(); + Array polygon; + Array holePolygon; + Vector2 holeEntrance = null; + Vector2 polygonEntrance = null; + Array blackList = new Array(); + // First of all: Check the array you just got. + if (pca.IsValid()) { + boolean searchOn; + do { + if (polygons.size == 0) { + polygon = CreateSimplePolygon(pca, new Vector2(), + new Vector2()); + if (polygon != null && polygon.size > 2) { + polygonEntrance = GetTopMostVertex(polygon); + } + } else if (polygonEntrance != null) { + polygon = CreateSimplePolygon(pca, polygonEntrance, + new Vector2(polygonEntrance.x - 1f, + polygonEntrance.y)); + } else { + break; + } + searchOn = false; + if (polygon != null && polygon.size > 2) { + if (pca.HoleDetection) { + do { + holeEntrance = GetHoleHullEntrance(pca, polygon, + holeEntrance); + if (holeEntrance != null) { + if (!vectorListContains(blackList, holeEntrance)) { + blackList.add(holeEntrance); + holePolygon = CreateSimplePolygon(pca, + holeEntrance, new Vector2( + holeEntrance.x + 1, + holeEntrance.y)); + if (holePolygon != null + && holePolygon.size > 2) { + holePolygon.add(holePolygon.get(0)); + Reference vertex2IndexRef = new Reference( + 0); + Reference vertex1IndexRef = new Reference( + 0); + if (SplitPolygonEdge(polygon, + EdgeAlignment.Vertical, + holeEntrance, vertex1IndexRef, + vertex2IndexRef)) { + + polygon.ensureCapacity(holePolygon.size); + for (int i = holePolygon.size - 1; i <= 0; i--) { + polygon.insert( + vertex2IndexRef.v, + holePolygon.get(i)); + } + } + } + } else { + break; + } + } else { + break; + } + } while (true); + } + polygons.add(polygon); + if (pca.MultipartDetection) { + // 1: 95 / 151 + // 2: 232 / 252 + // + polygonEntrance = new Vector2(); + while (GetNextHullEntrance(pca, polygonEntrance, + polygonEntrance)) { + boolean inPolygon = false; + for (int i = 0; i < polygons.size; i++) { + polygon = polygons.get(i); + if (InPolygon(pca, polygon, polygonEntrance)) { + inPolygon = true; + break; + } + } + if (!inPolygon) { + searchOn = true; + break; + } + } + } + } + } while (searchOn); + } else { + throw new Exception( + "Sizes don't match: Color array must contain texture width * texture height elements."); + } + return polygons; + } + + private static Vector2 GetHoleHullEntrance(PolygonCreationAssistance pca, + Array polygon, Vector2 startVertex) throws Exception { + Array edges = new Array(); + Vector2 entrance; + int startLine; + int endLine; + int lastSolid = 0; + boolean foundSolid; + boolean foundTransparent; + if (polygon != null && polygon.size > 0) { + if (startVertex != null) { + startLine = (int) startVertex.y; + } else { + startLine = (int) GetTopMostCoord(polygon); + } + endLine = (int) GetBottomMostCoord(polygon); + if (startLine > 0 && startLine < pca.Height && endLine > 0 + && endLine < pca.Height) { + // go from top to bottom of the polygon + for (int y = startLine; y <= endLine; y += pca + .getHoleDetectionLineStepSize()) { + // get x-coord of every polygon edge which crosses y + edges = GetCrossingEdges(polygon, EdgeAlignment.Vertical, y); + // we need an even number of crossing edges + if (edges.size > 1 && edges.size % 2 == 0) { + for (int i = 0; i < edges.size; i += 2) { + foundSolid = false; + foundTransparent = false; + for (int x = (int) edges.get(i).CrossingPoint.x; x <= (int) edges + .get(i + 1).CrossingPoint.x; x++) { + if (pca.IsSolid(x, y)) { + if (!foundTransparent) { + foundSolid = true; + lastSolid = x; + } + if (foundSolid && foundTransparent) { + entrance = new Vector2(lastSolid, y); + if (DistanceToHullAcceptable(pca, + polygon, entrance, true)) { + return entrance; + } + entrance = null; + break; + } + } else { + if (foundSolid) { + foundTransparent = true; + } + } + } + } + } + } + } + } + return null; + } + + private static boolean DistanceToHullAcceptable( + PolygonCreationAssistance pca, Array polygon, + Vector2 point, boolean higherDetail) { + if (polygon != null && polygon.size > 2) { + Vector2 edgeVertex2 = polygon.get(polygon.size - 1).cpy(); + Vector2 edgeVertex1 = new Vector2(); + if (higherDetail) { + for (int i = 0; i < polygon.size; i++) { + edgeVertex1.set(polygon.get(i)); + if (LineTools.DistanceBetweenPointAndLineSegment(point, + edgeVertex1, edgeVertex2) <= pca.getHullTolerance() + || LineTools.DistanceBetweenPointAndPoint(point, + edgeVertex1) <= pca.getHullTolerance()) { + return false; + } + edgeVertex2.set(polygon.get(i)); + } + return true; + } else { + for (int i = 0; i < polygon.size; i++) { + edgeVertex1.set(polygon.get(i)); + if (LineTools.DistanceBetweenPointAndLineSegment(point, + edgeVertex1, edgeVertex2) <= pca.getHullTolerance()) { + return false; + } + edgeVertex2.set(polygon.get(i)); + } + return true; + } + } + return false; + } + + private static boolean InPolygon(PolygonCreationAssistance pca, + Array polygon, Vector2 point) throws Exception { + boolean inPolygon = !DistanceToHullAcceptable(pca, polygon, point, true); + if (!inPolygon) { + Array edges = GetCrossingEdges(polygon, + EdgeAlignment.Vertical, (int) point.y); + if (edges.size > 0 && edges.size % 2 == 0) { + for (int i = 0; i < edges.size; i += 2) { + if (edges.get(i).CrossingPoint.x <= point.x + && edges.get(i + 1).CrossingPoint.x >= point.x) { + return true; + } + } + return false; + } + return false; + } + return true; + } + + private static Vector2 GetTopMostVertex(Array vertices) { + float topMostValue = Float.MAX_VALUE; + Vector2 topMost = null; + for (int i = 0; i < vertices.size; i++) { + if (topMostValue > vertices.get(i).y) { + topMostValue = vertices.get(i).y; + topMost = vertices.get(i); + } + } + return topMost.cpy(); + } + + private static float GetTopMostCoord(Array vertices) { + float returnValue = Float.MAX_VALUE; + for (int i = 0; i < vertices.size; i++) { + if (returnValue > vertices.get(i).y) { + returnValue = vertices.get(i).y; + } + } + return returnValue; + } + + private static float GetBottomMostCoord(Array vertices) { + float returnValue = Float.MIN_VALUE; + for (int i = 0; i < vertices.size; i++) { + if (returnValue < vertices.get(i).y) { + returnValue = vertices.get(i).y; + } + } + return returnValue; + } + + public static Boolean vectorEquals(Vector2 v1, Vector2 v2) { + return v1.x == v2.x && v1.y == v2.y; + } + + public static int vectorListIndexOf(Array list, Vector2 v) { + for (int i = 0; i < list.size; i++) { + Object obj = list.get(i); + if (obj == v) + return i; + if (obj instanceof Vector2) { + Vector2 vect = (Vector2) obj; + if (vectorEquals(v, vect)) + return i; + } + } + return -1; + } + + public static Boolean vectorListContains(Array list, Vector2 v) { + int index = vectorListIndexOf(list, v); + return index != -1; + } + + public static Vector2 vectorSub(Vector2 v1, Vector2 v2) { + return new Vector2(v1.x - v2.x, v1.y - v2.y); + } + + public static Vector2 vectorAdd(Vector2 v1, Vector2 v2) { + return new Vector2(v1.x + v2.x, v1.y + v2.y); + } + + public static float vectorCross(Vector2 v1, Vector2 v2) { + return v1.x * v2.y - v1.y * v2.x; + } + + public static Vector2 vectorCross(Vector2 v1, float scalar) { + return new Vector2(scalar * v1.y, -scalar * v1.x); + } + + public static float vectorDot(Vector2 v1, Vector2 v2) { + return v1.x * v2.x + v1.y * v2.y; + } + + public static Vector2 vectorMul(Vector2 v1, float scalar) { + return new Vector2(v1.x * scalar, v1.y * scalar); + } + + private static Array GetCrossingEdges( + Array polygon, EdgeAlignment edgeAlign, int checkLine) + throws Exception { + Array edges = new Array(); + Vector2 slope = new Vector2(); + Vector2 edgeVertex1 = new Vector2(); + Vector2 edgeVertex2 = new Vector2(); + Vector2 slopePreview = new Vector2(); + Vector2 edgeVertexPreview = new Vector2(); + Vector2 crossingPoint = new Vector2(); + boolean addCrossingPoint; + if (polygon.size > 1) { + edgeVertex2.set(polygon.get(polygon.size - 1)); + switch (edgeAlign) { + case Vertical: + for (int i = 0; i < polygon.size; i++) { + edgeVertex1.set(polygon.get(i)); + if ((edgeVertex1.y >= checkLine && edgeVertex2.y <= checkLine) + || (edgeVertex1.y <= checkLine && edgeVertex2.y >= checkLine)) { + if (edgeVertex1.y != edgeVertex2.y) { + addCrossingPoint = true; + slope.set(vectorSub(edgeVertex2, edgeVertex1)); + if (edgeVertex1.y == checkLine) { + edgeVertexPreview.set(polygon.get((i + 1) + % polygon.size)); + slopePreview.set(vectorSub(edgeVertex1, + edgeVertexPreview)); + if (slope.y > 0) { + addCrossingPoint = (slopePreview.y <= 0); + } else { + addCrossingPoint = (slopePreview.y >= 0); + } + } + if (addCrossingPoint) { + crossingPoint = new Vector2( + (checkLine - edgeVertex1.y) / slope.y + * slope.x + edgeVertex1.x, + checkLine); + edges.add(new CrossingEdgeInfo(edgeVertex1, + edgeVertex2, crossingPoint, edgeAlign)); + } + } + } + edgeVertex2.set(edgeVertex1); + } + break; + case Horizontal: + throw new Exception( + "EdgeAlignment.Horizontal isn't implemented yet. Sorry."); + } + } + edges.sort(); + // Collections.sort(edges); + return edges; + } + + private static boolean SplitPolygonEdge(Array polygon, + EdgeAlignment edgeAlign, Vector2 coordInsideThePolygon, + Reference vertex1IndexRef, + Reference vertex2IndexRef) throws Exception { + Array edges; + Vector2 slope = new Vector2(); + int nearestEdgeVertex1Index = 0; + int nearestEdgeVertex2Index = 0; + boolean edgeFound = false; + float shortestDistance = Float.MAX_VALUE; + boolean edgeCoordFound = false; + Vector2 foundEdgeCoord = new Vector2(); + vertex1IndexRef.v = 0; + vertex2IndexRef.v = 0; + switch (edgeAlign) { + case Vertical: + edges = GetCrossingEdges(polygon, EdgeAlignment.Vertical, + (int) coordInsideThePolygon.y); + foundEdgeCoord.y = coordInsideThePolygon.y; + if (edges != null && edges.size > 1 && edges.size % 2 == 0) { + float distance; + for (int i = 0; i < edges.size; i++) { + if (edges.get(i).CrossingPoint.x < coordInsideThePolygon.x) { + distance = coordInsideThePolygon.x + - edges.get(i).CrossingPoint.x; + if (distance < shortestDistance) { + shortestDistance = distance; + foundEdgeCoord.x = edges.get(i).CrossingPoint.x; + edgeCoordFound = true; + } + } + } + if (edgeCoordFound) { + shortestDistance = Float.MAX_VALUE; + int edgeVertex2Index = polygon.size - 1; + int edgeVertex1Index; + for (edgeVertex1Index = 0; edgeVertex1Index < polygon.size; edgeVertex1Index++) { + Vector2 tempVector1 = polygon.get(edgeVertex1Index) + .cpy(); + Vector2 tempVector2 = polygon.get(edgeVertex2Index) + .cpy(); + distance = LineTools + .DistanceBetweenPointAndLineSegment( + foundEdgeCoord, tempVector1, + tempVector2); + if (distance < shortestDistance) { + shortestDistance = distance; + nearestEdgeVertex1Index = edgeVertex1Index; + nearestEdgeVertex2Index = edgeVertex2Index; + edgeFound = true; + } + edgeVertex2Index = edgeVertex1Index; + } + if (edgeFound) { + slope.set(vectorSub( + polygon.get(nearestEdgeVertex2Index), + polygon.get(nearestEdgeVertex1Index))); + slope.nor(); + Vector2 tempVector = polygon.get( + nearestEdgeVertex1Index).cpy(); + distance = LineTools.DistanceBetweenPointAndPoint( + tempVector, foundEdgeCoord); + vertex1IndexRef.v = nearestEdgeVertex1Index; + vertex2IndexRef.v = nearestEdgeVertex1Index + 1; + // distance * slope + polygon[vertex1Index] + polygon.insert( + nearestEdgeVertex1Index, + vectorAdd(vectorMul(slope, distance), + polygon.get(vertex1IndexRef.v))); + polygon.insert( + nearestEdgeVertex1Index, + vectorAdd(vectorMul(slope, distance), + polygon.get(vertex2IndexRef.v))); + return true; + } + } + } + break; + case Horizontal: + throw new Exception( + "EdgeAlignment.Horizontal isn't implemented yet. Sorry."); + } + return false; + } + + private static Array CreateSimplePolygon( + PolygonCreationAssistance pca, Vector2 entrance, Vector2 last) { + boolean entranceFound = false; + boolean endOfHull = false; + Array polygon = new Array(); + Array hullArea = new Array(); + Array endOfHullArea = new Array(); + Vector2 current = new Vector2(); + Vector2 zeroVec = new Vector2(); + // Get the entrance point. //todo: alle moglichkeiten testen + if (vectorEquals(entrance, zeroVec) || !pca.InBounds(entrance)) { + entranceFound = GetHullEntrance(pca, entrance); + if (entranceFound) { + current.set(entrance.x - 1f, entrance.y); + } + } else { + if (pca.IsSolid(entrance)) { + if (IsNearPixel(pca, entrance, last)) { + current.set(last); + entranceFound = true; + } else { + Vector2 temp = new Vector2(); + if (SearchNearPixels(pca, false, entrance, temp)) { + current.set(temp); + entranceFound = true; + } else { + entranceFound = false; + } + } + } + } + if (entranceFound) { + polygon.add(entrance); + hullArea.add(entrance); + Vector2 next = entrance.cpy(); + do { + // Search in the pre vision list for an outstanding point. + Vector2 outstanding = new Vector2(); + if (SearchForOutstandingVertex(hullArea, + pca.getHullTolerance(), outstanding)) { + if (endOfHull) { + // We have found the next pixel, but is it on the last + // bit of the + // hull? + if (vectorListContains(endOfHullArea, outstanding) + && !vectorListContains(polygon, outstanding)) { + // Indeed. + polygon.add(outstanding); + } + // That's enough, quit. + break; + } + // Add it and remove all vertices that don't matter anymore + // (all the vertices before the outstanding). + polygon.add(outstanding); + int index = vectorListIndexOf(hullArea, outstanding); + if (index == -1) { + int debug = 1; + } + if (index >= 0) { + // hullArea = hullArea.subList(index + 1, + // hullArea.size); + + // Array newArray = new Array + // (hullArea.size - (index + 1)); + int counter = 0; + for (int i = index + 1; i < hullArea.size; i++) { + Vector2 v = hullArea.get(index); + // newArray.add(v); + hullArea.set(counter, v); + counter++; + } + // hullArea.clear(); + // hullArea = newArray; + for (int i = 0; i < index + 1; i++) { + hullArea.pop(); + } + } + } + // Last point gets current and current gets next. Our little + // spider is + // moving forward on the hull ;). + last.set(current); + current.set(next); + // Get the next point on hull. + next = new Vector2(); + if (GetNextHullPoint(pca, last, current, next)) { + // Add the vertex to a hull pre vision list. + hullArea.add(next); + } else { + // Quit + break; + } + if (vectorEquals(next, entrance) && !endOfHull) { + // It's the last bit of the hull, search on and exit at next + // found + // vertex. + endOfHull = true; + endOfHullArea.addAll(hullArea); + } + } while (true); + } + return polygon; + } + + private static boolean SearchNearPixels(PolygonCreationAssistance pca, + boolean searchingForSolidPixel, Vector2 current, Vector2 foundPixel) { + int x; + int y; + for (int i = 0; i < 8; i++) { + x = (int) current.x + ClosePixels[i][0]; + y = (int) current.y + ClosePixels[i][1]; + if (!searchingForSolidPixel ^ pca.IsSolid(x, y)) { + foundPixel.set(x, y); + return true; + } + } + // Nothing found. + foundPixel.set(0, 0); + return false; + } + + private static boolean IsNearPixel(PolygonCreationAssistance pca, + Vector2 current, Vector2 near) { + for (int i = 0; i < 8; i++) { + int x = (int) current.x + ClosePixels[i][0]; + int y = (int) current.y + ClosePixels[i][1]; + if (x >= 0 && x <= pca.Width && y >= 0 && y <= pca.Height) { + if (x == (int) near.x && y == (int) near.y) { + return true; + } + } + } + return false; + } + + private static boolean GetHullEntrance(PolygonCreationAssistance pca, + Vector2 entrance) { + // Search for first solid pixel. + for (int y = 0; y < pca.Height; y++) { + for (int x = 0; x < pca.Width; x++) { + if (pca.IsSolid(x, y)) { + entrance.set(x, y); + return true; + } + } + } + // If there are no solid pixels. + entrance.set(0, 0); + return false; + } + + private static boolean GetNextHullEntrance(PolygonCreationAssistance pca, + Vector2 start, Vector2 entrance) { + // Search for first solid pixel. + int size = pca.Height * pca.Width; + int x; + boolean foundTransparent = false; + for (int i = (int) start.x + (int) start.y * pca.Width; i < size; i++) { + if (pca.IsSolid(i)) { + if (foundTransparent) { + x = i % pca.Width; + entrance.set(x, (i - x) / pca.Width); + return true; + } + } else { + foundTransparent = true; + } + } + // If there are no solid pixels. + entrance.set(0, 0); + return false; + } + + private static boolean GetNextHullPoint(PolygonCreationAssistance pca, + Vector2 last, Vector2 current, Vector2 next) { + int x; + int y; + int indexOfFirstPixelToCheck = GetIndexOfFirstPixelToCheck(last, + current); + int indexOfPixelToCheck; + int pixelsToCheck = 8; // _closePixels.Length; + for (int i = 0; i < pixelsToCheck; i++) { + indexOfPixelToCheck = (indexOfFirstPixelToCheck + i) + % pixelsToCheck; + x = (int) current.x + ClosePixels[indexOfPixelToCheck][0]; + y = (int) current.y + ClosePixels[indexOfPixelToCheck][1]; + if (x >= 0 && x < pca.Width && y >= 0 && y <= pca.Height) { + if (pca.IsSolid(x, y)) // todo + { + next.set(x, y); + return true; + } + } + } + next.set(0, 0); + return false; + } + + private static boolean SearchForOutstandingVertex(Array hullArea, + float hullTolerance, Vector2 outstanding) { + Vector2 outstandingResult = new Vector2(); + boolean found = false; + if (hullArea.size > 2) { + int hullAreaLastPoint = hullArea.size - 1; + Vector2 tempVector1; + Vector2 tempVector2 = hullArea.get(0); + Vector2 tempVector3 = hullArea.get(hullAreaLastPoint); + // Search between the first and last hull point. + for (int i = 1; i < hullAreaLastPoint; i++) { + tempVector1 = hullArea.get(i); + // Check if the distance is over the one that's tolerable. + if (LineTools.DistanceBetweenPointAndLineSegment(tempVector1, + tempVector2, tempVector3) >= hullTolerance) { + outstandingResult.set(hullArea.get(i)); + found = true; + break; + } + } + } + outstanding.set(outstandingResult); + return found; + } + + private static int GetIndexOfFirstPixelToCheck(Vector2 last, Vector2 current) { + // .: pixel + // l: last position + // c: current position + // f: first pixel for next search + // f . . + // l c . + // . . . + // Calculate in which direction the last move went and decide over the + // next + // first pixel. + switch ((int) (current.x - last.x)) { + case 1: + switch ((int) (current.y - last.y)) { + case 1: + return 1; + case 0: + return 0; + case -1: + return 7; + } + break; + case 0: + switch ((int) (current.y - last.y)) { + case 1: + return 2; + case -1: + return 6; + } + break; + case -1: + switch ((int) (current.y - last.y)) { + case 1: + return 3; + case 0: + return 4; + case -1: + return 5; + } + break; + } + return 0; + } +} + +enum EdgeAlignment { + Vertical, Horizontal +} + +class CrossingEdgeInfo implements Comparable { + private EdgeAlignment _alignment; + private Vector2 _crossingPoint; + @SuppressWarnings("unused") + private Vector2 _edgeVertex2; + @SuppressWarnings("unused") + private Vector2 _egdeVertex1; + public Vector2 EdgeVertex1; + public Vector2 EdgeVertex2; + public EdgeAlignment CheckLineAlignment; + public Vector2 CrossingPoint; + + public CrossingEdgeInfo(Vector2 edgeVertex1, Vector2 edgeVertex2, + Vector2 crossingPoint, EdgeAlignment checkLineAlignment) { + _egdeVertex1 = edgeVertex1.cpy(); + _edgeVertex2 = edgeVertex2.cpy(); + _alignment = checkLineAlignment; + _crossingPoint = crossingPoint; + } + + public int compareTo(CrossingEdgeInfo obj) { + CrossingEdgeInfo cei = obj; + int result = 0; + switch (_alignment) { + case Vertical: + if (_crossingPoint.x < cei.CrossingPoint.y) { + result = -1; + } else if (_crossingPoint.x > cei.CrossingPoint.y) { + result = 1; + } + break; + case Horizontal: + if (_crossingPoint.y < cei.CrossingPoint.y) { + result = -1; + } else if (_crossingPoint.y > cei.CrossingPoint.y) { + result = 1; + } + break; + } + return result; + } +} + +// / +// / Class used as a tools container and helper for the texture-to-vertices code. +// / +class PolygonCreationAssistance { + private int _alphaTolerance; + private int _holeDetectionLineStepSize; + private float _hullTolerance; + + public PolygonCreationAssistance(int[] data, int width, int height) { + Data = data; + Width = width; + Height = height; + setAlphaTolerance((byte) 20); + setHullTolerance(1.5f); + setHoleDetectionLineStepSize(1); + HoleDetection = false; + MultipartDetection = false; + } + + private int[] Data; + public int Width; + public int Height; + + public int getAlphaTolerance() { + return _alphaTolerance; + } + + public void setAlphaTolerance(int value) { + _alphaTolerance = value & 0xFF; + } + + public float getHullTolerance() { + return _hullTolerance; + } + + public void setHullTolerance(float value) { + float hullTolerance = value; + if (hullTolerance > 4f) + hullTolerance = 4f; + if (hullTolerance < 0.9f) + hullTolerance = 0.9f; + _hullTolerance = hullTolerance; + } + + public int getHoleDetectionLineStepSize() { + return _holeDetectionLineStepSize; + } + + private void setHoleDetectionLineStepSize(int value) { + if (value < 1) { + _holeDetectionLineStepSize = 1; + } else { + if (value > 10) { + _holeDetectionLineStepSize = 10; + } else { + _holeDetectionLineStepSize = value; + } + } + } + + public boolean HoleDetection; + public boolean MultipartDetection; + + public boolean IsSolid(Vector2 pixel) { + return IsSolid((int) pixel.x, (int) pixel.y); + } + + public boolean IsSolid(int x, int y) { + if (x >= 0 && x < Width && y >= 0 && y < Height) { + int data = Data[x + y * Width]; + long mask1 = (long) data & 0xFFFFFFFFL; + long mask2 = mask1 & 0x000000FF; + Boolean opaque = mask2 >= _alphaTolerance; + if (opaque || mask2 != 0) { + int debug = 1; + } + return opaque; + } + return false; + } + + public boolean IsSolid(int index) { + if (index >= 0 && index < Width * Height) { + int data = Data[index]; + long mask1 = (long) data & 0xFFFFFFFFL; + long mask2 = mask1 & 0x000000FF; + Boolean opaque = mask2 >= _alphaTolerance; + if (opaque || mask2 != 0) { + int debug = 1; + } + return opaque; + // return (mask1 >= _alphaToleranceRealValue); + } + return false; + } + + public boolean InBounds(Vector2 coord) { + return (coord.x >= 0f && coord.x < Width && coord.y >= 0f && coord.y < Height); + } + + public boolean IsValid() { + if (Data != null && Data.length > 0) + return Data.length == Width * Height; + return false; + } +} + +class Reference { + public K v; + + public Reference(K v) { + this.v = v; + } + + @Override + public String toString() { + return v.toString(); + } + + @Override + public boolean equals(Object obj) { + return v.equals(obj); + } + + @Override + public int hashCode() { + return v.hashCode(); + } +} + +class LineTools { + public static float DistanceBetweenPointAndPoint(Vector2 point1, + Vector2 point2) { + Vector2 v = TextureConverter.vectorSub(point1, point2); + return v.len(); + } + + public static float DistanceBetweenPointAndLineSegment(Vector2 point, + Vector2 lineEndPoint1, Vector2 lineEndPoint2) { + Vector2 v = TextureConverter.vectorSub(lineEndPoint2, lineEndPoint1); + Vector2 w = TextureConverter.vectorSub(point, lineEndPoint1); + float c1 = TextureConverter.vectorDot(w, v); + if (c1 <= 0) + return DistanceBetweenPointAndPoint(point, lineEndPoint1); + float c2 = TextureConverter.vectorDot(v, v); + if (c2 <= c1) + return DistanceBetweenPointAndPoint(point, lineEndPoint2); + float b = c1 / c2; + Vector2 pointOnLine = TextureConverter.vectorAdd(lineEndPoint1, + TextureConverter.vectorMul(v, b)); + return DistanceBetweenPointAndPoint(point, pointOnLine); + } +} diff --git a/src/main/java/games/rednblack/editor/utils/poly/tracer/Tracer.java b/src/main/java/games/rednblack/editor/utils/poly/tracer/Tracer.java new file mode 100644 index 00000000..60f5e25c --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/poly/tracer/Tracer.java @@ -0,0 +1,83 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils.poly.tracer; + +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Pixmap.Blending; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.utils.poly.TextureUtils; + +/** + * @author Aurelien Ribon | http://www.aurelienribon.com/ + */ +public class Tracer { + public static Vector2[][] trace(Texture texture, float hullTolerance, int alphaTolerance, boolean multiPartDetection, boolean holeDetection) { + Pixmap pixmap = TextureUtils.getPOTPixmap(texture); + + Blending blending = pixmap.getBlending(); + pixmap.setBlending(Blending.None); + + + int w = pixmap.getWidth(); + int h = pixmap.getHeight(); + + int size = w * h; + int[] array = new int[size]; + + for (int y=0; y> outlines; + try { + outlines = TextureConverter.createPolygon(array, w, h, hullTolerance, alphaTolerance, multiPartDetection, holeDetection); + } catch (Exception e) { + return null; + } + + TextureRegion region = TextureUtils.getPOTTexture(texture); + float tw = region.getRegionWidth(); + float th = region.getRegionHeight(); + + Vector2[][] polygons = new Vector2[outlines.size][]; + + for (int i=0; i outline = outlines.get(i); + polygons[i] = new Vector2[outline.size]; + for (int ii=0; ii E get(E source) { + Class eClass = source.getClass(); + E target = null; + try { + target = (E) eClass.newInstance(); + Field[] sourceFields = source.getClass().getDeclaredFields(); + Field[] targetFields = target.getClass().getDeclaredFields(); + for(int i = 0; i < targetFields.length; i++) { + if(Modifier.isPublic(targetFields[i].getModifiers())) { + targetFields[i].set(target, sourceFields[i].get(source)); + } + } + } catch (InstantiationException e) { + //e.printStackTrace(); + } catch (IllegalAccessException e) { + //e.printStackTrace(); + } + + return target; + } + + + public static void set(E target, E source) { + try { + Field[] sourceFields = source.getClass().getDeclaredFields(); + Field[] targetFields = target.getClass().getDeclaredFields(); + for(int i = 0; i < targetFields.length; i++) { + if(Modifier.isPublic(targetFields[i].getModifiers())) { + targetFields[i].set(target, sourceFields[i].get(source)); + } + } + } catch (IllegalAccessException e) { + //e.printStackTrace(); + } + } + + public static Collection cloneAll(Collection components) { + Collection clones = new ArrayList<>(); + for(Component component: components) { + clones.add(get(component)); + } + + return clones; + } +} diff --git a/src/main/java/games/rednblack/editor/utils/runtime/EntityUtils.java b/src/main/java/games/rednblack/editor/utils/runtime/EntityUtils.java new file mode 100644 index 00000000..529b5239 --- /dev/null +++ b/src/main/java/games/rednblack/editor/utils/runtime/EntityUtils.java @@ -0,0 +1,306 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.utils.runtime; + +import com.badlogic.ashley.core.Component; +import com.badlogic.ashley.core.Entity; +import com.badlogic.ashley.core.Family; +import com.badlogic.ashley.utils.ImmutableArray; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import games.rednblack.editor.renderer.SceneLoader; +import games.rednblack.editor.renderer.components.*; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.data.CompositeVO; +import games.rednblack.editor.renderer.data.LayerItemVO; +import games.rednblack.editor.renderer.factory.EntityFactory; +import games.rednblack.editor.renderer.utils.ComponentRetriever; +import games.rednblack.editor.view.stage.Sandbox; + +import java.util.*; +import java.util.function.Consumer; + +/** + * Created by azakhary on 6/9/2015. + */ +public class EntityUtils { + + public static String getItemName(Entity entity) { + ParentNodeComponent parentNodeComponent = ComponentRetriever.get(entity, ParentNodeComponent.class); + if (parentNodeComponent == null) + return Sandbox.getInstance().sceneControl.getCurrentSceneVO().sceneName; + + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + if (mainItemComponent.itemIdentifier != null && !mainItemComponent.itemIdentifier.isEmpty()) { + return mainItemComponent.itemIdentifier; + } else { + int type = EntityUtils.getType(entity); + switch (type) { + case EntityFactory.IMAGE_TYPE: + return "Image"; + case EntityFactory.NINE_PATCH: + return "9Patch Image"; + case EntityFactory.LABEL_TYPE: + return "Label"; + case EntityFactory.COMPOSITE_TYPE: + return "Composite Item"; + case EntityFactory.PARTICLE_TYPE: + return "Particle Effect"; + case EntityFactory.LIGHT_TYPE: + return "Light"; + case EntityFactory.SPINE_TYPE: + return "Spine"; + case EntityFactory.SPRITE_TYPE: + return "Sprite Animation"; + case EntityFactory.SPRITER_TYPE: + return "Spriter Animation"; + case EntityFactory.COLOR_PRIMITIVE: + return "Primitive"; + default: + return "unknown"; + } + } + } + + public static Integer getEntityId(Entity entity) { + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + return mainItemComponent.uniqueId; + } + + public static Array getEntityId(Iterable entities) { + Array entityIds = new Array<>(); + for(Entity entity: entities) { + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + entityIds.add(mainItemComponent.uniqueId); + } + + return entityIds; + } + + public static Entity getByUniqueId(Integer id) { + return Sandbox.getInstance().getSceneControl().sceneLoader.entityFactory.getEntityByUniqueId(id); + } + public static HashSet getByUniqueId(Array ids) { + HashSet entities = new HashSet<>(); + for(Integer id: ids) { + Entity entity = Sandbox.getInstance().getSceneControl().sceneLoader.entityFactory.getEntityByUniqueId(id); + entities.add(entity); + } + return entities; + } + + public static HashMap> cloneEntities(Set entities) { + HashMap> data = new HashMap<>(); + + for(Entity entity: entities) { + Collection components = cloneEntityComponents(entity); + data.put(EntityUtils.getEntityId(entity), components); + } + + return data; + } + + public static Entity cloneEntity(Entity entity) { + Entity newEntity = new Entity(); + Collection components = cloneEntityComponents(entity); + for(Component component: components) { + newEntity.add(ComponentCloner.get(component)); + } + + return newEntity; + } + + public static Collection cloneEntityComponents(Entity entity) { + Collection components = ComponentCloner.cloneAll(ComponentRetriever.getComponents(entity)); + return components; + } + + public static Vector2 getPosition(Entity entity) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + return new Vector2(transformComponent.x, transformComponent.y); + } + + public static void getPosition(Entity entity, Vector2 position) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + position.set(transformComponent.x, transformComponent.y); + } + + public static TransformComponent setPosition(Entity entity, Vector2 position) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.x = position.x; + transformComponent.y = position.y; + return transformComponent; + } + + public static Vector2 getSize(Entity entity) { + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + return new Vector2(dimensionsComponent.width, dimensionsComponent.height); + } + + public static void getSize(Entity entity, Vector2 size) { + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + size.set(dimensionsComponent.width, dimensionsComponent.height); + } + + public static DimensionsComponent setSize(Entity entity, Vector2 size) { + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + dimensionsComponent.width = size.x; + dimensionsComponent.height = size.y; + if (dimensionsComponent.boundBox != null) { + dimensionsComponent.boundBox.width = size.x; + dimensionsComponent.boundBox.height = size.y; + } + return dimensionsComponent; + } + + public static Vector2 getRightTopPoint(Set entities) { + if(entities.size() == 0) return null; + + Vector2 rightTopPoint = getPosition(entities.stream().findFirst().get()); + + for(Entity entity: entities) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + DimensionsComponent dimensionsComponent = ComponentRetriever.get(entity, DimensionsComponent.class); + + if(rightTopPoint.x < transformComponent.x+dimensionsComponent.width) { + rightTopPoint.x = transformComponent.x+dimensionsComponent.width; + } + if(rightTopPoint.y < transformComponent.y+dimensionsComponent.height) { + rightTopPoint.y = transformComponent.y+dimensionsComponent.height; + } + } + + return rightTopPoint; + } + + public static Vector2 getLeftBottomPoint(Set entities) { + if(entities.size() == 0) return null; + + Vector2 leftBottomPoint = getPosition(entities.stream().findFirst().get()); + + for(Entity entity: entities) { + TransformComponent transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + if(leftBottomPoint.x > transformComponent.x) { + leftBottomPoint.x = transformComponent.x; + } + if(leftBottomPoint.y > transformComponent.y) { + leftBottomPoint.y = transformComponent.y; + } + } + + return leftBottomPoint; + } + + public static void changeParent(HashSet entities, Entity parent) { + for(Entity entity: entities) { + ParentNodeComponent parentNodeComponent = ComponentRetriever.get(entity, ParentNodeComponent.class); + + //remove me from previous parent children list + NodeComponent nodeComponent = ComponentRetriever.get(parentNodeComponent.parentEntity, NodeComponent.class); + nodeComponent.children.removeValue(entity, true); + + //add me to new parent child list + NodeComponent rootNodeComponent = ComponentRetriever.get(parent, NodeComponent.class); + rootNodeComponent.children.add(entity); + + //change my parent + parentNodeComponent.parentEntity = parent; + } + } + + public static HashSet getChildren(Entity entity) { + HashSet entities; + NodeComponent nodeComponent = ComponentRetriever.get(entity, NodeComponent.class); + Entity[] children = nodeComponent.children.toArray(); + entities = new HashSet<>(Arrays.asList(children)); + + return entities; + } + + public static int getType(Entity entity) { + MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class); + return mainItemComponent.entityType; + } + + public static Array getByLibraryLink(String link) { + Array result = new Array<>(); + ImmutableArray composites = Sandbox.getInstance().getEngine().getEntitiesFor(Family.all(NodeComponent.class).get()); + for(Entity composite: composites) { + MainItemComponent mainItemComponent = ComponentRetriever.get(composite, MainItemComponent.class); + if(mainItemComponent.libraryLink.equals(link)) { + result.add(composite); + } + } + + return result; + } + + public static void reInstantiateChildren(Entity entity) { + NodeComponent nodeComponent = ComponentRetriever.get(entity, NodeComponent.class); + if (nodeComponent != null) { + CompositeVO compositeVo = new CompositeVO(); + compositeVo.loadFromEntity(entity); + + entity.remove(NodeComponent.class); + entity.add(new NodeComponent()); + + SceneLoader sceneLoader = Sandbox.getInstance().getSceneControl().sceneLoader; + sceneLoader.entityFactory.initAllChildren(Sandbox.getInstance().getEngine(), entity, compositeVo); + } + } + + public static LayerItemVO getEntityLayer(Entity entity) { + ZIndexComponent zIndexComponent = ComponentRetriever.get(entity, ZIndexComponent.class); + LayerMapComponent layerMapComponent = ComponentRetriever.get(entity.getComponent(ParentNodeComponent.class).parentEntity, LayerMapComponent.class); + + return layerMapComponent.getLayer(zIndexComponent.layerName); + } + + /** + * iterate over children recursively and do some operations + * + * @param root + * @param action + */ + public static void applyActionRecursivelyOnEntities(Entity root, Consumer action) { + action.accept(root); + NodeComponent nodeComponent = ComponentRetriever.get(root, NodeComponent.class); + if (nodeComponent != null && nodeComponent.children != null) { + for (Entity targetEntity : nodeComponent.children) { + applyActionRecursivelyOnEntities(targetEntity, action); + } + } + } + + public static void applyActionRecursivelyOnLibraryItems(CompositeItemVO rootCompositeItemVo, Consumer action) { + action.accept(rootCompositeItemVo); + if (rootCompositeItemVo.composite != null && rootCompositeItemVo.composite.sComposites.size() != 0) { + for (CompositeItemVO currentCompositeItemVo : rootCompositeItemVo.composite.sComposites) { + applyActionRecursivelyOnLibraryItems(currentCompositeItemVo, action); + } + } + } + + public static void removeEntities(ArrayList entityList) { + for (Entity entity : entityList) { + Sandbox.getInstance().getEngine().removeEntity(entity); + } + } + +} diff --git a/src/main/java/games/rednblack/editor/view/HyperLap2DScreen.java b/src/main/java/games/rednblack/editor/view/HyperLap2DScreen.java new file mode 100644 index 00000000..7dc5e6df --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/HyperLap2DScreen.java @@ -0,0 +1,235 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.view; + +import java.io.File; + +import com.badlogic.ashley.core.Engine; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.InputMultiplexer; +import com.badlogic.gdx.InputProcessor; +import com.badlogic.gdx.Screen; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector2; +import games.rednblack.editor.view.menu.FileMenu; +import games.rednblack.h2d.common.MsgAPI; +import games.rednblack.editor.view.ui.widget.actors.basic.SandboxBackUI; +import games.rednblack.editor.view.stage.Sandbox; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.view.stage.UIStage; +import games.rednblack.editor.view.stage.input.SandboxInputAdapter; +import games.rednblack.editor.renderer.data.SceneVO; + +public class HyperLap2DScreen implements Screen, InputProcessor { + private static final String TAG = HyperLap2DScreen.class.getCanonicalName(); + //public SandboxStage sandboxStage; + + public UIStage uiStage; + + private Engine engine; + + private InputMultiplexer multiplexer; + private HyperLap2DFacade facade; + private ProjectManager projectManager; + private boolean paused = false; + + private Sandbox sandbox; + private SandboxBackUI sandboxBackUI; + + private Batch batch; + private Color bgColor; + private Texture bgLogo; + private Vector2 screenSize; + + + private boolean isDrawingBgLogo; + + public HyperLap2DScreen() { + facade = HyperLap2DFacade.getInstance(); + bgColor = new Color(0.15f, 0.15f, 0.15f, 1.0f); + isDrawingBgLogo = true; + batch = new SpriteBatch(); + bgLogo = new Texture(Gdx.files.internal("style/bglogo.png")); + screenSize = new Vector2(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + } + + @Override + public void render(float deltaTime) { + Gdx.gl.glClearColor(bgColor.r, bgColor.g, bgColor.b, bgColor.a); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + if(isDrawingBgLogo) { + batch.begin(); + batch.setColor(1, 1, 1, 0.3f); + batch.draw(bgLogo, screenSize.x/2 - bgLogo.getWidth()/2f, screenSize.y/2 - bgLogo.getHeight()/2f); + batch.end(); + } else { + if (sandboxBackUI != null) sandboxBackUI.render(deltaTime); + engine.update(deltaTime); + } + + uiStage.getViewport().apply(); + uiStage.act(deltaTime); + uiStage.draw(); + } + + public void disableDrawingBgLogo() { + if(!isDrawingBgLogo) return; + + this.isDrawingBgLogo = false; + bgLogo.dispose(); + batch.dispose(); + batch = null; + bgLogo = null; + } + + public void setBgColor(Color color) { + bgColor = color; + } + + @Override + public void pause() { + paused = true; + } + + @Override + public void resume() { + paused = false; + } + + @Override + public void dispose() { + + } + + @Override + public void show() { + sandbox = Sandbox.getInstance(); + uiStage = sandbox.getUIStage(); + + projectManager = facade.retrieveProxy(ProjectManager.NAME); + + multiplexer = new InputMultiplexer(); + multiplexer.addProcessor(this); + multiplexer.addProcessor(uiStage); + multiplexer.addProcessor(new SandboxInputAdapter()); + Gdx.input.setInputProcessor(multiplexer); + } + + @Override + public void hide() { + + } + + @Override + public void resize(int width, int height) { + // See https://github.com/libgdx/libgdx/issues/3673#issuecomment-177606278 + if (width == 0 && height == 0) return; + + uiStage.resize(width, height); + + if(Sandbox.getInstance().getViewport() != null) { + Sandbox.getInstance().getViewport().update(width, height, true); + } + } + + @Override + public boolean keyDown(int keycode) { + if (Gdx.input.isKeyPressed(Input.Keys.SYM) || Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT)) { + switch (keycode) { + case Input.Keys.N: + facade.sendNotification(FileMenu.NEW_PROJECT, null, FileMenu.FILE_MENU); + break; + case Input.Keys.O: + facade.sendNotification(FileMenu.OPEN_PROJECT, null, FileMenu.FILE_MENU); + break; + case Input.Keys.I: + if (sandbox.sceneControl.getCurrentSceneVO() != null) { + facade.sendNotification(FileMenu.IMPORT_TO_LIBRARY, null, FileMenu.FILE_MENU); + } + break; + case Input.Keys.S: + if (sandbox.sceneControl.getCurrentSceneVO() != null) { + SceneVO vo = sandbox.sceneVoFromItems(); + projectManager.saveCurrentProject(vo); + } + break; + case Input.Keys.E: + if (sandbox.sceneControl.getCurrentSceneVO() != null) { + facade.sendNotification(MsgAPI.ACTION_EXPORT_PROJECT); + } + break; + } + } + + if (Gdx.input.isKeyPressed(Input.Keys.SYM) && keycode == Input.Keys.Q) { + facade.sendNotification(MsgAPI.APP_EXIT); + } + return false; + } + + @Override + public boolean keyUp(int keycode) { + return false; + } + + @Override + public boolean keyTyped(char character) { + return false; + } + + @Override + public boolean touchDown(int screenX, int screenY, int pointer, int button) { + return false; + } + + @Override + public boolean touchUp(int screenX, int screenY, int pointer, int button) { + return false; + } + + @Override + public boolean touchDragged(int screenX, int screenY, int pointer) { + return false; + } + + @Override + public boolean mouseMoved(int screenX, int screenY) { + return false; + } + + @Override + public boolean scrolled(int amount) { + return false; + } + + public void setEngine(Engine engine) { + this.engine = engine; + } + + public void setBackUI(SandboxBackUI sandboxBackUI) { + this.sandboxBackUI = sandboxBackUI; + } +} diff --git a/src/main/java/games/rednblack/editor/view/HyperLap2DScreenMediator.java b/src/main/java/games/rednblack/editor/view/HyperLap2DScreenMediator.java new file mode 100644 index 00000000..d5c94805 --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/HyperLap2DScreenMediator.java @@ -0,0 +1,94 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.view; + +import com.badlogic.ashley.core.Engine; +import games.rednblack.h2d.common.MsgAPI; +import com.puremvc.patterns.mediator.SimpleMediator; +import com.puremvc.patterns.observer.Notification; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.renderer.systems.render.HyperLap2dRenderer; +import games.rednblack.editor.view.stage.SandboxMediator; +import games.rednblack.editor.view.ui.widget.actors.basic.SandboxBackUI; + +/** + * Created by sargis on 3/30/15. + */ +public class HyperLap2DScreenMediator extends SimpleMediator { + private static final String TAG = HyperLap2DScreenMediator.class.getCanonicalName(); + public static final String NAME = TAG; + + public HyperLap2DScreenMediator() { + super(NAME, null); + } + + @Override + public String[] listNotificationInterests() { + return new String[]{ + MsgAPI.CREATE, + MsgAPI.PAUSE, + MsgAPI.RESUME, + MsgAPI.RENDER, + MsgAPI.RESIZE, + MsgAPI.DISPOSE, + MsgAPI.SCENE_LOADED + }; + } + + @Override + public void handleNotification(Notification notification) { + super.handleNotification(notification); + switch (notification.getName()) { + case MsgAPI.CREATE: + setViewComponent(new HyperLap2DScreen()); + //TODO this must be changed to Command + facade = HyperLap2DFacade.getInstance(); + SandboxMediator sandboxMediator = facade.retrieveMediator(SandboxMediator.NAME); + + Engine engine = sandboxMediator.getViewComponent().getEngine(); + + getViewComponent().setEngine(engine); + viewComponent.show(); + break; + case MsgAPI.SCENE_LOADED: + facade = HyperLap2DFacade.getInstance(); + sandboxMediator = facade.retrieveMediator(SandboxMediator.NAME); + engine = sandboxMediator.getViewComponent().getEngine(); + SandboxBackUI sandboxBackUI = new SandboxBackUI(engine.getSystem(HyperLap2dRenderer.class).batch); + getViewComponent().setBackUI(sandboxBackUI); + getViewComponent().disableDrawingBgLogo(); + break; + case MsgAPI.PAUSE: + viewComponent.pause(); + break; + case MsgAPI.RESUME: + viewComponent.resume(); + break; + case MsgAPI.RENDER: + viewComponent.render(notification.getBody()); + break; + case MsgAPI.RESIZE: + int[] data = notification.getBody(); + viewComponent.resize(data[0], data[1]); + break; + case MsgAPI.DISPOSE: + break; + } + } +} diff --git a/src/main/java/games/rednblack/editor/view/ItemControlMediator.java b/src/main/java/games/rednblack/editor/view/ItemControlMediator.java new file mode 100644 index 00000000..720751d5 --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/ItemControlMediator.java @@ -0,0 +1,69 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.view; + +import java.util.Set; + +import com.badlogic.ashley.core.Entity; +import games.rednblack.editor.renderer.components.TransformComponent; +import games.rednblack.editor.renderer.components.ZIndexComponent; +import games.rednblack.editor.renderer.utils.ComponentRetriever; + +/** + * Created by CyberJoe on 3/18/2015. + */ +public class ItemControlMediator { + + private SceneControlMediator sceneControl; + + private TransformComponent transformComponent; + private ZIndexComponent zIndexComponent; + + public ItemControlMediator(SceneControlMediator sceneControl) { + this.sceneControl = sceneControl; + } + + + public void itemZIndexChange( Set currentSelection, boolean isUp) { + for (Entity item : currentSelection) { + zIndexComponent = ComponentRetriever.get(item, ZIndexComponent.class); + + int ammount = 1; + if (!isUp) ammount = -1; + + int setting = zIndexComponent.getZIndex() + ammount; + if (setting < 0) setting = 0; + zIndexComponent.setZIndex(setting); + } + } + + public void moveItemBy(Entity entity, float x, float y) { + transformComponent = ComponentRetriever.get(entity, TransformComponent.class); + transformComponent.x+=x; + transformComponent.y+=y; + } + + public void removeItem(Entity entity) { + //TODO and uncomment +// actor.remove(); +// sceneControl.getCurrentScene().removeItem(item); +// item.dispose(); + } + +} diff --git a/src/main/java/games/rednblack/editor/view/SceneControlMediator.java b/src/main/java/games/rednblack/editor/view/SceneControlMediator.java new file mode 100644 index 00000000..46144535 --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/SceneControlMediator.java @@ -0,0 +1,119 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.view; + +import com.badlogic.ashley.core.Entity; +import com.badlogic.gdx.utils.viewport.ScreenViewport; +import games.rednblack.editor.HyperLap2DFacade; +import games.rednblack.editor.proxy.ProjectManager; +import games.rednblack.editor.proxy.ResolutionManager; +import games.rednblack.editor.proxy.ResourceManager; +import games.rednblack.editor.renderer.SceneLoader; +import games.rednblack.editor.renderer.data.CompositeItemVO; +import games.rednblack.editor.renderer.data.ProjectInfoVO; +import games.rednblack.editor.renderer.data.SceneVO; + +/** + * Mediates scene communication between editor and current runtime + * + * @author azakhary + */ +public class SceneControlMediator { + + private final HyperLap2DFacade facade; + private final ProjectManager projectManager; + /** + * main holder of the scene + */ + public SceneLoader sceneLoader; + + /** + * runtime essentials + */ + // private Essentials essentials; + + /** + * current scene tools + */ + private SceneVO currentSceneVo; + + /** + * tools object of the root element of the scene + */ + private CompositeItemVO rootSceneVO; + + /** + * current scene rendering item + */ + private Entity currentScene; + + public SceneControlMediator(SceneLoader sceneLoader) { + this.sceneLoader = sceneLoader; + // this.essentials = essentials; + facade = HyperLap2DFacade.getInstance(); + projectManager = facade.retrieveProxy(ProjectManager.NAME); + } + + public ProjectInfoVO getProjectInfoVO() { + return sceneLoader.getRm().getProjectVO(); + } + + public void initScene(String sceneName) { + ResolutionManager resolutionManager = facade.retrieveProxy(ResolutionManager.NAME); + ResourceManager resourceManager = facade.retrieveProxy(ResourceManager.NAME); + + ScreenViewport viewport = new ScreenViewport(); + // Yey to whoever made this method + viewport.setUnitsPerPixel(1f/resourceManager.getProjectVO().pixelToWorld); + + currentSceneVo = sceneLoader.loadScene(sceneName, viewport); + // TODO: this is now in sceneLoaader but probably will be changed + // essentials.world = new World(new + // Vector2(currentSceneVo.physicsPropertiesVO.gravityX, + // currentSceneVo.physicsPropertiesVO.gravityY), true); + // essentials.rayHandler.setWorld(essentials.world); + + rootSceneVO = new CompositeItemVO(currentSceneVo.composite); + } + + public void updateAmbientLights() { + sceneLoader.setAmbientInfo(sceneLoader.getSceneVO()); + } + + public CompositeItemVO getRootSceneVO() { + return rootSceneVO; + } + + public Entity getCurrentScene() { + return currentScene; + } + + public SceneVO getCurrentSceneVO() { + return currentSceneVo; + } + + public Entity getRootEntity() { + return sceneLoader.rootEntity; + } + +// public CompositeItem getCompositeElement(CompositeItemVO vo) { +// return sceneLoader.getCompositeElement(vo); +// } + +} diff --git a/src/main/java/games/rednblack/editor/view/frame/FileDropListener.java b/src/main/java/games/rednblack/editor/view/frame/FileDropListener.java new file mode 100644 index 00000000..0d259b25 --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/frame/FileDropListener.java @@ -0,0 +1,76 @@ +/* + * ****************************************************************************** + * * Copyright 2015 See AUTHORS file. + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * ***************************************************************************** + */ + +package games.rednblack.editor.view.frame; + +import games.rednblack.editor.HyperLap2DFacade; + +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; + +/** + * Created by azakhary on 7/21/2015. + */ + +//TODO remove after migrate to Drag listener in LWJGL3 +public class FileDropListener implements DropTargetListener { + + private static final String CLASS_NAME = "games.rednblack.editor.view.frame.FileDropListener"; + public static final String ACTION_DRAG_ENTER = CLASS_NAME + "ACTION_DRAG_ENTER"; + public static final String ACTION_DRAG_OVER = CLASS_NAME + "ACTION_DRAG_OVER"; + public static final String ACTION_DRAG_EXIT = CLASS_NAME + "ACTION_DRAG_EXIT"; + public static final String ACTION_DROP = CLASS_NAME + "ACTION_DROP"; + + public void sendNotification(String notification) { + sendNotification(notification, null); + } + + public void sendNotification(String notification, Object data) { + HyperLap2DFacade facade = HyperLap2DFacade.getInstance(); + if(facade != null) { + facade.sendNotification(notification, data); + } + } + + @Override + public void dragEnter(DropTargetDragEvent dtde) { + sendNotification(ACTION_DRAG_ENTER, dtde); + } + + @Override + public void dragOver(DropTargetDragEvent dtde) { + sendNotification(ACTION_DRAG_OVER, dtde); + } + + @Override + public void dropActionChanged(DropTargetDragEvent dtde) { + // Do we even need this? + } + + @Override + public void dragExit(DropTargetEvent dte) { + sendNotification(ACTION_DRAG_EXIT); + } + + @Override + public void drop(DropTargetDropEvent dtde) { + sendNotification(ACTION_DROP, dtde); + } +} diff --git a/src/main/java/games/rednblack/editor/view/menu/EditMenu.java b/src/main/java/games/rednblack/editor/view/menu/EditMenu.java new file mode 100644 index 00000000..5061f82f --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/menu/EditMenu.java @@ -0,0 +1,44 @@ +package games.rednblack.editor.view.menu; + +import com.badlogic.gdx.Input; +import com.kotcrab.vis.ui.widget.MenuItem; +import games.rednblack.editor.event.MenuItemListener; + +public class EditMenu extends H2DMenu { + + public static final String EDIT_MENU = HyperLap2DMenuBar.prefix + ".EDIT_MENU"; + public static final String CUT = HyperLap2DMenuBar.prefix + ".CUT"; + public static final String COPY = HyperLap2DMenuBar.prefix + ".COPY"; + public static final String PASTE = HyperLap2DMenuBar.prefix + ".PASTE"; + public static final String UNDO = HyperLap2DMenuBar.prefix + ".UNDO"; + public static final String REDO = HyperLap2DMenuBar.prefix + ".REDO"; + + private final MenuItem cut; + private final MenuItem copy; + private final MenuItem paste; + private final MenuItem undo; + private final MenuItem redo; + + public EditMenu() { + super("Edit"); + cut = new MenuItem("Cut", new MenuItemListener(CUT, null, EDIT_MENU)).setShortcut(Input.Keys.CONTROL_LEFT, Input.Keys.X); + copy = new MenuItem("Copy", new MenuItemListener(COPY, null, EDIT_MENU)).setShortcut(Input.Keys.CONTROL_LEFT, Input.Keys.C); + paste = new MenuItem("Paste", new MenuItemListener(PASTE, null, EDIT_MENU)).setShortcut(Input.Keys.CONTROL_LEFT, Input.Keys.V); + undo = new MenuItem("Undo", new MenuItemListener(UNDO, null, EDIT_MENU)).setShortcut(Input.Keys.CONTROL_LEFT, Input.Keys.Z); + redo = new MenuItem("Redo", new MenuItemListener(REDO, null, EDIT_MENU)).setShortcut(Input.Keys.CONTROL_LEFT,Input.Keys.SHIFT_LEFT, Input.Keys.S); + addItem(cut); + addItem(copy); + addItem(paste); + addItem(undo); + addItem(redo); + } + + public void setProjectOpen(boolean open) { + cut.setDisabled(!open); + copy.setDisabled(!open); + paste.setDisabled(!open); + undo.setDisabled(!open); + redo.setDisabled(!open); + } + +} diff --git a/src/main/java/games/rednblack/editor/view/menu/FileMenu.java b/src/main/java/games/rednblack/editor/view/menu/FileMenu.java new file mode 100644 index 00000000..48ee45cd --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/menu/FileMenu.java @@ -0,0 +1,153 @@ +package games.rednblack.editor.view.menu; + +import com.badlogic.gdx.Input; +import com.badlogic.gdx.utils.Array; +import com.kotcrab.vis.ui.widget.MenuItem; +import com.kotcrab.vis.ui.widget.PopupMenu; +import games.rednblack.editor.data.manager.PreferencesManager; +import games.rednblack.editor.event.MenuItemListener; +import games.rednblack.editor.renderer.data.SceneVO; + +import java.io.File; +import java.util.ArrayList; + +public class FileMenu extends H2DMenu { + + public static final String FILE_MENU = HyperLap2DMenuBar.prefix + ".FILE_MENU"; + public static final String NEW_PROJECT = HyperLap2DMenuBar.prefix + ".NEW_PROJECT"; + public static final String OPEN_PROJECT = HyperLap2DMenuBar.prefix + ".OPEN_PROJECT"; + public static final String SAVE_PROJECT = HyperLap2DMenuBar.prefix + ".SAVE_PROJECT"; + public static final String IMPORT_TO_LIBRARY = HyperLap2DMenuBar.prefix + ".IMPORT_TO_LIBRARY"; + public static final String RECENT_PROJECTS = HyperLap2DMenuBar.prefix + ".RECENT_PROJECTS"; + public static final String CLEAR_RECENTS = HyperLap2DMenuBar.prefix + ".CLEAR_RECENTS"; + public static final String EXPORT = HyperLap2DMenuBar.prefix + ".EXPORT"; + public static final String EXPORT_SETTINGS = HyperLap2DMenuBar.prefix + ".EXPORT_SETTINGS"; + public static final String EXIT = HyperLap2DMenuBar.prefix + ".EXIT"; + public static final String NEW_SCENE = HyperLap2DMenuBar.prefix + ".NEW_SCENE"; + public static final String SELECT_SCENE = HyperLap2DMenuBar.prefix + ".SELECT_SCENE"; + public static final String DELETE_CURRENT_SCENE = HyperLap2DMenuBar.prefix + ".DELETE_CURRENT_SCENE"; + + private final PopupMenu scenesPopupMenu; + private final Array sceneMenuItems; + private final MenuItem saveProject; + private final MenuItem scenesMenuItem; + private final MenuItem importToLibrary; + private final MenuItem export; + private final MenuItem exportSettings; + + private final PopupMenu recentProjectsPopupMenu; + private final Array recentProjectsMenuItems; + private final MenuItem recentProjectsMenuItem; + + public FileMenu() { + super("File"); + saveProject = new MenuItem("Save Project", new MenuItemListener(SAVE_PROJECT, null, FILE_MENU)).setShortcut(Input.Keys.CONTROL_LEFT, Input.Keys.S); + addItem(new MenuItem("New Project", new MenuItemListener(NEW_PROJECT, null, FILE_MENU)).setShortcut(Input.Keys.CONTROL_LEFT, Input.Keys.N)); + addItem(new MenuItem("Open Project", new MenuItemListener(OPEN_PROJECT, null, FILE_MENU)).setShortcut(Input.Keys.CONTROL_LEFT, Input.Keys.O)); + addItem(saveProject); + //saveProject.debug(); + // + scenesMenuItem = new MenuItem("Scenes"); + scenesPopupMenu = new PopupMenu(); + + scenesMenuItem.setSubMenu(scenesPopupMenu); + addItem(scenesMenuItem); + // + addSeparator(); + importToLibrary = new MenuItem("Import Resources", new MenuItemListener(IMPORT_TO_LIBRARY, null, FILE_MENU)).setShortcut(Input.Keys.CONTROL_LEFT, Input.Keys.I); + export = new MenuItem("Export", new MenuItemListener(EXPORT, null, FILE_MENU)).setShortcut(Input.Keys.CONTROL_LEFT, Input.Keys.E); + exportSettings = new MenuItem("Export Settings", new MenuItemListener(EXPORT_SETTINGS, null, FILE_MENU)); + addItem(importToLibrary); + addItem(export); + addItem(exportSettings); + // + addSeparator(); + recentProjectsMenuItem = new MenuItem("Recent Projects..."); + recentProjectsPopupMenu = new PopupMenu(); + recentProjectsMenuItem.setSubMenu(recentProjectsPopupMenu); + recentProjectsMenuItems = new Array<>(); + addItem(recentProjectsMenuItem); + + PreferencesManager prefs = PreferencesManager.getInstance(); + prefs.buildRecentHistory(); + reInitRecent(prefs.getRecentHistory()); + // + addSeparator(); + addItem(new MenuItem("Exit", new MenuItemListener(EXIT, null , FILE_MENU))); + sceneMenuItems = new Array<>(); + } + + public void addScenes(ArrayList scenes) { + for (SceneVO sceneVO : scenes) { + MenuItem menuItem = new MenuItem(sceneVO.sceneName, new MenuItemListener(SELECT_SCENE, sceneVO.sceneName, FILE_MENU)); + sceneMenuItems.add(menuItem); + scenesPopupMenu.addItem(menuItem); + } + } + + public void reInitScenes(ArrayList scenes) { + sceneMenuItems.clear(); + scenesPopupMenu.clear(); + scenesPopupMenu.addItem(new MenuItem("Create New Scene", new MenuItemListener(NEW_SCENE, null, FILE_MENU))); + scenesPopupMenu.addItem(new MenuItem("Delete Current Scene", new MenuItemListener(DELETE_CURRENT_SCENE, null, FILE_MENU))); + scenesPopupMenu.addSeparator(); + addScenes(scenes); + } + + public String getFolderNameAndPath(String path) { + File path1 = new File(path); + File path2 = new File(path1.getParent()); + return path2.getName() + " - [ " + path + "]"; + } + + public void addRecent(ArrayList paths) { + for (String path : paths) { + MenuItem menuItem = new MenuItem(getFolderNameAndPath(path) , new MenuItemListener(RECENT_PROJECTS, path, FILE_MENU)); + recentProjectsMenuItems.add(menuItem); + recentProjectsPopupMenu.addItem(menuItem); + } + } + + public void reInitRecent(ArrayList paths) { + if (recentProjectsMenuItems != null && recentProjectsMenuItems.size != 0) { + recentProjectsMenuItems.clear(); + } + + if (recentProjectsPopupMenu != null && recentProjectsPopupMenu.hasChildren()) { + recentProjectsPopupMenu.remove(); + recentProjectsPopupMenu.clearChildren(); + } + addRecent(paths); + if (paths.size() > 0) { + recentProjectsPopupMenu.addSeparator(); + } + + MenuItem menuItem = new MenuItem("Clear list", new MenuItemListener(CLEAR_RECENTS, null, FILE_MENU)); + recentProjectsMenuItems.add(menuItem); + recentProjectsPopupMenu.addItem(menuItem); + + remove(); + } + + public void setProjectOpen(boolean open) { + saveProject.setDisabled(!open); + scenesMenuItem.setDisabled(!open); + importToLibrary.setDisabled(!open); + export.setDisabled(!open); + exportSettings.setDisabled(!open); + } + +// private class RecentProjectListener extends ChangeListener { +// private final String path; +// +// public RecentProjectListener(String path) { +// this.path = path; +// } +// +// @Override +// public void changed(ChangeEvent event, Actor actor) { +// Gdx.app.log(TAG, "recentProject : " + path); +// mediator.recentProjectItemClicked(path); +// } +// } +} diff --git a/src/main/java/games/rednblack/editor/view/menu/H2DMenu.java b/src/main/java/games/rednblack/editor/view/menu/H2DMenu.java new file mode 100644 index 00000000..93f0774f --- /dev/null +++ b/src/main/java/games/rednblack/editor/view/menu/H2DMenu.java @@ -0,0 +1,16 @@ +package games.rednblack.editor.view.menu; + +import com.badlogic.gdx.scenes.scene2d.ui.Cell; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import games.rednblack.editor.view.ui.widget.CustomMenu; + +public abstract class H2DMenu extends CustomMenu { + + public H2DMenu(String title) { + super(title); + Cell