funfriend is real! chatters about :)
|
@ -0,0 +1,103 @@
|
|||
info font="Space Mono" size=10 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=2,2,2,2 spacing=2,2
|
||||
common lineHeight=20 base=15 scaleW=128 scaleH=128 pages=1 packed=0
|
||||
page id=0 file="SpaceMono.png"
|
||||
chars count=97
|
||||
char id=125 x=2 y=2 width=4 height=14 xoffset=2 yoffset=3 xadvance=8 page=0 chnl=0 letter="}"
|
||||
char id=124 x=8 y=2 width=1 height=14 xoffset=3 yoffset=3 xadvance=8 page=0 chnl=0 letter="|"
|
||||
char id=93 x=11 y=2 width=3 height=14 xoffset=2 yoffset=3 xadvance=8 page=0 chnl=0 letter="]"
|
||||
char id=123 x=16 y=2 width=4 height=14 xoffset=2 yoffset=3 xadvance=8 page=0 chnl=0 letter="{"
|
||||
char id=41 x=22 y=2 width=6 height=14 xoffset=0 yoffset=3 xadvance=8 page=0 chnl=0 letter=")"
|
||||
char id=40 x=30 y=2 width=6 height=14 xoffset=2 yoffset=3 xadvance=8 page=0 chnl=0 letter="("
|
||||
char id=91 x=38 y=2 width=3 height=14 xoffset=3 yoffset=3 xadvance=8 page=0 chnl=0 letter="["
|
||||
char id=92 x=43 y=2 width=5 height=12 xoffset=1 yoffset=4 xadvance=8 page=0 chnl=0 letter="\"
|
||||
char id=81 x=50 y=2 width=7 height=12 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="Q"
|
||||
char id=47 x=59 y=2 width=5 height=12 xoffset=1 yoffset=4 xadvance=8 page=0 chnl=0 letter="/"
|
||||
char id=106 x=66 y=2 width=5 height=12 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="j"
|
||||
char id=55 x=73 y=2 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="7"
|
||||
char id=53 x=82 y=2 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="5"
|
||||
char id=56 x=91 y=2 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="8"
|
||||
char id=51 x=100 y=2 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="3"
|
||||
char id=54 x=109 y=2 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="6"
|
||||
char id=113 x=118 y=2 width=7 height=10 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="q"
|
||||
char id=50 x=2 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="2"
|
||||
char id=57 x=11 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="9"
|
||||
char id=98 x=20 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="b"
|
||||
char id=79 x=29 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="O"
|
||||
char id=52 x=38 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="4"
|
||||
char id=72 x=47 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="H"
|
||||
char id=71 x=56 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="G"
|
||||
char id=67 x=65 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="C"
|
||||
char id=37 x=74 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="%"
|
||||
char id=70 x=83 y=18 width=6 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="F"
|
||||
char id=69 x=91 y=18 width=6 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="E"
|
||||
char id=68 x=99 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="D"
|
||||
char id=65 x=108 y=18 width=8 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="A"
|
||||
char id=48 x=118 y=18 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="0"
|
||||
char id=63 x=2 y=30 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="?"
|
||||
char id=49 x=11 y=30 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="1"
|
||||
char id=116 x=20 y=30 width=6 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="t"
|
||||
char id=66 x=28 y=30 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="B"
|
||||
char id=38 x=37 y=30 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="&"
|
||||
char id=33 x=46 y=30 width=2 height=10 xoffset=3 yoffset=5 xadvance=8 page=0 chnl=0 letter="!"
|
||||
char id=73 x=50 y=30 width=6 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="I"
|
||||
char id=77 x=58 y=30 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="M"
|
||||
char id=74 x=67 y=30 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="J"
|
||||
char id=75 x=76 y=30 width=7 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="K"
|
||||
char id=80 x=85 y=30 width=7 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="P"
|
||||
char id=121 x=94 y=30 width=6 height=10 xoffset=1 yoffset=8 xadvance=8 page=0 chnl=0 letter="y"
|
||||
char id=82 x=102 y=30 width=7 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="R"
|
||||
char id=84 x=111 y=30 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="T"
|
||||
char id=107 x=2 y=42 width=6 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="k"
|
||||
char id=85 x=10 y=42 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="U"
|
||||
char id=86 x=19 y=42 width=8 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="V"
|
||||
char id=83 x=29 y=42 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="S"
|
||||
char id=100 x=38 y=42 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="d"
|
||||
char id=108 x=47 y=42 width=6 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="l"
|
||||
char id=105 x=55 y=42 width=6 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="i"
|
||||
char id=104 x=63 y=42 width=6 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="h"
|
||||
char id=89 x=71 y=42 width=8 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="Y"
|
||||
char id=102 x=81 y=42 width=6 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="f"
|
||||
char id=90 x=89 y=42 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="Z"
|
||||
char id=78 x=98 y=42 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="N"
|
||||
char id=76 x=107 y=42 width=6 height=10 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="L"
|
||||
char id=103 x=115 y=42 width=7 height=10 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="g"
|
||||
char id=88 x=2 y=54 width=7 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="X"
|
||||
char id=87 x=11 y=54 width=8 height=10 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="W"
|
||||
char id=112 x=21 y=54 width=7 height=10 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="p"
|
||||
char id=36 x=30 y=54 width=6 height=9 xoffset=1 yoffset=6 xadvance=8 page=0 chnl=0 letter="$"
|
||||
char id=59 x=38 y=54 width=2 height=9 xoffset=3 yoffset=8 xadvance=8 page=0 chnl=0 letter=";"
|
||||
char id=64 x=42 y=54 width=7 height=8 xoffset=0 yoffset=7 xadvance=8 page=0 chnl=0 letter="@"
|
||||
char id=109 x=51 y=54 width=7 height=7 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="m"
|
||||
char id=58 x=60 y=54 width=2 height=7 xoffset=3 yoffset=8 xadvance=8 page=0 chnl=0 letter=":"
|
||||
char id=101 x=64 y=54 width=7 height=7 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="e"
|
||||
char id=42 x=73 y=54 width=7 height=7 xoffset=0 yoffset=7 xadvance=8 page=0 chnl=0 letter="*"
|
||||
char id=120 x=82 y=54 width=7 height=7 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="x"
|
||||
char id=97 x=91 y=54 width=7 height=7 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="a"
|
||||
char id=99 x=100 y=54 width=7 height=7 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="c"
|
||||
char id=115 x=109 y=54 width=6 height=7 xoffset=1 yoffset=8 xadvance=8 page=0 chnl=0 letter="s"
|
||||
char id=122 x=117 y=54 width=6 height=7 xoffset=1 yoffset=8 xadvance=8 page=0 chnl=0 letter="z"
|
||||
char id=111 x=2 y=66 width=7 height=7 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="o"
|
||||
char id=35 x=11 y=66 width=7 height=7 xoffset=0 yoffset=6 xadvance=8 page=0 chnl=0 letter="#"
|
||||
char id=110 x=20 y=66 width=6 height=7 xoffset=1 yoffset=8 xadvance=8 page=0 chnl=0 letter="n"
|
||||
char id=117 x=28 y=66 width=6 height=7 xoffset=1 yoffset=8 xadvance=8 page=0 chnl=0 letter="u"
|
||||
char id=114 x=36 y=66 width=7 height=7 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="r"
|
||||
char id=119 x=45 y=66 width=8 height=7 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="w"
|
||||
char id=118 x=55 y=66 width=7 height=7 xoffset=0 yoffset=8 xadvance=8 page=0 chnl=0 letter="v"
|
||||
char id=60 x=64 y=66 width=6 height=6 xoffset=1 yoffset=7 xadvance=8 page=0 chnl=0 letter="<"
|
||||
char id=43 x=72 y=66 width=6 height=6 xoffset=1 yoffset=7 xadvance=8 page=0 chnl=0 letter="+"
|
||||
char id=62 x=80 y=66 width=6 height=6 xoffset=1 yoffset=7 xadvance=8 page=0 chnl=0 letter=">"
|
||||
char id=44 x=88 y=66 width=2 height=4 xoffset=3 yoffset=13 xadvance=8 page=0 chnl=0 letter=","
|
||||
char id=39 x=92 y=66 width=2 height=4 xoffset=3 yoffset=5 xadvance=8 page=0 chnl=0 letter="'"
|
||||
char id=34 x=96 y=66 width=5 height=4 xoffset=1 yoffset=5 xadvance=8 page=0 chnl=0 letter="""
|
||||
char id=94 x=103 y=66 width=7 height=4 xoffset=0 yoffset=5 xadvance=8 page=0 chnl=0 letter="^"
|
||||
char id=126 x=112 y=66 width=7 height=3 xoffset=0 yoffset=10 xadvance=8 page=0 chnl=0 letter="~"
|
||||
char id=61 x=2 y=75 width=6 height=3 xoffset=1 yoffset=9 xadvance=8 page=0 chnl=0 letter="="
|
||||
char id=46 x=10 y=75 width=2 height=2 xoffset=3 yoffset=13 xadvance=8 page=0 chnl=0 letter="."
|
||||
char id=96 x=14 y=75 width=3 height=2 xoffset=2 yoffset=5 xadvance=8 page=0 chnl=0 letter="`"
|
||||
char id=95 x=19 y=75 width=7 height=1 xoffset=0 yoffset=16 xadvance=8 page=0 chnl=0 letter="_"
|
||||
char id=45 x=28 y=75 width=4 height=1 xoffset=2 yoffset=11 xadvance=8 page=0 chnl=0 letter="-"
|
||||
char id=32 x=34 y=75 width=0 height=0 xoffset=0 yoffset=15 xadvance=8 page=0 chnl=0 letter=" "
|
||||
char id=127 x=36 y=75 width=0 height=0 xoffset=0 yoffset=15 xadvance=7 page=0 chnl=0 letter=""
|
||||
kernings count=2
|
||||
kerning first=102 second=105 amount=-8
|
||||
kerning first=102 second=108 amount=-8
|
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
26
shard.lock
|
@ -1,2 +1,26 @@
|
|||
version: 2.0
|
||||
shards: {}
|
||||
shards:
|
||||
crystgl:
|
||||
git: https://github.com/calebuharrison/crystgl.git
|
||||
version: 0.1.0+git.commit.c39912c8723873ea50b628940d79ce725b6cd37f
|
||||
|
||||
crystglfw:
|
||||
git: https://github.com/calebuharrison/crystglfw.git
|
||||
version: 0.2.0+git.commit.53de73c6ec07999ad11c42512929f0eff6f617a9
|
||||
|
||||
crystimage:
|
||||
git: https://github.com/calebuharrison/crystimage.git
|
||||
version: 0.1.0+git.commit.98f8a7b80100ee4bab3205ceb924128ec41e3148
|
||||
|
||||
lib_gl:
|
||||
git: https://github.com/calebuharrison/libgl.git
|
||||
version: 0.1.0+git.commit.fed2ca7f6cd15efea94458b234c3ca5b0a8ffc5e
|
||||
|
||||
lib_glfw:
|
||||
git: https://github.com/calebuharrison/libglfw.git
|
||||
version: 0.1.0+git.commit.4cf7c3774f278d7e044bb30a35b104f5b12fdc53
|
||||
|
||||
lib_stb_image:
|
||||
git: https://github.com/calebuharrison/libstbimage.git
|
||||
version: 0.1.0+git.commit.32bc23af165dbe004a7468426f09e6701463bc72
|
||||
|
||||
|
|
13
shard.yml
|
@ -4,6 +4,19 @@ version: 0.1.0
|
|||
authors:
|
||||
- Jill "oatmealine" Monoids <oatmealine@disroot.org>
|
||||
|
||||
dependencies:
|
||||
crystglfw:
|
||||
github: calebuharrison/CrystGLFW
|
||||
branch: master
|
||||
lib_glfw:
|
||||
github: calebuharrison/LibGLFW
|
||||
branch: master
|
||||
crystgl:
|
||||
github: calebuharrison/CrystGL
|
||||
branch: master
|
||||
crystimage:
|
||||
github: calebuharrison/CrystImage
|
||||
|
||||
targets:
|
||||
funfriend:
|
||||
main: src/funfriend.cr
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
class Funfriend::ChatterContext < Funfriend::WindowContext
|
||||
getter renderer : TextRenderer
|
||||
getter window_size : NamedTuple(width: Int32, height: Int32)
|
||||
property timer : Float64
|
||||
|
||||
WINDOW_SIZE = {width: 256, height: 32}
|
||||
DEFAULT_DURATION = 10.0
|
||||
|
||||
def initialize(text : String, position : NamedTuple(x: Int32, y: Int32), duration : Float64 = DEFAULT_DURATION)
|
||||
sheet = FontMan.parse_bm(File.read "assets/fonts/SpaceMono.fnt")
|
||||
|
||||
position_data = FontMan.position_text(text, sheet)
|
||||
|
||||
@window_size = {
|
||||
width: position_data[:width],
|
||||
height: position_data[:height]
|
||||
}
|
||||
|
||||
super(
|
||||
title: "??__FUNFRIEND__?? > CHATTER",
|
||||
width: window_size[:width], height: window_size[:height],
|
||||
transparent: false
|
||||
)
|
||||
|
||||
# just for initialization, let OpenGL know this is the current context
|
||||
window.make_context_current
|
||||
|
||||
@timer = duration
|
||||
@renderer = TextRenderer.new(text, sheet)
|
||||
|
||||
window.position = {
|
||||
x: position[:x] - window_size[:width]//2,
|
||||
y: position[:y] - window_size[:height]//2,
|
||||
}
|
||||
end
|
||||
|
||||
def render(dt : Float64)
|
||||
# let OpenGL draw to it
|
||||
window.make_context_current
|
||||
|
||||
LibGL.clear_color(0.0, 0.0, 0.0, 1.0)
|
||||
LibGL.clear(Buffer::Bit::Color)
|
||||
|
||||
renderer.render(dt, window_size[:width], window_size[:height])
|
||||
end
|
||||
|
||||
def update(dt : Float64)
|
||||
@timer = @timer - dt
|
||||
if @timer <= 0.0
|
||||
window.should_close
|
||||
end
|
||||
|
||||
render(dt)
|
||||
|
||||
window.swap_buffers
|
||||
end
|
||||
|
||||
def clean_up
|
||||
renderer.clean_up
|
||||
end
|
||||
end
|
|
@ -0,0 +1,103 @@
|
|||
module Funfriend::FontMan
|
||||
extend self
|
||||
|
||||
private def quoted_space_split(string : String)
|
||||
accum = [] of String
|
||||
chars = [] of Char
|
||||
quoted = false
|
||||
|
||||
string.each_char do |char|
|
||||
if !quoted && char == ' '
|
||||
if (chars.count &.!= ' ') > 0
|
||||
accum << chars.join
|
||||
end
|
||||
chars = [] of Char
|
||||
else
|
||||
if char == '"'
|
||||
quoted = !quoted
|
||||
end
|
||||
chars << char
|
||||
end
|
||||
end
|
||||
|
||||
if (chars.count &.!= ' ') > 0
|
||||
accum << chars.join
|
||||
end
|
||||
|
||||
return accum
|
||||
end
|
||||
|
||||
alias BMCommon = NamedTuple(line_height: Int32, base: Int32, scale_w: Int32, scale_h: Int32)
|
||||
alias BMChar = NamedTuple(id: Int32, x: Int32, y: Int32, width: Int32, height: Int32, xoffset: Int32, yoffset: Int32, xadvance: Int32, letter: Char)
|
||||
alias BMKerning = NamedTuple(first: Int32, second: Int32, amount: Int32)
|
||||
alias BMSheet = NamedTuple(common: BMCommon, chars: Array(BMChar), kernings: Array(BMKerning))
|
||||
|
||||
def parse_bm(data : String) : BMSheet
|
||||
common = nil
|
||||
chars = [] of BMChar
|
||||
kernings = [] of BMKerning
|
||||
|
||||
data.each_line do |line|
|
||||
words = line.split
|
||||
key = words[0]?
|
||||
args_array = quoted_space_split(words[1..].join(" ")).map &.split('=', 2)
|
||||
args = Hash.zip(args_array.map &.[0], args_array.map &.[1])
|
||||
|
||||
case key
|
||||
when "common"
|
||||
common = {
|
||||
line_height: args["lineHeight"].to_i,
|
||||
base: args["base"].to_i,
|
||||
scale_w: args["scaleW"].to_i,
|
||||
scale_h: args["scaleH"].to_i
|
||||
}
|
||||
when "char"
|
||||
chars << {
|
||||
id: args["id"].to_i,
|
||||
x: args["x"].to_i,
|
||||
y: args["y"].to_i,
|
||||
width: args["width"].to_i,
|
||||
height: args["height"].to_i,
|
||||
xoffset: args["xoffset"].to_i,
|
||||
yoffset: args["yoffset"].to_i,
|
||||
xadvance: args["xadvance"].to_i,
|
||||
letter: args["letter"].lchop('"').rchop('"')[0],
|
||||
}
|
||||
when "kerning"
|
||||
kernings << {
|
||||
first: args["first"].to_i,
|
||||
second: args["second"].to_i,
|
||||
amount: args["amount"].to_i,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
common: common.not_nil!,
|
||||
chars: chars,
|
||||
kernings: kernings,
|
||||
}
|
||||
end
|
||||
|
||||
# TODO: kerning
|
||||
def position_text(text : String, sheet : BMSheet)
|
||||
positions = [] of NamedTuple(x: Int32, y: Int32, char: BMChar)
|
||||
|
||||
x = 0
|
||||
text.each_char do |char|
|
||||
bm_char = sheet[:chars].find! { |c| c[:letter] == char }
|
||||
positions << {
|
||||
x: x + bm_char[:xoffset],
|
||||
y: sheet[:common][:base] - bm_char[:height],
|
||||
char: bm_char,
|
||||
}
|
||||
x = x + bm_char[:xadvance]
|
||||
end
|
||||
|
||||
return {
|
||||
width: x,
|
||||
height: sheet[:common][:line_height],
|
||||
positions: positions,
|
||||
}
|
||||
end
|
||||
end
|
|
@ -1,6 +1,77 @@
|
|||
# TODO: Write documentation for `Funfriend`
|
||||
require "crystglfw"
|
||||
require "lib_glfw"
|
||||
require "crystgl"
|
||||
require "crystimage"
|
||||
|
||||
require "./log.cr"
|
||||
require "./gl.cr"
|
||||
require "./textureman.cr"
|
||||
require "./fontman.cr"
|
||||
require "./window_context.cr"
|
||||
require "./funfriend_context.cr"
|
||||
require "./funfriend_renderer.cr"
|
||||
require "./chatter_context.cr"
|
||||
require "./text_renderer.cr"
|
||||
|
||||
include CrystGLFW
|
||||
include CrystGL
|
||||
|
||||
module Funfriend
|
||||
VERSION = "0.1.0"
|
||||
|
||||
# TODO: Put your code here
|
||||
LOG = ::Log.for("")
|
||||
|
||||
@@contexts = [] of WindowContext
|
||||
@@main_context : WindowContext?
|
||||
|
||||
@@clean_up_queue = [] of WindowContext
|
||||
|
||||
def self.should_close?
|
||||
@@main_context && @@main_context.not_nil!.window.should_close?
|
||||
end
|
||||
|
||||
def self.init_contexts
|
||||
add_context(FunfriendContext.new)
|
||||
@@main_context = @@contexts[0]
|
||||
end
|
||||
|
||||
def self.add_context(context : WindowContext)
|
||||
@@contexts << context
|
||||
end
|
||||
|
||||
def self.contexts
|
||||
@@contexts
|
||||
end
|
||||
|
||||
def self.run
|
||||
Logging.init
|
||||
|
||||
CrystGLFW.run do
|
||||
init_contexts
|
||||
|
||||
last_t = CrystGLFW.time
|
||||
until should_close?
|
||||
dt = CrystGLFW.time - last_t
|
||||
last_t = CrystGLFW.time
|
||||
|
||||
@@contexts = @@contexts.select do |context|
|
||||
if context.window.should_close?
|
||||
context.close
|
||||
@@clean_up_queue << context
|
||||
false
|
||||
else
|
||||
context.update(dt)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
CrystGLFW.wait_events(1/120)
|
||||
end
|
||||
|
||||
@@contexts.each &.destroy
|
||||
@@clean_up_queue.each &.clean_up
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Funfriend.run
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
class Funfriend::FunfriendContext < Funfriend::WindowContext
|
||||
getter renderer : FunfriendRenderer
|
||||
property chatter_timer : Float64
|
||||
|
||||
WINDOW_SIZE = {width: 82, height: 82}
|
||||
CHATTER_TIMER = 5.0
|
||||
|
||||
def initialize
|
||||
super(
|
||||
title: "??_FUNFRIEND_??",
|
||||
width: WINDOW_SIZE[:width], height: WINDOW_SIZE[:height],
|
||||
transparent: true
|
||||
)
|
||||
|
||||
@chatter_timer = 1.0
|
||||
|
||||
# just for initialization, let OpenGL know this is the current context
|
||||
window.make_context_current
|
||||
@renderer = FunfriendRenderer.new
|
||||
|
||||
window.on_mouse_button do |event|
|
||||
if event.action.press? && event.mouse_button.two?
|
||||
renderer.catmoding = !renderer.catmoding
|
||||
end
|
||||
end
|
||||
|
||||
window.on_key do |event|
|
||||
if event.action.press? && event.key.escape?
|
||||
event.window.should_close
|
||||
end
|
||||
end
|
||||
|
||||
# pick a random pos
|
||||
monitor = Monitor.primary
|
||||
window.position = {
|
||||
x: monitor.position[:x] + (monitor.video_mode.size[:width] * rand((0.0..1.0))).to_i,
|
||||
y: monitor.position[:y] + (monitor.video_mode.size[:height] * rand((0.0..1.0))).to_i
|
||||
}
|
||||
end
|
||||
|
||||
def render(dt : Float64)
|
||||
# let OpenGL draw to it
|
||||
window.make_context_current
|
||||
|
||||
# draw funfriend
|
||||
renderer.render(dt, WINDOW_SIZE[:width], WINDOW_SIZE[:height])
|
||||
end
|
||||
|
||||
def update(dt : Float64)
|
||||
@chatter_timer = @chatter_timer - dt
|
||||
if @chatter_timer <= 0.0
|
||||
@chatter_timer = @chatter_timer + CHATTER_TIMER
|
||||
|
||||
Funfriend.contexts.each do |context|
|
||||
if context.is_a?(ChatterContext)
|
||||
context.window.position = {
|
||||
x: context.window.position[:x],
|
||||
y: context.window.position[:y] - 30
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
Funfriend.add_context(ChatterContext.new(renderer.catmoding ? "HEWWO INTEWLOPEW" : "HELLO INTERLOPER", {
|
||||
x: window.position[:x] + WINDOW_SIZE[:width] // 2,
|
||||
y: window.position[:y] + WINDOW_SIZE[:height] // 2 - 70
|
||||
}))
|
||||
end
|
||||
|
||||
render(dt)
|
||||
|
||||
window.swap_buffers
|
||||
end
|
||||
|
||||
def clean_up
|
||||
renderer.clean_up
|
||||
end
|
||||
end
|
|
@ -0,0 +1,113 @@
|
|||
class Funfriend::FunfriendRenderer
|
||||
FUNFRIEND_SIZE = {width: 64, height: 64}
|
||||
FPS = 10.0
|
||||
|
||||
getter shader_program : Program
|
||||
getter vertex_array : VertexArray
|
||||
getter vertex_buffer : Buffer
|
||||
getter textures : Hash(String, TextureMan::TextureBasket)
|
||||
|
||||
property catmoding : Bool
|
||||
|
||||
def initialize
|
||||
@catmoding = false
|
||||
|
||||
@shader_program = init_shaders
|
||||
@vertex_array, @vertex_buffer = init_buffers
|
||||
@textures = init_textures
|
||||
end
|
||||
|
||||
def init_textures
|
||||
return {
|
||||
"normal" => TextureMan::TextureBasket.new(
|
||||
(0..39).map { |i| TextureMan.load_texture("assets/funfriend/funfriend_#{i.to_s.rjust(2, '0')}.png") },
|
||||
FPS
|
||||
),
|
||||
"cat" => TextureMan::TextureBasket.new(
|
||||
(0..39).map { |i| TextureMan.load_texture("assets/funfriend/catfriend_#{i.to_s.rjust(2, '0')}.png") },
|
||||
FPS
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
def init_buffers
|
||||
vertices = {
|
||||
# ------ positions ------- texture coordinates
|
||||
1.0f32, 1.0f32, 0.0f32, 1.0f32, 1.0f32, # top right
|
||||
1.0f32, -1.0f32, 0.0f32, 1.0f32, 0.0f32, # bottom right
|
||||
-1.0f32, -1.0f32, 0.0f32, 0.0f32, 0.0f32, # bottom left
|
||||
-1.0f32, 1.0f32, 0.0f32, 0.0f32, 1.0f32 # top left
|
||||
}
|
||||
|
||||
# Indices used for indexed draw calls. Each is used as an index into the four vertices.
|
||||
indices = {
|
||||
0, 1, 3, # first triangle
|
||||
1, 2, 3 # second triangle
|
||||
}
|
||||
|
||||
vertex_buffer = Buffer.new
|
||||
element_buffer = Buffer.new
|
||||
vertex_array = VertexArray.new
|
||||
|
||||
vertex_array.bind do
|
||||
vertex_buffer.bind(Buffer::Target::Array) do |buffer, target|
|
||||
target.buffer_data(vertices, Buffer::UsageHint::StaticDraw)
|
||||
vertex_array.define_attributes do |va|
|
||||
va.attribute(3, DataType::Float, false)
|
||||
va.attribute(2, DataType::Float, false)
|
||||
end
|
||||
end
|
||||
|
||||
# bind the element buffer to GL_ELEMENT_ARRAY_BUFFER
|
||||
element_buffer.bind(Buffer::Target::ElementArray)
|
||||
|
||||
# Send index data to the GPU.
|
||||
Buffer::Target::ElementArray.buffer_data(indices, Buffer::UsageHint::StaticDraw)
|
||||
end
|
||||
|
||||
# unbind the element buffer.
|
||||
element_buffer.unbind
|
||||
|
||||
return {vertex_array, vertex_buffer}
|
||||
end
|
||||
|
||||
def init_shaders
|
||||
vertex_shader_source = File.read "src/glsl/nop.vert"
|
||||
fragment_shader_source = File.read "src/glsl/funfriend.frag"
|
||||
|
||||
vertex_shader = VertexShader.create(vertex_shader_source)
|
||||
fragment_shader = FragmentShader.create(fragment_shader_source)
|
||||
|
||||
shaders = {vertex_shader, fragment_shader}
|
||||
return Program.create(shaders)
|
||||
end
|
||||
|
||||
def render(dt : Float64, window_width : Int32, window_height : Int32)
|
||||
LibGL.clear_color(0.0, 0.0, 0.0, 0.0)
|
||||
LibGL.clear(Buffer::Bit::Color)
|
||||
|
||||
textures.each_value &.update(dt)
|
||||
texture_basket = textures[catmoding ? "cat" : "normal"]
|
||||
frame = texture_basket.texture
|
||||
|
||||
width, height = frame[:width], frame[:height]
|
||||
|
||||
Texture::Unit.activate(0)
|
||||
frame[:tex].bind(Texture::Target::Texture2D) do
|
||||
shader_program.use do |shader|
|
||||
shader.set_uniform("texture1", 0)
|
||||
shader.set_uniform("funfriendSize", FUNFRIEND_SIZE[:width].to_f32, FUNFRIEND_SIZE[:height].to_f32)
|
||||
shader.set_uniform("resolution", window_width.to_f32, window_height.to_f32)
|
||||
shader.set_uniform("time", CrystGLFW.time.to_f32)
|
||||
|
||||
vertex_array.bind do
|
||||
LibGL.draw_elements(LibGL::TRIANGLES, 6, DataType::UnsignedInt, Pointer(Void).new(0))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def clean_up
|
||||
{vertex_array, vertex_buffer}.each { |v| v.delete }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
module Funfriend::GL
|
||||
extend self
|
||||
|
||||
def buffer_data_array(target : Enum, data : Array, usage_hint : Buffer::UsageHint)
|
||||
data_size = data.reduce(0) {|memo, i| memo + sizeof(typeof(i))}
|
||||
LibGL.buffer_data(target, data_size, Pointer(Void).new(0), usage_hint)
|
||||
|
||||
offset = 0
|
||||
data.each do |byte|
|
||||
size = sizeof(typeof(byte))
|
||||
LibGL.buffer_sub_data(target, offset, size, pointerof(byte))
|
||||
offset += size
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
#version 330 core
|
||||
in vec2 TexCoord;
|
||||
|
||||
uniform sampler2D texture1;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
vec4 tex = texture(texture1, TexCoord);
|
||||
FragColor = vec4(mix(vec3(0.0, 0.0, 0.0), tex.rgb, tex.a), 1.0);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#version 330 core
|
||||
#define PI 3.141592653589793
|
||||
in vec2 TexCoord;
|
||||
|
||||
uniform sampler2D texture1;
|
||||
uniform vec2 funfriendSize;
|
||||
uniform vec2 resolution;
|
||||
uniform float time;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
vec2 rotate(vec2 uv, float angle) {
|
||||
// algebra formula for rotation by matrix , https://en.wikipedia.org/wiki/Rotation_matrix
|
||||
mat2 m = mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
|
||||
// rotation of uv with matrix algebra formula where is set the rotation angle
|
||||
return m * uv;
|
||||
}
|
||||
|
||||
vec3 rotateY(vec3 uv, float angle) {
|
||||
mat3 m = mat3(
|
||||
cos(angle), 0.0, sin(angle),
|
||||
0.0, 1.0, 0.0,
|
||||
-sin(angle), 0.0, cos(angle)
|
||||
);
|
||||
return m * uv;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 uv = TexCoord;
|
||||
|
||||
// [0.0 - 1.0] -> [-0.5 - 0.5]
|
||||
uv -= 0.5;
|
||||
|
||||
// BUDDYBOUNCE-Y
|
||||
float y = sin(time * PI);
|
||||
uv.y += y * 0.05;
|
||||
uv = rotateY(vec3(uv, 0.0), y * (20. / 360.) * PI*2.).xy;
|
||||
|
||||
// BUDDYBOUNCE-X
|
||||
float x = sin(time * 0.5 * PI);
|
||||
uv.x += x * 0.05;
|
||||
uv = rotate(uv, x * (5. / 360.) * PI*2.);
|
||||
|
||||
// scale funfriend to fit in the center
|
||||
vec2 scale = funfriendSize / resolution;
|
||||
uv /= scale;
|
||||
|
||||
// [-0.5 - 0.5] -> [0.0 - 1.0]
|
||||
uv += 0.5;
|
||||
|
||||
// ooo you're a vflipper... you like flipping your y coordinate.... ooooo
|
||||
uv.y = 1.0 - uv.y;
|
||||
|
||||
FragColor = texture(texture1, uv);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#version 330 core
|
||||
in vec2 TexCoord;
|
||||
|
||||
uniform sampler2D texture1;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
FragColor = texture(texture1, TexCoord);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#version 330 core
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec2 aTexCoord;
|
||||
|
||||
out vec2 TexCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(aPos, 1.0);
|
||||
TexCoord = aTexCoord.xy;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
require "log"
|
||||
require "colorize"
|
||||
|
||||
module Funfriend::Logging
|
||||
extend self
|
||||
|
||||
struct FunfriendFormat < Log::StaticFormatter
|
||||
private def severity_color(severity : Log::Severity) : Colorize::Object
|
||||
case severity
|
||||
when .trace?
|
||||
Colorize.with.dark_gray
|
||||
when .debug?
|
||||
Colorize.with.dark_gray
|
||||
when .info?
|
||||
Colorize.with.cyan
|
||||
when .notice?
|
||||
Colorize.with.cyan
|
||||
when .warn?
|
||||
Colorize.with.yellow
|
||||
when .error?
|
||||
Colorize.with.red
|
||||
when .fatal?
|
||||
Colorize.with.light_red
|
||||
else
|
||||
Colorize.with.white
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
severity_color(@entry.severity).surround(@io) do
|
||||
@entry.severity.label.rjust(@io, 6)
|
||||
end
|
||||
string " "
|
||||
Colorize.with.white.surround(@io) do
|
||||
source
|
||||
end
|
||||
string " "
|
||||
message
|
||||
end
|
||||
end
|
||||
|
||||
def init
|
||||
Log.setup(backend: Log::IOBackend.new(formatter: FunfriendFormat, dispatcher: Log::DispatchMode::Sync))
|
||||
end
|
||||
end
|
|
@ -0,0 +1,120 @@
|
|||
class Funfriend::TextRenderer
|
||||
getter text : String
|
||||
|
||||
getter shader_program : Program
|
||||
getter vertex_array : VertexArray
|
||||
getter vertex_buffer : Buffer
|
||||
getter font_texture : Texture
|
||||
getter sheet : FontMan::BMSheet
|
||||
|
||||
def initialize(text : String, sheet : FontMan::BMSheet)
|
||||
@text = text
|
||||
@sheet = sheet
|
||||
@shader_program = init_shaders
|
||||
@vertex_array, @vertex_buffer = init_buffers
|
||||
@font_texture = init_textures
|
||||
end
|
||||
|
||||
def init_textures
|
||||
TextureMan.load_texture("assets/fonts/SpaceMono.png", {
|
||||
Texture::ParameterName::TextureWrapS => Texture::ParameterValue::ClampToBorder,
|
||||
Texture::ParameterName::TextureWrapT => Texture::ParameterValue::ClampToBorder,
|
||||
Texture::ParameterName::TextureMinFilter => Texture::ParameterValue::Linear,
|
||||
Texture::ParameterName::TextureMagFilter => Texture::ParameterValue::Linear
|
||||
})[:tex]
|
||||
end
|
||||
|
||||
def get_letter_crop(char : FontMan::BMChar)
|
||||
x = (char[:x] / sheet[:common][:scale_w]).to_f32
|
||||
y = (char[:y] / sheet[:common][:scale_h]).to_f32
|
||||
w = (char[:width] / sheet[:common][:scale_w]).to_f32
|
||||
h = (char[:height] / sheet[:common][:scale_h]).to_f32
|
||||
|
||||
return {x, y, w, h}
|
||||
end
|
||||
|
||||
def init_buffers
|
||||
vertices = [] of Float32
|
||||
indices = [] of Int32
|
||||
|
||||
position_data = FontMan.position_text(text, sheet)
|
||||
|
||||
i = 0
|
||||
position_data[:positions].each do |letter|
|
||||
char = letter[:char]
|
||||
x, y, w, h = get_letter_crop(char)
|
||||
|
||||
pos_x = (letter[:x] / position_data[:width]).to_f32 * 2 - 1
|
||||
pos_w = (char[:width] / position_data[:width]).to_f32 * 2
|
||||
pos_y = (letter[:y] / position_data[:height]).to_f32 * 2 - 1
|
||||
pos_h = (char[:height] / position_data[:height]).to_f32 * 2
|
||||
|
||||
vertices += [
|
||||
# ------ positions ------- texture coordinates
|
||||
pos_x + pos_w, pos_y + pos_h, 0.0f32, x + w, y, # top right
|
||||
pos_x + pos_w, pos_y, 0.0f32, x + w, y + h, # bottom right
|
||||
pos_x, pos_y, 0.0f32, x, y + h, # bottom left
|
||||
pos_x, pos_y + pos_h, 0.0f32, x, y, # top left
|
||||
]
|
||||
|
||||
# Indices used for indexed draw calls. Each is used as an index into the four vertices.
|
||||
indices += [
|
||||
0, 1, 3, # first triangle
|
||||
1, 2, 3 # second triangle
|
||||
].map &.+ (i * 4)
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
vertex_buffer = Buffer.new
|
||||
element_buffer = Buffer.new
|
||||
vertex_array = VertexArray.new
|
||||
|
||||
vertex_array.bind do
|
||||
vertex_buffer.bind(Buffer::Target::Array) do |buffer, target|
|
||||
GL.buffer_data_array(target, vertices, Buffer::UsageHint::StaticDraw)
|
||||
vertex_array.define_attributes do |va|
|
||||
va.attribute(3, DataType::Float, false)
|
||||
va.attribute(2, DataType::Float, false)
|
||||
end
|
||||
end
|
||||
|
||||
# bind the element buffer to GL_ELEMENT_ARRAY_BUFFER
|
||||
element_buffer.bind(Buffer::Target::ElementArray)
|
||||
|
||||
# Send index data to the GPU.
|
||||
GL.buffer_data_array(Buffer::Target::ElementArray, indices, Buffer::UsageHint::StaticDraw)
|
||||
end
|
||||
|
||||
# unbind the element buffer.
|
||||
element_buffer.unbind
|
||||
|
||||
return {vertex_array, vertex_buffer}
|
||||
end
|
||||
|
||||
def init_shaders
|
||||
vertex_shader_source = File.read "src/glsl/nop.vert"
|
||||
fragment_shader_source = File.read "src/glsl/font.frag"
|
||||
|
||||
vertex_shader = VertexShader.create(vertex_shader_source)
|
||||
fragment_shader = FragmentShader.create(fragment_shader_source)
|
||||
|
||||
shaders = {vertex_shader, fragment_shader}
|
||||
return Program.create(shaders)
|
||||
end
|
||||
|
||||
def render(dt : Float64, window_width : Int32, window_height : Int32)
|
||||
font_texture.bind(Texture::Target::Texture2D) do
|
||||
shader_program.use do |p|
|
||||
p.set_uniform("texture1", 0)
|
||||
vertex_array.bind do
|
||||
LibGL.draw_elements(LibGL::TRIANGLES, 6 * text.size, DataType::UnsignedInt, Pointer(Void).new(0))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def clean_up
|
||||
{vertex_array, vertex_buffer}.each { |v| v.delete }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,63 @@
|
|||
module Funfriend::TextureMan
|
||||
extend self
|
||||
|
||||
DEFAULT_TEXTURE_PARAMS = {
|
||||
Texture::ParameterName::TextureWrapS => Texture::ParameterValue::ClampToBorder,
|
||||
Texture::ParameterName::TextureWrapT => Texture::ParameterValue::ClampToBorder,
|
||||
Texture::ParameterName::TextureMinFilter => Texture::ParameterValue::Nearest,
|
||||
Texture::ParameterName::TextureMagFilter => Texture::ParameterValue::Nearest
|
||||
}
|
||||
|
||||
alias SizedTexture = NamedTuple(tex: Texture, width: Int32, height: Int32)
|
||||
|
||||
def load_texture(filepath : String, texture_params : Texture::ParameterHash = DEFAULT_TEXTURE_PARAMS) : SizedTexture
|
||||
# Create a texture
|
||||
texture = Texture.new
|
||||
width, height = 0, 0
|
||||
|
||||
# Bind the texture the 2D target
|
||||
texture.bind(Texture::Target::Texture2D) do |tex, target|
|
||||
|
||||
# Apply the previously declared configurations.
|
||||
target.set_parameters(texture_params)
|
||||
|
||||
# Open up container image
|
||||
CrystImage.open(filepath) do |image|
|
||||
width, height = image.width, image.height
|
||||
|
||||
# Send the image data to the GPU
|
||||
target.image_2d(0, BaseInternalFormat::RGBA, image.width, image.height, Format::RGBA, DataType::UnsignedByte, image.data)
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
tex: texture,
|
||||
width: width,
|
||||
height: height
|
||||
}
|
||||
end
|
||||
|
||||
class TextureBasket
|
||||
property textures : Array(SizedTexture)
|
||||
property fps : Float64
|
||||
property t : Float64
|
||||
|
||||
def initialize(textures : Array(SizedTexture), fps : Float64)
|
||||
@textures = textures
|
||||
@fps = fps
|
||||
@t = 0
|
||||
end
|
||||
|
||||
def frame : Int32
|
||||
(t * fps).floor().to_i % textures.size
|
||||
end
|
||||
|
||||
def texture : SizedTexture
|
||||
textures[frame]
|
||||
end
|
||||
|
||||
def update(delta : Float64)
|
||||
@t += delta
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,55 @@
|
|||
# GLFW_TRANSPARENT_FRAMEBUFFER, seems to be unsupported by LibGLFW
|
||||
GLFW_TRANSPARENT_FRAMEBUFFER = 0x0002000A
|
||||
# GLFW_FOCUS_ON_SHOW, also unsupported by LibGLFW
|
||||
GLFW_FOCUS_ON_SHOW = 0x0002000C
|
||||
|
||||
class Funfriend::WindowContext
|
||||
getter window : CrystGLFW::Window
|
||||
|
||||
DEFAULT_HINTS = {
|
||||
# supposedly required on MacOS
|
||||
Window::HintLabel::ContextVersionMajor => 3,
|
||||
Window::HintLabel::ContextVersionMinor => 3,
|
||||
Window::HintLabel::OpenGLForwardCompat => true,
|
||||
Window::HintLabel::OpenGLProfile => OpenGLProfile::Core,
|
||||
Window::HintLabel::ClientAPI => ClientAPI::OpenGL,
|
||||
|
||||
Window::HintLabel::Resizable => false,
|
||||
Window::HintLabel::Decorated => false,
|
||||
Window::HintLabel::Floating => true,
|
||||
Window::HintLabel::Focused => false,
|
||||
}
|
||||
|
||||
def initialize(title : String, width : Int32, height : Int32, transparent : Bool, hints = DEFAULT_HINTS)
|
||||
if transparent
|
||||
LibGLFW.window_hint(GLFW_TRANSPARENT_FRAMEBUFFER, 1)
|
||||
end
|
||||
LibGLFW.window_hint(GLFW_FOCUS_ON_SHOW, 0)
|
||||
|
||||
@window = Window.new title: title, width: width, height: height, hints: hints
|
||||
|
||||
LOG.info { "creating context #{self}" }
|
||||
end
|
||||
|
||||
def update(dt : Float64)
|
||||
# let OpenGL draw to it
|
||||
window.make_context_current
|
||||
|
||||
# nothing to draw; dummy out
|
||||
|
||||
# idk why you need to do this but oh well
|
||||
window.swap_buffers
|
||||
end
|
||||
|
||||
def close
|
||||
window.destroy
|
||||
end
|
||||
|
||||
def clean_up
|
||||
end
|
||||
|
||||
def destroy
|
||||
close
|
||||
clean_up
|
||||
end
|
||||
end
|