From 118e832a21510c7f730bea2efc19ee59062fa186 Mon Sep 17 00:00:00 2001 From: Julia <145168563+julia-aph@users.noreply.github.com> Date: Thu, 2 May 2024 17:17:37 -0500 Subject: [PATCH] fjc f --- build.py | 2 +- hi.exe | Bin 65675 -> 65720 bytes source/fumoengine/fumoengine.c | 40 ++----- source/fumoengine/fumoengine.h | 23 ++++ source/fumoengine/include/event.c | 2 +- source/fumoengine/include/ringbuffer.h | 7 ++ source/fumoengine/input/ctrl.c | 50 +++++---- source/fumoengine/input/ctrl.h | 54 ++------- source/fumoengine/input/input.c | 43 ++++---- source/fumoengine/input/input.h | 34 +++--- source/fumoengine/input/platforms/platform.h | 2 +- source/fumoengine/input/platforms/win.c | 50 +++++---- source/fumotris.c | 43 -------- source/fumotris/fumotris.c | 110 +++++++++++++++++++ test.exe | Bin 84906 -> 85504 bytes 15 files changed, 253 insertions(+), 207 deletions(-) create mode 100644 source/fumoengine/fumoengine.h delete mode 100644 source/fumotris.c create mode 100644 source/fumotris/fumotris.c diff --git a/build.py b/build.py index 546fe20..23b9c28 100644 --- a/build.py +++ b/build.py @@ -88,7 +88,7 @@ def build(source_path, obj_path, out_path, recompile = False): os.system(f"gcc -c {path} -I {' -I '.join(subdirs)} -o {obj_path}\\{name}.o -pthread -Wall -std=c17 -pedantic") write_checksum_file(checksums_now) - print(os.system(f"gcc {obj_path}\\*.o -o {out_path} -pthread -Wall -std=c17 -pedantic")) + print(os.system(f"gcc {obj_path}\\*.o -o {out_path} -pthread -Wall -std=c17 -pedantic -g")) build(sys.argv[1], sys.argv[2], sys.argv[3], True) \ No newline at end of file diff --git a/hi.exe b/hi.exe index 0799adada267a0015f48dc8b384e328022597846..c6fb070c202a361cbad2f78d6622789f75354c02 100644 GIT binary patch delta 12449 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 qywb(Xb51EqcU)^ zwK5&kT-#nKreaoTCY0q;Yh{`)X0?>NMQycMw*0@p`1N4GWVOvili3S6`oNTG&~Ca*x!>>!l%*gEvc?rCXYAH+>o~(v`v3`LJe* zG1j>heCJm~8IwKHdnYsIiF8{!KTzd|b@?F+FAIv7Ugm3pZkJk{J`d_InWBgA3&A6$ zT0T4^+cZ0!7lh=QDq{Jekc^}gL*R3Q1}=-Yp(9MUhVg4c zG6jMNdGaw}oK*#w{eODB8L9t7A=X9U1ls&V% z6*EjO>FMbK+6fuM5h7y=Q#`X{Np{0=jwNERBW$fxB6gwM8AcQ5^XRw7;>n2}e`r~d z0!`vcW^8KPoG2#>Z*ldQbJ66Ml+*#5H; zwmV|)Y-_~coOJZ07CvbC(O9$I*Jo5U%3bk9eHu?H(>+y6qm@oo#bKG&%4pVXH0$>y zQ8Ny9m~U7+fR?ITb~{7PC&->L=WTz%L+_x0Jb`!m@+!y>zt^^J|#&~&FNMgM(nK$(fWrKE?3qgVoy~S4n)MBcJj5*?IjJlHK&UL zeBs6~gvTy#m!%e2auB=eUyK+FDw3PtI{{ z-5)P1o1+6=?O+u{;0lK%r-N>!4Yc*tdTFPlpxMB0X$v_oc~L_bYH(3owS-%+O}ipi z=F#?~7AvrJx~mU6X>nHky^*TX?!(T601|RK_JiW?!yR~`r>DA0LgT}fTj7gLMLnlu zQgbO(CaHJR1Df{6i#@I$vY*r(V$6b5e7R6q#GaabG!tjLc0DoFmHBVU?lz@)ZA$Of zsuzpYDGzrd+QNvhTO#^{eBiMBCtaB`Yjv?43ils;I>=`$D}~Z~`l_jm)+_KtC>>$a zuTR(YEAwTY)bjtHZpiY`$?C%n_W+LOA$hI&1-rUR zQwD+>ruyO?R!xE`MNL?!tZopFob$t7zE)tUFZYh{VaZE z>>ShDEbfk7CjFN8#7;LQm+*TM;`=yaaX2mIx5}Qr7x;*{IKFOBu=F9gf&BSFNv0je z{MevO%gW)D&cV+8%E9kDAM>%?8y^&k`{p_;Y_A3~S_)F^9*XNHb?}+-vHa<{n23+? z=7jE|FB74+Rlz@ri#9!-$uGp+CM5tEEPc<*63Agc=@_^;-W(riZ^k=SPdn`5(7OeS zplpyYhN-!{iM{19KX4ag)h&|ST+Ra$Y|<1m@8`iXM69a9k|SgyK_Qbp7VtkWM$uN& zDIzianS{9hZ{p7AX~(@)opVw0n4enQbUfi&$@In0rs%}0B-3Z>;?=@j1_K!hGy=1@L4d7Q-f^5n6m zwgr4o@(|PJ1^lncpZ2?uW^99hq&2;pGFkD`ZWYj1-aQ38zL zEYKs3RU^^!jILC~K2yLgX=$dt1$=Cpa3ey7t9Oz*|f3Y+w%3quH&}BznQQQGO~|C&LjO(Z{95( zNDNQm<(-|_z#j8B0M*^nvSRof#hV9@v|h}^JU*@FFEtLHUIwf7Ik~CNkOh*|hu@R_ zj5LqO51l5(@I^ysnGPlK14Fk-=e!??GAPRxJIkW)P3Bc$`e_aHu0TC8?}IT z&7ozy>Oj_LgGRT5@_RN6Gu@I*6k z1iu4MvlO z+YP}1p%LQ%c%pTK8EXSibkPvTj)N!q0!9aTqT}$?{5yD}A7gZb?*N^e$yne@l~#ba zfJgV)R=htXfNunyi5HV}@H1UtBJHRi0@0lq4)8>uAA#!005mfj)q^Mc2F3#LL_H%> zJ$Rz0FdhU?bl51yYQYoz5aSW>M8iij<^xakK@8V(5Qv#O25)rWaRS*{jKkn@`q+%I zjJ1Qu$zxkFJ_e6N!Ehj0CwQVbb?iIBL2>f%Bv2_13+n@(C=LvZ1y6JqMk;vFVGJjT zWkMi|Q^dxBCwc*6GWf;`jJ<^6tmXxQ`x~Zaj_$fjJ+$WjjKyP6bBTtA1eil^4h)c- zNL|wz1$-*$@Peto4XTL@2*cTUV`@cIgQ_Q40&6S*A=0f(ayB`qHJa+}fxB)T7Z!@` zq})U;O_S!d28?KX7G*h5E{N4v<@5S{zDD0ZUyHBJ*Wv5*b^F+skS&%iv0JQL(zn>R zjB6Ty=Z8{gzIK0Q*C!8bvj6t1WXd1Y6qTP5N%Y!sRZgj>?Hhb!;l0;alo#`zE3R-& zDK9J}AvlBzwK5Z1R9KNW@9qjV%a0%rHYX70Q$XeedD4$8T)bof=`9b{{g6}&os2LY zsVL1`OiD$5SYDnQvDL4gRZ&=3fjKzNUzNfis_Dn4y87`=t1?Z~ zCH_@a3jbVk*0DNy*^Y8!8? zOT}cWxlCd#h#y=Z%S#_#YGVDlWp#=+8OBd~$6;%kKZE2|a=!>} zD|V*3z|dhKX53a962SD_VVmw&+%_$7TP3NI*ZuxOlO@t0>;+G;Ax`41HGd@$*+y6* z$vs*lC4uyz-Xpz9eE5oB{?*!4X#4yElxVsf$!9?^h?&G;&W^ zSXN%R6kEU^rKhYX2!(ZZDLnu2RLwTdyt`Lpf_Z|s*yK=ys7gga15qlVYwGQ;!CydWSefQ-YV#^~@9KrRZgw)20~+sq#V zZ^x>{b9+Mw<$6_vT2NJkEFIu)Hh5wKgJ6fUj5H&Gbi`{5J1`y6R6NtvV0v#l_!e$c zTGPo>r9j^IkvdaVg3@nl#ix%HnXiRm6`#4@CROoe>s93g>r?S(+}ZUnUVSTO9YWXz zK#Bz9ULdp;jnry@G$v}PO?V2@%p^TE>hK{TkyaH^`*{k;P7N{n_g*7U`-7TM@gGv9 zbYB05I=oaQZ?JLarc|ErSQrm`S=}jXHe{Q=4&wRi2dD~C8Q)oFgGy0Q0P<=~){=3> zK*~(%olF{#Hw5G=ARb$9o!fw%5|C0L!%}r?*{WRPo$Vm2lG2X&Ij{{o){dSKbU;cdCKPBtRAEoT#Hj}`d2XT zw=qQu<|8)R@Mp|y{7&ZgZJcKE4W_kL6o>PeCu7KO){`j_r;)}0c zv{9tTpG+Z#uRgiNFrT@pPV(`yn{4=P-fZKtPnHhzdp6hMMk2I}r}=EWXbZmV;Pt*b zlXD1N0O8Iddcw1K#O6U}AHtdVB-cQGv1#9#ph{W!K&S?Ruh~wFWbb7g z`fN!rIhTL(Y%w3aN4341Z__v%H$5-&l)bvoDo8%R^lwOs`}Da7Uy%7mzx3k^UMas< zyzgHu=_Tj#V~xc;u35J&+bKsCWoSE)Wi2SEC_rb`{(QAl<{izUVZVTjcgeip0o}ou zkXF5_OGQm`RPANlecmMVA6rOs((b!?DCii49XuBmqrP zczagwqhEA!|Epe;#Za8WUwW;iH;~KMwG{KW-qwTK56WDAN0(lJbi^-Z9+LUwWBS~m z4taUlpHsDjo_@W=FXi%w4i`t+FO!k=4LOSbPEu~qUu3)K4X?@3JKM*Ol=KF2d3kGb zl;aZC-?ZKxC0_y`u`iYLw%jP^CFW>JEN{wDb1pNt4s-dJnd|cwHuPoYevi4b%gluw zm7^*zGq)OZRhO7Md-U$8+DqV*cBk^{w{xSsmzYCs4e!WN8!kP?AHtmPGIJL(x8pK% z_aF0`8hbC$vOkyf26Fk0?P~^(#T`i>yw+-O?m0m4p5AWjtxV5L{@}Z*mfLAok0_ZL z-%>sxbP+%&-bjM@m9_Cfzk_sj08jKLnrpze@&514b~S)w5o!#2IN-g75anW^Kb7cn z0EkmS-X|TThNpq1a~8;Chz9aAkaPq$5K9<&Q!P}_NiIMqw6s+yi-BK?gtZm^WW}A7GV23?Fpz z(W;&vJ+pn}$I=^l_YOcESPG+iJ*0#WUYfLIqwz;3L+Xa3D}mrGz85kLh#d&6yjsRw z-hA99-N#Sk_a-jAAMLUT>FtJvW0-nNsTK!;Y!C{64@j)w^-~~LVg0`cB1Sg%#Vfk7 z05%{NmjF!wL?0{`5-uq$nO}Av)>cSy3UutKQ|&To-v*@J-*-Zm1EGY}c9j$q7njb* z&Q=Pu!gJpBH{X&s;}({WZ{L*8sI@){GpA7fQ$Xlr^t};CC4w1ibCh(17=E@90v#$-Ewvd4 zUF0rwNrR36+9#Nu1=1#%eNQ^@Yq++da=X8=P-b>Qgk`+}$lI7Px;PJrOjhW>7XBVU z10Wf$w*jdY+PD)4)nRPt*MW2jJv#%WOW85H=YImB4 zD)K21i_pt&fwcQmr>K$(-;dD!XC&Gm$kmuKIyVsrod^TD0f@K(^MKd^8sYB+(g73I zYQA=AVugfu^v8%P3{q|G%5-{Xves?p~WK*S4l5|Dghndbp<2wSQIh*!|@0NDq( zMiSe}3bBlXw#x;m#SblAyl6>5F_u|y{R(vK0`d-7p<=_)r$FeV9=)X%IdkY5E2R>fbAkSJPwDv0}VGe&{aSz!ZPIoS%Y9kWy^p#h3X##(k=vh9teGmgV{0w z7pyFt!*8JE6V^K*TKyi`2xcKf(76JLRk(<+1`;dmiJ3skgfiv%UIBR@NTsmbz6KH^g#VFr=z=vW8-lM8tAHQ_WiU1d2&{UgI1Pvu zh;hl@0i;p0AWM9&L5NUBC6IRE^gab-M*wd>ZJ+TXScj0?F(BQ7gDxN~aBZaaZy;4d zjeYU$<_SLIOj1TXxE7%!89-=L8O4qPQZ|e~dM0t~G_Xa&*13;X>jJntI z^Ji?XCxC|tw$B5x3&=t8CM@E6Kq`fj&jINI0z<9$-vRMylG;}j?uA;Rtbr~-RFjcb zI*@e1^#mYoLP9fu+zB(I8!Lgd2pxX}NWKtkGZ2g4PhMVSao&91r^DjfO%q5WOv{$B zgFvi8H6H+p^&3NxeF3CXKrR4rXg<`6&4bi;4CAIr1hPsvvopp3s)ZSRX{{>+5+dYY z284F9q4O|*x5MUo3HUz0=E8f+7grSGc>57pvDcuJFLd-BAQs`ke++~QHahw(5c(Kf zC=CDZ6_I!sApKiYwc>OjZNlAp4Ulm{Let0*UR%^+)ITJ!_5C^pY8+)v$gApkF06<% z61p#r&c6WFL#azxlre`fDXe zTYxM8H4H$}LRO1`ga}rZ zK+60&3-Rwz%EKyLF{}DPsROWjcGfq2cJ8)7`@Q7_WqJ6wXJI9y|9<9`mgmtIx(Z)V dxp*mCuy|=%LB;%{yk%whLb9;w+0MSP{|BcyUVi`p diff --git a/source/fumoengine/fumoengine.c b/source/fumoengine/fumoengine.c index be46ffb..4c030d4 100644 --- a/source/fumoengine/fumoengine.c +++ b/source/fumoengine/fumoengine.c @@ -1,7 +1,5 @@ -#include "ctrl.h" - -#include "event.h" -#include "fumocommon.h" +#include "fumoengine.h" +#include "platform.h" void ErrorExit(char *message) @@ -10,43 +8,19 @@ void ErrorExit(char *message) exit(1); } -struct FumoGame { - struct Controller ctrl; - struct InputHandle input_hand; - - struct Event start; - struct Event draw; - struct Event update; - - Time time; -}; - -bool FumoEngineInit(struct FumoGame *game) +bool FumoInit(struct FumoGame *game) { if (!PlatformInit()) ErrorExit("Platform failed to initialize"); - if (!CreateCtrl(&game->ctrl)) + if (!CreateController(&game->ctrl)) ErrorExit("Out of memory"); - //CtrlMap(&ctrl, 0, BUTTON, 'A'); + if (!CreateEvent(&game->update)) + ErrorExit("Out of memory"); - CreateEvent(&game->update); - - if (!BeginInputThread(&game->input_hand, &game->input_hand.recs, &ctrl.str)) + if (!BeginInputThread(&game->input_hand)) ErrorExit("Input handle failed to initialize"); - while (true) { - if (!InputAquire(&input_hand)) - ErrorExit("Aquire failed"); - - CtrlPoll(&ctrl); - - if (!InputRelease(&input_hand)) - ErrorExit("Release failed"); - - EventInvokeUpdate(&game.update, 0); - } - return 0; } \ No newline at end of file diff --git a/source/fumoengine/fumoengine.h b/source/fumoengine/fumoengine.h new file mode 100644 index 0000000..9bbc60e --- /dev/null +++ b/source/fumoengine/fumoengine.h @@ -0,0 +1,23 @@ +#pragma once +#include "ctrl.h" +#include "event.h" +#include "fumocommon.h" +#include "input.h" + + +struct FumoGame { + struct Controller ctrl; + struct InputHandle input_hand; + + struct Event start; + struct Event draw; + struct Event update; + + Time time; +}; + + +void ErrorExit(char *message); + +bool FumoInit(struct FumoGame *game); + diff --git a/source/fumoengine/include/event.c b/source/fumoengine/include/event.c index fe2a9da..b602115 100644 --- a/source/fumoengine/include/event.c +++ b/source/fumoengine/include/event.c @@ -50,7 +50,7 @@ void EventInvoke(struct Event *event, void *arg) } } -void EventInvokeUpdate(struct Event *event, u64 dt) +void EventInvokeUpdate(struct Event *event, Time dt) { for (size_t i = 0; i < event->len; i++) { event->clbks[i].update(dt); diff --git a/source/fumoengine/include/ringbuffer.h b/source/fumoengine/include/ringbuffer.h index 67627fa..0ceacbd 100644 --- a/source/fumoengine/include/ringbuffer.h +++ b/source/fumoengine/include/ringbuffer.h @@ -17,6 +17,13 @@ struct RingBufferHead { size_t start; }; +#define RINGBUF_T_INIT(RBUF_STRUCT, RBUF_ITEM, RBUF_LEN) \ + (&(struct RingBufferT) { \ + .OFFSET = offsetof(RBUF_STRUCT, buf), \ + .SIZE = sizeof(RBUF_ITEM), \ + .LEN = RBUF_LEN \ + }) \ + #define RINGBUF_HEAD_INIT ((struct RingBufferHead) { 0, 0 }) size_t RingBufferEmpty(RingBufferT T, struct RingBufferHead *head); diff --git a/source/fumoengine/input/ctrl.c b/source/fumoengine/input/ctrl.c index 5eea0b9..c7b932e 100644 --- a/source/fumoengine/input/ctrl.c +++ b/source/fumoengine/input/ctrl.c @@ -5,7 +5,7 @@ #define INIT_SIZE 16 -bool CreateCtrl(struct Controller *ctrl) +bool CreateController(struct Controller *ctrl) { struct ctrl_bkt *code_bkts = calloc(INIT_SIZE, sizeof(struct ctrl_bkt)); struct ctrl_bkt *bind_bkts = calloc(INIT_SIZE, sizeof(struct ctrl_bkt)); @@ -36,7 +36,7 @@ bool CreateCtrl(struct Controller *ctrl) return true; } -void FreeCtrl(struct Controller *ctrl) +void FreeController(struct Controller *ctrl) { free(ctrl->codes.bkts); free(ctrl->binds.bkts); @@ -105,7 +105,7 @@ union InputID as_id(u16f value, u16f type) { return (union InputID) { .value = value, .type = type }; } -bool CtrlMap(struct Controller *ctrl, u16f code, u16f type, u16f bind) +bool ControllerMap(struct Controller *ctrl, u16f code, u16f bind, u16f type) { struct ctrl_bkt *code_bkt = find_set(&ctrl->codes, as_id(code, type)); struct ctrl_bkt *bind_bkt = find_set(&ctrl->binds, as_id(bind, type)); @@ -120,7 +120,7 @@ bool CtrlMap(struct Controller *ctrl, u16f code, u16f type, u16f bind) return true; } -struct InputAxis *CtrlGet(struct Controller *ctrl, u16f code, u16f type) +struct InputAxis *ControllerGet(struct Controller *ctrl, u16f code, u16f type) { struct ctrl_bkt *code_bkt = find(&ctrl->codes, as_id(code, type)); if (code_bkt == nullptr) @@ -144,16 +144,16 @@ void dispatch_update(struct InputAxis *axis, struct InputRecord *rec) axis->data = rec->data; } -void CtrlPoll(struct Controller *ctrl, struct InputRecordBuf *recs) +void ControllerPoll(struct Controller *ctrl, struct RecordBuffer *recs) { - for (size_t i = 0; i < ctrl->pending_buf.len; i++) { + /*for (size_t i = 0; i < ctrl->pending_buf.len; i++) { struct InputAxis *axis = ctrl->pending_buf.axes[i]; axis->is_up = false; axis->is_down = false; } - ctrl->pending_buf.len = 0; - + ctrl->pending_buf.len = 0;*/ + for (size_t i = 0; i < recs->head.len; i++) { struct InputRecord *rec = &recs->buf[i]; @@ -171,31 +171,37 @@ void CtrlPoll(struct Controller *ctrl, struct InputRecordBuf *recs) /*int main() { struct Controller ctrl; - if (!CreateCtrl(&ctrl)) + if (!CreateController(&ctrl)) return 1; - CtrlMap(&ctrl, 123, BUTTON, 111); - CtrlMap(&ctrl, 0, BUTTON, 8); + ControllerMap(&ctrl, 123, 111, BUTTON); + ControllerMap(&ctrl, 0, 8, BUTTON); - ctrl.buf.recs[ctrl.buf.len++] = (struct InputRecord) { - .bind = 111, - .type = BUTTON, + struct RecordBuffer recs = { .head.len = 0, .head.start = 0 }; + + recs.buf[recs.head.len++] = (struct InputRecord) { + .but.value = 69, + .is_down = true, - .but.value = 69 + + .id.bind = 111, + .id.type = BUTTON }; - ctrl.buf.recs[ctrl.buf.len++] = (struct InputRecord) { - .bind = 8, - .type = BUTTON, + recs.buf[recs.head.len++] = (struct InputRecord) { + .but.value = 1000, + .is_down = true, - .but.value = 1000 + + .id.bind = 8, + .id.type = BUTTON }; - CtrlPoll(&ctrl); + ControllerPoll(&ctrl, &recs); - struct InputAxis *a = CtrlGet(&ctrl, 123, BUTTON); + struct InputAxis *a = ControllerGet(&ctrl, 123, BUTTON); printf("%u\n", a->but.value); - struct InputAxis *b = CtrlGet(&ctrl, 0, BUTTON); + struct InputAxis *b = ControllerGet(&ctrl, 0, BUTTON); printf("%u\n", b->but.value); printf("success"); diff --git a/source/fumoengine/input/ctrl.h b/source/fumoengine/input/ctrl.h index 595085d..270634a 100644 --- a/source/fumoengine/input/ctrl.h +++ b/source/fumoengine/input/ctrl.h @@ -57,49 +57,19 @@ struct Controller { struct ctrl_dict binds; }; -bool CreateCtrl(struct Controller *ctrl); - -void FreeCtrl(struct Controller *ctrl); - -bool CtrlMap(struct Controller *ctrl, u16f code, u16f type, u16f bind); - -struct InputAxis *CtrlGet(struct Controller *ctrl, u16f code, u16f type); - -void CtrlPoll(struct Controller *ctrl, struct InputRecordBuf *recs); - -enum ControlCode { - LEFT, - RIGHT, - SOFT_DROP, - HARD_DROP, - ROTATE_CCW, - ROTATE_CW, - ROTATE_180, - SWAP, - ESC, - VSCROLL, - HSCROLL, - MOUSE -}; - struct ControlBind { - enum ControlCode code; + int code; u16 bind; - u8 type; + u16 type; }; -#define CODE_COUNT 12 -/*const struct ControlBind ctrl_binds[12] = { - { LEFT, 0x25, BUTTON }, - { RIGHT, 0x27, BUTTON }, - { SOFT_DROP, 0x28, BUTTON }, - { HARD_DROP, 0x20, BUTTON }, - { ROTATE_CCW, 'Z', BUTTON }, - { ROTATE_CW, 'X', BUTTON }, - { ROTATE_180, 'A', BUTTON }, - { SWAP, 'C', BUTTON }, - { ESC, 0x1B, BUTTON }, - { VSCROLL, 0, AXIS }, - { HSCROLL, 1, AXIS }, - { MOUSE, 0, JOYSTICK } -};*/ \ No newline at end of file + +bool CreateController(struct Controller *ctrl); +void FreeController(struct Controller *ctrl); + +bool ControllerMap(struct Controller *ctrl, u16f code, u16f bind, u16f type); + +struct InputAxis *ControllerGet(struct Controller *ctrl, u16f code, u16f type); + +void ControllerPoll(struct Controller *ctrl, struct RecordBuffer *recs); + diff --git a/source/fumoengine/input/input.c b/source/fumoengine/input/input.c index 7882318..6aa1ea7 100644 --- a/source/fumoengine/input/input.c +++ b/source/fumoengine/input/input.c @@ -4,25 +4,25 @@ #include "platform.h" -const struct RingBufferT IO_BUF_T = { - .OFFSET = offsetof(struct InputRecordBuf, buf), - .SIZE = sizeof(struct InputRecord), - .LEN = IO_BUF_SIZE -}; +RingBufferT IO_BUF_T = RINGBUF_T_INIT( + struct RecordBuffer, + struct InputRecord, + IO_BUF_SIZE +); -const struct RingBufferT STR_BUF_T = { - .OFFSET = offsetof(struct InputStringBuf, buf), - .SIZE = sizeof(char), - .LEN = STR_BUF_SIZE -}; +RingBufferT STR_BUF_T = RINGBUF_T_INIT( + struct StringBuffer, + char, + STR_BUF_SIZE +); void *input_worker(void *arg) { struct InputHandle *hand = arg; - struct InputRecordBuf tmp_recs = { .head.len = 0, .head.start = 0 }; - struct InputStringBuf tmp_str = { .head.len = 0, .head.start = 0 }; + struct RecordBuffer tmp_recs = { .head.len = 0, .head.start = 0 }; + struct StringBuffer tmp_str = { .head.len = 0, .head.start = 0 }; while (!hand->is_terminating) { if (!PlatformReadInput(&tmp_recs, &tmp_str)) { @@ -42,8 +42,8 @@ void *input_worker(void *arg) } } - RingBufferTransfer(&IO_BUF_T, &hand->recs->head, &tmp_recs.head); - RingBufferTransfer(&STR_BUF_T, &hand->str->head, &tmp_str.head); + RingBufferTransfer(IO_BUF_T, &hand->recs.head, &tmp_recs.head); + RingBufferTransfer(STR_BUF_T, &hand->str.head, &tmp_str.head); if (pthread_mutex_unlock(&hand->mutex) != 0) { hand->err = true; @@ -54,14 +54,11 @@ void *input_worker(void *arg) return nullptr; } -bool BeginInputThread( - struct InputHandle *hand, - struct InputRecordBuf *in, - struct InputStringBuf *str -) { +bool BeginInputThread(struct InputHandle *hand) +{ *hand = (struct InputHandle) { - .recs = in, - .str = str, + .recs.head = RINGBUF_HEAD_INIT, + .str.head = RINGBUF_HEAD_INIT, .err = 0, .is_terminating = false, @@ -114,7 +111,7 @@ bool InputRelease(struct InputHandle *hand) return true; } -size_t InputString(struct InputStringBuf *str, size_t n, char *buf) +size_t InputString(struct InputHandle *hand, size_t n, char *buf) { - return RingBufferOut(&STR_BUF_T, n, buf, &str->head); + return RingBufferOut(STR_BUF_T, n, buf, &hand->str.head); } \ No newline at end of file diff --git a/source/fumoengine/input/input.h b/source/fumoengine/input/input.h index 76ec18d..4d0e97b 100644 --- a/source/fumoengine/input/input.h +++ b/source/fumoengine/input/input.h @@ -13,8 +13,8 @@ #define STR_BUF_SIZE (IO_BUF_SIZE * 4) -extern const struct RingBufferT IO_BUF_T; -extern const struct RingBufferT STR_BUF_T; +extern RingBufferT IO_BUF_T; +extern RingBufferT STR_BUF_T; enum InputType { @@ -25,15 +25,17 @@ enum InputType { }; union InputID { + u32 hash; + struct { union { u16 code; u16 bind; u16 value; }; + u16 type; }; - u32 hash; }; @@ -76,20 +78,19 @@ struct InputRecord { }; }; -struct InputBuffer { - struct { - struct RingBufferHead head; - struct InputRecord buf[IO_BUF_SIZE]; - } recs; +struct RecordBuffer { + struct RingBufferHead head; + struct InputRecord buf[IO_BUF_SIZE]; +}; - struct { - struct RingBufferHead head; - char buf[STR_BUF_SIZE]; - } str; +struct StringBuffer { + struct RingBufferHead head; + char buf[STR_BUF_SIZE]; }; struct InputHandle { - struct InputBuffer in; + struct RecordBuffer recs; + struct StringBuffer str; pthread_t thread; pthread_mutex_t mutex; @@ -99,10 +100,7 @@ struct InputHandle { bool is_terminating; }; -bool BeginInputThread( - struct InputHandle *hand, - struct InputBuffer *in, -); +bool BeginInputThread(struct InputHandle *hand); bool EndInputThread(struct InputHandle *hand); @@ -110,4 +108,4 @@ bool InputAquire(struct InputHandle *hand); bool InputRelease(struct InputHandle *hand); -size_t InputString(struct Controller *ctrl, size_t n, char *buf); \ No newline at end of file +size_t InputString(struct InputHandle *hand, size_t n, char *buf); \ No newline at end of file diff --git a/source/fumoengine/input/platforms/platform.h b/source/fumoengine/input/platforms/platform.h index 291d9e0..a7a6d86 100644 --- a/source/fumoengine/input/platforms/platform.h +++ b/source/fumoengine/input/platforms/platform.h @@ -16,7 +16,7 @@ bool PlatformInit(); bool PlatformGetRefreshRate(u16f *out); -bool PlatformReadInput(struct InputRecordBuf *in, struct InputStringBuf *str); +bool PlatformReadInput(struct RecordBuffer *recs, struct StringBuffer *str); bool PlatformStopInput(); diff --git a/source/fumoengine/input/platforms/win.c b/source/fumoengine/input/platforms/win.c index 57837d7..e36b5bd 100644 --- a/source/fumoengine/input/platforms/win.c +++ b/source/fumoengine/input/platforms/win.c @@ -69,11 +69,6 @@ struct win_rec { }; }; -union record { - struct win_rec native; - INPUT_RECORD win; -}; - bool init_handles() { win.input_hand = GetStdHandle(STD_INPUT_HANDLE); @@ -123,33 +118,33 @@ bool PlatformGetRefreshRate(u16f *out) } bool dispatch_rec( - struct InputRecord *out, - struct InputStringBuf *str, - struct win_rec *rec + struct InputRecord *rec, + struct StringBuffer *str, + struct win_rec *win ) { - u8f type = rec->type | (rec->is_mouse & rec->mouse.flags); + u8f type = win->type | (win->is_mouse & win->mouse.flags); switch (type) { case KEY_EVENT: { - ReadButton(out, rec->key.vk_code, rec->key.is_down); + ReadButton(rec, win->key.vk_code, win->key.is_down); - if (rec->key.is_down) - str->head.len += UCS2ToUTF8(str->buf, rec->key.ucs2_char); + if (win->key.is_down) + str->head.len += UCS2ToUTF8(str->buf, win->key.ucs2_char); return true; } case MOUSE_MOVE: { - ReadJoystick(out, 0, rec->mouse.pos.x, rec->mouse.pos.y); + ReadJoystick(rec, 0, win->mouse.pos.x, win->mouse.pos.y); return true; } case MOUSE_VWHEEL: { - ReadAxis(out, 0, rec->mouse.but); + ReadAxis(rec, 0, win->mouse.but); return true; } case MOUSE_HWHEEL: { - ReadAxis(out, 1, rec->mouse.but); + ReadAxis(rec, 1, win->mouse.but); return true; } @@ -163,21 +158,30 @@ bool dispatch_rec( return false; } -bool PlatformReadInput(struct InputRecordBuf *recs, struct InputStringBuf *str) +size_t read_input(struct win_rec *buf, size_t n) { - DWORD read_max = RingBufferEmpty(&IO_BUF_T, &recs->head); - union record win_buf[read_max]; - DWORD filled; + DWORD len; + if (!ReadConsoleInputW(win.input_hand, buf, n, &len)) + return 0; + + return len; +} - if (!ReadConsoleInputW(win.input_hand, &win_buf->win, read_max, &filled)) +bool PlatformReadInput(struct RecordBuffer *recs, struct StringBuffer *str) +{ + size_t n = RingBufferEmpty(IO_BUF_T, &recs->head); + struct win_rec buf[n]; + + size_t len = read_input(buf, n); + if (len == 0) return false; Time now = TimeNow(); - for (size_t i = 0; i < filled; i++) { - struct InputRecord *rec = RingBufferNext(&IO_BUF_T, &recs->head); + for (size_t i = 0; i < len; i++) { + struct InputRecord *rec = RingBufferNext(IO_BUF_T, &recs->head); - if (dispatch_rec(rec, str, &win_buf->native + i)) { + if (dispatch_rec(rec, str, &buf[i])) { rec->time = now; recs->head.len += 1; } diff --git a/source/fumotris.c b/source/fumotris.c deleted file mode 100644 index cad8a4e..0000000 --- a/source/fumotris.c +++ /dev/null @@ -1,43 +0,0 @@ - - -/*const u8 I[16] = { - 0, 0, 0, 0, - 0, 0, 0, 0, - 1, 1, 1, 1, - 0, 0, 0, 0 -}; - -const u8 O[4] = { - 1, 1, - 1, 1 -}; - -const u8 T[9] = { - 0, 1, 0, - 1, 1, 1, - 0, 0, 0 -}; - -const u8 S[9] = { - 0, 1, 1, - 1, 1, 0, - 0, 0, 0 -}; - -const u8 Z[9] = { - 1, 1, 0, - 0, 1, 1, - 0, 0, 0 -}; - -const u8 J[9] = { - 1, 0, 0, - 1, 1, 1, - 0, 0, 0 -}; - -const u8 L[9] = { - 0, 0, 1, - 1, 1, 1, - 0, 0, 0 -};*/ \ No newline at end of file diff --git a/source/fumotris/fumotris.c b/source/fumotris/fumotris.c new file mode 100644 index 0000000..06946d7 --- /dev/null +++ b/source/fumotris/fumotris.c @@ -0,0 +1,110 @@ +#include "fumocommon.h" +#include "fumoengine.h" + + +enum ControlCode { + LEFT, + RIGHT, + SOFT_DROP, + HARD_DROP, + ROTATE_CCW, + ROTATE_CW, + ROTATE_180, + SWAP, + ESC, + VSCROLL, + HSCROLL, + MOUSE +}; + +#define CODE_COUNT 12 + +const struct ControlBind ctrl_binds[12] = { + { LEFT, 0x25, BUTTON }, + { RIGHT, 0x27, BUTTON }, + { SOFT_DROP, 0x28, BUTTON }, + { HARD_DROP, 0x20, BUTTON }, + { ROTATE_CCW, 'Z', BUTTON }, + { ROTATE_CW, 'X', BUTTON }, + { ROTATE_180, 'A', BUTTON }, + { SWAP, 'C', BUTTON }, + { ESC, 0x1B, BUTTON }, + { VSCROLL, 0, AXIS }, + { HSCROLL, 1, AXIS }, + { MOUSE, 0, JOYSTICK } +}; + +void Loop(struct FumoGame *game) +{ + while (true) { + game->time = TimeNow(); + + if (!InputAquire(&game->input_hand)) + ErrorExit("Aquire failed"); + + //ControllerPoll(&game->ctrl, &game->input_hand.recs); + + if (!InputRelease(&game->input_hand)) + ErrorExit("Release failed"); + + //EventInvokeUpdate(&game->update, 0); + } +} + +int main() +{ + struct FumoGame game; + FumoInit(&game); + + for (size_t i = 0; i < CODE_COUNT; i++) { + const struct ControlBind *bind = &ctrl_binds[i]; + ControllerMap(&game.ctrl, bind->code, bind->bind, bind->type); + } + + Loop(&game); + + return 0; +} + + +/*const u8 I[16] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 1, 1, + 0, 0, 0, 0 +}; + +const u8 O[4] = { + 1, 1, + 1, 1 +}; + +const u8 T[9] = { + 0, 1, 0, + 1, 1, 1, + 0, 0, 0 +}; + +const u8 S[9] = { + 0, 1, 1, + 1, 1, 0, + 0, 0, 0 +}; + +const u8 Z[9] = { + 1, 1, 0, + 0, 1, 1, + 0, 0, 0 +}; + +const u8 J[9] = { + 1, 0, 0, + 1, 1, 1, + 0, 0, 0 +}; + +const u8 L[9] = { + 0, 0, 1, + 1, 1, 1, + 0, 0, 0 +};*/ \ No newline at end of file diff --git a/test.exe b/test.exe index a855f5e09e004fa0e118c883c164c3a89f51e6d5..ada5cb88d40cb90acf973e401aa00269bf7013da 100644 GIT binary patch delta 22883 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