Submind YouTube summaries
Thumbnail for 3D scatter plots in x86 asm | SCHIZONE EP-32

3D scatter plots in x86 asm | SCHIZONE EP-32

Watch on YouTube

Video summary

In this episode of the Skid Stone series, the creator demonstrates how to implement 3D scatter plots entirely in x86 assembly language, focusing on practical implementation rather than theoretical concepts. The video introduces three distinct examples that showcase the capabilities of the rendering system: a random point cloud with full interactive support for zooming, panning, and rotating; a dual dataset plot displaying two vertically shifted sine waves to illustrate multiple data sets on a single graph; and a subplot feature allowing multiple independent plots to exist within the same rendering space. Each example highlights how the system handles various visual variables such as marker colors, sizes, and types—including shapes corresponding to PlayStation buttons like triangles, squares, circles, and Xs—while maintaining precise control over axis labels, tick marks, and plot origins. The core of the implementation revolves around a governing data structure that defines all aspects of the plot, including titles, axis labels, color schemes, font sizes, and numerical precision. This structure acts as a blueprint, containing pointers to memory locations where actual data resides, such as arrays for X, Y, and Z coordinates, along with metadata like marker dimensions and types. A key feature discussed is the use of linked lists generated by the `scatter_plot_3D` function, which breaks down the complex plotting task into manageable rendering structures for axes, grid lines, text labels, and data points. The system also supports advanced positioning through origin translations, allowing subplots to be placed anywhere in 3D space relative to their local coordinates, effectively treating each plot as an independent object that can be positioned within a larger scene or environment. Beyond the visual output, the video delves into the architectural efficiency of the assembly code, emphasizing how a complete 3D rendering engine capable of handling mouse input, cursor interaction, and complex data visualization fits into a mere 29-kilobyte static binary. The creator explains the necessity of managing heap memory for dynamic data structures and the importance of calculating string lengths to center text rather than defaulting to left alignment. Furthermore, the code includes robust error handling mechanisms that gracefully manage memory allocation failures by terminating execution if the heap is exhausted. The flexibility of the system allows users to modify plot properties in real-time or at compile time, demonstrating how changing parameters like tick subdivisions or marker colors instantly updates the visualization without requiring a full program restart. Ultimately, the project serves as a testament to what can be achieved with minimal resources and low-level programming techniques, proving that sophisticated graphical applications do not require massive libraries or gigabytes of code. The creator notes that while features like legends are not natively supported due to the complexity of mapping symbols to colors, users can easily implement custom text overlays using existing drawing routines. By keeping the binary bare-bones and avoiding unnecessary dependencies, the assembly program remains highly portable and efficient, capable of rendering high-resolution graphics on a 1920x1080 screen while managing intricate data sets. The episode concludes by encouraging viewers to experiment with the provided structures and macros to further customize their own 3D plotting environments, reinforcing the idea that powerful tools can be built from scratch without relying on bloated frameworks.
Read the full video transcript
hey guys welcome back skid Stone series episode 32 long time no assembly topic today is going to be 3D Scatter Plots very simple straightforward topic not too much Theory to talk about just really the implementation and then obviously the examples so we'll start with those uh we have three examples today the first one is just a random Point Cloud so I can uh run this and you'll see here's a you random Point Cloud you can see you can zoom in and out obviously have the full cursor support you can pan left right um zoom in and out rotate the model so we have X Y and Z coordinates obviously um we have tick marks we have numbers on the the axis as well uh access labels plot label and of course you have those three dimensional location so X Y and Z there's three variables there you also have the marker color that's a variable you also have the marker size see there's some small circles some Big C circles Etc um and then you have one discrete variable which is like the marker type we have all the the PlayStation buttons here Triangle Square Circle and X um we can add more if you want right now we only have four so yeah this is the first example kind of cool um everything is supported rotationally speaking um then we have example B this is similar much similar but uh here you actually have two different data sets and I'm plotting basically a s of XY vertically shifted and you kind of can see here how how cool that looks kind of hard to tell what's going on but yeah so you can see we can plot multiple data sets on the same plot that's what they showing here and then example C this is subplots if you're familiar with like mat lab or others this is a pretty common feature here I've got multiple different plots on the same rendering basically um yellow Aqua magenta orange and we can have these all located somewhere else in space and all the coordinates are basically defined relative to the local origin and we can move that origin around that's the idea so that's kind of the goal today it took me the better part of a month to get this working um and there's not much to show for it outside of these examples but this will help us down the road to uh visually Express data in the future hopefully let's get back to our slides so yeah Sky plots not much to be said for this you can plot data also if you think about it you could actually draw stuff too to the screen um any kind of geometry that you can represent by a point Cloud you can also show in this fashion um and then of course whatever else you want to add you can add I don't think we have support for Legends for example like a little plot Legend like a triangle is this or you know this color is this there's too much variation for that so I was thinking if you wanted a legend you could add it in yourself you know how to put text on the screen you know how to draw lines and stuff so that shouldn't be too hard and then here you can see this is actually like a six-dimensional plot with those five continuous variables and then one discre variable so pretty powerful and here is the implementation so as usual everything is defined with these Thea structures and the idea is let me just show you down here first you basically call this function scatter plot 3D and that takes in that governing scatter plot defining structure does a bunch of logic and generates a series of like a length list of other structures that our rendering system knows how to render so it will sh it will generate like a bunch of line segments for the axis and if you want grid marks it'll make a bunch of line segments for for the grid marks all the right color then if you want to add tick labels it will put text in all those locations um so you'll have like a text Cloud basically as one of those structures in the link list then you have sing for the title and the access labels Etc and then of course you have the actual data in that link list as well so this function returns basically it takes in this defining structure we'll talk about that in a second and it spits out like six or seven smaller rendering structures which are fed by data in this input structure and then what you do is you just basically pass that link list into our rendering routines and it renders as usual so pretty simple implementation there the key details are how do you define the structure and here's just an example of how I did it you could do it whatever way you wanted so here's what I have um here's that governing structure that you pass in to the scatter plot through routine and in this just a bunch of pointers and a bunch of data so first thing you pass in or you put in in the structure is the title so you have a pointer to this title this is all null terminated strings so this is the scatter plot title random Point Cloud um then you have titles for the axis so X Y and Z and of course you could change this and the text on the screen would change right that's the idea it's very general setup for this rendering system so you pass in all those different pieces of text then you pass in a linked list of all the data sets talk about that in a second but that's where all the data comes in the rest of the structure defines just the plot itself so we have an origin translation this is how you would define those subplots you got to think I want this plot to be at0 zero or should it be somewhere off to the side here's where you define that using floating Point numbers so if you want to put it at 777 you change these to 777 obviously um then for the data you can move the origin around so this is for the actual data that you have to plot where should the origin be should it be at 0 0 0 or should it be at 10 10 10 um whatever you want your axis to to cut through basically that's these three quad words here and then you define for your axis the Min and Max so in our case we had -10 to 10 so I've defined that for X for y and for Z but you could change those as well then you can put the title wherever you want and you could even use this to encode something about the legend as well if you remember in our example B I can even pull that up I put you know z = sinx y + - 5 so I didn't have to label the ledge you know with with what's going on here you can tell just from the title hey obviously the yellow is the plus five and the blue is the minus5 right that's the idea there but yeah either way those three quad words describe where this text should be in space relative to the origin of the data and so you got to think if your data was you know a lot larger than this like it was Millions this location would be in the millions right if your plot wasn't from from to 10 but from like 10 million to positive 10 million this point would also be a very large Point okay going back what's next we then have the colors so you see here if you recall from before we have these four bytes the first bite is not really used the high bite there and then the rest is just RGB and so you can see here the x axis is red the Y AIS is G or green and the z-axis is blue and then your color here for the title in this case is white RGB of Maximum value is white that's how that works and then of course if you look at this example um the text and the the tick labels assume the color of the axis that's a pretty good assumption I think if you want to do something else feel free to add more elements in that structure and uh handle them separately up to you what else do we got we have number of tick marks these are major ticks and there also minor ticks and so you can see here number of subdivisions per X Y and Z tick this is how many times you want to divide between ticks that you're actually labeling so essentially you know when I say five ticks -10 5 0 5 and 10 those are five major ticks and then you can see here in between that we have some minor ticks so there's two subdivisions that's what those uh those byes were defining in fact um we could change that number maybe we will in a second just to show you how this can be changed uh in real time or I should say at the at compile time or I guess at run time I don't know depending uh then we have number of digits you want to display in the floating Point numbers you saw before all those numbers had I believe three digits I guess 10 we always for the for the powers of 10 we always have one extra that's just the way it works but uh for everything else you can see we have three sig figs essentially that's what this is defining here these three bytes and then we have the font size for the text rendering this is actually font scaling we have an 8 bit font if you recall so in this case our title is 4 * 8 pixels 32 pixels in like I think it's height I guess um or is it width I don't remember maybe it's both and then it's three times scaling so 24 pixels for the axis labels and then 2 * 8 or 16 for the take labels what else here comes something weird um if you think about it how are you going to offset those tick labels and even the axis labels from the axis so if you look here like this this five right here it's not on the axis it's off to the side right and this x is off to the other side and then on the y axis you know Y is up and down why why is the the font why is the text above the axis and then why below why isn't it collocated right Etc look at the Z the Z you have hard to see I guess but um you have like numbers on the side Etc so that's all captured by oops by this guy here these offsets so the X tick labels are offset in the y direction the Y tick labels are in the Z Direction and the Z ticks are in the X Direction so it's kind of like a a triangle there of their offsets and that looked pretty good if you want to change that go ahead and change it it's not a huge thing to change um just change the way these numbers are interpreted then we have a couple of other things so this is weird this is how thick The Strokes should be so if you if you see like the thickness of these this is like a two pixel thickness essentially the line is two pixels thick wherever you see it I believe um that's what it's supposed to be at least and uh here you can change that number and then uh you have a couple bytes here for how big each of those ticks should be as a fraction of 255 so the max value for a bite across the direction so the idea is here um if you put 255 those ticks would extend the entire length so here in this case the X ticks are going in the y direction and going in the y direction five out of 255 that's the fraction that this red is over this green um and if you make it one or make it 255 so the ratio is one this tick will be the entire length there of the I guess the y direction Y axis the XY plane would be filled with these red streaks left to right maybe we'll try that out in a second and then lastly what do we have we have some Flags here if you want to turn on the title The X labels the ticks Etc you can set these flags here um these bits for this flag bite I always like to have a flag bite it's nice to have down the line to be able to turn things on and off just with bits here in this case everything is on what's next now here comes the actual data sets so if you recall our 32nd offset quad word here this is the scatter data this is the linked list of actual data that you want to render to the screen and this is what that points do here and what are you passing in well first this is a link list so if you have multiple data sets for example in this example that I just showed you there's two data sets that we're plotting one yellow one and one cyan one or whatever and so for this we would have a a nonzero number here but if it's only one you always have the link list end with a null pointer in this slot so that's the idea there then I have a slot here down the line if you did want to have a legend and wanted to track data set like what their name is this is like you know this data has this name Etc you can use this to identify where that is currently I'm not using that quad word but if you wanted to use it for whatever you want it's there for you and then Here Comes data so you can see I have a quad word for the X Y and Z so basically this points to a chunk of memory like this um in which you're storing all the X data points y points and Z points then you also have arrays in memory it's going to either be here in the binary or on the Heap up to you just for the sake of Simplicity here I put it here in memory so you can see um and then you have it for the marker colors in this case you pass in like things like this ZX FF you know FF A5 00 that would be orange right if you pass that in for one of these l words and then marker sizes this is a value just characterizing how big your data points should be like the characteristic size of a circle is the diameter I think and then for the triangle it's like the side length Etc so you pass that in here this is like pixels of characteristic size and then marker type we have 1 through four um it looks like I didn't write down what they were but one of them means Circle one of them means square one means triangle one means X if you want to add a plus you want to add a cross symbol whatever feel free um to do that no big deal okay that's how that works so basically you have quadwords pointing to all those places in memory either on the Heap or whatever you have it um to to describe all the data that you want to have plotted on the screen now I also pass in this stride length I always have this kind of thing in my data structures just because what if you like this assumes that all of those quad words so let's say you x coordinates were like 2 3 4 they're all adjacent in memory what if they're not and why this matters is because what if you had like arrays of something else like what if this was like an array of some of things in your house and it was like multiple things about that stuff like it had its location obviously X Y and Z but then also had hey this is the color of my chair this is the um the floor of my house the chairs on this is you know the the material code five means wood four means plastic Etc right so you have an array of just structures in general well what you could do is for this stride length you could pass in the size of each structure you'd point to the first one and then all of a sudden you could pull out of that array of structures all the x coordinates all the Y coordinates all the Z coordinates all the material codes all the colors whatever else you want to pull out you can pull that out even if the data is not adjacent in memory that's kind of a nice feature to have so I've wasted a couple of words of memory here to define those offsets so this is a sh Lim of zero because the data is touching if you had 100 bytes of garbage in between you'd put 100 in this slot here that's the idea okay what next um that covers most of the structure here all the way down to this then number of elements obviously we have 101 elements so 101 here now here's the thing if so I assume for a data structure like this for like scatter plot you want to have X Y and Z coordinates that's the whole idea of a 3D scatter plot now if you don't want to make color a variable for example in this color is not a variable necessarily nor is the marker type nor the marker size they are constants so I'm not going to waste memory describing you know a thousand of the same color a thousand of the same marker type thousand of the same marker size I'm just going to let me pull it up again Define a default value that's the idea behind this so here's the default color assuming you pass in zero for this this or this it automatically assumes these defaults so here I want everything to be red basically that's what this is saying this is I want everything to be a I don't know whatever it would be um you know a five pixel whatever and then here this is the wrong value obviously it has to be between 1 and four but let's say this meant X right everything that would not be defined here is now defined by this overarching default value so that's how that works and then of course you have the things which you're pointing to in that structure so these things are all pointing somewhere in memory either on the Heap or somewhere here that's the idea so it's pretty straightforward I don't have any Flags here I pointed out here um you could down the down the line add a flag for should this be a a legend should this be um some kind of opacity thing turn it on and off like you could add flags for all the data here if you'd like not currently implemented but you could if you'd like I always like to save a bite for this kind of stuff stuff it's very useful to have a an easy on andof switch for certain features in your structure like that in my experience and then the usage so I touched on this before but just to go through it once again um this is the bulk of this entire example episode this scatter plot 3D function again it takes in basically a pointer to this structure here so you define all this in memory you pass in this address in RDI you call this function as you can see here you need the Heap for this so I have to initialize that first um and then it will spit out in Rax a linked list of everything that's on the screen so in this case it will spit out a rendering structure for all the axes so a red line from here to here green line from here to here blue line from here to here so one structure for all that then that that will point to the next structure let's say it's going to be all these tick marks so you have a bunch of blue dash lines there red Dash lines there green Dash lines there so that's another rendering data structure that's being plotted to the screen then that points to let's say the title the title is now uh a point on the screen you pass that in this car carries the point to the text the font size Etc so there's one structure for that then that points to let's say the axis label so X Y and Z structure to characterize those that points to a structure for all the marks so -10 through 10 all the different axes right and then that points to a structure that characterizes this data set one up on top so all these little Yow circles are rendered as one entity one point cloud and then you have this would be the last structure here pointed to a point Cloud for all those aqua colored x's and then that link list is returns out of this function so how does that look basically the very first element that will probably be the axis line segments gets dumped in Rax and return to you so basically here in Rax you have uh the address of those of the first of those whatever 5 six seven um rendered structure in memory then you have our usual rendering routine only difference here is that now you're passing in you can see RX is now passed into what I'm actually drawing RSI is what we're actually drawing and that's how that works so yeah that's pretty much it I will now go through just the basics of the implementation really quickly here not too interesting you can stop watching right now so let's go to example a just to see how this works um so in this case we have a lot going on so we have our frame buffer that video memory we need to have in our Heap we also have a depth buffer that's like 8 Meg or something of of space there as well so you have to have quite a bit of Heap not only for the structures that we're talking about and data that we're talking about you know but you also have to have space for the video memory that we also use our own Heap to do so that has to be large enough to accommodate all your numbers um and then here are the include so those random Point clouds they actually are random Point clouds it's not real data it's randomly created so we have a couple of includes here for generating random float arrays in arrays and misc case color arrays or um or like the size of the markers Etc so that's uh these three functions here and then here's our scatter plot 3D function that does most of the heavy lifting in this episode we have our usual cross cursor function here nothing special about that now the first chunk of code here you see this is actually generating those random arrays so we randomly create between 10 and 10 a bunch of X chords y chords and Z chords then we create a bunch of marker types between 1 and four and we create a bunch of marker sizes between 1 and 10 and we create a bunch of uh colors between zero and white or I guess between black and white um so yeah that's how that works and then we have defined in memory here a structure that I described before so basically we have our title we have our axis labels this structure here the plots at 0 0 0 the axis is 10 to 10 the colors are RGB let's change them let's make the xaxis is this yellow um let's make the font or the the title let's make that orange just to show you you can do this let's change the number of X ticks from 5 to 10 subdivisions from 2 to three in X Direction let's um let's make the Y tix larger how much larger and uh let's just run this I don't know will this work hopefully not let's see there you go we've done something weird now um we have a bunch of weird yellow X numbers because we changed that from a nice number to a weird number our title is now Orange um the Y markers are really ugly and Tall uh yeah kind of cringe there but yeah you can see how we can change everything about this plot whenever we want so that's kind of cool and actually you could change this while it's running um as long as you recall that scatter plot thing you could update this in real time so yeah that would be cool uh kind of how about example B what's different about this one so this one if you recall that was the The sinos soidal Wave thing um two different point set so this is just pretty much um the same thing take a look at how that how that looks so the only difference here is that we have to in this case I'm using the Heap for the data so all the X chords are on the Heap same with Y and Z um interesting thing is those two point clouds share the same X and Y data like the same sets of X and Y points are valid for both of those IDs just the Z has to be different so in this case I have a common x coordinates array Y coordinates array and I have a different Z coordinates so I have Z chords one and Z chords 2 and those get populated here by uh these Loops basically just fills in it basically computes s of XY plus orus 5 that's how that works and it rers of the screen the difference here is that now you have two different Thea set structure so for example in the first example remember this was the governing data structure we had a pointer here for the scatter plot data so you had one point Cloud basically you wanted to draw on the screen that worked in this case I want to have two different point clouds so the first data structure the first point cloud is a link list that points to the second one and the second one points to zero that's how that works so in that way you basically have two different data sets on the same plot um and then you can see here all this N Stuff I've basically pulled out in a macro the number of discretization points in the XY I guess X and Y directions and we could change that right now it's 101 we can drop that down so let's just say 11 run this again you can see it will regenerate hopefully now you can't really see the waves as much but uh yeah the whole plot still works so cool stuff St you can now have multiple data sets on the same plot very cool and then of course last example was 32c um I have to use pseudo for this in case you're wondering because it uses the framew for device and anoun device so we have to have access to those things here was multiple different point clouds on each has its own access system basically so yellow has its own Aqua magenta orange all have their own individual axis systems and the data is located relative to its local origin that's a cool thing there so I could have data and I could put it on the corner of the screen always at this point in space and so basically this is literally just an object in space everything you see here is just an entity in space a linked list of entities in space um and that's kind of cool very useful actually because now you can you can have a 3D model over here you could have something else over here you can have a scene over here as long as it has its own position in space you can put this plot anywhere you want in space you can put this in your house you know what I mean if you had a house model this could be on your table Etc so it's kind of cool that you can do that um in this setup so how does this one work let's take a look much the same of course this one might have um more things to render obviously because you have four different plots and so in this case um we're actually cheating here we here the same data for all of the different plots cuz you can't really tell um cuz it's so small but um we copied the same data for each individual plot and then you can see here we call this scatter plot 3D function four times so each call generates a link list of of um I spelled scatter plot wrong let's change that really quick so basically this first call defines everything about the top left um AIS system and point Cloud second call the top right third call bottom left fourth call bottom right and then we just um attach them all together so we have the seven whatever element link list for the top left and we just dump the top right one after it or whatever I don't know the order I forgot the order but you can see we just attached those link lists together have a function here that does that just here um found the end of the link list and then it just glues it to the end that's how that works and then we do Define this in memory so you can see they set structure for the first plot the second plot the third plot and the fourth plot and each one has its own color in this case this is R and B this is the magenta one this one is the orange one looks like ff5 and so yeah that's how that one works so again all of those differents are on the screen in different locations oh and how did that work sorry I forgot to mentioned um the important thing on this one you can see here for each plot I actually filled out those three quadword here where it says plot origin X translation this is hey where should the plot actually be in space should it be at 0 0 no in this case it should be at 0 - 20 - 20 so this plot is now shifted to the bottom whatever that happens to be in space of the screen I think bottom left so that's how that works and uh that's the gist now I will go very quickly and very top level through the scatter pla function so you can kind of get a feel of how much went into this particular episode um lib iio frame buffer parallel scatter plot 3D and a lot of the includes I had to do so a lot went on here so the first thing that went on the text rendering that we have that was always left align if you do recall that I added something that basically computes the length of a string and and you can Center or write a line or left Al line deliberately your text so all the text is actually Center Aline that's the first thing I want to point out um then so much stuff so we have to be able to print to memory so we're able to print to the screen for how many months like a year over now right um but to the to to memory is important because all of those 10 10.0 5.0 floats they're in memory and they're they can change I'm not I'm not typing that out beforehand and ending with a zero byte that's has to be made by the program and so we have to be able to print Floats or whatever to memory and so this print buffer flush memory basically dumps the print buffer to a memory location which it seems very simple and it is but it's very important that this program is working um so that's that and of course this is all what's going on so you can see how many how long this file is this is I guess a thousand lines of assembly code to handle all the different stuff that could happen just as far as parsing that input structure is concerned there's more logic that has to go in for the actual point clouds and for the text rendering and for the line thickness and all that different stuff that was also done behind the scenes for this episode I'm not going to talk about it too much it's very simple in nature but uh let's go through what's going on here so first things first I always put a sample of the structure so if you ever want to write software with the skit Zone code base you can just snag this structure and change the numbers that's how that works copy and paste um the first thing it does is it checks for if you well first is FL the print buffer then it goes through creates the axis structure then I assume it creates the uh the grid mark marks yeah the grid points um then it creates the actual text Cloud for the for the grids um yeah that's what it's doing there now it does the tick labels for the title x y and the Z Direction um and then you can see here the Heap is used a lot for this so a lot of these calls to Heap Outlook and if it fails if we're out of memory every single time it just jumps to die which is just some end I guess it's down here somewhere probably probably should put like an air handling thing but I hate that so yeah it just returns when you when it when it fails it just returns out but uh you could change it if you want down the line to process an error down here if you didn't have a space on your HEAP Etc so yeah then it does the title and the X Y and Z labels and then lastly it does the actual scatter plot data and it Loops through um potentially you know multiple data sets that you want to plot on the same plot so there's a loop here that it goes through so very simple and then of course every single time it checks that flag bite to see hey that I actually even want to put uh zext or not if not just skip so there's the processing there to handle hey should this be active or should this be deactivated Etc so that's that um I don't think I will say much more about this I just want to say that you know this entire well this one's a bad example now I Chang the number let me quickly change that back um let's go back to to was it 101 so this plotting system this is just a single plot right we can do multiple of these but I want to show you like how big do you think this is going to be in memory is it going to be a huge file the binary for this this binary is 29k and a lot of that is just data structures that you don't even need to have defin you can define those um programmatically if you'd like but that's insanely small is it not 29 kilobytes for this entire 3D rendering like engine basically um for a 1920 by 1080 screen to handle all the different types of scatter plot data handle a cursor hand your mouse input you know all that stuff that's so much that goes on in 29k and we we could go way smaller I didn't even try to code golf this you could you can get way way smaller than this if you really wanted to I'm just showing that you don't need and this is a static binary too there's no other things being linked and that's really why it's so small is cuz only what's being used is being included here nothing else and it's not like align there's no like special chunks here alignment whatever it's very very like Bare Bones so I'm just saying you don't need a whole bunch of crap to do interesting things like this like this didn't require you know 17 you know gigabytes of trash this didn't require you know 100 megabytes of trash didn't require even 1 Megabyte it's 29 kilobytes so that's cool in my opinion so with that I'll end the video thanks for watching um I hope you enjoyed if not I'll see you in the next one see you