Renderer API Abstraction | Game Engine series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

This post appears to be a direct link to a video.

As a reminder, please note that posting footage of a game in a standalone thread to request feedback or show off your work is against the rules of /r/gamedev. That content would be more appropriate as a comment in the next Screenshot Saturday (or a more fitting weekly thread), where you'll have the opportunity to share 2-way feedback with others.

/r/gamedev puts an emphasis on knowledge sharing. If you want to make a standalone post about your game, make sure it's informative and geared specifically towards other developers.

Please check out the following resources for more information:

Weekly Threads 101: Making Good Use of /r/gamedev

Posting about your projects on /r/gamedev (Guide)

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

👍︎︎ 1 👤︎︎ u/AutoModerator 📅︎︎ Jun 02 2019 🗫︎ replies
Captions
Hey look guys my name is trying to welcome back to my game engine series so last time we finally actually used shaders to draw a triangle properly and that should work for everyone today we're going to talk about something that we haven't talked about thus far we kind of just wanted to get everything up onto the screen as quickly as possible just having kind of raw OpenGL code right inside our application class and today we're finally getting to discussing kind of the design the abstraction all these kind of rendering API calls that we have currently with OpenGL and how we're actually gonna handle multiple rendering API is because that's a pretty big issue that really needs to be addressed when you're thinking about your engine to the line especially if you want to actually have some kind of rendering engine that supports multiple API so it's kind of true big kind of abstractions that go on in game engines usually to do with kind of multiple platforms and that is the multiple of actual platforms rights and stuff like Windows Mac Linux Android iOS ps4 Xbox switch whatever those kind of abstractions were you actually doing with different platforms and there's also the rendering API abstraction in which you're dealing with the potential for rendering API is that it actually maava basically supporting multiple rendering API so being able to render using DirectX using OpenGL using the Vulcan any of that kind of stuff so both are very big discussions obviously we're talking about rendering API today and I also want to kind of say that there's a lot of schools of thought on this I've seen in my professional career I've seen a lot of different ways of doing this the way that I like doing it and the way that we're gonna do it for hazel is just one of the many ways you don't like it there's no correct way it depends on what kind of suits your needs and what you actually like and what you want the API to look like and what you want the code to look like programming and just you know writing code is such a subjective kind of thing I mean yes there are objective truths as to sure you could do it this way but it's like technically on paper worse in every way like sure the code might look pretty but the performance is bad the abstraction is bad the API is terrible well I guess if the code is pretty the API wouldn't be terrible but you get my drift I'm a big believer of doing things like properly in the sense of yes the code might be harder to read and it might not be as nice but it's gonna perform faster obviously me coming from a background of like game engine engineering at EA we definitely care about performance because we're trying to push the limits so it's important to kind of consider that and that's kind of just that's kind of just who I am as a programmer I really care about performance and I like to kind of do it that way anyway I don't wanna blab we're on forever I want to give a huge thank you to all the patrons that made this series possible Peter and helpful stuff that sure know if you guys sign up there you'll get videos early you'll get access to these source code to the hazel kind of development repository the development branch which I'm working on pretty much every day not every day but almost every day last video I actually showed like a bit of a bit of a tour of what the hazel engine actually is in the development branch and that was like a huge kind of little kind of show-and-tell that I did you guys are more interested in that I noticed that some people wanted me to like make a video actually showing the end like a standalone video just cannot get tour of what we actually have in the engine runtime and what everything what it can actually do like all the features if you guys interested in that definitely leave a comment below but you want access to that like right now you can stamp on patreon football-sized sure no help support the series and you'll get access to that source code and to that build ok so anyway back to this let's talk about rendering API is how do we support multiple rendering ideas so I think the biggest choice that you have to make here is if you're going to kind of have this support during compilation or during runtime so I kind of talked about like what I mean by that essentially what you could do right with multiple rendering api's is you could say that at compile time when I physically compile my code right you need to select a rendering API for example I want DirectX and then what will happen is you know viola essentially if devs or certain files that either compiled or not compiled based on your kind of configuration setup here you can basically choose that like I am going to compile with DirectX meaning that hazel is going to be built with DirectX right if you want up in jail then at compile time you choose gl right and then all the files are compiled uh kind of OpenGL specific right and then you get opengl into your final build and that and and to give you a more practical example what I mean is like you know you could have like essentially a file for each kind of you break down the rendering API into primitives so you have like a vertex buffer and index buffer texture class in our shader class and then what you do is you have like an OpenGL shader class and then you have a DirectX shared a class and only one of those will be compiled right and the one that gets compiled depends on your configuration setup which depends on which rendering API you've actually selected so you can kind of do it like that right or you could even just have a shade of file shader for CBP and then just if def so the kind of just says you know if DirectX is defined then compile this chunk of code otherwise if OpenGL is defined compile this chunk of code right that's another way to do it same same principle arise just instead of breaking it up into multiple files you have everything in one file sure so let's talk about the advantages and disadvantage of that okay so the biggest disadvantage well some of the disadvantages because I think that's kind of the glaring obvious one is you need a separate build of Hazel a separate build a separate physical binary build in order to actually select which heavy I you want to use and once you compile your code with that API that's it you have to recompile the whole engine or at least the rendering component of the engine and like the whole renderer if you actually want to switch rendering APRs so picture this right what I mean we're working and well like I you know you will Rin this game in like I don't know it's web console sandbox project we've written in an OpenGL suddenly I want to see what it looks like in DirectX hold my beer while I compile my entire code again with DirectX right that's not I'm not I'm really not a big fan of that so apart from development times being kind of slow especially when you're actually working on the renderer that's another big thing but that people didn't realize you have to make this developer friendly so what I mean by that is while you're actually developing the render how you're gonna deal with this well you know I've finished the OpenGL implementation now I'm working on the DirectX implementation I need to switch between them right I need to switch between between them to know whether or not the visual parity is turn the same right I they're like scrapping is between the two renderers does direct axial difference to OpenGL it shouldn't right it should be exactly the same if it looks different I've made a mistake so I'm gonna have to go back and forth them quite a bit but to do that I need to recompile my code and yeah I mean there's a lot of things you could do right OpenGL is done you could bring out all the rendering code into a module so it's like in a separate kind of component in separate kind of module DLL file whatever right and then if you want to kind of just launch with OpenGL I mean you could just or DirectX or whichever one you're using you could just you know switch which one which DLL file it uses sure but that still means that you need to recompile code and it still means you need to do that kind of at compile time right not something we want to kind of do to do with that right so that kind of decision is it falls into kind of those two areas when do you want to make that decision do you want to choose which rendering API user compile time or at runtime obviously right now it seems like on x definitely the superior one because what you know why I have this hard decision that you have to make ahead of time if you can just make it at the very end and still be fine with it right and what kind of go on to that in a minute but the other thing with this is that the benefit the primary benefit of doing it this way is essentially performance right you you know which IP I you're using you compile the hop the whole card base with that API right which means that there's no kind of runtime decisions that ever get made not even once that say all right well if we're actually using this API want you to do this no because all that stuff is done offline all that stuff is done during compile time and it means that during runtime your code your your program your engine doesn't have to make any decisions and waste time that's what waiting out waste time making those decisions as to which API is currently in you so which one you want to use right that's not stuff that actually has to be done because it's already been done ahead of time at compile time so once it gives you less flexibility it does potentially give you more performance now so about the second half of things and that is making those decisions at runtime so what does that mean what that essentially means is that you compile everything right so you have an you have an OpenGL implementation you have a DirectX directx implementation both of those implementations get compiled usually the way you do this again you could just you know instead of if deafs or whatever you can't really do if Deaf's because you can't have like a shader class that suddenly does both I mean if you were really crazy I'm like a big psychopath you could probably just have like inside of every kind of function that you have right inside every kind of function that you have for shaders like buying shader or you know upload uniforms or whatever you could have an if check that says hey if it's DirectX run this code if it's OpenGL run this code that's just like a Pathak to be honest i don't know why anyone would do that but i have seen that that's why I'm mentioning it don't do that you could do something like that usually you break it up into multiple files and potentially I can many ways to do this but potentially if you doing in a runtime you'd probably have a base kind of abstract you know pure virtual kind of class that has no implementations probably stores no data at all just act as like essentially a an indirection and abstraction if you will and then you have two classes or basically one class that breaks off per rendering API so you might have you know a shader and you might have OpenGL shader and you might have direct access writer those are both child classes subclasses from that original base class which is that just shader class right and then since they're pure virtual the at runtime when you actually create a shader you decide upon creation right so it's not really like taxing and there are ways to make it even faster if you want by like pulling your heads together or doing whatever you want but essentially when you create a shader it checks to see what the current rendering API you're using actually is and if it is you know OpenGL then it creates a new OpenGL shader and returns that if it's DirectX it creates a new DirectX shader and returns that right but the base type it's returning is the base class type which is a shader so you're all of your client code that's in sandbox at this stage right or inside your game that just sees shader that's all it is it's it's a pointer is some kind of reference to a shader object but the implementation detail of whether it's an OpenGL shader would write a shed is kind of hidden I mean usually you would provide ways to extract that just in case because you know no engines API is that that kind of complete really that you can just do everything you want within that it's a bit weird I haven't really seen that before I mean if you it depends what you're doing if you're doing really simple stuff you shouldn't need to dig in deep into the implementation details but you might so you might have that kind of filtering through but essentially the client code just says shader doesn't care what shader is because if you think about it what does it do it opens some kind of you know credits a new shader based on like a file or something it binds the shader it uploads uniform data it doesn't need to know if you're using DirectX OpenGL because that's kind of the API you've defined in that rendering API kind of video thing that I made a few weeks ago a few months ago maybe I talked about that line right between your actual renderer API and then your actual renderer so the renderer just uses the rendering API it doesn't it shouldn't care which implementation you're actually using which specific render a you're using it should just be as simple as just kind of just looking up shader and being like I want to create I'm gonna upload these uniforms I want to bind the shader for rendering right simple as that so obviously there's the obvious fact here that if like not all rendering ideas are supported on all platforms so DirectX we've been talking about directx and opengl is our two main ones just for the sake of this example right for the sake of this kind of conversation OpenGL is available in pretty much everything DirectX is only available on Windows and like Xbox and just Microsoft common products so if you're compiling on Mac or Linux your DirectX code is not going to compile is it no it's not so you still have to have like if devs open or not even if that's the way I do what I don't usually have with devs I just have separate files so I have shaded or H and maybe shaded or CDP which is like my base abstraction and then in my platform specific kind of folder hierarchy I have OpenGL shader dot CPP and our age and then DirectX trader don't say VP undulation right and director you don't really need to worry about the header file but DirectX shader dot CPP that is turned off for like Mac and Linux bills and probably all bulbs except for except for windows at this right right so that's not even gonna compile it's only gonna compile when you generate the project for Visual Studio for Windows right if you're targeting windows that gets compiled otherwise it does not get compiled okay and if I you don't need to worry about that way obviously oh and then also usually in your actual kind of generic shader bill cpp you have like some kind of create function which doesn't look which does a runtime check and it says which which rendering API are currently using it's basically like a switch statement if it's OpenGL do that otherwise if it's DirectX and you have that block inside if deafs then you can return a new DirectX data so that way it's kind of protective it's only going to compile for Windows that's specific code and I mean you know for other api's it's kind of the same thing so you wouldn't really compile metal on anything except for Mac OS or iOS right so you have that stuff either filtered out by the configuration if they're separate kind of CPP files or if depth if they're in kind of common files because you do need some kind of link to a common file at some rate in this anyway I've talked a lot hopefully this design is making sense um it's really cool to just sit down and think about this I could draw a diagram of all this I realized that I usually don't because I I feel like it's not I feel like it's just me running down my words on paper I think for some people it's good to see things visually so let me know what you think about diagrams in general I'll run a little poll maybe to see if you guys want more diagrams I mean I do them very rarely usually I do them if the video is dedicated about planning or something like that but the main reason I don't is just because this stuff is well it's in my mind it's kind of simple to the like to the point where everything I would draw is just the words I'm saying so if you just think about them and maybe rewatch that area if you don't if it doesn't make sense to you and just visualize it not to mention where about it see the card behind this so that will act as a visual aid that's why I don't usually both of it anyway I'm always open to feedback obviously so please let me know what you think we have several classes here we're not gonna check to open today I think what we're all we do the vertex buffer because I think that's pretty easy just to give you guys an idea and what I want you to do for homework is actually go ahead and do the same thing with the shadow class do the same thing with the vertex the right class do the same thing with the index buffer okay so in fact I think I will do both the index buffer and the back spot for today let's jump in and see what we can do okay so this is where we left off last time if we just run this then we'll see what we get so we had this kind of triangle that was kind of interpolating between the vertex position colors that we had here what we did is we had just inside application we had all this opengl code which obviously is not something that we ever want to keep right this is just kind of an example of how to kind of get this stuff on screen as soon as possible but what we want to do now is make this generic right make this generic in the sense that you know I want to just be able to like none of this other code has any idea of what a rendering API is right it doesn't really you know it's got layers it's got event dispatcher it's got stuff that is not render API specific instead of creating stuff like this and having GL code here that for example defines our vertex buffer what I essentially want to be able to do is create a vertex buffer right which essentially you know and the way you do this might be different depending on how you choose to implement it but you know probably want to do something like vertex buffer create we'll probably want to take in you know the vertices like this maybe the draw mode as well like the memory storage type because is whether it's static or dynamic or streaming or anything like that but essentially we want to probably take in the whole kind of vertices definition that we have here as a vet has buffer and that's kind of it and then when it's time to draw we just probably do something like that X like buffer to bind and that's done we want it to be like this because we don't actually want to include glad or anything like that this could be using Direct X for all we know and this kind of way of doing things and obviously we don't just have the open shell code inside vertex buffer it returns an implementation of which API we've actually chosen and will actually create all of them right now and see what that looks like okay cool so that's kind of the goal usually you do kind of usually this would returns on sort of pointer I usually just like returning a completely raw pointer in here right and then it's gonna be up to like if you do have an engine with a reference counting or something like that I would probably return a ref since we don't have that at the moment I'm just going to have create return a raw pointer and then it's going to be the clients job to actually manage that however they like either by shoving that raw pointer into like a shared pointer or usually like what we're gonna do here is just kind of putting it into a unique pointer okay so let's take a look at how we can do something like this this is kind of the goal for the API so over here in renderer I'm gonna make a new item and I'm actually just gonna call this buffer dot H now you might be like well okay is this gonna be the vertex buffer way clean your buffer there isn't long a buffer is because I I'm not a huge fan of creating a million files I think that it's not that necessary I think that it like it slows down your build times it makes code harder to read through if you want to like share your code with someone you have to give them a million files it's just a bit annoying so I I definitely like creating more than one file you can see I've actually got quite a few here they might get collapsed in the future or probably not but for things like buffer I don't really like having a vertex buffer and index buffer kind of class they're both buffers they're just different types of buffers so you should just have them in one of one file this is clearly just my opinion feel free to disagree with it but that's kind of what I do okay I like to do something I basically like to create code like this and then just have multiple classes and want to file it just makes it easier okay and then you know I'll do the same for textures for example so they'll just be one file per rendering API called like texture essentially and then in there we'll have 2d textures you know 3d textures cube Maps that kind of stuff everything with textures kind of all in one file instead of having to have a separate a separate file for each kind of type of texture because that's just annoying in my opinion anyway so we have both of these will include alt PCH will include our buffer class and then I'll had a file I made and then we'll have a namespace hazal and then let's talk about what we need here so this is our pure virtual interface right what I mean by that is there is no implementation here and there is absolutely no members no data members at all this this should take up zero storage obviously it'll take up one byte when we initialize it because it has to its class but is Scot no members it takes up no storage it's literally just like a V table of just functions of those virtual functions that get dispatched to whatever kind of subclass actually realizes this implementation right this kind of abstraction so we don't really need a constructor or anything like that you do need to have a virtual destructor usually this is just empty right we'll do this straight away I think for both of these so you kind of get the idea of how it's implemented and hopefully by implementing it twice as I am here you'll kind of see what you need to do to import the stuff of shader and then we just define the interface so vertex buffer what are the functions of a vertex buffer well we definitely want to have some sort of like binding function so virtual void bind right we want to be able to bind a vertex buffer for rendering or if we want to put into a vertex array the way that this will actually work with the vertex array by the way we will talk about that later because that's a bit different and that is actually a bit more API specific unlike you know drug tests for example which deals with this stuff differently so bind unbind I definitely like to have some kind of like set data upload data things over for you know you if you you would rather you do like virtual void set data and then you have your stuff here and now finally for the construction what we actually want to do is you'll notice is if I can find where this stuff is we want to actually you'll see that what we kind of want is the actual vertex data right that is attribute pointers as well something to do with vertex arrays not really something we want to do right now but just this kind of chunk of code here we need to actually give the vertices to this the wrong thing to this right however I don't want to create a constructor because if I create a constructor that means that I need to actually I can't kind of choose which type I want so what I'm actually going to do is create a static vertex buffer and again that's what I said we're returning a roll pointer it would be like maybe some kind of ref if you had a reference counting system inside your engine which we don't at the moment static vertex buffer create and makea that's what this is like my constructor so I taking everything I want here right and it's static so doesn't actually belong to this class and then I stuff create and then I'll probably just take in my vertices and then a UN 32t which is my kind of size could just use a size t by the way but we'll use you in 32 T okay there we go done this is very similar in both of these except this returns a index buffer instead and we'll probably have a UN 32 T which is our industries right so we haven't unsigned 32-bit integer we're probably gonna kind of stick with 32-bit integer 32-bit indices for now 16-bit is definitely optimization you could make in the future but more often than not if you turn around the things and you're trying to just have a simple implementation just you know a 32-bit is just the way to go otherwise we'll just run out of indices okay cool this looks pretty good to me now which do you create these to create functions so they're pretty easy we just drag this over here this is gonna be a better spot I'll create right and then we do the same thing I'll just use visual assist here to make this implementation for me we've got this here wonderful now what we need to do is actually decide in this function in this create function we decide which API we're currently using so what API are and Roy is using and thus which which class type which actual kind of class we instantiate and return okay it's gonna kind of obviously cost it through the base type here so we're not returning the actual derived type but that's that's the intention cool okay so in order to have classes returned away she needs to make them so since we're kind of dealing with OpenGL for now inside platform OpenGL I'm going to add a new item and this is going to be called OpenGL buffer dot H so you can see that everything that is kind of OpenGL related I'm starting with the OpenGL kind of prefix here and then buffer is kind of the fight the the type of class or rather the file name over the class inside the actual kind of generic renderer so we add this which is the rendering API we have our namespace we include the file from the generic kind of rendering API which is this one right and then we make our OpenGL vertex buffer class which is a vertex buffer okay and then what we do here is we actually implement that file right so that class that we've created this we we implemented here so we don't need the create obviously so we can take this we can put it in here we can keep this as a virtual destructor just because it's already virtual and this way we know that it is special and smart correctly and then bind it unbind which by the way I should have made cons and this stuff we just kind of implement over here inside our inside our implementation which is the OpenGL Vettes buffer in this case you can put anything else you want here right so obviously we're going to put a renderer ID did I'm a friend I don't remember yeah I don't know I didn't it's just a UN 32 usually I'd make a run dry heat I have we'll talk about that in another time in the shredder class we just had a render idea so we store this you'll note we store this in the actual implementation we don't store anything in here at all you shouldn't we shouldn't store anything here right this is just an interface just should not sort any data this is where the data where the data is actually stored so we have a UN 32 team which is our n variety we'll make an open GL buffer CPP file open GL which will include our PCH and what we can do here is just oh and one thing that I definitely want to make is a constructor which takes in exactly what our create function takes in so inside buffer we had this create function which takes in vertices and sighs that's what I want the constructor to take in okay vertices and sighs now let's create these implementations using visual assist who by the way I'm not sponsored by just I'm just like using it and then over here we're gonna do some things okay so first of all I mean look this is a vertex buffer class this is we're currently drawing a triangle in a game engine new vertex buffer class is quite exhaustive it's quite big right there's a lot of decisions you want to make such as whether or not you retain this vertex information on the CPU side which you might want to do if you're doing things like ray picking or you know ray casting to Mouse pick stuff like that there's tons of different like collision whatever there's tons of different things you actually might want to do from a vertex buffer what we'll do for now is we'll probably won't retain this we won't copy it and keep it here but what we do need over here really I think is well I don't know I mean we don't really need anything to be honest the size and all that stuff we'll handle in the constructor so this is the actual code we have here and what's clean Gen buff is not great but that's ok we could probably just which to be honest if iti can use something called to help create better things buffers a job create buffers right which is basically these two steps in one so and I don't remember the function see I think it's just that we'll need a write-off for a song okay so I don't know I'm just gonna look this up so Craig buffers glad create buffers there's a function signature okay cool so it actually does just have the buffers and a size okay so back here we have our size then we have our render ID all right cool we also need to include glad age and there we go so we create our buffer doesn't matter what kind of buffer it is at this stage anyway when we actually set up off a data bit that's when we will use array buffer for vertex buffer and element array buffer for index bottom so we have we can't your sides and vertices anymore obviously it's just a pointer we sighs we use vertices and we are now again hard coding business static drop okay so there we go and then we'll also have in the destructor which we haven't let's see so this needs to not be implemented here anymore we need to take this and implement it here and then this will just GL delete buffers because we don't want to retain that gel bind buffer let's see so GL array buffer and M R and writing and then I'm buying which we probably will not use that often but we will unbind it then okay cool so there we go very simple class just simply creates buffers uploads them and then we can bind them for rendering and I'll do all of that kind of stuff okay so back inside our application class let's try that out and see what happens so we still have our vertices we don't need to generate this anymore if I go back to here we can instead of having unsign in vertex buffer we can get rid of that and actually have a unique pointer to a vertex pop-up and now that will be out there Tex pop-up cool so then over here um and I'll have to include this so basically the same as that except the vertex buffer so now over here we have a vertex buffer I like to just use reset so II's lost time yeah I did and then we put this in here obviously we have the dot offense in the size second here that should be okay I get that Chloe didn't work sorry it's not about it's my face just buffer okay and there we go and then that's kind of it I mean we probably should bind it I'm actually not sure if create create binds it or not that's kind of the problem mm-hmm I guess we can run this and see what happens but yeah that'll be interesting I don't think we're doing anything you know we're still doing buffer data so I shouldn't shouldn't actually do that let's just cancel that build I failed anyway thank you I what it fail okay so creative course Craig does nothing yet we haven't sorted this out yet so what you actually should do is we don't have a renderer class which is kind of annoying we should definitely set that up next time because we really need to because we also have kind of generic renderer commands like clear and clear color that you know in most cases you could probably associate to a frame buffer but also useful functions to have inside your actual render as renderer commands and inside that renderer class we'd probably have a switch for the API right so if you're using like OpenGL or DirectX it would kind of the renderer is what should kind of have that for you right so what we'll do right now is will create a renderer class which is just called a renderer all right this is gonna be so great for today but basically what's what it's gonna do is have an enum class render our API right and then this is gonna be none which is like if you're running headless or if you just don't want to have it you may be doing unit tests that to require rendering I mean running them on like a build a build machine or something like that which might not even have a graphics card in it you want to test with so you have none and then you have Arkin Jail and then in the future you know we'll probably have like direct3d or Vulcan or whatever but these are kind of a - that we obviously have right now okay this needs to be stored in some kind of static state probably again since I said it's gonna be really brave essentially what we're gonna do is just have a static renderer API it's like the render class right which is the s run variety I will just say okay and then inside this video file which I'll now have to create since I chose to do it this way which is fine render SHP to include our PCH will include our renderer dot H name space hazel and then this for now clearly something that we can set at runtime but for now this just gets set to render our API OpenGL okay so without high creating it here obviously it's something that you could definitely set at runtime in fact we're gonna add a get up for it so we'll have inline public private inline render API not in there get render API probably just get API to be honest clean side the renderer you could call it current API or whatever and then this will just Mississippi static and it will just return ass right yeah okay cool and then you could also do set API but does the same thing if you want to set this and obviously if you set it before you create the renderer and the context of the application essentially before you create the window and everything it should use that chosen API okay cool so now that we've got that inside our open side adjust our buffer class which is over here we will include well already Inc yes we can just include the renderer and then we do a switch statement and we checked renderer and get API okay so if it is non you know then we'll probably won't return anything so return a null pointer for now we probably will have an implementation that does nothing though otherwise it'll crash so we could just assert in this case to be honest and we might do that edge set or assert false and we'll say render API none is not supported I'm currently not supported and then we will return not pointer and then for OpenGL boss I know move this over here we will we will return a new OpenGL vertex buffer with the vertices and the size so I really just kind of making sense how this little works right and then obviously over here we return null pointer and we could just you know also having a set here essentially that says it fails that's if somehow you set it to a value that's not here so just we could just have a having a set as his false on Aarn renderer api okay and then i gel that his buffers before something that we need to include so hazel where is it actually platform its platform not inside hazel apparently not I can jump off oh right and then obviously if for example right this will shed some light here if for example we you know had direct3d and direct3d buffer a DirectX buffer or whatever you called it right um that since that's when there's only you would do something like you know if H said platform windows or something you would do this otherwise you wouldn't right and that way you'd still be able to compile this class on like Mac OS and then same with this if this was you know DirectX instead of OpenGL you could surround this case specifically by that right and then that way obviously the direct tax code is ignored and not compiled at all on platforms that do not support it okay so there we go that is that and then that's pretty much it obviously for index buffer when you should do the exact same thing so I'll come over here our job offer is told of the file here this will be opengl index buff um which has our indices and our size still not a class that we've created yet i guess but yeah there we go the exact same code right I just like to tap his across cool so now I will have to create that index buffer I guess so if we copy and paste appears we'll call this our index buffer and obviously it will be an index buffer if we go to buffing I was running out for some reason but if we go here we can steal this copy it paste it here it's gonna be another long episode lucky you guys okay index buffer looks good to me and then if we go over here we can basically copy and paste this I'm just going to replace code here from vertex to index all right and then obviously we need to get the appropriate code here which is that buffer Dada this becomes elements alright well probably might still need to bind it we'll check that our in in a minute we'll both learn that together I guess indices and then I've been gelling this buffer we change this to P element right before everything else stays the same okay cool and then usually what I like to do is just kind of separate this because it's all in one file and you kind of want to see kind of the I guess separation of these two things so you know sometimes I do something like this essentially and I don't know the formatting for this varies I just kind of change it up depending on my mood but right now I guess I'll do something like this which is just our index buffer and then this will be our vertex buffer and sometimes I do this in the header file as well just so that it's super obvious where we have those two kind of implementations you probably don't need to have like three full lines to take yourself by the way in but do as you wish okay cool um so there we go we've got an extra one here because I guess the FairTax was too many lines or rather one more character anyway so there we go we're missing something cuz I put this into the wrong spot lovely yeah that looks pretty good to me if we go back to the buffer save a file you can check the make sure this all compiles and it does and then back inside application instead of having that index buffer as just two unsigned in here will have an index buffer instance yeah okay cool and then for that to happen I need to include buffer which I already am because they're both in one file which is lovely nice and easy we're going to do this anymore instead of Gen buffers and all that stuff and buffer data we can just create the indices and then say M index buffer dot reset index buffer create indices science and that's all we need and size is just size and this is now actually this is a good point right sir the point is do we actually need size here or should we rather have a count the reason is that you are specifying you and 32 indices they they you you know the the size of them anyway so why not just have a count and the other thing that we actually do need an index buffer which I have neglected is the count right so virtual you and 30 to get count and right and then this will just tell us how many indices are actually invisible next buffer which is important for rendering since we want to commonly render all of them so we'll have virtual get count here which will return a count and count and then you know GT and the count right and then over here when we take in the count we'll set count so that we can do this and then this becomes count times size of you into a t-shirt okay so that's how I like to differentiate between what is in bytes and what is not advice right if it's count then it's not invite us in elements which means that you need to multiply by the size if it's sizes and bytes okay there we go wonderful so now back in inside our application we create this we create these and we instead of having indices in this case we just have rather size of indices we just have three because there's three indices in here yeah look I mean if you wanted this to be automated you could do just do size of when I some people gonna complain their way through you and thirties routine right like that just what I should use here all right and then that will give you the actual count if you really want to do it that way this will keep the same and then I mean we probably need to bind at some point if I run this right now probably won't give us a triangle cuz this is a bit suspicious and unfortunately has been a while since I've used up in jail but we will see what we get here if anything okay so we get nothing and we got a crash in fact inside the driver yeah probably nothing is found I mean we're trying to draw element yeah I bet we've got nothing to draw so the other thing we need to do is actually use our instead of just having three hard-coded here we should get our index buffer and actually get the count that's why I wanted it here okay so let's fix up our buffers cuz clearly I am NOT as good as I thought we need to bind our buffer which I guess means that why do you use create why to use Jen they're the same in terms of buffers flecked textures you actually specify the target immediately I kind of maybe thought that it would be like the same here and but I guess not right so this is the one with index buffer so you know open gels a bit inconsistent even though it tries to be consistent and the reason they have create knowledge is to match the shader API which has GL create shaders you know Creator um and Joe create program and by anyway I guess we'll see so that's why you should still use create instead of just Jen because it that way your API is kind of consistent or rather your queued like OpenGL API is consistent let's run that and see what happens and since we've bounded and left it bound it should be in the vertex all right now and everything should be great and as you can see it is so hopefully that sheds some light as to all the blabbing I did in the beginning of the video where I was like you know you have to do this you have to create all these classes now we've done that you can see we have the base classes here which are just interfaces with no data at all and then runtime we make the choice to actually return a specific instance of a specific rendering API I hope you guys enjoy this video if you did you can hit that like button you can also help supply the series by going to patreon come for slash the channel your support is greatly appreciated and it is what keeps his series going so huge thank you to everyone who helps support the series let me know what you think of this kind of design let me know if you've seen other designs that you think of better this is the one that I've kind of been using for years and to be honest it's my favorite because all the decisions are made at runtime and in terms of performance like I don't know some people out there might be nitpicking being like but it's a virtual dispatch every time you doesn't matter like it honestly doesn't matter I've done benchmarks around this kind of stuff I have never been in this situation where I've written a game or an and I've been like man you know I wish I had the extra performance that having non-virtual function calls would have had I mean not saying that that scenario doesn't exist I'm saying in my experience and for what I'm doing and for what I'm trying to do with hazel which is gonna be a very high performance like quite demanding and visually you know visually demanding kind of engine right this kind of stuff definitely he's not going to matter if you're making some really small engine for like you know pixel graphics I'm like an embedded system yeah maybe this stuff would matter but it doesn't for something like this for homework see if you can create you can create the shader API like of this because right now I've just got shader I've got the shade of glass but it's actually just opengl functions whereas this buffer does the movie file has no relation to open jail at all right we include opengl buffer but that's again only if we're on the platform that supports it and also you know we're not including cloud or anything like that and neither is opengl buffer by the way if you look at opengl if we just quickly look at the buffer class this doesn't include GLAAD right these CVP file does so we're never actually including GLAAD into our generic buffer class and we shouldn't write same with kind of DirectX you usually don't want to do that with rad dice is probably okay because you'll be only building that on Windows but for something like this we don't even need to and if you can avoid it you definitely should and then the other one you can have a go with is vertex alright and just see if you can make that application class completely kind of generic anyway hope you guys enjoy this very long episode been sitting here for like an hour almost next time I think we're gonna either take more control with the renderer class or I really want to also talk about vertex arrays and how they fit in and how we can abstract that and maybe the buffer layout as well but yeah let me know what you want to see and I'll see you guys next time goodbye [Music]
Info
Channel: The Cherno
Views: 32,226
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: BwCqRqqbB1Y
Channel Id: undefined
Length: 47min 16sec (2836 seconds)
Published: Sun Jun 02 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.