SPIR-V and the New Shader System // Game Engine series

Patreon ► / thecherno
Instagram ► / thecherno
Twitch ► / thecherno
Twitter ► / thecherno
Discord ► thecherno.com/discord
Hazel ► github.com/TheCherno/Hazel
Chapters
0:00 Intro and series discussion
5:10 Viewing specific commits
7:10 Shader system and Vulkan
10:40 Uniform buffers
17:10 Additional GLSL changes
21:00 SPIR-V
22:02 The new shader pipeline
35:00 Code overview
49:05 Next time and Outro
Series Playlist ► thecherno.com/engine
#Hazel

Пікірлер: 114

  • @TheCherno
    @TheCherno3 жыл бұрын

    Excited to be back with the Game Engine series! Let me know what you thought of this new format. I've put some timestamps into the video so that it's a little easier to navigate since it ended up being so long. Enjoy! ❤️

  • @antopilo7418

    @antopilo7418

    3 жыл бұрын

    Make whatever makes you happy!

  • @stormsoendergaard3023

    @stormsoendergaard3023

    3 жыл бұрын

    I really like this format, way more than the other iterations. This is, to me, way more educational, since it's mostly theory - i think everyone that still follows the series should be experienced enough to write their own code without too much hand holding. Also, stop apologizing for long videos - long videos are great, it's better than rushing the explanation!

  • @motbus3

    @motbus3

    3 жыл бұрын

    well you asked for opinions so here is mine I know there are advanced graphics developers see stuff here but probably most won't know the basics. many things were explained in opengl series and some times it would be nice to point to that content as you used to do. things are getting more complicated. so I think it would be nice to start drawing the basic architecture layout in the start of the video and explain what you'll be talking about. I'm not saying what you should or shouldn't but I was trying to build the engine alongside when moved to twitch stuff I couldn't keep up. streams take too much time and if I would learn something I would have to pay attention for hours straight. nothing wrong with that. guess it's not just for me. I keep checking new videos because I hope someday you'll do a short resumed version of the contents you had to do in these other formats. but for now I guess I can't keep up anymore. good luck! see ya!

  • @stormsoendergaard3023

    @stormsoendergaard3023

    3 жыл бұрын

    @@motbus3 I agree that high level architecture explanations (or even visualized with flow-map or something similar) would be a nice way to keep the complicated matters on a more easily understandable level.

  • @mbielcik

    @mbielcik

    3 жыл бұрын

    I too liked this longer format video better, than the shorter ones.

  • @teckleedeyi
    @teckleedeyi3 жыл бұрын

    in what feels like a blink of an eye its been a whopping 100 episodes of the game engine series! As a student i have learnt so much from you and want to say a massive thanks for doing this despite how little it may make for you in comparison to other videos, you still continue to make them! Im extremely thankful and grateful for that, cheers to another 100 more episodes :V

  • @jonphillips4082
    @jonphillips40823 жыл бұрын

    Love the format, especially when you drop a load of information like this, whew!, and more on the way! This is a better solution for these large sections within these topics. I'm looking forward to watching the devlogs too!, Great Job!

  • @kye2920
    @kye29203 жыл бұрын

    awesome vid!! I really enjoyed the format, and I'm so excited to check out the twitch streams!

  • @morthim
    @morthim3 жыл бұрын

    ""basicly that is how the shader pipeline works: we take the vukan gsl code, we compile it using spir-v into a binary file, we then take that binary file and feed it into teh cross compiler which gives us the opengl compatible gsl text file, which is just a string. we take that string and compile it but this time using open gl. and then we cage both those binary files to disk. and we can give that to open gl into a binary. the one step that i missed there is the reflection step. what fresh hell has youtube caused me to stumble into?

  • @rafavillegasmichel
    @rafavillegasmichel3 жыл бұрын

    Great video Cherno! Love the new format. Looking forward to the next video. Cheers!

  • @nikolaiarsenov1595
    @nikolaiarsenov15953 жыл бұрын

    Very great explanation :) I love the new format.

  • @kikiwunder6114
    @kikiwunder61143 жыл бұрын

    Prolly the best video you've done in terms of pacing and info amount. I prefer these longer ones, too.

  • @Xblade45
    @Xblade453 жыл бұрын

    You should probably declare all those hardcoded filepaths/filenames, etc as const somewhere easier to update/reference than having them burried in funcs :)

  • @ChrisGripeos
    @ChrisGripeos3 жыл бұрын

    Perfect timing! I've been building a renderer/game-engine using the WebGPU API (w. C++ binding) from the Mozilla peoples. It works with SPIR-V shaders. Thanks!

  • @lightusmax5287
    @lightusmax52873 жыл бұрын

    Hey! Thanks for vids! Idea for a video: Character encodings in C++, Unicode (utf-8, utf-16, etc.), ASCII and how to deal with all this stuff.

  • @F1nalspace
    @F1nalspace3 жыл бұрын

    All that new stuff, Uniform Buffers, Layout Locations, Command Buffers are very new to me - compared to OpenGL 2.x, which I used for 15 years now. But i understand it now, thanks to your explanation ;) Good format btw, I like that.

  • @DalasYoo
    @DalasYoo3 жыл бұрын

    Such a good tutorial on the shader cpmpilation and the all of graphics :)

  • @mr.mirror1213
    @mr.mirror12133 жыл бұрын

    CHERNO PLS vulkan series 😍❤️❤️❤️(LOVE UR OPENGL SERIES)

  • @mr.mirror1213

    @mr.mirror1213

    3 жыл бұрын

    @@JaceMorley 😂😂😂😂 true , i tried learning from websites but too much steep learning curve

  • @regbot4432

    @regbot4432

    3 жыл бұрын

    Yes. Let's make cherno do like 5 series simultaneously. There is only one cherno, if he dies we are in damn big problem.

  • @QuietSnake-xs5vx
    @QuietSnake-xs5vx3 жыл бұрын

    Hair looks magnificent in this vid for some reason ...cheers!

  • @xvoidee
    @xvoidee3 жыл бұрын

    I do not program rendering engine at the moment, but your English and pronunciation is awesome :) listening your casts to improve my skills.

  • @maynoaria6361
    @maynoaria63613 жыл бұрын

    Your hair looks amazing btw!

  • @xraynova8295
    @xraynova82953 жыл бұрын

    glClipControl() is your friend if you want to automatically set the depth range to 0 to 1 to be consistent with other APIs

  • @SimonBuchanNz
    @SimonBuchanNz3 жыл бұрын

    33:30: regarding using define vs a uniform for handling opengl vs Vulkan differences: Vulkan at least also has shader constants you can set when loading a shader, which could handle some cases.

  • @ruadeil_zabelin
    @ruadeil_zabelin3 жыл бұрын

    One thing to mention is that it's probably wise to have multiple uniform buffers, grouped based on update frequency. So for example you'd have one for the camera, maybe a seperate one for dynamic lighting, yet another one for any other data, and so on. Another thing that might be interresting to people; Unreal Engine uses HLSL (the directx shader language) as its shading language for everything; even when running opengl and vulkan. They use the hlsl to spir-v compiler to achieve this.

  • @ddanielsandberg
    @ddanielsandberg3 жыл бұрын

    It might be a good idea to store SHA-1 digests (of the shader source) together with the shader cache. That way we can do cache invalidation and recompile if any shaders has changed. Maybe handling dependencies/includes in such a way that we only recompile the shaders that has changed.

  • @n1ghtyunso

    @n1ghtyunso

    3 жыл бұрын

    @Biotorial as there's no cryptographic requirement involved, there certainly are much more lightweight alternatives than sha-1

  • @nullpointer1284

    @nullpointer1284

    3 жыл бұрын

    @@n1ghtyunso sha-1 hashes are implemented in hardware in many CPUs

  • @ThePC007

    @ThePC007

    7 ай бұрын

    @@nullpointer1284 I believe the same is true for CRC32, isn’t it?

  • @redox5373
    @redox53733 жыл бұрын

    Congrats, that's your 100th video in game engine series

  • @SionGRG
    @SionGRG Жыл бұрын

    Hey! Thanks for the videos! very helpful. After adding the Vulkan SDK and using the New Shader System, I encountered an error where after loading in the scene file, I would get a blank viewport even though in the scene hierarchy panel it seemed that the entities had loaded in correctly and are clickable too. After rigorous debugging I found out that the 'CalculatePosition()' function in the "Editor Camera" Class was producing an incorrect z-value (basically -z; z being the value i.e 10), after further investigation I found out that the error was coming from the 'GetForwardDirection()' function from the same class, to be specific it's on the glm::rotate() function being called. To my understanding, the problem was as a result of the glm commit version I am using (which is from Jan 13 2023, Hazel is using the one from Jan 22 2019) and since the Vulkan SDK also uses glm at some point it may have caused a change in the way the quaternion data is used by defining the macro "GLM_FORCE_QUAT_DATA_XYZW". *Fix: #define GLM_FORCE_QUAT_DATA_WXYZ macro before including #include in EditorCamera.cpp file, if you are using a newer version of glm * To reproduce the error if you are using a newer version of glm #define GLM_FORCE_QUAT_DATA_XYZW macro before including #include in EditorCamera.cpp file. (Note: I haven't investigated at which commit point in the glm repo this become a problem). I hope this helps anyone whose facing the same problem :)

  • @izzynab332
    @izzynab3323 жыл бұрын

    giga koksem jestes nie zmieniaj się!!!

  • @_general_error
    @_general_error2 жыл бұрын

    You should write a doc comment in each c++ source file to summarize why it is needed and what it is doing... your code abstraction would be easier to understand and see what features the engine supports.

  • @moeman1984
    @moeman19842 жыл бұрын

    What did you use for glsl reflection? The stuff that tells you the uniforms and bindings.

  • @hjups
    @hjups3 жыл бұрын

    I believe the layout increment in your VertexOutput is because each variable gets packed into 16 bytes. So to use fewer layout slots, you would want to do vec4 Color; vec4 TexCoord;, where TexCoord.z = texIndex, and TexCoord.w = TilingFactor. I'm not sure if it really makes much of a difference though, except with the layout packing efficiency. For example, if you look at the AMD ISA (I don't believe NVidia shows their ISA from any language other than CUDA), then you will see that the interpolation is done via a 2-stage VINTERP instruction. The VINTERP is done once per "word", so Color would take 4 passes = 4*4 = 16 instructions. However, the interpolation is done by setting an attribute to select from (encoded in the instruction - there are 64 on RDNA each with 4 channels). So by doing what you did, it probably consumes some padding in memory, and also uses 4/64 attributes vs 2/64 (not a big difference if you only use 5 at most). However, flat vs linear DOES matter. Because, doing a flat interpolation, the coefficient is loaded from memory without any interpolation instructions. This allows you to save 1 instruction per interpolation. Additionally, it means that the barycentric coordinates don't have to be loaded / re-used, which frees up registers faster, etc.

  • @SimonBuchanNz

    @SimonBuchanNz

    3 жыл бұрын

    IIRC you can apply one of the std* layouts to tell it to pack, right? Or even apply specific offsets.

  • @hjups

    @hjups

    3 жыл бұрын

    ​@@SimonBuchanNz I'm not sure to be honest, but I wouldn't trust the std* layouts to do that for me. i.e. it's always safer to be explicit.

  • @shavais33
    @shavais336 ай бұрын

    One of the things that I do in the games I work on is use custom shaders that I write myself. For example I have a starfield point shader I made that has a smooth parallax based on each individual star distance rather than having some number of distinct layers of stars. I need to be able to write the code for that shader, pass uniforms to it, give it a custom vertex buffer, etc. There are a whole lot of applications for custom shaders in games, beyond simply using them for materials. This is one of the reasons I don't currently use a game engine - I haven't figured out how to use custom shaders that I write myself with Unity, for example, and setup buffers for them and pass uniforms to them and so on.

  • @allluckyseven
    @allluckyseven3 жыл бұрын

    Cherno, I don't know if this is a comment that's appropriate for this channel or the other, but one thing I would like to see being discussed is, if you know about them, which I guess you do, how trees are usually handled by engines in general. Specifically, how do they make the branches and leaves move in the wind and with character movement. Are they simply warped or are they rigged and have bones inside... That kind of thing. Maybe most people would buy their assets online instead of building them in-house, and in this case, what do people get when they buy this stuff other than the mesh itself and its textures, and what do they have to do with them once they get them. I guess that could eventually be expanded to how do engines deal with "blank". I think people could benefit from knowing which approach, if there are multiple ones, would be better for their game. By the way if you have discussed this already elsewhere, please let me know where. Thanks!

  • @ariseyhun2085
    @ariseyhun20853 жыл бұрын

    Hey man, I'd absolutely love to see you express your thoughts on Rust programming language. Have you used it? Whats your thoughts on it?

  • @fanisdeli
    @fanisdeli3 жыл бұрын

    If you have the time, I think before you go into Vulkan in the game engine series, it'd be amazing if you made a "Vulkan Basics" series, like the other OpenGL series you have. It'll be crazy helpful for us noobs!

  • @Borgilian

    @Borgilian

    3 жыл бұрын

    You're better off learning OpenGL AZDO as a beginner. Vulkan is a bad API which has no reason to exist.... and you can't use portability as an excuse. Apple has Metal, and writing Vulkan on an Apple device is stupid because it's automatically translated to Metal... that's just one more layer of indirection and performance overhead. On Windows you have directx 11 and 12, which I might say are better APIs than OpenGL and Vulkan, and there's no point not writing in the platform's native supported API. What about Linux? Well, it doesn't really have a native API, so you might as well go OpenGL. Same for Android.

  • @SimonBuchanNz

    @SimonBuchanNz

    3 жыл бұрын

    @@Borgilian Vulkan is the industries best agreed on definition of how hardware works. MoltenVK is stupid fast, as Metal is incredibly close to Vulkan and the Vulkan loader API design means you don't have any interception layer thing going on, you're directly calling a very simple wrapper (and certainly the obj-C runtime will be slower) Vulkan lets you write very specific behavior that can run on just about any platform, and you can still access vendor extensions with little effort. Vulkan has every reason to exist.

  • @danyildiabin4953
    @danyildiabin49533 жыл бұрын

    I like the new organization principle

  • @kebrus
    @kebrus3 жыл бұрын

    this looks very similar to how unity works, have you consider using a wrapper like shaderlab from unity?

  • @goodwayman
    @goodwayman3 жыл бұрын

    I don't know if somebody mentioned this, but as of OpenGL 4.6, it's possible to load SPIR-v shaders directly using OpenGL API (see ARB_spirv_extensions).

  • @oostenjadenhtv
    @oostenjadenhtv2 жыл бұрын

    Any advice on integrating shaderc into my own projects? The dependencies and the number of CMake targets it generates is insane. There's got to be an easier way!

  • @sam_is_people1170
    @sam_is_people11702 жыл бұрын

    thanks!

  • @StephanusTavilrond
    @StephanusTavilrond3 жыл бұрын

    You can actually compile HLSL into SPIRV tho. Just sayin'. Love your videos btw.

  • @tannermahofski4441
    @tannermahofski44413 жыл бұрын

    Can you give your opinion of using OpenGL or Vulkan with c++ vs something like lwjgl OpenGL or vulkan for Java?

  • @justdaniel3510
    @justdaniel35103 жыл бұрын

    Cherno, thank you for a great content. Do you speak russian?

  • @ChronoTales17
    @ChronoTales173 жыл бұрын

    i am also working on an engine but i am on linux and having some issues compiling and adding glfw in an ide

  • @Kaolidas
    @Kaolidas3 жыл бұрын

    5:20 Oh no, my eyes are burning 🌒🌓🌔🌕👀. Cherno please consider using Github's dark mode😉. I am not against to light mode, but abrupt transition from dark mode to light mode is kinda painful.

  • @brunomarques5258
    @brunomarques52583 жыл бұрын

    Do You have plans to add D3D12? in that case, I'm working to add support

  • @ruadeil_zabelin

    @ruadeil_zabelin

    3 жыл бұрын

    Coming from years (10+) of just opengl, I struggled a bit to wrap my head around Vulkan fully. Recently I ported my code to dx11, and later dx12 and then suddenly a lot more vulkan things started to make sense.

  • @nullbeyondo

    @nullbeyondo

    2 жыл бұрын

    I don't think so. Just let go of DirectX. OpenGL/Vulkan are superior cause they can cross-compile to all platforms except Xbox. I realize that you may be more comfortable with DirectX but it is unnecessary at the moment and there are far greater priorities to be taken care of in the engine currently. Hopefully one day but I don't think anytime soon.

  • @Marcus615
    @Marcus6153 жыл бұрын

    Heads up, you forgot the Twitch link in the description !

  • Жыл бұрын

    I have a bit of a problem, I don't know if Cherno had it also. When I change tag of an ent through the text box and mouse pick another ent it gets the same name. This only happens when I change a name of an ent. Any thoughts from you guys?

  • @arsenbabaev1022

    @arsenbabaev1022

    10 ай бұрын

    Probably a bit late but its due to how ImGui ids work. When you select other entity ImGui will draw the same TextBox component but in context of other entity, and in the same frame TextBox input is applied to the wrong entity. I didnt solve this in my project yet. But possible solution is using ImGui::PushID around the TextBox code with for example UUID of the entity, maybe it will help.

  • @SeoFernando
    @SeoFernando3 жыл бұрын

    Wouldn't HLSL make more sense than GLSL since it converts to SPIR-V anyways (and is also the main language in gameDev)? (pls correct me if I'm wrong)

  • @moeman1984
    @moeman19842 жыл бұрын

    I'm pretty sure the index into a sampler2D array has to a "dynamically uniform" expression, you can't use an index passed in as an attribute. Pretty sure about that.

  • @MrProdigy65
    @MrProdigy653 жыл бұрын

    this is the most interesting video I did not understand

  • @i_sirojiddinov
    @i_sirojiddinov3 жыл бұрын

    Please more video about making a game engine

  • @olegartamonov3439
    @olegartamonov34392 жыл бұрын

    What theme do you use? I cant find it anywhere

  • @Ev3r0x

    @Ev3r0x

    2 жыл бұрын

    From visual assist

  • @santi5655
    @santi56553 жыл бұрын

    how about a vulkan series?

  • @pvtnewb
    @pvtnewb3 жыл бұрын

    ooo yea SPIRV time

  • @beautifulmind684
    @beautifulmind6842 жыл бұрын

    question: the diff tool seems so cool, could you please share the name of it? thx very much!

  • @Ev3r0x

    @Ev3r0x

    2 жыл бұрын

    fork

  • @BackerSultan
    @BackerSultan3 жыл бұрын

    9:30 I'm not sure what the code actually does, but I see you're using a switch and just providing the index to the array. Why not just omitting the switch and writing: `texColor *= texture(u_Textures[Input.texIndex], ... ` ?

  • @TheCherno

    @TheCherno

    3 жыл бұрын

    Because that’s not valid GLSL (you’re not allowed to index sampler arrays like that), it won’t work on all drivers

  • @BackerSultan

    @BackerSultan

    3 жыл бұрын

    @@TheCherno Thanks for the clarification! Your videos are great btw! keep it up!

  • @ChronoTales17
    @ChronoTales173 жыл бұрын

    Hey cherno can you do a vid on how to compile glfw on linux please and add it to codeblocks

  • @LittleRainGames
    @LittleRainGames3 жыл бұрын

    Any plan on implementing CG so you dont have to write 2 shaders? Nevermind, i thought DX was going to be supported, guess you did vulkan instead.

  • @SimonBuchanNz

    @SimonBuchanNz

    3 жыл бұрын

    "Cg has been discontinued and NVIDIA doesn't recommend to use it for new projects." SPIR-V is the new Cg.

  • @slBrelaz
    @slBrelaz3 жыл бұрын

    You can get diffs for branches and make patches for branches (even against older versions of main) so you don't need to stop committing just to get a diff to show the audience when you make these videos. Just tag the version of main you had at the point of the last vlog (you don't even need to push the tag to the remote) and then run a diff between your latest commit and that tag.

  • @amir_habibi79
    @amir_habibi793 жыл бұрын

    what is your mic? plz I need to know 😘😘😘😘😘😘

  • @brunomarques5258
    @brunomarques5258 Жыл бұрын

    Vulkan is more similar to Direct3D than OpenGL, it also supports HLSL

  • @mr_ggg5370
    @mr_ggg53703 жыл бұрын

    can you make hazel open sours

  • @sub_zero_911
    @sub_zero_9113 жыл бұрын

    Cherno, I have a very interesting proposal for you game engine. How can I get hold of you?

  • @Conversion108
    @Conversion1083 жыл бұрын

    can you make a web browser tutorial?

  • @guywithknife
    @guywithknife3 жыл бұрын

    What's a kay-shh ;-)

  • @grieferpolizei4948
    @grieferpolizei49483 жыл бұрын

    Looks like a depth-log ;-) .... bad joke I know

  • @kilngod1943
    @kilngod19433 жыл бұрын

    WebGL?

  • @nullbeyondo

    @nullbeyondo

    2 жыл бұрын

    That's actually a possibility since this engine is exclusively for OpenGL/Vulkan but let's keep browser support for later cause it is meaningless currently.

  • @p3rk4n27
    @p3rk4n27 Жыл бұрын

    Well... this episode didn't age very well

  • @JustATempest
    @JustATempest3 жыл бұрын

    I'm sorry you've made my day. I'm pretty sure you're supposed to say cache like cash.

  • @TheCherno

    @TheCherno

    3 жыл бұрын

    I’ve always tossed up which pronunciation to go with, because here in Australia we pronounce that word as “kaysh” but in tech most people say “kash”

  • @jaycelee8453
    @jaycelee84532 жыл бұрын

    i love ed sheeran

  • @danielyrovas
    @danielyrovas3 жыл бұрын

    early damn

  • @yogeshpanzade5572
    @yogeshpanzade55723 жыл бұрын

    First

  • @oukid2633
    @oukid26333 жыл бұрын

    First :)

  • @AbuUbaida89
    @AbuUbaida893 жыл бұрын

    Bro please recommend me the best book on c++/oop cuz I wanna be professional not just by videos!

  • @rubberduckdebug

    @rubberduckdebug

    3 жыл бұрын

    The Cherno's C++ series is honesty the best programming series I've ever seen, even better than any paid course that I've had. As for other resources, all the things you'll find in books you'll find online, with the added benefit that they can be revised and updated to include the latest C++ features as the language updates, unlike books. The only time I think a book would be decent is if it targets fundamentals or a specific topic.

  • @AbuUbaida89

    @AbuUbaida89

    3 жыл бұрын

    @@rubberduckdebug the cherno c++ series isn't good for beginners 🙂 I believe it's for a bit advanced cuz i can't understand him, i actually watched like 10 or 20 episodes but shifted to Caleb curry, once i finished watching Caleb curry I'll watch the cherno in Sha Allah 😊🙂❤️

  • @ausieaxemurderboyz1711

    @ausieaxemurderboyz1711

    3 жыл бұрын

    a book doesn't make u professional. the only thing to make u that is schooling/university/diploma/software development courses, note a professional doent mean god tier or even good for that fact. you dont need to be professional you just need to first learn the fundamentals of how ALL code works. this excludes Asm And such as nobody in 2021 use these often for creating stuff. but all these regular languages are all the same with there own punctuation and words for things. but they all have the SAME Fundamentals. math ect once you learn this you can learn any language with ease l

  • @Wanderlust073

    @Wanderlust073

    3 жыл бұрын

    If you are starting from zero knowledge get The C Programming Language by kernighan and ritchie. That covers the fundamentals, after which you can bootstrap into c++ via other books or endless courses on udemy or youtube or whatever. A lot of the expertise comes from writing (and writing and writing and writing) code, so I wouldn’t get too hung up on finding the perfect book(s).

  • @AbuUbaida89

    @AbuUbaida89

    3 жыл бұрын

    @@ausieaxemurderboyz1711 ik practice and schooling does, but books actually explains in detail and have definitions and examples...I'm a beginner so i might need book so i can teach in future also,cuz cherno also learned definitions and distinctions from the book maybe

  • @vladyslav007
    @vladyslav0073 жыл бұрын

    I wonder how the fuck did you integrate stupid shaderc into your project. For me using CMake it did not go well at all. It for some reason tries to link HSLS.lib to the final exe yet there is no HSLS lib :D

  • @louisgjohnson
    @louisgjohnson3 жыл бұрын

    I'd much rather you just talk about topics and discuss certain problems than watch you write code tbh

  • @wawamake6627
    @wawamake66273 жыл бұрын

    thats actually phenomenal format for an engine devlog. except my soul dies a little everytime i see std::

  • @wawamake6627

    @wawamake6627

    3 жыл бұрын

    @Lemon no-no, i think one shouldn't use cpp standard library at all. namespaces are another pile of crap i cry everytime i see.

  • @user-dh8oi2mk4f

    @user-dh8oi2mk4f

    2 жыл бұрын

    @@wawamake6627 firstly, why are namespaces so bad? Secondly, what’s wrong with the standard library?

  • @dylanclarke9497

    @dylanclarke9497

    2 ай бұрын

    @@wawamake6627 pls we need an answer