Window Abstraction and GLFW | Game Engine series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up guys my name is Jonah welcome back to my game engine series so last time we took a look at precompiled headers definitely check out that video you haven't already and today we're gonna be finally creating a window so that we can render stuff onto our window so I was really contemplating when to do this in this whole game engine series because I mean technically speaking I probably would have done a lot of stuff before I even considered adding the window if I was just making a game engine in my own time I was kind of a software engineer I would make sure that I had a lot of stuff already done before I kind of just made the window making the window and kind of doing all of that graphic stuff is what a lot of people do is their first kind of steps as you kind of learn more though and as you get more familiar with what kind of a game engine how game engine is actually architectured and what that looks like it becomes apparent that there's so much more than a window and whilst adding a window is useful because you can like render text and display debug information and visualize things actually working in your game engine as well as the fact that you know games typically render graphics and that's kind of important once you kind of if you put that aside there's actually a lot of stuff to a game engine like the event system like the application system like a layer stack system like I don't know input manages all of that stuff that actually have acted that actually has to be done potentially long before you have a window so I've kind of made this decision to actually make a window now though because I feel like a lot of people are beginning to maybe lose a bit of interest and I have to kind of in this whole game engine series I have to actually remember that I'm not just a software engineer building a game engine I'm actually also trying to teach and also trying to be somewhat entertaining so that people are actually enjoying these videos and so because of that there are kind of compromises that I make and we talked a lot about this during the partner hangout by the way if you guys aren't aware you can support me on patreon I come for slash the Cherno and if you pledge 1/7 here you actually get invited to a partner hangout but we have fun once a month where we actually just have a video chat with all the other partners partner is a tier of patreon support on my patreon we actually have a discussion about where the series is going and how to do things and this actually came up I think in the last month partner hangout in November so um definitely check that out you're interested but I have to make compromises because I have to compromise between entertainment education and software engineering anyway I've decided to make a window kind of now I think now is a good point we at least have logging and we have events that stuff is like a must in my opinion before you make a window because I mean it doesn't really matter you can make your window first and then make the other systems but that your hand-in-hand you need logging because you need to see what's happening if things go wrong and as you're kind of running your window klass it's nice to be able to insert logging and like a sessions and stuff we actually talked about assertions of loosely today as well but you also want events because a window is very tightly tied with events and we're just going to take a look at actually implementing kind of a window class today in an abstract way because remember we want to support multiple platforms and the implementation of windows on those other platforms will actually kind of differ so we want an abstract representation of a window which we'll talk about today and then also you know stuff like events I think we'll cover in the next episode a week we can actually hook up our window system to all the power events and just have that kind of work correctly so let's talk about the technology that we use a little bit so I'm going to use a library called GL FW I have an open GL series and I have a video about GLW which will probably be more detailed in today's video I'm gonna assume that you guys kind of know how to use that GL w is very very simple kind of cross-platform cross-platform meaning like Windows Mac Linux I think they support maybe other platforms as well but it's just a really easy way to kind of create a window a window using your relevant platform API I don't really want to take too much time to actually use the win32 API to create a window just because not what this series is really about we we might eventually have to because you know jello W for example doesn't actually support directx right we probably we definitely want to support directx and hazel at some point because that's my preferred rendering platform on Windows and it should be everyone's preferred rendering API on Windows because it's made by Microsoft for Windows so obviously it's going to be better than any other API when you're running on Windows that being said I do want to get something up and running and I think I mentioned that we're gonna stick to OpenGL in the beginning just so that we can get stuff as quickly as possible so because of that we have kind of a dilemma so I don't want to waste time now writing win32 API code but we might have to in the future and also GL FW something that's available on multiple platforms so immediately we kind of have to think about well where does the abstraction lie what I've chosen to do is to implement a window class per platform now you might be like well hang on if you're using GL of w isn't the implementation going to be largely the same on Windows Mac and Linux well yes initially it probably will be or it will be similar maybe there's some slight differences some stuff that we might want to add that's on Windows only for example or that might differ on other platforms but GL of W wise of course it's going to be the same because it's a Jill of W use that abstraction away into the other kind of platforms so I'm still going to make a separate window class per platform however and I think this is the first time we're actually abstracting stuff so we'll talk about that as well however in the future we might be like you know what job W on Windows I'm dropping that because we're actually going to switch to using win32 API because we need to make a DirectX context know what that I mean we could modify jail of W potentially to do that or we could just get the required win32 like H wind handles and stuff like that and like the device handles the device context handles from shelf W which it uses to create the windows window using the win32 api anyway and then from there we would have our necessary handles that we need to actually create a DirectX context but I haven't decided yet but the point is there's definitely going to be a point but we do Windows only windows creation code and all that stuff right so we definitely want a Windows kind of window even though we're using jelf W which is cross-platform so hopefully that makes sense I've also modified I've also forked GL FW into my own private or put into my own github repository it's public it's just the turn of its github book home slash the turn o /f w we'll use it here in a minute I've just added premake to it it's a really quick pre make file that only works on Windows for now I'll probably update that in the future to support more platforms as well but they're just an easy way to integrate Chillicothe with our pre make built while still having gel FW or the source code in our visual studio solution and all of that and then just link it kind of project wise so that's what I've done as well um and I think we can probably talk about just the notion of platform abstraction and how that works I'm probably make a video dedicated to that because today I just want to get a window up and running and if I start talking about this it's gonna end up taking up the whole episode but essentially what I've done is I made a platform folder which is for platform-specific code and then I've made a Windows folder which is for Windows code right we'll also have you know eventually a Mac and Linux folder and maybe if we support mobile platforms you know Android iOS that kind of stuff and in the platform folder will also lie our rendering API specific codes such as locum jail DirectX welcome metal that kind of stuff will also have its own fault of that um we might even have a POSIX folder that's just kind of you know Mac and Linux related in that and Android related kind of code if it ends up being the same but that's kind of the idea that's all you need to know about Homestar abstraction now let's go ahead and add the gfw repository that I've as a sub-module now so that we can actually get it into our project okay so what I have here is as you can see the channel is /lw I've just forked it from GL FW um a while ago I think because you can see it's 11 commits behind master but it's just forked from shelf to view master and then what we'll have done is I've added this and there's actually 28 days ago Wow four weeks ago I added this premix so you can see how much how far ahead the the hazeled dev repository is which patrons get access to because I did this actually like four weeks ago but anyway um it's per make five lower file very simple right it's 45 lines of code all this does is just for Windows essentially for now the indentation I think is a bit wrong but anyway um this stuff doesn't even work and this needs to be updated to the latest and there's a few things that need to be done actually I thought I pushed that by I didn't so yeah an indentation is horrible but anyway you can see includes all the relevant files here under filter windows these are all the platform platform-independent files is the windows only files and then it's got defines as well and all that stuff really simple stuff nothing really to it we're going to clone this as a sub module because this includes our pre make file as well as all of GL fw so on a command prompt in c dev hazel which is our kind of repository root I'm just going to type in get sub module add I want to add this job W sub module and I want to add it to hazel slash vendor /lw ok and it's going to clone this whole repository into that directory and then if we kind of boot this up we should see inside vendor we now have GL fw ok and that has our version of jail shelf w along with that pre make file so now what we want to do is actually add it to our pre make file and I've already done that so I will just show you the diff in fact we'll just do a git will do a difficult idea ok so this is all of it let's look at the pre make 5 files so this is what I've done to the pre make file I actually ended up creating basically a struct a lower table which is going to be a list of include directories that we have that aren't ours now these are important because we want to obviously have gel fwz include directory you know in Hazel's so that we can just use gel fw /lw 3 - 4 which will have to include so I'm setting a compiler include directory but I've just put it into its own kind of struct here into its own table because this will grow obviously to include each dependency this include here actually includes that pre make file that we have so this pre make file you know we just looked at this this directory is hazel Vantage lfw ok I'm including this which what this will do is include that pre make 5 file into here so basically this is almost like a c++ style include where this if we look at this individual studio this kind of gets copied and pasted into our pre make 5 file right so inside our pre make file we now have another project called GL fw you can see this does not have workspace or anything like that it doesn't have space job W it doesn't have a solution it's just a project just an additional project which compiles as a static library outputs into the same directory and it just includes a bunch of files okay that's all it is we've just added now added another project and then the important thing is what we have that project we're actually going to link it right to our hazel project so hazel is now dependent on GFW hazel is a shared library meaning if the dll file so of course we can just include a static library into it right or linked rather a static library into it we need to fix up this in the indentation I did not know it was so bad this is what happens when you don't let's look at this for a minute and let's go to view where is this I think it's in view no edit advanced and view whitespace just so we can see what on earth is going on so you can see this is tabs and this is space as that's why it's messing up so I'm just going to convert all of this to spaces and this should make everything a lot better because clearly we're mostly using spaces in this file I think that's not this is a tab as well okay and so is this stuff so it's quite useful for if you want to fix stuff up like this I can we can get rid of that okay brilliant then hopefully refresh this everything should be better it's not though this is on digital well if it's made a temporary for some reason so that's just um rerun diff tool and we should see this is now perfect but it's clearly not it's the right file Ison shelf W whoops okay so we fixed the show of w1 let's fix our one as well because this is apparently a mess oh wow so this is mostly tabs I see yeah this is little tabs [Music] okay this is spaces oh wow okay we need to really stick to tabs all spaces and not use both because this is a bit of a drag anyway I think that should be good we've got tabs everywhere now okay so does that fix it don't we have to restart this again because it is in a temporary directory and there we go good it's good now okay so back back to this so we're linking Jeff W which is that project that we've just included okay now this include directory just needs to get at it as a compiler include directory which is what we've done here now included directories in our include directories we've added include directory don't you love w which means that Hazel Vantage of W include is now a compiler include directory okay and that's all the changes that I've made so literally include that pre make file and then just set the include directory and link we're also linking OpenGL 32 live because we need that that's all that I've done okay now let's take a look at some of the new files that I've added actually well first thing let's just run Premack because I haven't even ran pretty much yet so we'll do generate projects and then her voice will do dual that you can see is generate that she'll be project if we go back to visual studio reload this the solution we should see gel of w here then you should see that hazel actually references gel of w okay beautiful let's try and compile that in debug x64 hopefully this compiles successfully I haven't actually done this ok so there's some unknown options I'll clean that up in the gel if W thing I don't know this is just trying to use c11 but obviously this is not for fiddle to use compiler because of the way that it's linking this is more or less for probably clang or JCC would probably both accept this but um obviously there's a different syntax for command-line arguments in the MS they say compiler anyway one succeeded is just ignoring those that's fine and we've now built gel double you can see how easy that was so I love premake because it's so nice and easy to use ok so next step let's take a look at some of the window classes that I've made so inside hazel just inside hazel you see there's a platform folder as well but inside hey all itself I have this window class now and this is an abstract representation of a window okay so this is platform independent this is what our application uses haven't written it yet I'll write it in front of you guys application it hasn't been modified yet but we're basically gonna use this window okay and you can see what it has now it's got an event callback function which we'll talk about in the next episode I did a virtual destructor and then it's mostly as you can see pretty much it's it's all actually just an interface right all of these are pure virtual methods there's no data in this class at all and there's no functions in this class at all just pure virtual stuff right because this has to be implemented per platform so I've just made an interface okay a desktop system of course because mobile apps for example don't really have a window they more or less have it like a surface okay so that's that okay kind of basic not much will add stuff to it as we go but that's just what it is and then this I just have some basically window properties which you can specify over here now because this is kind of platform independent this we have this create function which actually has to be implemented per platform so this is not there's no window door CPP file there's just a window file just a header file and then this gets implemented per platform because obviously this creation function should return for example windows window if we're compiling on Windows or Mac Windows or Linux window or whatever we decide to call it depending on what platform were actually compiling on there's no need for example have a platform independent one which you know it has a switch statement which includes and it doesn't it this is all decided at compile time anyway we're not gonna be compiling mac code on windows or vice versa property is titled width height that's all we got now default valid default parameters here as well hazel engine is the the default title if you don't specify one and then 1280 by 720 is the default width and height and then you can see we have if you don't specify where's properties it creates the default which is this okay that's that now inside platform inside windows we have windows winter and the CPP file as well okay this is pretty simple this is just an implementation of everything okay so some of this stuff actually it really should be marked as override I don't know why it's not so let's see what it actually inherits so vsync and then event callback with height and on update so that's all set I just missed these two apparently okay yeah okay so the way that this is primarily um implemented is we have a struct of window data you'll see why we have this because we need to pass it into jelf W but that's more or less for events which we'll talk about next time anyway but basically this is where we store all of our actual data that might be requested by jello W during about callbacks and then we just have a struct this way we can pass just the struct to gel of W as like custom user data and we don't have to pass this entire class not that it matters too much but this just keeps all of our kind of window specific data grouped nicely here which I claim which I kind of like we have in it and shutdown which is two kind of functions that we've created on update we'll just kind of should just update shelf W swap the buffers pull the input events all that kind of stuff it should be run like once the frame and called from our application we'll call that in a minute everything else I think is pretty straightforward let's pop over to the implementation so here's the implementation of that creation function that we had in Windows and window we had this create function was it this actually gets implemented in a platform specific file so in this case it's implemented you can seize window create not windows window create just window create and returns a new windows window ok that's it pretty simple it's just returns a pointer okay will store this pointer in probably a unique pointer in the actual application class okay so in the init in the initialization destructor does nothing for now this just causing it we the reason I haven't done anything in the destructor yet is because we not don't necessarily need to we can destroy the window actually I think Jill if W destroy window we should do that in shutdown let's just add that right now shut down we can do that but we don't want to necessarily shut down jail fw because we might we might need it like we might have more than one window that's also why I have this static here because we only want to initialize jail w once when we initialize our window but we might create multiple windows so yeah but if it's not a if it hasn't been initialized yet we'll initialize it so this is that's essentially what in it does when we create this window it calls the constructor which calls in it sets up all of our data based on the properties log some stuff that we might want to see initializes gel-v if it hasn't yet and then let's talk about this chorus cuz that's new inside core RH I've added assertions if we enabled them okay we should add that to the pre make file for debug probably probably not released what this does is basically it says it checks a certain condition and then logs a message if it fails and also its windows only for now just cause debug break which basically just is like in setting a breakpoint at that line of code so that it just breaks the debugger on this actual line of code okay so that if an assertion fails we can see what has gone wrong okay so for example in this case we're using it here to check to see if this has worked out so if this is something that gets removed in run time sorry in like release builds for example or distribution builds that's why I didn't write this code like this for example because if that happened and gelled up you would not be initialized at all interlaced fields which is not what we want we still want it to be initialized but we're just checking the condition only in India bug builds we might add something called verify instead of assert which basically is the same as an assert except it doesn't strip the condition so it basically does that instead the reason is that this can because this compiles to nothing at all in like certain configurations if enable of sessions is off we can do we can run functions that we wouldn't otherwise run at all just to verify stuff so it's quite useful amen just something that we'll be using a lot of I love using them just a quick way to verify that your state is correct and you don't have to worry about wasting performance when you do that because they get stripped from release builds we gel W create window again that sure little that GLW video and my opengl scenarios will probably explain more about this but we basically just create gel up W window make the contacts current and set a window user pointer now this is something that we'll use in our event callbacks for M data because when we but the way the GL Toby works is that we just set certain event callbacks for example jello W set you know Kiki callback and this is just a callback function that we specify that will get called whenever we press a key this means that we are passing this struct of data or appointed to this struct of data into that callback function so that we can for example be like I can call that event callback function if if a key is pressed or if the window size changes I can set this width and height and also call the callback so that's kind of what we said this form and then vsync we've just set it true because there's no reason really for it to be off shutdown destroys the window we just added that now update will just pull the events and swap the buffers and then we have a set of async function which if if we decide to enable vsync access these interval to one this isn't actually necessarily have to be one one just means it'll wait for like one frame to be called one frame to be rendered before it starts like the next thing whereas zero means nothing so that's what we've done for now again I imagine once we replaces we with the win32 card will actually might do something a bit different but that's just a basic implementation facing and then we keep track of whether or not it's enabled because we can't actually retrieve that data from Java over here and then we just we haven't and is facing function which returns for the wrong that is switched on okay that's it that's our window really simple stuff let's add this to our our application now so what I'm going to do is inside application again this is platform independent I'm going to create a unique pointer which is going to hold an instance of the window class unique because obviously only this class owns it this will be just window garage so we have a unique pointer of window and then all we do is in the constructor we'll set this to be want to make unique or anything it's just gonna be window create window or window window create and we'll specify probably no properties now because this is an explicit constructor we actually have to type unique pointer here and then do window create like that crater okay cool so we've got that we've got our unique pointer means we don't have to delete the window ourselves when the application terminates we application obviously is kind of a singleton meaning we only have one application for our entire application so um this is definitely fine okay we'll get rid of all this kind of event testing for now and then inside here I'm actually going to make a bull here called running which will probably set to true to begin with we can just initialize it here so while this is running by going to update our window by calling em window on update and I mean we could just chuck in some OpenGL card here to test it in a minute but that should be all we need to do really because window create will call the constructor which will call init which will actually create an initializer self W and create our windows they actually should be good so if we hit f5 or the play button here just to actually debug our code we'll see what happens and this is obviously building and linking jail W for the first time so hopefully everything works out okay check that out so we have hazel engine here over here it says that we've created a window which is our hazel engine I might just get rid of this app hollow maybe we can keep it that because it's testing um client side logging but yeah credit window hazel engine 1280 by 720 you can see it's there we can't close it or anything because we're not handling events yet there will be the next episode but we have the awesome and we should also have an OpenGL context so what we should be able to do is for now I'll be naughty and include Chell w3 in this file and I'll just do something like GL clear color um one zero one one which is pink or magenta and then we'll just call jail clear on the color buffer bit okay let's see if this works we should get a pink window here awesome there you go okay so we have now a window finally and an OpenGL context no events yet so we wanna the next step kind of of where I would go from here is to actually make it so that key events and mouse events and window events like closing and resizing and all of that fun stuff is actually propagated to this application class so essentially what we want to have is a function here which is like on event right and on event function which one we call which we will kind of call from the window class but we obviously don't want the window class to be aware of application at all should be completely modular and kind of out to the side should not depend on application at all which is why we have a set event callback function which will just kind of call from the application to notify the window hey all the events please call them back into here and then we can propagate them to all about layers and that is how this engine will basically deal with events of any kind including window events so next time we'll implement that that I'm really excited about that I think if we just look at the diff I don't think I've missed anything other stuff I did I modified the PCH oh yeah I added the log to the PCH file because log is not going to change and this is something we want in pretty much every file and chord on H I add the sessions as I mentioned earlier and that's it so I didn't modify much the big thing was obviously she loved W so that is it okay so that's our window class I hope you guys enjoyed this video if you did you can hit that like button you can also help support this series by got a patron come forward slash the churner huge thank you as always to all the patrons that make this series possible next time we're going to be implementing advance into our window class I'm really excited about that because that'll be cool we'll actually be able to like move the mouse and see what the mouse position is and then from there we can probably get on to rendering graphics of some kind and probably before that though setting up like a layer system and we can get on to more kind of engine architecture kind of stuff as well but now we have a graphics context where we can draw things on to so we'll probably add items go into that pretty quickly so that we can actually start seeing like you know a visual representation of of things and actually just have more data available to us there might be a bit awkward or just anointing to log so yeah that's the plan hope you guys are excited for that I'll see you next time goodbye [Music] you [Music]
Info
Channel: The Cherno
Views: 74,604
Rating: undefined out of 5
Keywords: thecherno, thechernoproject, cherno, c++, programming, gamedev, game development, learn c++, c++ tutorial, game engine, how to make a game engine, game engine series
Id: 88dmtleVywk
Channel Id: undefined
Length: 29min 20sec (1760 seconds)
Published: Sun Dec 16 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.