From 5c192ffd2e4cefdb05e71cf4122e56a463af35f0 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 19 May 2024 14:20:27 -0500 Subject: [PATCH] text_editor: initial gap buffer implementation --- Makefile | 6 + dejavusansmono.data | Bin 18328 -> 18332 bytes dejavusansmono_mono.data | Bin 2968 -> 3996 bytes example/example.mk | 12 + font/font.hpp | 6 +- ter_u20n.data | Bin 0 -> 6044 bytes ter_u20n.hpp | 5 + text_editor/gap_buffer.cpp | 116 ++++++++++ text_editor/gap_buffer.hpp | 34 +++ text_editor/text_editor.cpp | 430 ++++++++++++++++++++++++++++++++++++ text_editor/text_editor.mk | 14 ++ tools/ttf_outline.cpp | 36 +-- 12 files changed, 639 insertions(+), 20 deletions(-) create mode 100644 ter_u20n.data create mode 100644 ter_u20n.hpp create mode 100644 text_editor/gap_buffer.cpp create mode 100644 text_editor/gap_buffer.hpp create mode 100644 text_editor/text_editor.cpp create mode 100644 text_editor/text_editor.mk diff --git a/Makefile b/Makefile index 015b086..46e6b6d 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,13 @@ geometry/%.hpp: geometry/%.obj PYTHONPATH=regs/gen python tools/obj_to_cpp.py $< > $@.tmp mv $@.tmp $@ +build-fonts: + ./tools/ttf_outline 20 7f 20 0 little /usr/share/fonts/dejavu/DejaVuSans.ttf dejavusansmono.data + ./tools/ttf_outline 20 7f 20 1 little /usr/share/fonts/dejavu/DejaVuSans.ttf dejavusansmono_mono.data + ./tools/ttf_outline 20 7f 20 1 little /usr/share/fonts/terminus/ter-u20n.otb ter_u20n.data + include example/example.mk +include text_editor/text_editor.mk include pokemon/pokemon.mk .PHONY: phony diff --git a/dejavusansmono.data b/dejavusansmono.data index d25d936fe167b833fecd675dccd3b99807d55e63..d644ae602b73ffad97fb0b5ccf5a06e1f09808d8 100644 GIT binary patch literal 18332 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 literal 18328 zcmcIr30zdw_dhJc2nq;fxFIMgq>>_0nhGM73zn(5l)04UMrLmDQ%p@#b1Bry4VToC zG|RR8yCm+YNNVm0f{>sNvdq8?Ff;de&b{w341>S_N8WU-`|dsO-t)cZ+;h)e-rxrS zqanp{9?(CeNPym9l(D3F_5eL#0@yCuRgeAJ(O3C=Y{#2JQcivxQ-UMFT*>?af6gyofbtq* z2}#ne1J+bw-N8!bUJD${nzmQLP^)?#waD{HUsUjZEp1y^ z*eXS=M_I<V}I=TVF8J4s_?SFbt`l@T$c1=c0*43dqzMKvdLnWMGffmgvPKK7HEZ00Z~rdA*#f`u zjqM#&p=sY%!*9-BlK>)*mumNRL;Rhqz`10H7QQXUrDrG$7w>I>zh?`{3NX5u^|#Mk zA>_9!pFUyQYX=a2c#d7nwFE8PK7wzWuy}y?GRn`-QEvZ`GA|gK^Juvy#EcJXDqrFq zn68n>-~XTRjR^@_2g62uVOOyQqS+LWfo00^=l%kLx`EH^VPR(c*vibm`L1r1DMa!= zzi*eSLld;_Y!!8^XfGT(kIxOt@qd{OU+n^DRSn<2VnU#19l*U2PRDdNcXT8F^XsL{ z2Et#-@%O+(%Dk@}|M-XS`y3QiY}Wsi#||)t^@oz)VE5Xu_sUPWA-#j1SMwtFYaME`C&JMH$F#?57aC~e9R)g@IN2)zXvwbKY2d4zkfCR zzs1_)4kD{;J7MDZU)o~E|BmM0TR8uIKZh@EF#gkyKw#Mb?_aCoJD$58<i}FC6f9kIvo9z#7tMYW$K1(PMbN}>wSy}2J z@;|Z#+8?@}))lO$_&X-kCi5SbpP^*|$vpo6`mu*%=@9X^Jxj}Cto-I89+uzD(4UQC z0dab4)QyQq!6nowaoTk$hOZ~p)*o11#JUJ+eEt*ueo*x*I)Tg{rkRcUYix!Oc5fej zT>fW$cnR0PJCX|7D+<1lvhId3xH}pUA7BCN3~=Bg=GNN|pH|ehZs5GW=xT(7`8@0Y z%VjA)puj$WH5d3J*Z>eS?>(F0ixu?%%=$miJ`bgH-)w_>ETfY&(ziQc!gUb%@vIYw z$n&Pn@TC>C^X_*5ZlZaK&R&4$*aXaYOM4QQg!Xrec(50F4`>O%$UCzfpRX$RKWRms z6@Q>n??>q0xPkUIehH9w0L23|XRYmu`=S2Slf-(+;p3mg0!Fh&05g>0%PZ>ls*S}r zqM*;oZO$-?^#=Gs$LHl+kI)nth*5u+*@kGuk7P4FVhUM6E5p);T{D&9%PZ<0Qnvr; z4XyF9Q&_z}v6k(FF@NKe`~Tq#C(Mq%t3N%R`N9X;x+7zhv#sF_$Y!d#+ z_ba0(iTVg98`>Je3=|%@{c*!R7Iz~TO7DCjP8n2BA*~WCYBv&-I2+)|Kq$b?4^den z{ICxGb4HXz8pH-y72Bnh+^;IsHRE4GD=GzcfOpe;!V6kMs@UIqvq{8syo6CNNjQQY zs^jm@^cRO|s#a%u@sy5T_u|d%mK9_V1K4_vmpZXm={e&uMO~tH73miEH?|4B;xyKX zr=0ODj0CN$bpNabeA!WWgRlC2nyE7Wabvi^A6Geos@_SW)D|>JL~yFQLSAG4a90e>=4_)tJnX4y}>hz6AAwn_A$Hs0|ZKb_Sd ziDwj>kc1EWkD=dFINexq3R)FcMnah69a$I+KjB#9e}UQ!JpaJ9;}4VcsxbzNy>V}2ojG!@Ssq8`*!8p)q3AuAP3MGALvr9zysnS3M2$o21Y^`3Zd%g;PMXrc}T-1p}_-MHFuI{f` zhiJq7Rb>C5!=?Glqz@_pdoo(uApV=}553vLDuFMvp7;Vn_CL~V;NtAH)xykH~UlZF{i>G)8J6NQZ-J+D_}ztfT@)};5q9` z>8-gg{LF$QhyHD zoNDKs!A%)reDA~sR2yk+mLsMe@D2jLVQe$zf6i=YU%2JjyiLGXU=dWWsJGz5x8Rrv zOvI}bb!TtKXAKV-V}xxW)&g`uZtp&<2T|B$hX3}Q#sNF$B= zd_Bckj<5bgo__{O<6$f!nr>p1((FnKHJl{;&x+ke+4b`I=bc|H+KeUge|L;OovPwb zJ2rm22+Mw=cHL6{vc-G;l6*+uyQ&w0R+L7Nz;8PPW@p)}7wJw6?fvm6^^ujAp1irv$A$cO=HsK3o=O>rXxpS@G~9>xBpV zaxaw7RKy>3a-y)WSL(RARrq`L4b1p&u?|m*Xi?wpP+F){_;SLBzrF`Z-N9dr_^U2q zwCr=5BI9>AeFJ9vp6nH=LfsyNbz+xE_*1m50n(=@vHqypxQn?`D3I~Jvu-y;{09{o zbI9^hcyLleJH#~?*WXJ&az6P05nq4Rdm+@YK`X#On|r*M$)x0c~@Eoh~wCEbZD^S^?koj!gk_f%YDG&A{0 z!h!Z*gzs`UyCLxe{(M7!xdNWg-vl_JaQ+pRH3C$2B$sNJXWnno{*&-=Q_44-9DlTF zOcgx5j`%H<#-A(rZ=y(+~f-jt|*MZM+H7E zt^lsv`L2fxm(L$#HG!fm>>qPft=`!Jejf0w*LeME@G4Qd{=^IWk3f(_;}z+|Lx^K< zR^%>n0$6?#6C{rR?A{&?J7%7T@O}5ouTQhbEh}Tn{I9Wkr;qO+na;SMBANt)E@<+0 zw1NTbBlpNh-{9|__I!otx%{oz4S&u&_cLb7-xrE6Vin>;$YHJafMnwY*1ET8fm^Gy znXYHfqVVaJ-U&sMb9H~T#R7K8j~;d@kDd1Cf?c!Z!sa%>hxgOV?k;xalCw_1rV=|s zih8^jIT377f+;Pa*`W+FvV_0FI0O(MujAPJHo*U~c!0=4MC;JfA6(jx|to!3N z$cSK{Ca@j=ZN-f+)qzQL2hH(A8Q$6{wSTAyl>kpZqc-V0pxxs+4gF6au{(1H+0)s= z1V-*xxR{^7{cyuwMDdvH@4K%6_eDzaSLwxh3x&F9e!?_L%~*;jUO`NBi^$O@B$Of# zGU--`+rK3bRp@_={ezZKjDP+wlFw-bt+lU}&v0*j>}ms;aHryWOz9L!|1Yry#}8n` zFw6aKr6x={e)e$zj_Kii^s;lQm}|pgIkzQ?;^W_j4ac(NfAofrzkN0yhm_hsJB8#C zH8avgf4mJ7d($f7KzyDf_y2=;>tTuGccd=>0w0dvR*rw6%KmZed6azV943J*K5%i1 zhGX?ZA)#o>Kl)=q$h5}4iFK9g|DC=*$wsREu`lt(b9;(Q5455h%GV#Tn{Zi|^`+}{5!^|rbO^#6 z;=}9L%dbphkyskZ+&c(ZXl@9dgOd(U>SAH8VWe-Hk$>pDf1$Ke%#{XH)^< zyB$e~Lll*F-?I+@|&&3VS0v5T9m7i&ch)9JSDZR8Zc3rd0 z(Y;byP^r$uw^(b78azq=i@%`gek?L)p@7I)=pa0V?ShD3bJCaL8lZ$Yeor<`@;@92 z%kj^p<)$l({7LLgeef7uL_SE=t|`ZF!WKV4|C#BM{vQ|Ox{P0_nHTIj z&$AG_9_=4(3;VmUq+0RYu!$RU#Q49!0v!qx;q#j~{WR-ZxxTPwFm}fl{)b{z*7$z3 zBk0R|wKIIts3-crW9i#nvu?xhG#u@A6_lQz;A}g5A8Y#u=sxoBJDuYM18$UGnTqo- z@brZHnVk?HZpKlnfF%DLUeo?|@0={s9&RrrhavvL(`oINtYE>2 z|7ol8i;ed3gSu_-*AzFD{69&Kzxk{$V(Z0@oA6`w8PHuy?rCtf={Ji^m@01JYP3GhkA04We?6__8?%=mC`ggEL#b^Kcf zj4b+Pc89KDwC!OWi6Gn32#N615@1Re6%^~=UMR8KO8=xAbGZF|9;^V5>>mj1-@zYG zqOI+pG&RefkAELy@9i0G*cZ`L4_oX1Bz!M@AK`yrYb#&meYDbl<4<@IXx7=z zmwr;C7TTHpFA0A9Rp5uPbc}&WHSt3YLFS9Fr^J=3SK%ikr@H?oL1bkUnt#rJo-Lil zs|$S3im6n(^eg=IN41MMUgPN#$^XKv{STdcHsP--XgaR4D@hjk{ALKZ$V0s=#@Yh^ zN#l=uqPykG@GLqAzlvowGULC)@ZKw4>oSD3`FHWX%h|H#1+?4ozP}68HPi>IY`u{_|ezxDc@&xd#9HB za%k59-`}TIY6xqq9G}+Rf-{5QEZ<*FLg9YmXC=rd`*$h6zc`36Idv633+~PG(GhGi z|7hRgvxbey+$Ip>L>wG|C1HQpv1#ng2X0_L`LYJzz1p6|EXvR40V&xA@rUnw9P=*h zd`zcrq5%G-2{Tpx*Ll6RY~!4=p&rnQ^={8n7d3CbgvKG%5Ukk$#J=lvj&Hi@^b)?z zSmWc_YvSn}s}Zq3;UC0|pp82euRoIh$H6{gVJh2-J9|s~zB{AEZvP&JV%SLdB4FZg z!tccEH%mRK^Mml8UBfSxXg1@f-V#6f6uUj$8^y293-y?!CVcS)z-IW26{Zdo{kPLC zu8EJAk4y6PKlA{%O=`^nZvWo0vbNHna^m0m3 z-sWa_J(YVWK6k0$)jj?H@caGzikN@X@Z?S8S+v6QnRn*m4>hyy#9y6VcVy8rUMrqY z(mzfgb5-|eIO#90Um~TSh~ZV(op`0_w2!KZFX7<_A9@pKJnZLl>Ti4SGYYik703G0 zCt17-`&aN~JQ<&EWrxs?@2k@HJeyC5f|yjJ>1-#u3bV!hi`Tw;Pk*Al+5f8WWc?ih zy0aJXyU)Zc`n&UJ-Ekdw?+)34V=cOmFBGBbI~UF%eQ{T z_pU4+mpy90$tL)W>z_ElG_6tVBYAEz9s-QaG%;_voWFq}E0$Hq=bccP#EbDC1^rVs zdE5P~^hL2F82u-atiN2g)ia)@2R1!$k5=Eo#*An2QFX0jfxk_R|EspbmF2{1C*|so zQ)um>o0po_K<4Aq0{;aA`F}b;e^skvyKKA1Gr{f5L3BBpEb!sA^ZLRc$UgrLHM=(h Y1vfmk*=+w>fo$!6wSxQ)rmgY+3r+PS-~a#s diff --git a/dejavusansmono_mono.data b/dejavusansmono_mono.data index 9dea48d39264508c0e2102b72665d68f6ffceec4..987a7f96a3b008dffc5708f3c4ee49a6530df224 100644 GIT binary patch literal 3996 zcmZve-*4O26~_-v_0mZs(M`6DYE;op(G@{cjD}E0sU3^kx`!aZh5~&EhIOE!A=%IX zQIP#$5?8u}hv;Em^6D%@^Do#au;pP$FDpRVgND31K+w=I5cgpiXc%Y}R5tg$lw>iA zNzl^g-1GaMOL>xr>UhK}L=H_5$4%oz#`_TBQg9D0j;~kg4H_ez1cXAxpE082WD}!T zq-8AQkR8UIh2B7Br-)8bfet{vCzJNDeieH1lKuqrh^As&dmw}SE&3TkC1N0#i}WK( zCH%=;E+fBD*#%f1po7x!UVdljV@l)ZQV9PtzvGCZB8CkSmrq=J4U(}~CcyGJLGME{ z*3;?h{fgct4gHf>TnF?H(eDsd@7c;2cz%L>4N)-LHf9^`vYP zI_ZQzDSH>|QZ~?&KF@Pg*VU(ZhHou@OfebL`MSWEO- zU|vqcX760WmyBU!)<$RdPnazEe&+oca@HzwuZ}>{%TLNm(2@RlUnc9gwvR1ge_GEJ3eu{Oe#}j(5#q*bnWj1n?xx9zjJ=i~&ac#0b61v(kJ2m3F zVX$oqJuI{T*1HjfyWQMYYCk(mS%bJdXT;#v{px9 z?3u1*c}Ao!aINLS;G5g(&0~6xJIXFAw3Vi*3!{Q{p?|3r+O(06In&T;Jag=SR55gM zzruGKTF7_4i_FTh8LZ5U=PiZvt#HTOc#?C#)EXzg)gji5s-?gQQ%#rr&aT34&V*(V z)Vs}4jf||qvZyZz%#PsZoS{)YKS}xUR7n-ojUtumr4p68<-FRVP%;Zmvht;@>QYxV zz(S)bW@&23O%?WRQCpnSR@CNBsH)OG_*FGjHrg(!hK%3v3^k;yVw|EJ^1Io19)V{B z^2u?ZwU#6+rs!y@!Tnlm$sbo&R9%c`B`>twBCT1PDJU)3ZMW?-v$8Xi#b>^IX{}q& zm-1I*{-Vd-a%n>li~KF$U2vULc≫NsIizcU^aqMc>uO1uq7Vf(@`0bEh#CJarRe~jayrgeV4|*~*43)zguyj8KOvMzT|B3jz|J*ydO~>G*x~`TQwHB~E91gb zsK*`2X{V`>YTjV8ftkAQR#HwA{%cWsI?z)!w=!0J2>$wEX4!p=@n|uNiH0{p-aZU*=1>Ho9J4T-~Ze|DwJ0{IvSj;%XBVBN9aH;b zbsVg-)H7{zDP!zbtntP5P}fp7*u+}e=mrMZqDl>1Wfrya4?fM#QRVug7E(718h?$V z{3%k8d0Iz_wga!>H}4m@a@W)HN@F`v8lJbh)tJB2(9&G_$Ewn}=dFj0b;&|`ut=9u;}+heF|* z-FdKE>RSBt+x7!5bF*@tQKbL9+_v7dBR`|g)FgjaZ-;N%&2=N1Ax6ahw%!ij5Z)C- z9uI8YUB4|Rg?AdKgKKz4-sy49idlGf)?K-tv$7a03dC}~&t3VtaqQ(X*lsFL2d^%& zoaHN*z){Wt;WxutUjGgFL7($s8Tcda?<1X{YUpnerrjqbKS zX2Ja-Tm{Se4(EY+t@UByU%rVz{QiLh8t?}PZwmj zrqY(m2*cRBmU6~QlAq*^`$}Sc%`k3Xdy(%&->e@S*jEi>r5SAx$|G>#>BVlpe6l2K zh2??1W#KGqg}wMC>twZ=;6kujj@WQLE1LR3f+I5@{y1CA5Bx>ubho~{Z4TPZ`+gfHoe&f%i7uAq}kfBqUnm;>e701TUebw2#N|0tZWKCh;t6f zuxrmrv$g@5-9X$xls@=Bhy+Z3Chw zt->L=hSA9tMJzuy@c3#r1+?_^4cJx)DmkTL(GNJ*{onS4S8>x58f3 z={Wgy(SROU0lHWK*9+gx{p&`b{9KohJ48o)+za$7s^yj5qiofKVR{E;wpV&z<%qIS zRr>5yxjuRij6n`^DpmV;49}xk*FqP3eIfLdBX7^P>aRbbwm$T;xwhv5bjJg9eVEE- z+v5S;sQ`b&0saQjtCptcdyrnoY&6dEa6pWBK<|%XuA1|+>4c9vMkyaR6kyBidRm*) zQ1uL|KG(RR0Dt@FkngOj8=*Nr9>A&LQD@0pdv}E2mN56t_dzVc-zjMW4S8`p|b4QgybqxTov5S{)X><(suZI*&R!8}1xJubQ7*Pr#fW zfo*dg`vY>`kDQzP!s}wxawd9nFK&$+!n15euS%--)pOoWQ$BwqGz49{*Zb0*?gO80 zKYi-s4kDK@VyN{r#$}(52jmy0b3WY}%yLUpPfudjG_o3Il5npz>-tFL%)B~8^-hEp zxW>D#e5TBM%ydzER`Ndc!XH{fj%hub1pY#|gg6nGg`O(LD|o|M7MtL|2bRvo1da&dc`uV>Tc#ZaU@x$Z9g*J*~6x$z~#G|l8AxnzVR zX7aw=ZTly*(_fHxDTIANPEyD;4+8~^^A6PI?vAO@tl!kI&cDqSU)jmRdCiC-~xNy z8aR;6>rCg?NtyL9p=m(Fay7{muF_8|n`PE|F1veuom<&!G&isF^jK z_O2WNKEtILWCivYFgaFWTIi0GaBnKK6XNE)9+FmEEa&G#l9$DDcKVWQ*kVN#HMiBy ztcX=DUAD(GAvGywSu4tGQo2H0m21*}aoSL^P=6~fROh5$xPvsK~0osYK{&QqRq^Gf~|x()pN zlL^XO5EAS*+JR>&Pk)Bg+aNEju!mo8@I(_^orhb2`VxQK0-XDnd;9m7_yJr$G`M6X zG@yNZV+BA{U-NZ^rLQnKSVB~O-{jUlr9aH=L&{$pw^x*1+pPUAUMt{BDaCK{QcS%e J1^#NO^*<`pp3?vT diff --git a/example/example.mk b/example/example.mk index 61b9cff..9877d0b 100644 --- a/example/example.mk +++ b/example/example.mk @@ -481,3 +481,15 @@ LFSR_OBJ = \ example/lfsr.elf: LDSCRIPT = $(LIB)/main.lds example/lfsr.elf: $(START_OBJ) $(LFSR_OBJ) + +TA_TRANSFER_PROFILE_OBJ = \ + example/ta_transfer_profile.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + holly/video_output.o \ + sh7091/serial.o + +example/ta_transfer_profile.elf: LDSCRIPT = $(LIB)/main.lds +example/ta_transfer_profile.elf: $(START_OBJ) $(TA_TRANSFER_PROFILE_OBJ) diff --git a/font/font.hpp b/font/font.hpp index 3f13133..4b18a14 100644 --- a/font/font.hpp +++ b/font/font.hpp @@ -30,14 +30,14 @@ static_assert((sizeof (glyph)) == ((sizeof (glyph_bitmap)) + (sizeof (glyph_metr struct font { uint32_t first_char_code; + uint32_t last_char_code; + int32_t glyph_height; // 26.6 fixed point uint16_t glyph_count; - uint16_t glyph_height; uint16_t texture_stride; uint16_t texture_width; uint16_t texture_height; - uint16_t _pad; uint32_t texture_size; uint32_t max_z_curve_ix; } __attribute__ ((packed)); -static_assert((sizeof (font)) == ((sizeof (uint32_t)) * 6)); +static_assert((sizeof (font)) == ((sizeof (uint32_t)) * 7)); diff --git a/ter_u20n.data b/ter_u20n.data new file mode 100644 index 0000000000000000000000000000000000000000..0e6957204c295263b8c1d078a1ee75ab51b3863a GIT binary patch literal 6044 zcmeH~&5j#I6opThi%i9fna;>aSs=S?0y4YcRTf4rMwT@T7KWu)Au<~lhGmefp{Fy7 zoG2(#o&e?_XnjE&3EEiDCW1BDhoQ_#3&O3m>tTx=zFPV*JLtbMP{wS@!7 zbgVC9lL%YC#4$r(lu(p@kl99~F~A#Zt`s@vD>>VDv17Nvt#vb+;LGAhy-I)8PvpVOXm-LrlYc;!-D zfwg&j+KXaQpcmd#x3# zv5&b?51{?hi_H-?LTc1~r~*UXYS5CSb-1dy%ybH>E!}SU*5r_FFeF>lZj2DZB)JcDYmFNFV0>_@L$O7tA8$ z{SW{C>ww`r&$Ak^?jP(dJ|5-%b}z2c>(-11}Z#g3NXXre>;9d*irce17i_rxBX+bH!HXgd4!OjXkH= zbuE-Gg#1qqZ|QCJd5Pl+ADvy>b_Y+{5~t~|z0B%#$DY-q;woAeV!x%^XgwjDbkTYO zUyj39$)+pUm%xSPjbX{&EwO*g6!VwuW&f1*D~_M%<#sUPuEhSlf1NFfl242A9JnhA zt;z)>Z{04g+~e@-*{I2Nd(Uow|DD@q>+Ge18L=x856@D5U1C)l|C@SC?2hUky{o{x J3cQI5`~$V^i9Y}U literal 0 HcmV?d00001 diff --git a/ter_u20n.hpp b/ter_u20n.hpp new file mode 100644 index 0000000..151c6b9 --- /dev/null +++ b/ter_u20n.hpp @@ -0,0 +1,5 @@ +#include + +extern uint32_t _binary_ter_u20n_data_start __asm("_binary_ter_u20n_data_start"); +extern uint32_t _binary_ter_u20n_data_end __asm("_binary_ter_u20n_data_end"); +extern uint32_t _binary_ter_u20n_data_size __asm("_binary_ter_u20n_data_size"); diff --git a/text_editor/gap_buffer.cpp b/text_editor/gap_buffer.cpp new file mode 100644 index 0000000..1994c5f --- /dev/null +++ b/text_editor/gap_buffer.cpp @@ -0,0 +1,116 @@ +#include "gap_buffer.hpp" + +#include "sh7091/serial.hpp" +/* + 2 3 4 5 6 7 + s e + [a] [ ] [b] [q] | [ ] [ ] [ ] [ ] + i ^ + */ + +void line_init_from_buf(struct gap_buffer& gb, + int32_t * offsets, + int32_t size) +{ + gb.line.offsets = offsets; + gb.line.size = size; + gb.line.length = 0; + + for (int32_t i = 0; i < gb.gap_start; i++) { + serial::integer(i); + if (gb.buf[i] == '\n') { + gb.line.offsets[gb.line.length++] = i; + } + } + + gb.line.gap = gb.line.length; + + serial::string("gbgapend\n"); + for (int32_t i = gb.gap_end; i < gb.size; i++) { + serial::integer(i); + if (gb.buf[i] == '\n') { + gb.line.offsets[gb.line.length++] = i; + } + } +} + +void gap_init_from_buf(struct gap_buffer& gb, + char_type * buf, + int32_t size, + int32_t length) +{ + gb.buf = buf; + gb.size = size; + + gb.gap_start = length; + gb.gap_end = size; +} + +/* +void gap_resize(struct gap_buffer& gb) +{ + for (int32_t i = (gb.size - 1); i >= gb.gap_end; i--) { + gb.buf[i + gb.size] = gb.buf[i]; + } + gb.gap_end += gb.size; + gb.size += gb.size; +} +*/ + +void gap_append(struct gap_buffer& gb, char_type c) +{ + if (gb.gap_start == gb.gap_end) { + return; + //gap_resize(gb); + } + + if (c == '\n') { + for (int32_t i = gb.line.length - 1; i >= gb.line.gap; i--) { + gb.line.offsets[i + 1] = gb.line.offsets[i]; + } + gb.line.offsets[gb.line.gap++] = gb.gap_start; + gb.line.length += 1; + } + gb.buf[gb.gap_start++] = c; +} + +void gap_pop(struct gap_buffer& gb) +{ + gb.gap_start--; +} + +/* + 0 1 2 3 4 5 6 7 + [a] [b] [ ] [ ] [ ] [ ] [q] [r] + ^ e + */ + +/* + */ + +void gap_cursor_pos(struct gap_buffer& gb, int32_t delta) +{ + if (delta > 0) { + if (gb.gap_end + delta >= gb.size) { + delta = gb.size - gb.gap_end; + } + for (int32_t i = 0; i < delta; i++) { + char_type c = gb.buf[gb.gap_end++]; + if (c == '\n') { + gb.line.offsets[gb.line.gap++] = gb.gap_start; + } + gb.buf[gb.gap_start++] = c; + } + } else { + if (gb.gap_start + delta < 0) { + delta = -gb.gap_start; + } + for (int32_t i = delta; i < 0; i++) { + char_type c = gb.buf[--gb.gap_start]; + gb.buf[--gb.gap_end] = c; + if (c == '\n') { + gb.line.offsets[--gb.line.gap] = gb.gap_end; + } + } + } +} diff --git a/text_editor/gap_buffer.hpp b/text_editor/gap_buffer.hpp new file mode 100644 index 0000000..5211ee8 --- /dev/null +++ b/text_editor/gap_buffer.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +typedef uint8_t char_type; + +struct line_metadata { + int32_t * offsets; + int32_t size; + int32_t length; + int32_t gap; +}; + +struct gap_buffer { + char_type * buf; + int32_t size; + int32_t gap_start; + int32_t gap_end; + struct line_metadata line; +}; + +void line_init_from_buf(struct gap_buffer& gb, + int32_t * offsets, + int32_t size); + +void gap_init_from_buf(struct gap_buffer& gb, + char_type * buf, + int32_t size, + int32_t length); + +void gap_resize(struct gap_buffer& gb); +void gap_append(struct gap_buffer& gb, char_type c); +void gap_pop(struct gap_buffer& gb); +void gap_cursor_pos(struct gap_buffer& gb, int32_t delta); diff --git a/text_editor/text_editor.cpp b/text_editor/text_editor.cpp new file mode 100644 index 0000000..4adeee1 --- /dev/null +++ b/text_editor/text_editor.cpp @@ -0,0 +1,430 @@ +#include +#include + +#include "align.hpp" +#include "holly/video_output.hpp" + +#include "holly/texture_memory_alloc.hpp" +#include "holly/holly.hpp" +#include "holly/core.hpp" +#include "holly/core_bits.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" +#include "holly/ta_parameter.hpp" +#include "holly/ta_global_parameter.hpp" +#include "holly/ta_vertex_parameter.hpp" +#include "holly/ta_bits.hpp" +#include "holly/isp_tsp.hpp" +#include "memorymap.hpp" +#include "holly/background.hpp" +#include "holly/region_array.hpp" +#include "twiddle.hpp" +#include "palette.hpp" + +#include "sh7091/serial.hpp" + +#include "maple/maple.hpp" +#include "maple/maple_impl.hpp" +#include "maple/maple_bus_bits.hpp" +#include "maple/maple_bus_commands.hpp" +#include "maple/maple_bus_ft0.hpp" + +#include "font/font.hpp" +#include "ter_u20n.hpp" + +#include "gap_buffer.hpp" + +struct vertex { + float x; + float y; + float u; + float v; +}; + +const struct vertex strip_vertices[4] = { + // [ position ] [ uv coordinates ] + { 0.f, 0.f, 0.f, 0.f, }, + { 1.f, 0.f, 1.f, 0.f, }, + { 1.f, 1.f, 1.f, 1.f, }, + { 0.f, 1.f, 0.f, 1.f, }, +}; +constexpr uint32_t strip_length = (sizeof (strip_vertices)) / (sizeof (struct vertex)); + +constexpr inline float float_26_6(int32_t n) +{ + float v = n >> 6; +//float d = n & 63; +//return v + (d / 64.f); + return v; +} + +void transform(ta_parameter_writer& parameter, + const uint32_t texture_width, uint32_t texture_height, + const glyph& glyph, + const float origin_x, + const float origin_y) +{ + const uint32_t parameter_control_word = para_control::para_type::sprite + | para_control::list_type::opaque + | obj_control::col_type::packed_color + | obj_control::texture + | obj_control::_16bit_uv; + + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater + | isp_tsp_instruction_word::culling_mode::no_culling; + + const uint32_t tsp_instruction_word = tsp_instruction_word::src_alpha_instr::src_alpha + | tsp_instruction_word::dst_alpha_instr::one + | tsp_instruction_word::fog_control::no_fog + | tsp_instruction_word::use_alpha + | tsp_instruction_word::texture_u_size::from_int(texture_width) + | tsp_instruction_word::texture_v_size::from_int(texture_height); + + const uint32_t texture_address = texture_memory_alloc::texture.start; + const uint32_t texture_control_word = texture_control_word::pixel_format::_4bpp_palette + | texture_control_word::scan_order::twiddled + | texture_control_word::texture_address(texture_address / 8); + + parameter.append() = + ta_global_parameter::polygon_type_0(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + texture_control_word, + 0, // data_size_for_sort_dma + 0 // next_address_for_sort_dma + ); + + struct vertex out[strip_length]; + for (uint32_t i = 0; i < strip_length; i++) { + float x = strip_vertices[i].x; + float y = strip_vertices[i].y; + + x *= glyph.bitmap.width; + y *= glyph.bitmap.height; + x += origin_x + float_26_6(glyph.metrics.horiBearingX); + y += origin_y - float_26_6(glyph.metrics.horiBearingY); + + float u = strip_vertices[i].u; + float v = strip_vertices[i].v; + u *= glyph.bitmap.width; + v *= glyph.bitmap.height; + u += glyph.bitmap.x; + v += glyph.bitmap.y; + u = u / static_cast(texture_width); + v = v / static_cast(texture_height); + + out[i].x = x; + out[i].y = y; + out[i].u = u; + out[i].v = v; + } + + const float z = 0.1f; + parameter.append() = + ta_vertex_parameter::sprite_type_1(para_control::para_type::vertex_parameter, + out[0].x, + out[0].y, + z, + out[1].x, + out[1].y, + z, + out[2].x, + out[2].y, + z, + out[3].x, + out[3].y, + uv_16bit(out[0].u, out[0].v), + uv_16bit(out[1].u, out[1].v), + uv_16bit(out[2].u, out[2].v) + ); +} + +void init_texture_memory(const struct opb_size& opb_size) +{ + region_array2(640 / 32, // width + 480 / 32, // height + opb_size + ); + background_parameter(0xff0000ff); +} + +void inflate_font(const uint32_t * src, + const uint32_t stride, + const uint32_t curve_end_ix) +{ + auto texture = reinterpret_cast(&texture_memory64[texture_memory_alloc::texture.start / 4]); + + twiddle::texture3<4, 1>(texture, reinterpret_cast(src), + stride, + curve_end_ix); +} + +uint32_t _command_buf[(1024 + 32) / 4]; +uint32_t _receive_buf[(1024 + 32) / 4]; + +struct button_state { + bool ra; + bool la; + bool da; + bool ua; + bool a; + bool b; + bool x; + bool y; + bool start; + + void reset() + { + ra = la = da = ua = 0; + a = b = x = y = 0; + start = 0; + } +}; + +void do_get_condition(uint32_t * command_buf, + uint32_t * receive_buf, + button_state& buttons) +{ + using command_type = get_condition; + using response_type = data_transfer; + + get_condition::data_fields data_fields = { + .function_type = std::byteswap(function_type::controller) + }; + + const uint32_t command_size = maple::init_host_command_all_ports(command_buf, receive_buf, + data_fields); + using host_response_type = struct maple::command_response; + auto host_response = reinterpret_cast(receive_buf); + + maple::dma_start(command_buf, command_size, + receive_buf, maple::sizeof_command(host_response)); + + buttons.reset(); + + for (uint8_t port = 0; port < 4; port++) { + auto& bus_data = host_response[port].bus_data; + if (bus_data.command_code != response_type::command_code) { + return; + } + auto& data_fields = bus_data.data_fields; + if ((data_fields.function_type & std::byteswap(function_type::controller)) == 0) { + return; + } + + buttons.ra |= ft0::data_transfer::digital_button::ra(data_fields.data.digital_button) == 0; + buttons.la |= ft0::data_transfer::digital_button::la(data_fields.data.digital_button) == 0; + buttons.da |= ft0::data_transfer::digital_button::da(data_fields.data.digital_button) == 0; + buttons.ua |= ft0::data_transfer::digital_button::ua(data_fields.data.digital_button) == 0; + + buttons.a |= ft0::data_transfer::digital_button::a(data_fields.data.digital_button) == 0; + buttons.b |= ft0::data_transfer::digital_button::b(data_fields.data.digital_button) == 0; + buttons.x |= ft0::data_transfer::digital_button::x(data_fields.data.digital_button) == 0; + buttons.y |= ft0::data_transfer::digital_button::y(data_fields.data.digital_button) == 0; + + buttons.start |= ft0::data_transfer::digital_button::start(data_fields.data.digital_button) == 0; + } +} + +uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4]; + +struct editor_state { + struct gap_buffer gb; +}; + +void render_gap_buffer(ta_parameter_writer& parameter, + const struct font * font, + const struct glyph * glyphs, + struct gap_buffer& gb) +{ + int32_t advance = 0; + int32_t cursor = 0; + for (int32_t i = 0; i < gb.size; i++) { + char_type c; + + if (i < gb.gap_start || i >= gb.gap_end) { + c = gb.buf[i]; + } else { + c = '_'; + } + if (i == gb.gap_start) + cursor = advance; + + uint32_t ix; + if (c >= font->first_char_code && c <= font->last_char_code) { + ix = c - font->first_char_code; + } else { + ix = '#' - font->first_char_code; + } + auto& glyph = glyphs[ix]; + + transform(parameter, + font->texture_width, + font->texture_height, + glyph, + 50.f + float_26_6(advance), // x + 100.f // y + ); + + advance += glyph.metrics.horiAdvance; + } + + for (int32_t i = 0; i < gb.line.length; i++) { + int32_t j = gb.line.offsets[i]; + + auto& glyph = glyphs['X' - font->first_char_code]; + transform(parameter, + font->texture_width, + font->texture_height, + glyph, + 50.f + 10.f * j, // x + 100.f - float_26_6(font->glyph_height) // y + ); + } + + auto& glyph = glyphs['^' - font->first_char_code]; + transform(parameter, + font->texture_width, font->texture_height, + glyph, + 50.f + float_26_6(cursor), // x + 100.f + float_26_6(font->glyph_height) // y + ); + + { + auto& glyph = glyphs['`' - font->first_char_code]; + int32_t j; + if (gb.line.gap < gb.line.length) { + j = gb.line.offsets[gb.line.gap]; + } else { + j = gb.size; + } + transform(parameter, + font->texture_width, font->texture_height, + glyph, + 50.f + 10.f * j, // x + 100.f + float_26_6(font->glyph_height) * 2 // y + ); + } + + int32_t h_advance = 0; + int32_t v_advance = 0; + for (int32_t i = 0; i < gb.size; i++) { + char_type c; + + if (i < gb.gap_start || i >= gb.gap_end) { + c = gb.buf[i]; + } else { + continue; + } + + uint32_t ix; + if (c >= font->first_char_code && c <= font->last_char_code) { + ix = c - font->first_char_code; + } else { + ix = '#' - font->first_char_code; + } + auto& glyph = glyphs[ix]; + + transform(parameter, + font->texture_width, + font->texture_height, + glyph, + 350.f + float_26_6(h_advance), // x + 100.f + float_26_6(v_advance) // y + ); + + if (c == '\n') { + h_advance = 0; + v_advance += font->glyph_height; + } else { + h_advance += glyph.metrics.horiAdvance; + } + } +} + +void update_state(button_state& prev, button_state& next, editor_state& state) +{ + if ((next.la == true) && (next.la != prev.la)) { + gap_cursor_pos(state.gb, -1); + } + if ((next.ra == true) && (next.ra != prev.ra)) { + gap_cursor_pos(state.gb, +1); + } +} + +void main() +{ + video_output::set_mode_vga(); + + auto font = reinterpret_cast(&_binary_ter_u20n_data_start); + auto glyphs = reinterpret_cast(&font[1]); + auto texture = reinterpret_cast(&glyphs[font->glyph_count]); + + inflate_font(texture, + font->texture_stride, + font->max_z_curve_ix); + palette_data<2>(); + + // The address of `ta_parameter_buf` must be a multiple of 32 bytes. + // This is mandatory for ch2-dma to the ta fifo polygon converter. + uint32_t * ta_parameter_buf = align_32byte(_ta_parameter_buf); + + constexpr uint32_t ta_alloc = ta_alloc_ctrl::pt_opb::no_list + | ta_alloc_ctrl::tm_opb::no_list + | ta_alloc_ctrl::t_opb::no_list + | ta_alloc_ctrl::om_opb::no_list + | ta_alloc_ctrl::o_opb::_16x4byte; + + constexpr struct opb_size opb_size = { .opaque = 16 * 4 + , .opaque_modifier = 0 + , .translucent = 0 + , .translucent_modifier = 0 + , .punch_through = 0 + }; + + holly.SOFTRESET = softreset::pipeline_soft_reset + | softreset::ta_soft_reset; + holly.SOFTRESET = 0; + + core_init(); + init_texture_memory(opb_size); + + uint32_t frame_ix = 0; + + uint32_t * command_buf = align_32byte(_command_buf); + uint32_t * receive_buf = align_32byte(_receive_buf); + struct button_state buttons[2] = { 0 }; + struct editor_state state = { 0 }; + // 01234567 + char_type buf[64] = "abqb\neggs1\nbarley"; + int32_t offsets[64]; + gap_init_from_buf(state.gb, buf, 24, 17); + line_init_from_buf(state.gb, offsets, 64); + gap_cursor_pos(state.gb, (-state.gb.gap_start) + 6); + gap_append(state.gb, '\n'); + + while (true) { + do_get_condition(command_buf, receive_buf, buttons[frame_ix & 1]); + update_state(buttons[(frame_ix + 1) & 1], buttons[frame_ix & 1], state); + + ta_polygon_converter_init(opb_size.total(), + ta_alloc, + 640 / 32, + 480 / 32); + + auto parameter = ta_parameter_writer(ta_parameter_buf); + render_gap_buffer(parameter, font, glyphs, state.gb); + parameter.append() = ta_global_parameter::end_of_list(para_control::para_type::end_of_list); + + ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset); + ta_wait_opaque_list(); + + core_start_render(frame_ix); + core_wait_end_of_render_video(); + + while (!spg_status::vsync(holly.SPG_STATUS)); + core_flip(frame_ix); + while (spg_status::vsync(holly.SPG_STATUS)); + + frame_ix = (frame_ix + 1) & 1; + } +} diff --git a/text_editor/text_editor.mk b/text_editor/text_editor.mk new file mode 100644 index 0000000..079daf5 --- /dev/null +++ b/text_editor/text_editor.mk @@ -0,0 +1,14 @@ +TEXT_EDITOR_OBJ = \ + text_editor/text_editor.o \ + text_editor/gap_buffer.o \ + holly/video_output.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + maple/maple.o \ + sh7091/serial.o \ + ter_u20n.data.o + +text_editor/text_editor.elf: LDSCRIPT = $(LIB)/main.lds +text_editor/text_editor.elf: $(START_OBJ) $(TEXT_EDITOR_OBJ) diff --git a/tools/ttf_outline.cpp b/tools/ttf_outline.cpp index ba5c042..70f569a 100644 --- a/tools/ttf_outline.cpp +++ b/tools/ttf_outline.cpp @@ -18,10 +18,11 @@ std::endian _target_endian; constexpr uint32_t max_texture_dim = 1024; constexpr uint32_t max_texture_size = max_texture_dim * max_texture_dim; -uint32_t byteswap(const uint32_t n) +template< class T > +constexpr T byteswap(const T n) { if (std::endian::native != _target_endian) { - return std::byteswap(n); + return std::byteswap(n); } else { return n; } @@ -128,15 +129,15 @@ load_outline_char(const FT_Face face, } glyph_bitmap& bitmap = glyph->bitmap; - bitmap.x = byteswap(rect.x); - bitmap.y = byteswap(rect.y); - bitmap.width = byteswap(rect.width); - bitmap.height = byteswap(rect.height); + bitmap.x = byteswap(rect.x); + bitmap.y = byteswap(rect.y); + bitmap.width = byteswap(rect.width); + bitmap.height = byteswap(rect.height); glyph_metrics& metrics = glyph->metrics; - metrics.horiBearingX = byteswap(face->glyph->metrics.horiBearingX); - metrics.horiBearingY = byteswap(face->glyph->metrics.horiBearingY); - metrics.horiAdvance = byteswap(face->glyph->metrics.horiAdvance); + metrics.horiBearingX = byteswap(face->glyph->metrics.horiBearingX); + metrics.horiBearingY = byteswap(face->glyph->metrics.horiBearingY); + metrics.horiAdvance = byteswap(face->glyph->metrics.horiAdvance); return 0; } @@ -286,14 +287,15 @@ int main(int argc, char *argv[]) } font font; - font.first_char_code = byteswap(start); - font.glyph_count = byteswap(num_glyphs); - font.glyph_height = byteswap(face->size->metrics.height); - font.texture_stride = byteswap(texture_stride); - font.texture_width = byteswap(window_curve_ix.window.width); - font.texture_height = byteswap(window_curve_ix.window.height); - font.texture_size = byteswap(texture_size); - font.max_z_curve_ix = byteswap(window_curve_ix.max_z_curve_ix); + font.first_char_code = byteswap(start); + font.last_char_code = byteswap(end); + font.glyph_height = byteswap(face->size->metrics.height); + font.glyph_count = byteswap(num_glyphs); + font.texture_stride = byteswap(texture_stride); + font.texture_width = byteswap(window_curve_ix.window.width); + font.texture_height = byteswap(window_curve_ix.window.height); + font.texture_size = byteswap(texture_size); + font.max_z_curve_ix = byteswap(window_curve_ix.max_z_curve_ix); std::cerr << "start: 0x" << std::hex << start << '\n'; std::cerr << "end: 0x" << std::hex << end << '\n';