From cdb2c800ccf0f892d5f2531ec1148cc910c2561c Mon Sep 17 00:00:00 2001 From: a dinosaur Date: Sat, 31 May 2025 18:09:29 +1000 Subject: [PATCH] c: Add lessons 1-10 --- .gitignore | 26 ++ CMakeLists.txt | 8 + cmake/modules/AddLesson.cmake | 38 ++ data/Crate.bmp | Bin 0 -> 66614 bytes data/Glass.bmp | Bin 0 -> 49220 bytes data/Mud.bmp | Bin 0 -> 196662 bytes data/NeHe.bmp | Bin 0 -> 196664 bytes data/Star.bmp | Bin 0 -> 17476 bytes data/World.txt | 160 +++++++++ data/shaders/lesson2.metallib | Bin 0 -> 5374 bytes data/shaders/lesson3.metallib | Bin 0 -> 5687 bytes data/shaders/lesson6.metallib | Bin 0 -> 6298 bytes data/shaders/lesson7.metallib | Bin 0 -> 7044 bytes data/shaders/lesson9.metallib | Bin 0 -> 6730 bytes scripts/compile_shaders.py | 186 ++++++++++ src/c/CMakeLists.txt | 12 + src/c/application.c | 211 +++++++++++ src/c/application.h | 22 ++ src/c/lesson1.c | 34 ++ src/c/lesson10.c | 392 ++++++++++++++++++++ src/c/lesson2.c | 182 ++++++++++ src/c/lesson3.c | 189 ++++++++++ src/c/lesson4.c | 197 +++++++++++ src/c/lesson5.c | 245 +++++++++++++ src/c/lesson6.c | 266 ++++++++++++++ src/c/lesson7.c | 377 ++++++++++++++++++++ src/c/lesson8.c | 400 +++++++++++++++++++++ src/c/lesson9.c | 359 +++++++++++++++++++ src/c/matrix.c | 132 +++++++ src/c/matrix.h | 36 ++ src/c/nehe.c | 649 ++++++++++++++++++++++++++++++++++ src/c/nehe.h | 62 ++++ src/shaders/lesson2.metal | 36 ++ src/shaders/lesson3.metal | 39 ++ src/shaders/lesson6.metal | 45 +++ src/shaders/lesson7.metal | 65 ++++ src/shaders/lesson9.metal | 52 +++ 37 files changed, 4420 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 cmake/modules/AddLesson.cmake create mode 100644 data/Crate.bmp create mode 100644 data/Glass.bmp create mode 100644 data/Mud.bmp create mode 100644 data/NeHe.bmp create mode 100644 data/Star.bmp create mode 100644 data/World.txt create mode 100644 data/shaders/lesson2.metallib create mode 100644 data/shaders/lesson3.metallib create mode 100644 data/shaders/lesson6.metallib create mode 100644 data/shaders/lesson7.metallib create mode 100644 data/shaders/lesson9.metallib create mode 100755 scripts/compile_shaders.py create mode 100644 src/c/CMakeLists.txt create mode 100644 src/c/application.c create mode 100644 src/c/application.h create mode 100644 src/c/lesson1.c create mode 100644 src/c/lesson10.c create mode 100644 src/c/lesson2.c create mode 100644 src/c/lesson3.c create mode 100644 src/c/lesson4.c create mode 100644 src/c/lesson5.c create mode 100644 src/c/lesson6.c create mode 100644 src/c/lesson7.c create mode 100644 src/c/lesson8.c create mode 100644 src/c/lesson9.c create mode 100644 src/c/matrix.c create mode 100644 src/c/matrix.h create mode 100644 src/c/nehe.c create mode 100644 src/c/nehe.h create mode 100644 src/shaders/lesson2.metal create mode 100644 src/shaders/lesson3.metal create mode 100644 src/shaders/lesson6.metal create mode 100644 src/shaders/lesson7.metal create mode 100644 src/shaders/lesson9.metal diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41fd8d6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +/build/ +/xcode/ +/build-*/ + +.idea/ +cmake-build-*/ + +.swiftpm/ +.build/ +xcuserdata/ +DerivedData/ +Package.resolved + +/out/ +/target/ +Cargo.lock + +.vs/ +.vscode/ +CMakeSettings.json + +Thumbs.db +.DS_Store +*.exe +*.dll +*.metallibsym diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ebd7345 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION "3.11" FATAL_ERROR) +project(NeHe-SDL_GPU LANGUAGES C) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules") + +find_package(SDL3 REQUIRED CONFIG) + +add_subdirectory(src/c) diff --git a/cmake/modules/AddLesson.cmake b/cmake/modules/AddLesson.cmake new file mode 100644 index 0000000..d191435 --- /dev/null +++ b/cmake/modules/AddLesson.cmake @@ -0,0 +1,38 @@ +function (add_lesson target) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "SOURCES;SHADERS;DATA") + + add_executable(${target} MACOSX_BUNDLE WIN32 + application.c application.h + nehe.c nehe.h + matrix.c matrix.h) + set_property(TARGET ${target} PROPERTY C_STANDARD 99) + + target_compile_options(${target} PRIVATE + $<$:-Weverything -Wno-declaration-after-statement -Wno-padded -Wno-switch-enum -Wno-cast-qual> + $<$:-Wall -Wextra -pedantic> + $<$:/W4>) + target_compile_definitions(${target} PRIVATE + $<$:_CRT_SECURE_NO_WARNINGS>) + target_link_libraries(${target} SDL3::SDL3) + + target_sources(${target} PRIVATE ${arg_SOURCES}) + + foreach (shader IN LISTS arg_SHADERS) + if (shader MATCHES "\\.metal$") + set(path "${CMAKE_SOURCE_DIR}/src/shaders/${shader}") + else() + set(path "${CMAKE_SOURCE_DIR}/data/shaders/${shader}") + endif() + set_source_files_properties(${path} PROPERTIES + HEADER_FILE_ONLY ON + MACOSX_PACKAGE_LOCATION "Resources/Shaders") + target_sources(${target} PRIVATE "${path}") + endforeach() + foreach (resource IN LISTS arg_DATA) + set(path "${CMAKE_SOURCE_DIR}/data/${resource}") + set_source_files_properties(${path} PROPERTIES + MACOSX_PACKAGE_LOCATION "Resources/Data") + target_sources(${target} PRIVATE "${path}") + endforeach() + unset(path) +endfunction() diff --git a/data/Crate.bmp b/data/Crate.bmp new file mode 100644 index 0000000000000000000000000000000000000000..73fe985a835b40e4bbf09019a9af75399c5d6a2e GIT binary patch literal 66614 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 m_;_%`?U1sP-I0%NoP-{7A6_Qqy&6G?R9- zr<Lq4R>xOscv=llr{(K)Vv|v5FaUQ6^g6CqBL==otK}(`{d%29r{in2T(yd? zRf~-Jev?6H&9o=u7KY2g@wx{?0ZG883D*3*)vT~u>a}8(d{Cp3=rw~{wbZC(^7)r9bzDcvE>m<@uIjGC4P7^BXF8adRd-SDk06B? zJ^HsVLk(iHu6XaL^x$s#-f`yMgY@xH?A{&UgJavlu61wQd1v3fx9vOJ_uoAX9N%%@ zI}AU57~TYdh+h{ zlXu$>-fZ4EuI?RX_ivYv_iFd=)_`BUcPF*Co!+^f-MJm#SPiW#2A1c&^E1))<lf_RyNH$tRr+eZ1&#S-uGXJZuGr#)U`PoO7UwmNt z^r`F9_hMgt>Uj2+<@poai>J_dfm@ z82g`meDLANd(S?)`|&6HAAYd+;YXX#Ki+!p*~UBXu0MTx`|&#)kKb8;`^namcbD!x zSb6Z~=HqvY6XRz(I!+G^pYp!RN8|mGs5F*PL}QwGT%Sqll1W`EDNV#AiI_MN;`zN) zr@c?Bf|&FuhlLvo%2O#goxvU)G{zzdms{ob0$a7)qjh!MelMB4$7`yL7h>pzZ(1U6zI#>^j}?p z_|9CQUKMZR+>arJCotv~wbRnN96=R81HeU+IQZ84}=<=!DZn+WoU9ZU(G6$ljV9XGTY5fs} zHzu<9gch&d9koRZjzqzk$%X6Hc%_)GluFII#-#6p^h&f!qr<7tS&R;!D;D*oQ=UZJ zlT4T*Av1u9$0c_=auzK4tGEx9PEZbNeniILx2%D46az9RB@ydzEUnw$|NeaKrZLVqynWvVlf)sW}U;R zaoMykmnrBmhuqe1&=~Z1!$GGzpmR9ndexvp#h0nrg90KFjwfQ!yncRvKSQCQN<@5t zRIE_REqbHZZIAjb0jI$YEaQ;DV^=tx0)sIZa2nZ*vAQP?bM zhh3~z(*;5Z0!`s?B?^^Dt>GJhYji4`O=-1CEf#@R$CfK7VlfPfzjhOR7Am}kkY2u` zxPp}R_M$qF;8=T1>2|?TaF5s5)!9e8fz$L+aVNf%k($29awO;ClVM`!>`2Ec6O^*;0!s2(Eo zVN9wnfx27ZN7{l2r>1w1(22oZL>Lj85ZdQQdu)AX8^{>Oczhs}6K275A~;tC{yw=2 zEVFitE!{#>7taA5F!u# zMCl}Wu=a6kx{SB9D2@ihRimay(Rw{jO6kG-(RwFzzyxAD`}h_R-Ox#L_K2MrEvXxW zy}%y0;TK-j@~$a)SC#BbQvNkH|EAu6jmITp{ZKpax>DL>lJ{6-oo4Y3qv*OmP0VC5 z2`9p*?Xwx+Zq5aX=#orxO*3#+X#qQIeOe@_y9bMd^!0M3gOR0asa6T0kcW5gd&>

