From d42ab3a25841cc1d164025ad4caae5b4c4718136 Mon Sep 17 00:00:00 2001 From: Patrick Wuttke Date: Tue, 17 Sep 2024 00:52:04 +0200 Subject: [PATCH] Added some simple test text. --- assets/bitmaps/ui.png | Bin 0 -> 2559 bytes assets/fonts/symtext.fnt | 125 +++++++++ assets/shaders/glsl/ui.vert | 24 ++ private/sdl_gpu_test/6_ui/app.cpp | 273 +++++++++++++++----- private/sdl_gpu_test/6_ui/app.hpp | 17 ++ private/sdl_gpu_test/SModule | 1 + private/sdl_gpu_test/util/font_map.cpp | 91 +++++++ private/sdl_gpu_test/util/font_map.hpp | 67 +++++ private/sdl_gpu_test/util/texture_atlas.hpp | 14 + 9 files changed, 548 insertions(+), 64 deletions(-) create mode 100644 assets/bitmaps/ui.png create mode 100644 assets/fonts/symtext.fnt create mode 100644 assets/shaders/glsl/ui.vert create mode 100644 private/sdl_gpu_test/util/font_map.cpp create mode 100644 private/sdl_gpu_test/util/font_map.hpp create mode 100644 private/sdl_gpu_test/util/texture_atlas.hpp diff --git a/assets/bitmaps/ui.png b/assets/bitmaps/ui.png new file mode 100644 index 0000000000000000000000000000000000000000..09a1e3d6d58629ecc11c3f928d01423c5606b423 GIT binary patch literal 2559 zcmXw(c|6oxAIHy(8Ozkg&8WzhC5e#9&SUJOY?sP%!)R33?#VJj`bpNZ#$-vB>uN!= zWSeA?CHGBay-rfd_SSHI)rqa|NArU` zWf(vSfV|gCeV#I0xDJl_qrom$CW)$)6y?AE`>GrzbC@~zRW^DrDL0@9XhPL^g~1~U zW3S+5`NzXpB|@2_#g)R|0fE0)=iFEnQ4$N$j~4^GJ72x{(s#E=(#CvHos+}v2HSb- zB=*e(^8CU-S3Xu0a8-WL4O!hW@{L*yy*9fvGZtm~SSdzPBYSpSZiN45QTw&6liYb; z3NC1~wpdji1J7MxD(NHDJh_jS{}j>vIh?(w&-)Viw;o}bM+q0}CcEkkTYqLV*0&=uljjv#A89;+Aj@W5%u|n|8{3xqyqUlT7^Y zS}Z?Mqlq~Rk4npsra)88P`Uhu$*OUsx+UqJ_DdA>|3$X&U@28TAFgsjs(~xq<_u3 zeQYJn57X7uXpTpL(*T0AH?s$~3$nDlJi^Nf^F56tITPJ~QY8^37b!8a01E?XfF&e9 zTzKMp79qULKmQR~+jsnnk7FGs&MBowR;GpL1>>cO@^76OHC2+sEmkHROF)71MQks- zl!bgji$f7O;+-@vDl)X9EwWVr6Gq+Okw4U6b!|c$?q~_Ktov1;lU)TC$Bpa%PKbVL z*Jr&}#W+EN=dMg8@o84br!4M*nN!@i_#1~-qMoxf_6sNO_XN|c2vbN>A(#R}Fw5jMIbejty1 zT)BPHn%IiE7!hYtZKW|DMoTMdE<+Z9WV9?H_*R#A5#x<6>&~jb8 zMc@z+Qg`ezc2b#1<;Z{o6vzXh(GAEwQ1hBDaW}?kqNX*<2WHm%l1=QP^LmSk+vLU* zCv$VPVD8Op?8zm_0UFyc!70ix)nodxm~`iI`BHzaTPQ48yKp1>Y+A8FOUjdu@UU`} z7{;h7Y*)z(0HM7s=T1sYA5XLkDsf?n+w}?D-Kdeh?_o9W&RoCnQLt@$h}NYo^DIl< zu-O#_-tXL8;tiVPj5rMiN$>6|^*Ys9cu|NQnl>bA)B2ou#^GhtU)W56z+`tsaxq{2 z7s4xJvAjtuVJxJY0!+IZRn5jmo#|OSFz;e9sy_rF+fHZ8hHHjB zDo8eRBmh)oO!+QpS&>Lpe1Q*%cTrD~gRlR=5{Zd1%W|X%YMaB@(YOJA?dpw(t`}eH zGPY$y$Q%dJIoQJd)L?*%ob{x2 zxZF?msQQL9)zp2pp}~2)%tv7yU4E)DW8>JC>yGWYgHrCOLauc)o{aX@hXj(m9mQW% z8;%e1{5(JPdTr9bz4Y(+%R*dL0k%bZjAQfiqVm1Bfy=Y=k{;e7^q%_GzCwnF>Gb%w z-el9&aX*n??;jY7X4_dK+^C<@tiFkA3%6@UTlLuQusHEnHC|(jyJ?GLa_Cy=IJq1B za~J>(!yLNhB6<;-P$pbvQc{MXoKSk>*}YWC0ym!eRe1^#d)9iak`!(CXOkEd6^Kpe zEu|(h5!zakBb?w#k(k(to!;fzhLTY<;5`K<@o>P~U-#>2cZId4H!t1G&#^*$(VU*| zZ_?osW~=&A?e8@S^K?4%?W#oP?1ZW<(8vH#BoELS?8~#awRoWSBJiP8u_Cdwdam|N zmCg9d3uDR@!QaB955L^Fp#K?Tkn0IQsi3+60X+uMXGB@~2YZ<#Y`3%}s0wlL7$%!UK`Vypl z#Lan(lpVr0ygXwv?sfey6;2L2%g;dbhcSm-9s8B8cA<8~ziV%I z*t;lH<`}+14h|a38BG150&!jzLj(NC5eXko#ZP7a?fmkoh~~=53<4>7;Qlc^HPJkj z_){MP8v%GdXm0F!{pwLfqQ$c;E_!j4+ z-sEMv9zVrFb<^vVE#?|;fk BelP$4 literal 0 HcmV?d00001 diff --git a/assets/fonts/symtext.fnt b/assets/fonts/symtext.fnt new file mode 100644 index 0000000..79b54c2 --- /dev/null +++ b/assets/fonts/symtext.fnt @@ -0,0 +1,125 @@ +info face="Symtext" size=-32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0 +common lineHeight=47 base=38 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4 +page id=0 file="symtext.png" +chars count=121 +char id=32 x=1 y=252 width=1 height=1 xoffset=0 yoffset=38 xadvance=14 page=0 chnl=15 +char id=33 x=240 y=51 width=5 height=24 xoffset=0 yoffset=14 xadvance=9 page=0 chnl=15 +char id=34 x=61 y=221 width=14 height=10 xoffset=0 yoffset=14 xadvance=19 page=0 chnl=15 +char id=35 x=85 y=1 width=23 height=24 xoffset=0 yoffset=14 xadvance=28 page=0 chnl=15 +char id=36 x=1 y=1 width=23 height=34 xoffset=0 yoffset=9 xadvance=28 page=0 chnl=15 +char id=37 x=233 y=126 width=14 height=24 xoffset=0 yoffset=14 xadvance=19 page=0 chnl=15 +char id=38 x=105 y=61 width=14 height=34 xoffset=0 yoffset=9 xadvance=19 page=0 chnl=15 +char id=39 x=77 y=232 width=5 height=10 xoffset=0 yoffset=14 xadvance=9 page=0 chnl=15 +char id=40 x=245 y=1 width=10 height=24 xoffset=0 yoffset=14 xadvance=14 page=0 chnl=15 +char id=41 x=222 y=116 width=10 height=24 xoffset=0 yoffset=14 xadvance=14 page=0 chnl=15 +char id=42 x=16 y=236 width=14 height=14 xoffset=0 yoffset=14 xadvance=19 page=0 chnl=15 +char id=43 x=31 y=236 width=14 height=14 xoffset=0 yoffset=19 xadvance=19 page=0 chnl=15 +char id=44 x=81 y=243 width=5 height=10 xoffset=0 yoffset=33 xadvance=9 page=0 chnl=15 +char id=45 x=66 y=243 width=14 height=5 xoffset=0 yoffset=23 xadvance=19 page=0 chnl=15 +char id=46 x=66 y=249 width=5 height=5 xoffset=0 yoffset=33 xadvance=9 page=0 chnl=15 +char id=47 x=232 y=151 width=14 height=24 xoffset=0 yoffset=14 xadvance=19 page=0 chnl=15 +char id=48 x=81 y=61 width=23 height=24 xoffset=0 yoffset=14 xadvance=28 page=0 chnl=15 +char id=49 x=221 y=141 width=10 height=24 xoffset=0 yoffset=14 xadvance=14 page=0 chnl=15 +char id=50 x=106 y=26 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=51 x=109 y=1 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=52 x=105 y=96 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=53 x=120 y=51 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=54 x=126 y=26 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=55 x=129 y=1 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=56 x=105 y=121 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=57 x=105 y=146 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=58 x=93 y=236 width=5 height=15 xoffset=0 yoffset=23 xadvance=9 page=0 chnl=15 +char id=59 x=87 y=236 width=5 height=19 xoffset=0 yoffset=23 xadvance=9 page=0 chnl=15 +char id=60 x=211 y=166 width=14 height=24 xoffset=0 yoffset=14 xadvance=19 page=0 chnl=15 +char id=61 x=1 y=236 width=14 height=15 xoffset=0 yoffset=18 xadvance=19 page=0 chnl=15 +char id=62 x=226 y=176 width=14 height=24 xoffset=0 yoffset=14 xadvance=19 page=0 chnl=15 +char id=63 x=105 y=171 width=19 height=24 xoffset=0 yoffset=14 xadvance=24 page=0 chnl=15 +char id=65 x=111 y=196 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=66 x=111 y=221 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=67 x=125 y=76 width=19 height=24 xoffset=0 yoffset=14 xadvance=24 page=0 chnl=15 +char id=68 x=140 y=51 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=69 x=146 y=26 width=19 height=24 xoffset=0 yoffset=14 xadvance=24 page=0 chnl=15 +char id=70 x=149 y=1 width=19 height=24 xoffset=0 yoffset=14 xadvance=24 page=0 chnl=15 +char id=71 x=125 y=101 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=72 x=125 y=126 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=73 x=246 y=61 width=5 height=24 xoffset=0 yoffset=14 xadvance=9 page=0 chnl=15 +char id=74 x=125 y=151 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=75 x=131 y=176 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=76 x=131 y=201 width=19 height=24 xoffset=0 yoffset=14 xadvance=24 page=0 chnl=15 +char id=77 x=81 y=86 width=23 height=24 xoffset=0 yoffset=14 xadvance=28 page=0 chnl=15 +char id=78 x=131 y=226 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=79 x=145 y=76 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=80 x=160 y=51 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=81 x=166 y=26 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=82 x=169 y=1 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=83 x=145 y=101 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=84 x=81 y=111 width=23 height=24 xoffset=0 yoffset=14 xadvance=28 page=0 chnl=15 +char id=85 x=145 y=126 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=86 x=145 y=151 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=87 x=81 y=136 width=23 height=24 xoffset=0 yoffset=14 xadvance=28 page=0 chnl=15 +char id=88 x=151 y=176 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=89 x=151 y=201 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=90 x=151 y=226 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=91 x=211 y=191 width=10 height=24 xoffset=0 yoffset=14 xadvance=14 page=0 chnl=15 +char id=93 x=241 y=176 width=10 height=24 xoffset=0 yoffset=14 xadvance=14 page=0 chnl=15 +char id=94 x=46 y=236 width=19 height=10 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=95 x=46 y=247 width=19 height=5 xoffset=0 yoffset=43 xadvance=24 page=0 chnl=15 +char id=96 x=66 y=232 width=10 height=10 xoffset=0 yoffset=-1 xadvance=14 page=0 chnl=15 +char id=97 x=165 y=76 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=98 x=180 y=51 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=99 x=186 y=26 width=19 height=24 xoffset=0 yoffset=14 xadvance=24 page=0 chnl=15 +char id=100 x=189 y=1 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=101 x=165 y=101 width=19 height=24 xoffset=0 yoffset=14 xadvance=24 page=0 chnl=15 +char id=102 x=165 y=126 width=19 height=24 xoffset=0 yoffset=14 xadvance=24 page=0 chnl=15 +char id=103 x=165 y=151 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=104 x=171 y=176 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=105 x=216 y=101 width=5 height=24 xoffset=0 yoffset=14 xadvance=9 page=0 chnl=15 +char id=106 x=171 y=201 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=107 x=171 y=226 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=108 x=185 y=76 width=19 height=24 xoffset=0 yoffset=14 xadvance=24 page=0 chnl=15 +char id=109 x=81 y=161 width=23 height=24 xoffset=0 yoffset=14 xadvance=28 page=0 chnl=15 +char id=110 x=200 y=51 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=111 x=206 y=26 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=112 x=209 y=1 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=113 x=185 y=101 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=114 x=185 y=126 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=115 x=185 y=151 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=116 x=81 y=186 width=23 height=24 xoffset=0 yoffset=14 xadvance=28 page=0 chnl=15 +char id=117 x=191 y=176 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=118 x=191 y=201 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=119 x=87 y=211 width=23 height=24 xoffset=0 yoffset=14 xadvance=28 page=0 chnl=15 +char id=120 x=191 y=226 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=121 x=205 y=76 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=122 x=220 y=51 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=123 x=229 y=1 width=15 height=24 xoffset=0 yoffset=14 xadvance=19 page=0 chnl=15 +char id=124 x=246 y=26 width=5 height=34 xoffset=0 yoffset=9 xadvance=9 page=0 chnl=15 +char id=125 x=205 y=141 width=15 height=24 xoffset=0 yoffset=14 xadvance=19 page=0 chnl=15 +char id=176 x=81 y=36 width=24 height=24 xoffset=0 yoffset=14 xadvance=26 page=0 chnl=15 +char id=180 x=76 y=221 width=10 height=10 xoffset=0 yoffset=-1 xadvance=14 page=0 chnl=15 +char id=193 x=1 y=36 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=196 x=25 y=1 width=19 height=34 xoffset=0 yoffset=4 xadvance=23 page=0 chnl=15 +char id=201 x=1 y=76 width=19 height=39 xoffset=0 yoffset=-1 xadvance=24 page=0 chnl=15 +char id=205 x=225 y=76 width=10 height=39 xoffset=-5 yoffset=-1 xadvance=9 page=0 chnl=15 +char id=211 x=1 y=116 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=214 x=45 y=1 width=19 height=34 xoffset=0 yoffset=4 xadvance=23 page=0 chnl=15 +char id=218 x=1 y=156 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=220 x=65 y=1 width=19 height=34 xoffset=0 yoffset=4 xadvance=23 page=0 chnl=15 +char id=223 x=226 y=26 width=19 height=24 xoffset=0 yoffset=14 xadvance=23 page=0 chnl=15 +char id=224 x=1 y=196 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=225 x=21 y=36 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=226 x=21 y=76 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=228 x=61 y=116 width=19 height=34 xoffset=0 yoffset=4 xadvance=23 page=0 chnl=15 +char id=232 x=21 y=116 width=19 height=39 xoffset=0 yoffset=-1 xadvance=24 page=0 chnl=15 +char id=233 x=21 y=156 width=19 height=39 xoffset=0 yoffset=-1 xadvance=24 page=0 chnl=15 +char id=234 x=21 y=196 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=236 x=205 y=101 width=10 height=39 xoffset=-5 yoffset=-1 xadvance=9 page=0 chnl=15 +char id=237 x=236 y=86 width=10 height=39 xoffset=-5 yoffset=-1 xadvance=9 page=0 chnl=15 +char id=238 x=41 y=36 width=19 height=39 xoffset=-5 yoffset=-1 xadvance=9 page=0 chnl=15 +char id=242 x=41 y=76 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=243 x=41 y=116 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=244 x=41 y=156 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=246 x=61 y=151 width=19 height=34 xoffset=0 yoffset=4 xadvance=23 page=0 chnl=15 +char id=249 x=41 y=196 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=250 x=61 y=36 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=251 x=61 y=76 width=19 height=39 xoffset=0 yoffset=-1 xadvance=23 page=0 chnl=15 +char id=252 x=61 y=186 width=19 height=34 xoffset=0 yoffset=4 xadvance=23 page=0 chnl=15 diff --git a/assets/shaders/glsl/ui.vert b/assets/shaders/glsl/ui.vert new file mode 100644 index 0000000..805cb7c --- /dev/null +++ b/assets/shaders/glsl/ui.vert @@ -0,0 +1,24 @@ +#version 460 + +layout(set = 1, binding = 0) +uniform Parameters +{ + vec2 u_windowSize; +}; + +layout(location = 0) +in vec2 i_position; + +layout(location = 1) +in vec2 i_texCoord; + +layout(location = 0) +out vec2 o_texCoord; + +void main() +{ + vec2 relativePos = 2.0 * (i_position / u_windowSize) - vec2(1.0); + relativePos.y *= -1.0; + gl_Position = vec4(relativePos, 0.0, 1.0); + o_texCoord = i_texCoord; +} diff --git a/private/sdl_gpu_test/6_ui/app.cpp b/private/sdl_gpu_test/6_ui/app.cpp index f004031..9a8c620 100644 --- a/private/sdl_gpu_test/6_ui/app.cpp +++ b/private/sdl_gpu_test/6_ui/app.cpp @@ -8,7 +8,10 @@ #include #include "../sdlpp/keyboard.hpp" +#include "../util/bitmap.hpp" +#include "../util/font_map.hpp" #include "../util/mesh.hpp" +#include "../util/texture_atlas.hpp" namespace sdl_gpu_test { @@ -23,25 +26,17 @@ struct VertexShaderParameters glm::mat4 worldToView; glm::mat4 viewToClip; }; + +struct UIVertexShaderParameters +{ + glm::vec2 windowSize; +}; } void UIApp::init(const AppInitArgs& args) { Application::init(args); - // create shaders - const sdlpp::GPUShader vertexShader = loadShader("shaders/glsl/textured_3dtriangles_from_buffer.vert.spv", { - .format = sdlpp::GPUShaderFormat::SPIRV, - .stage = sdlpp::GPUShaderStage::VERTEX, - .numUniformBuffers = 1 - }); - const sdlpp::GPUShader fragmentShader = loadShader("shaders/glsl/color_from_texture.frag.spv", { - .format = sdlpp::GPUShaderFormat::SPIRV, - .stage = sdlpp::GPUShaderStage::FRAGMENT, - .numSamplers = 1, - .numUniformBuffers = 1 - }); - // create depth buffer mDepthBuffer.create(mDevice, { .format = sdlpp::GPUTextureFormat::D16_UNORM, @@ -51,55 +46,10 @@ void UIApp::init(const AppInitArgs& args) }); // create graphics pipeline - std::array colorTargetsDescs = { - sdlpp::GPUColorTargetDescription{ - .format = mDevice.getSwapchainTextureFormat(mWindow), - .blendState = { - .enableBlend = true, - .srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA, - .dstColorBlendfactor = sdlpp::GPUBlendFactor::ONE_MINUS_SRC_ALPHA, - .colorBlendOp = sdlpp::GPUBlendOp::ADD, - .srcAlphaBlendfactor = sdlpp::GPUBlendFactor::ONE, - .dstAlphaBlendfactor = sdlpp::GPUBlendFactor::ZERO, - .alphaBlendOp = sdlpp::GPUBlendOp::ADD - } - } - }; - std::array vertexBindings = { - sdlpp::GPUVertexBinding{ - .index = 0, - .pitch = sizeof(Vertex) - } - }; - std::array vertexAttributes = { - sdlpp::GPUVertexAttribute{ - .location = 0, - .bindingIndex = 0, - .format = sdlpp::GPUVertexElementFormat::FLOAT3, - .offset = offsetof(Vertex, pos) - }, - sdlpp::GPUVertexAttribute{ - .location = 1, - .bindingIndex = 0, - .format = sdlpp::GPUVertexElementFormat::FLOAT2, - .offset = offsetof(Vertex, texcoord) - } - }; - mMeshPipeline.create(mDevice, { - .vertexShader = vertexShader, - .fragmentShader = fragmentShader, - .vertexInputState = { - .vertexBindings = vertexBindings, - .vertexAttributes = vertexAttributes - }, - .rasterizerState = { - .cullMode = sdlpp::GPUCullMode::BACK - }, - .targetInfo = { - .colorTargetDescriptions = colorTargetsDescs, - .depthStencilFormat = sdlpp::GPUTextureFormat::D16_UNORM - } - }); + createMeshPipeline(); + + // create UI pipeline + createUIPipeline(); // load the mesh const Mesh mesh = loadMesh(mFileSystem.getPath("meshes/cube.obj")); @@ -110,7 +60,7 @@ void UIApp::init(const AppInitArgs& args) .usage = {.vertex = true}, .size = static_cast(mesh.vertices.size() * sizeof(Vertex)) }); - uploadVertexData(mVertexBuffer, std::span(mesh.vertices.begin(), mesh.vertices.end())); + uploadVertexData(mVertexBuffer, std::span(mesh.vertices)); // create texture and sampler sdlpp::GPUTextureCreateArgs textureArgs = { @@ -120,6 +70,57 @@ void UIApp::init(const AppInitArgs& args) mTexture = loadTexture("bitmaps/cube.png", textureArgs); mSampler.create(mDevice, {}); + const FontMap fontMap = loadFontMap(mFileSystem.getPath("fonts/symtext.fnt")); + const UVFontMap uvFontMap = makeUVFontMap({ + .original = &fontMap, + .textureWidth = 256, + .textureHeight = 256 + }); + + unsigned posX = 100; + const unsigned posY = 100; + for (const char chr : std::string_view("Dies ist ein Test-Text!")) + { + const UVFontMapEntry& entry = uvFontMap.entries[chr]; + const UIVertex topLeft = { + .pos = {posX + entry.xOffset, posY + entry.yOffset}, + .texcoord = {entry.uvX, entry.uvY} + }; + const UIVertex bottomRight = { + .pos = {topLeft.pos.x + static_cast(entry.width), topLeft.pos.y + static_cast(entry.height)}, + .texcoord = {entry.uvX + entry.uvWidth, entry.uvY + entry.uvHeight} + }; + const UIVertex bottomLeft = { + .pos = {topLeft.pos.x, bottomRight.pos.y}, + .texcoord = {topLeft.texcoord.x, bottomRight.texcoord.y} + }; + const UIVertex topRight = { + .pos = {bottomRight.pos.x, topLeft.pos.y}, + .texcoord = {bottomRight.texcoord.x, topLeft.texcoord.y} + }; + + mUIVertices.push_back(topLeft); + mUIVertices.push_back(bottomLeft); + mUIVertices.push_back(topRight); + mUIVertices.push_back(bottomRight); + mUIVertices.push_back(topRight); + mUIVertices.push_back(bottomLeft); + + posX += entry.xAdvance; + } + + // create UI vertex buffer + mUIVertexBuffer.create(mDevice, { + .usage = {.vertex = true}, + .size = static_cast(mUIVertices.size() * sizeof(UIVertex)) + }); + uploadVertexData(mUIVertexBuffer, std::span(mUIVertices)); + + // and UI texture + mUITexture = loadTexture("bitmaps/ui.png", textureArgs); + + mUISampler.create(mDevice, {}); + // open gamepad const std::vector gamepads = sdlpp::getGamepads(); if (!gamepads.empty()) @@ -187,7 +188,25 @@ void UIApp::update(const AppUpdateArgs& args) renderPass.end(); // render the "UI" - + if (!mUIVertices.empty()) + { + const UIVertexShaderParameters uiVertexShaderParameters = { + .windowSize = { + static_cast(swapchainWidth), static_cast(swapchainHeight) + } + }; + colorTargets[0].loadOp = sdlpp::GPULoadOp::LOAD; // don't clear again + renderPass = cmdBuffer.beginRenderPass({ + .colorTargetInfos = colorTargets + }); + cmdBuffer.pushFragmentUniformData(0, std::span(&WHITE, 1)); + cmdBuffer.pushVertexUniformData(0, std::span(&uiVertexShaderParameters, 1)); + renderPass.bindFragmentSampler({.texture = mUITexture, .sampler = mUISampler}); + renderPass.bindGraphicsPipeline(mUIPipeline); + renderPass.bindVertexBuffer({.buffer = mUIVertexBuffer}); + renderPass.drawPrimitives({.numVertices = static_cast(mUIVertices.size())}); + renderPass.end(); + } // finalize cmdBuffer.submit(); @@ -216,6 +235,132 @@ void UIApp::handleMouseMotionEvent(const sdlpp::MouseMotionEvent& event) } } +void UIApp::createMeshPipeline() +{ + // create shaders + const sdlpp::GPUShader vertexShader = loadShader("shaders/glsl/textured_3dtriangles_from_buffer.vert.spv", { + .format = sdlpp::GPUShaderFormat::SPIRV, + .stage = sdlpp::GPUShaderStage::VERTEX, + .numUniformBuffers = 1 + }); + const sdlpp::GPUShader fragmentShader = loadShader("shaders/glsl/color_from_texture.frag.spv", { + .format = sdlpp::GPUShaderFormat::SPIRV, + .stage = sdlpp::GPUShaderStage::FRAGMENT, + .numSamplers = 1, + .numUniformBuffers = 1 + }); + std::array colorTargetsDescs = { + sdlpp::GPUColorTargetDescription{ + .format = mDevice.getSwapchainTextureFormat(mWindow), + .blendState = { + .enableBlend = true, + .srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA, + .dstColorBlendfactor = sdlpp::GPUBlendFactor::ONE_MINUS_SRC_ALPHA, + .colorBlendOp = sdlpp::GPUBlendOp::ADD, + .srcAlphaBlendfactor = sdlpp::GPUBlendFactor::ONE, + .dstAlphaBlendfactor = sdlpp::GPUBlendFactor::ZERO, + .alphaBlendOp = sdlpp::GPUBlendOp::ADD + } + } + }; + std::array vertexBindings = { + sdlpp::GPUVertexBinding{ + .index = 0, + .pitch = sizeof(Vertex) + } + }; + std::array vertexAttributes = { + sdlpp::GPUVertexAttribute{ + .location = 0, + .bindingIndex = 0, + .format = sdlpp::GPUVertexElementFormat::FLOAT3, + .offset = offsetof(Vertex, pos) + }, + sdlpp::GPUVertexAttribute{ + .location = 1, + .bindingIndex = 0, + .format = sdlpp::GPUVertexElementFormat::FLOAT2, + .offset = offsetof(Vertex, texcoord) + } + }; + mMeshPipeline.create(mDevice, { + .vertexShader = vertexShader, + .fragmentShader = fragmentShader, + .vertexInputState = { + .vertexBindings = vertexBindings, + .vertexAttributes = vertexAttributes + }, + .rasterizerState = { + .cullMode = sdlpp::GPUCullMode::BACK + }, + .targetInfo = { + .colorTargetDescriptions = colorTargetsDescs, + .depthStencilFormat = sdlpp::GPUTextureFormat::D16_UNORM + } + }); +} + +void UIApp::createUIPipeline() +{ + // create shaders + const sdlpp::GPUShader vertexShader = loadShader("shaders/glsl/ui.vert.spv", { + .format = sdlpp::GPUShaderFormat::SPIRV, + .stage = sdlpp::GPUShaderStage::VERTEX, + .numUniformBuffers = 1 + }); + const sdlpp::GPUShader fragmentShader = loadShader("shaders/glsl/color_from_texture.frag.spv", { + .format = sdlpp::GPUShaderFormat::SPIRV, + .stage = sdlpp::GPUShaderStage::FRAGMENT, + .numSamplers = 1, + .numUniformBuffers = 1 + }); + std::array colorTargetsDescs = { + sdlpp::GPUColorTargetDescription{ + .format = mDevice.getSwapchainTextureFormat(mWindow), + .blendState = { + .enableBlend = true, + .srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA, + .dstColorBlendfactor = sdlpp::GPUBlendFactor::ONE_MINUS_SRC_ALPHA, + .colorBlendOp = sdlpp::GPUBlendOp::ADD, + .srcAlphaBlendfactor = sdlpp::GPUBlendFactor::ONE, + .dstAlphaBlendfactor = sdlpp::GPUBlendFactor::ZERO, + .alphaBlendOp = sdlpp::GPUBlendOp::ADD + } + } + }; + std::array vertexBindings = { + sdlpp::GPUVertexBinding{ + .index = 0, + .pitch = sizeof(UIVertex) + } + }; + std::array vertexAttributes = { + sdlpp::GPUVertexAttribute{ + .location = 0, + .bindingIndex = 0, + .format = sdlpp::GPUVertexElementFormat::FLOAT2, + .offset = offsetof(UIVertex, pos) + }, + sdlpp::GPUVertexAttribute{ + .location = 1, + .bindingIndex = 0, + .format = sdlpp::GPUVertexElementFormat::FLOAT2, + .offset = offsetof(UIVertex, texcoord) + } + }; + mUIPipeline.create(mDevice, { + .vertexShader = vertexShader, + .fragmentShader = fragmentShader, + .vertexInputState = { + .vertexBindings = vertexBindings, + .vertexAttributes = vertexAttributes + }, + .targetInfo = { + .colorTargetDescriptions = colorTargetsDescs + } + }); +} + void UIApp::processInput(const AppUpdateArgs& args) { const std::span keystates = sdlpp::getKeyboardState(); diff --git a/private/sdl_gpu_test/6_ui/app.hpp b/private/sdl_gpu_test/6_ui/app.hpp index bd6d85e..299d531 100644 --- a/private/sdl_gpu_test/6_ui/app.hpp +++ b/private/sdl_gpu_test/6_ui/app.hpp @@ -4,11 +4,19 @@ #if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_APP_HPP_INCLUDED) #define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_APP_HPP_INCLUDED 1 +#include + #include "../application.hpp" #include "../sdlpp/gamepad.hpp" namespace sdl_gpu_test { +struct UIVertex +{ + glm::vec2 pos; + glm::vec2 texcoord; +}; + class UIApp : public Application { private: @@ -17,6 +25,13 @@ private: sdlpp::GPUGraphicsPipeline mMeshPipeline; sdlpp::GPUTexture mTexture; sdlpp::GPUSampler mSampler; + + sdlpp::GPUBuffer mUIVertexBuffer; + sdlpp::GPUGraphicsPipeline mUIPipeline; + std::vector mUIVertices; + sdlpp::GPUTexture mUITexture; + sdlpp::GPUSampler mUISampler; + sdlpp::Gamepad mGamepad; Uint32 mNumVertices = 0; Uint32 mLastSwapchainWidth = 1280; @@ -29,6 +44,8 @@ public: void handleKeyboardEvent(const sdlpp::KeyboardEvent& event) override; void handleMouseMotionEvent(const sdlpp::MouseMotionEvent& event) override; private: + void createMeshPipeline(); + void createUIPipeline(); void processInput(const AppUpdateArgs& args); }; } // namespace sdl_gpu_test diff --git a/private/sdl_gpu_test/SModule b/private/sdl_gpu_test/SModule index ebc040d..5992680 100644 --- a/private/sdl_gpu_test/SModule +++ b/private/sdl_gpu_test/SModule @@ -6,6 +6,7 @@ src_files = Split(""" application.cpp util/bitmap.cpp + util/font_map.cpp util/mesh.cpp 0_clear_swapchain/app.cpp diff --git a/private/sdl_gpu_test/util/font_map.cpp b/private/sdl_gpu_test/util/font_map.cpp new file mode 100644 index 0000000..b9fa919 --- /dev/null +++ b/private/sdl_gpu_test/util/font_map.cpp @@ -0,0 +1,91 @@ + +#include "./font_map.hpp" + +#include + +namespace sdl_gpu_test +{ +FontMap loadFontMap(const mijin::PathReference& path) +{ + std::unique_ptr stream; + mijin::throwOnError(path.open(mijin::FileOpenMode::READ, stream)); + + auto parseNumber = [](std::string_view value, auto& outNumber) + { + if (!mijin::toNumber(value, outNumber)) + { + throw std::runtime_error("Invalid number."); + } + }; + + FontMap result; + std::string line; + while (!stream->isAtEnd()) + { + mijin::throwOnError(stream->readLine(line)); + const std::vector parts = mijin::split(line, " "); + if (parts.empty()) { + continue; + } + if (parts[0] == "common") + { + for (const std::string_view& part : std::span(parts).subspan<1>()) + { + const auto [name, value] = mijin::splitFixed<2>(part, "="); + if (name == "lineHeight") { parseNumber(value, result.lineHeight); } + else if (name == "base") { parseNumber(value, result.base); } + else if (name == "scaleW") { parseNumber(value, result.scaleW); } + else if (name == "scaleH") { parseNumber(value, result.scaleH); } + } + } + else if (parts[0] == "char") + { + FontMapEntry entry; + unsigned id = 0; + for (const std::string_view& part : std::span(parts).subspan<1>()) + { + const auto [name, value] = mijin::splitFixed<2>(part, "="); + if (name == "id") { parseNumber(value, id); } + else if (name == "x") { parseNumber(value, entry.x); } + else if (name == "y") { parseNumber(value, entry.y); } + else if (name == "width") { parseNumber(value, entry.width); } + else if (name == "height") { parseNumber(value, entry.height); } + else if (name == "xoffset") { parseNumber(value, entry.xOffset); } + else if (name == "yoffset") { parseNumber(value, entry.yOffset); } + else if (name == "xadvance") { parseNumber(value, entry.xAdvance); } + } + if (id > 0 && id < result.entries.size()) + { + result.entries[id] = entry; + } + } + } + return result; +} + +UVFontMap makeUVFontMap(const MakeUVFontMapArgs& args) +{ + UVFontMap result = { + .lineHeight = args.original->lineHeight, + .base = args.original->base, + .scaleW = args.original->scaleW, + .scaleH = args.original->scaleH + }; + for (std::size_t chr = 0; chr < result.entries.size(); ++chr) + { + const FontMapEntry& origEntry = args.original->entries[chr]; + result.entries[chr] = { + .uvX = static_cast(origEntry.x + args.textureOffsetX) / static_cast(args.textureWidth), + .uvY = static_cast(origEntry.y + args.textureOffsetX) / static_cast(args.textureHeight), + .uvWidth = static_cast(origEntry.width) / static_cast(args.textureWidth), + .uvHeight = static_cast(origEntry.height) / static_cast(args.textureHeight), + .width = origEntry.width, + .height = origEntry.height, + .xOffset = origEntry.xOffset, + .yOffset = origEntry.yOffset, + .xAdvance = origEntry.xAdvance + }; + } + return result; +} +} diff --git a/private/sdl_gpu_test/util/font_map.hpp b/private/sdl_gpu_test/util/font_map.hpp new file mode 100644 index 0000000..aa95120 --- /dev/null +++ b/private/sdl_gpu_test/util/font_map.hpp @@ -0,0 +1,67 @@ + +#pragma once + +#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_FONT_MAP_HPP_INCLUDED) +#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_FONT_MAP_HPP_INCLUDED 1 + +#include + +#include + +namespace sdl_gpu_test +{ +struct FontMapEntry +{ + unsigned x = 0; + unsigned y = 0; + unsigned width = 0; + unsigned height = 0; + int xOffset = 0; + int yOffset = 0; + unsigned xAdvance = 0; +}; + +template +struct BaseFontMap +{ + std::array entries; + unsigned lineHeight = 0; + unsigned base = 0; + unsigned scaleW = 0; + unsigned scaleH = 0; +}; + +using FontMap = BaseFontMap; + +struct UVFontMapEntry +{ + float uvX = 0.f; + float uvY = 0.f; + float uvWidth = 0.f; + float uvHeight = 0.f; + unsigned width = 0; + unsigned height = 0; + int xOffset = 0; + int yOffset = 0; + unsigned xAdvance = 0; +}; + +using UVFontMap = BaseFontMap; + +struct MakeUVFontMapArgs +{ + const FontMap* original; + unsigned textureWidth; + unsigned textureHeight; + unsigned textureOffsetX = 0; + unsigned textureOffsetY = 0; +}; + +[[nodiscard]] +FontMap loadFontMap(const mijin::PathReference& path); + +[[nodiscard]] +UVFontMap makeUVFontMap(const MakeUVFontMapArgs& args); +} // namespace sdl_gpu_test + +#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_FONT_MAP_HPP_INCLUDED) diff --git a/private/sdl_gpu_test/util/texture_atlas.hpp b/private/sdl_gpu_test/util/texture_atlas.hpp new file mode 100644 index 0000000..eaa963b --- /dev/null +++ b/private/sdl_gpu_test/util/texture_atlas.hpp @@ -0,0 +1,14 @@ + +#pragma once + +#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_TEXTURE_ATLAS_HPP_INCLUDED) +#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_TEXTURE_ATLAS_HPP_INCLUDED 1 + +#include + +namespace sdl_gpu_test +{ + +} // namespace sdl_gpu_test + +#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_UTIL_TEXTURE_ATLAS_HPP_INCLUDED)