Testing, testing, testing, testing, maybe too loud. Testing, testing. All right, Twitch window, exposure setting, not doing anything in my, I have 10 million windows open here, I'm trying to manage them. So, some administrative notes here. I've reorganized my apartment. I'm no longer at a standing desk, although I will probably buy a proper standing desk. I've been using, haven't actually been at a standing desk. I have a regular desk and then I mounted my monitors really high and mounted the monitors, raised the monitors up and raised my keyboard up so that I could stand at it. And that's actually in some ways nicer than a standing desk because I could have storage space underneath those things on top of the desk, so it's kind of cool. But I may try to get a real mobile desk, that can go up and down and do standing desk properly. But until I do that, I'm back to seated. The reason for all this is I totally rearranged my primary room in my apartment, the room where I spend all my time. That's why there's no backdrop yet. I haven't set up the backdrop. And because I've rearranged everything, oh, I'm getting notifications from Hexjet. Let me see if I can disable that. Preferences, alerts, enable system tray icon. That's not going what I want. Maybe it is. Oh, here we go. Blank test bar on highlighted message, private message, okay. How about just the tray icon? So because I reorganized everything, like my mic setting isn't correct, my mic position is totally different. So if there are issues with audio, with the camera, the camera is in a different spot now. So if there are issues with any of these things, please call them to my attention and I will try to fix them. Those are non-structs, oh yeah. So let's talk about what we're doing. So I have this library that I've been working on for a while, which has had all these function calls for doing stuff. And I was watching an old stream by Pair Vogensen. I never, he was a coworker, but I never learned to pronounce his last name. Vogensen, Vogten, Vogten, Pair. And in that, when he was doing a stream about doing a platform wrapper. So this is kind of redundant. You could just go watch his old stream from nine months ago or whatever. His system called Mu. And in that system, he proposed doing away with as many of these functions as possible. And instead, having the, and getting rid of callbacks for events and stuff like that. That's what happened. Currently I have event callbacks. And instead, having this nice, I'm calling it the API because I can't think of a better term for it. It's the, all the info is interchanged through this structure between the app and the framework. And there's a couple of things that this lets you do. And one thing is that all of these things can be in and out parameters. They can be used as initialization. They can be used for feedback about what happened after initialization. They can be used for feedback during the while running. So I started to move things into this and I still have all the old APIs around and I'm just calling the old APIs. I'm parsing this truck and calling the old APIs in some trivial ways. So I just, I've been doing this over the last night and now that it's not the middle of the night, I decided to go ahead and start streaming some of this work. But I am still kind of talking quietly and that's part of why the audio thing is relevant. If I talk louder, I can turn down the audio and get less background noise. I don't know how much background noise you have. The microphone is no longer mounted to the desk that I type on. I think I've did that actually at the old one. So it shouldn't get direct typing things. Instead, you only hear the actual sound of the typing instead of it transmitting through the desk. So this library does a ton of stuff. The main thing about this library is that it's a no dependency library. And what that means is it doesn't even depend on GL.H, GLX.H, it doesn't depend on Windows.H. So to get around that and to make that work, it's going ahead and creating all of the OpenGL function pointers itself and exposing them to you as with the GL names. And we will not look at all the GL things. And I don't have everything in here. I just have the stuff that I use and I'll have to add more things as people report what they use that's missing. But I don't want to just put everything in. I do want to start moving towards sub-saying OpenGL a little bit and just not provide all of the functionality. So did I talk about everything? I reorganized my, this room. So I moved everything. Yeah, I think I talked about all the consequences here.  So I have a ton of Windows open trying to understand various issues, although Pear gave me permission to just basically cut and paste his code for some of these things so I won't have to work them out. But because I don't use Windows.H, in addition to having to load all the OpenGL functions, I have to load all the Windows functions. Currently I'm doing that with JackalSpecDL and OMPORT and letting Windows, allowing this operating system load them. And I should probably switch to actually dynamically loading them all. The same way I do with OpenGL just because that will let me avoid name collisions. Right now there's issues if I take my sample app. If I want in my app to use Windows.H, I compile, it should just work. Oh, I've left things broken. I was in the middle of adding this structure. Let's just turn it off for now. I have already compiled this code successfully. Why is this broken now? It's all using an old version. Now here it is, switch to five or create five. Oh, okay, yeah. This doesn't compile because this is bringing a really old version of Windows.H. So if you're using a modern version of Windows.H that has the necessary stuff, the fiber stuff I think postates it. Although maybe if I did the, it might be that I could put a pound of fine before that to make sure it compiles in. There's some trickery with that. So, but the main issue is that if after doing this you try to include Windows.H, you'll get conflicts trying to compile Windows.H because I've defined my own definitions for all the things in it. So what I want to do is switch this to these being function pointers and then I can name them with an STBP prefix so that they won't collide and then I can have the whole thing actually be Windows independent. Properly, fully Windows. It's already in Windows independent. It's just you can't use Windows.H unless you do it in the right order right now. And some other stuff is gonna have to get loaded in DLLs like if I could to use, will stop you maybe. I'm not sure. I know Pear did that stuff directly. And I'm probably not gonna work on the sound today. That's not been a priority. It's just been a priority to the graphics. But if I get through converting everything to the new API style, then maybe I can look at sound. And yeah, I really wanna fix a lot of this stuff. So the main idea of this thing is that you have this API structure that you pass everything through. And then in the main loop, the main loop looks like this.  This is my own code. And then you call this update. And then you communicate with these things by setting these variables. So one thing that's a downside of this approach, spelled this out, is that this is more verbose than my old way of doing it, which is, I gotta start using search. There's too much stuff in this file because it's 3,600 lines. Okay, nope, there we go. So my old API for this is, what's this, right? So here's the old API. And so here's the equivalent. Right, and so in some sense that got worse. There's more typing there. So I added this constructor so you can do this. And it's still more verbose, but it's not too much more verbose. And there are some advantages to this. So, you know, one thing is I could potentially do something like this. We got window.title equals foobar. And I don't need another separate function for changing the window.title. This isn't programmed to work. I'll have to do work in update to detect the change and change the window.title. And similarly here, did I make a constructor for that? I think it did. Yeah, that's your PGL version. Yeah, the problem is because I'm trying to support non-C99, I can't do the anonymous structures. And yeah, and the thing is that like, yeah, I guess there's no reason they can't do it that way. This whole thing of this being named P, like that's on you. Like I spent a lot of time trying to think what the prefix for this should be. Should it be concise or not or whatever. And I could actually make this be very verbose. I could let this be that because you can name this whatever you want. And this namespaces everything. So the big thing that I really like about this, except I have to actually have to be the right thing, is the autocomplete is hierarchical. So you can, like there'll be time and keyboard and mouse and stuff like that. And that will autocomplete here automatically for you. And then you can keep drilling down into things. So compared to a flat thing of functions that could get really long when you're looking at the, trying to get the autocomplete, like if you did a C++ API where it's an interface attached to an object. And the problem in C is that you can't make clean interfaces that autocomplete, maybe you can nowadays, maybe you'll have made smart editors that have some kind of sophistication for this. But this is really convenient. And so if we turn the helpers back on and get this to compile.  All right, I was going to have it be effect three, but then I realized there's no standard convention for up and down movement. So it can just be a point F. So right now, let me show you what this program does. So it's just, it was a train height viewer, but I don't have any real height data. I've switched over the mouse, the input pulling to the way Pear was doing it using fibers and there's some glitchiness, probably nothing to do with the fibers, probably just some bad interaction. And I don't know if you probably can't tell, but there's, yeah, you can't tell, but there's latency on the mouse now due to the switchover and I don't know what it is, but I wanna get everything switched over and then I'll try to debug that because it's a pain to debug windows messaging things and having it switching fibers is just gonna be worse. So you could see I was doing mouse look and movement in there and the way that works in the old API here is like this. You, the framework is going ahead and maintaining a mouse look for you and keyboard movement for you that you can totally ignore. You don't have to use it, it's just a shortcut. And so now in the new thing, it's gonna be p.helpers.fsinput.mouselookdegrees.x and you'll have to have two of those, which is obviously way more wordy. X, Y, Z, let me think. Yeah, I don't know, I'll just follow the same thing. I don't know. So it's obviously more wordy, but I like that it's sort of hidden away in the API and I could name these shorter names like the mouse look degrees was just so that there'd be no ambiguity about that. Now I have to actually change the API, let's do this. Why is that not okay, because it's called. So this is all, a lot of this stuff is already state in a structure and so all I have to actually do right now to start with we're gonna copy it between the structures. That was pre-app, right now I'm copying it between the structures, but it can just change to live in the, to live in this structure and instead of copying. So this, eventually when I fix that, when I change this to work directly with the API struct, then this copy just goes away. So what's it called mouse move? No, it's called computer, oh it's keyboard. Keynote, I only called it forward and right. Or it was first. So, and it, p dot, hope it's not auto completing for me. Why you not auto completing p dot. Let's see if that works. It does. So now those functions aren't needed. And so yeah, I don't need to do these structures bare. I can push them off into their own structs and there are some things where I will and I could just always do that. Like I don't know, like I know later MSVC's show this comment in the, when you're looking at the auto complete in tele sense, but this one doesn't. And I don't know if it works to put stuff here in that case, in which case I can just leave the struct embedded, but if it doesn't then I'd have to make the struct separate. And let's make this clearer. What happens is chatting in general. So, do do do do do do. So, I use pointer diff T as int and I use size T as unsigned int, because they are typically register sized. The correct way to do that is you in pointer and in pointer, but because I try to work on pre-C99 things, size T and pointer diff T do exist and currently are always correct. You could definitely have theoretical platforms where pointers are not register sized and it wouldn't be correct, but it'll do. So yeah, and then these FPS inputs, I'm not actually using correctly like the movement I'm pushing forward and the movement is not relative to the reaction I'm looking, that's the job of your app and I just haven't bothered to make my app do that. All right, so I guess what we'll do is first we'll get rid of all the functions. First we'll get rid of all the functions and then we'll fix everything to use the shared thing. Oh, so one thing that I'm doing very different from what Pear did is he had a Win32 struct in here that had all the internal state and that is not how this is going to work at all. This is the public state and it's going to look in your app like, hey, you've declared, in Pearce, you've declared all the data that it stores in some sense and in this it's going to be, this is the public state and then it's going to keep like a mirrored copy of a lot of this state so that it can detect whether things changed and all of the Win32 internal state is going to live in its own structs and that'll all just be global in a struct stored globally and who cares? Like you can only have one app so it's not a big deal to use global. I can store that context in a struct and pass that struct around explicitly if I really wanted to. So VC6 sorts the intelligence by alphabetical, I think. Am I remembering correctly? Yeah, I don't know if modern things keep them in the order they are in the struct but so in some cases that means I want to think about it. If I can always keep the struct short, it's probably fine. It doesn't matter what they're named but I may want to choose names a little bit more smart based on the ordering so that for example, my natural inclination would be to use structs audio but that would make it first on the list and it's like not really a high priority thing so I'll probably call it sound. Hopers, I kind of wish it was a name later in the alphabet but I can't do everything about that. So the other thing that Pear mentioned in his talk was, okay Pear said that he was actually doing the, he was planning on doing the mirroring. Oh no, well, no, he was gonna put the data in the struct just not expose the type depths whereas I'm saying just don't have that in the struct at all. Let me link in chat the, where is, there it is. Oh no, this is the wrong one. This is the old, this is the fiber stuff. Let me look at them though. Why does that have a second, why does that have a slash whatever on it? I don't know. But yeah, I actually closed this one which is his Pear's thing which I'm only gonna look at for the sound stuff I think I've copied everything else that I need but I did the fiber stuff from a different just. Would the platform funk pointers be something a hot loaded DLL would need to re-init or are they stored in export from the EXE? I'm not sure scenario you're talking about. This float TT is just a quick hack. So let's fix that struct time. So we wanna do some stuff for time like with clamping the maximum frame time and then when you wanna know the absolute time you might wanna know the absolute time in the wall clock or the absolute time based on the clamped time and maybe even have the ability to pause the app, pause the timer and unpause it so that might be separate. So probably what we wanna do is have a struct and have, oh I know what I was gonna say, also about that Win32 thing. The other thing Pear mentioned is that he wanted it to be a platform extraction layer and not have too much junk in it that's not platform specific and so for that reason there was no separation of the code into the platform specific and platform non-specific parts because everything should get rewritten and he included like an image loader but he's using a Windows based image loader where hey it's Windows specific and that makes sense. And that is not how I want to approach this. A lot of these, the convenience here is that you derive things that you get, you have mouse button up, down state and then you also get a pressed flag and that derived state can be computed platform independently and so in the same way one of these like that can be computed platform dependent and then everything else can be computed from it. Let's just call these ms and delta ms and so I do wanna make that separation although this is still only going to be when 32 and part of that is because I do a ton of open jail stuff that is cross-platform in this library so it definitely doesn't make sense to rewrite it all. Okay somebody clarified my question that I said I didn't understand but now I can't find, oh here it is. A hot loaded DL, okay yeah sorry. There are two kinds of, there are two senses of hot loading a DL, one is reloading it which is the traditional name hot loading but the other is just dynamically load by wearing it. I was really only thinking of the dynamic load case not the hot load case. I've never messed with hot loading so let other people in the chat deal with that hot loading DL also I mean. Like I don't do it the handmade here away. I make my game be able to restart quickly. The whole idea of having to be able to preserve state across the DLL reload doesn't make any sense to me and I like being able to use Malik and free and other standard library things so I don't do the game in a DLL stuff. So the idea though is that, so if we're gonna have a struck time there's a bunch of different things we can do. There's a bunch of different things we can do. We can have the basic time and then we can have the clamped time and the possible time and then the basic one is to have wall clock time but I don't wanna have to actually type dot time dot wall all the time so I'm gonna embed that one into this I think or I could do SCP time info time and then this is, that's only for clamped. Can I call that max frame time? Like that's just really wordy, clamped max Delta seconds but you're not gonna use it very much. This is what you, this is, so what I should do is have a convention here like that's an input parameter, that's an output parameter, that's an input parameter and that's an output parameter and it doesn't help me because I don't get on a complete, my intelligence doesn't show that stuff but I'm making a Windows OpenGL platform wrapper that hides all the, that junk so I don't have to worry about it. So this is in out and this is in only. So like with functions you can tag those in the parameter names, not parameter names in the parameters like you can decorate them. I guess you could, I guess those decorations are always just empty definitions so I could do the same thing, I could do that but the problem is I like to prefix everything and then that would just get way too wordy. Right, if I did this, also maybe these should be inside the, it should be that. It'll also possibly break the intelligence parser, I don't know. So I'll just do them as comments. This is a knit only in out, I should probably have a way of tagging that if you don't get the compound ability you don't want, oh yeah, I don't know. Outs, these are all outs. I'm gonna make these wordier just so that when you get the autocomplete it's clear what they are. All right, so you'll see, you'll have to type it would be p.time-extra.clamped-time .delta-seconds because when you're confronted with just this list it says clamp next seconds, clamp to pause possible, you can't tell which ones are expandable so clamp to time is hopefully gonna lead you better down the path. Maybe the names should actually have something it tells you whether it's a struct or not. Hungarian notation for the wind and then what I wanna do in the long run, well that's not relevant to this actually. So one of the things though, it's so like say this isn't how I wanna do it but say it looks something like, you know, so then this will be, can I define you at 64? Oh, it's not. It hasn't been defined at this point. Oh, it's only in the implementation. Oh look, this is Windows only at the moment. Do-do-do-do-do. How is it long long? Oh, I do have it. Wait, oh, I'm just using it without having to find it. That's why. Okay, I'm so confused. Let's spot the type-tests. S-D-B-P-TIME-INFO type-tests. So now it's the fact that I have the old one that's not actually implemented. So one of the things I wanna do is have, to deal with sub-sampling, if you have a long frame, I wanna actually have available the state that you missed. So the idea would be that you'd have something like something like this, which would show you the last end samples of the mouse, assuming there's some way to get at that data, I have no idea how to do that in Windows. That's for future expansion, and it would actually be inside the mouse structure. So you'd have to do this annoying thing of have two versions of this structure. I used to use a NMX blue keyboard, but now I use, oh, I can't see this window.  There it is. I now use this cheap Dell keyboard. I used one for a couple of years when I bought a Dell computer and got used to it. So I'm not gonna implement this indefinitely, but I just wanted to show how, the idea of how this kind of stuff works. And actually, it probably wants to be, one of the whole things here is to use the hierarchy. So whenever you have the same prefix on multiple things, you really want to push it down another struct so that, because it's about the same amount of typing, it actually can autocomplete faster. Here, it's a little more wordy because you need a word for this, but this might be fixed. The sample rate might be something where you just like the state thing will always be filled every five milliseconds regardless of the actual mouse sample rate. So that can all be worried about in the future, but. Right, okay, so we'll start populating some of this stuff that I've just written. So this time stuff, what order do I want this stuff to be in? There's Canvas, Jail is at the top. Here, we'll start having events. And we'll probably be a struct system. And I don't remember what I want to put in struct system. I just remembered that I wanted one. These struct names can all be very wordy because the user never has to use the struct names. So let's make it more verbose, I mean more explicit. These are temporary. The reason I like this keyboard, by the way, in particular is that it's got no bezel around the edges. So it doesn't have any wasted space. It still has a numeric keypad and the full arrow keys. And the bezel is microscopic. So like I can pack it and take it with me my luggage and the minimal amount of space in the luggage, but also just on the desk. It just doesn't take up very much space. I mean, it takes up the full amount of space, especially because it's got the numeric keypad, but it doesn't take up extra space beyond that. And they were like $10 and I bought like five of them because I was concerned they might stop making them. So I was like, I'll stock up for the future. And so I still have three or so. But it's a super cheap keyboard.  Don't care about the feel. Don't care about that stuff. It doesn't bother me. You know, the mushy plastic springs, I think. Not real springs. I forget. Where's this flathead? It's a poppy key. Double check my memory here. Oh, go back. Where did it go? Yeah, it's a little rubber or plastic. Yeah, it must be a rubber squeegee thing, right? So yeah, like they don't bother me at all, but they might bother you. So it's not very much. Okay, so now I've got close to the full thing, which is an intentional thing I wanted to do so that I could look at the auto-complete and see how it feels. What did I do in here? Synthetic error, curly brace. Oh, I turned off helpers. Okay. Before I fix that, oops, why is that? Get that back in. That will be a little bit longer than it should be, but okay. So now I can go down here and I can say p. Yeah, it scrolls on mine. I'd like it to be a little shorter. So I can put all the inputs under input. Is that gonna be too wordy? Is this all fitting on the screen? Yeah, okay. Oh, the other thing I forgot to mention that they mentioned early on that this is all a new setup. So the other thing is I changed my font. And so you should complain if the font is unreadable, but nobody's complained. So I think that's okay. This, I used to be using console-less and now this is console-less bold and I believe I made it a little smaller. So, so let's see. Let's try putting the input in a struct. I don't know why I called that inputs. That's it was input, not, I mean, don't count the events I meant input. And now that the group in the struct, I don't need a column. Is there anything else I can group? So I could put the time extra stuff back under time. How much info is there in time? There's a lot. It's a little, I don't know about having them being consistent like this, but DT is garbage that will disappear. I could put jail under system because you don't use it that much. Unless it's gonna turn out that there's a lot more jail stuff that I want. There will be a few more jail things. I mean, this isn't too long. This might be okay. Make sure everything starts with any character. Yeah, it does. This doesn't have the other things. I was still getting the old definition because I didn't change this to time top level. So one thing is that this beginning is the same as this. So you can like try to find a way to make a union of them, but I'll probably just cast between them. Yeah, the namespacing trick here is something you can see in the SEL event stuff. And I'm just trying to do it globally. Now this is the original. I mean, certainly Pear's whole new system is based on this. And when he did that stream, other people mentioned they did a big struct as well. Yeah, I agree. Some of this stuff is verbose. The biggest issue is how often do you type it? The things that you use frequently versus the things you use infrequently? But I also agree that making the hierarchy clean and not have indirections like input is probably nicer. It's just a question of how that trade off feels versus the autocomplete. Like if you're not using the IntelliSense stuff at all, it doesn't really matter. But that size in VC6, the size of this is so small that making it not have to scroll is nice for VC6, but obviously that's totally machine-specific. Like maybe I'm over-optimizing for VC. And the DT goes away, so then it won't scroll. All right, let's get rid of the DT so we can actually look at the real, the exact thing. So this has to change. Everything has to change to use the time. But I mean, you could make that same argument that I could put the time extra stuff out at the top level. And I don't want everything to expand out to the top level. It's definitely a choice I want to make looking at pairs of stuff of pushing things down hierarchically more. Specifically clearly when they're prefixed, but like you could argue for making position and delta position and things like that actually be position dot value and position dot delta. And that does clearly get too wordy for getting at the values. And you can make the same argument about the input, but I mean, yeah, it's just a trade-off. All right, so DT becomes time delta seconds. Do I get rid of top level? Time info top level. All right, I don't have to go look it up because I'll just be able to type it and find it. But let's put that in my face butter. I got that wrong. I said time dot seconds, I meant delta seconds. Obviously, this all has to get fixed to work, correct? I'm just trying to get to compile. Okay, so now I can look at D dot. The thing is I'm sure there's some top level thing I'm forgetting that I haven't put in yet because it's not trying to be systematic at this point. I could put quit in it. I could make it so that the top level is always, everything is always at least one deep and change quit to be part of system, maybe. I don't remember what system was for now. Oh, I haven't put sound in yet. So sound will take up a slot. I honestly don't remember what I was thinking about for system. I remember while watching pairs of stuff and thinking about this stuff that I had a particular thing that came up that I felt like didn't fit any of the other categories. But I don't remember what. But I definitely do need sound and that will bump it over. I could put GL stuff under window or canvas, actually. Or I could put canvas under GL, maybe canvas under GL. I'm calling it frame buffer instead of calling it canvas. I don't think there's anything else that needs to be in it. I think that's everything in the canvas structure. So it's probably not a bad idea. And that will match because the other thing I needed from the GL is to return the render buffer that you're targeting. That's an existing function that I have. And frame buffer, so let's go and call it. It's really a back buffer. Let's test this feature that's in here and see if it works. Be point. Let's make the window 10, 19.20 by 1080 instead. That should have no visible difference, okay? Now let's try this. What is that ratio? Is that 16.9? I think it is. So then let's try 16. There you go. It's grayed out. I'm not sure what's grayed out. And there's a to-do that the frame time should be rendered on top at the actual size. But here you go. And let me show you another feature. Let me use the magnifier in this. So I haven't adapted this yet. It's a Z. Remember, this is in windowed pixels or canvas pixels, but also it may not work. I may not have tested on my work machine, but I have never tried it on a lag there. Yeah, it's black. It's supposed to be a magnifying glass of the stuff I'm doing. Anyway, so yeah, it'll auto-stretch things for you and now it doesn't have the linear filter applied. Okay, I should figure out why they graze out when I do that, but the pixelate will be ignored. Yeah, it's an odd gray out. Why is the frame rate low? Anyway, so yeah, so this is one of the things in here. Also, that's an example of something that's platform independent. So that's why this thing has to be, definitely wants to be split carefully along platforms dependent and platform independent parts. Will this be publicly available? Yes, it will be a public domain, STB library, STB platform. Yeah, I just haven't actually, no, okay, I have. I've written a lot of the boilerplate. All this is going away. All the docs are gonna have to get rewritten. But yeah, so you can see that windowed, that scaling thing, there was an old way of doing it and now the new way is to just let you set the size of the back buffer and the window independently and it'll, if they're the same, if you only set one, it'll auto size to the other. The only if you set both, then it'll do the scaling. And I could do some, try to do some trickery, like if you ask for a size that's larger, I'll actually use a smart down sampling filter and give you super sampling. That might be kind of cute. It's not something I'm gonna do now. It's not a high priority thing, but it's just one of those things you can do because part of the goal here is to make this something that you can just write quick and dirty apps. That's what it originally existed for. I wrote it at work for some experiments with font rendering, which is why it has that magnifying glass stuff. And you know, helpers for setting up shaders, the blitting and the magnify stuff is all using, trying to use GL 3.3 features only so that the stuff it does behind your back will work regardless of what GL version you've requested. And all that stuff will have to get improved because I haven't tested it on other environments and stuff, but so this thing, this app doesn't actually use the events that are currently being generated because I used that FPS stuff, the FPS input. So yeah, I wanna add that magnify option. This is one of those things that it will be annoying to fill out because you want three different values. Again, so maybe I'll do the same thing of making constructors for those, for filling out all the fields at once. Okay, so, all right, so I got rid of the DT. I have an added sound, so I just wanna see what the audit complete looks like with everything. Now, sound and system would have the same prefix. So maybe that should make it audio. It would help if I could remember what I want system for so I could see whether I really need something like that or not. It's for functionality that's not really multimedia, what we think of as multimedia, but it's probably stuff that's in SDL. What else is in SDL? It's a list of the categories of stuff. Now I want the, hey, we're going API by category. Video, input events, audio, threads, timers, files. Yeah, some of these have to be functions if you wanted to do them. If you wanted to provide thread APIs and to make it possible to have user threads and stuff like that. For, to start with, I don't really care about that because it's for making quick apps, smaller apps, but I would like in the long run to be able to make the shipable game using this stuff. As I said, you can add multiple APIs like the whole thing of like the history of the mouse state that enables you to make smarter stuff. The sound I'll probably have two ways, the easy way of doing sound and the more sophisticated way that lets you do a better job of reducing latency and avoiding dropouts. I don't see, we probably want timer functions so that you can do profiling and those have to be functions. I mean, it's not like Parer was anathema, like he had the image loader stuff and stuff like that. It's not like everything has to be defunctionalized. It's just you try to defunction as much as you can. Just the stuff that's like always once per frame kind of things. Or most once per frame, I guess. Yeah, it's not, I don't think I was thinking of it as being platform specific functionality. I don't know what it was. All right, well, let's just get rid of it but let's assume that there will be one new thing. We'll just call it placeholder. So as I recall, I was saying this was one too many things. Nope, this fits. Oh, right, I was worried that, no, I don't know. Gamepad and GL start with the same character. OpenGL, should I spell it out? OpenGL. If you're not typing all the letters, it doesn't matter. You type one character and then press dot and you get the autocomplete like that. And I assume that's the same in other IDs. But if you are typing it out yourself, it'll kind of be annoying. Gotta fix all the places that use it. I'll do the search and replace. One of the reasons why I had canvas separate was because I was thinking about doing a mode like, I can't remember who it is, who has the app.h library, T.S. Gustafson or something like that. That one of the things is if you don't wanna do OpenGL work yourself, you just have a pixel buffer that then you, the framework uploads to GL. Like the framework could either do GDI or can just always open the GL canvas and then have it upsample, upload it to GL and draw it as a texture. We're called GL, whatever the opposite of GL read pixels is. I never use that, the whole bitmap renderer. But you probably want stretch, stretch, blip. So I'll play the texture and draw it. As just a, again, for writing quick and dirty apps that wanna draw to the screen, that's probably convenient. And so that was clear when there was a separate canvas because then that stuff could live in canvas and didn't imply that it was part of GL. And now putting that under OpenGL would be kind of goofy. But whatever. API design, you spend a lot of time sitting around thinking about what should be the right thing. So if people are asking me questions in chat, you should really say nothing's to somewhere in it so that I know that it's directed at me. Or even say Sean and nothing's or whatever. Doesn't have to be nothing's to you. If you say nothing's to you, it'll be highlight at all. Definitely see it. But if you don't put my name in at all, I can't tell the difference between you chatting with me and you chatting with chat. I say that because somebody said something about deferred rendering, which I can't tell whether he's talking to a random person or if he's asking me. If he's talking to a random person, that's fine. He didn't need to say anything different and I'm not following the flow. But if he was talking to me, then he needs to clarify. Okay, so what do I need to do? So I've got all the things that I want in here. What was that? Did I just say there was another one that I hadn't put in yet? I don't think so. So now I need to actually fill them all out and figure out how I want to do that, the whole portable versus non-portable stuff. So the GL declarations, this is all part of the header file. This event stuff is gonna go away or be redone. So one of the reasons why the input field is nice is because I also want to do the history stuff and you could put input.history and then have all the things instead of each one having their own history. Because they should all have the same sample rate. Like you should just be looking at the full input history state. I could add a separate input history or just called history as a top level thing. But that expands my structure by one, which I'm trying not to do at this point. All right, I moved the canvas and that's why this got smaller. So deferred rendering. This is not any specific program doing rendering. Like the thing we see when we run is just a placeholder thing that does something so that you can see it rendering. So, no. And if you're talking about like OBBG, no I don't plan on making OBBG deferred. And if you're talking about anything else, I guess I don't have anything else that I'm working on that I would make deferred. But, so yeah, I mean, I've never done an API like this before. So that's why I'm spending a lot of time sort of iterating on it. Okay, so yeah, let's go ahead and figure this out. Okay, so we're in the header file section. Then, boom. Okay, here we get down to the implementation. And this stuff goes away. Thank God it was a weird hack. Definitions of the own deal function pointers. Yeah, I don't know how this needs to work on other platforms, but for now we'll assume it's the same on other platforms. We don't have these. So now we need our, oh, we have a one. It's called xplot. xplot, okay. So here is old date used on all platforms. And some of this stuff will change and start living in the API. And let's go ahead and keep a pointer to the stvp API so that we only have to pass around one thing and we'll change this from being a global. We'll make it a global, but we'll make it passed around and you'll see why when I do it. Okay, still need this extern. Okay, then all these now live in the XP state and will eventually be moved into, why is that not working? Why is home moving to the right? I don't remember that being the behavior. Is that one of these properties? That's one that, this doesn't feel right to me. Okay, so, I have to remember that that needs to be default to one. So anyway, I'm doing all this stuff incrementally. Like I said, this is totally redundant now and can just use the API one, but I've just gone do it incrementally so I don't break things. This is this. I should have searched or replaced these. I was dumb. You can see I was inconsistent about using the cross-platform thing. Just not in the habit of using structs to store global. So when I try to switch to doing it, I forget some things live in the struct and some things don't. All right, I'm just checking what I got. Just to be on the safe side.  All right, so, right, so now I wanna start figuring out what lives cross-platform. So I moved the cross-platform stuff up here and so then we'll have static for this to be. So, why is that? Oh, no, they're completing. Is that not parse? That's to be, right, that's a struct non-type. Let's just go ahead and call it x. Probably want it to be less wordy. I'll just rename it to xplot once I change everything. Okay, so now, yep, okay, good. So now what we wanna do is derive state such as time, extra, right, okay. Or xabi, I don't know why. Just close that, time.data.seconds with xera. Seconds plus equal. Oh, those are two different types, I think. Derm, derm, derm, derm, derm. So there'll be more derived state, actually, but this is the starting point. Maybe I can put all this in this. It's just, because they sort alphabetically, it's really a pain to find the one you want. Oh, it's not extra, it's... Yeah, that's probably not a good name for this. Thousands. Maybe I should use seconds. It's the key thing in derived delta seconds from it. It's probably better. I should think about what to do about signed because these need to wrap and this doesn't wrap. Although, if this ever starts losing precision, maybe I should make the nanoseconds one be the consistent one. Well, I can change the implementation at any time. All right. So this is where we do things like button up and down, determining press and release states as well. So let's take a look at how Peri did that stuff so I don't have to figure out the Windows APIs myself. I'll use this raw input kit because I've never used raw input. Oh, he changed how he does his flag. No, I guess that was what he always said. Now, the other one, the fiber one did do something about this differently. And Peri mentioned I need to look at these things. Yeah, I'm not using that part of the code anyway. If you sleep until time's your all right. It's much smoother. Yeah, that's, I'm already kind of doing that. Although this none of this code has been adapted perfectly yet. Yeah, here he did this loop. Oh, this was in WinMain, right? Yeah, of course, which isn't part of the... So yeah, so he had to change how that works. Okay, good. Because that's a total hack. I didn't put it in my... I was concerned that there's other ways to post quit messages.  I don't know, that's fine. But I was wondering about like when you get shut down, how does that, like when it tries to auto shut you down, I don't know how that stuff works. Because like this code is just never looking at WM quit, I assume. Yeah, you never detects WM quit. And so I don't know if you potentially miss something from that. But it's definitely easier if I don't have to handle WM quit because this is a total hack. Because I don't... So to save, because I don't use windows.h to save myself in trouble, I don't bother defining some structs. If I don't ever need to parse them because like when you get the Winprock, you don't have to unpack the message struct. It's nice to never have to look inside the message struct. So I don't have a message struct declaration. I have a dummy thing that's just a bunch of bytes. Just because it reduces the amount of code I need to work with that one 32.  Like I don't have a query performance counter yet. And I want to change all my time stuff to use query performance counter instead of time get time, which is kind of dumb. Anyway, what was I in the middle of doing? Deleted that. Oh, because I was going to change that. So where's the destroy? Destroy is here. Yeah, I have this to do about that I probably don't need these things. I don't know why they're in there. This all probably been cut and pasted over from old things. So yeah, platform independent stuff.  Right, all right. So I'm looking at, I'll look at how he did his and I got distracted by some because I saw his, his WM destroying lost in this. So I want to look at how he's doing the keyboard keys. Right, so it's get keyboard state, which apparently it just must be hard-coded to that. And that's all indexed by what VKs. Yeah, so yeah, I'll have to define the VK table myself. That's something I always never get around to doing and I need to actually do it. So here we process our windows events. So he calls this relative to everything else. Pull, is that window pull? Yeah, that's where he does this event processing in here. So after the window pull, this stuff, why do I set this state? I think this should be in post. This doesn't set a shader. How is this working? Both the text probably does. So then, so after we're done pulling, we wanna get this off. And then at the end of pre-app, we wanna make sure our state is correct. So now this wants to go into S3DXplot. S3DXplot, because now this derived state should compute it. And this stuff can go into derived. I don't have access to that. How is the advantage of this? Is that I didn't need a global? How does he do some trickery with some way to get, yeah, the user data? Just use a global, what was it called, API state? No, it was just called API. Well, just for one thing, so I don't care how long this is. And then that was this. I need to knit that somewhere before I run the Winprock. It's the same place as this. Which of course means if I have to have that global for this, I probably shouldn't bother sticking in this and should just access the global everywhere. Okay, yep, now I have to create, get keyboard state. Oh, I have to get key state. This is just replacing that with a single thing to get it all. This is so tied to Windows, but it's like, we don't actually have that function yet. So let's just do that. All right. And then, so, let's see. So yeah, I need the keyboard state to actually have state. So type def struct, wait, I already have one type def struct. Type def struct. You call it a digital button. I think it was called a button. And it has FBP, pull, what did I call it? Small bowl, pull P. Down, pressed. So there better name for that so that it's not ambiguous about what down versus is pressed. Look at its header file. Down, pressed, released. Cause to me, both of those can mean either thing. Do most people use pressed for the state and down for the edge or vice versa? Press goes with released, right? That's funny that I wrote the exact same thing. Let's do that. Keys of, so I usually like to make my reads be singular because it reads better when you access a thing of it. You're accessing keys to X. You're not accessing keys to X. Like it maps to the language better. But I think I want to do a thing here where you can read out from the name if it's plural that that implies there are multiples of them. Maybe history should be the array itself. All right, but that was the whole thing was the embedding this. I mean, the whole thing, right, the people are talking about this whole thing is that and I said this already once in the stream, but the whole thing is that this program, this library goes to great lengths to hide the details from you. So you don't need to include gl.h or windows.h which means it has to do all this work to get at that stuff itself. In the case of gl it's supplying you the gl so you're not supposed to do it yourself but in the case of windows it should work even if you're using windows.h yourself or not. It doesn't quite right now, but it should. And so the thing about that is because it's going to do these great lengths the details on the internals are going to be really gory and gross. And, but as a result, it should be very clean and simple to use. And because of that, since the goal is to make it as easy and happy to use as possible, a lot of time has to get spent thinking about the API because that's all that's left for the user to deal with in your library is this. This for the most part, these structures are everything that the users might deal with. So getting them as good as possible is important. We can always change it, although I'd like to avoid breaking back compatibility which means I can always add things but I can't remove them. And then as I add things while I start having the problem that the IntelliSense window gets too long. So I haven't been doing my in-outs. Well, these are all outs. All right, I didn't like the helpers thing. So let's try taking that out and see how that struct looks without. I had done this originally though and didn't like how it looked. Demonstrate, I wasn't actually gonna ever use that. What was I in the middle of doing? Oh, right. I forgot what I was in the middle of doing. I wanted to test how this looks now. I just don't like that like the, because the sorting of this gets this way and then I guess it's the same order, but this is kind of gross. Seconds is the last thing in the list. We'll try it that way. That window, I need to check my Twitter real quick. Put it right, this little message. I am back. So what was I doing? Right, so I checked that and decided that that was okay. All right, I was doing keyboard. So key state. Oh, right, I see. That's from all that stuff. There goes the way down. Once we get keyboard state, okay. So then we do this and we do API arrow keyboard keys. These down equals. Let's just be able to get that up. Here's code. I don't have to do all the freaking MSDN reading. And then, and I'm sort of practicing the John Carmack inlining idea here. Instead of put modularizing all this, it's just all going inline. However, the derived state, the pressed and released can actually go into this. But to do that, I have to save the old state. So let's instead do, let's do the exploit. Let's do this and leave the rest to the derived stuff. And obviously on non-windows, you'll have to translate everything into the windows virtual key indices, which is obnoxious, but this is just this now. So, yeah, I mean inline, quote unquote, inlining the stuff instead of for single functions that are all only executed in one place and they're all executed in series. No, I typed in the wrong window and now I've done something over here that I didn't mean. Oh, it's called back. It's somehow hummed. Oh, you can do, right. So, xplot key state, so just compile. So I get this, now I can add it here. So that's an RPI, keyboard.keys. That's super redundant, keyboard.keys. I guess that's the thing, if keys don't ever have anything else in them, if they only have this key state, then pushing it out to the top level would probably be better. Let's check what you did. It's so nice to be able to have somebody else's thing. Yeah, he just has keys at top level. I wonder if I should do that. The thing is Windows is hard coded to 256. Like there's no value to pound defining that because Windows can't change, but I guess if you want this to be future proof to someday when you weren't running on Windows. I mean, it does appear multiple times in the code so I guess that's a good reason. Let's just x, how about that? Ha! Now it does appear multiple times in the code. So right, I want to change the keyboard state. Yeah, this is gonna be one deeper now, but let's do struct history, and then that can actually just have the input history.  Yeah, let's just go ahead. I'll decide later how I really want this to be since I'm not actually implementing any of that currently. Okay, that means these top level things can go away. This says we're only because of the history, which I might never implement, right? Like it could be like years from now and I've never bothered to implement that stuff. Okay, so that just goes away. I haven't messed it because I had, yeah. Because I had both top level and not top level. So can you increase video quality just a little bit? Yeah, like are you running at source? Wow, I have enough people that you actually have the option of not being at source, I guess. Maybe? I think where do you get to set the resolution? I don't see any way to set the resolution. It's not under options. Oh, no, it is. No, there's just source. Yeah, so if it's good enough for everyone and it's not good for you, I don't know what's going on. Why can I not close this window? Because it's not even showing the whole, why is my hair color the same as the color as the background? That's terrible. I'm gonna turn this, it doesn't light up the background very much. It's not really any better. All right, so now we've been getting all this key state and maybe it works. So then how do we do this derived mouse state? How did the, that's part of it. That was in the X plot. So how do we compute this? Move forward, move back. This is being computed somewhere as part of the key events. All right, so let's drive that from the virtual keys. Keys of, what is it? Capital letters. Of course, this is really not much work for you to have to do yourself. The fact that I supplied this to make it like easier is now unnecessary because the old thing was event driven and now that you can just pull the state yourself. It's really, it's this right mouse left over, what am I sorry, it's right mouse left. I think I actually wanna change that though. I think it's actually in the wrong direction. But it's not hard to, it's not like it's a problem to supply these helpers, so you can just ignore them. That's one of the fun things about this stuff because everything runs only once per frame. You can do tons and tons of work that's just ignored, that you can provide all sorts of optional information that's just ignored. Okay, so now we can test that that still works. So we got rid of that stuff, it still compiles. Check again, I guess mouse buttons, which I'm not using in this test app. So yeah, the oft requested and never supplied vector math library, there is one in this thing because if you're using over gel, you maybe wanna do math. So, and I made it sort of all GL style. I have to rename it, the PG is an old sort of placeholder name and it could be a separate library but I just decided to go ahead and make it part of the GL library, make it go hand in hand with that. You know, in the same way that this is gonna have the compatibility wrapper that, so you get a core profile and provide some of the compatibility function. That stuff you might want without all the rest of this infrastructure, but I'll just make it possible to include the header file and not use those features. So, so you had a mouse state, so you'd be button right and then you have the mouse wheel and I think we'll just, these need to be, promise this is gonna sort into that on a complete terribly. The buttons aren't grouped, middle button in this version. They are in alphabetical order, left, middle, right, but position will sort into the middle of them and mouse wheel, delta will sort into the middle of them. Could do delta mouse wheel to be consistent with all the other deltas. Windows has that whole crazy multiple of 120 thing. I don't, it never makes any sense. Like they say it's always multiples of 120 but they also say you should accumulate fractions and I've never understood what's going on. So for this I need to get pairs for input stuff, I think. Do you have to allocate or can you actually just, no, it has to be one of these three. So the upper bounds of the size must be bounded. Wait, what is this? Is he doing the buffered one? No, or the more than one at a time one? Yeah, I don't know why he's allocating. He's in the chat so he can probably tell me. You could just have a stack buffer that's generously sized. I just don't understand why it has to be generous if it's only one item. So what's the zero size call first here? Really input data PCB size. So let's see where they talk about this. Data is not null and the function is successful. The return value is the number of bytes copied into pdata. So you're using an undocumented feature that the return value is the size. If you pass in null, the return value is the size. They don't actually say that. They very carefully don't say that. They say it has to be not null. Oh no, that's the return value. Sorry, my bad. Of course, that's still not, that's still ambivalent to find. The documentation is so terrible some of the times. Anyway, it seems like it's just got to be the max of those three things, which probably doesn't need to be that big, does it? Let's know. One thing, I want to click on that again. How can these be really big? Okay. Yes, I see. What does W input have to do with O? I see. I'm from the same head. The size of the raw data array. Do we size hit times DW count? Oh my God.  If you're using the buffer, can't you just read a chunk at a time? I think that's what I did. Well, this doesn't explain. I know there is a separate raw input buffer, but I was looking at the docs for this before and it doesn't really explain anything. Using get raw input buffer, the raw input buffer data is buffered in the array of raw input structures. What array of raw input structures? The one I passed in. So what do you mean by it's buffered there? You mean it's buffered somewhere else? That's just like there might be, there's some top level docs that explains it. Like I never do this kind of stuff. Like that was, Casey went into the stuff where for, I went higher than the raw input reference then or something. I want the overview of it. Casey like knows the Win32 stuff better than me and knows where to look for the stuff. So, let's see if this talks about buffering. The unbuffered, yes, the raw data run and it's accurate for many IDs. But one raw input structure we were just seeing can have an array of stuff that we don't know what to do with. The raw hid. Like there's no information on what to do with this. Maybe that's somewhere else, but using the raw input handle contained in WM input. Where's the raw input handle? It's the L-param. Yeah, anyway, all right. So we definitely don't want the buffered one. Okay, does this document what happens if you call it without a large enough buffer? No, it does not say what happens if you call it with not a large enough buffer. Oh, here's the thing that I was talking about pair doing. It's documented in pdata, not document PCB size. Spends on the value of UI command. What? What? What is the header info? I don't want to know. I'm just gonna copy what pair did. Okay, so yeah, I'll just use a generously sized stack thing and they don't say what happens if it's too small. So I wonder if that'll just get stuck if it'll never consume the thing, if you never pass in a large enough thing. Will it return to a truncated thing? That's my only worry about that. Yeah, I've always used non-raw mouse input. And I think what pair did does, which is also what I'll do is that for the deltas, you get a raw input, but for the absolute position in the window, you use the regular windows thing. I guess he doesn't use the mouse move event to get it, though he does something else to pull it. Get cursor, yeah, get cursor pause. What is happening to this? Why is this Firefox window? So you just get cursor pause to get, and that will give you the ballistic, my Firefox is just dying. I have so many Firefox windows open. Somebody is busy. Is that just the Twitch? It's Twitch using that much? Yeah, I have one of the Firefoxs. Hey, it's using two gigs in Firefox. All right, let me restart my Firefox. Okay, so what I wanna do is not lose all this window state though, so we're gonna end the process. That news, this tab is crashed. No, I want you to... Why are there two Firefox processes? Has Firefox changed and added up some kind of helper? Are they actually running the glue? The gooey, what do you call that? Are they running the Chrome in one process and everything else in another process or something? Yeah, I've noticed that there are two Firefox processes nowadays when I run. Now one of them is already up to 500K. Yeah, what I've done in the past is hide the cursor and keep teleporting the cursor back to the middle, but it's possible to move the cursor out of the window. You can't, because you can't capture it, obviously, when the mouse isn't down. Okay, so now which of these things was I looking at? Let's look at the mu. This one I can close. Let me check my Twitter notifications real quick. Right, because I posted about whether I should do an mp3lib, so. Oh, I'm overlapping handmade hero. That's a shame. But yeah, and I don't like doing that ugly hack, which is why I figured I would copy Paris raw input stuff. Dun dun dun dun dun dun dun dun dun dun dun. Dun dun dun boom boom. Oh wait, this was only the initialization code which doesn't belong here. Initialization code belongs here. Do I have to do it after I create the window? What? Yeah, it needs the window. So I've called create window at this point. Does calling create window, why does this call stb create window? Oh, because it does some other stuff. Let's just look at where he did it. So he does window initialize, creates fibers. Wait, but he hasn't created the window yet? Where does he create the window? Creates the window here, but he starts the fiber. Oh, because you switched to the manually, right, of course. It's not a big deal to create it. And then calls to a window. Oh, he doesn't do anything in W create. The problem is that I do a bunch of my stuff in WM create and he doesn't do that, I think, or though it's not the old one. Yeah, he doesn't do anything in WM create. So he probably creates that stuff because once upon a time when I was doing the Windows programming, there was something where you don't know the size of the window till you get the WM resize message, which requires you to have pumped events or something like that. And so you were encouraged to do everything in WM create and WM resize or WM size. I don't remember the details of that and this was all back in 32, you know, Windows 95 days. So maybe some of this stuff has changed. So what I was looking for initialize. He does OpenGL initialize last. So he's already created the window, yeah, and here's where he does the pixel format descriptor and create context. Yeah, and I'm doing that inside the create window, the WM create. But the handle, the window handle, at least, should be create window. Should already exist after create window, right? Yeah. Do we store it to somewhere? It has to be win window, right? So this is the window specific way. I forgot what it's called. So I'm gonna have to make versions of all these structs. Oh, no, I'm violating Microsoft's copyright on stream. Why is this not auto-completing? What's my error handling in this? Don't I have to, oh, he has those as numbers already. So that's in some other, so user 32, did I typo? Oh, is this not in the VC6? It's not in the VC6 SDK. Win user.h, though, that's not, what was it called? Nope, it's not in the VC6 set of all. So yeah, I think I will have to actually get that one out of user 32 DLL by hand, which maybe means I should convert everything over to that. What happened to my declaration of it? No, I'm already doing it a little bit for this. To actually use the right syntax. Cannot modify pointers to data. An acronym that's gonna be used. Modifiers and data are ignored. Is it like this, then? Okay, there you go. Ah, all right. All right, so now we've got the register. I'm writing a wrapper for the Windows functionality and OpenGL so that it's easy to use library for making apps without much work. I should make a simpler test app with that as much crap in it so it fits on one page or something. Inline all this stuff so it's not a function call. And this old get height thing, am I even using it anymore? And the new renderer? No, I'm not. Oh, yeah, I am. I'm using it for camera, get height. I could just move the camera in a plane instead of having it try to track the terrain. Okay, so I think maybe cursor visibility was something I wanted to put in system because it's not exactly window specific. I can put it under window, but it's not really. All right. When did I start eight? Am I going from here in three hours and barely done anything? It feels like, all right, so we got that working. Let's just paste this whole thing and then fix it up. Oh, I'm in the wrong. No, I'm in the right file. What do I have? WM create. All right, these are not documented. So this is windows, so this is WM input. Sure, it's OFF. So, okay, plus equals it because you might get multiple of these per frame. That makes sense. So we'll have to zero it elsewhere. So actually, and instead of going to the API, we could just go directly to the xplot structure and then require it to get copied out. That might be better. And then you have to decode the button flags, though. Okay, so we'll need the raw input struct. We'll need to get raw input data. Oh, I should have left that raw window open. Why this wasn't hot linked from one of those, I don't know, but so we need this function. Oops, I keep going down to the end and that's not where this stuff is. It's all in WinMain currently. I need to clean this up. What's that? Share? WinUser, which I mean. No, I guess I want the real one. This is a modern, over here I have a modern SDK so I can use WinUser. WinUser, and why are these, okay, great. Oh, okay, the wrong window. No, that's not the wrong one right now. Oh, wait, what's the wrong one? I closed it. How many is it? WPram, so void star, one, two, three, four. It's about WPram only four bytes or it can be eight bytes. Four, eight, 12. Let's just assume 12 bytes worst case. Oh, no, it has to be the actual size of it. It can't be an estimate. But I never look at the raw input header, right? We do look at the raw input, okay. So it can be the size of, all right. This is not something where there's offset of but there's no equivalent field size of. Okay, so raw input, raw input. And then we say size of raw input header for mouse structure. That data, we need mouse wheel. Oh, we need these flags. Okay, so all that data needs to, whoops, needs to live in our thing. Yeah, raw input. So, let's put that there for now. We left out the raw input. Hopefully that's only used for the buffered stuff or something. Where is the actual raw input struct? Where is that struct? Raw input header. Where is the raw input? Then the keyboard. Where's the struct? Oh, there it is. So then our raw input struct is going to be raw input header followed by a raw mouse. And then the raw mouse is right here. So we just do this. All right, now we reformand it. So the whole thing here is just to make it as compact as possible because nobody needs to look at this code. This code is all just to replace the windows.h. It's compactly as possible. So that's why it's super compacted. Like this stuff is not meant to be readable. All right, and I have a, I had a thing up here so I didn't need to go figure out what W pair was. I have my cheat sheet. Do we use these? Button flags. We use button flags. But we don't use the other thing. Oh wait, us flags. Us button flags and us flags. Us button flags and us flags. But we don't use UL buttons. I mean, I could just use windows.h. Like, since currently it is doing the DLL import still. It wouldn't be the end of the world. It's just not very sanitary. Windows.h puts some stuff into your namespace that is pretty ugly. I can't remember what, like. There's some names that you can no longer use because they kind of find backwards. They're just like short words that are reasonable words for you to want to use. I can't remember what. I've run into them a couple of times. So there's a few reasons to maybe want to stay away from this windows.h. But you could include it. It wouldn't be the end of the world. But since I have to import all the openGL stuff anyway, I figured importing the windows stuff is going to be way less work. So my might as well. And like I said, I haven't done the work to actually import it properly. I've done it for the raw input, but not for everything else. One, I import them properly and I give them all stvp underscore names, then it will just won't have any interaction with the windows.h at all, which will be better. So I don't need to do this twice if I'm just passing in the static buffer. Does that have to do that? I'm not sure. I have to look that up. And then read input and then type mouse. As long as I'm doing this for the other ones, I can do that. I don't usually do it this way though. But this will be a little more readable. Equal size though. That's not right. So I'd have to change how that works. Let's see if anybody else said what I should do. So I could undefine the things that windows.h brings in that you don't want. But if I undefined them and the user wanted them, that would be a problem. So the easiest way to avoid any collision with what the user wants is to just avoid the whole mess. That's not the easiest way, sorry.  But it seems worth doing. So I got to look back at how this works and figure out what I need to do. I still have the problem that if this buffer isn't big enough, it just won't pull the data out. And they just don't tell you. I guess I need to go up to the overview again, but I don't think it said anything when I was looking at it. Yeah, they just knew the f- Oh my God. So bad. So bad.  There's just no way to tell what you're supposed to do. You could have an STB that undefs them and otherwise doesn't. Yeah, but like, that's just more things that you have to know to use the library. It's easier to just make the library not easier. Your life as a user is easier if the library just hides it from you. So could I use just use this library just for window management and input, but not have to use it for openGL? Not at the moment, you would have to actually turn off the openGL stuff. It's not currently ifdeffable, I mean you could put ifdeffs in to turn it off. But you need some way of drawing to the screen. So you would still have to it currently doesn't expose the window handle to you and you would need the window handle to draw to the screen and stuff. So as I mentioned, I plan on adding a thing where it will use openGL for you to draw a bitmap to the screen and you would just fill out a bitmap and do it. But if you actually want to use GDI functions, yeah, you'd have to it would be pretty messy because of the lack of the window handle being exposed and the paint being exposed. Right, so I'm trying to just get it to compile. H raw input. Alright, I was trying to figure this out, the size stuff. So right, and so because this documentation is so round about okay, returns you the correct size alright, zero. Data is not null and the function is successful. The return value is a number of bytes copied. So I don't need to check that. I just need to check there is an error, the return value is negative one. So that then cb size is an in parameter. No, it's an out parameter. Oh, cb size head, sorry, pcb size is in and out. Quarantize, let's return there. I think this is correct, but boy, they don't really. So you're going for the SEL renderer stuff. No, I'm not really going for that. It would just be a really lightweight, dumb, simple thing. It's just a thing I could throw in. It's definitely not my priority. It's the easiest way I could imagine you to use this library without using OpenGL, is if I have that, then you could do that. But if you really wanted to use it just for window management and input you'd be hard pressed and you wanted to like GDI render, it would have trouble figuring out how to do that. Um, mouse, because I simplified the structure on the assumption that I'm only using the mouse. Wait, why does this oh right, because he's because he was doing it that way in his code. I need a Corlebrace at the end. Try running it and see if it, all right. It's now getting really slow. So something is something in those messages is triggering something bad. Or I'm not propagating and my alt f4 is not working. It's not processing messages efficiently.  Either too many messages are getting generated or something weird is going on. Uh, I don't need all these anymore. They weren't doing anything anyway. I do need these for the mouse look actually at the moment. That's about to change. But at the moment I do still need them. Yeah, I have this. This stuff is still in here at the moment. Um, so I would be nice to figure out why that's all going crazy. It's something to do with either the fiber stuff or something else I changed at the same time I put the fiber stuff in, which is possible because I restructured my event loop to put the fiber stuff in.  Which is really easy with windows because I don't really know the Windows API that well. I often just cut and paste stuff. So it would be really easy for me to screw something up. My, uh, my way of, I have a whole system for keeping let's see where I call sleep. Let's just not have the, let's never wait just to make sure it's not that. Nope. You can see the frame time is still fine. It's just the events are not getting pumped. So did I screw up the peak message stuff and I like only processing one event per yes. That is not correct. Where was pairs? No, that is what he does. He switches to fiber after every event. Let's check what he does in the new thing. Maybe that was a bug in that. Oh, yes. That's a while now. Okay. That will fix it. I recognize that pattern of behavior. Yes. Okay. Get raw input data returns unsigned in. So that's always true. Brilliant. Oh, you went of negative one. Yeah. Okay. Thank you. Uh, isn't you in the negative one? Have we all decided that that is undefined behavior or something to find or is it undefined behavior? Yeah. The chat is confused and not understanding what I'm talking about. Yes. Of course, negative one is this does work. It's totally fine. That's what it means on all compilers. The question is whether it's actually see specification legal because compilers have been moving into defining a whole bunch of wrap around things as being undefined behavior and exploiting them in their users. Here's your overflow. So the question is whether casting them is one of those or not, which I just don't know offhand. It's fine on windows. I'm just I'm amused. My point here is that I'm amused that that is what they put in their docs if they themselves because MSVC has not exploited this kind of stuff for a long time, but they have started doing it recently. And so if that were actually undefined behavior, that would be amusing. That is my point. But I don't remember whether integer casts count for that or whether that's a safe one. That's the only question. Oh, no, I want signed unsigned, not unsigned to sign, but close enough. Implementation defined, but not undefined behavior. Oh, wait. No, that's the new type signed. What's the new type is unsigned. Okay. Yes. So the new type is unsigned. This is totally safe, but in the other direction it's implementation defined. But it's never undefined behavior. Right. So that is safe. Right. So now are we getting this code? Yes, we are. Okay. So now we got to do the buttons. So we have if button flags and left button down. Wait, are these edge triggers or these states? I was expecting them to be states, but I guess they're edge triggers. Yeah, they're edge triggers. All right. So but on other platforms, it's possible that it would just have the state. So yeah, let's turn it into state, which is what his code is doing. I see that now. We'll turn it into state and then we'll recover the edge trigger. Let's do middle first. Um, so this is 400. Okay. So because we want this to be cross-platform we're going to convert to units arbitrarily chosen so that a one-wheel delta is one unit. And we'll preserve mouse move relative. He wasn't checking that. Oh, there it is. And this one is I didn't preserve that. What is it again? RIM mouse type. RIM type mouse. Like that. 456. Try to compile it. Now we have all these. I want to change these from button flags to flags just because I wanted it to be less like Paris code. And we have this mouse button down, mouse wheel delta, mouse delta wheel. It should be mouse wheel delta. All right. What do you mean no intelligence? It has a crappy old instance. Oh, it's just not completing something. For some reason this structure is failing to complete some of the time. That one's doing it. I don't have that structure here. All right. So now I'm derogating all this mouse data into X-plat and then I can derive. So we want this to be a generalized function. So this is VP random accidental typing messing everything up. Okay. It's the arrow. And it has to be a compute derived button. So I and then we haven't actually even tested any of this state yet. Pair is much more careful. I know from watching that he's much more careful but every time he implements something he can actually test it. Whereas I'm just running hog wild with this crazy stuff.  So this it's got this formatted. Okay. So all right. So we filled out delta position X and Y. Okay. So I said everything. I have to I mean other than all the huge amounts of rewriting I have to do like I have to test this stuff. And then once I tested it is there anything else? Is this gone now? I think it is gone. I'm going to have to recreate it though. It doesn't crash. Let's go ahead and check it in. And then let's test the things. So need to test. Okay. So I have some kind of debug. I said debug print function to debug it. That's to be debug debug dot mouse dot left dot pressed to get that open and we need to get that showing it. Nope. It's not working. All right. Am I calling that function? There we are. I'm calling it. Let's break here if anything ever shows us is down. Okay. So is down is true. Was down is false. V was pressed. Is true. Why is that for a keyboard button when I pressed the mouse button? Do they have like virtual key buttons that mean mouse buttons? Okay. So obviously I hit a key that will trigger but if I hit the mouse button very weird. They must have virtual keys that are mouse buttons, I guess. Okay. So but it just triggered so we can look at the mouse button state. Okay. So that doesn't seem to be working. So raw input. Oh, we should look at that state whether it's mouse move relative. Wait, how did Pear do this? We should look at that all the time, right? You don't need a mouse move to trigger that. Whereas, no, he does all this inside that. He does it all inside mouse move relative. Do I ever get to this code? Yeah, I get to this code. Do I get to that? Wait, some key is stuck down now. It's never finding out that is that looking at the wrong thing key state 116 maybe I should be testing the keyboard instead of testing the mouse. So let's take out the assert keys of definitely seeing the key. It's doing the right behavior for the key. So for some reason the button is getting triggered. We don't know why raw input but this is never triggering. So we're doing something wrong. Maybe the size thing isn't working. We were getting here though. We saw that we were getting here. Right? Yeah. But only when we move the mouse, all right. So now if I don't move the mouse and I click it now it does get to here. But the US button flags is 0. Why is the US button flag 0? It didn't overwrite size with oh right this returns the size. Yeah, it's about mouse buttons are keys. Okay, that's interesting. Didn't know that. We probably want to hide that because we don't want to force the other platforms to have to implement it. Although maybe it's convenient. Maybe we could just do that. Maybe just make that view the official requirement and the other platforms have to replicate it themselves or the xplot code could do it itself. So why does this not work? It didn't check whether the position dots were changing. So let's print that. Right now they'll just accumulate because I don't ever don't ever zero that. Yeah, it's definitely getting the mouse moves. So why is it not getting the mouse buttons? Did I put it in the wrong spot? Did I get the format of the structure wrong? It's possible that because it was in a union it changed the alignment of it. But no, then these wouldn't be right. Let's trigger it again. US button data. Oh, I'm looking at US button flags. Am I looking at the wrong field? Did I get the fields backwards? Button flags equals US button flags. That's pretty unambiguous. This was a union of this struct. Let me go look at that again. Where's the mouse? Am I in the wrong? Yeah, I'm in the wrong one. There we go. Union of flags and data. A union of buttons and a struct that contains flags and data. Why is this backwards for me? Because the U long there, it does. It does cause alignment. Yep. Okay. Yeah, I should have just I shouldn't have tried to reduce the structure. I should have just left it alone. So that should fix that. I'm still not seeing it, although it might be because it's just scrolling off. Yeah. Okay. So I have to get rid of the mouse move print now. Okay. I got the down, but not the up. Cut the Facebook. Cut the Facebook. And then so that'll be fixed. Then what else do I need to test? Um, I guess that's it. I have to test the mouse with Delta, but that requires a different print. Okay. The other buttons, I'm not testing. So just change left to right. Yep. Okay. That's good. We already saw key down was working. And it looks bad. Looks like it's printing something funky. How do I move my window? Okay, the mouse wheel doesn't look like it's working. Not sure why. Whenever I hit the mouse wheel, it's moving my display. So I'm fricking up position instead of well, it's just right in the mouse will data. I don't see how that's going to how is that going to bleed into position? I don't know. Let me clean up these Delta positions that accumulate. Well, no, let me leave it accumulating so that I can see it in the debug. So why is the mouse wheel not working? It's really not working. No, it's really not. It's glitching my thing, but it doesn't, it recovers the position. Where am I getting this position from currently? Oh, I still get mouse move events. Um, so doing something with the mouse wheel event. Just store it into that structure. Yeah. So somebody in chat had actually caught the that I left out that your buttons. The subframe event question. I'm not planning on handling it anytime soon, but I have this thing in the API that will tell you about events that happened over the last frame, but I may never, ever implement it. But it's there in the API. Um, I just, I don't even know how to implement that on the window side. Can I run a thread that pulls the input? Like, I don't really know. Um, because the raw input is currently coming in through messages. So I'd have to pump the messages. Oh, I'm storing it into Xplot. Xplot, and I'm never propagating it in derived. That's why. Uh, the mouse wheel is up here, and I must have made an int, and I want it to be mouse state. Yep. Okay. So that's accumulating. I want it to actually accumulate some mouse wheel delta. So this is compute derived state. So here, pre-app, right here is when we do the message pumping, so we want to clear out some Xplot state in this particular case. No, I know. Why is that not completing? Um, where's the NCB file? Oh, it's part of tests. Now that's not fixed. Yep. Um, so what was it? Uh, mouse wheel equal to zero. CBP. What was the mouse position? Or do we do that directly? We do that directly into the API. I guess we should do the same thing. We should do, we shouldn't go through Xplot. We should just do it directly for the mouse wheel as well. Make them consistent. All right. So now it spikes for a moment. All right. What about resizing the window? No, this, I didn't enable resizing. So yeah, you see it go negative one for a moment. That's fine. Okay. That all seems to be working. We're thinking about collecting all the events and moving through on the outside. Yeah, that is also a possible alternative API. The, I do want to do something like that so that you don't miss button up button downs. But I'll probably do it through the naive API by default. It will actually lie about the events. It will record events if it knows about subframe events and will record the events and play them out over successive frames. And then you can disable that if you don't want that behavior. And then you can also use the time stamped. I mean, that's a time stamp. The event queue, if you want to directly grab events in correct order and like to hand them off to an AIM GUI or something like that, you would want to just grab the events in order potentially a multi-pass AIM GUI. If it's a single pass AIM GUI, you actually want all the cheating that I was just describing. And but I don't even know how to pull the state with subframe in the first place. So I'm not going to do any of that coding for a while. Like if we actually got an event queue that had time stamps we could get that. But since we're polling the keyboard state, instead of using key events we can miss the transitions on the keyboard. The mouse I guess we would get every event, so we could do that for the mouse here. We could queue up. We could turn them into an event queue here. And so that's probably what happens in the long run, is you build an event queue and then the cross-platform stuff knows how to parse the event queue and turn it back into into the final state. But I don't have to do everything initially. I can just get it working. Like right now I still have this thing where I have some redundant state between the cross-platform struct and the API struct. And I want to flatten that stuff out once that stuff's dead. And I want to flatten out all the functions. We don't use any other functions currently. So I want to get rid of all the functions that aren't needed as well. So now that I've finally gotten all the input working that's sort of the next thing. I want to clean up the timer first, actually. So I guess the first thing to do is use query performance counter. I think I'm done with looking at pairs code. Oh, he has the gamepad stuff that I will want to do eventually. So I'll keep that around. But I'm done with raw. I'm handling WM timer. I found out if you sleep until time to draw instead of wing until the next WM timer, the frame rate is much smoother. I know what you mean, but I don't see how his code WM timer is doing that. Because his only WM timer here is to wait one millisecond. He's just not using that for... He's not using the WM timer for that. He's just waiting until his ticks is like that rather than using WM timer. Let's see what else we got here. There's another raw input. Windows messages. Are we done with Windows messages now? I think we might be done with Windows messages. We need to be able to reject resize events. How do you reject resize attempts? Can you reject resize attempts? There's this enter resize call. Can you resize? That's also for move. We definitely wouldn't want to do that. Because we can create the window with the right state about whether it's resizeable or not. For some reason, this one is not resizeable. Let me fix that. Why did this not get created resizeable? Window is resizeable. Create window 1, 0. These are just calling us to be a windowed. Oh, they need to be called windowed resizeable. I can just check a flag here to see whether to create it resizeable or not. What if you change and I could make the whether to resize or not be windowed resizeable? Of course, since you have mouths, it gets super annoying. That is not resizeable. Even though I have the fiber going on, something is not propagating the new window size until the end. I think that's a little weird because of the mouse look. Oh, and then I don't get the mouse move. I'm not getting mouse moves. Oh, no, I'm not using the mouse move though. I need to use the getCursorPause stuff. GetCursorPause that needs to go here. I have that code in here. I think. Don't I have something so I wasn't Oh, that is the absolute coordinates with mouse move. I thought I remembered seeing this code other than in Paris thing because I thought I remembered seeing a different way to do it because he's subtracting the window position. GetCursorPause in screen coordinates. So then you have to keep track of the window pause. Is there not a getCursorPause that's in the client coordinates? I guess not. Yeah, screen coordinates. All right, I just have to do it the way a pair does it. Let me look at my DLL imports. Why did a forward search find the last one? GetCursor. No, that turns it that's the cursor, what cursor it is. Nope, I don't have any functions. I could have sworn I remembered seeing this. Maybe it was in a different program. I don't think. I don't even have rect. Oh, I see what I'm doing. How do I use that? I just do it directly. So I can avoid having all these types. That goes into I guess I could just declare it as taking the array. There would be no harm in doing that. That's correct. I have not done that yet. That should be a point. Then where does he get that from? Initial decision. Yeah, this whole mess. I've happened to client to screen. Won't need all of that eventually. So many functions. Right, that's not right. This is just always zero zero. I'm pretty sure this is a dummies of the rect shrink. Yeah, left and top are always zero. Like the whole thing doesn't need to be a rect. It's a total misleading thing. How long will you be streaming today? I have no idea. I've already been streaming for four hours. That is a good question. But one I don't know. So yeah, I'm just going to rely on knowing that these are zero zero. I better check the ordering of left, top, bottom, right. Left, top, right, bottom. That's correct. X, Y, X, Y. Other than you have the whole Windows inverted thing too. That's that. I want to expose the Windows position on screen. I guess I do. As I mentioned, some of these are also output variables. So I'll want to check if they've changed and like the user can ask for this resize of the client's rect. It can specify the that change and it should resize the window automatically. But I'm not going to do any of that kind of work at this point. Via WM Timer or whatever. But the WM Timer needs to be message pumped. Which means it's got to be in a different thread or something. That was why I was asking about that. Because there's a whole mess in Windows with the Winprock is associated with a particular thread. But I think there's also a thing with the OpenGL rendering has to be the thread associated with the window as well. So you're forced to do it on the same thread as the Winprock or something. I don't know. I don't really understand that stuff very well. But it seems to me there was some mess about that. Because then I've got to add client to screen and get client rect. And I still have a mute left over. Client to screen. I already had get client rect. I closed it. I wonder if like minimizing also can do this. I don't know. Maybe that's very specific to it being No, it might be the kids once minimized. Let's get client rect fail or something. Get client rect returns a bull. They don't tell you what the circumstances of it failing are. If the function fails, but why could it fail? I'm sure it failed. Return value is non-zero. Returns a bull. Get client rect. It's all right. All right. There we go. I did not screw up on exit. I minimize. Client rect works. Client to screen works. It's only while it's being destroyed. Maybe it's already destroyed by the time we run this. The window is invalid.  No.  Isn't it inside? No, it's not. That's probably better. Probably see for. Okay. I haven't checked any other stuff. But...  I'm pretty good about being able to guess what the name of a function is that I've named previously because I used the same thing. All right. So now I should start margin removing the redundant state from the structures. So... Let's look at this stuff right here. Pat version. All the functions are all going to come from the state anyway. So... Right here. So this just does... Those are all just setting state. So we can just use that state. Okay. So we need to take it out of the export state. We need the GL debug. GL... OpenGL... So now let's come out of OpenGL.version.major. Then we want to query back what version we got. And, of course, if it was 0, I think we just have to always do this. How do you ask for 4.0 under this scheme? That's kind of a problem. This is part of CreateContext. So where does CreateContext get called? Currently inside WM Create, which I want to fix. And then... that's part of the window proc. So... part of init. So we've created the window by here. So we have to do it before that. Wait, what am I trying to do? I lost track of what my goal was. Um... Oh, we have to fill that API. That's all. So... API... Still working. So we got rid of some of the export state. So let's say if there's more export state to get rid of. We have to move that to Bsync. Is it a bad idea to call this every frame? I don't know. Let's see where else there's a Bsync. We automatically did it here. And then... to do... check if... undo... undo undo. Testing on the function is still correct. It's this. We got rid of that. What else can we get rid of from here? Is it used anymore? No, it is. So how is that being computed? Ah... So we want to change this to... plus equal... position. How much does that need to get scaled by? Bsync scale. Create a default value for that. API... FDS.Bsync... scale in zero. Then... default. I have no idea. Let's try that. I assume that's too small. Let's check. Also, I thought I was... What happened to be clamping the vertical? Oh, that was in that code. And I turned off. I guess. Hey, look, it keeps turning when I'm outside. No, we know. Yay. So yeah, I have no idea. That's the derived. So we're working directly from the Delta positions. Which we're computing directly from that. And we're zeroing at that. Okay, that's good. That's all actually doing the correct thing. Just wanted to make sure we were going through that path. Um... So now this stuff can go away. But this clamping, I need to... move up. Okay, so now that other stuff is commented out. And this is scaled wrong again.  I left it at 0.1. Okay, but now it clamps... that way and doesn't clamp that way. This is backwards, though. Right, let me think. Move the mouse right. You're turning to your right. Move the mouse right. I'm turning to the right. Yeah, that's backwards. Why did this get reversed? What's one of those negated? ViewedRx. Where did it compute? ViewedRx. Why am I not seeing this in the diff? ViewedRx. Right there. So in the red. So there should be a red ViewedRx somewhere else. It's being used. Where's it computed? ViewedRx.computed. Oh, it's f0, no. No, I was using 0.35 before now. It's 0.25. Neither of these is negated. Was it just always backwards? Oh, no, they're both negated. Why are they both negated? Push forward should... tilt you forward. Push forward. If you're going to shoot her... you can still look down, right? Pull back. Wait, no, now I'm using... Or is that flight controls? Crap, I'm getting confused. It's controlling which way your head moves.  Yeah, so these are both negated. Okay. So... It's right here. So these both can be negated. Oh, that's the plan. Doom, doom, doom, doom, doom. Yep, okay. That feels right. Oh, we already switched that over. Those now are stored in the API structure. We should get rid of those. Onto my backups. So then... Release. Oh, I don't want to save. Why is so much stuff changing? No, it's just git. I'm just going to global search and replace these. vpxplot.canvaswith. vpxplot.apiarrowopengl.backcover.size.x. That's awfully long. The height comes to that.y. It says vpxplot.apiarrowindo.size.x. Check if it still works. It still works. All right. So we got rid of that stuff. OpenGL state now includes int. That's probably the back cover. int. It's our better name for that. What's it called in GL render buffer? Replace that. That's vpxplot.framebuffer. It comes as tv. vpxplot.apiarrowopengl.backbuffer.renderbuffer. That replaced too many things. Let's undo that. Let's restore the frame buffer. Save that in our paste buffer. And now undo past it. So I'm going to get back to... So this should still come out. We're back to the state. Now fix all these. I could probably use an identifier where search replace. But there might be other appearances of frame buffer somewhere. But I don't want those to break. So it's faster to just do this. All right. Now we can search and replace that. xplot.framebuffer. I'm going to go back to the state. I'm going to go back to the state. xplot.framebuffer-rv. And now the problem is that that is not in this declaration. Now it should all work. All right. Last mouse positions. We're probably not using those anymore. Wait, we're still using... This code exists. It doesn't do anything though. We should be able to just get rid of all this code now. Let's make these do nothing. Let's see if everything still works. Oh, this is using the client coordinates. Right? Yep, okay. Let's not search and replace this because I want to make sure there's nobody else using it. This one should use it. I can just use api directly. I'll do the magnifying glass. What did I put it on? No, I turned it on. It's still not showing up. Oh, because now I'm not doing the key events. So it never gets a chance to trigger. Let me say key n equals x arrow api arrow keys of key. What was this doing? I'm going to buy scan code. Oh, because it was distinguishing keys from scan codes. This one was using a key interface. Not the scan code interface. Isn't that what it's called? No, there was only a man with my key. I see it was just checking about why are they incompatible types? Shouldn't this be .insertdown? So it's magnifying a little bit. It's weird. It wasn't working before. Now it's sort of working, but it's also causing that gray out. There's some state that's not being cleared properly. It should be zooming 4x though. I'm sure it's not zooming 4x. Oh, I guess I was trying to write it before while I was in the fat pixel mode. So that does not look to me like 4x. That looks like 0x zoom to me. Well, it moves at a slightly different rate. But it's definitely not 4x. Or is it because it's all self-similar? Maybe it could be almost 4x zoom? I just can't tell. I just know where near the origin. Am I starting far from the origin? Yeah, I am. I'm only drawing a region far from the origin. I did zooming a little bit, but it's like a 2x zoom instead of a 4x. Or 8x or whatever I said it to last. 4. Why is it not actually zooming 4x? Oh, maybe that really was zooming by that much and I just couldn't tell. Obviously, it doesn't work very well in FPS mode. So I need to change this so it's not a function, but I just wanted to get it working first. Okay, so that works. What did I have to do? What have I done? Let's go ahead and have things commented out here. Yes, I turned these off. Now we can stop calling them. Which is this block here. How we get this thing now. It's a couple hundred lines larger than it was before when I started this morning. Before I started you're fine. So xplot should only contain state that does not need to be user-visible. And it should contain all the states. So these three need to move into the app. Not this one. Well, this one could as well. You don't set a key, you turn on and off magnify yourself. So I guess all three can. And that can be part of the window. It's kind of related to the back buffer. Kind of related to the mouse. Because it uses the mouse position to draw the magnifier. I guess we could make that separate the magnifier. You could set the position yourself. Really only intended for quick and dirty help. If you want, you can make your own magnifier if you really need it. Scan code. It's always just square. Magnify Key becomes magnify.scancode So let me bring this on screen. Sbxplot magnify Key becomes sbxplot magnify.scancode magnify zoom magnify factor magnify size magnifypixels magnify.nonpixels magnify is not a matter of no, let's pull out window. abiero magnify abiero magnify magnify becomes Here we go. We just have that state. Got pissed at the bad one. Yeah, I do still have to fix that state. All right. So now we've got that out. OK, now I think this is down to the actual minimum I wanted it to be. So now there's no more junk being carried around redundantly. So now the next thing to do is get rid of any remaining functions. Do we already get rid of magnify? No, we have to actually do that now. That's to do E dot window dot. It doesn't know how to complete. That's annoying. That looks good. Wonder if it's intentionally fading the background and trying to not fade the foreground? Maybe I should finally look at what that state is causing that. And then I assume that this is just an interaction with these. Ah, I see what it is. It's using the wrong coordinates. It's trying to interpret the mouse coordinates in the back buffer space when it needs to convert from back buffer to foreground. Oh, and I'll have to fix that in the client coordinate system as well. The mouse position. I'll need to do a derived thing to convert from the window the mouse position dot x to the mouse canvas dot x, something like that. It's supposed to clamp that. Oh, but it's clamping to the wrong coordinates. So we can fix that, at least. Magnify. We're doing the magnify. Clamp. Window center. Oh, it's supposed to be converting client to window. It is supposed to know about this. It is supposed to be doing that conversion. But this one is using the wrong size. It's way too big also. So it is clamping, but it's clamping. Some code in here somewhere is, where does it clamp? Here's where it clamps. It's using back buffer size. X-form is using it as how it decides the canvas coordinates, just glass width, glass height, which is the back buffer. And that is w-center, which is the back buffer. So these should be the right thing. But c should be the canvas. w should be the window. This should be the window. c should be canvas and w should be window. So clearly, back buffer.side or opengl.backbuffer. So that was just how it was before. No, it's not exactly how it was before. Oh, I've checked it in. I checked into some of these changes, I think. Clean this up a little bit. That's cvp x flat arrow api becomes api. cvp underscore x flat dot api. All right, so this is the wrong one. OK, that's just not zooming at all. And that's great. Yeah, that's being drawn before I do the magnifying instead of after. So that's what w should have meant, but it's apparently not what this code was doing. So it seems like if you want to clamp, you want to clamp the magnifying glass in window space, and then you want to recompute c center and c y based on that. Right, so the problem is this mouse position is in window coordinates. So it's never correct to do that. So we still have to do this in window size, don't why. No, it's not. Oh, well, OK, it's just not zooming. But it is actually, it's down zooming. But yeah, there it's off the edge a little bit, but that's OK, at least to start with. So now why is that down zooming? Because I changed these back to window, and these things were using window instead of c. So wait, x form. Oh, OK, here's the one that's texturing. So this is the coordinates of the window, and this is the coordinates of the canvas. And that one seems correct, but now that's the window that's wrong. So why is the window wrong? Window is not being scaled up enough. So magnify num pixels. OK, so if you specify the number of pixels in window space, then you would use magnify num pixels in window space. And in the scaled space, it would be divided by it, which is what we have. That seems correct. That's also, because it's in the window space, it's just awfully small. But that shouldn't change the zoom. Yeah, it doesn't. So why is this divide here not doing what it's supposed to?  Old code. Right, I changed this. Well, it was never working in the old code, so it doesn't really mean anything to check. What I should check is that I haven't broken the non-zoom version. And I have. It's not zooming anymore. Well, it's that same question of it's four. It might actually be wrong. It might be that that's not 16, that that's only eight or something. OK, so it's zooming up a little bit. Right, so the problem is it's not accounting for the implicit zoom in the difference between the two scales. Why should it have to? Oh, right, it should have to, because so that means if this one was just, let's see if that would be a divide by a larger number, I think that would work. I think this is just the window size. Nope, it's shrinking now. So there is like a factor of two wrong. Well, there's a bunch of divide by twos in there, which is perhaps suspicious. Yeah, these are divide by two, because I wanted to make this code work. And then we use this as offset, which all seems correct. These we use as offset, so they also need to be divide by two. We're using center and half width. OK, so there you go. It's scaling up by a factor of two. All right, so that works even when you're in fat bit mode. So we're done with that. And now, well, this is an interesting thing. If we don't pixelate on the zoom, so this stuff is linear interpolated. But this should be, no, it's also, shouldn't this always go nearest neighbor? It really should, I think. The zoom mode should. So that's a bug as well, probably. Where do we decide that? Blitzjader, we do it in the canvas. We actually want to redo that constantly. Let's go ahead and commit that. We just committed. Oh, yeah, we just made that one fix. So now, this is because I was trying to check some other issue. Oh, right, now we have that screen glitch that I want to fix. So I'm setting some state when I do the magnifying glass. So what state do I set and then not clear? Why do I have that? Oh, that's part of that. It's only inside this that I was running. The only state I'd set is x form. So how could that change any state? I mean, now I just added this state change, but I'm always resetting it. Why is that divide by four? That seems crazy. But I don't even use the color shader for. Oh, for drawn text. Yeah. I see a color being passed into that. We just use jail color. Oh, right, because I determined that even with that compatibility mode, that is still legal. You can still pass in those states. Well, maybe not color. Maybe you have to use an attribute. I need to change that to an arbitrary attribute. So I am setting jail color. And is that somehow affecting the rest of our rendering? Yeah, it probably is. That's not that. So the question is, is that affecting our blit or is that affecting our render? It's not affecting drawing the black things, which I think means the blit can't be being affected. So it must be the renderer. Oh, but the frame time is also... No, because it's being drawn white. You can't really tell. What could do that? Well, we do create our render target. I forgot about that. We do call this create canvas. So we can that change our state, which means we then start blitting. We weren't blitting by fault. Okay, so let's do this. Let's turn this on and see if we just already are muted. Yeah, we are, okay. So there's just some bug in probably the blitter. Blit shader, blit shader, here's what we do. We sample our texture. We don't do anything else. We just sample our texture. So it's hard to see how the blit shader would break. So we created a render target, but our client code, nothing should depend on, this should be being set by the caller. Use programs here, yeah. No, we can't do this because you might have destroyed the context again. Not destroy the context, that's probably smart. What could cause that? I'm not doing it. The thing is that the lightning effect is like averaging with white, but I don't have any code that averages with white. I don't think. It's like turning on fog. I don't have fog, do I? There's no fog. What would do this? What could cause that? Drawing over the whole screen with transparent alpha. Need to get this into a state where I can render docket. I mean, we're rendering to a render target. I never called GL clear RGB. What happens if I clear to black? No, it just definitely gets brighter. Why did it get faster? Where's that? It's just random. Oh yeah, it's faster now. What was making it take 18 before? What would make that happen? When I render to the render buffer, it's always wrong. Is that the RGB? It's that sRGB thing. Why am I enabling frame buffer sRGB? Just blitting through unchanged values, shouldn't it? Why would you want to say that you're rendering sRGB unless the texture is set to sRGB? But I don't think it is. No, nothing sets the texture to sRGB. So you render to the back buffer. Is the Blitz shader doing the conversion itself? I don't think so. I would have noticed it when I was looking at it. No, I remember it just copied through. Our color equals texture. What am I not thinking of? Why is this go darker? Why is that not just a copy? Doesn't make any sense to me. Oh, because I made the texture sRGB. Why did I make the texture sRGB? I don't know. What was I thinking? Why did I want this to not just be a pass through? Okay, well, that was it. But if I make them both sRGB, shouldn't it do the right thing? I don't know why that wasn't working. But I don't know why I was doing that. I mean, there was a whole thing where I was trying to play with the font rendering. And so I was using sRGB rendering or not. And maybe I was trying to make it match that. Okay, I'll double check that that's still fixed. Okay, get it, get it, actually, fix, ring. Now what do I have to do? So I still have to make all the windows stuff. Get proc address. I have this xplot state. I might want to start passing it around. Like I did for this, I passed it into this. That's the one user function. Okay, so this function I'm going to get rid of. And it's already in the right place. So that's all I have to do. I wasn't calling it anywhere. This is dead. These are all internal only right now. These to worry functions should be in out eventually. It's not even used at all right now. I guess we do compute it, yeah. Okay, now it should be resizable. Oh, it was already resizable, that's right. Now it's not resizable because I forgot to negate it. I named it so that it needed to be negated. So the default is resizable. Okay, that works. And I know the affirmative case works because I just accidentally tested it. All right, so we got rid of those functions. Why does it claim to still have those functions? It has a little bit of a static. All right, I didn't actually get rid of them. How long is this? 3700, so it's still about the same length. Maybe that's enough. So what is there still to do? Some things need to be output. I need to find out what jail version we got. Oh, we do here. And while we're here, I might as well do it then. Jail.verdm, all right. So now we output that. We already documented it's being get out. What else is there? I don't know. Still have to do gamepad and sound. Clean up the ordering here. The win main, the init. Let's see what's called from win main. Win main does some of these load libraries, parses command line and calls main. That's all reasonable. And then init, all right, the create window stuff. The stuff that's inside create, wm create. I want to move after the show window, we do init gl. So it needs to go here. I don't know, what's a good user facing description for that failure? I don't know what causes that failure. Infinite loop. This is that thing I was saying about the event pumping. I don't know, do you have to pump your events once after the show window or something like that? You just call show window and then immediately gets the device context returns and then down here he does open gl initialize. So how does that, how does that work? And he starts creating a special format descriptor. So why do I get in a busy loop here? It's just something went wrong. So it didn't, something isn't getting set now. He returns zero. Do I return zero for my window proc? He returns result. My God, what is going on with this brace formatting? Oh, that's his, how he does switches. Okay. He returns zero. Am I returning negative one by default or something? No, I'm returning zero. Am I passing my WM input through? Yeah, I am. Oh, I'm trying to read this on WM size. Where's he just flags it. But he never checks that flag yet. He's just passing that back to the user. So he doesn't do this. Why can I not step across this? Oh, now if I tab away from it, it fixes itself. It's a tab doing this activate code. Am I not calling wiggle make current in the right spot anymore? That would be, what is he called wiggle make current? After he creates the wiggle context, he immediately calls it, which is where I'm doing it. As soon as I create the context, I do it. That's interesting. So I assume dying on that. No, it didn't even get there. What have I changed? How does adding that line break it before it even gets to that line? How did I get that line back? That makes no difference. What am I doing wrong? I tried def window proc regardless of whether you handle the message. WM create is going to def window proc size. So I'm sorry. Size, nope. He doesn't go to default window proc. Yeah, I mean, I'm just imitating him. I default window proc. Oh, I don't want, he got rid of the enter. He got rid of this. Wait, I assume Pear is not here anymore. He doesn't do the, he doesn't set the timer anymore in there. Oh, he just runs a continuous timer now. Is that the thing that the guy said? I closed that. Is that what this guy was saying? I don't know about that. Firing a timer all the time at one millisecond seems kind of grotesque. But I assume he changed it for some reason. Anyway, I don't think this is gonna have anything to do with this particular behavior. But let's see if he's still doing the paint thing. No, he's not even getting, he's not even processing paint messages, but doesn't that break? Don't, if you never process a paint message, doesn't it always do a new paint message? Anyway, this is why I always do that stuff inside WMCreate because then if I try to move it out, everything breaks. Oh, hey, he changed his. Oh, I don't have access to it. scbpxplot. Oh, it's not xplot, it's the win. Okay, so it still seems like that scbwigglemate current is probably what's triggering it. I don't know what's going on there. It's in create window. It's really no x show window. Let me try to init gl and do all the gl stuff. So we pretty much have to do it before that. We got the DC, we computed an RC, it's both non-zero. The init gl is working because we're building our gl pointers and stuff inside that. Even though the rendering isn't rendering. And we're getting to the rendering. Oh, if it breaks without alt-tabbing, it doesn't fix itself. That's only if you go through the alt-tab. Interesting. So we were trying to set it every frame and setting it every frame still didn't work. I have something else in here that I missed. Return zero, return negative one, set cursor. Why do we do the set cursor twice? Seems redundant. I'm just gonna put it back in the WM create because I don't know. I was just doing this for the sake of cleanliness. Oh, maybe it has to happen before show window. Interesting. Well, that's why. But he doesn't create his context until the open gl stuff. Oh, no, that's not the context. That's the RC, the Windows context. Okay. Right, the wiggle create contexts. No, that is, wait. Yeah, he doesn't do that until then. Yeah, he does his show window before it and it works. I have show normal and he has show. Application should dispensify this flag when displaying the window for the first time. So I just followed their rules. So he's calling it with five when I'm calling it with one. All right, so what we were saying is this breaks, we're saying this one breaks. Yep, okay. Now if we see five, no, it's still broken. Who knows? I'm not gonna worry about it. I don't know what's different between what I'm doing and what pair I was doing, but. All right, hooray. So what did I do here? This is, I changed that timer thing as well while I was trying to debug that. I'll leave it that way. Main thing is stop handling WM create. Right, and now he's not doing WM paints anymore. Wish I, which was one of the points of the switch file. Oh, but he, because he's doing the timer all the time now. But I thought there was a thing that if you didn't, it didn't paint. It's what makes this work. No, who knows? We got a begin paint, end paint, we need to kill timer. See if there's any other functions I don't need anymore. Jill, Windows functions I don't need anymore. For stuff that got deleted. You have to put the set capturing, release capture stuff back in. The, I missed it, but the async key state or whatever the get key state, it's somewhere in here and isn't anymore. The mouse events or the keyboard events or somebody. I thought somebody was pulling that key state. What was I just saying? I also saw it was gone. I saw something I forgot. Oh, there's the get key state. Now I see it. All right, so capture, release capture. I wanted to document that. I need to add those back in. I don't think I'm going to get message any more. That was an old hack. Yep, everything else seems legit. And I thought of something else and now I've forgotten it again. Oh, whatever it was, I'll think of it someday. So get rid of WCrate and clean up. All right, I think I'm done. So I'll stick around and chat just a little bit. No, this isn't going online yet. I won't go online until it's a little more fully baked. And I was intending to wait until I got the OpenGL compatibility mode done, but I may not wait for that. This font is so crappy that now I'm tempted to make a new version of Easy Font with a higher res font. So that when I use this framework, the things look nicer. I mean, I could just do it inside this framework and not change Easy Font, but if I'm going to do it, it seems like I might as well change Easy Font too. Whenever there's a good way to pack it, because that's already pretty packed, but it's pretty small. So if I bump the resolution up and use somebody else's bitmap font as a source for it, yeah, it's hard to say. It also gets less efficient because it draws with lots of quads because I don't want to have to upload a texture. I could upload a texture. I have my own shaders already. I could have a shader for text and a texture for the text. You do plan to trap the cursor. Well, you can't actually trap the cursor except when the mouse is down. That's the eternal problem in Windows. It forbids you from, it ignores your attempts to trap the cursor. So you can just hide the cursor. And it's already got the relative mouse movement. I didn't debug that yet. I guess I should print it and make sure it's working. Oh, I did. I did at some point. That might have been when it wasn't working though. Mouse move. Yep, you can see the mouse move going. So it's got the mouse deltas going. And that works even when it's off the screen. And so if you just hid the cursor, that would work. Like here, if I move the cursor to the left edge and I keep moving the cursor left, it still rotates because I'm using the wrong mouse input. So yeah, I've explained this already. I used to do the hack where I keep teleporting it to the center. And that's gross because you can break it. So yeah, I can do that as an optional extra thing to keep you from accidentally moving outside when it's in windowed mode. But sometimes you don't want that. Like you're not in FPS. If you're just a 2D or isometric game with a mouse cursor, you don't necessarily want it trapped in the window. So you'll have to request that. And as I said, it does use the mouse cursor for this magnifying glass. So you definitely want to have the option to keep the mouse free and not teleporting it back to the center so that this stuff works. So it definitely doesn't want to do that by default. But if you're doing FPS style stuff, then you don't normally want the mouse cursor. And so maybe if you hide the mouse cursor, it'll be coupled by default. There'll be a mode that when you hide the mouse cursor, it also automatically tries to teleport it to the center. So I'm going to stop the stream and I'll stick around and chat for just a little bit.