From f2db0dc5e83ae3e2d43d4c7b63fac142a1a22561 Mon Sep 17 00:00:00 2001 From: Hoguchi-live Date: Sat, 7 Jan 2023 21:02:50 +0100 Subject: [PATCH] Large overhaul, added simple text --- .../index/bitmap.h.AD4FEEC482722464.idx | Bin 240 -> 1316 bytes .../clangd/index/main.c.4CB5CE34A69A03F5.idx | Bin 6478 -> 4260 bytes .../clangd/index/main.h.5E55335D654F222C.idx | Bin 3096 -> 2656 bytes .gitignore | 1 + Makefile | 4 +- res/CC.ttf | Bin 0 -> 32308 bytes res/shaders/glyph_vs.glsl | 2 +- run.sh | 2 +- src/danmaku/danmaku.cpp | 151 ------ src/danmaku/danmaku.h | 65 --- src/gfx/bitmap.c | 118 ++--- src/gfx/bitmap.h | 37 +- src/gfx/player.c | 9 +- src/gfx/player.h | 4 + src/gfx/renderer.c | 164 +++++++ src/gfx/renderer.h | 54 ++ src/main.c | 464 ++++++++---------- src/main.h | 45 +- src/{ => old}/csv/csv.cpp | 0 src/{ => old}/csv/csv.h | 0 src/{ => old}/csv/danmaku.csv | 0 src/{ => old}/csv/main | Bin "src/getChat/\\" => "src/old/getChat/\\" | 0 .../__pycache__/helper.cpython-310.pyc | Bin .../__pycache__/socketHelper.cpython-310.pyc | Bin .../__pycache__/wsInterface.cpython-310.pyc | Bin src/{ => old}/getChat/helper.py | 0 src/{ => old}/getChat/replay/data/danmaku.csv | 0 src/{ => old}/getChat/replay/data/res.text | 0 src/{ => old}/getChat/replay/replay.py | 0 .../__pycache__/csv_reader.cpython-310.pyc | Bin .../__pycache__/csv_socket.cpython-310.pyc | Bin .../getChat/replay/sockets/csv_reader.py | 0 .../getChat/replay/sockets/csv_server.py | 0 .../getChat/replay/sockets/csv_socket.py | 0 .../getChat/replay/sockets/data/danmaku.csv | 0 .../getChat/replay/sockets/data/res.text | 0 .../getChat/replay/sockets/py_server.py | 0 src/{ => old}/getChat/wsChat.py | 0 src/{ => old}/getChat/wsInterface.py | 0 src/{ => old}/overlay/danmaku.cpp | 0 src/{ => old}/overlay/danmaku.h | 0 src/{ => old}/overlay/overlay.cpp | 0 src/{ => old}/overlay/overlay.h | 0 44 files changed, 543 insertions(+), 577 deletions(-) create mode 100644 res/CC.ttf delete mode 100644 src/danmaku/danmaku.cpp delete mode 100644 src/danmaku/danmaku.h create mode 100644 src/gfx/renderer.c create mode 100644 src/gfx/renderer.h rename src/{ => old}/csv/csv.cpp (100%) rename src/{ => old}/csv/csv.h (100%) rename src/{ => old}/csv/danmaku.csv (100%) rename src/{ => old}/csv/main (100%) rename "src/getChat/\\" => "src/old/getChat/\\" (100%) rename src/{ => old}/getChat/__pycache__/helper.cpython-310.pyc (100%) rename src/{ => old}/getChat/__pycache__/socketHelper.cpython-310.pyc (100%) rename src/{ => old}/getChat/__pycache__/wsInterface.cpython-310.pyc (100%) rename src/{ => old}/getChat/helper.py (100%) rename src/{ => old}/getChat/replay/data/danmaku.csv (100%) rename src/{ => old}/getChat/replay/data/res.text (100%) rename src/{ => old}/getChat/replay/replay.py (100%) rename src/{ => old}/getChat/replay/sockets/__pycache__/csv_reader.cpython-310.pyc (100%) rename src/{ => old}/getChat/replay/sockets/__pycache__/csv_socket.cpython-310.pyc (100%) rename src/{ => old}/getChat/replay/sockets/csv_reader.py (100%) rename src/{ => old}/getChat/replay/sockets/csv_server.py (100%) rename src/{ => old}/getChat/replay/sockets/csv_socket.py (100%) rename src/{ => old}/getChat/replay/sockets/data/danmaku.csv (100%) rename src/{ => old}/getChat/replay/sockets/data/res.text (100%) rename src/{ => old}/getChat/replay/sockets/py_server.py (100%) rename src/{ => old}/getChat/wsChat.py (100%) rename src/{ => old}/getChat/wsInterface.py (100%) rename src/{ => old}/overlay/danmaku.cpp (100%) rename src/{ => old}/overlay/danmaku.h (100%) rename src/{ => old}/overlay/overlay.cpp (100%) rename src/{ => old}/overlay/overlay.h (100%) diff --git a/.cache/clangd/index/bitmap.h.AD4FEEC482722464.idx b/.cache/clangd/index/bitmap.h.AD4FEEC482722464.idx index b61cd9542985dcc90b7038df28ecc0304195a0af..e1499314b3a9b4a2a9c3b4c98d3b4a74fac0f80f 100644 GIT binary patch literal 1316 zcmYLJeM}Q)7=Nymi9}p*K}Vzml`k+NXEF=ll12 z)3PUN;N-5p^ac5&2cMmS?Y|Fwd1Rsc%!SJOxM-g`_8&yr8^gPCE3Lk8*Tk@gad4yq z%W`JvrU41J#uJ!Y*Va4PG07nf-MXx2nugqqr@Q9VMtci5SkRr#vfZX3chl18B_I7$ z7!d&pWnRUbWg4)7@e!EN>U(RdJHGoC2d@MyAO&R8Q2zdh_fMC4=DxwfjqacnR7^we zqka9um3sdz2Z&fc&yuH_#;A=4%O8Keys~6s-d)iQ$W?N4m|^ z@}FgxV~&JVhSX3t*aQJGWE`-$W^1I_GOL1MH`yoNh<$_&>Io*+5jH3%xUNOJ)2$0T z)9lPGxz%JxkeT1**Js~?YA}o5C>1Li>JUt_ARItVh{o1GqL&}HFaH2xMN(2FNhO30 zi75JDS+#blb7CLDT;i$dL&J9GP{s7-I5MAcUh06 UK~)}!+^J@|6v&*-NOb`CAJQ&Ao&W#< literal 240 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 literal 6478 zcmY*d2Ut|c6TjW}z`OGyy*CjA?r74hB1Q>^1`vq_lqy9HNclOv1=3w3W>2BELcDU6-(6rK4IT`|M$W7-EU`hW_EUFc6R+Go}QkXJl=PUB}uW7 zE5k@0kEe+K6IRAA5knsD9U4d~&YLrP#qIG5Pn=J|z3aRhoa*m3ZjLGHlK80a?W?o& zZ!#HsHmoA_z$BmRb3eZ#T(euJzqmDKT>tx%Jv|Tp{IzSAz0QF8L(4;+;wcs<+%K47lVDBo; z*M@l$+fV0qzJK!}WmV$j^*6oR+hxDM`=8C}nhtf_y}I|j`nUe|_2x&JORaHM(O;$c z-7XfjPlRz@>BOE}#eL(i_TCDc>$k1q(#5}tg{Ky3U;g>rop(-g#nW#n!T$MOq{lc$5@Sk7v)2T@E*nR7_yA=vy;7){$`eyAf(vLYd znRUOM9kX^zh}Cgc~|v8D%`T~ zZy#?b$?QG3L%uiUZ**)?siwj=?AMc6>i(k<{rsl->pTnpAWv`c+nrK}SmVS3wY%xd z>h~Wsd+ol|T zt9n(-psl(oC9P|{ectTmY0gI*4{fSyiJto9_lmY@o;6ZQoBHkU6VVsJk z!nE}kE4!UkZo$M88@}+O1;3{xB*%sip~#so=cOU%+SN(%%y>Le4k436=!v~$y!Chj zKIGXL0WnzNW45N(##2i1tPsmKg4#xCio>aJO`d>~9bq}H)F6(ZQWQ_|CL)$1Lb(V@ ziByh6QpU=Ruw1H79{cCHxHlBf9I*I;2ll*{d-Hg09H2z2)mIx}*~A_5qSabS zrf4{iFvufZu#d<;wr>`fb&Z3RND4?PP(c3s_EDmIg3KovEMuT?qA%IQ7D;GbT*^7lxzyQ#Yi9;QTTgi0D=jGZ_3LU*9+g|IL* zzZj6k04-wVlS>QkDSK-16wS{9WEP-U3E6NGeL^V09ghUv1n4%1o=%+mBo1knMWvMcPSg2uW`F` z!V=k(33M}o2s6^yJ`;Fgtd2Ck=004v&=PV92Q4L+a!{;7>_m3na&kFC(=k*% zuM(2g2*^>-U^d-#*Ww=SZf}&MM2_B$KG(EQm~lC4ZyGga3sBlR_~!LOV1}F^NA%G>mKu37!moT z?VJ03q<~{=J~1bsh+r6p{N1l_Ubqao|0yJ<&5_J>}ES_FZWG84=O}na(DLp4Ntp zPwU3MK?HY!JLAy_15@V~G}u`qjYH6C2s&d8lxP@Q4nrr5C;A<@_%T^&2b!M-w9){R zqbBm7uQ~e+<|7GFWRyHMgc5y#Dj%Rejtf!c@PI?hqDcfL+62f=Y#LCa9e_k)*@=yi z-v|{j7S}}e=byZ*ffT0#rBtB95FSULFAbZ$O9t(-jiWmrrjy310lKj`mmqW5T%aq2 zb3WmTbAu8U5A`LZsm(A z;)c}4C;NTL1UqXz-CCg>g1?3&dThx)> zX2@@bD%c=bt(T;lZml9BjCcnVCQG{{897Gb$ZeH?tOQ!vDEG{~o_E{ZUZNR}%8rJ3 zcxu$0D+S$e7o*`|elQb#c-N52+|1o(U~b{)`H8i8E%4lC<@VkR%}xiZ>1+^5G}7N3 z+3oL)=4SzmEWjxN*}x*3#okM$sbS4C9Fc@lK$Zf!*ZcPUF!(M7n!GDTzI7BhGGR-J zT(w;%V0(~thHlK+gN_V1p%`+ia23?7g5z249;nd+^)dEo9dy*Ru@sP~3PY+EDq#X8 zItHm@T-*w&RxaK`kXr~LK8k(4WCIqYhAu)*A6Wzzj+5{(ol6D{ z(1OJ~334Z)fW1!Vl370C$l^j`Y9TQT!4X3&Qr()(2w_5)IIP2`63_X zHBc%8Oajv_grXGa;SHsePo*3fu($%KRB&-6@TdfwBcKVYH99Sa0AY{ZweHnf$|0J*(&6WZ)DX_!#(`uY* z*)C&QvBSUHEaKG>V;M9ogXS!w6!N8PrTnSuWogHc`YuRSJyfV?GbWalK92nRoH-;# z5>mpP9i+&c^kxw5mXVrpgK$f%L^#?wV{gQrS2Q~8x2m320tEGdNyCKJ`{gsNyjCH? z8;Jgxg(kEM%8XK|<0y>^2(o}s!}0!$W#eq&k*3*bMmQPH9Lm2O>I~WNI=c=HH$&BC z$b{Ag>)rv$wt5M&kX{D1i2Ak+j5f-hx1BaSb^tLI5b6blF(%OQqgBZ6{-$X)RYsfc z&ZR_u)*&C&9g20P=;Z~ z7`jy;Qvs(L*#zV^0S&xzy6u(EWX~MB_-kbWPS=?Yw6eK)2awyro!+X6NPwFFkJ3ZmEL~b&%=RYeAO$ zrOR(KQTZ6THefTT(Q5;XN3IPR*UE;P@2{HeiX^&{uFTFhtg_y=HuemOh95!xBgh2Q ze#u9t^)G_l5n<#^$AS*sZ+G81s7@cAslYN7Fb(kG(C?r9`@@m*uCF;FW8Mpy@}Q@fH|8>@jqH9!~Tk*{fa?z$ZH z2mRk{&`kyC?mO}|OAk$UldQXi2#I48nRf4p+O>YCqz_3bev5!s5ir9R(29+Vfg_7+ zfL{#=V{t7oss;8KA4w^j^&#cUSR{V~L2e*4@fGq&pBj;2+oOyK5;=6W9{q4ng%rn< zv78u=BjY&e1LS{z%D8nDj$ZY#kWS5bkp-i4a)bYp{iRB$a0{J2_))I$qE*qnK(w* z_Ndcmq{dF!jwx7YUNs#Lc{q3jDM?aJ;$&m8ax#O?dUz~MEeb_<<)y2ST@SX z9fdHufskozqkU0v|3LCb|4&F;pdgU39lIH63$O}c?gzrr7Z2>IE62+%|7ppKN3-jo zVjcTJaMgH;IBv4bUPLH?{1V7Cznx0cQ+QyfGa}3v%x4a->jSy=vF{8T(QqapGudXj z`_ajZYfTOuLIgL`jp+&hIdt;DP_<6rI7;M0`i#NLL>r*)%j6o`0P|pGN$6P731`|u zbm3BnV)g*tx3!{mSt&7EF&wl+YY7J})mq9yvBt5SR&=@6at>$oRghC9 zd!be@WVmrGB8OK&eidZ4R5<#Agk64n?!kL=J2&h^4k;waLIORbj(m4@7a8Wn+_yy% z2B6vi9FIj(sGrx*Aw;;+-wm~md0qD69+Gen@()7B3-^LZ)$PBQ(=SHWq&3qD+~4rL zrgP(0Hzarn@`s=jD|i_4hgtlzq8TG$iDx`=Ie(~p%Jt)j@CNeVu#0(AV!W07CD;oQyyd*LG5^yoGi*^*fNL+6~M59Z7K%;)hza!8Iq0& z^91vlSR1w<`+AoCbM#a&`i_BB51%#4%02irAMyJLeVC(i_}bmB6uWjlDorB~f|#E~ zEi(Neh$H6%72S2k{G1+&gpnGCO{Wc`YZ%5KFX@$iG_kyg7&8Ew!F`~}0b~w~KiR6R z-#c_?Dl&B>nz5=+xd*4M>w5-}sq2;2GtI((+T}sZx__phBI52~2$>x(^^o*EsC(FJZjxt?=OWB|DgZsU>#B!nVi*5J bzYFLp>1$}KsH&+e$tx%;YHAtijMMucUH8Yy diff --git a/.cache/clangd/index/main.h.5E55335D654F222C.idx b/.cache/clangd/index/main.h.5E55335D654F222C.idx index 7bc68436dea47a121dc8080ecb476743c5047a0b..ef98969fe773b2037bf8c89c746f1d19f5409bbe 100644 GIT binary patch literal 2656 zcmYk72~<#Uy}%2nkCd1VS(@(NKjHrGQX;q7QqD3L;9S1aU!@0xoO< zK7Cj#QfS569;}boB2q0Vb-`941+ju6a)d4qrD_kYrONy6z?j~1_|D{?-~Hy!-1&vL zWqN%A7onvamhDJS&Prk;gskDukd?Wq+zg?ASR%CJ*x~r}t%H)eV}?A7xT*S*=3SfH zPxSWbGut9^-(0`#Xk*uQ7WzPQ3NRo?V#kI|{KSg%8$abt&TqL4-7B+YH`eym%YaF$TH2bJLip+j*D2w zM<;jw#ZQave>YlcTj0Lvhu)H#sjT|t4rQC7)yLmBcEM>RuD{;q1T(t0VY82a<&K<( zcJ0i8()99)xA#>CML74_wU?Y6jJjjjUb?P)Z=R7mem%XQcKcMlv;^(lpY{8ea|f^W zTGu|RI~_f7^K{Op$0tgJXJ796wnD=HFz1m#YJTC?*&v>x?X}B3e5>F4Cq8~>Og{5>~jdm9q5BVFD?%TIm!ak!_@*Q!vm%A$1*qdAYQdZ(zO`TFjRt4w{bByyst zc(Cx$zUOo7G})JGZYajXjQ3VP3R49og~X*bWOuqxS1Q>x<{8OZJzr)FFNn{mnp75? zo~wE?r}5z3gfYz?mzLW6`T2j9#6@ukq(&@aQF>HTvPryicHftc0Yk96Qv{3Zb zuc;47t&s^*oY|FYbxjOdLVZ+AVPn5~4SO4~z%Xh+!XY~){X`|1#wJ&UW zSy5f@5PBsz_FBU2G`riS{@SjND?>SNhHO3 z`>XCB=?dzzCzAGh{1~^YZ=|JS?e*Fr&C~voXOF^bQe;%O)OWhF{;2i2^~J+oP0wHSG){%(nU4qiq!@OluM09qi1h(~B+p{Ho`p3$905=XRAO8(utWfW)G0LM?b8|og&b&rQrY2R0%R-BT>W#WO*MrU z0^mpa+2LXWj~I=xhK8qas99NS~31 zykO<@B@49(bwV6VGZbbIK*VZ&nNs_Ql0t#-ou9x@j0^67_aW-(9}p>P0JFjsITTq~|M4J?9XN*FQS{%_`1HBl6L9RLre$6Q=+ z2fPn)^G2x{%WFIe`2nD?Q#j&+0e?G~V)LQSd1Wi2(?qLTqs{0e70e9)8w1e+`9v0r2K|^Krp|$`+;=*pQv)#oa#0 zLjg0d0?Bk1x_OAhGS}jFF?7nJsNuhnWfW3F2Mu2{4;S2Fu{CrUy7*+sdYp5dhpb44 zc#C*3;&3cxPW6jbzvMhP!Qab6N&>hs-Pnl3W-{7sR`DFGkgI7Z sH4PV-hAyU|n`tO94V_FwchgXIq)Zg~^LuqSxXy0wu2RVY4;Lr&f8Br3bN~PV literal 3096 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 XL#BOh!QnZ-Xj$7k%(Hd0u|od`ew8{t diff --git a/.gitignore b/.gitignore index 5f8f79c..6870d94 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ build/* assets/* bin/* +.cache/* # Prerequisites *.d diff --git a/Makefile b/Makefile index 886235d..9b449e2 100644 --- a/Makefile +++ b/Makefile @@ -15,10 +15,10 @@ DEPEXT := d OBJEXT := o #Flags, Libraries and Includes -CFLAGS := -Wall -pedantic +CFLAGS := -Wall -pedantic CFLAGS += -Ilib/cglm/include -Ilib/glad/include -Ilib/glfw/include -Ilib/stb CFLAGS += -Iinclude/ -I/usr/include/freetype2 -I/usr/include/stb -LDFLAGS := -lglfw -ldl -lmpv -lfreetype -lm +LDFLAGS := -lglfw -ldl -lmpv -lfreetype -lm INC := -I$(INCDIR) -I/usr/local/include INCDEP := -I$(INCDIR) diff --git a/res/CC.ttf b/res/CC.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a113b316877163f8d8b0c72083f3f8334d065221 GIT binary patch literal 32308 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 Characters, float window_width) -{ - - // activate corresponding render state - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - s.use(); - - glUniform3f(glGetUniformLocation(s.ID, "textColor"), color.x, color.y, color.z); - glActiveTexture(GL_TEXTURE0); - glBindVertexArray(VAO); - - Character ch; - - float xpos; - float ypos; - float w; - float h; - - // iterate through all characters - std::string::const_iterator c; - for (c = text.begin(); c != text.end(); c++) - { - ch = Characters[*c]; - - xpos = x + ch.Bearing.x * scale; - ypos = y - (ch.Size.y - ch.Bearing.y) * scale; - - w = ch.Size.x * scale; - h = ch.Size.y * scale; - // update VBO for each character - float vertices[6][4] = { - { xpos, ypos + h, 0.0f, 0.0f }, - { xpos, ypos, 0.0f, 1.0f }, - { xpos + w, ypos, 1.0f, 1.0f }, - - { xpos, ypos + h, 0.0f, 0.0f }, - { xpos + w, ypos, 1.0f, 1.0f }, - { xpos + w, ypos + h, 1.0f, 0.0f } - }; - // render glyph texture over quad - glBindTexture(GL_TEXTURE_2D, ch.TextureID); - // update content of VBO memory - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); - glBindBuffer(GL_ARRAY_BUFFER, 0); - // render quad - glDrawArrays(GL_TRIANGLES, 0, 6); - // now advance cursors for next glyph (note that advance is number of 1/64 pixels) - x += (ch.Advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64) - } - glBindVertexArray(0); - glBindTexture(GL_TEXTURE_2D, 0); - - return xpos; -} - - -//TODO: Status <-> - -/* - Sets nextRow to the index of the next free danmaku row and returns 1 if one is available, returns 0 otherwise. - */ -int getNextDanmakuRow(uint *ph_danmakuRows, int length, uint *nextRow) { - for(int row = 0; row < length; row++) { - if( (ph_danmakuRows)[row] ){ - *nextRow = row; - return 1; - } - } - return 0; -} - -/* - Flips the status of the danmaku row. -*/ -int updateDanmakuRow(uint *ph_danmakuRows, uint row) { - ph_danmakuRows[row] = !ph_danmakuRows[row]; - return 0; -} - -/* - Updates danmaku array according to the delta between last frame and current frame. -*/ -//int updateDanmakus(Render *r){ -// -// // Amount of pixels to translate the danmakus by -// float deltaPix = DANMAKU_SPEED*delta; -// // Last glyph x-position (last pixel on the string) -// float lastPix = 0.0f; -// -// // Keep track of danmaku index -// uint danmakuIndex = 0; -// -// for(Danmaku &danmaku : danmakus) { -// if(danmaku.isNew) { -// // Try to assign the new danmaku's row to a free slot -// if(getNextDanmakuRow(ph_danmakuRows, nb_danmakuRows, &(danmaku.row))){ -// // Compute the height for that row -// danmaku.ypos = (r->h - DANMAKU_MARGIN_TOP) - -// (danmaku.row + 1) * (DANMAKU_PADDING_V + GLYPH_SIZE); -// danmaku.xpos = r->w; -// // Set the slot to unavailable -// updateDanmakuRow(ph_danmakuRows, danmaku.row); -// danmaku.tailCheck = 0; -// } -// danmaku.isNew = 0; -// } -// else { -// // Translate danmaku -// danmaku.xpos -= deltaPix; -// } -// -// // Draw the danmaku and get tail position -// lastPix = RenderText(r, danmaku.text, danmaku.xpos, danmaku.ypos, 1.0f, glm::vec3(0.0, 0.26f, 0.0f)); -// if(lastPix + DANMAKU_PADDING_H < 0) { -// danmakus.erase(danmakus.begin() + danmakuIndex); -// } -// -// // Check if the tail of the danmaku is free (only check once) -// if(!danmaku.tailCheck && (r->w > lastPix + (float)DANMAKU_PADDING_H)) { -// // Free the row slot -// updateDanmakuRow(ph_danmakuRows, danmaku.row); -// danmaku.tailCheck = 1; -// } -// } -// danmakuIndex++; -// } -// return 1; -//} - - -//OverlayHandler() { -// init(); -//} -// -//int OverlayHandler::init() { -// glGenVertexArrays(1, &VAO); -// glGenBuffers(1, &VBO); -// glBindVertexArray(VAO); -// glBindBuffer(GL_ARRAY_BUFFER, VBO); -// glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW); -// glEnableVertexAttribArray(0); -// glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0); -// glBindBuffer(GL_ARRAY_BUFFER, 0); -// glBindVertexArray(0); -// -//} diff --git a/src/danmaku/danmaku.h b/src/danmaku/danmaku.h deleted file mode 100644 index 66b161c..0000000 --- a/src/danmaku/danmaku.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _DANMAKU_H_ -#define _DANMAKU_H_ - -#include -#include -#include -#include "stdlib.h" -#include "stdio.h" - -#include -#include FT_FREETYPE_H - -#define GLYPH_SIZE 36 -#define DANMAKU_MARGIN_TOP 50 -#define DANMAKU_MARGIN_BOT 50 -#define DANMAKU_PADDING_H 200 -#define DANMAKU_PADDING_V 20 -#define DANMAKU_SPEED_V 200.0f - -// Glyphs -typedef struct Character { - unsigned int TextureID; // ID handle of the glyph texture - glm::ivec2 Size; // Size of glyph - glm::ivec2 Bearing; // Offset from baseline to left/top of glyph - long int Advance; // Offset to advance to next glyph -} Character; - -// Danmaku -typedef struct Danmaku { - std::string text; - uint isActive; - float xpos; - float ypos; - uint isNew; - uint row; - uint tailCheck; -} Danmaku; - -//class OverlayHandler() { -// public: -// OverlayHandler(); -// -// float RenderText(Shader, std::string, float, float, float, glm::vec3, uint &, uint &, std::map&); -// -// int init(); -// -// private: -// unsigned int VAO, VBO; -// -// void makeBitmaps(std::map &); -// -// Shader *glyphShader = new Shader("shaders/glyph_vs.glsl", "shaders/glyph_fs.glsl"); -// -// -//} - - - - - -int getNextDanmakuRow(uint *, int, uint* ); -int updateDanmakuRow(uint *, uint); - -int updateDanmakus(Danmaku *, float); -#endif diff --git a/src/gfx/bitmap.c b/src/gfx/bitmap.c index 33ccdaf..f8daec5 100644 --- a/src/gfx/bitmap.c +++ b/src/gfx/bitmap.c @@ -1,58 +1,64 @@ #include "bitmap.h" -//void makeBitmaps(std::map& Characters){ -// ///////// FREETYPE2 INIT -// FT_Library ft; -// if (FT_Init_FreeType(&ft)){ -// std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl; -// exit(EXIT_FAILURE); -// } -// FT_Face face; -// if (FT_New_Face(ft, "/usr/share/fonts/TTF/DejaVuSans.ttf", 0, &face)){ -// std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl; -// exit(EXIT_FAILURE); -// } -// FT_Set_Pixel_Sizes(face, 0, GLYPH_SIZE); -// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction -// glEnable(GL_BLEND); -// -// -// for (unsigned char c = 0; c < 128; c++){ -// // load character glyph -// if (FT_Load_Char(face, c, FT_LOAD_RENDER)){ -// std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl; -// continue; -// } -// // generate texture -// unsigned int texture; -// glGenTextures(1, &texture); -// glBindTexture(GL_TEXTURE_2D, texture); -// glTexImage2D( -// GL_TEXTURE_2D, -// 0, -// GL_RED, -// face->glyph->bitmap.width, -// face->glyph->bitmap.rows, -// 0, -// GL_RED, -// GL_UNSIGNED_BYTE, -// face->glyph->bitmap.buffer -// ); -// // set texture options -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -// // now store character for later use -// Character character = { -// texture, -// glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows), -// glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top), -// face->glyph->advance.x -// }; -// Characters.insert(std::pair(c, character)); -// } -// /// Clear glyphs -// FT_Done_Face(face); -// FT_Done_FreeType(ft); -//} +CharacterAtlas* makeBitmaps(){ + /////// FREETYPE2 INIT + FT_Library ft; + if (FT_Init_FreeType(&ft)){ + printf("ERROR::FREETYPE: Could not init FreeType Library\n"); + exit(EXIT_FAILURE); + } + FT_Face face; + if (FT_New_Face(ft, "res/CC.ttf", 0, &face)){ + printf("ERROR::FREETYPE: Failed to load font\n"); + exit(EXIT_FAILURE); + } + FT_Set_Pixel_Sizes(face, 0, GLYPH_SIZE); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction + glEnable(GL_BLEND); + + CharacterAtlas *atlas = malloc(sizeof(CharacterAtlas)); + + for (unsigned char c = 0; c < 128; c++){ + // load character glyph + if (FT_Load_Char(face, c, FT_LOAD_RENDER)){ + printf("ERROR::FREETYTPE: Failed to load Glyph\n"); + continue; + } + // generate texture + unsigned int texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RED, + face->glyph->bitmap.width, + face->glyph->bitmap.rows, + 0, + GL_RED, + GL_UNSIGNED_BYTE, + face->glyph->bitmap.buffer + ); + // set texture options + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // now store character for later use + Character character = { + texture, + {face->glyph->bitmap.width, face->glyph->bitmap.rows}, + {face->glyph->bitmap_left, face->glyph->bitmap_top}, + face->glyph->advance.x + }; + atlas->map[c] = character; + atlas->hashmap[(int)c] = c; // trivial at this point + } + /// Clear glyphs + FT_Done_Face(face); + FT_Done_FreeType(ft); + + return atlas; +} + + diff --git a/src/gfx/bitmap.h b/src/gfx/bitmap.h index cf5372a..8b2f232 100644 --- a/src/gfx/bitmap.h +++ b/src/gfx/bitmap.h @@ -1,15 +1,40 @@ #ifndef _BITMAP_H_ #define _BITMAP_H_ +#include "gfx.h" + #include #include FT_FREETYPE_H -//typedef struct Character { -// unsigned int TextureID; // ID handle of the glyph texture -// glm::ivec2 Size; // Size of glyph -// glm::ivec2 Bearing; // Offset from baseline to left/top of glyph -// long int Advance; // Offset to advance to next glyph -//} Character; +#include "stdlib.h" +#include "stdio.h" + +#include "../util/ivec2.h" + +#define GLYPH_SIZE 36 +#define DANMAKU_MARGIN_TOP 50 +#define DANMAKU_MARGIN_BOT 50 +#define DANMAKU_PADDING_H 200 +#define DANMAKU_PADDING_V 20 +#define DANMAKU_SPEED_V 200.0f + +#define MAP_SIZE 128 + +// Glyphs +typedef struct Character { + unsigned int TextureID; // ID handle of the glyph texture + ivec2 Size; // Size of glyph + ivec2 Bearing; // Offset from baseline to left/top of glyph + long int Advance; // Offset to advance to next glyph +} Character; + +typedef struct CharacterAtlas { + Character map[MAP_SIZE]; + int size; + int hashmap[MAP_SIZE]; +} CharacterAtlas; + +CharacterAtlas *makeBitmaps(); #endif diff --git a/src/gfx/player.c b/src/gfx/player.c index a79d318..4ca553b 100644 --- a/src/gfx/player.c +++ b/src/gfx/player.c @@ -33,8 +33,6 @@ void player_init(struct Player *self) { mpv_set_wakeup_callback(self->handle, on_mpv_events, NULL); mpv_render_context_set_update_callback(self->ctx, on_mpv_render_update, NULL); - //const char *cmd[] = {"loadfile", argv[1], NULL}; - //mpv_command(mpv, cmd); mpv_set_option_string(self->handle, "loop", ""); mpv_set_option_string(self->handle, "gpu-api", "opengl"); mpv_set_option_string(self->handle, "hwdec", "auto"); @@ -65,7 +63,7 @@ static void *get_proc_address(void *ctx, const char *name) static void on_mpv_render_update(void *ctx) { // we set the wakeup flag here to enable the mpv_render_context_render path in the main loop. - //wakeup = 1; + wakeup = 1; } static void on_mpv_events(void *ctx) @@ -80,3 +78,8 @@ static inline void check_error(int status) exit(1); } } + +void player_loadfile(struct Player* self, const char *file){ + const char *cmd[] = {"loadfile", file, NULL}; + mpv_command(self->handle, cmd); +} diff --git a/src/gfx/player.h b/src/gfx/player.h index 339d25d..39ebee6 100644 --- a/src/gfx/player.h +++ b/src/gfx/player.h @@ -8,6 +8,8 @@ #include #include +extern int wakeup; + struct Player { mpv_handle *handle; mpv_render_context *ctx; @@ -17,4 +19,6 @@ struct Player* player_create(); void player_init(struct Player *self); void player_destroy(struct Player *self); +void player_loadfile(struct Player* self, const char *file); + #endif diff --git a/src/gfx/renderer.c b/src/gfx/renderer.c new file mode 100644 index 0000000..dbc7f8b --- /dev/null +++ b/src/gfx/renderer.c @@ -0,0 +1,164 @@ +#include "renderer.h" +#include "shader.h" +#include "vao.h" +#include "vbo.h" + +void _renderer_mpv(struct Renderer *self); +void _renderer_glyph(struct Renderer *self); + +float quadVertices[] = { + // positions // texCoords + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f , 0.0f, 0.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f +}; + +int fbo_width = 1920; +int fbo_height = 1080; + +struct Renderer* renderer_create() { + return malloc(sizeof(struct Renderer)); +} + +void renderer_init(struct Renderer *self) { + self->current_shader = SHADER_NONE; + + // Compile shaders + self->shaders[SHADER_MPV] = shader_create( + "res/shaders/screen_vs.glsl", "res/shaders/screen_fs.glsl", + 2, (struct VertexAttr[]){ + { .index = 0, .name = "pos" }, + { .index = 1, .name = "texcoord" } + }); + + self->shaders[SHADER_GLYPH] = shader_create( + "res/shaders/glyph_vs.glsl", "res/shaders/glyph_fs.glsl", + 2, (struct VertexAttr[]){ + { .index = 0, .name = "texcoord" } + }); + + // Define buffers + _renderer_mpv(self); + _renderer_glyph(self); + + // Create bitmaps + self->atlas = makeBitmaps(); +} + +void renderer_destroy(struct Renderer *self) { + for (size_t i = 0; i <= SHADERS_LAST; i++) { + shader_destroy(self->shaders[i]); + } + + vao_destroy(self->screenVAO); + vbo_destroy(self->screenVBO); + + free(self); +} + +/* + Setting up the glyph renderer (for text) +*/ +void _renderer_glyph(struct Renderer *self) { + self->glyphVAO = vao_create(); + self->glyphVBO = vbo_create(GL_ARRAY_BUFFER, true); + + vao_bind(self->glyphVAO); + vbo_bind(self->glyphVBO); + + vbo_buffer(self->glyphVBO, &quadVertices, 0, sizeof(float)*6*4); + vao_attr(self->glyphVAO, self->glyphVBO, 0, 4, GL_FLOAT, 4*sizeof(float), 0); +} + +/* + Setting up the mpv renderer +*/ +void _renderer_mpv(struct Renderer *self) { + + /* Screen VAO and VBO */ + self->screenVAO = vao_create(); + self->screenVBO = vbo_create(GL_ARRAY_BUFFER, false); + + vao_bind(self->screenVAO); + vbo_bind(self->screenVBO); + + vbo_buffer(self->screenVBO, &quadVertices, 0, sizeof(quadVertices)); + vao_attr(self->screenVAO, self->screenVBO, 0, 3, GL_FLOAT, 5*sizeof(float), 0); + vao_attr(self->screenVAO, self->screenVBO, 1, 2, GL_FLOAT, 5*sizeof(float), (3 * sizeof(float))); + + /* Framebuffer for Video */ + glGenFramebuffers(1, &(self->video_framebuffer)); + glBindFramebuffer(GL_FRAMEBUFFER, self->video_framebuffer); + + /* create a color attachment texture */ + glGenTextures(1, &(self->video_textureColorbuffer)); + glBindTexture(GL_TEXTURE_2D, self->video_textureColorbuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fbo_width, fbo_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->video_textureColorbuffer, 0); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + printf("ERROR::FRAMEBUFFER:: VIDEO Framebuffer #%d is not complete!\n", self->video_framebuffer); + self->mpv_fbo = (mpv_opengl_fbo){(int)(self->video_framebuffer), fbo_width, fbo_height, 0}; +} + +/* + Render text on the screen using the given Shader +*/ +float render_text(struct Renderer *self, const char* text, uint length, float x, float y, float scale, float color[3]) +{ + shader_bind(self->shaders[SHADER_GLYPH]); + glUniform3f(glGetUniformLocation((self->shaders[SHADER_GLYPH]).handle, "textColor"), color[0], color[1], color[2]); + glActiveTexture(GL_TEXTURE0); + vao_bind(self->glyphVAO); + + Character ch; + + float xpos; + float ypos; + float w; + float h; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // iterate through all characters + for (unsigned char c = 0; c < length; c++){ + ch = self->atlas->map[self->atlas->hashmap[(int)text[c]]]; + + xpos = x + ch.Bearing[0] * scale; + ypos = y - (ch.Size[1] - ch.Bearing[1]) * scale; + + w = ch.Size[0] * scale; + h = ch.Size[1] * scale; + // update VBO for each character + float vertices[6][4] = { + { xpos, ypos + h, 0.0f, 0.0f }, + { xpos, ypos, 0.0f, 1.0f }, + { xpos + w, ypos, 1.0f, 1.0f }, + + { xpos, ypos + h, 0.0f, 0.0f }, + { xpos + w, ypos, 1.0f, 1.0f }, + { xpos + w, ypos + h, 1.0f, 0.0f } + }; + // render glyph texture over quad + glBindTexture(GL_TEXTURE_2D, ch.TextureID); + // update content of VBO memory + vbo_bind(self->glyphVBO); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); + glBindBuffer(GL_ARRAY_BUFFER, 0); + // render quad + glDrawArrays(GL_TRIANGLES, 0, 6); + // now advance cursors for next glyph (note that advance is number of 1/64 pixels) + x += (ch.Advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64) + } + glBindVertexArray(0); + glBindTexture(GL_TEXTURE_2D, 0); + + return xpos; +} diff --git a/src/gfx/renderer.h b/src/gfx/renderer.h new file mode 100644 index 0000000..70e35f1 --- /dev/null +++ b/src/gfx/renderer.h @@ -0,0 +1,54 @@ +#ifndef _RENDERER_H_ +#define _RENDERER_H_ + +#include +#include "shader.h" +#include "vao.h" +#include "vbo.h" +#include "bitmap.h" + +#define SHADERS_LAST SHADER_BASIC_COLOR +enum ShaderType { + SHADER_NONE = 0, + SHADER_MPV, + SHADER_GLYPH, + SHADER_BASIC_COLOR, + SHADER_BASIC_TEXTURE +}; + + +struct Renderer{ + struct Shader shaders[SHADERS_LAST + 1]; + enum ShaderType current_shader; + struct Shader shader; + + + // TODO: all of these should be more generically defined + struct VBO screenVBO; + struct VAO screenVAO; + + unsigned int video_framebuffer; + unsigned int video_textureColorbuffer; + + unsigned int screen_framebuffer; + unsigned int screen_textureColorbuffer; + + unsigned int screen_rbo; + unsigned int video_rbo; + + mpv_opengl_fbo mpv_fbo; + mpv_render_param *params_fbo; + + struct VBO glyphVBO; + struct VAO glyphVAO; + + CharacterAtlas *atlas; +}; + +struct Renderer* renderer_create(); +void renderer_init(struct Renderer *self); +void renderer_destroy(struct Renderer *self); + +float render_text(struct Renderer *self, const char* text, uint length, float x, float y, float scale, float color[3]); + +#endif diff --git a/src/main.c b/src/main.c index a8345dc..2be1304 100644 --- a/src/main.c +++ b/src/main.c @@ -3,12 +3,214 @@ #include "gfx/vbo.h" #include "glad/glad.h" +static inline void check_error(int); + int main(int argc, char const *argv[]) { if (argc < 2){ //std::cout << "Usage: " << argv[0] << " videofilename" << std::endl; return -1; } + + ////////// GLFW INIT + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + ///////// Create window + if ((wwindow = glfwCreateWindow(window_width, window_height, "a-mpv", NULL, NULL)) == NULL){ + printf("ERROR::GLFW::Failed to create window\n"); + return -1; + } + glfwMakeContextCurrent(wwindow); + glfwSetFramebufferSizeCallback(wwindow, framebuffer_size_callback); + + ///////// Load GLAD + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){ + printf("ERROR::GLAD::Failed to initialize GLAD\n"); + return -1; + } + + //////////// Initializing placeholder for FT text glyphs + //std::map Characters; + //makeBitmaps(Characters); + + ///////// GL parameters + glEnable(GL_DEPTH); + glEnable(GL_MULTISAMPLE); + glfwWindowHint(GLFW_SAMPLES, 4); + + /* Glyph shenanigans + */ + + //mat4s transformation = glms_ortho(0.0f, (float)(window_width), 0.0f, (float)window_height, -100, 100); + + /* Setting up MPV player + The mpv and mpv_ctx variables are temporary + */ + player = player_create(); + player_init(player); + mpv = player->handle; + mpv_ctx = player->ctx; + + /* Setting the renderer + The mpv and mpv_ctx variables are temporary + */ + renderer = renderer_create(); + renderer_init(renderer); + + // this doesn't work when called inside the Renderer struct... + int flip_y = 1; + renderer->params_fbo = (mpv_render_param [3]){ + {MPV_RENDER_PARAM_OPENGL_FBO, &(renderer->mpv_fbo)}, + {MPV_RENDER_PARAM_FLIP_Y, &flip_y}, + {MPV_RENDER_PARAM_INVALID, NULL}}; + + /* + Start video playback + */ + const char filename[] = "https://stream.wotos.eu/snw_master.m3u8"; + player_loadfile(player, filename); + + const char *text = "I Joe"; + + while (!glfwWindowShouldClose(wwindow)) + { + fcount++; + float currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; + //if (fcount % 100 == 0){ + // std::cout << "FPS: " << 1 / deltaTime << "\n" << std::endl; + // } + processGLFWInput(wwindow, mpv); + // ----- + + if (wakeup) + { + if ((mpv_render_context_update(mpv_ctx) & MPV_RENDER_UPDATE_FRAME)) + { + mpv_render_context_render(mpv_ctx, renderer->params_fbo); // this "renders" to the video_framebuffer "linked by ID" in the params_fbo - BLOCKING + glViewport(0, 0, window_width, window_height); // fucky + } + } + //screenShader->use(); + shader_bind(renderer->shaders[SHADER_MPV]); + + vao_bind(renderer->screenVAO); + glBindTexture(GL_TEXTURE_2D, renderer->video_textureColorbuffer); // <-- SCREEN Colorbuffer IS THE TEXTURE + glDrawArrays(GL_TRIANGLES, 0, 6); + + // ----- + if (wakeup) + { + mpv_render_context_report_swap(mpv_ctx); + wakeup = 0; + } + + render_text(renderer, text, strlen(text), 0, 0, 0.001, (float [3]){0.0, 1.0, 0.0}); + + //glUniformMatrix4fv(glGetUniformLocation(renderer->shaders[SHADER_GLYPH].handle, "ransformation"), 1, GL_FALSE, (GLfloat *)&transformation.raw); + + //Distance during deltaTime for consistent translation + + //// Draw image + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + //imgShader->use(); + //glBindVertexArray(imgVBO); // <-- The SCREEN QUAD + //glBindTexture(GL_TEXTURE_2D, imgTex); // <-- SCREEN Colorbuffer IS THE TEXTURE + + //imgMatrix = glm::translate(imgMatrix, glm::vec3(0.5/deltaPix, 0.0f, 0.0f)); + //glUniformMatrix4fv(glGetUniformLocation(imgShader->ID, "transformation"), 1, GL_FALSE, glm::value_ptr(imgMatrix)); + + //glDrawArrays(GL_TRIANGLES, 0, 6); + + + // // Glyphs + //transformation = glm::translate(transformation, glm::vec3(deltaPix , 0.0f, 0.0f)); + + + /////////////////////////////////////////// SOCKET + + //recv_bytes = recv(sock, buffer, RECV_BUFFER_SIZE, 0); + //if(recv_bytes >= 1){ + // danmakus.push_back({buffer, 1, (float)window_width, 400.0f, 1, 0, 0}); + //} + //std::cout << danmakus.front().text << std::endl; + + /////////////////////////////////////////// Danmaku update + //updateDanmakus(r); + + //} + + glfwSwapBuffers(wwindow); + glfwPollEvents(); + usleep(16 * 1000); // we LIMIT the main render loop to 100FPS! If VSYSNC is enabled the limit is the VSYNC limit (~60fps) + } + renderer_destroy(renderer); + player_destroy(player); + mpv_render_context_free(mpv_ctx); + mpv_terminate_destroy(mpv); + glfwTerminate(); + + + + return 0; +} + +void processGLFWInput(GLFWwindow *window, mpv_handle *ctx) +{ + glfwSetInputMode(window, GLFW_STICKY_KEYS, GLFW_FALSE); + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { + glfwSetWindowShouldClose(window, true); + } + + if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { + const char *c[] = {"show-text", "lol", NULL}; + check_error(mpv_command(ctx, c)); + } + +} + +void framebuffer_size_callback(GLFWwindow *window, int width, int height) +{ + // we have to rescale the Texture and renderbuffer storage. + window_height = height; + window_width = width; + glBindTexture(GL_TEXTURE_2D, renderer->screen_textureColorbuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glBindRenderbuffer(GL_RENDERBUFFER, screen_rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, window_width, window_height); +} + +static inline void check_error(int status) +{ + if (status < 0) { + printf("mpv API error: %s\n", mpv_error_string(status)); + + //exit(1); + } +} +// +///** Returns true on success, or false if there was an error */ +//bool SetSocketBlockingEnabled(int fd, bool blocking) +//{ +// if (fd < 0) return false; +// +//#ifdef _WIN32 +// unsigned long mode = blocking ? 0 : 1; +// return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false; +//#else +// int flags = fcntl(fd, F_GETFL, 0); +// if (flags == -1) return false; +// flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); +// return (fcntl(fd, F_SETFL, flags) == 0) ? true : false; +//#endif + + + //////////// SOCKET SERVER //// create socket file descriptor //int server_fd; @@ -45,117 +247,9 @@ int main(int argc, char const *argv[]) // perror("listen failed"); // exit(EXIT_FAILURE); //} +//} - ////////// GLFW INIT - glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - - ///////// Create window - if ((wwindow = glfwCreateWindow(window_width, window_height, "a-mpv", NULL, NULL)) == NULL){ - printf("ERROR::GLFW::Failed to create window\n"); - return -1; - } - glfwMakeContextCurrent(wwindow); - glfwSetFramebufferSizeCallback(wwindow, framebuffer_size_callback); - - ///////// Load GLAD - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){ - printf("ERROR::GLAD::Failed to initialize GLAD\n"); - return -1; - } - - //////////// Initializing placeholder for FT text glyphs - //std::map Characters; - //makeBitmaps(Characters); - - ///////// GL parameters - glEnable(GL_DEPTH); - glEnable(GL_MULTISAMPLE); - glfwWindowHint(GLFW_SAMPLES, 4); - - ///////// MPV INIT - mpv = mpv_create(); - if (mpv_initialize(mpv) < MPV_ERROR_SUCCESS){ - printf("ERROR::MPV::Failed to initialize mpv\n"); - return -1; - } - - mpv_opengl_init_params opengl_init_params={get_proc_address, NULL}; - int adv = 1; // we will use the update callback - mpv_render_param render_param[] = { - {MPV_RENDER_PARAM_API_TYPE, (char *)(MPV_RENDER_API_TYPE_OPENGL)}, - {MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &opengl_init_params}, - {MPV_RENDER_PARAM_ADVANCED_CONTROL, &adv}, - {MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME, NULL}, - {MPV_RENDER_PARAM_INVALID, NULL}, - }; - - if (mpv_render_context_create(&mpv_ctx, mpv, render_param) < MPV_ERROR_SUCCESS){ - printf("ERROR::MPV::Failed to create MPV render context\n"); - return -1; - } - mpv_set_wakeup_callback(mpv, on_mpv_events, NULL); - mpv_render_context_set_update_callback(mpv_ctx, on_mpv_render_update, NULL); - - const char *cmd[] = {"loadfile", argv[1], NULL}; - mpv_command(mpv, cmd); - mpv_set_option_string(mpv, "loop", ""); - mpv_set_option_string(mpv, "gpu-api", "opengl"); - mpv_set_option_string(mpv, "hwdec", "auto"); - mpv_set_option_string(mpv, "vd-lavc-dr", "yes"); - //mpv_set_option_string(mpv, "terminal", "yes"); - // mpv_set_option_string(mpv, "video-timing-offset", "0"); // this need manual fps adjustment mpv_render_frame_info() - check_error(mpv_set_option_string(mpv, "input-default-bindings", "yes")); - mpv_set_option_string(mpv, "input-vo-keyboard", "yes"); - int val = 1; - check_error(mpv_set_option(mpv, "osc", MPV_FORMAT_FLAG, &val)); - - - - - struct Shader screenShader = shader_create( - "res/shaders/screen_vs.glsl", "res/shaders/screen_fs.glsl", - 2, (struct VertexAttr[]){ - { .index = 0, .name = "pos" }, - { .index = 1, .name = "texCoords"} - }); - - - //// TEST VAO REPLACE - - quadVAOTEST = vao_create(); - quadVBOTEST = vbo_create(GL_ARRAY_BUFFER, false); - - vao_bind(quadVAOTEST); - vbo_bind(quadVBOTEST); - - vbo_buffer(quadVBOTEST, &quadVertices, 0, sizeof(quadVertices)); - vao_attr(quadVAOTEST, quadVBOTEST, 0, 3, GL_FLOAT, 5*sizeof(float), 0); - vao_attr(quadVAOTEST, quadVBOTEST, 1, 2, GL_FLOAT, 5*sizeof(float), (3 * sizeof(float))); - - //Framebuffer for Video - glGenFramebuffers(1, &video_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, video_framebuffer); - - // create a color attachment texture - glGenTextures(1, &video_textureColorbuffer); - glBindTexture(GL_TEXTURE_2D, video_textureColorbuffer); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fbo_width, fbo_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, video_textureColorbuffer, 0); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - printf("ERROR::FRAMEBUFFER:: VIDEO Framebuffer #%d is not complete!\n", video_framebuffer); - mpv_opengl_fbo mpv_fbo = {(int)(video_framebuffer), fbo_width, fbo_height, 0}; - int flip_y = 1; - mpv_render_param params_fbo[] = { - {MPV_RENDER_PARAM_OPENGL_FBO, &mpv_fbo}, - {MPV_RENDER_PARAM_FLIP_Y, &flip_y}, - {MPV_RENDER_PARAM_INVALID, NULL}}; - +//// BUNCH OF CRAP ////////// IMAGE TEST //// Import image //int imgWidth, imgHeight, imgChan; @@ -265,153 +359,3 @@ int main(int argc, char const *argv[]) //////////////////////////////////////////////////////////////////////////////// - while (!glfwWindowShouldClose(wwindow)) - { - fcount++; - float currentFrame = glfwGetTime(); - deltaTime = currentFrame - lastFrame; - lastFrame = currentFrame; - //if (fcount % 100 == 0){ - // std::cout << "FPS: " << 1 / deltaTime << "\n" << std::endl; - // } - processGLFWInput(wwindow, mpv); - // ----- - - if (wakeup) - { - if ((mpv_render_context_update(mpv_ctx) & MPV_RENDER_UPDATE_FRAME)) - { - mpv_render_context_render(mpv_ctx, params_fbo); // this "renders" to the video_framebuffer "linked by ID" in the params_fbo - BLOCKING - glViewport(0, 0, window_width, window_height); // fucky - } - } - //screenShader->use(); - shader_bind(screenShader); - - //glBindVertexArray(quadVBO); // <-- The SCREEN QUAD - vao_bind(quadVAOTEST); - glBindTexture(GL_TEXTURE_2D, video_textureColorbuffer); // <-- SCREEN Colorbuffer IS THE TEXTURE - glDrawArrays(GL_TRIANGLES, 0, 6); - - // ----- - if (wakeup) - { - mpv_render_context_report_swap(mpv_ctx); - wakeup = 0; - } - - //Distance during deltaTime for consistent translation - - //// Draw image - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - //imgShader->use(); - //glBindVertexArray(imgVBO); // <-- The SCREEN QUAD - //glBindTexture(GL_TEXTURE_2D, imgTex); // <-- SCREEN Colorbuffer IS THE TEXTURE - - //imgMatrix = glm::translate(imgMatrix, glm::vec3(0.5/deltaPix, 0.0f, 0.0f)); - //glUniformMatrix4fv(glGetUniformLocation(imgShader->ID, "transformation"), 1, GL_FALSE, glm::value_ptr(imgMatrix)); - - //glDrawArrays(GL_TRIANGLES, 0, 6); - - - // // Glyphs - //transformation = glm::translate(transformation, glm::vec3(deltaPix , 0.0f, 0.0f)); - - //glyphShader->use(); - - //// TEMPORARY - //glUniformMatrix4fv(glGetUniformLocation(glyphShader->ID, "transformation"), 1, GL_FALSE, glm::value_ptr(transformation)); - - /////////////////////////////////////////// SOCKET - - //recv_bytes = recv(sock, buffer, RECV_BUFFER_SIZE, 0); - //if(recv_bytes >= 1){ - // danmakus.push_back({buffer, 1, (float)window_width, 400.0f, 1, 0, 0}); - //} - //std::cout << danmakus.front().text << std::endl; - - /////////////////////////////////////////// Danmaku update - //updateDanmakus(r); - - //} - - glfwSwapBuffers(wwindow); - glfwPollEvents(); - //usleep(10000); // we LIMIT the main render loop to 100FPS! If VSYSNC is enabled the limit is the VSYNC limit (~60fps) - } - mpv_render_context_free(mpv_ctx); - mpv_terminate_destroy(mpv); - glfwTerminate(); - - - - return 0; -} - -void processGLFWInput(GLFWwindow *window, mpv_handle *ctx) -{ - glfwSetInputMode(window, GLFW_STICKY_KEYS, GLFW_FALSE); - if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { - glfwSetWindowShouldClose(window, true); - } - - if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { - const char *c[] = {"show-text", "lol", NULL}; - check_error(mpv_command(ctx, c)); - } - -} - -// Returns the address of the specified function (name) for the given context (ctx) -static void *get_proc_address(void *ctx, const char *name) -{ - glfwGetCurrentContext(); - return (void *)(glfwGetProcAddress(name)); -} - -static void on_mpv_render_update(void *ctx) -{ - // we set the wakeup flag here to enable the mpv_render_context_render path in the main loop. - wakeup = 1; -} - -static void on_mpv_events(void *ctx) -{ - //std::cout << "INFO::" << __func__ << std::endl; -} - -void framebuffer_size_callback(GLFWwindow *window, int width, int height) -{ - // we have to rescale the Texture and renderbuffer storage. - window_height = height; - window_width = width; - glBindTexture(GL_TEXTURE_2D, screen_textureColorbuffer); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glBindRenderbuffer(GL_RENDERBUFFER, screen_rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, window_width, window_height); -} - -static inline void check_error(int status) -{ - if (status < 0) { - printf("mpv API error: %s\n", mpv_error_string(status)); - //exit(1); - } -} -// -///** Returns true on success, or false if there was an error */ -//bool SetSocketBlockingEnabled(int fd, bool blocking) -//{ -// if (fd < 0) return false; -// -//#ifdef _WIN32 -// unsigned long mode = blocking ? 0 : 1; -// return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false; -//#else -// int flags = fcntl(fd, F_GETFL, 0); -// if (flags == -1) return false; -// flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); -// return (fcntl(fd, F_SETFL, flags) == 0) ? true : false; -//#endif -//} diff --git a/src/main.h b/src/main.h index 5543252..7f61098 100644 --- a/src/main.h +++ b/src/main.h @@ -9,19 +9,13 @@ #include "gfx/vao.h" #include "gfx/vbo.h" +#include "gfx/player.h" +#include "gfx/renderer.h" -//#include "danmaku/danmaku.h" - -//#include #include #include "gfx/shader.h" #include "gfx/bitmap.h" -//#include "glm/glm.hpp" -//#include -//#include -//#include - //#include //#include //#include @@ -41,23 +35,16 @@ //#define STB_IMAGE_IMPLEMENTATION //#include + int main(int argc, char const *argv[]); -int window_width = 1366; -int window_height = 768; -int fbo_width = 1366; -int fbo_height = 768; +int window_width = 1920; +int window_height = 1080; GLFWwindow *wwindow = NULL; mpv_handle *mpv; mpv_render_context *mpv_ctx; -unsigned int video_framebuffer; -unsigned int video_textureColorbuffer; - -unsigned int screen_framebuffer; -unsigned int screen_textureColorbuffer; - unsigned int screen_rbo; unsigned int video_rbo; unsigned int quadVAO, quadVBO; @@ -66,11 +53,14 @@ unsigned int cubeVAO, cubeVBO; struct VAO quadVAOTEST; struct VBO quadVBOTEST; +struct Player *player; +struct Renderer *renderer; + float deltaTime, lastFrame; unsigned int fcount = 0; bool animation=true; -static void *get_proc_address(void *ctx, const char *name); +//static void *get_proc_address(void *ctx, const char *name); void processGLFWInput(GLFWwindow *window, mpv_handle *); void framebuffer_size_callback(GLFWwindow *window, int width, int height); @@ -84,22 +74,13 @@ float imgVertices[] = { 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f}; -float quadVertices[] = { - // positions // texCoords - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, - -1.0f, -1.0f, 0.0f , 0.0f, 0.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f}; +//static void on_mpv_render_update(void *ctx); +//static void on_mpv_events(void *ctx); +int wakeup = 0; +extern int wakeup; -static void on_mpv_render_update(void *ctx); -static void on_mpv_events(void *ctx); -unsigned int wakeup = 0; - -static inline void check_error(int); bool SetSocketBlockingEnabled(int fd, bool blocking); diff --git a/src/csv/csv.cpp b/src/old/csv/csv.cpp similarity index 100% rename from src/csv/csv.cpp rename to src/old/csv/csv.cpp diff --git a/src/csv/csv.h b/src/old/csv/csv.h similarity index 100% rename from src/csv/csv.h rename to src/old/csv/csv.h diff --git a/src/csv/danmaku.csv b/src/old/csv/danmaku.csv similarity index 100% rename from src/csv/danmaku.csv rename to src/old/csv/danmaku.csv diff --git a/src/csv/main b/src/old/csv/main similarity index 100% rename from src/csv/main rename to src/old/csv/main diff --git "a/src/getChat/\\" "b/src/old/getChat/\\" similarity index 100% rename from "src/getChat/\\" rename to "src/old/getChat/\\" diff --git a/src/getChat/__pycache__/helper.cpython-310.pyc b/src/old/getChat/__pycache__/helper.cpython-310.pyc similarity index 100% rename from src/getChat/__pycache__/helper.cpython-310.pyc rename to src/old/getChat/__pycache__/helper.cpython-310.pyc diff --git a/src/getChat/__pycache__/socketHelper.cpython-310.pyc b/src/old/getChat/__pycache__/socketHelper.cpython-310.pyc similarity index 100% rename from src/getChat/__pycache__/socketHelper.cpython-310.pyc rename to src/old/getChat/__pycache__/socketHelper.cpython-310.pyc diff --git a/src/getChat/__pycache__/wsInterface.cpython-310.pyc b/src/old/getChat/__pycache__/wsInterface.cpython-310.pyc similarity index 100% rename from src/getChat/__pycache__/wsInterface.cpython-310.pyc rename to src/old/getChat/__pycache__/wsInterface.cpython-310.pyc diff --git a/src/getChat/helper.py b/src/old/getChat/helper.py similarity index 100% rename from src/getChat/helper.py rename to src/old/getChat/helper.py diff --git a/src/getChat/replay/data/danmaku.csv b/src/old/getChat/replay/data/danmaku.csv similarity index 100% rename from src/getChat/replay/data/danmaku.csv rename to src/old/getChat/replay/data/danmaku.csv diff --git a/src/getChat/replay/data/res.text b/src/old/getChat/replay/data/res.text similarity index 100% rename from src/getChat/replay/data/res.text rename to src/old/getChat/replay/data/res.text diff --git a/src/getChat/replay/replay.py b/src/old/getChat/replay/replay.py similarity index 100% rename from src/getChat/replay/replay.py rename to src/old/getChat/replay/replay.py diff --git a/src/getChat/replay/sockets/__pycache__/csv_reader.cpython-310.pyc b/src/old/getChat/replay/sockets/__pycache__/csv_reader.cpython-310.pyc similarity index 100% rename from src/getChat/replay/sockets/__pycache__/csv_reader.cpython-310.pyc rename to src/old/getChat/replay/sockets/__pycache__/csv_reader.cpython-310.pyc diff --git a/src/getChat/replay/sockets/__pycache__/csv_socket.cpython-310.pyc b/src/old/getChat/replay/sockets/__pycache__/csv_socket.cpython-310.pyc similarity index 100% rename from src/getChat/replay/sockets/__pycache__/csv_socket.cpython-310.pyc rename to src/old/getChat/replay/sockets/__pycache__/csv_socket.cpython-310.pyc diff --git a/src/getChat/replay/sockets/csv_reader.py b/src/old/getChat/replay/sockets/csv_reader.py similarity index 100% rename from src/getChat/replay/sockets/csv_reader.py rename to src/old/getChat/replay/sockets/csv_reader.py diff --git a/src/getChat/replay/sockets/csv_server.py b/src/old/getChat/replay/sockets/csv_server.py similarity index 100% rename from src/getChat/replay/sockets/csv_server.py rename to src/old/getChat/replay/sockets/csv_server.py diff --git a/src/getChat/replay/sockets/csv_socket.py b/src/old/getChat/replay/sockets/csv_socket.py similarity index 100% rename from src/getChat/replay/sockets/csv_socket.py rename to src/old/getChat/replay/sockets/csv_socket.py diff --git a/src/getChat/replay/sockets/data/danmaku.csv b/src/old/getChat/replay/sockets/data/danmaku.csv similarity index 100% rename from src/getChat/replay/sockets/data/danmaku.csv rename to src/old/getChat/replay/sockets/data/danmaku.csv diff --git a/src/getChat/replay/sockets/data/res.text b/src/old/getChat/replay/sockets/data/res.text similarity index 100% rename from src/getChat/replay/sockets/data/res.text rename to src/old/getChat/replay/sockets/data/res.text diff --git a/src/getChat/replay/sockets/py_server.py b/src/old/getChat/replay/sockets/py_server.py similarity index 100% rename from src/getChat/replay/sockets/py_server.py rename to src/old/getChat/replay/sockets/py_server.py diff --git a/src/getChat/wsChat.py b/src/old/getChat/wsChat.py similarity index 100% rename from src/getChat/wsChat.py rename to src/old/getChat/wsChat.py diff --git a/src/getChat/wsInterface.py b/src/old/getChat/wsInterface.py similarity index 100% rename from src/getChat/wsInterface.py rename to src/old/getChat/wsInterface.py diff --git a/src/overlay/danmaku.cpp b/src/old/overlay/danmaku.cpp similarity index 100% rename from src/overlay/danmaku.cpp rename to src/old/overlay/danmaku.cpp diff --git a/src/overlay/danmaku.h b/src/old/overlay/danmaku.h similarity index 100% rename from src/overlay/danmaku.h rename to src/old/overlay/danmaku.h diff --git a/src/overlay/overlay.cpp b/src/old/overlay/overlay.cpp similarity index 100% rename from src/overlay/overlay.cpp rename to src/old/overlay/overlay.cpp diff --git a/src/overlay/overlay.h b/src/old/overlay/overlay.h similarity index 100% rename from src/overlay/overlay.h rename to src/old/overlay/overlay.h