A& 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 N&!LW3o_pcB{|_*>WrF|! literal 0 HcmV?d00001 diff --git a/data/Mud.bmp b/data/Mud.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9b10897c61a7eb70d9550e5d94bb66ee359a809f GIT binary patch literal 196662 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

=z#6}SG6EE^YDHQ6`_gwLAuXG3e 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 AnE(I) literal 0 HcmV?d00001 diff --git a/data/Star.bmp b/data/Star.bmp new file mode 100644 index 0000000000000000000000000000000000000000..15737cdab2e436c6830a1cce49913d80b9293889 GIT binary patch literal 17476 zcmeHu2UwF=`}eVGRU9Y|K#-XP5+DhLKo%j8Kp?EJWp4#!smO4FpeQ(T?_Ec$);e0X zt=3k%YinEW($@8M*yY}}|NB1AlMvLl_HF&H>$|S^NFa%t-@Vtl35^NR5qbi;5#kBY z8req|(v!a5>06hMS6#YvAx}N^6zSTvE9us)8|mJ?J9+x)r%8_AF;N!CjI;OCj$lyAT~BOWZ=MoWYC~NWboj@WXO;q#Mai9 z*xA_;dwY8_bm&mx;NU8jXg8goKdL&`_e)YKcy# zBVl1-Bs@Hv==FLM5fMQmBO{5yU?5RZQ6xG#n#9D!kl5H*5*HUoj7B4gkB=t_2?-=I zF_9!CC6VOhWRjASLQ+#x$?)OBNm^PONl#BF85tQQGc%K9Wo41<>}-;glS6WIb4gxa z9?8$oCj|usq_D7%6crVb5hF&Bkt0Wv;^JabQc^-nOH0Y9QKLv%Ss5uWFDDfh6{NDV zl2lbykBQd3hyYHMprU0ofiudgTL$B!oyCQKj`Cr%`j zCQTxfCr>5~4GpBRv5`!fGKDlXHIe4#W-@i^R5ESaG}6-2LZ(ljPG-!QL0Vf|Nn2YR znK^SNnKf$`nLT?pnKNe&nLBqbnKy49X>V^Q^XJbe3l=OO3l}aVixw>+ix)2@OO`Al zOP4Ms%a$!8%a<=FD^{!^D_5>0t5&Tdt5>fkYu2nGYuBzN>(;F!>({R*8#Zhp8#itw z&ph)C*|cdB*}Qo(*|KE|*}8QrdG^_7$#c&=N49O-Mz(L?PIm0rL7sp9d9rioPV&MF zFOXfkc9Gq?cauGP_K>}M_mUT1e388L(o1CDzI|l>{{7^@fdk~_mtQ8Yyz&Zp_0?C& z!Gj0Mp+kqrYp=aV4j(>DUVr^{^2Qr)kRwNqkfTSBk~iOclf3oTTjcGx-zM+8^A36U z-FL}*@4ZLffB${*!3Q6ZW54?p~neDu*r#x5i-+c28IdkR=IeYdjId|?H zIe-2FTeak ze*N`Va_Q0~a{2OQa^=bua`oy}a_!nRa{c;sa^uDga`Wa*a_iPDa{Kmea_7z+a`*0C za_`;y(0+x@7e!X5`dW9=@5wF|8EWp3kjp+m`Qo!Bp?!l+qLUc zkg(u9^%Q*J>GBk%<4Mub1!PRI8Q^YRAy+bop#v!aBJex`67XZ;;}OaPOMiAZzrw$w zqIeP%P;^W1?%kkFFrRKL8I*>9T?i)DSym}36et#lz6BJ)zd$LV9{x2Qm{>=2#G$ZI z8!@LR^W*6r@HRsQC7~-dgnxkslh!-1DInBkJ$v@*#XRT>B!r;>2}MN!4gZ(`gl8;{ zGTx&{&mMpYUsg~RT3NvtKEZ=TAZb(#R94;oF#!zo^us{x@Zpqc1jPgOC_Pra=}U$R zRtnv^gGRdjLpuO?kRre%?<{x+FqFdP!_a}U0O3#)Ksh}?3+M~~r4r1{o6vzlmTAC+ zBD~}D>5G)~rgET~=+P5i^Z+w}fB^RU-%x;NkK9v>N2Rmq3^vsN{rXw=v$m#B;2RLb zl0a>tci+B<|KCdhxo2cgMUUX1a0EwS=0Nj-hrR$}fCeN1{$a1)*8Q!mz#owU8jk*^ z1Q?%ZG!Ke5u?|ckI7Nl7XTSg(8~OvjAsJK*sE6LxHa7iwp(`*V_`51#WY5|iIveng zDrdkE77nyq?4d8sG=LPW2Mr$B7u^v<66)Y@5^zsf4(9FZZXGn=XL&2aS&Ky@eGy@<2L;z;Uy1`=!z{EYoZ-57n zN7(~9Fh3Z8~$Y&V&T#90iH!4fM&;{ zI}W4Rt{g6x5CIQI2X`NDjvZLy!vtVH{)<$=C?B&O<=)IZDjs>K z=&r7A?p#j+--FBL@;n7zo?H&c-ObI_oy&D|a`pE0b{%RvgdqTRV3Gh6ivLssCgro- z_hAi>W!}Nj33vo>4u|XEB@zidJv=?V#bPf{9tZ*66Yx2%e2GNhIt&N^5wJ!81W-3b z0{+wq03K`~(k*Zgw%4aG>vdpvVDTt;WSzt1d3f-J{{A8uN_mN;Qjvhq_w?ZLeMH_| zPl?>0@9yGYM+snbfD-7{6TOhu1Ai<53XheGN%)M@Q_VX%ySjnSsmS?!fw!+*;V%*j zMN*~0&&SJ4z!!-8r9w|%rAi{;xj2F$f&^GAq;5#P@J|DAC+P$C)b9okLU<6pE05

d+4zqH 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 literal 0 HcmV?d00001 diff --git a/data/World.txt b/data/World.txt new file mode 100644 index 0000000..767385e --- /dev/null +++ b/data/World.txt @@ -0,0 +1,160 @@ + +NUMPOLLIES 36 + +// Floor 1 +-3.0 0.0 -3.0 0.0 6.0 +-3.0 0.0 3.0 0.0 0.0 + 3.0 0.0 3.0 6.0 0.0 + +-3.0 0.0 -3.0 0.0 6.0 + 3.0 0.0 -3.0 6.0 6.0 + 3.0 0.0 3.0 6.0 0.0 + +// Ceiling 1 +-3.0 1.0 -3.0 0.0 6.0 +-3.0 1.0 3.0 0.0 0.0 + 3.0 1.0 3.0 6.0 0.0 +-3.0 1.0 -3.0 0.0 6.0 + 3.0 1.0 -3.0 6.0 6.0 + 3.0 1.0 3.0 6.0 0.0 + +// A1 + +-2.0 1.0 -2.0 0.0 1.0 +-2.0 0.0 -2.0 0.0 0.0 +-0.5 0.0 -2.0 1.5 0.0 +-2.0 1.0 -2.0 0.0 1.0 +-0.5 1.0 -2.0 1.5 1.0 +-0.5 0.0 -2.0 1.5 0.0 + +// A2 + + 2.0 1.0 -2.0 2.0 1.0 + 2.0 0.0 -2.0 2.0 0.0 + 0.5 0.0 -2.0 0.5 0.0 + 2.0 1.0 -2.0 2.0 1.0 + 0.5 1.0 -2.0 0.5 1.0 + 0.5 0.0 -2.0 0.5 0.0 + +// B1 + +-2.0 1.0 2.0 2.0 1.0 +-2.0 0.0 2.0 2.0 0.0 +-0.5 0.0 2.0 0.5 0.0 +-2.0 1.0 2.0 2.0 1.0 +-0.5 1.0 2.0 0.5 1.0 +-0.5 0.0 2.0 0.5 0.0 + +// B2 + + 2.0 1.0 2.0 2.0 1.0 + 2.0 0.0 2.0 2.0 0.0 + 0.5 0.0 2.0 0.5 0.0 + 2.0 1.0 2.0 2.0 1.0 + 0.5 1.0 2.0 0.5 1.0 + 0.5 0.0 2.0 0.5 0.0 + +// C1 + +-2.0 1.0 -2.0 0.0 1.0 +-2.0 0.0 -2.0 0.0 0.0 +-2.0 0.0 -0.5 1.5 0.0 +-2.0 1.0 -2.0 0.0 1.0 +-2.0 1.0 -0.5 1.5 1.0 +-2.0 0.0 -0.5 1.5 0.0 + +// C2 + +-2.0 1.0 2.0 2.0 1.0 +-2.0 0.0 2.0 2.0 0.0 +-2.0 0.0 0.5 0.5 0.0 +-2.0 1.0 2.0 2.0 1.0 +-2.0 1.0 0.5 0.5 1.0 +-2.0 0.0 0.5 0.5 0.0 + +// D1 + +2.0 1.0 -2.0 0.0 1.0 +2.0 0.0 -2.0 0.0 0.0 +2.0 0.0 -0.5 1.5 0.0 +2.0 1.0 -2.0 0.0 1.0 +2.0 1.0 -0.5 1.5 1.0 +2.0 0.0 -0.5 1.5 0.0 + +// D2 + +2.0 1.0 2.0 2.0 1.0 +2.0 0.0 2.0 2.0 0.0 +2.0 0.0 0.5 0.5 0.0 +2.0 1.0 2.0 2.0 1.0 +2.0 1.0 0.5 0.5 1.0 +2.0 0.0 0.5 0.5 0.0 + +// Upper hallway - L +-0.5 1.0 -3.0 0.0 1.0 +-0.5 0.0 -3.0 0.0 0.0 +-0.5 0.0 -2.0 1.0 0.0 +-0.5 1.0 -3.0 0.0 1.0 +-0.5 1.0 -2.0 1.0 1.0 +-0.5 0.0 -2.0 1.0 0.0 + +// Upper hallway - R +0.5 1.0 -3.0 0.0 1.0 +0.5 0.0 -3.0 0.0 0.0 +0.5 0.0 -2.0 1.0 0.0 +0.5 1.0 -3.0 0.0 1.0 +0.5 1.0 -2.0 1.0 1.0 +0.5 0.0 -2.0 1.0 0.0 + +// Lower hallway - L +-0.5 1.0 3.0 0.0 1.0 +-0.5 0.0 3.0 0.0 0.0 +-0.5 0.0 2.0 1.0 0.0 +-0.5 1.0 3.0 0.0 1.0 +-0.5 1.0 2.0 1.0 1.0 +-0.5 0.0 2.0 1.0 0.0 + +// Lower hallway - R +0.5 1.0 3.0 0.0 1.0 +0.5 0.0 3.0 0.0 0.0 +0.5 0.0 2.0 1.0 0.0 +0.5 1.0 3.0 0.0 1.0 +0.5 1.0 2.0 1.0 1.0 +0.5 0.0 2.0 1.0 0.0 + + +// Left hallway - Lw + +-3.0 1.0 0.5 1.0 1.0 +-3.0 0.0 0.5 1.0 0.0 +-2.0 0.0 0.5 0.0 0.0 +-3.0 1.0 0.5 1.0 1.0 +-2.0 1.0 0.5 0.0 1.0 +-2.0 0.0 0.5 0.0 0.0 + +// Left hallway - Hi + +-3.0 1.0 -0.5 1.0 1.0 +-3.0 0.0 -0.5 1.0 0.0 +-2.0 0.0 -0.5 0.0 0.0 +-3.0 1.0 -0.5 1.0 1.0 +-2.0 1.0 -0.5 0.0 1.0 +-2.0 0.0 -0.5 0.0 0.0 + +// Right hallway - Lw + +3.0 1.0 0.5 1.0 1.0 +3.0 0.0 0.5 1.0 0.0 +2.0 0.0 0.5 0.0 0.0 +3.0 1.0 0.5 1.0 1.0 +2.0 1.0 0.5 0.0 1.0 +2.0 0.0 0.5 0.0 0.0 + +// Right hallway - Hi + +3.0 1.0 -0.5 1.0 1.0 +3.0 0.0 -0.5 1.0 0.0 +2.0 0.0 -0.5 0.0 0.0 +3.0 1.0 -0.5 1.0 1.0 +2.0 1.0 -0.5 0.0 1.0 +2.0 0.0 -0.5 0.0 0.0 \ No newline at end of file diff --git a/data/shaders/lesson2.metallib b/data/shaders/lesson2.metallib new file mode 100644 index 0000000000000000000000000000000000000000..0a3f31e539d4d46de8fe0677cd569cc495bf4952 GIT binary patch literal 5374 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 literal 0 HcmV?d00001 diff --git a/data/shaders/lesson6.metallib b/data/shaders/lesson6.metallib new file mode 100644 index 0000000000000000000000000000000000000000..e5bd78fe64e37aa6d78376df87fff619df4750f6 GIT binary patch literal 6298 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 R!jbzvb2D?)O3i)p{1^RT4p0C9 literal 0 HcmV?d00001 diff --git a/data/shaders/lesson7.metallib b/data/shaders/lesson7.metallib new file mode 100644 index 0000000000000000000000000000000000000000..cb46b926e559b83731b8ba0fa96e1b6cf9006b2c GIT binary patch literal 7044 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 E0Cu7w8vpt-{Lo(J^bhQ z>dbW8lj8*bbLS3<^8bLJRZ}FZz$`XX6f!3WAX!WEJHd3JfFO@TvARj_U z032%2_9Oh#C6*Zh9YJ=H5yYnnbH62jXh*eShs6%cMk*^Nsg2Z3f5?-@;Zt5H(gb9B zq__E`_pxFE5^3y>-Z2^BQg5RmY-pQ?&JifXQHRv8sNd8t8eSq^*j5N`6_g!ve@4uoa`7j$+yxR(lV~KTBGkHiJf4L&O3_*qu2$d;2#vTSL>p*$Z6qGA!Rw@G zoe5VO@%TuzR*Kgm3u69NGZ(S(X3V}$G2dq9jhcO3v%Co_Z^6u+Gy9Hec@t*dl!Z5A z)0>V_J(TF!j zq8bHWSFUT2;wlBM#PIkr!m7INUvz(Z7F6@+1Y8%14~AX1UsN~RNW*Iiz(FFCjgfeb z39kbmArwMX6^S+wiqQR$D8fXJ@xdOOl?!ep6Iu^{W7ID-Xrud&xG6&$Suoa6xPYn(Lm}Qu z6ABkly+?xV-d5Rtt;~Bw$(TyfU7}>ndnC)4YB1ooZ8GM)ikJ;gM5;wfyh~am$IDR=sgI7fMFh%n0Lqd;S4asvG&2uZoGdPzT zmyI9|Fy2s@G=j-Ftj<5LKPeo1dob?oJA$k*si;`UXmYtGM@3Vk3${to;^^G`#LTp) ztVC8)R#;i26y>@boTIyL-`dtnYZDHYH_w+-1Gki_<&_fF>*dW^<yRH)=dm8BBOmsn6}EkpHPns=g$`f#%Eu@7?_1GKRF*5F`OTt zVf6137aV=%+~n?%!r%BL(tGwD%emHhc7xjbE=eJS4^5NyctZYd{^p*<`1lx9+V!8fep> z6$U>w_3~$|%xA;18^fgs*)1StvU6m-b9VpPi{sXdsmZ_v0vu+zHlPpy@Wx5A#P*$oV16saf&5r>)SjLW_}j3lk*wt4NmYePI#>Gf=O`n7^g3L!X32c zkyrPRU$J)XKY#qo&adx@zjyKG6x9z$H-8k>Tl{21_KwygbMe_h^YQsv;peLkJ>sl- ztCGf!)5lTUF411Z4r}wM{=w3UvGBIwxRyETZ!xid$P!_q-&Jl0-+Ek8c% z$nt!AMn!9DIdz2ImmpgazvD_**>c3CVN*4Y6L%2AhQu|`Jt_&4mSCM)3c4*guDOr8 zMUb?OD>a6r`)m_)g%i{B3%2Ru(Z5VMq#qw29Ix4^db!s}6%w^M)E;7sYt2C0!Y*nl z8*7CbhixK%^6S2RNyck3{nv>9+F8=?-;aMk?o`6*n1o~_d`n3iwpUasDoZg*R1}t% zE*48D70gz48(+FlxK2WUo!PgcyUWinWk8p9QWtX4o??`w4M>tsX_E#diLcmGbG(}T zyjNTM$VnZ#lrejUjD4b6lI+lhOiGd*_S8Om$|-w?hAnP!--HKG*^@qo$0bR(n$kLS zsZL4q8C^<_m%(p)VxKPclr`~;B*h|021U1QDHd{?TS96MhtmYB)@%jel z5n_%w4rMG&!yTICmIaW~^peD8yCL1Z5URRs=<^8kD;DEB4I`GG4$B^_o!l~^r@Naj z#7RzbNYV`CG-tg*tw8tEP*{%@3RslLwe`3H!#Per#-foiD`Zv+nU|LsOSz0#)(~$7 zvJe5!Cg+z4pHBfF#w1B6$*E^_sm( zIt~6btUGL6*^M`JYoo6%F|N57-&+`qLUNIV$T_%9_jy{*g=}L;%NvzbKQTf~B}v`x z^C^2`ha^!?PU*1!29(}vO8JVyGr7hv9~4;NRnUCr8slLR~?bzb@ga{ z_tu>6j7%Z|{Ac;2a_)kFNQn-RAVuRk1-vCWHLpdN=(MK{NYWr6w`{3%k`z5u?S>D$ z!BZS^J2hl=k*Km;TX>npShO&%1PToy8*`mKxlrHe6_ z%eWy7`+QN(wP|^ivq6gj-n@V}B;dgtTo621hP|3{Mv``l7{p1=f-~^;!CA;h8l`xh z0-}dAuCN$OZfpNt$oSUC_zofvDWu_QBbp$@8x=&drLIToZnUT%f$N7rp)e$o8f;|= zq?*oT#Q7cZ!d~<&MEq|yeUz6GceCZ`k54~+Qgwe8)@-DGg0I7$AJRFN;lp&E$#0mW_IoWS(nyOxojJ&*N>&55Rc$OOF ziQES~ZW?yv?PND=C1OrVV#i3cXhUGY66fu))L0?;`KB0$CAG&(yYDTUEA}71e$g8I zmN*MK>iho%I_6WLVYmhox!bhInW#5vIlsU~Mn?lJ-$K zZ9*B@hktXDWqIaII%C+x{43@g8L6XNIj6LqMcD7ftt8*iEgnMSN_WGf{bZk1cXy+p zMwdFEX(t+nqyC04^2BSFG+-QS%*roVqJG0EVPCZ{qsz%R=`jIyEbqX6Ehs#cih256 z5N*)W-&{g_Wo0bKGe+~8bZbDR&s?ly$-CF+P4)cd#Bt3_o{W9b1+HSP$AdnM8wD~j z&>WZ};6_Fk)3k{OHcOPtuyQ3)lsRFmsN1e5ktho+=XyFR*&yIv78Z#RYcfSem*g^v zY2Hahe;4$(v%2k-kl{;F5Yr>Mz8*M@m=gd|lrUwL-$p)yc`RIDo+&eT3gOQH0c!c9fP5xm?wvCG zLWdP51em#psX(CWKj$b54_1NsUxFVuD|X}RM6?d(sB$v!QUlPzFS+l=ML7AF_mCSHT{jN^tY%lqk~)SQd}G z5Q7;BG)-w(#He@-p<|?r)Lxp#vp=5QN&p)v>2J{RJA^IrAef9`HG=!ytVYj}=dcgi zpz3Be9+dwjvq=e5qX@}DgNSCQHLViYj~RsztnvHjv|AssNkV-tC1~UJ46pVdHzVIh zXMFcWF~x$}1OZ`mfBLbwY!>jCRoG++2xn*H?{1nFS%3w8<*)xs{@Qwnzf$kzFJf`J zkH3lt{vz0`6xxWKY7WZ#xr-VmLL~nq?lKC8WR%xrx4EldM#+->9qwBAJKUxDZ*v!E zmpl1)bPgWw9N9nKGV*HY_|M_1SQ|K8mK96U2A65L3!G39t7jlCDd^PugK?)%CL}!U zhD6xkD^+$7$@uilUt9p4uF>IziN(?K?h|KQ#>b5W0T4(>&|H|u_4p(1pU=A9IZxe@{o&$m67$4YLCxTJeEwW?%M*Z>K7~Eg+`>=U zPaS=V;~V?l`@&>S=uew{lJG1|j8qpr(VwZ=PBeF}fzs+p!vK0}4 zSFImn=Ti5NQL2pOG^3}MbcFEmbWG~$=SblzMt0q(uo9u<v@w_{*={sYL@3P z^I?~9+5&3~_kx`N8pTR$S#5=l#!=W5ly4Fm3Ty)2oR!#yoRjk>U>%Zg5*bV@H{n58 z53a)FX6^wiv0_2G35oJ+lwtipa3Ry3mT_myJXkhB(Scc>OS>Y0{~BFyGssqi5Id2u zsDLF}u%Qw@$6s0JSJwG|%{s)sUf=*pI!B}gLy!4g%E%nr!#vOu^lmlc3?fk_aqV6h z{GUONA+QU5hj##hkdFayE<%#9urn;M1& literal 0 HcmV?d00001 diff --git a/scripts/compile_shaders.py b/scripts/compile_shaders.py new file mode 100755 index 0000000..32399f5 --- /dev/null +++ b/scripts/compile_shaders.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +""" +SPDX-FileCopyrightText: (C) 2025 a dinosaur +SPDX-License-Identifier: Zlib +""" + +import os +import shutil +import sys +from collections import namedtuple +from pathlib import Path +import subprocess +import platform +from typing import Iterable + + +def compile_metal_shaders( + sources: list[str | Path], library: str | Path, + cflags: list[str] = None, sdk="macosx", debug: bool = False, cwd: Path | None = None) -> None: + """Build a Metal shader library from a list of Metal shaders + + :param sources: List of Metal shader source paths + :param library: Path to the Metal library to build + :param cflags: Optional list of additional compiler parameters + :param sdk: Name of the Xcode platform SDK to use (default: "macosx"), + can be "macosx", "iphoneos", "iphonesimulator", "appletvos", or "appletvsimulator" + :param debug: Generate a symbol file that can be used to debug the shader library + :param cwd: Optionally set the current working directory for the compiler + """ + if cflags is None: + cflags = [] + + def xcrun_find_program(name: str): + return subprocess.run(["xcrun", "-sdk", sdk, "-f", name], + capture_output=True, check=True).stdout.decode("utf-8").strip() + + # Find Metal compilers + metal = xcrun_find_program("metal") + if debug: + metal_dsymutil = xcrun_find_program("metal-dsymutil") + else: + metallib = xcrun_find_program("metallib") + + # Compile each source to an AIR (Apple Intermediate Representation) + cflags = cflags + ["-frecord-sources"] + air_objects = [f"{str(s).removesuffix('.metal')}.air" for s in sources] + for src, obj in zip(sources, air_objects): + subprocess.run([metal, *cflags, "-c", src, "-o", obj], cwd=cwd, check=True) + + try: + # Build the Metal library + if debug: + subprocess.run([metal, "-frecord-sources", "-o", library, *air_objects], cwd=cwd, check=True) + subprocess.run([metal_dsymutil, "-flat", "-remove-source", library], cwd=cwd, check=True) + else: + subprocess.run([metallib, "-o", library, *air_objects], cwd=cwd, check=True) + finally: + # Clean up AIR objects + for obj in air_objects: + cwd.joinpath(obj).unlink() + + +Shader = namedtuple("Shader", ["source", "type", "output"]) + + +def shaders_suffixes(shaders: list[Shader], + in_suffix: str | None, out_suffix: str | None) -> Iterable[Shader]: + """Add file extensions to the source and outputs of a list of shaders + + :param shaders: The list of Shader tuples + :param in_suffix: Optional file extension to append to source + :param out_suffix: Optional file extension to append to output + :return: Generator with the modified shaders + """ + for s in shaders: + yield Shader( + f"{s.source}.{in_suffix}" if in_suffix else s.source, + s.type, + f"{s.output}.{out_suffix}" if out_suffix else s.output) + + +def compile_spirv_shaders(shaders: Iterable[Shader], + flags: list[str] = None, glslang: str | None=None, cwd: Path | None = None) -> None: + """Compile shaders to SPIR-V using glslang + + :param shaders: The list of shader source paths to compile + :param flags: List of additional flags to pass to glslang + :param glslang: Optional path to glslang executable, if `None` defaults to "glslang" + :param cwd: Optionally set the current working directory for the compiler + """ + if glslang is None: + glslang = "glslang" + if flags is None: + flags = [] + + for shader in shaders: + sflags = [*flags, "-V", "-S", shader.type, "-o", shader.output, shader.source] + subprocess.run([glslang, *sflags], cwd=cwd, check=True) + + +def compile_dxil_shaders(shaders: Iterable[Shader], dxc: str | None = None, cwd: Path | None = None) -> None: + """Compile HLSL shaders to DXIL using DXC + + :param shaders: The list of shader source paths to compile + :param dxc: Optional path to dxc excutable, if `None` defaults to "dxc" + :param cwd: Optionally set the current working directory for the compiler + """ + if dxc is None: + dxc = "dxc" + for shader in shaders: + entry, shader_type = { + "vert": ("VertexMain", "vs_6_0"), + "frag": ("FragmentMain", "ps_6_0") }[shader.type] + cflags = ["-E", entry, "-T", shader_type] + subprocess.run([dxc, *cflags, "-Fo", shader.output, shader.source], cwd=cwd, check=True) + + +def compile_dxbc_shaders(shaders: Iterable[Shader], cwd: Path | None = None) -> None: + """Compile HLSL shaders to DXBC using FXC + + :param shaders: The list of shader source paths to compile + :param cwd: Optionally set the current working directory for the compiler + """ + for shader in shaders: + entry, shader_type = { + "vert": ("VertexMain", "vs_5_1"), + "frag": ("FragmentMain", "ps_5_1") }[shader.type] + cflags = ["/E", entry, "/T", shader_type] + subprocess.run(["fxc", *cflags, "/Fo", shader.output, shader.source], cwd=cwd, check=True) + + +def compile_shaders() -> None: + build_spirv = False + build_metal = True + build_dxil = False + build_dxbc = False + lessons = [ "lesson2", "lesson3", "lesson6", "lesson7", "lesson9" ] + src_dir = Path("src/shaders") + dest_dir = Path("data/shaders") + + system = platform.system() + def add_shaders() -> Iterable[Shader]: + for lesson in lessons: + yield Shader(src_dir / f"{lesson}.vertex", "vert", dest_dir / f"{lesson}.vertex") + yield Shader(src_dir / f"{lesson}.fragment", "frag", dest_dir / f"{lesson}.fragment") + shaders = list(add_shaders()) + + root = Path(sys.argv[0]).resolve().parent.parent + root.joinpath(dest_dir).mkdir(parents=True, exist_ok=True) + + # Try to find cross-platform shader compilers + glslang = shutil.which("glslang") + dxc = shutil.which("dxc", path=f"/opt/dxc/bin:{os.environ.get('PATH', os.defpath)}") + + if build_spirv: + # Build SPIR-V shaders for Vulkan + compile_spirv_shaders(shaders_suffixes(shaders, "glsl", "spv"), + flags=["--quiet"], glslang=glslang, cwd=root) + + if build_metal: + # Build Metal shaders on macOS + if system == "Darwin": + compile_platform = "macos" + sdk_platform = "macosx" + min_version = "10.11" + for lesson in lessons: + compile_metal_shaders( + sources=[src_dir / f"{lesson}.metal"], + library=dest_dir / f"{lesson}.metallib", + cflags=["-Wall", "-O3", + f"-std={compile_platform}-metal1.1", + f"-m{sdk_platform}-version-min={min_version}"], + sdk=sdk_platform, + cwd=root) + + if build_dxil: + # Build HLSL shaders on Windows or when DXC is available + if system == "Windows" or dxc is not None: + compile_dxil_shaders(shaders_suffixes(shaders, "hlsl", "dxb"), dxc=dxc, cwd=root) + if build_dxbc: + if system == "Windows": # FXC is only available thru the Windows SDK + compile_dxbc_shaders(shaders_suffixes(shaders, "hlsl", "fxb"), cwd=root) + + +if __name__ == "__main__": + compile_shaders() diff --git a/src/c/CMakeLists.txt b/src/c/CMakeLists.txt new file mode 100644 index 0000000..9f88703 --- /dev/null +++ b/src/c/CMakeLists.txt @@ -0,0 +1,12 @@ +include(AddLesson) + +add_lesson(lesson1 SOURCES lesson1.c) +add_lesson(lesson2 SOURCES lesson2.c SHADERS lesson2.metallib) +add_lesson(lesson3 SOURCES lesson3.c SHADERS lesson3.metallib) +add_lesson(lesson4 SOURCES lesson4.c SHADERS lesson3.metallib) +add_lesson(lesson5 SOURCES lesson5.c SHADERS lesson3.metallib) +add_lesson(lesson6 SOURCES lesson6.c SHADERS lesson6.metallib DATA NeHe.bmp) +add_lesson(lesson7 SOURCES lesson7.c SHADERS lesson6.metallib lesson7.metallib DATA Crate.bmp) +add_lesson(lesson8 SOURCES lesson8.c SHADERS lesson6.metallib lesson7.metallib DATA Glass.bmp) +add_lesson(lesson9 SOURCES lesson9.c SHADERS lesson6.metallib lesson9.metallib DATA Star.bmp) +add_lesson(lesson10 SOURCES lesson10.c SHADERS lesson6.metallib DATA Mud.bmp World.txt) diff --git a/src/c/application.c b/src/c/application.c new file mode 100644 index 0000000..52ad65e --- /dev/null +++ b/src/c/application.c @@ -0,0 +1,211 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" +#define SDL_MAIN_USE_CALLBACKS +#include + + +typedef struct +{ + NeHeContext ctx; + bool fullscreen; +} AppState; + +SDL_AppResult SDLCALL SDL_AppInit(void** appstate, int argc, char* argv[]) +{ + (void)argc; (void)argv; + + // Initialise SDL + if (!SDL_Init(SDL_INIT_VIDEO)) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + SDL_SetCurrentThreadPriority(SDL_THREAD_PRIORITY_HIGH); + + // Allocate application context + AppState* s = *appstate = SDL_malloc(sizeof(AppState)); + if (!s) + { + return SDL_APP_FAILURE; + } + *s = (AppState) + { + .ctx = (NeHeContext) + { + .window = NULL, + .device = NULL + }, + .fullscreen = false + }; + NeHeContext* ctx = &s->ctx; + ctx->baseDir = SDL_GetBasePath(); // Resources directory + + // Initialise GPU context + if (!NeHe_InitGPU(ctx, appConfig.title, appConfig.width, appConfig.height)) + { + return SDL_APP_FAILURE; + } + + // Handle depth buffer texture creation if requested + if (appConfig.createDepthFormat != SDL_GPU_TEXTUREFORMAT_INVALID) + { + unsigned backbufWidth, backbufHeight; + SDL_GetWindowSizeInPixels(ctx->window, (int*)&backbufWidth, (int*)&backbufHeight); + if (!NeHe_SetupDepthTexture(ctx, backbufWidth, backbufHeight, appConfig.createDepthFormat, 1.0f)) + { + return false; + } + } + + if (appConfig.init) + { + if (!appConfig.init(ctx)) + { + return SDL_APP_FAILURE; + } + } + + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDLCALL SDL_AppIterate(void* appstate) +{ + NeHeContext* ctx = &((AppState*)appstate)->ctx; + SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(ctx->device); + if (!cmdbuf) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_AcquireGPUCommandBuffer: %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + SDL_GPUTexture* swapchainTex = NULL; + uint32_t swapchainWidth, swapchainHeight; + if (!SDL_WaitAndAcquireGPUSwapchainTexture(cmdbuf, ctx->window, &swapchainTex, &swapchainWidth, &swapchainHeight)) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_WaitAndAcquireGPUSwapchainTexture: %s", SDL_GetError()); + SDL_CancelGPUCommandBuffer(cmdbuf); + return SDL_APP_FAILURE; + } + if (!swapchainTex) + { + SDL_CancelGPUCommandBuffer(cmdbuf); + return SDL_APP_CONTINUE; + } + + if (appConfig.createDepthFormat != SDL_GPU_TEXTUREFORMAT_INVALID && ctx->depthTexture + && (ctx->depthTextureWidth != swapchainWidth || ctx->depthTextureHeight != swapchainHeight)) + { + if (!NeHe_SetupDepthTexture(ctx, swapchainWidth, swapchainHeight, appConfig.createDepthFormat, 1.0f)) + { + SDL_CancelGPUCommandBuffer(cmdbuf); + return SDL_APP_FAILURE; + } + } + + if (appConfig.draw) + { + appConfig.draw(ctx, cmdbuf, swapchainTex); + } + + SDL_SubmitGPUCommandBuffer(cmdbuf); + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDLCALL SDL_AppEvent(void* appstate, SDL_Event* event) +{ + AppState* s = appstate; + + switch (event->type) + { + case SDL_EVENT_QUIT: + return SDL_APP_SUCCESS; + case SDL_EVENT_WINDOW_ENTER_FULLSCREEN: + case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN: + s->fullscreen = event->type == SDL_EVENT_WINDOW_ENTER_FULLSCREEN; + return SDL_APP_CONTINUE; + case SDL_EVENT_KEY_DOWN: + if (event->key.key == SDLK_ESCAPE) + { + return SDL_APP_SUCCESS; + } + if (event->key.key == SDLK_F1) + { + SDL_SetWindowFullscreen(s->ctx.window, !s->fullscreen); + return SDL_APP_CONTINUE; + } + // Fallthrough + case SDL_EVENT_KEY_UP: + if (appConfig.key) + { + appConfig.key(&s->ctx, event->key.key, event->key.down, event->key.repeat); + } + return SDL_APP_CONTINUE; + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + if (appConfig.resize) + { + appConfig.resize(&s->ctx, event->window.data1, event->window.data2); + } + return SDL_APP_CONTINUE; + default: + return SDL_APP_CONTINUE; + } +} + +void SDLCALL SDL_AppQuit(void* appstate, SDL_AppResult result) +{ + (void)result; + + if (appstate) + { + NeHeContext* ctx = &((AppState*)appstate)->ctx; + if (appConfig.quit) + { + appConfig.quit(ctx); + } + if (appConfig.createDepthFormat != SDL_GPU_TEXTUREFORMAT_INVALID && ctx->depthTexture) + { + SDL_ReleaseGPUTexture(ctx->device, ctx->depthTexture); + } + SDL_ReleaseWindowFromGPUDevice(ctx->device, ctx->window); + SDL_DestroyGPUDevice(ctx->device); + SDL_DestroyWindow(ctx->window); + SDL_free(ctx); + } + SDL_Quit(); +} + + +#ifndef SDL_MAIN_USE_CALLBACKS +int main(int argc, char* argv[]) +{ + void* appstate = NULL; + SDL_AppResult res; + if ((res = SDL_AppInit(&appstate, argc, argv)) != SDL_APP_CONTINUE) + { + goto Quit; + } + while (true) + { + SDL_Event event; + while (SDL_PollEvent(&event)) + { + if ((res = SDL_AppEvent(appstate, &event)) != SDL_APP_CONTINUE) + { + goto Quit; + } + } + if ((res = SDL_AppIterate(appstate)) != SDL_APP_CONTINUE) + { + goto Quit; + } + } +Quit: + SDL_AppQuit(appstate, res); + return res == SDL_APP_SUCCESS ? 0 : 1; +} +#endif diff --git a/src/c/application.h b/src/c/application.h new file mode 100644 index 0000000..b431084 --- /dev/null +++ b/src/c/application.h @@ -0,0 +1,22 @@ +#ifndef APPLICATION_H +#define APPLICATION_H + +#include +#include +#include + +struct NeHeContext; + +extern const struct AppConfig +{ + const char* const title; + int width, height; + SDL_GPUTextureFormat createDepthFormat; + bool (*init)(struct NeHeContext*); + void (*quit)(struct NeHeContext*); + void (*resize)(struct NeHeContext*, int width, int height); + void (*draw)(struct NeHeContext* restrict, SDL_GPUCommandBuffer* restrict, SDL_GPUTexture* restrict); + void (*key)(struct NeHeContext*, SDL_Keycode, bool down, bool repeat); +} appConfig; + +#endif//APPLICATION_H diff --git a/src/c/lesson1.c b/src/c/lesson1.c new file mode 100644 index 0000000..d9a9908 --- /dev/null +++ b/src/c/lesson1.c @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" + + +static void Lesson1_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + (void)ctx; + + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.5f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, NULL); + SDL_EndGPURenderPass(pass); +} + + +const struct AppConfig appConfig = +{ + .title = "NeHe's OpenGL Framework", + .width = 640, .height = 480, + .init = NULL, + .quit = NULL, + .resize = NULL, + .draw = Lesson1_Draw +}; diff --git a/src/c/lesson10.c b/src/c/lesson10.c new file mode 100644 index 0000000..2428cd8 --- /dev/null +++ b/src/c/lesson10.c @@ -0,0 +1,392 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" +#include + + +typedef struct +{ + float x, y, z; + float u, v; +} Vertex; + +typedef struct +{ + Vertex vertices[3]; +} Triangle; + +typedef struct +{ + int numTriangles; + Triangle* tris; +} Sector; + +typedef struct +{ + float x, z; + float yaw, pitch; + float walkBob, walkBobTheta; +} Camera; + + +static SDL_GPUGraphicsPipeline* pso = NULL, * psoBlend = NULL; +static SDL_GPUBuffer* vtxBuffer = NULL; +static SDL_GPUTexture* texture = NULL; +static SDL_GPUSampler* samplers[3] = { NULL, NULL, NULL }; + +static bool blend = false; +static unsigned filter = 0; + +static float projection[16]; +static Camera camera = +{ + .x = 0.0f, .z = 0.0f, + .yaw = 0.0f, .pitch = 0.0f, + .walkBob = 0.0f, .walkBobTheta = 0.0f +}; +static Sector world = { .numTriangles = 0, .tris = NULL }; + + +static void ReadLine(SDL_IOStream* restrict file, char* restrict str, int max) +{ + do + { + char* p = str; + for (int n = max - 1; n > 0; --n) + { + int8_t c; + if (!SDL_ReadS8(file, &c)) + break; + (*p++) = c; + if (c == '\n') + break; + } + (*p) = '\0'; + } while (str[0] == '/' || str[0] == '\n' || str[0] == '\r'); +} + +static void SetupWorld(const NeHeContext* ctx) +{ + SDL_IOStream* file = NeHe_OpenResource(ctx, "Data/World.txt", "r"); + if (!file) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open \"%s\": %s", "Data/World.txt", SDL_GetError()); + return; + } + + int numTris; + char line[255]; + ReadLine(file, line, sizeof(line)); + SDL_sscanf(line, "NUMPOLLIES %d\n", &numTris); + + world.tris = SDL_malloc(sizeof(Triangle) * (size_t)numTris); + world.numTriangles = numTris; + for (int tri = 0; tri < numTris; ++tri) + { + for (int vtx = 0; vtx < 3; ++vtx) + { + ReadLine(file, line, sizeof(line)); + SDL_sscanf(line, "%f %f %f %f %f", + &world.tris[tri].vertices[vtx].x, + &world.tris[tri].vertices[vtx].y, + &world.tris[tri].vertices[vtx].z, + &world.tris[tri].vertices[vtx].u, + &world.tris[tri].vertices[vtx].v); + } + } +} + + +static bool Lesson10_Init(NeHeContext* ctx) +{ + SetupWorld(ctx); + + SDL_GPUShader* vertexShader, * fragmentShader; + if (!NeHe_LoadShaders(ctx, &vertexShader, &fragmentShader, "lesson6", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1, .fragmentSamplers = 1 })) + { + return false; + } + + const SDL_GPUVertexAttribute vertexAttribs[] = + { + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, x) + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, + .offset = offsetof(Vertex, u) + } + }; + SDL_GPUGraphicsPipelineCreateInfo info = + { + .vertex_shader = vertexShader, + .fragment_shader = fragmentShader, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .vertex_input_state = + { + .vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription) + { + .slot = 0, + .pitch = sizeof(Vertex), + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX + }, + .num_vertex_buffers = 1, + .vertex_attributes = vertexAttribs, + .num_vertex_attributes = SDL_arraysize(vertexAttribs) + }, + .rasterizer_state = + { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_NONE, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE // Right-handed coordinates + }, + .target_info = + { + .num_color_targets = 1 + } + }; + + // Setup blend pipeline + const SDL_GPUTextureFormat swapchainTextureFormat = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window); + info.target_info.color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = swapchainTextureFormat, + .blend_state = + { + .enable_blend = true, + .color_blend_op = SDL_GPU_BLENDOP_ADD, + .alpha_blend_op = SDL_GPU_BLENDOP_ADD, + .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE, + .src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE + } + }; + psoBlend = SDL_CreateGPUGraphicsPipeline(ctx->device, &info); + if (!psoBlend) + { + SDL_ReleaseGPUShader(ctx->device, fragmentShader); + SDL_ReleaseGPUShader(ctx->device, vertexShader); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + // Setup regular pipeline w/ depth testing + info.depth_stencil_state = (SDL_GPUDepthStencilState) + { + .compare_op = SDL_GPU_COMPAREOP_LESS, // Pass if pixel depth value tests less than the depth buffer value + .enable_depth_test = true, // Enable depth testing + .enable_depth_write = true + }; + info.target_info.color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = swapchainTextureFormat + }; + info.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM; + info.target_info.has_depth_stencil_target = true; + pso = SDL_CreateGPUGraphicsPipeline(ctx->device, &info); + SDL_ReleaseGPUShader(ctx->device, fragmentShader); + SDL_ReleaseGPUShader(ctx->device, vertexShader); + if (!pso) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + if ((texture = NeHe_LoadTexture(ctx, "Data/Mud.bmp", true, true)) == NULL) + { + return false; + } + + samplers[0] = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_NEAREST, + .mag_filter = SDL_GPU_FILTER_NEAREST + }); + samplers[1] = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_LINEAR, + .mag_filter = SDL_GPU_FILTER_LINEAR + }); + samplers[2] = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_LINEAR, + .mag_filter = SDL_GPU_FILTER_LINEAR, + .mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, + .max_lod = FLT_MAX + }); + if (!samplers[0] || !samplers[1] || !samplers[2]) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUSampler: %s", SDL_GetError()); + return false; + } + + if ((vtxBuffer = NeHe_CreateVertexBuffer(ctx, world.tris, sizeof(Triangle) * (uint32_t)world.numTriangles)) == NULL) + { + return false; + } + + return true; +} + +static void Lesson10_Quit(NeHeContext* ctx) +{ + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + for (int i = SDL_arraysize(samplers) - 1; i > 0; --i) + { + SDL_ReleaseGPUSampler(ctx->device, samplers[i]); + } + SDL_ReleaseGPUTexture(ctx->device, texture); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, pso); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, psoBlend); + SDL_free(world.tris); +} + +static void Lesson10_Resize(NeHeContext* ctx, int width, int height) +{ + (void)ctx; + + // Avoid division by zero by clamping height + height = SDL_max(height, 1); + // Recalculate projection matrix + Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f); +} + +static void Lesson10_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.0f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + const SDL_GPUDepthStencilTargetInfo depthInfo = + { + .texture = ctx->depthTexture, + .clear_depth = 1.0f, // Ensure depth buffer clears to furthest value + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_DONT_CARE, + .stencil_load_op = SDL_GPU_LOADOP_DONT_CARE, + .stencil_store_op = SDL_GPU_STOREOP_DONT_CARE, + .cycle = true + }; + + // Begin pass & bind pipeline state + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, &depthInfo); + SDL_BindGPUGraphicsPipeline(pass, blend ? psoBlend : pso); + + // Bind texture + SDL_BindGPUFragmentSamplers(pass, 0, &(SDL_GPUTextureSamplerBinding) + { + .texture = texture, + .sampler = samplers[filter] + }, 1); + + // Bind world vertex buffer + SDL_BindGPUVertexBuffers(pass, 0, &(SDL_GPUBufferBinding) + { + .buffer = vtxBuffer, + .offset = 0 + }, 1); + + // Setup the camera view matrix + float modelView[16]; + Mtx_Rotation(modelView, camera.pitch, 1.0f, 0.0f, 0.0f); + Mtx_Rotate(modelView, 360.0f - camera.yaw, 0.0f, 1.0f, 0.0f); + Mtx_Translate(modelView, -camera.x, -(0.25f + camera.walkBob), -camera.z); + + // Push shader uniforms + struct { float modelViewProj[16], color[4]; } u; + Mtx_Multiply(u.modelViewProj, projection, modelView); + SDL_memcpy(u.color, (float[4]){ 1.0f, 1.0f, 1.0f, 1.0f }, sizeof(float) * 4); + SDL_PushGPUVertexUniformData(cmd, 0, &u, sizeof(u)); + + // Draw world + SDL_DrawGPUPrimitives(pass, 3u * (uint32_t)world.numTriangles, 1, 0, 0); + + SDL_EndGPURenderPass(pass); + + // Handle keyboard input + const bool *keys = SDL_GetKeyboardState(NULL); + + const float piover180 = 0.0174532925f; + + if (keys[SDL_SCANCODE_UP]) + { + camera.x -= SDL_sinf(camera.yaw * piover180) * 0.05f; + camera.z -= SDL_cosf(camera.yaw * piover180) * 0.05f; + if (camera.walkBobTheta >= 359.0f) + { + camera.walkBobTheta = 0.0f; + } + else + { + camera.walkBobTheta += 10.0f; + } + camera.walkBob = SDL_sinf(camera.walkBobTheta * piover180) / 20.0f; + } + + if (keys[SDL_SCANCODE_DOWN]) + { + camera.x += SDL_sinf(camera.yaw * piover180) * 0.05f; + camera.z += SDL_cosf(camera.yaw * piover180) * 0.05f; + if (camera.walkBobTheta <= 1.0f) + { + camera.walkBobTheta = 359.0f; + } + else + { + camera.walkBobTheta -= 10.0f; + } + camera.walkBob = SDL_sinf(camera.walkBobTheta * piover180) / 20.0f; + } + + if (keys[SDL_SCANCODE_LEFT]) { camera.yaw += 1.0f; } + if (keys[SDL_SCANCODE_RIGHT]) { camera.yaw -= 1.0f; } + if (keys[SDL_SCANCODE_PAGEUP]) { camera.pitch -= 1.0f; } + if (keys[SDL_SCANCODE_PAGEDOWN]) { camera.pitch += 1.0f; } +} + +static void Lesson10_Key(NeHeContext* ctx, SDL_Keycode key, bool down, bool repeat) +{ + (void)ctx; + + if (down && !repeat) + { + switch (key) + { + case SDLK_B: + blend = !blend; + break; + case SDLK_F: + filter = (filter + 1) % SDL_arraysize(samplers); + break; + default: + break; + } + } +} + + +const struct AppConfig appConfig = +{ + .title = "Lionel Brits & NeHe's 3D World Tutorial", + .width = 640, .height = 480, + .createDepthFormat = SDL_GPU_TEXTUREFORMAT_D16_UNORM, + .init = Lesson10_Init, + .quit = Lesson10_Quit, + .resize = Lesson10_Resize, + .draw = Lesson10_Draw, + .key = Lesson10_Key +}; diff --git a/src/c/lesson2.c b/src/c/lesson2.c new file mode 100644 index 0000000..53e5995 --- /dev/null +++ b/src/c/lesson2.c @@ -0,0 +1,182 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" + + +typedef struct +{ + float x, y, z; +} Vertex; + +static const Vertex vertices[] = +{ + // Triangle + { 0.0f, 1.0f, 0.0f }, // Top + { -1.0f, -1.0f, 0.0f }, // Bottom left + { 1.0f, -1.0f, 0.0f }, // Bottom right + // Quad + { -1.0f, 1.0f, 0.0f }, // Top left + { 1.0f, 1.0f, 0.0f }, // Top right + { 1.0f, -1.0f, 0.0f }, // Bottom right + { -1.0f, -1.0f, 0.0f } // Bottom left +}; + +static const uint16_t indices[] = +{ + // Triangle + 0, 1, 2, + // Quad + 3, 4, 5, 5, 6, 3 +}; + + +static SDL_GPUGraphicsPipeline* pso = NULL; +static SDL_GPUBuffer* vtxBuffer = NULL; +static SDL_GPUBuffer* idxBuffer = NULL; + +static float projection[16]; + + +static bool Lesson2_Init(NeHeContext* restrict ctx) +{ + SDL_GPUShader* vertexShader, * fragmentShader; + if (!NeHe_LoadShaders(ctx, &vertexShader, &fragmentShader, "lesson2", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1 })) + { + return false; + } + + const SDL_GPUVertexAttribute vertexAttribs[] = + { + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, x) + } + }; + pso = SDL_CreateGPUGraphicsPipeline(ctx->device, &(const SDL_GPUGraphicsPipelineCreateInfo) + { + .vertex_shader = vertexShader, + .fragment_shader = fragmentShader, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .vertex_input_state = + { + .vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription) + { + .slot = 0, + .pitch = sizeof(Vertex), + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX + }, + .num_vertex_buffers = 1, + .vertex_attributes = vertexAttribs, + .num_vertex_attributes = SDL_arraysize(vertexAttribs) + }, + .rasterizer_state = + { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_NONE, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE + }, + .target_info = + { + .color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window) + }, + .num_color_targets = 1, + } + }); + SDL_ReleaseGPUShader(ctx->device, fragmentShader); + SDL_ReleaseGPUShader(ctx->device, vertexShader); + if (!pso) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + if (!NeHe_CreateVertexIndexBuffer(ctx, &vtxBuffer, &idxBuffer, + vertices, sizeof(vertices), + indices, sizeof(indices))) + { + return false; + } + + return true; +} + +static void Lesson2_Quit(NeHeContext* restrict ctx) +{ + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, pso); +} + +static void Lesson2_Resize(NeHeContext* restrict ctx, int width, int height) +{ + (void)ctx; + + // Avoid division by zero by clamping height + height = SDL_max(height, 1); + // Recalculate projection matrix + Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f); +} + +static void Lesson2_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + (void)ctx; + + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.5f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + // Begin pass & bind pipeline state + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, NULL); + SDL_BindGPUGraphicsPipeline(pass, pso); + + // Bind vertex & index buffers + SDL_BindGPUVertexBuffers(pass, 0, &(const SDL_GPUBufferBinding) + { + .buffer = vtxBuffer, + .offset = 0 + }, 1); + SDL_BindGPUIndexBuffer(pass, &(const SDL_GPUBufferBinding) + { + .buffer = idxBuffer, + .offset = 0 + }, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + float model[16], viewproj[16]; + + // Draw triangle 1.5 units to the left and 6 units into the camera + Mtx_Translation(model, -1.5f, 0.0f, -6.0f); + Mtx_Multiply(viewproj, projection, model); + SDL_PushGPUVertexUniformData(cmd, 0, viewproj, sizeof(viewproj)); + SDL_DrawGPUIndexedPrimitives(pass, 3, 1, 0, 0, 0); + + // Move to the right by 3 units and draw quad + Mtx_Translate(model, 3.0f, 0.0f, 0.0f); + Mtx_Multiply(viewproj, projection, model); + SDL_PushGPUVertexUniformData(cmd, 0, viewproj, sizeof(viewproj)); + SDL_DrawGPUIndexedPrimitives(pass, 6, 1, 3, 0, 0); + + SDL_EndGPURenderPass(pass); +} + + +const struct AppConfig appConfig = +{ + .title = "NeHe's First Polygon Tutorial", + .width = 640, .height = 480, + .init = Lesson2_Init, + .quit = Lesson2_Quit, + .resize = Lesson2_Resize, + .draw = Lesson2_Draw +}; diff --git a/src/c/lesson3.c b/src/c/lesson3.c new file mode 100644 index 0000000..7a152cf --- /dev/null +++ b/src/c/lesson3.c @@ -0,0 +1,189 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" + + +typedef struct +{ + float x, y, z; + float r, g, b, a; +} Vertex; + +static const Vertex vertices[] = +{ + // Triangle + { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }, // Top (red) + { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f }, // Bottom left (green) + { 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f }, // Bottom right (blue) + // Quad + { -1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 1.0f, 1.0f }, // Top left + { 1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 1.0f, 1.0f }, // Top right + { 1.0f, -1.0f, 0.0f, 0.5f, 0.5f, 1.0f, 1.0f }, // Bottom right + { -1.0f, -1.0f, 0.0f, 0.5f, 0.5f, 1.0f, 1.0f } // Bottom left +}; + +static const uint16_t indices[] = +{ + // Triangle + 0, 1, 2, + // Quad + 3, 4, 5, 5, 6, 3 +}; + + +static SDL_GPUGraphicsPipeline* pso = NULL; +static SDL_GPUBuffer* vtxBuffer = NULL; +static SDL_GPUBuffer* idxBuffer = NULL; + +static float projection[16]; + + +static bool Lesson3_Init(NeHeContext* restrict ctx) +{ + SDL_GPUShader* vertexShader, * fragmentShader; + if (!NeHe_LoadShaders(ctx, &vertexShader, &fragmentShader, "lesson3", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1 })) + { + return false; + } + + const SDL_GPUVertexAttribute vertexAttribs[] = + { + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, x) + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4, + .offset = offsetof(Vertex, r) + } + }; + pso = SDL_CreateGPUGraphicsPipeline(ctx->device, &(const SDL_GPUGraphicsPipelineCreateInfo) + { + .vertex_shader = vertexShader, + .fragment_shader = fragmentShader, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .vertex_input_state = + { + .vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription) + { + .slot = 0, + .pitch = sizeof(Vertex), + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX + }, + .num_vertex_buffers = 1, + .vertex_attributes = vertexAttribs, + .num_vertex_attributes = SDL_arraysize(vertexAttribs) + }, + .rasterizer_state = + { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_NONE, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE + }, + .target_info = + { + .color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window) + }, + .num_color_targets = 1, + } + }); + SDL_ReleaseGPUShader(ctx->device, fragmentShader); + SDL_ReleaseGPUShader(ctx->device, vertexShader); + if (!pso) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + if (!NeHe_CreateVertexIndexBuffer(ctx, &vtxBuffer, &idxBuffer, + vertices, sizeof(vertices), + indices, sizeof(indices))) + { + return false; + } + + return true; +} + +static void Lesson3_Quit(NeHeContext* restrict ctx) +{ + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, pso); +} + +static void Lesson3_Resize(NeHeContext* restrict ctx, int width, int height) +{ + (void)ctx; + + // Avoid division by zero by clamping height + height = SDL_max(height, 1); + // Recalculate projection matrix + Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f); +} + +static void Lesson3_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + (void)ctx; + + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.5f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + // Begin pass & bind pipeline state + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, NULL); + SDL_BindGPUGraphicsPipeline(pass, pso); + + // Bind vertex & index buffers + SDL_BindGPUVertexBuffers(pass, 0, &(const SDL_GPUBufferBinding) + { + .buffer = vtxBuffer, + .offset = 0 + }, 1); + SDL_BindGPUIndexBuffer(pass, &(const SDL_GPUBufferBinding) + { + .buffer = idxBuffer, + .offset = 0 + }, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + float model[16], viewproj[16]; + + // Draw triangle 1.5 units to the left and 6 units into the camera + Mtx_Translation(model, -1.5f, 0.0f, -6.0f); + Mtx_Multiply(viewproj, projection, model); + SDL_PushGPUVertexUniformData(cmd, 0, viewproj, sizeof(viewproj)); + SDL_DrawGPUIndexedPrimitives(pass, 3, 1, 0, 0, 0); + + // Move to the right by 3 units and draw quad + Mtx_Translate(model, 3.0f, 0.0f, 0.0f); + Mtx_Multiply(viewproj, projection, model); + SDL_PushGPUVertexUniformData(cmd, 0, viewproj, sizeof(viewproj)); + SDL_DrawGPUIndexedPrimitives(pass, 6, 1, 3, 0, 0); + + SDL_EndGPURenderPass(pass); +} + + +const struct AppConfig appConfig = +{ + .title = "NeHe's Color Tutorial", + .width = 640, .height = 480, + .init = Lesson3_Init, + .quit = Lesson3_Quit, + .resize = Lesson3_Resize, + .draw = Lesson3_Draw +}; diff --git a/src/c/lesson4.c b/src/c/lesson4.c new file mode 100644 index 0000000..18c0917 --- /dev/null +++ b/src/c/lesson4.c @@ -0,0 +1,197 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" + + +typedef struct +{ + float x, y, z; + float r, g, b, a; +} Vertex; + +static const Vertex vertices[] = +{ + // Triangle + { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }, // Top (red) + { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f }, // Bottom left (green) + { 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f }, // Bottom right (blue) + // Quad + { -1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 1.0f, 1.0f }, // Top left + { 1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 1.0f, 1.0f }, // Top right + { 1.0f, -1.0f, 0.0f, 0.5f, 0.5f, 1.0f, 1.0f }, // Bottom right + { -1.0f, -1.0f, 0.0f, 0.5f, 0.5f, 1.0f, 1.0f } // Bottom left +}; + +static const uint16_t indices[] = +{ + // Triangle + 0, 1, 2, + // Quad + 3, 4, 5, 5, 6, 3 +}; + + +static SDL_GPUGraphicsPipeline* pso = NULL; +static SDL_GPUBuffer* vtxBuffer = NULL; +static SDL_GPUBuffer* idxBuffer = NULL; + +static float projection[16]; + +static float rotTri = 0.0f; +static float rotQuad = 0.0f; + + +static bool Lesson4_Init(NeHeContext* restrict ctx) +{ + SDL_GPUShader* vertexShader, * fragmentShader; + if (!NeHe_LoadShaders(ctx, &vertexShader, &fragmentShader, "lesson3", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1 })) + { + return false; + } + + const SDL_GPUVertexAttribute vertexAttribs[] = + { + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, x) + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4, + .offset = offsetof(Vertex, r) + } + }; + pso = SDL_CreateGPUGraphicsPipeline(ctx->device, &(const SDL_GPUGraphicsPipelineCreateInfo) + { + .vertex_shader = vertexShader, + .fragment_shader = fragmentShader, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .vertex_input_state = + { + .vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription) + { + .slot = 0, + .pitch = sizeof(Vertex), + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX + }, + .num_vertex_buffers = 1, + .vertex_attributes = vertexAttribs, + .num_vertex_attributes = SDL_arraysize(vertexAttribs) + }, + .rasterizer_state = + { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_NONE, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE + }, + .target_info = + { + .color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window) + }, + .num_color_targets = 1, + } + }); + SDL_ReleaseGPUShader(ctx->device, fragmentShader); + SDL_ReleaseGPUShader(ctx->device, vertexShader); + if (!pso) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + if (!NeHe_CreateVertexIndexBuffer(ctx, &vtxBuffer, &idxBuffer, + vertices, sizeof(vertices), + indices, sizeof(indices))) + { + return false; + } + + return true; +} + +static void Lesson4_Quit(NeHeContext* restrict ctx) +{ + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, pso); +} + +static void Lesson4_Resize(NeHeContext* restrict ctx, int width, int height) +{ + (void)ctx; + + // Avoid division by zero by clamping height + height = SDL_max(height, 1); + // Recalculate projection matrix + Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f); +} + +static void Lesson4_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + (void)ctx; + + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.5f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + // Begin pass & bind pipeline state + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, NULL); + SDL_BindGPUGraphicsPipeline(pass, pso); + + // Bind vertex & index buffers + SDL_BindGPUVertexBuffers(pass, 0, &(const SDL_GPUBufferBinding) + { + .buffer = vtxBuffer, + .offset = 0 + }, 1); + SDL_BindGPUIndexBuffer(pass, &(const SDL_GPUBufferBinding) + { + .buffer = idxBuffer, + .offset = 0 + }, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + float model[16], viewproj[16]; + + // Draw triangle 1.5 units to the left and 6 units into the camera + Mtx_Translation(model, -1.5f, 0.0f, -6.0f); + Mtx_Rotate(model, rotTri, 0.0f, 1.0f, 0.0f); + Mtx_Multiply(viewproj, projection, model); + SDL_PushGPUVertexUniformData(cmd, 0, viewproj, sizeof(viewproj)); + SDL_DrawGPUIndexedPrimitives(pass, 3, 1, 0, 0, 0); + + // Draw quad 1.5 units to the right and 6 units into the camera + Mtx_Translation(model, 1.5f, 0.0f, -6.0f); + Mtx_Rotate(model, rotQuad, 1.0f, 0.0f, 0.0f); + Mtx_Multiply(viewproj, projection, model); + SDL_PushGPUVertexUniformData(cmd, 0, viewproj, sizeof(viewproj)); + SDL_DrawGPUIndexedPrimitives(pass, 6, 1, 3, 0, 0); + + SDL_EndGPURenderPass(pass); + + rotTri += 0.2f; + rotQuad -= 0.15f; +} + + +const struct AppConfig appConfig = +{ + .title = "NeHe's Rotation Tutorial", + .width = 640, .height = 480, + .init = Lesson4_Init, + .quit = Lesson4_Quit, + .resize = Lesson4_Resize, + .draw = Lesson4_Draw +}; diff --git a/src/c/lesson5.c b/src/c/lesson5.c new file mode 100644 index 0000000..62ca955 --- /dev/null +++ b/src/c/lesson5.c @@ -0,0 +1,245 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" + + +typedef struct +{ + float x, y, z; + float r, g, b, a; +} Vertex; + +static const Vertex vertices[] = +{ + // Pyramid + { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }, // Top of pyramid (Red) + { -1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f }, // Front-left of pyramid (Green) + { 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, // Front-right of pyramid (Blue) + { 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f }, // Back-right of pyramid (Green) + { -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, // Back-left of pyramid (Blue) + // Cube + { 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f }, // Top-right of top face (Green) + { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f }, // Top-left of top face (Green) + { -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f }, // Bottom-left of top face (Green) + { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f }, // Bottom-right of top face (Green) + { 1.0f, -1.0f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f }, // Top-right of bottom face (Orange) + { -1.0f, -1.0f, 1.0f, 1.0f, 0.5f, 0.0f, 1.0f }, // Top-left of bottom face (Orange) + { -1.0f, -1.0f, -1.0f, 1.0f, 0.5f, 0.0f, 1.0f }, // Bottom-left of bottom face (Orange) + { 1.0f, -1.0f, -1.0f, 1.0f, 0.5f, 0.0f, 1.0f }, // Bottom-right of bottom face (Orange) + { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }, // Top-right of front face (Red) + { -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }, // Top-left of front face (Red) + { -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }, // Bottom-left of front face (Red) + { 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f }, // Bottom-right of front face (Red) + { 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f }, // Top-right of back face (Yellow) + { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f }, // Top-left of back face (Yellow) + { -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f }, // Bottom-left of back face (Yellow) + { 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f }, // Bottom-right of back face (Yellow) + { -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, // Top-right of left face (Blue) + { -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, // Top-left of left face (Blue) + { -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, // Bottom-left of left face (Blue) + { -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, // Bottom-right of left face (Blue) + { 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f }, // Top-right of right face (Violet) + { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }, // Top-left of right face (Violet) + { 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f }, // Bottom-left of right face (Violet) + { 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f } // Bottom-right of right face (Violet) +}; + +static const uint16_t indices[] = +{ + // Pyramid + 0, 1, 2, // Front + 0, 2, 3, // Right + 0, 3, 4, // Back + 0, 4, 1, // Left + // Cube + 5, 6, 7, 7, 8, 5, // Top + 9, 10, 11, 11, 12, 9, // Bottom + 13, 14, 15, 15, 16, 13, // Front + 17, 18, 19, 19, 20, 17, // Back + 21, 22, 23, 23, 24, 21, // Left + 25, 26, 27, 27, 28, 25 // Right +}; + + +static SDL_GPUGraphicsPipeline* pso = NULL; +static SDL_GPUBuffer* vtxBuffer = NULL; +static SDL_GPUBuffer* idxBuffer = NULL; + +static float projection[16]; + +static float rotTri = 0.0f; +static float rotQuad = 0.0f; + + +static bool Lesson5_Init(NeHeContext* restrict ctx) +{ + SDL_GPUShader* vertexShader, * fragmentShader; + if (!NeHe_LoadShaders(ctx, &vertexShader, &fragmentShader, "lesson3", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1 })) + { + return false; + } + + const SDL_GPUVertexAttribute vertexAttribs[] = + { + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, x) + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4, + .offset = offsetof(Vertex, r) + } + }; + pso = SDL_CreateGPUGraphicsPipeline(ctx->device, &(const SDL_GPUGraphicsPipelineCreateInfo) + { + .vertex_shader = vertexShader, + .fragment_shader = fragmentShader, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .vertex_input_state = + { + .vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription) + { + .slot = 0, + .pitch = sizeof(Vertex), + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX + }, + .num_vertex_buffers = 1, + .vertex_attributes = vertexAttribs, + .num_vertex_attributes = SDL_arraysize(vertexAttribs) + }, + .rasterizer_state = + { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_NONE, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE + }, + .depth_stencil_state = + { + .compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL, + .enable_depth_test = true, + .enable_depth_write = true + }, + .target_info = + { + .color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window) + }, + .num_color_targets = 1, + .depth_stencil_format = appConfig.createDepthFormat, + .has_depth_stencil_target = true + } + }); + SDL_ReleaseGPUShader(ctx->device, fragmentShader); + SDL_ReleaseGPUShader(ctx->device, vertexShader); + if (!pso) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + if (!NeHe_CreateVertexIndexBuffer(ctx, &vtxBuffer, &idxBuffer, + vertices, sizeof(vertices), + indices, sizeof(indices))) + { + return false; + } + + return true; +} + +static void Lesson5_Quit(NeHeContext* restrict ctx) +{ + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, pso); +} + +static void Lesson5_Resize(NeHeContext* restrict ctx, int width, int height) +{ + (void)ctx; + + // Avoid division by zero by clamping height + height = SDL_max(height, 1); + // Recalculate projection matrix + Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f); +} + +static void Lesson5_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.5f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + const SDL_GPUDepthStencilTargetInfo depthInfo = + { + .texture = ctx->depthTexture, + .clear_depth = 1.0f, // Ensure depth buffer clears to furthest value + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_DONT_CARE, + .stencil_load_op = SDL_GPU_LOADOP_DONT_CARE, + .stencil_store_op = SDL_GPU_STOREOP_DONT_CARE, + .cycle = true + }; + + // Begin pass & bind pipeline state + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, &depthInfo); + SDL_BindGPUGraphicsPipeline(pass, pso); + + // Bind vertex & index buffers + SDL_BindGPUVertexBuffers(pass, 0, &(const SDL_GPUBufferBinding) + { + .buffer = vtxBuffer, + .offset = 0 + }, 1); + SDL_BindGPUIndexBuffer(pass, &(const SDL_GPUBufferBinding) + { + .buffer = idxBuffer, + .offset = 0 + }, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + float model[16], viewproj[16]; + + // Draw triangle 1.5 units to the left and 6 units into the camera + Mtx_Translation(model, -1.5f, 0.0f, -6.0f); + Mtx_Rotate(model, rotTri, 0.0f, 1.0f, 0.0f); + Mtx_Multiply(viewproj, projection, model); + SDL_PushGPUVertexUniformData(cmd, 0, viewproj, sizeof(viewproj)); + SDL_DrawGPUIndexedPrimitives(pass, 12, 1, 0, 0, 0); + + // Draw quad 1.5 units to the right and 7 units into the camera + Mtx_Translation(model, 1.5f, 0.0f, -7.0f); + Mtx_Rotate(model, rotQuad, 1.0f, 1.0f, 1.0f); + Mtx_Multiply(viewproj, projection, model); + SDL_PushGPUVertexUniformData(cmd, 0, viewproj, sizeof(viewproj)); + SDL_DrawGPUIndexedPrimitives(pass, 36, 1, 12, 0, 0); + + SDL_EndGPURenderPass(pass); + + rotTri += 0.2f; + rotQuad -= 0.15f; +} + + +const struct AppConfig appConfig = +{ + .title = "NeHe's Solid Object Tutorial", + .width = 640, .height = 480, + .createDepthFormat = SDL_GPU_TEXTUREFORMAT_D16_UNORM, + .init = Lesson5_Init, + .quit = Lesson5_Quit, + .resize = Lesson5_Resize, + .draw = Lesson5_Draw +}; diff --git a/src/c/lesson6.c b/src/c/lesson6.c new file mode 100644 index 0000000..5b91892 --- /dev/null +++ b/src/c/lesson6.c @@ -0,0 +1,266 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" + + +typedef struct +{ + float x, y, z; + float u, v; +} Vertex; + +static const Vertex vertices[] = +{ + // Front Face + { -1.0f, -1.0f, 1.0f, 0.0f, 0.0f }, + { 1.0f, -1.0f, 1.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }, + { -1.0f, 1.0f, 1.0f, 0.0f, 1.0f }, + // Back Face + { -1.0f, -1.0f, -1.0f, 1.0f, 0.0f }, + { -1.0f, 1.0f, -1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, -1.0f, 0.0f, 1.0f }, + { 1.0f, -1.0f, -1.0f, 0.0f, 0.0f }, + // Top Face + { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }, + { -1.0f, 1.0f, 1.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }, + // Bottom Face + { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f }, + { 1.0f, -1.0f, -1.0f, 0.0f, 1.0f }, + { 1.0f, -1.0f, 1.0f, 0.0f, 0.0f }, + { -1.0f, -1.0f, 1.0f, 1.0f, 0.0f }, + // Right face + { 1.0f, -1.0f, -1.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, -1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }, + { 1.0f, -1.0f, 1.0f, 0.0f, 0.0f }, + // Left Face + { -1.0f, -1.0f, -1.0f, 0.0f, 0.0f }, + { -1.0f, -1.0f, 1.0f, 1.0f, 0.0f }, + { -1.0f, 1.0f, 1.0f, 1.0f, 1.0f }, + { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f } +}; + +static const uint16_t indices[] = +{ + 0, 1, 2, 2, 3, 0, // Front + 4, 5, 6, 6, 7, 4, // Back + 8, 9, 10, 10, 11, 8, // Top + 12, 13, 14, 14, 15, 12, // Bottom + 16, 17, 18, 18, 19, 16, // Right + 20, 21, 22, 22, 23, 20 // Left +}; + + +static SDL_GPUGraphicsPipeline* pso = NULL; +static SDL_GPUBuffer* vtxBuffer = NULL; +static SDL_GPUBuffer* idxBuffer = NULL; +static SDL_GPUSampler* sampler = NULL; +static SDL_GPUTexture* texture = NULL; + +static float projection[16]; + +static float xRot = 0.0f, yRot = 0.0f, zRot = 0.0f; + + +static bool Lesson6_Init(NeHeContext* restrict ctx) +{ + SDL_GPUShader* vertexShader, * fragmentShader; + if (!NeHe_LoadShaders(ctx, &vertexShader, &fragmentShader, "lesson6", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1, .fragmentSamplers = 1 })) + { + return false; + } + + const SDL_GPUVertexAttribute vertexAttribs[] = + { + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, x) + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, + .offset = offsetof(Vertex, u) + } + }; + pso = SDL_CreateGPUGraphicsPipeline(ctx->device, &(const SDL_GPUGraphicsPipelineCreateInfo) + { + .vertex_shader = vertexShader, + .fragment_shader = fragmentShader, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .vertex_input_state = + { + .vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription) + { + .slot = 0, + .pitch = sizeof(Vertex), + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX + }, + .num_vertex_buffers = 1, + .vertex_attributes = vertexAttribs, + .num_vertex_attributes = SDL_arraysize(vertexAttribs) + }, + .rasterizer_state = + { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_NONE, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE + }, + .depth_stencil_state = + { + .compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL, + .enable_depth_test = true, + .enable_depth_write = true + }, + .target_info = + { + .color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window) + }, + .num_color_targets = 1, + .depth_stencil_format = appConfig.createDepthFormat, + .has_depth_stencil_target = true + } + }); + SDL_ReleaseGPUShader(ctx->device, fragmentShader); + SDL_ReleaseGPUShader(ctx->device, vertexShader); + if (!pso) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + if ((texture = NeHe_LoadTexture(ctx, "Data/NeHe.bmp", true, false)) == NULL) + { + return false; + } + + sampler = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_LINEAR, + .mag_filter = SDL_GPU_FILTER_LINEAR + }); + if (!sampler) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUSampler: %s", SDL_GetError()); + return false; + } + + if (!NeHe_CreateVertexIndexBuffer(ctx, &vtxBuffer, &idxBuffer, + vertices, sizeof(vertices), + indices, sizeof(indices))) + { + return false; + } + + return true; +} + +static void Lesson6_Quit(NeHeContext* restrict ctx) +{ + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + SDL_ReleaseGPUSampler(ctx->device, sampler); + SDL_ReleaseGPUTexture(ctx->device, texture); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, pso); +} + +static void Lesson6_Resize(NeHeContext* restrict ctx, int width, int height) +{ + (void)ctx; + + // Avoid division by zero by clamping height + height = SDL_max(height, 1); + // Recalculate projection matrix + Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f); +} + +static void Lesson6_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.5f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + const SDL_GPUDepthStencilTargetInfo depthInfo = + { + .texture = ctx->depthTexture, + .clear_depth = 1.0f, // Ensure depth buffer clears to furthest value + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_DONT_CARE, + .stencil_load_op = SDL_GPU_LOADOP_DONT_CARE, + .stencil_store_op = SDL_GPU_STOREOP_DONT_CARE, + .cycle = true + }; + + // Begin pass & bind pipeline state + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, &depthInfo); + SDL_BindGPUGraphicsPipeline(pass, pso); + + // Bind texture + SDL_BindGPUFragmentSamplers(pass, 0, &(const SDL_GPUTextureSamplerBinding) + { + .texture = texture, + .sampler = sampler + }, 1); + + // Bind vertex & index buffers + SDL_BindGPUVertexBuffers(pass, 0, &(const SDL_GPUBufferBinding) + { + .buffer = vtxBuffer, + .offset = 0 + }, 1); + SDL_BindGPUIndexBuffer(pass, &(const SDL_GPUBufferBinding) + { + .buffer = idxBuffer, + .offset = 0 + }, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + float model[16]; + struct { float modelViewProj[16], color[4]; } u; + + // Move cube 5 units into the screen and apply some rotations + Mtx_Translation(model, 0.0f, 0.0f, -5.0f); + Mtx_Rotate(model, xRot, 1.0f, 0.0f, 0.0f); + Mtx_Rotate(model, yRot, 0.0f, 1.0f, 0.0f); + Mtx_Rotate(model, zRot, 0.0f, 0.0f, 1.0f); + + // Push shader uniforms + Mtx_Multiply(u.modelViewProj, projection, model); + SDL_memcpy(u.color, (float[4]){ 1.0f, 1.0f, 1.0f, 1.0f }, sizeof(float) * 4); + SDL_PushGPUVertexUniformData(cmd, 0, &u, sizeof(u)); + + // Draw textured cube + SDL_DrawGPUIndexedPrimitives(pass, SDL_arraysize(indices), 1, 0, 0, 0); + + SDL_EndGPURenderPass(pass); + + xRot += 0.3f; + yRot += 0.2f; + zRot += 0.4f; +} + + +const struct AppConfig appConfig = +{ + .title = "NeHe's Texture Mapping Tutorial", + .width = 640, .height = 480, + .createDepthFormat = SDL_GPU_TEXTUREFORMAT_D16_UNORM, + .init = Lesson6_Init, + .quit = Lesson6_Quit, + .resize = Lesson6_Resize, + .draw = Lesson6_Draw +}; diff --git a/src/c/lesson7.c b/src/c/lesson7.c new file mode 100644 index 0000000..26df537 --- /dev/null +++ b/src/c/lesson7.c @@ -0,0 +1,377 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" +#include + + +typedef struct +{ + float x, y, z; + float nx, ny, nz; + float u, v; +} Vertex; + +static const Vertex vertices[] = +{ + // Front Face + { -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }, + { 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }, + { -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f }, + // Back Face + { -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f }, + { -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f }, + { 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f }, + // Top Face + { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }, + { -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }, + // Bottom Face + { -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f }, + { 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f }, + { 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f }, + { -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f }, + // Right face + { 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }, + { 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, + // Left Face + { -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, + { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }, + { -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, + { -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f } +}; + +static const uint16_t indices[] = +{ + 0, 1, 2, 2, 3, 0, // Front + 4, 5, 6, 6, 7, 4, // Back + 8, 9, 10, 10, 11, 8, // Top + 12, 13, 14, 14, 15, 12, // Bottom + 16, 17, 18, 18, 19, 16, // Right + 20, 21, 22, 22, 23, 20 // Left +}; + + +static SDL_GPUGraphicsPipeline* psoUnlit = NULL, * psoLight = NULL; +static SDL_GPUBuffer* vtxBuffer = NULL; +static SDL_GPUBuffer* idxBuffer = NULL; +static SDL_GPUSampler* samplers[3] = { NULL, NULL, NULL }; +static SDL_GPUTexture* texture = NULL; + +static float projection[16]; + +static bool lighting = false; +struct Light { float ambient[4], diffuse[4], position[4]; } static light = +{ + .ambient = { 0.5f, 0.5f, 0.5f, 1.0f }, + .diffuse = { 1.0f, 1.0f, 1.0f, 1.0f }, + .position = { 0.0f, 0.0f, 2.0f, 1.0f } +}; + +static int filter = 0; + +static float xRot = 0.0f, yRot = 0.0f; +static float xSpeed = 0.0f, ySpeed = 0.0f; +static float z = -5.0f; + + +static bool Lesson7_Init(NeHeContext* restrict ctx) +{ + SDL_GPUShader* vertexShaderUnlit, * fragmentShaderUnlit; + SDL_GPUShader* vertexShaderLight, * fragmentShaderLight; + if (!NeHe_LoadShaders(ctx, &vertexShaderUnlit, &fragmentShaderUnlit, "lesson6", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1, .fragmentSamplers = 1 })) + { + return false; + } + if (!NeHe_LoadShaders(ctx, &vertexShaderLight, &fragmentShaderLight, "lesson7", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 2, .fragmentSamplers = 1 })) + { + SDL_ReleaseGPUShader(ctx->device, fragmentShaderUnlit); + SDL_ReleaseGPUShader(ctx->device, vertexShaderUnlit); + return false; + } + + const SDL_GPUVertexAttribute vertexAttribs[] = + { + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, x) + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, + .offset = offsetof(Vertex, u) + }, + { + .location = 2, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, nx) + } + }; + + const SDL_GPUVertexInputState vertexInput = + { + .vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription) + { + .slot = 0, + .pitch = sizeof(Vertex), + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX + }, + .num_vertex_buffers = 1, + .vertex_attributes = vertexAttribs, + .num_vertex_attributes = SDL_arraysize(vertexAttribs) + }; + + const SDL_GPURasterizerState rasterizer = + { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_NONE, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE + }; + + const SDL_GPUDepthStencilState depthStencil = + { + .compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL, + .enable_depth_test = true, + .enable_depth_write = true + }; + + const SDL_GPUGraphicsPipelineTargetInfo targetInfo = + { + .color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window) + }, + .num_color_targets = 1, + .depth_stencil_format = appConfig.createDepthFormat, + .has_depth_stencil_target = true + }; + + psoUnlit = SDL_CreateGPUGraphicsPipeline(ctx->device, &(const SDL_GPUGraphicsPipelineCreateInfo) + { + .vertex_shader = vertexShaderUnlit, + .fragment_shader = fragmentShaderUnlit, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .vertex_input_state = vertexInput, + .rasterizer_state = rasterizer, + .depth_stencil_state = depthStencil, + .target_info = targetInfo + }); + SDL_ReleaseGPUShader(ctx->device, fragmentShaderUnlit); + SDL_ReleaseGPUShader(ctx->device, vertexShaderUnlit); + if (!psoUnlit) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + SDL_ReleaseGPUShader(ctx->device, fragmentShaderLight); + SDL_ReleaseGPUShader(ctx->device, vertexShaderLight); + return false; + } + + psoLight = SDL_CreateGPUGraphicsPipeline(ctx->device, &(const SDL_GPUGraphicsPipelineCreateInfo) + { + .vertex_shader = vertexShaderLight, + .fragment_shader = fragmentShaderLight, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .vertex_input_state = vertexInput, + .rasterizer_state = rasterizer, + .depth_stencil_state = depthStencil, + .target_info = targetInfo + }); + SDL_ReleaseGPUShader(ctx->device, fragmentShaderLight); + SDL_ReleaseGPUShader(ctx->device, vertexShaderLight); + if (!psoUnlit) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + if ((texture = NeHe_LoadTexture(ctx, "Data/Crate.bmp", true, true)) == NULL) + { + return false; + } + + samplers[0] = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_NEAREST, + .mag_filter = SDL_GPU_FILTER_NEAREST + }); + samplers[1] = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_LINEAR, + .mag_filter = SDL_GPU_FILTER_LINEAR + }); + samplers[2] = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_LINEAR, + .mag_filter = SDL_GPU_FILTER_LINEAR, + .mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, + .max_lod = FLT_MAX + }); + if (!samplers[0] || !samplers[1] || !samplers[2]) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUSampler: %s", SDL_GetError()); + return false; + } + + if (!NeHe_CreateVertexIndexBuffer(ctx, &vtxBuffer, &idxBuffer, + vertices, sizeof(vertices), + indices, sizeof(indices))) + { + return false; + } + + return true; +} + +static void Lesson7_Quit(NeHeContext* restrict ctx) +{ + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + for (int i = SDL_arraysize(samplers) - 1; i > 0; --i) + { + SDL_ReleaseGPUSampler(ctx->device, samplers[i]); + } + SDL_ReleaseGPUTexture(ctx->device, texture); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, psoLight); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, psoUnlit); +} + +static void Lesson7_Resize(NeHeContext* restrict ctx, int width, int height) +{ + (void)ctx; + + // Avoid division by zero by clamping height + height = SDL_max(height, 1); + // Recalculate projection matrix + Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f); +} + +static void Lesson7_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.5f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + const SDL_GPUDepthStencilTargetInfo depthInfo = + { + .texture = ctx->depthTexture, + .clear_depth = 1.0f, // Ensure depth buffer clears to furthest value + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_DONT_CARE, + .stencil_load_op = SDL_GPU_LOADOP_DONT_CARE, + .stencil_store_op = SDL_GPU_STOREOP_DONT_CARE, + .cycle = true + }; + + // Begin pass & bind pipeline state + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, &depthInfo); + SDL_BindGPUGraphicsPipeline(pass, lighting ? psoLight : psoUnlit); + + // Bind texture + SDL_BindGPUFragmentSamplers(pass, 0, &(const SDL_GPUTextureSamplerBinding) + { + .texture = texture, + .sampler = samplers[filter] + }, 1); + + // Bind vertex & index buffers + SDL_BindGPUVertexBuffers(pass, 0, &(const SDL_GPUBufferBinding) + { + .buffer = vtxBuffer, + .offset = 0 + }, 1); + SDL_BindGPUIndexBuffer(pass, &(const SDL_GPUBufferBinding) + { + .buffer = idxBuffer, + .offset = 0 + }, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + // Setup the cube's model matrix + float model[16]; + Mtx_Translation(model, 0.0f, 0.0f, z); + Mtx_Rotate(model, xRot, 1.0f, 0.0f, 0.0f); + Mtx_Rotate(model, yRot, 0.0f, 1.0f, 0.0f); + + // Push shader uniforms + if (lighting) + { + struct { float model[16], projection[16]; } u; + SDL_memcpy(u.model, model, sizeof(u.model)); + SDL_memcpy(u.projection, projection, sizeof(u.projection)); + SDL_PushGPUVertexUniformData(cmd, 0, &u, sizeof(u)); + SDL_PushGPUVertexUniformData(cmd, 1, &light, sizeof(light)); + } + else + { + struct { float modelViewProj[16], color[4]; } u; + Mtx_Multiply(u.modelViewProj, projection, model); + SDL_memcpy(u.color, (const float[4]){ 1.0f, 1.0f, 1.0f, 1.0f }, sizeof(float) * 4); + SDL_PushGPUVertexUniformData(cmd, 0, &u, sizeof(u)); + } + + // Draw textured cube + SDL_DrawGPUIndexedPrimitives(pass, SDL_arraysize(indices), 1, 0, 0, 0); + + SDL_EndGPURenderPass(pass); + + const bool* keys = SDL_GetKeyboardState(NULL); + + if (keys[SDL_SCANCODE_PAGEUP]) { z -= 0.02f; } + if (keys[SDL_SCANCODE_PAGEDOWN]) { z += 0.02f; } + if (keys[SDL_SCANCODE_UP]) { xSpeed -= 0.01f; } + if (keys[SDL_SCANCODE_DOWN]) { xSpeed += 0.01f; } + if (keys[SDL_SCANCODE_RIGHT]) { ySpeed += 0.1f; } + if (keys[SDL_SCANCODE_LEFT]) { ySpeed -= 0.1f; } + + xRot += xSpeed; + yRot += ySpeed; +} + +static void Lesson7_Key(NeHeContext* ctx, SDL_Keycode key, bool down, bool repeat) +{ + (void)ctx; + + if (down && !repeat) + { + switch (key) + { + case SDLK_L: + lighting = !lighting; + break; + case SDLK_F: + filter = (filter + 1) % (int)SDL_arraysize(samplers); + break; + default: + break; + } + } +} + + +const struct AppConfig appConfig = +{ + .title = "NeHe's Textures, Lighting & Keyboard Tutorial", + .width = 640, .height = 480, + .createDepthFormat = SDL_GPU_TEXTUREFORMAT_D16_UNORM, + .init = Lesson7_Init, + .quit = Lesson7_Quit, + .resize = Lesson7_Resize, + .draw = Lesson7_Draw, + .key = Lesson7_Key +}; diff --git a/src/c/lesson8.c b/src/c/lesson8.c new file mode 100644 index 0000000..5b9ae68 --- /dev/null +++ b/src/c/lesson8.c @@ -0,0 +1,400 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" +#include + + +typedef struct +{ + float x, y, z; + float nx, ny, nz; + float u, v; +} Vertex; + +static const Vertex vertices[] = +{ + // Front Face + { -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }, + { 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }, + { -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f }, + // Back Face + { -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f }, + { -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f }, + { 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f }, + // Top Face + { -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }, + { -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f }, + { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }, + // Bottom Face + { -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f }, + { 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f }, + { 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f }, + { -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f }, + // Right face + { 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }, + { 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, + // Left Face + { -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, + { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }, + { -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, + { -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f } +}; + +static const uint16_t indices[] = +{ + 0, 1, 2, 2, 3, 0, // Front + 4, 5, 6, 6, 7, 4, // Back + 8, 9, 10, 10, 11, 8, // Top + 12, 13, 14, 14, 15, 12, // Bottom + 16, 17, 18, 18, 19, 16, // Right + 20, 21, 22, 22, 23, 20 // Left +}; + + +static SDL_GPUGraphicsPipeline* psoUnlit = NULL, * psoLight = NULL; +static SDL_GPUGraphicsPipeline* psoBlendUnlit = NULL, * psoBlendLight = NULL; +static SDL_GPUBuffer* vtxBuffer = NULL; +static SDL_GPUBuffer* idxBuffer = NULL; +static SDL_GPUSampler* samplers[3] = { NULL, NULL, NULL }; +static SDL_GPUTexture* texture = NULL; + +static float projection[16]; + +static bool lighting = false; +static bool blending = false; +struct Light { float ambient[4], diffuse[4], position[4]; } static light = +{ + .ambient = { 0.5f, 0.5f, 0.5f, 1.0f }, + .diffuse = { 1.0f, 1.0f, 1.0f, 1.0f }, + .position = { 0.0f, 0.0f, 2.0f, 1.0f } +}; + +static int filter = 0; + +static float xRot = 0.0f, yRot = 0.0f; +static float xSpeed = 0.0f, ySpeed = 0.0f; +static float z = -5.0f; + + +static bool Lesson8_Init(NeHeContext* restrict ctx) +{ + SDL_GPUShader* vertexShaderUnlit, * fragmentShaderUnlit; + SDL_GPUShader* vertexShaderLight, * fragmentShaderLight; + if (!NeHe_LoadShaders(ctx, &vertexShaderUnlit, &fragmentShaderUnlit, "lesson6", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1, .fragmentSamplers = 1 })) + { + return false; + } + if (!NeHe_LoadShaders(ctx, &vertexShaderLight, &fragmentShaderLight, "lesson7", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 2, .fragmentSamplers = 1 })) + { + SDL_ReleaseGPUShader(ctx->device, fragmentShaderUnlit); + SDL_ReleaseGPUShader(ctx->device, vertexShaderUnlit); + return false; + } + + const SDL_GPUVertexAttribute vertexAttribs[] = + { + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, x) + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, + .offset = offsetof(Vertex, u) + }, + { + .location = 2, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, nx) + } + }; + + SDL_GPUGraphicsPipelineCreateInfo psoInfo; + SDL_zero(psoInfo); + + psoInfo.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST; + psoInfo.vertex_input_state = (SDL_GPUVertexInputState) + { + .vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription) + { + .slot = 0, + .pitch = sizeof(Vertex), + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX + }, + .num_vertex_buffers = 1, + .vertex_attributes = vertexAttribs, + .num_vertex_attributes = SDL_arraysize(vertexAttribs) + }; + + psoInfo.rasterizer_state = (SDL_GPURasterizerState) + { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_NONE, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE + }; + + psoInfo.target_info.num_color_targets = 1; + psoInfo.target_info.depth_stencil_format = appConfig.createDepthFormat; + psoInfo.target_info.has_depth_stencil_target = true; + + // Common pipeline depth & colour target options + psoInfo.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL; + const SDL_GPUTextureFormat swapchainTextureFormat = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window); + + // Setup depth/stencil & colour pipeline state for no blending + psoInfo.depth_stencil_state.enable_depth_test = true; + psoInfo.depth_stencil_state.enable_depth_write = true; + psoInfo.target_info.color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = swapchainTextureFormat + }; + + // Create unlit pipeline + psoInfo.vertex_shader = vertexShaderUnlit; + psoInfo.fragment_shader = fragmentShaderUnlit; + psoUnlit = SDL_CreateGPUGraphicsPipeline(ctx->device, &psoInfo); + + // Create lit pipeline + psoInfo.vertex_shader = vertexShaderLight; + psoInfo.fragment_shader = fragmentShaderLight; + psoLight = SDL_CreateGPUGraphicsPipeline(ctx->device, &psoInfo); + + // Setup depth/stencil & colour pipeline state for blending + psoInfo.depth_stencil_state.enable_depth_test = false; + psoInfo.depth_stencil_state.enable_depth_write = false; + psoInfo.target_info.color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = swapchainTextureFormat, + .blend_state = + { + .enable_blend = true, + .color_blend_op = SDL_GPU_BLENDOP_ADD, + .alpha_blend_op = SDL_GPU_BLENDOP_ADD, + .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE, + .src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE + } + }; + + // Create unlit blended pipeline + psoInfo.vertex_shader = vertexShaderUnlit; + psoInfo.fragment_shader = fragmentShaderUnlit; + psoBlendUnlit = SDL_CreateGPUGraphicsPipeline(ctx->device, &psoInfo); + + // Create lit blended pipeline + psoInfo.vertex_shader = vertexShaderLight; + psoInfo.fragment_shader = fragmentShaderLight; + psoBlendLight = SDL_CreateGPUGraphicsPipeline(ctx->device, &psoInfo); + + // Free shaders + SDL_ReleaseGPUShader(ctx->device, fragmentShaderLight); + SDL_ReleaseGPUShader(ctx->device, vertexShaderLight); + SDL_ReleaseGPUShader(ctx->device, fragmentShaderUnlit); + SDL_ReleaseGPUShader(ctx->device, vertexShaderUnlit); + + if (!psoUnlit || !psoLight || !psoBlendUnlit || !psoBlendLight) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + if ((texture = NeHe_LoadTexture(ctx, "Data/Glass.bmp", true, true)) == NULL) + { + return false; + } + + samplers[0] = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_NEAREST, + .mag_filter = SDL_GPU_FILTER_NEAREST + }); + samplers[1] = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_LINEAR, + .mag_filter = SDL_GPU_FILTER_LINEAR + }); + samplers[2] = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .min_filter = SDL_GPU_FILTER_LINEAR, + .mag_filter = SDL_GPU_FILTER_LINEAR, + .mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, + .max_lod = FLT_MAX + }); + if (!samplers[0] || !samplers[1] || !samplers[2]) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUSampler: %s", SDL_GetError()); + return false; + } + + if (!NeHe_CreateVertexIndexBuffer(ctx, &vtxBuffer, &idxBuffer, + vertices, sizeof(vertices), + indices, sizeof(indices))) + { + return false; + } + + return true; +} + +static void Lesson8_Quit(NeHeContext* restrict ctx) +{ + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + for (int i = SDL_arraysize(samplers) - 1; i > 0; --i) + { + SDL_ReleaseGPUSampler(ctx->device, samplers[i]); + } + SDL_ReleaseGPUTexture(ctx->device, texture); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, psoBlendLight); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, psoBlendUnlit); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, psoLight); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, psoUnlit); +} + +static void Lesson8_Resize(NeHeContext* restrict ctx, int width, int height) +{ + (void)ctx; + + // Avoid division by zero by clamping height + height = SDL_max(height, 1); + // Recalculate projection matrix + Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f); +} + +static void Lesson8_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.5f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + const SDL_GPUDepthStencilTargetInfo depthInfo = + { + .texture = ctx->depthTexture, + .clear_depth = 1.0f, // Ensure depth buffer clears to furthest value + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_DONT_CARE, + .stencil_load_op = SDL_GPU_LOADOP_DONT_CARE, + .stencil_store_op = SDL_GPU_STOREOP_DONT_CARE, + .cycle = true + }; + + // Begin pass & bind pipeline state + SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, &depthInfo); + SDL_GPUGraphicsPipeline* const pipelines[] = { psoUnlit, psoLight, psoBlendUnlit, psoBlendLight }; + SDL_BindGPUGraphicsPipeline(pass, pipelines[lighting + blending * 2]); + + // Bind texture + SDL_BindGPUFragmentSamplers(pass, 0, &(const SDL_GPUTextureSamplerBinding) + { + .texture = texture, + .sampler = samplers[filter] + }, 1); + + // Bind vertex & index buffers + SDL_BindGPUVertexBuffers(pass, 0, &(const SDL_GPUBufferBinding) + { + .buffer = vtxBuffer, + .offset = 0 + }, 1); + SDL_BindGPUIndexBuffer(pass, &(const SDL_GPUBufferBinding) + { + .buffer = idxBuffer, + .offset = 0 + }, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + // Setup the view + float model[16]; + Mtx_Translation(model, 0.0f, 0.0f, z); + Mtx_Rotate(model, xRot, 1.0f, 0.0f, 0.0f); + Mtx_Rotate(model, yRot, 0.0f, 1.0f, 0.0f); + + // Push shader uniforms + if (lighting) + { + struct { float model[16], projection[16]; } u; + SDL_memcpy(u.model, model, sizeof(u.model)); + SDL_memcpy(u.projection, projection, sizeof(u.projection)); + SDL_PushGPUVertexUniformData(cmd, 0, &u, sizeof(u)); + SDL_PushGPUVertexUniformData(cmd, 1, &light, sizeof(light)); + } + else + { + struct { float modelViewProj[16], color[4]; } u; + Mtx_Multiply(u.modelViewProj, projection, model); + // 50% translucency + SDL_memcpy(u.color, (const float[4]){ 1.0f, 1.0f, 1.0f, 0.5f }, sizeof(float) * 4); + SDL_PushGPUVertexUniformData(cmd, 0, &u, sizeof(u)); + } + + // Draw textured cube + SDL_DrawGPUIndexedPrimitives(pass, SDL_arraysize(indices), 1, 0, 0, 0); + + SDL_EndGPURenderPass(pass); + + const bool* keys = SDL_GetKeyboardState(NULL); + + if (keys[SDL_SCANCODE_UP]) { xSpeed -= 0.01f; } + if (keys[SDL_SCANCODE_DOWN]) { xSpeed += 0.01f; } + if (keys[SDL_SCANCODE_RIGHT]) { ySpeed += 0.1f; } + if (keys[SDL_SCANCODE_LEFT]) { ySpeed -= 0.1f; } + if (keys[SDL_SCANCODE_PAGEUP]) { z -= 0.02f; } + if (keys[SDL_SCANCODE_PAGEDOWN]) { z += 0.02f; } + + xRot += xSpeed; + yRot += ySpeed; +} + +static void Lesson8_Key(NeHeContext* ctx, SDL_Keycode key, bool down, bool repeat) +{ + (void)ctx; + + if (down && !repeat) + { + switch (key) + { + case SDLK_L: + lighting = !lighting; + break; + case SDLK_B: + blending = !blending; + break; + case SDLK_F: + filter = (filter + 1) % (int)SDL_arraysize(samplers); + break; + default: + break; + } + } +} + + +const struct AppConfig appConfig = +{ + .title = "Tom Stanis & NeHe's Blending Tutorial", + .width = 640, .height = 480, + .createDepthFormat = SDL_GPU_TEXTUREFORMAT_D16_UNORM, + .init = Lesson8_Init, + .quit = Lesson8_Quit, + .resize = Lesson8_Resize, + .draw = Lesson8_Draw, + .key = Lesson8_Key +}; diff --git a/src/c/lesson9.c b/src/c/lesson9.c new file mode 100644 index 0000000..4030554 --- /dev/null +++ b/src/c/lesson9.c @@ -0,0 +1,359 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" + + +typedef struct +{ + float x, y, z; + float u, v; +} Vertex; + +static const Vertex vertices[] = +{ + { -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, 1.0f, 1.0f }, + { -1.0f, 1.0f, 0.0f, 0.0f, 1.0f } +}; + +static const uint16_t indices[] = +{ + 0, 1, 2, + 2, 3, 0 +}; + +static SDL_GPUGraphicsPipeline* pso = NULL; +static SDL_GPUBuffer* vtxBuffer = NULL; +static SDL_GPUBuffer* idxBuffer = NULL; +static SDL_GPUTexture* texture = NULL; +static SDL_GPUSampler* sampler = NULL; + +static SDL_GPUBuffer* instanceBuffer = NULL; +static SDL_GPUTransferBuffer* instanceXferBuffer = NULL; + +typedef struct +{ + float model[16]; + float color[4]; +} Instance; + +static float projection[16]; + +static bool twinkle = false; + +static struct Star +{ + float distance, angle; + uint8_t r, g, b; +} stars[50]; + +static float zoom = -15.0f; +static float tilt = 90.0f; +static float spin = 0.0f; + +static uint32_t rngState = 1; +static inline int RngNext(void) +{ + //TODO: check which one of these matches win32 +#if 0 + rngState = rngState * 1103515245 + 12345; +#else + rngState = rngState * 214013 + 2531011; +#endif + return (int)((rngState >> 16) & 0x7FFF); // (s / 65536) % 32768 +} + + +static bool Lesson9_Init(NeHeContext* ctx) +{ + SDL_GPUShader* vertexShader, * fragmentShader; + if (!NeHe_LoadShaders(ctx, &vertexShader, &fragmentShader, "lesson9", + &(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1, .fragmentSamplers = 1, .vertexStorage = 1 })) + { + return false; + } + + const SDL_GPUVertexAttribute vertexAttribs[] = + { + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = offsetof(Vertex, x) + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, + .offset = offsetof(Vertex, u) + } + }; + pso = SDL_CreateGPUGraphicsPipeline(ctx->device, &(const SDL_GPUGraphicsPipelineCreateInfo) + { + .vertex_shader = vertexShader, + .fragment_shader = fragmentShader, + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + .vertex_input_state = + { + .vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription) + { + .slot = 0, + .pitch = sizeof(Vertex), + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX + }, + .num_vertex_buffers = 1, + .vertex_attributes = vertexAttribs, + .num_vertex_attributes = SDL_arraysize(vertexAttribs) + }, + .rasterizer_state = + { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_NONE, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE + }, + .target_info = + { + .color_target_descriptions = &(const SDL_GPUColorTargetDescription) + { + .format = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window), + .blend_state = + { + .enable_blend = true, + .color_blend_op = SDL_GPU_BLENDOP_ADD, + .alpha_blend_op = SDL_GPU_BLENDOP_ADD, + .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE, + .src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE + } + }, + .num_color_targets = 1 + } + }); + SDL_ReleaseGPUShader(ctx->device, fragmentShader); + SDL_ReleaseGPUShader(ctx->device, vertexShader); + if (!pso) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError()); + return false; + } + + if ((texture = NeHe_LoadTexture(ctx, "Data/Star.bmp", true, false)) == NULL) + { + return false; + } + + sampler = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo) + { + .mag_filter = SDL_GPU_FILTER_LINEAR, + .min_filter = SDL_GPU_FILTER_LINEAR + }); + if (!sampler) + { + return false; + } + + if (!NeHe_CreateVertexIndexBuffer(ctx, &vtxBuffer, &idxBuffer, + vertices, sizeof(vertices), + indices, sizeof(indices))) + { + return false; + } + + const int numStars = SDL_arraysize(stars); + + instanceBuffer = SDL_CreateGPUBuffer(ctx->device, &(const SDL_GPUBufferCreateInfo) + { + .usage = SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ, + .size = sizeof(Instance) * 2 * numStars + }); + if (!instanceBuffer) + { + return false; + } + instanceXferBuffer = SDL_CreateGPUTransferBuffer(ctx->device, &(const SDL_GPUTransferBufferCreateInfo) + { + .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, + .size = sizeof(Instance) * numStars + }); + if (!instanceXferBuffer) + { + return false; + } + + // Initialise stars + for (int i = 0; i < numStars; ++i) + { + stars[i] = (struct Star) + { + .angle = 0.0f, + .distance = 5.0f * ((float)i / (float)numStars), + .r = (uint8_t)(RngNext() % 256), + .g = (uint8_t)(RngNext() % 256), + .b = (uint8_t)(RngNext() % 256) + }; + } + + return true; +} + +static void Lesson9_Quit(NeHeContext* ctx) +{ + SDL_ReleaseGPUTransferBuffer(ctx->device, instanceXferBuffer); + SDL_ReleaseGPUBuffer(ctx->device, instanceBuffer); + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + SDL_ReleaseGPUSampler(ctx->device, sampler); + SDL_ReleaseGPUTexture(ctx->device, texture); + SDL_ReleaseGPUGraphicsPipeline(ctx->device, pso); +} + +static void Lesson9_Resize(NeHeContext* ctx, int width, int height) +{ + (void)ctx; + + // Avoid division by zero by clamping height + height = SDL_max(height, 1); + // Recalculate projection matrix + Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f); +} + +static void Lesson9_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain) +{ + const SDL_GPUColorTargetInfo colorInfo = + { + .texture = swapchain, + .clear_color = { 0.0f, 0.0f, 0.0f, 0.5f }, + .load_op = SDL_GPU_LOADOP_CLEAR, + .store_op = SDL_GPU_STOREOP_STORE + }; + + static const int numStars = SDL_arraysize(stars); + + // Animate stars + Instance* instances = SDL_MapGPUTransferBuffer(ctx->device, instanceXferBuffer, true); + for (int i = 0, instanceIdx = 0; i < numStars; ++i, ++instanceIdx) + { + struct Star* star = &stars[i]; + Instance* instance = &instances[instanceIdx]; + + Mtx_Translation(instance->model, 0.0f ,0.0f, zoom); + Mtx_Rotate(instance->model, tilt, 1.0f, 0.0f, 0.0f); + Mtx_Rotate(instance->model, star->angle, 0.0f, 1.0f, 0.0f); + Mtx_Translate(instance->model, star->distance, 0.0f, 0.0f); + Mtx_Rotate(instance->model, -star->angle, 0.0f, 1.0f, 0.0f); + Mtx_Rotate(instance->model, -tilt, 1.0f, 0.0f, 0.0f); + + if (twinkle) + { + instance->color[0] = (float)stars[numStars - i - 1].r / 255.0f; + instance->color[1] = (float)stars[numStars - i - 1].g / 255.0f; + instance->color[2] = (float)stars[numStars - i - 1].b / 255.0f; + instance->color[3] = 1.0f; + SDL_memcpy(instances[++instanceIdx].model, instance->model, sizeof(float) * 16); + instance = &instances[instanceIdx]; + } + + Mtx_Rotate(instance->model, spin, 0.0f, 0.0f, 1.0f); + instance->color[0] = (float)star->r / 255.0f; + instance->color[1] = (float)star->g / 255.0f; + instance->color[2] = (float)star->b / 255.0f; + instance->color[3] = 1.0f; + + spin += 0.01f; + star->angle += (float)i / (float)numStars; + star->distance -= 0.01f; + if (star->distance < 0.0f) + { + star->distance += 5.0f; + star->r = (uint8_t)(RngNext() % 256); + star->g = (uint8_t)(RngNext() % 256); + star->b = (uint8_t)(RngNext() % 256); + } + } + SDL_UnmapGPUTransferBuffer(ctx->device, instanceXferBuffer); + + const unsigned numInstances = twinkle ? 2 * (unsigned)numStars : (unsigned)numStars; + + // Upload instances buffer to the GPU + SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmd); + SDL_UploadToGPUBuffer(copyPass, &(const SDL_GPUTransferBufferLocation) + { + .transfer_buffer = instanceXferBuffer, + .offset = 0 + }, &(const SDL_GPUBufferRegion) + { + .buffer = instanceBuffer, + .offset = 0, + .size = sizeof(Instance) * numInstances + }, true); + SDL_EndGPUCopyPass(copyPass); + + // Begin pass & bind pipeline state + SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, NULL); + SDL_BindGPUGraphicsPipeline(renderPass, pso); + + // Bind particle texture + SDL_BindGPUFragmentSamplers(renderPass, 0, &(const SDL_GPUTextureSamplerBinding) + { + .texture = texture, + .sampler = sampler + }, 1); + + SDL_BindGPUVertexBuffers(renderPass, 0, &(const SDL_GPUBufferBinding) + { + .buffer = vtxBuffer, + .offset = 0 + }, 1); + SDL_BindGPUVertexStorageBuffers(renderPass, 0, &instanceBuffer, 1); + SDL_BindGPUIndexBuffer(renderPass, &(const SDL_GPUBufferBinding) + { + .buffer = idxBuffer, + .offset = 0 + }, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + SDL_PushGPUVertexUniformData(cmd, 0, projection, sizeof(projection)); + SDL_DrawGPUIndexedPrimitives(renderPass, SDL_arraysize(indices), numInstances, 0, 0, 0); + + SDL_EndGPURenderPass(renderPass); + + const bool* keys = SDL_GetKeyboardState(NULL); + + if (keys[SDL_SCANCODE_UP]) { tilt -= 0.5f; } + if (keys[SDL_SCANCODE_DOWN]) { tilt += 0.5f; } + if (keys[SDL_SCANCODE_PAGEUP]) { zoom -= 0.2f; } + if (keys[SDL_SCANCODE_PAGEDOWN]) { zoom += 0.2f; } +} + +static void Lesson9_Key(NeHeContext* ctx, SDL_Keycode key, bool down, bool repeat) +{ + (void)ctx; + + if (down && !repeat) + { + switch (key) + { + case SDLK_T: + twinkle = !twinkle; + break; + default: + break; + } + } +} + + +const struct AppConfig appConfig = +{ + .title = "NeHe's Animated Blended Textures Tutorial", + .width = 640, .height = 480, + .init = Lesson9_Init, + .quit = Lesson9_Quit, + .resize = Lesson9_Resize, + .draw = Lesson9_Draw, + .key = Lesson9_Key +}; diff --git a/src/c/matrix.c b/src/c/matrix.c new file mode 100644 index 0000000..8cfb9aa --- /dev/null +++ b/src/c/matrix.c @@ -0,0 +1,132 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "matrix.h" + + +extern inline void Mtx_Identity(float m[16]); +extern inline void Mtx_Translation(float m[16], float x, float y, float z); + +static void MakeRotation(float m[9], float c, float s, float x, float y, float z) +{ + const float rc = 1.f - c; + const float rcx = x * rc, rcy = y * rc, rcz = z * rc; + const float sx = x * s, sy = y * s, sz = z * s; + + m[0] = rcx * x + c; + m[3] = rcx * y - sz; + m[6] = rcx * z + sy; + + m[1] = rcy * x + sz; + m[4] = rcy * y + c; + m[7] = rcy * z - sx; + + m[2] = rcz * x - sy; + m[5] = rcz * y + sx; + m[8] = rcz * z + c; +} + +static void MakeGLRotation(float m[9], float angle, float x, float y, float z) +{ + // Treat inputs like glRotatef + const float theta = angle * (SDL_PI_F / 180.0f); + const float axisMag = SDL_sqrtf(x * x + y * y + z * z); + if (SDL_fabsf(axisMag - 1.f) > SDL_FLT_EPSILON) + { + x /= axisMag; + y /= axisMag; + z /= axisMag; + } + + MakeRotation(m, SDL_cosf(theta), SDL_sinf(theta), x, y, z); +} + +void Mtx_Rotation(float m[16], float angle, float x, float y, float z) +{ + float r[9]; + MakeGLRotation(r, angle, x, y, z); + + m[3] = m[7] = m[11] = m[12] = m[13] = m[14] = 0.0f; + m[15] = 1.0f; + + m[0] = r[0]; m[1] = r[1]; m[2] = r[2]; + m[4] = r[3]; m[5] = r[4]; m[6] = r[5]; + m[8] = r[6]; m[9] = r[7]; m[10] = r[8]; +} + +void Mtx_Perspective(float m[16], float fovy, float aspect, float near, float far) +{ + const float h = 1.0f / SDL_tanf(fovy * (SDL_PI_F / 180.0f) * 0.5f); + const float w = h / aspect; + const float invClipRng = 1.0f / (far - near); + const float zh = -(far + near) * invClipRng; + const float zl = -(2.0f * far * near) * invClipRng; + + /* + [w 0 0 0] + [0 h 0 0] + [0 0 zh zl] + [0 0 -1 0] + */ + m[1] = m[2] = m[3] = m[4] = m[6] = m[7] = m[8] = m[9] = m[12] = m[13] = m[15] = 0.0f; + m[0] = w; + m[5] = h; + m[10] = zh; + m[14] = zl; + m[11] = -1.0f; +} + +void Mtx_Multiply(float m[16], const float l[16], const float r[16]) +{ + int i = 0; + for (int col = 0; col < 4; ++col) + { + for (int row = 0; row < 4; ++row) + { + float a = 0.f; + for (int j = 0; j < 4; ++j) + { + a += l[j * 4 + row] * r[col * 4 + j]; + } + m[i++] = a; + } + } +} + +void Mtx_Translate(float m[16], float x, float y, float z) +{ + /* + m = { [1 0 0 x] + [0 1 0 y] + [0 0 1 z] + [0 0 0 1] } * m + */ + m[12] += x * m[0] + y * m[4] + z * m[8]; + m[13] += x * m[1] + y * m[5] + z * m[9]; + m[14] += x * m[2] + y * m[6] + z * m[10]; + m[15] += x * m[3] + y * m[7] + z * m[11]; +} + +void Mtx_Rotate(float m[16], float angle, float x, float y, float z) +{ + // Set up temporaries + float tmp[12], r[9]; + SDL_memcpy(tmp, m, sizeof(float) * 12); + MakeGLRotation(r, angle, x, y, z); + + // Partial matrix multiplication + m[0] = r[0] * tmp[0] + r[1] * tmp[4] + r[2] * tmp[8]; + m[1] = r[0] * tmp[1] + r[1] * tmp[5] + r[2] * tmp[9]; + m[2] = r[0] * tmp[2] + r[1] * tmp[6] + r[2] * tmp[10]; + m[3] = r[0] * tmp[3] + r[1] * tmp[7] + r[2] * tmp[11]; + m[4] = r[3] * tmp[0] + r[4] * tmp[4] + r[5] * tmp[8]; + m[5] = r[3] * tmp[1] + r[4] * tmp[5] + r[5] * tmp[9]; + m[6] = r[3] * tmp[2] + r[4] * tmp[6] + r[5] * tmp[10]; + m[7] = r[3] * tmp[3] + r[4] * tmp[7] + r[5] * tmp[11]; + m[8] = r[6] * tmp[0] + r[7] * tmp[4] + r[8] * tmp[8]; + m[9] = r[6] * tmp[1] + r[7] * tmp[5] + r[8] * tmp[9]; + m[10] = r[6] * tmp[2] + r[7] * tmp[6] + r[8] * tmp[10]; + m[11] = r[6] * tmp[3] + r[7] * tmp[7] + r[8] * tmp[11]; +} diff --git a/src/c/matrix.h b/src/c/matrix.h new file mode 100644 index 0000000..71b70c7 --- /dev/null +++ b/src/c/matrix.h @@ -0,0 +1,36 @@ +#ifndef MATRIX_H +#define MATRIX_H + +#include + +inline void Mtx_Identity(float m[16]) +{ + SDL_memcpy(m, (float[]) + { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + }, sizeof(float) * 16); +} + +inline void Mtx_Translation(float m[16], float x, float y, float z) +{ + SDL_memcpy(m, (float[]) + { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + x, y, z, 1 + }, sizeof(float) * 16); +} + +void Mtx_Rotation(float m[16], float angle, float x, float y, float z); +void Mtx_Perspective(float m[16], float fovy, float aspect, float near, float far); + +void Mtx_Multiply(float m[16], const float l[16], const float r[16]); + +void Mtx_Translate(float m[16], float x, float y, float z); +void Mtx_Rotate(float m[16], float angle, float x, float y, float z); + +#endif//MATRIX_H diff --git a/src/c/nehe.c b/src/c/nehe.c new file mode 100644 index 0000000..620860f --- /dev/null +++ b/src/c/nehe.c @@ -0,0 +1,649 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include "nehe.h" + + +bool NeHe_InitGPU(NeHeContext* ctx, const char* title, int width, int height) +{ + // Create window + ctx->window = SDL_CreateWindow(title, width, height, SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY); + if (!ctx->window) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateWindow: %s", SDL_GetError()); + return false; + } + + // Open GPU device + const SDL_GPUShaderFormat formats = + SDL_GPU_SHADERFORMAT_METALLIB | SDL_GPU_SHADERFORMAT_MSL | + SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL; + ctx->device = SDL_CreateGPUDevice(formats, true, NULL); + if (!ctx->device) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUDevice: %s", SDL_GetError()); + return false; + } + + // Attach window to the GPU device + if (!SDL_ClaimWindowForGPUDevice(ctx->device, ctx->window)) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_ClaimWindowForGPUDevice: %s", SDL_GetError()); + return false; + } + + // Enable VSync + SDL_SetGPUSwapchainParameters(ctx->device, ctx->window, + SDL_GPU_SWAPCHAINCOMPOSITION_SDR, + SDL_GPU_PRESENTMODE_VSYNC); + + return true; +} + +bool NeHe_SetupDepthTexture(NeHeContext* ctx, uint32_t width, uint32_t height, + SDL_GPUTextureFormat format, float clearDepth) +{ + if (ctx->depthTexture) + { + SDL_ReleaseGPUTexture(ctx->device, ctx->depthTexture); + ctx->depthTexture = NULL; + } + + SDL_PropertiesID props = SDL_CreateProperties(); + if (props == 0) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateProperties: %s", SDL_GetError()); + return false; + } + // Workaround for https://github.com/libsdl-org/SDL/issues/10758 + SDL_SetFloatProperty(props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT, clearDepth); + + SDL_GPUTexture* texture = SDL_CreateGPUTexture(ctx->device, &(const SDL_GPUTextureCreateInfo) + { + .type = SDL_GPU_TEXTURETYPE_2D, + .format = format, + .width = width, + .height = height, + .layer_count_or_depth = 1, + .num_levels = 1, + .sample_count = SDL_GPU_SAMPLECOUNT_1, + .usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, + .props = props + }); + SDL_DestroyProperties(props); + if (!texture) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUTexture: %s", SDL_GetError()); + return false; + } + + SDL_SetGPUTextureName(ctx->device, texture, "Depth Buffer Texture"); + ctx->depthTexture = texture; + ctx->depthTextureWidth = width; + ctx->depthTextureHeight = height; + return true; +} + +char* NeHe_ResourcePath(const NeHeContext* restrict ctx, const char* const restrict resourcePath) +{ + SDL_assert(ctx && ctx->baseDir && resourcePath); + + // Build path to resouce: "{baseDir}/{resourcePath}" + const size_t baseLen = SDL_strlen(ctx->baseDir); + const size_t resourcePathLen = SDL_strlen(resourcePath); + char* path = SDL_malloc(baseLen + resourcePathLen + 1); + if (!path) + { + return NULL; + } + SDL_memcpy(path, ctx->baseDir, baseLen); + SDL_memcpy(&path[baseLen], resourcePath, resourcePathLen); + path[baseLen + resourcePathLen] = '\0'; + return path; +} + +extern inline SDL_IOStream* NeHe_OpenResource(const NeHeContext* restrict ctx, + const char* restrict resourcePath, + const char* restrict mode); + +SDL_GPUTexture* NeHe_LoadTexture(NeHeContext* restrict ctx, const char* const restrict resourcePath, + bool flipVertical, bool genMipmaps) +{ + char* path = NeHe_ResourcePath(ctx, resourcePath); + if (!path) + { + return NULL; + } + + // Load image into a surface + SDL_Surface* image = SDL_LoadBMP(path); + SDL_free(path); + if (!image) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_LoadBMP: %s", SDL_GetError()); + return NULL; + } + + // Flip surface if requested + if (flipVertical && !SDL_FlipSurface(image, SDL_FLIP_VERTICAL)) + { + SDL_DestroySurface(image); + return NULL; + } + + // Upload texture to GPU + SDL_GPUTexture* texture = NeHe_CreateGPUTextureFromSurface(ctx, image, genMipmaps); + SDL_DestroySurface(image); + if (!texture) + { + return NULL; + } + + return texture; +} + +static SDL_GPUTexture* CreateTextureFromPixels(SDL_GPUDevice* restrict device, + const void* restrict data, size_t dataSize, const SDL_GPUTextureCreateInfo* restrict createInfo, bool genMipmaps) +{ + SDL_assert(dataSize <= UINT32_MAX); + + SDL_GPUTexture* texture = SDL_CreateGPUTexture(device, createInfo); + if (!texture) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUTexture: %s", SDL_GetError()); + return NULL; + } + + // Create and copy image data to a transfer buffer + SDL_GPUTransferBuffer* xferBuffer = SDL_CreateGPUTransferBuffer(device, &(const SDL_GPUTransferBufferCreateInfo) + { + .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, + .size = (Uint32)dataSize + }); + if (!xferBuffer) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUTransferBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUTexture(device, texture); + return NULL; + } + + void* map = SDL_MapGPUTransferBuffer(device, xferBuffer, false); + if (!map) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_MapGPUTransferBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUTransferBuffer(device, xferBuffer); + SDL_ReleaseGPUTexture(device, texture); + return NULL; + } + SDL_memcpy(map, data, dataSize); + SDL_UnmapGPUTransferBuffer(device, xferBuffer); + + // Upload the transfer data to the GPU resources + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device); + if (!cmd) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_AcquireGPUCommandBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUTransferBuffer(device, xferBuffer); + SDL_ReleaseGPUTexture(device, texture); + return NULL; + } + + SDL_GPUCopyPass* pass = SDL_BeginGPUCopyPass(cmd); + SDL_UploadToGPUTexture(pass, &(const SDL_GPUTextureTransferInfo) + { + .transfer_buffer = xferBuffer, + .offset = 0 + }, &(const SDL_GPUTextureRegion) + { + .texture = texture, + .w = createInfo->width, + .h = createInfo->height, + .d = createInfo->layer_count_or_depth + }, false); + SDL_EndGPUCopyPass(pass); + + if (genMipmaps) + { + SDL_GenerateMipmapsForGPUTexture(cmd, texture); + } + + SDL_SubmitGPUCommandBuffer(cmd); + SDL_ReleaseGPUTransferBuffer(device, xferBuffer); + return texture; +} + +SDL_GPUTexture* NeHe_CreateGPUTextureFromSurface(NeHeContext* restrict ctx, const SDL_Surface* restrict surface, + bool genMipmaps) +{ + SDL_GPUTextureCreateInfo info; + SDL_zero(info); + info.type = SDL_GPU_TEXTURETYPE_2D; + info.format = SDL_GPU_TEXTUREFORMAT_INVALID; + info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; + info.width = (Uint32)surface->w; + info.height = (Uint32)surface->h; + info.layer_count_or_depth = 1; + info.num_levels = 1; + + bool needsConvert = false; + switch (surface->format) + { + // FIMXE: I'm not sure that these are endian-safe + case SDL_PIXELFORMAT_RGBA32: info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; break; + case SDL_PIXELFORMAT_RGBA64: info.format = SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM; break; + case SDL_PIXELFORMAT_RGB565: info.format = SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM; break; + case SDL_PIXELFORMAT_ARGB1555: info.format = SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM; break; + case SDL_PIXELFORMAT_BGRA4444: info.format = SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM; break; + case SDL_PIXELFORMAT_BGRA32: info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM; break; + case SDL_PIXELFORMAT_RGBA64_FLOAT: info.format = SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT; break; + case SDL_PIXELFORMAT_RGBA128_FLOAT: info.format = SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT; break; + default: + needsConvert = true; + info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; + break; + } + + size_t dataSize = (size_t)surface->w * (size_t)surface->h; + void* data = NULL; + SDL_Surface* conv = NULL; + if (needsConvert) + { + // Convert pixel format if required + if ((conv = SDL_ConvertSurface((SDL_Surface*)surface, SDL_PIXELFORMAT_ABGR8888)) == NULL) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_ConvertSurface: %s", SDL_GetError()); + SDL_free(data); + return NULL; + } + dataSize *= SDL_BYTESPERPIXEL(conv->format); + data = conv->pixels; + } + else + { + dataSize *= SDL_BYTESPERPIXEL(surface->format); + data = surface->pixels; + } + + if (genMipmaps) + { + info.usage |= SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; + // floor(log₂(max(𝑤,ℎ)) + 1 + info.num_levels = (Uint32)SDL_MostSignificantBitIndex32(SDL_max(info.width, info.height)) + 1; + } + + SDL_GPUTexture* texture = CreateTextureFromPixels(ctx->device, data, dataSize, &info, genMipmaps); + SDL_DestroySurface(conv); + return texture; +} + +static char* ReadBlob(const char* const restrict path, size_t* restrict outLength) +{ + SDL_ClearError(); + SDL_IOStream* file = SDL_IOFromFile(path, "rb"); + if (!file) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_IOFromFile: %s", SDL_GetError()); + return NULL; + } + + // Allocate a buffer of the size of the file + if (SDL_SeekIO(file, 0, SDL_IO_SEEK_END) == -1) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_SeekIO: %s", SDL_GetError()); + } + const int64_t size = SDL_TellIO(file); + char* data; + if (size < 0 || (data = SDL_malloc((size_t)size)) == NULL) + { + SDL_CloseIO(file); + return NULL; + } + if (SDL_SeekIO(file, 0, SDL_IO_SEEK_SET) != 0) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_SeekIO: %s", SDL_GetError()); + } + + SDL_ClearError(); + // Read the file contents into the buffer + const size_t read = SDL_ReadIO(file, data, (size_t)size); + if (read == 0 && SDL_GetIOStatus(file) == SDL_IO_STATUS_ERROR) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_ReadIO: %s", SDL_GetError()); + } + if (!SDL_CloseIO(file)) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CloseIO: %s", SDL_GetError()); + } + if (read != (size_t)size) + { + SDL_free(data); + return NULL; + } + + *outLength = (size_t)size; + return data; +} + +static SDL_GPUShader* LoadShaderBlob(NeHeContext* restrict ctx, + const char* restrict code, size_t codeLen, + const NeHeShaderProgramCreateInfo* restrict info, + SDL_GPUShaderFormat format, SDL_GPUShaderStage type, + const char* const restrict main) +{ + if (!code) + { + return NULL; + } + + SDL_GPUShader* shader = SDL_CreateGPUShader(ctx->device, &(const SDL_GPUShaderCreateInfo) + { + .code_size = codeLen, + .code = (const Uint8*)code, + .entrypoint = main, + .format = format, + .stage = type, + .num_samplers = (type == SDL_GPU_SHADERSTAGE_FRAGMENT) ? info->fragmentSamplers : 0, + .num_storage_buffers = (type == SDL_GPU_SHADERSTAGE_VERTEX) ? info->vertexUniforms : 0, + .num_uniform_buffers = (type == SDL_GPU_SHADERSTAGE_VERTEX) ? info->vertexUniforms : 0, + }); + if (!shader) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUShader: %s", SDL_GetError()); + return NULL; + } + return shader; +} + +static SDL_GPUShader* LoadShader(NeHeContext* restrict ctx, const char* restrict path, + const NeHeShaderProgramCreateInfo* restrict info, SDL_GPUShaderFormat format, SDL_GPUShaderStage type, + const char* const restrict main) +{ + size_t size; + char* data = ReadBlob(path, &size); + SDL_GPUShader *shader = LoadShaderBlob(ctx, data, size, info, format, type, main); + SDL_free(data); + return shader; +} + +bool NeHe_LoadShaders(NeHeContext* restrict ctx, + SDL_GPUShader** restrict outVertex, + SDL_GPUShader** restrict outFragment, + const char* restrict name, + const NeHeShaderProgramCreateInfo* restrict info) + //unsigned vertexUniforms, unsigned fragmentSamplers, unsigned vertexStorage) +{ + SDL_GPUShader *vtxShader = NULL, *frgShader = NULL; + + // Build path to shader: "{base}/Shaders/{name}.{ext}" + const char* resources = SDL_GetBasePath(); // Resources directory + const size_t resourcesLen = SDL_strlen(resources); + const size_t nameLen = SDL_strlen(name); + const size_t basenameLen = resourcesLen + 8 + nameLen; + char* path = SDL_malloc(basenameLen + 10); + if (!path) + { + return false; + } + SDL_memcpy(path, resources, resourcesLen); + SDL_memcpy(&path[resourcesLen], "Shaders", 7); + path[resourcesLen + 7] = resources[resourcesLen - 1]; // Copy path separator + SDL_memcpy(&path[resourcesLen + 8], name, nameLen); + + const SDL_GPUShaderFormat availableFormats = SDL_GetGPUShaderFormats(ctx->device); + if (availableFormats & (SDL_GPU_SHADERFORMAT_METALLIB | SDL_GPU_SHADERFORMAT_MSL)) + { + size_t size; + if (availableFormats & SDL_GPU_SHADERFORMAT_METALLIB) // Apple Metal (compiled library) + { + const SDL_GPUShaderFormat format = SDL_GPU_SHADERFORMAT_METALLIB; + SDL_memcpy(&path[basenameLen], ".metallib", 10); + char* lib = ReadBlob(path, &size); + vtxShader = LoadShaderBlob(ctx, lib, size, info, format, SDL_GPU_SHADERSTAGE_VERTEX, "VertexMain"); + frgShader = LoadShaderBlob(ctx, lib, size, info, format, SDL_GPU_SHADERSTAGE_FRAGMENT, "FragmentMain"); + SDL_free(lib); + } + if ((!vtxShader || !frgShader) && availableFormats & SDL_GPU_SHADERFORMAT_MSL) // Apple Metal (source) + { + const SDL_GPUShaderFormat format = SDL_GPU_SHADERFORMAT_MSL; + SDL_memcpy(&path[basenameLen], ".metal", 7); + char* src = ReadBlob(path, &size); + if (!vtxShader) + vtxShader = LoadShaderBlob(ctx, src, size, info, format, SDL_GPU_SHADERSTAGE_VERTEX, "VertexMain"); + if (!frgShader) + frgShader = LoadShaderBlob(ctx, src, size, info, format, SDL_GPU_SHADERSTAGE_FRAGMENT, "FragmentMain"); + SDL_free(src); + } + } + else if (availableFormats & SDL_GPU_SHADERFORMAT_SPIRV) // Vulkan + { + const SDL_GPUShaderFormat format = SDL_GPU_SHADERFORMAT_SPIRV; + SDL_memcpy(&path[basenameLen], ".vtx.spv", 9); + vtxShader = LoadShader(ctx, path, info, format, SDL_GPU_SHADERSTAGE_VERTEX, "main"); + SDL_memcpy(&path[basenameLen], ".frg.spv", 9); + frgShader = LoadShader(ctx, path, info, format, SDL_GPU_SHADERSTAGE_FRAGMENT, "main"); + } + else if (availableFormats & SDL_GPU_SHADERFORMAT_DXIL) // Direct3D 12 Shader Model 6.0 + { + const SDL_GPUShaderFormat format = SDL_GPU_SHADERFORMAT_DXIL; + SDL_memcpy(&path[basenameLen], ".vtx.dxb", 9); + vtxShader = LoadShader(ctx, path, info, format, SDL_GPU_SHADERSTAGE_VERTEX, "VertexMain"); + SDL_memcpy(&path[basenameLen], ".pxl.dxb", 9); + frgShader = LoadShader(ctx, path, info, format, SDL_GPU_SHADERSTAGE_FRAGMENT, "PixelMain"); + } + + SDL_free(path); + if (!vtxShader || !frgShader) + { + if (vtxShader) + SDL_ReleaseGPUShader(ctx->device, vtxShader); + if (frgShader) + SDL_ReleaseGPUShader(ctx->device, frgShader); + return false; + } + + *outVertex = vtxShader; + *outFragment = frgShader; + return true; +} + +SDL_GPUBuffer* NeHe_CreateVertexBuffer(NeHeContext* restrict ctx, const void* restrict vertices, uint32_t verticesSize) +{ + // Create vertex data buffer + SDL_GPUBuffer* buffer = SDL_CreateGPUBuffer(ctx->device, &(const SDL_GPUBufferCreateInfo) + { + .usage = SDL_GPU_BUFFERUSAGE_VERTEX, + .size = verticesSize + }); + if (!buffer) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUBuffer: %s", SDL_GetError()); + return false; + } + + // Create vertex transfer buffer + SDL_GPUTransferBuffer* xferBuffer = SDL_CreateGPUTransferBuffer(ctx->device, &(const SDL_GPUTransferBufferCreateInfo) + { + .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, + .size = verticesSize + }); + if (!xferBuffer) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUTransferBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUBuffer(ctx->device, buffer); + return false; + } + + // Map transfer buffer and copy the vertex data + Uint8* map = SDL_MapGPUTransferBuffer(ctx->device, xferBuffer, false); + if (!map) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_MapGPUTransferBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUTransferBuffer(ctx->device, xferBuffer); + SDL_ReleaseGPUBuffer(ctx->device, buffer); + return false; + } + SDL_memcpy(map, vertices, (size_t)verticesSize); + SDL_UnmapGPUTransferBuffer(ctx->device, xferBuffer); + + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(ctx->device); + if (!cmd) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_AcquireGPUCommandBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUTransferBuffer(ctx->device, xferBuffer); + SDL_ReleaseGPUBuffer(ctx->device, buffer); + return false; + } + + // Upload the vertex & index data into the GPU buffer(s) + SDL_GPUCopyPass* pass = SDL_BeginGPUCopyPass(cmd); + SDL_UploadToGPUBuffer(pass, &(const SDL_GPUTransferBufferLocation) + { + .transfer_buffer = xferBuffer, + .offset = 0 + }, &(const SDL_GPUBufferRegion) + { + .buffer = buffer, + .offset = 0, + .size = verticesSize + }, false); + SDL_EndGPUCopyPass(pass); + SDL_SubmitGPUCommandBuffer(cmd); + + SDL_ReleaseGPUTransferBuffer(ctx->device, xferBuffer); + + return buffer; +} + +bool NeHe_CreateVertexIndexBuffer(NeHeContext* restrict ctx, + SDL_GPUBuffer** restrict outVertexBuffer, + SDL_GPUBuffer** restrict outIndexBuffer, + const void* restrict vertices, uint32_t verticesSize, + const void* restrict indices, uint32_t indicesSize) +{ + // Create vertex data buffer + SDL_GPUBuffer* vtxBuffer = SDL_CreateGPUBuffer(ctx->device, &(const SDL_GPUBufferCreateInfo) + { + .usage = SDL_GPU_BUFFERUSAGE_VERTEX, + .size = verticesSize + }); + if (!vtxBuffer) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUBuffer: %s", SDL_GetError()); + return false; + } + + // Create index data buffer + SDL_GPUBuffer* idxBuffer = SDL_CreateGPUBuffer(ctx->device, &(const SDL_GPUBufferCreateInfo) + { + .usage = SDL_GPU_BUFFERUSAGE_INDEX, + .size = indicesSize + }); + if (!idxBuffer) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + return false; + } + + // Create vertex transfer buffer + SDL_GPUTransferBuffer* vtxXferBuffer = SDL_CreateGPUTransferBuffer(ctx->device, &(const SDL_GPUTransferBufferCreateInfo) + { + .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, + .size = verticesSize + }); + if (!vtxXferBuffer) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUTransferBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + return false; + } + + // Create index transfer buffer + SDL_GPUTransferBuffer* idxXferBuffer = SDL_CreateGPUTransferBuffer(ctx->device, &(const SDL_GPUTransferBufferCreateInfo) + { + .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, + .size = indicesSize + }); + if (!idxXferBuffer) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUTransferBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUTransferBuffer(ctx->device, vtxXferBuffer); + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + return false; + } + + // Map transfer buffer and copy the vertex data + Uint8* map = SDL_MapGPUTransferBuffer(ctx->device, vtxXferBuffer, false); + if (!map) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_MapGPUTransferBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUTransferBuffer(ctx->device, idxXferBuffer); + SDL_ReleaseGPUTransferBuffer(ctx->device, vtxXferBuffer); + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + return false; + } + SDL_memcpy(map, vertices, (size_t)verticesSize); + SDL_UnmapGPUTransferBuffer(ctx->device, vtxXferBuffer); + + // Map transfer buffer and copy the index data + map = SDL_MapGPUTransferBuffer(ctx->device, idxXferBuffer, false); + if (!map) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_MapGPUTransferBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUTransferBuffer(ctx->device, idxXferBuffer); + SDL_ReleaseGPUTransferBuffer(ctx->device, vtxXferBuffer); + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + return false; + } + SDL_memcpy(map, indices, (size_t)indicesSize); + SDL_UnmapGPUTransferBuffer(ctx->device, idxXferBuffer); + + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(ctx->device); + if (!cmd) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_AcquireGPUCommandBuffer: %s", SDL_GetError()); + SDL_ReleaseGPUTransferBuffer(ctx->device, idxXferBuffer); + SDL_ReleaseGPUTransferBuffer(ctx->device, vtxXferBuffer); + SDL_ReleaseGPUBuffer(ctx->device, idxBuffer); + SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer); + return false; + } + + // Upload the vertex & index data into the GPU buffer(s) + SDL_GPUCopyPass* pass = SDL_BeginGPUCopyPass(cmd); + SDL_UploadToGPUBuffer(pass, &(const SDL_GPUTransferBufferLocation) + { + .transfer_buffer = vtxXferBuffer, + .offset = 0 + }, &(const SDL_GPUBufferRegion) + { + .buffer = vtxBuffer, + .offset = 0, + .size = verticesSize + }, false); + SDL_UploadToGPUBuffer(pass, &(const SDL_GPUTransferBufferLocation) + { + .transfer_buffer = idxXferBuffer, + .offset = 0 + }, &(const SDL_GPUBufferRegion) + { + .buffer = idxBuffer, + .offset = 0, + .size = indicesSize + }, false); + SDL_EndGPUCopyPass(pass); + SDL_SubmitGPUCommandBuffer(cmd); + + SDL_ReleaseGPUTransferBuffer(ctx->device, idxXferBuffer); + SDL_ReleaseGPUTransferBuffer(ctx->device, vtxXferBuffer); + + *outVertexBuffer = vtxBuffer; + *outIndexBuffer = idxBuffer; + return true; +} diff --git a/src/c/nehe.h b/src/c/nehe.h new file mode 100644 index 0000000..2f72ef1 --- /dev/null +++ b/src/c/nehe.h @@ -0,0 +1,62 @@ +#ifndef NEHE_H +#define NEHE_H + +#include "application.h" +#include "matrix.h" + +#include +#include +#include + +typedef struct NeHeContext +{ + SDL_Window* window; + SDL_GPUDevice* device; + SDL_GPUTexture* depthTexture; + uint32_t depthTextureWidth, depthTextureHeight; + + const char* baseDir; + +} NeHeContext; + +typedef struct +{ + unsigned vertexUniforms; + unsigned vertexStorage; + unsigned fragmentSamplers; +} NeHeShaderProgramCreateInfo; + +bool NeHe_InitGPU(NeHeContext* ctx, const char* title, int width, int height); +bool NeHe_SetupDepthTexture(NeHeContext* ctx, uint32_t width, uint32_t height, + SDL_GPUTextureFormat format, float clearDepth); +char* NeHe_ResourcePath(const NeHeContext* restrict ctx, const char* restrict resourcePath); +inline SDL_IOStream* NeHe_OpenResource(const NeHeContext* restrict ctx, + const char* const restrict resourcePath, + const char* const restrict mode) +{ + char* path = NeHe_ResourcePath(ctx, resourcePath); + if (!path) + { + return NULL; + } + SDL_IOStream* file = SDL_IOFromFile(path, mode); + SDL_free(path); + return file; +} +SDL_GPUTexture* NeHe_LoadTexture(NeHeContext* restrict ctx, const char* restrict resourcePath, + bool flipVertical, bool genMipmaps); +SDL_GPUTexture* NeHe_CreateGPUTextureFromSurface(NeHeContext* restrict ctx, const SDL_Surface* restrict surface, + bool genMipmaps); +bool NeHe_LoadShaders(NeHeContext* restrict ctx, + SDL_GPUShader** restrict outVertex, + SDL_GPUShader** restrict outFragment, + const char* restrict name, + const NeHeShaderProgramCreateInfo* restrict info); +SDL_GPUBuffer* NeHe_CreateVertexBuffer(NeHeContext* restrict ctx, const void* restrict vertices, uint32_t verticesSize); +bool NeHe_CreateVertexIndexBuffer(NeHeContext* restrict ctx, + SDL_GPUBuffer** restrict outVertexBuffer, + SDL_GPUBuffer** restrict outIndexBuffer, + const void* restrict vertices, uint32_t verticesSize, + const void* restrict indices, uint32_t indicesSize); + +#endif//NEHE_H diff --git a/src/shaders/lesson2.metal b/src/shaders/lesson2.metal new file mode 100644 index 0000000..7bb7c8c --- /dev/null +++ b/src/shaders/lesson2.metal @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include +#include + +struct VertexInput +{ + float3 position [[attribute(0)]]; +}; + +struct VertexUniform +{ + metal::float4x4 viewproj; +}; + +struct Vertex2Fragment +{ + float4 position [[position]]; +}; + +vertex Vertex2Fragment VertexMain( + VertexInput in [[stage_in]], + constant VertexUniform& u [[buffer(0)]]) +{ + Vertex2Fragment out; + out.position = u.viewproj * float4(in.position, 1.0); + return out; +} + +fragment half4 FragmentMain(Vertex2Fragment in [[stage_in]]) +{ + return half4(1.0); +} diff --git a/src/shaders/lesson3.metal b/src/shaders/lesson3.metal new file mode 100644 index 0000000..e87d096 --- /dev/null +++ b/src/shaders/lesson3.metal @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include +#include + +struct VertexInput +{ + float3 position [[attribute(0)]]; + float4 color [[attribute(1)]]; +}; + +struct VertexUniform +{ + metal::float4x4 viewproj; +}; + +struct Vertex2Fragment +{ + float4 position [[position]]; + half4 color; +}; + +vertex Vertex2Fragment VertexMain( + VertexInput in [[stage_in]], + constant VertexUniform& u [[buffer(0)]]) +{ + Vertex2Fragment out; + out.position = u.viewproj * float4(in.position, 1.0); + out.color = half4(in.color); + return out; +} + +fragment half4 FragmentMain(Vertex2Fragment in [[stage_in]]) +{ + return in.color; +} diff --git a/src/shaders/lesson6.metal b/src/shaders/lesson6.metal new file mode 100644 index 0000000..6ef0955 --- /dev/null +++ b/src/shaders/lesson6.metal @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include +#include + +struct VertexInput +{ + float3 position [[attribute(0)]]; + float2 texcoord [[attribute(1)]]; +}; + +struct VertexUniform +{ + metal::float4x4 viewproj; + float4 color; +}; + +struct Vertex2Fragment +{ + float4 position [[position]]; + float2 texcoord; + half4 color; +}; + +vertex Vertex2Fragment VertexMain( + VertexInput in [[stage_in]], + constant VertexUniform& u [[buffer(0)]]) +{ + Vertex2Fragment out; + out.position = u.viewproj * float4(in.position, 1.0); + out.texcoord = in.texcoord; + out.color = half4(u.color); + return out; +} + +fragment half4 FragmentMain( + Vertex2Fragment in [[stage_in]], + metal::texture2d texture [[texture(0)]], + metal::sampler sampler [[sampler(0)]]) +{ + return in.color * texture.sample(sampler, in.texcoord); +} diff --git a/src/shaders/lesson7.metal b/src/shaders/lesson7.metal new file mode 100644 index 0000000..a680ad4 --- /dev/null +++ b/src/shaders/lesson7.metal @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include +#include + +struct VertexInput +{ + float3 position [[attribute(0)]]; + float2 texcoord [[attribute(1)]]; + float3 normal [[attribute(2)]]; +}; + +struct VertexUniform +{ + metal::float4x4 modelView; + metal::float4x4 projection; +}; + +struct Light +{ + float4 ambient; + float4 diffuse; + float4 position; +}; + +struct Vertex2Fragment +{ + float4 position [[position]]; + float2 texcoord; + half4 color; +}; + +vertex Vertex2Fragment VertexMain( + VertexInput in [[stage_in]], + constant VertexUniform& u [[buffer(0)]], + constant Light& light [[buffer(1)]]) +{ + const auto position = u.modelView * float4(in.position, 1.0); + const auto normal = metal::normalize(u.modelView * float4(in.normal, 0.0)).xyz; + + const auto lightVec = light.position.xyz - position.xyz; + const auto lightDist2 = metal::length_squared(lightVec); + const auto dir = metal::rsqrt(lightDist2) * lightVec; + const auto lambert = metal::max(0.0, metal::dot(normal, dir)); + + const auto ambient = 0.04 + 0.2 * half3(light.ambient.rgb); + const auto diffuse = 0.8 * half3(light.diffuse.rgb); + + Vertex2Fragment out; + out.position = u.projection * position; + out.texcoord = in.texcoord; + out.color = half4(ambient + lambert * diffuse, 1.0); + return out; +} + +fragment half4 FragmentMain( + Vertex2Fragment in [[stage_in]], + metal::texture2d texture [[texture(0)]], + metal::sampler sampler [[sampler(0)]]) +{ + return in.color * texture.sample(sampler, in.texcoord); +} diff --git a/src/shaders/lesson9.metal b/src/shaders/lesson9.metal new file mode 100644 index 0000000..6a2130f --- /dev/null +++ b/src/shaders/lesson9.metal @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: (C) 2025 a dinosaur + * SPDX-License-Identifier: Zlib + */ + +#include +#include + +struct VertexInput +{ + float3 position [[attribute(0)]]; + float2 texcoord [[attribute(1)]]; +}; + +struct VertexInstance +{ + metal::float4x4 model; + float4 color; +}; + +struct VertexUniform +{ + metal::float4x4 projection; +}; + +struct Vertex2Fragment +{ + float4 position [[position]]; + float2 texcoord; + half4 color; +}; + +vertex Vertex2Fragment VertexMain( + VertexInput in [[stage_in]], + const device VertexInstance* instance [[buffer(1)]], + constant VertexUniform& u [[buffer(0)]], + const uint instanceIdx [[instance_id]]) +{ + Vertex2Fragment out; + out.position = u.projection * instance[instanceIdx].model * float4(in.position, 1.0); + out.texcoord = in.texcoord; + out.color = half4(instance[instanceIdx].color); + return out; +} + +fragment half4 FragmentMain( + Vertex2Fragment in [[stage_in]], + metal::texture2d texture [[texture(0)]], + metal::sampler sampler [[sampler(0)]]) +{ + return in.color * texture.sample(sampler, in.texcoord); +}