Kohi #004: Windows Platform Layer (Vulkan Game Engine Series)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's happening everybody welcome back to the kohi game engine series today we're going to knock out the platform layer and we're going to start on that right now so before we jump into the video i would like to take a second and thank the channel's partners arsleya and wencheng the partners are the highest tier of membership on the channel so i thank you guys for your support i'd also like to take a quick moment and thank everybody under the supporters section all of you guys that are listed here on the screen thank you very much for your support it's greatly appreciated if you're interested in supporting the channel one way that you can do that is you can go ahead and click the join button below this video if you'd like more information on memberships i'll go ahead and post a link in the description below as well as a card in the upper corner of the screen with that stuff out of the way let's go ahead and jump into it so before we jump into the code i wanted to take a quick second and talk about what a platform layer is and how we are going to set it up in kohi so first off what is the platform layer well in our case we're going to loosely define the platform as an os or type of device so this might mean windows or linux mac for example it could mean android or it could even mean a game console like xbox or playstation switch something like that and so our platform layer is going to abstract the platform specific code that each of these things requires from the rest of the engine so the engine doesn't have to care whether it's running on windows or whether it's running on mac linux playstation whatever and so we're going to achieve this by piping all platform requests through a single platform interface is what we're going to call it and you guys will see what i mean by that here in a second one more note that i want to make is windowing is one of the things that we're actually going to be abstracting away now desktop operating systems for example have the concept of windows to allow you to switch applications and things like that but that is pretty specific to desktop operating systems themselves so windows mac and linux have this but if you think about it on a android device or xbox and playstation you don't have the concept of a window you simply just switch the entire screen and so there's not really that concept that exists on some of these platforms and so what we're going to do is the concept of windowing itself is not going to be a concept that we are going to embrace in this engine and if you think about it windowing isn't really something the engine ever needs to know about all it needs to know about is how big is the surface i'm going to be drawing to it doesn't care where it is on the screen it doesn't care that it's a window even it doesn't care whether it's full screen or not at the end of the day all it really cares about is how big it needs to draw to to somewhere on the screen and so we're going to do our best to abstract all of that away so what is our platform layer going to look like well we're going to have a platform interface which i mentioned before that's going to be a platform.h file this will not contain any platform code itself however it will contain function signatures to call into platform code and so behind this our implementation of this interface if you will we'll have various c files right so we'll have one for win32 we'll have one for linux we'll have one for mac and then maybe at some point we'll have like one for xbox or playstation and one for mobile operating systems things of that nature right and the way that this will work is only one of these c files will actually be compiled for a particular platform at a time and all the others will be disabled and so we're going to define our interface in the h file and then whichever platform we're compiling for will determine which of these implementations we use and so all of these files essentially are going to point to platform.h the rest of the engine will make its calls into platform.h and our platform specific implementation then no longer matters to the rest of the engine with that in mind i want to create a new folder under source and i'm going to call this platform and under that i'm going to create platform.h and of course we're going to have our standard pragma once with our defines h to get our types one thing you may be asking is any of you that have programmed against windows or linux before or any platform specific code we'll know that there are certain aspects of state that have to be maintained whether it's a handle to a window or something of those lines and so you might be wondering how we're actually going to maintain that and be able to communicate with the rest of the application in a decoupled way well the answer to that is something that i'm going to refer to as the platform state so it's a simple structure here with a void pointer to internal state right so this is typeless and the type of this will be determined on the particular implementation in the c file so that is how we're going to keep all of this opaque to the rest of the engine is we're going to use a technique like this and you're actually going to see me use this technique in several places through the engine so i know some of you guys were asking about how we were going to go about doing that this is the answer to that okay so the very first function that we're going to add here is something called platform startup now it takes a platform state which is one of these right so something will have to create this structure and pass it in and then this will actually wind up filling that out now you'll note here that i have application name is something that's in here and then we have an x y and a width and a height so these things are determined by the user application so if you're running on a desktop for example we can say the starting window size whereas if you're running on a platform like i don't know playstation or something like that you'll know this in advance as to what that's for the application name is pretty much only going to be used for windowed operating systems but we want to be able to supply that in anyways so that it can be used to title the title bar of whatever window we're using but there's a chance that this may not actually be used in all platforms so um i tried to keep this structure as minimal as possible so that is our platform startups the very first thing that we'll have to call so as you may have guessed since we have a startup we also need a shutdown and that is simply going to take a pointer to our platform state the next call that we're going to have is something called platform pump messages and this is something that needs to be done continuously throughout the loop of the the application and we're actually going to see some examples of this once we actually start on the windows portion of it as well as the linux portion of it and so because of that i will come back and actually explain that later okay so the next thing that can be a little bit platform specific is dealing with memory and so i'm actually going to create some functions here to allow us to have platform specific ways of dealing with memory one for allocation one for free so you have your equivalent of malik and free something to zero out memory something to copy blocks of memory and then something to set blocks of memory and this is going to wind up being pretty simple at least in the beginning but eventually we're going to be writing custom allocators and stuff that that works with this directly as well as things like align memory and whatnot so you'll notice in here that there's an aligned i'm not going to talk about aligned memory just yet but in terms of setting up the interface that is something that we're going to have to do on some platforms so that is something that i wanted to include right from the get go okay so the next thing is and some of you had alluded to this in the comments to the logging video that there are various ways that we can write out colored text to the command prompt or whatever it is terminal that we're using and so this is a way that's going to allow us to do that in a platform agnostic way and so this u8 color here is actually going to be tied to our log level and you'll see once we actually get into the specific platform code there's going to be different implementations of this platform so we have a platform console right which is going to be responsible for writing to whatever console that platform provides if it provides one at all and then we also have a separate one for errors in case we want to separate that to a different stream one more thing that the platform layers is responsible for is getting time and so we have here a way to get the absolute time as a float 64. the way that you obtain the current time or the clock or wall clock time if you want to call it that is different per platform and so this just gives us a agnostic way to deal with that so that we can make that translation under the hood and again the engine doesn't have to worry about it last but not least we also need a way to sleep and this is not something we're going to be using at least right away but it is something i wanted to include because it is something we're going to need once we go to stabilize our frame rates so we need a way to be able to sleep for a certain amount of milliseconds and this will provide that okay so this is pretty much the entirety of our platform state for right now we may expand on this as the engine grows but for right now this is pretty much it there's not a whole lot to it however as you'll see here in a moment when we actually go to fill this out behind the scenes there is a lot that actually happens under the hood right so the whole goal of this is to simplify things for the rest of the application and abstract away the complexities of the operating system and that is exactly what this interface is going to do so i'm going to go ahead and save this because we're done with this for right now and under platform i'm going to create a new file and i'm going to call that platform win32.c since we're starting on windows first that makes sense to me to uh to go ahead and just knock the windows out right now so the very first thing we're going to do is include platform platform.h because obviously we are going to be implementing this interface and the next thing that we're going to want to do is we're going to want to check to see if we are actually on the windows platform and so we are basically going to block the entire implementation of this out within this if check so if we're on linux this whole thing is going to be disabled or that is how we are going to implement our platform specific code is basically by just shutting off the implementation for all platforms except the one we are currently compiling on and that will give us what we need in terms of functionality okay so in terms of the files that we're going to have to include we need a couple of windows specific files right so we need windows.h and we need another one called windows x and i will get into why we need that i put a note here for parameter input extraction uh we'll get into this a little bit later but these are the operating system specific includes that we need for the win32 platform all right so the very first thing that i want to do is within this i want to put together the implementation of our platform startup right let me space this out a little bit different there we go okay and so in here this is where we're actually going to start filling out these functions right so the first one is startup so as i mentioned before one of the things that we have we have to do right off the bat is to create our internal state right and so since we have an internal state that we we need to create we need to declare a type for that right because if you recall back here our internal state is just a void pointer right so the rest of the application doesn't know what it is so in here right after r includes we need to create a structure and we're going to call this internal state okay and in this we are going to for right now include two things so we have an h instance which is basically a handle to the instance of the application this is a windows specific thing and then a window handle which is an h-wind and that is what we're going to use to keep a handle to the window that we're actually going to be opening and again the rest of the application is not going to know about the window so it's okay to create it in our internal state here so the first thing that we're going to do is in order to use our void pointer we are going to call malik and we are going to create the internal state the size of the internal state structure that we have here right so we're going to go ahead and allocate the memory for that and then we're going to go ahead and cold cast that to our known type and we're just going to call it state right and this is how we're going to work in the rest of the platform layer and actually several places throughout the system where we deal with void pointer types like this or opaque types as i'll call them this is how we're going to handle that now that we have the states we can actually access these internal objects because we know they are without having to sort of cast it in line everywhere because that gets messy okay so the first thing we're going to do is we are going to save the uh current module handle to h instance so the module handle when you pass 0 like this is basically saying give me a handle to the application that's currently executing this code and so we're just going to save that off and now is when we actually get into the sort of meat and potatoes of the windowing code windowing in windows is a little bit strange it's a little bit of an antiquated api and we'll see some examples of why that is or at least we'll see some examples of of how that is but the windows api basically requires you to fill out a structure called a window class and the window class contains some basic information that we need to create a window and so we'll have to create a window class and then we'll do what's called registering the window class and if at that point it succeeds then we can go ahead and fill out a little bit more information to go ahead and create our window and then of course we'll want to open our window so that we can actually see something on the screen so we're actually going to do all of that within platform startup and so to get started with this we need to set up our window class so i'm not going to walk through a lot of detail on how to actually do this however i do want to point out that the microsoft documentation is available on all of these structures if you guys are curious as to what these individual properties do i'm not going to go into depth on coding in windows against the windows api because the whole point of this is to get away from this stuff as quickly as i possibly can so um i'm not going to sort of open this up but just know that you can actually search for you know win class a or register class a et cetera and um be able to pull up the msdn documentation on all those various things so the very first thing we do is we go ahead and zero out the memory right so we want our window class to have a default of everything at zeros and then as far as our style we can pass a bunch of flags here but the one that i'm interested in is i want to capture double clicks because we may need that at some point and if you don't explicitly actually provide that it may not actually do it this next thing is lpn fn wind proc so this is a pointer to the window procedure so the window procedure is basically what handles events within the system so windows is a very event-based operating system and so there are going to be various events that need to be handled and popped up over over time that we need to handle and this is basically the method that's going to do that now you'll notice that we have not actually declared this yet so we'll come back to that in just a second one other thing of note we're pointing to our h instance that we got up here and then also i've gone ahead and created a icon this is something that we could change out later once we get to the point where we actually want to display some sort of icon we don't really have an icon yet to speak of for this but this is how we would go about doing that and then uh we basically tell the operating system here that we're going to manage the the cursor on on our own and so that is what that is doing and then this last thing is is kind of important this is what the class name is so the name of the class that we are registering this is the string representation for that so when we actually go to create the window we are going to need to know what this string is and use it accordingly as i mentioned before you create your window class and then the next thing you have to do is register it and so register class a takes in our window class that we've filled out and this actually returns essentially what is a boolean so if it returns zero then we know that there's some sort of registration failure we may have filled out something incorrectly here something that's invalid and so this message box a is actually a windows specific way to say hey pop up a message box that says that the window registration failed throw an error and then put in an ok button and so forth and then we're actually going to return false because when we call this if we return false then we know the platform did not start up correctly and we can't continue with the application so this is one of the first ways that we are going to check to see that things are actually put together properly and boot out of the application if they're not okay so before i move on to window creation i probably should go ahead and set up this window procedure so i'm going to forward declare this at the top and this is what the function signature looks like right so again this is a whole bunch of windows specific mumbo jumbo but basically what we have here is our win32 process message and it takes in a handle to a window the message that is currently being processed or handled and then wpram and lpram these are fields that mean different things depending on what message is actually coming through and so we'll fill this out in a bit but i just wanted to put this here so that the compiler knows that there's something coming cool the next thing that we're going to do is create the window with a windows window there are two sizes that we have to be concerned about there's the size of the overall window itself right which is this outside rectangle with the border and all that stuff so that is one rectangle that we have to worry about and then we have what's known as the client area which is everything sort of inside this area here and this is the area that we're actually interested in let's say we want to create a window at 1280x720 right so 1280 across by 720 that's actually the size that we want the client area to be not the entire window so we'll actually need to perform some calculation to say hey um we want our client space to be this big how big does the actual outer window need to be to accommodate that what we're going to do is a couple of checks right so we're going to create um some client spaces which is actually what we're going to pass our x y width and height to so this is defining our client area and we're initially going to set our window [Music] area to those same things we're just going to copy them over from the client but we're actually going to be modifying these when we go to actually create the window some other things that i want to put in here is some information about window styling and so if we actually look if we look at the msdn documentation there are all kinds of these windows styles that we can use right so one of the first ones that i just searched for was overlapped right and this is basically saying the window is an overlapped window super useful stuff an overlap window has a title bar and a border same as ws tiled style so if we look up w is tiled oh it says it's the exact same thing okay well i didn't say msdn's documentation is always the greatest but this is sometimes the kind of stuff that you get so let's suffice it to say that i have looked into this and these are the properties that we're going to be wanting to use right [Music] and so we are basically going to i'll explain the important ones here anyway which is minimize maximize box minimize box and thick frame these sort of describe how the window looks and what individual buttons it may have okay so now that we have that we need to obtain the size of the border right and so what i mean by this is basically we're going to take a look at our window style that we've passed here take the framing title bar all that stuff into account as well as our our windows style here and it's basically going to fill in the values of this border rectangle here with how large this actually is and what we're looking for here is actually this is going to be an adjustment rectangle so this is essentially how different the client area is from the outer window and so in this case our border rectangle is actually going to be negative right because this is saying that our client area is smaller than the window area right so this means that we'll actually have to push out the border x y as well as the width and height by the adjustments that we got in here right and so if you look at this you can kind of see how that works again i'm not really going to go into depth on this because i don't really want to focus on windows programming but just know that basically this expands the outer rectangle of the window in order to accommodate the client size okay so the next thing we're going to do is actually create the window and to do that we call create window xa this is the extended styles for the window creation and here you'll see our window class again that we had up here so that is where that has to match if that doesn't match this will fail here we're also passing the application name this will become the title bar and then you'll see here we are actually passing the windows style the window x style and then we're passing the x y uh width and height so that's those adjusted numbers that we calculated here that's really the only important bits of window creation it's actually pretty straightforward stuff if you guys are interested in more in-depth knowledge of that feel free to look up these various functions on msdn to have a better understanding of those okay so the next thing that we need to do is if we messed anything up along the way then what's going to happen is this is going to return a null pointer and so we need to check that to say hey if it's equal to zero then something failed to create our window we are going to log which actually i need to create i need to add the logger here so we'll include poor logger we're going to log that as a fatal message and return false because we can't continue the execution of the application if we don't have a window however if it is successful then we're going to update our state objects h wind to hold the handle so that is why i didn't just you know sort of assign it right away because i want to be explicit about only assigning it if it was a success okay so that is window creation the next thing that we need to do is actually show it because we've created it but we haven't actually told the operating system that we need to show it so showing the window isn't quite as simple as just calling show window unfortunately and the reason for this is is because of the way that windows manages input and so when we show a window if the window should accept input from like a mouse and keyboard then we actually need to do what's called activating the window which is automatically done if we pass this show but if we don't want to accept input for some reason maybe there's going to be a window that we create at some point that we don't want to we would want to use specifically this show no activate and so all we're simply doing here is basically choosing the correct flag as to whether or not we want to activate i also put some notes in here that if we create the window and we go to show the window and if it's initially minimized or maximized some additional flags that we can use that are needed for those states but we're not going to need that because we're not going to start off in a minimized or maximized state we're just going to start in the standard in the standard mode for that okay and then we call show window we pass our window handle and then of course our command flags that we're building here all right and that is almost it so i'm going to put in a return true here because if we get to this point we have successfully initialized our platform and we're ready to go uh there is one more thing that we're gonna have to add here i'll come back to that in a moment okay so that knocks out our platform startup so this is uh one of the biggest methods that we're gonna have to implement a lot of these are actually pretty small uh let's see so shutdown is going to be the next one so back in our c file i'm going to make sure to stay above the end if and add on our platform shutdown and our shutdown method of course is going to need our internal state so we're going to cold cast that and the only thing that we have to do here is essentially if we have the window destroy it right so we'll check here to see if we have a window then we'll call destroy window on it and then set it to zero and that's it that's all we're going to do for the shutdown of the platform for right now nice and simple okay so the next one is going to be this pump messages guy so this pump messages just to give you a some form of reference here this is actually going to be called within our main application loop and i'll touch more on that once we actually get to that point but our our application loop is going to call this once every single loop okay so we have our platform pump messages which i'm going to fill out now so turn that into a function and this is actually a shockingly simple method right there's only a couple things that we have to do here so the way that the windows messaging system works is it basically has a stack of messages and we have to process those one at a time and so strangely enough it actually requires us to create a message object which i believe is nothing but a simple structure it's like an opaque type and then this peak message a basically says okay if there's a message on the top of the message stack to be processed fill out the message structure with it and in this case we want to actually remove it now you can peek without actually removing it from the stack but if the meth if the message stack does not get cleared out the window will become unresponsive and so we have to constantly keep that cleared out and so you'll notice here that we have this in a while loop that basically says just keep peaking messages until this returns essentially false so when the message queue is empty it will actually return false and we're going to empty the message queue via this pm remove right so every time we call this we're going to be popping a message off the top of that stack it's going to be populated in here we'll do some processing on it and then we'll move on to the next one so this is not our main game loop this is sort of a secondary message processing loop that has to happen within the platform layer and it's sort of specific to the way that windows works so again i don't want to expose our application to that this should be totally handled at the platform layer so every time we grab a message off the queue we need to perform translation on it and then dispatch the message the dispatch message is actually what makes it fire off according to whatever method is defined here so in this case it's our win32 process message which we've not set up yet but basically that dispatch message makes it actually call this method so we're going to be filling that out in a little bit i'll come back to that but that's basically the way this loop works and then once that has completed it returns true all right so the next thing that we need to do is we need to fill out all of these guys these platform allocate free zero memory copy memory now at least in the beginning the way we're going to do this is we are simply going to call methods that are in the standard library so we're actually going to need to include standard library and for now we're just going to return malek size right and note that this is very temporary right because we're not making use of this alignment and that is something we're going to cover but it's sort of outside the scope of what i want to cover in this video so for now we're just going to use plain old malek but we are going to be changing this to something a little bit more robust in the very near future so the next one is our platform free and as you may have guessed that's just going to call free okay so the same is actually going to be true for our zero memory our copy memory and our set memory although if you are familiar with c you know that there's no zero memory so this is actually convenience method that we're setting up and basically all we're doing is we're calling memsat to set the entire block of memory to all zeros so this is how we're going to zero out our memory right and this keeps us from just having to to call essentially this platform set memory and pass zero every single time we can just say you know what we want to zero this block of memory and then this just handles it copy memory just calls memory copy under the hood and then memsat of course is called by platform set memory so we do still have this if we need to do it but zero memory is probably the one we're going to wind up using more often so that is those so the next two we're going to handle are these platform console rights so let's go ahead and get these in here and if you recall before i said that we have this color here and this is where we're actually going to color our console output more often than not console output is actually done via a printf so something like this but for windows we actually have something that's a little bit more powerful for that then that that we actually want to reference so i'm not actually going to use printf for windows we're going to use something that is windows specific which is called write console a and it basically allows us to pick which stream we want to output to the standard output handle is basically the same as saying you know c out in c plus plus or something like that it's the standard output stream it does require us to pass a u64 as uh to the length of the actual string right so we're we're actually taking the string length there and then we're also taking a long pointer to a d word which is uh the number of bytes written right that is actually passed here so our right console a is actually what we're going to be using for that however where the power of this comes in is we also have something called output debug string a and this is a totally separate output stream that only windows has as far as i'm aware and what this actually allows is in the terminal this debug console here it'll actually allow us to output text to here as well so we're actually going to be outputting to both channels on windows so it just gives us a sort of extra way that we can kind of look at things okay so that's the output to the debug console as well as the command prompt that is actually running but we haven't handled this color section yet right so that is actually going to be handled by something that is called set console text attribute right and again this is something that i've sort of figured out ahead of time but basically what this does is it obtains uh it takes a console handle which we get um the same as this one here so basically returns a handle to our console window and then it allows us to set an attribute on that now there is a lot of documentation on this which i'll briefly pull up and it does say that this is outdated in the documentation however the default is to run with command prompt right so these things actually what they're referring to here in this documentation only applies if you're using like powershell or the windows terminal which is not the default so i'm actually going to completely ignore this for windows and not do this but basically what this allows us to do is we can set our attributes our character attributes here and if you see here we have a lot of different values so these individual numbers here coincide with the fatal error worn info debug and trace levels and this is a specific configuration of four bat foreground and background colors that is sort of given an index as to what that combination is and basically what we're doing here is we're saying okay look at the color that's passed in match that up with one of these guys and then from there we want to go ahead and set the text attribute to that which effectively changes the color for that line to the color combination defined in the index here now i'm not going to go into how i found these because that was actually took quite a bit to digging if you guys want to look into this feel free to look it up but just understand that these are appropriate color schemes for these individual messages and we'll see those in action here in a little bit okay so that is how we handle color so the next thing that we have is our write error which is exactly the same function with one major change we change it to error handle right and so when we write out an error we're basically writing to a different stream and this is actually something that technically is supported in c plus plus through the c error instead of c out that is the stream that this uses it's a special stream for errors so we're going to go ahead and leverage that as well other than that everything else here is exactly the same all right so that covers colored console output now we have the bit about time let's go ahead and fill this out so what this does is gets the absolute time since the application has actually been running now there is some setup that we actually need to perform on this first before we can actually fill this out or use it and so i'm actually going to go back to the top here after our state here i'm going to go ahead and paste in some static variable declarations so the first thing that we need is a float64 clock frequency this is basically a multiplier that we'll use to take the clock cycles that we'll be obtaining from the operating system and multiply them by that to get the actual time and then we have something here called start time which we're going to need and this is basically the starting time of the application speaking of which i did mention that we have one more thing that we need to do here and that is what that is is setting that start time so to set that start time we are going to paste in some code here so we have a frequency that we've obtained from query performance frequency this is what gives us our clock frequency for our specific processor so that we know how fast the clock speeds actually are relatively speaking and then we're actually going to take that to get our floating point number and we're going to say 1.0 divided by that frequency.quad part and what this basically is this quad part is a 64-bit integer and so we're basically converting that to a floating point by by saying 1.0 divided by that and then query performance counter essentially gives us a snapshot of the current time whenever this is called right so since this is when the application is starting this is when we fill out start time okay and then if we come back down here so when we actually obtain the time all we do is call query performance counter again and then we take our quad part which is our 64-bit number that is our number of cycles since the application started and we multiply that by our clock frequency to get the actual time and then we return that so this is how at least on windows we're actually going to get our our time in seconds stored as a 64-bit floating point number so platform sleep this is going to be another one of those things where we are actually not going to we're not actually going to fill out a whole heck of a lot actually we're not really going to do much of anything on this um we're basically just just going to call windows sleep function and pass the milliseconds right and that's it for now linux handles this a little bit differently windows it's actually nice and simple for once but that's all there is to that we've talked about this window procedure up here a couple of times but we haven't actually filled it out yet and so now is when we're going to do that so i'm going to go all the way to the bottom because i don't want this huge function towards the top it's just a big boy and i'm going to declare this down here or define this down here rather and we are going to take a look at some events and how we should actually handle those things right so the first thing we're going to do is we're going to switch on the message that comes in because there's a huge variety of messages okay and the very first thing that we're going to want to look at and again this is without really wanting to get too deep into this is erase background so if you want to see what all messages are available you can have a look at this exhaustive list here on msdn's documentation we're going to be looking at you know things like wm destroy and some some various sizing ones things things of that nature so i'm not going to make you guys look at all of this i'm actually going to explicitly put the ones in here that we need to care about right so this first one is erase background which is basically notifying the os that um erasing uh the screen will be handled by the application and that way the os won't be trying to draw that in as we're trying to draw from vulcan or opengl directx whatever and this will prevent a a flicker from occurring and uh this return one is said explicitly by microsoft's documentation return one to tell the os not to worry about it that will handle it so the next one is going to be wm close and this is another one where we need to return something specific to let the os know that we've handled it in this case we need to return zero and there is an additional thing that we're going to want to do which we don't have an event system yet but we're eventually going to want to fire an event fire and event for the application to quit right so we don't have the application layer yet but i'm just putting a to-do in here to say hey when we get that and when we get our event system set up we'll need to come back in here and hook that up okay um wm destroy was another one that we need to handle so basically when we try to destroy the window we need to post this quick message um which post quit message actually if i recall correctly posts wm quit right and actually in our case um we don't need to do anything specific with wm quit so i'm going to let the default window procedure handle that and we'll come back to that in a second so the next one that we care about is one that's called wm size and i'm actually going to wrap this one in braces because um we're actually gonna have to write out a little bit of code here so we need to get uh the updated size of the window right so whenever we have this we we want to say okay this is basically telling us a resize has occurred okay and so we want to get that size and then we want to eventually fire off a message so i'm going to say to do fire and event for window resize okay and then that'll be handled by the renderer or whatnot so i'm going to comment this out for now but i just want to put that in place so that we remember to come back to it so the next one that we're going to have to concern ourselves with is input and remember i talked about activation so this is where that comes into play so this is going to be another one these are the key up events and system key up events and key down events and system key down events and some of the buttons only work and key down some of them only work in system key down and so we're just going to handle them all up and down all together at once so the first thing we'll do is we'll say we'll check to see if it's an actual press or release by checking to see if the message was key down or system key down and then we'll take that information and we'll fire off some events so again input processing right so i'm going to comment that out for now uh because it will not run um it will not compile if we if we have unused variables there so we'll be handling input processing here at least for the the keyboard and the next thing that we'll want to put in is mouse move and as you may have guessed we need to get a x and y and if you recall up here at the top i talked about parameter input extraction and so if we look at our callback here we have w pram and l param and so our x and y coordinates are actually stored within those two parameters specifically in this case it's actually l param and so oops not that one so what we'll do here is we'll get our x and y position by using these macros that microsoft has provided to get the x and y params at the end of the l param and i believe it's the high end of the number is the x position the lower end of the number is the y position i may have that backwards but they basically pack the x and y into a single integer and pass it that way all right i'm going to say to do input processing because we're going to come back to this but i just want you guys to kind of get a feeling for some of the things that we have to map out here one more thing that we'll need to do is we also want to be able to handle the mouse wheel so we'll go ahead and scaffold something for that and the mouse wheel is actually pretty straightforward so in this case since the x and y are the movement of the mouse on the screen back and forth up and down this way we're actually going to consider the the wheel delta um which is the wheel mouse wheel going up and down we're going to consider that the zed and we're basically going to say if the delta which is the change from from the last time that the mouse was interacted with is not zero meaning something has happened then we're basically going to flatten the input to a negative one or a one and what this means is windows actually provides kind of strange values for for the scrolling and i think they do this because you can adjust you could technically use it to adjust the sensitivity um of the scroll wheel but in our case we only want to know if it's gone up or down so we don't care if they have like a value of 120 or whatever but it may eventually screw us up if we have different amounts coming in from different os's so we're going to flatten that to a range of negative one to one and so basically we're saying if the delta is less than zero we're going to just say all right it's negative one now and otherwise it's one and we don't have to worry about the zero case because the zero case in this case this won't be processed if this is anything if if this is zero this won't actually happen so it'll already be handled sort of by that case automatically and then as you probably already guessed to do input processing so i'm going to comment this out so the next thing that we need to do is handle the messages for mouse buttons being up or down and there are a total of six messages for this at least in windows which is l button down m button which is middle button that's the mouse wheel so that's if you click the mouse wheel and then you have r button down which is the right button and then you have the up states for those three things too so let's go ahead and put a break there all right and so we're going to first detect if it's a press similar to how we did the key by saying if it's one of the down messages we'll go ahead and set this to true otherwise it'll be false and then we're going to go ahead and to do input processing here because there's actually going to be some more logic that we need to add to this but we are not at the point where we can actually handle that yet so i just want to sort of scaffold that out for now okay so for now those are all the events that we want to handle and i say handle with air quotes because we're not really doing much handling here at all yet um but i just wanted to give you guys an idea of some of the things that we need to handle at this level once we actually have some more things stood up okay so after this switch we've handled the event and we potentially get down here and we say okay well what if we have one of these events that we have handled that doesn't necessarily have a return value that doesn't have to boot out what do we do next right because this has to return something well that is where we call our default window procedure and this is one that windows provides to us which says anything that we're not handling here go ahead and handle in the default manner that it would under normal circumstances right so you can think of all these things that we've added here as overrides okay and so if we get to this point we'll say okay just call the return call the default window procedure um pass in everything to it that was passed in to us here and then go ahead and return its value and that is it as far as the platform uh goes at least for for message processing for right now so let me actually do one more thing let me go down here and just put a comment as to what that's for so this is actually the windows layer at least as complete as it's going to be right now right so you can see all this stuff is not stuff that we want to have to worry about in the rest of our application it'll be nice for us to be able to split out some of these things and translate some of the things into a platform agnostic type of data so that we can handle it in our application gracefully okay so let's go ahead and build this real quick okay so that looks good and we'll go ahead and put in a temporary test so we'll go to to our main.c here you know what actually before i do that i want to actually make an update to our logger because we actually put the um the logic in there to handle our colored text but we didn't actually hook it up so let's actually do that really quickly so i'm gonna go here and put include platform platform h instead of this printf right here we're actually going to resolve this to do so let's get rid of that get rid of this and we'll also make use of our is air and we will go ahead and snip in some logic here so now we can say if it's an error we want to go ahead and tell our platform layer to write to the console and if it's not narrow then we want to just write normally so right now or right normally and we'll pass the level along as well a couple things that i wanted to point out as well we are going to be enhancing some of this in here once we actually set up our string library so we don't have to do all this but there are some kind of hard-coded magic number things in here i want to get rid of we have this is error is less than 2 which is not very not very great so i'm actually going to use the log level for that to say if the log level is less than warning which evaluates the two so it'll actually be the exact same thing and then i'm actually going to set up a constant i32 message length equals 32 000 so that's a little bit more clear as to what that is that way if we change it one spot we don't have to change it in all the others we can just change it here and be done with it okay and again like i said we'll be coming back to this but i just wanted to hook that up real quickly that should be it for now so let's go ahead and build this let's just make sure it builds first and it does okay so we'll hook this up in main so for right now i'm going to go ahead and include a platform platform h and i'm going to get rid of this assertion because i don't actually want to do that i'm going to leave these here so that we can see our test text so i'll say if platform startup right and our platform state we actually need to create one of those so let's go ahead and create that here pass the address of state and application name we'll just say test and actually we'll say let's be a little bit more creative with this kohi engine test bed x will set to 100 uh y we'll set to 100 width will set to remember this is the client width so we'll need to set this to 1280 and the height will set to for 720p so if this is successful then we will go ahead and call our platform pump messages right so what we'll need to do is we'll need to create a small loop so in this case i'll say while platform pump messages and i'll pass the address of state okay and uh basically actually you know what i don't want to do that i want to move this we'll just say all true for now that's fine okay uh and then if we will say if we do not have a successful return from that um that will go ahead and break the loop one more thing our pump messages is always going to return you know what let me i'm just going to call this as is for now okay so this is basically going to ignite our cpu and just continuously run and check messages but that's fine this is basically what our game loop is going to wind up looking like and we'll have cancel flags and things like that in there but for now this is kind of the way that works and then down here we'll have platform shutdown and we'll pass the address of the state okay let's go ahead and build that and looks like we have a link or error aha that is because these are not exported and these are not something i'm going to want to leave exported um because really the user code should have no knowledge of this but for now i'll export them and we'll go ahead and run and now well we can see that at least it's partially working so we have our window here right it doesn't do anything but at least we have our window and we can see our our console output here now it does look like we are not actually out putting um a new carriage return here so i'll need to fix that so let's go ahead and close this and go back to platform yeah it looks like we're adding we're adding a new line here i'm not sure why that's not oh because this is passing out message instead of outmessage two minor bug yes we will be fixing this just not right now okay so now we have our window and now we have our colored output so this fatal message really sticks out like a sore thumb that's why it's the only one that does not have a black background but as you can see here these are all appropriate colors i think um for the individual level of logging that they're responsible for so with that um that is pretty much all there is to the platform layer at least the windows platform layer so that is where i'm going to leave this video in the next video we are actually going to implement the same thing but for linux so we're going to jump over to linux and up and um go ahead and stand up the platform layer on that side and then after that we're going to set up an actual application to house our loop here our game loop so that we don't have to have all of this in user code and technically that means the application will be in user code and it really shouldn't be either but it's a little bit better than having platform code in our user code so anyway with that thank you guys for watching if you like this video please feel free to give it the old thumbs up if you haven't already consider subscribing go ahead and click that little notification bell there so that you get notified when new videos in this or other series drop and i'll see you guys next time [Music] you
Info
Channel: Travis Vroman
Views: 3,093
Rating: undefined out of 5
Keywords: write a game engine, write your own game engine, make a game engine, how to write a game engine, learn to write a game engine, writing a game engine, make your own game engine, game development, game dev, game engine, game developer, how to, tutorial, programming, gamedev, vulkan game engine, vulkan, game engine series, how to make a game engine, vulkan api, 3d game engine, vulkan engine, vulkan tutorial, 3d graphics, learn vulkan, 3d vulkan, how to vulkan, vulkan renderer
Id: ojEPsZFPj2Q
Channel Id: undefined
Length: 57min 19sec (3439 seconds)
Published: Fri Apr 02 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.