Hacker Newsnew | past | comments | ask | show | jobs | submit | pducks32's commentslogin

Would someone mind explaining the technical aspect here? I feel with modern compute and OS paradigms I can’t appreciate this. But even now I know that feeling when you crack it and the thrill of getting the imposible to work.

It’s on all of us to keep the history of this field alive and honor the people who made it all possible. So if anyone would nerd out on this, I’d love to be able to remember him that way.

(I did read this https://www.folklore.org/I_Still_Remember_Regions.html but might be not understanding it fully)


There were far fewer abstraction layers than today. Today when your desktop application draws something, it gets drawn into a context (a "buffer") which holds the picture of the whole window. Then the window manager / compositor simply paints all the windows on the screen, one on top of the other, in the correct priority (I'm simplifying a lot, but just to get the idea). So when you are programing your application, you don't care about other applications on the screen; you just draw the contents of your window and that's done.

Back at the time, there wouldn't be enough memory to hold a copy of the full contents all possible windows. In fact, there were actually zero abstraction layers: each application was responsible to draw itself directly into the framebuffer (array of pixels), into its correct position. So how to handle overlapping windows? How could each application draw itself on the screen, but only on the pixels not covered by other windows?

QuickDraw (the graphics API written by Atkinson) contained this data structure called "region" which basically represent a "set of pixels", like a mask. And QuickDraw drawing primitives (eg: text) supported clipping to a region. So each application had a region instance representing all visible pixels of the window at any given time; the application would then clip all its drawing to the region, so that only the visibile pixels would get updated.

But how was the region implemented? Obviously it could have not been a mask of pixels (as in, a bitmask) as it would use too much RAM and would be slow to update. In fact, think that the region datastructure had to be quick at doing also operations like intersections, unions, etc. as the operating system had to update the regions for each window as windows got dragged around by the mouse.

So the region was implemented as a bounding box plus a list of visible horizontal spans (I think, I don't know exactly the details). When you represent a list of spans, a common hack is to use simply a list of coordinates that represent the coordinates at which the "state" switches between "inside the span" to "outside the span". This approach makes it for some nice tricks when doing operations like intersections.

Hope this answers the question. I'm fuzzy on many details so there might be several mistakes in this comment (and I apologize in advance) but the overall answer should be good enough to highlight the differences compared to what computers to today.


It's a good description, but I'm going to add a couple of details since details that are obvious to someone who lived through that era may not be obvious to those who came after.

> Obviously it could have not been a mask of pixels

To be more specific about your explanation of too much memory: many early GUIs were 1 bit-per-pixel, so the bitmask would use the same amount of memory as the window contents.

There was another advantage to the complexity of only drawing regions: the OS could tell the application when a region was exposed, so you only had to redraw a region if it was exposed and needed an update or it was just exposed. Unless you were doing something complex and could justify buffering the results, you were probably re-rendering it. (At least that is my recollections from making a Mandelbrot fractal program for a compact Mac, several decades back.)


And even ignoring memory requirements, an uncompressed bitmap mask would have taken a lot of time to process (especially considering when combining regions where one was not a multiple of 8 pixels shifted with respect to the other. With just the horizontal coordinates of inversions, it takes the same amount of time for a region 8 pixels wide and 800 pixels wide, given the same shape complexity.


> But how was the region implemented?

The source code describes it as "an unpacked array of sorted inversion points". If you can read 68k assembly, here's the implementation of PtInRgn:

https://github.com/historicalsource/supermario/blob/9dd3c4be...


Yeah those are the horizontal spans I was referring to.

It’s a sorted list of X coordinates (left to right). If you group them in couples, they are begin/end intervals of pixels within region (visibles), but it’s actually more useful to manipulate them as a flat array, as I described.

I studied a bit the code and each scanline is prefixed by the Y coordinates, and uses an out of bounds terminator (32767).


It's a bit more than that. The list of X coordinates is cumulative - once an X coordinate has been marked as an inversion, it continues to be treated as an inversion on all Y coordinates below that, not just until the next Y coordinate shows up. (This manifests in the code as D3 never being reset within the NOTRECT loop.) This makes it easier to perform operations like taking the union of two disjoint regions - the sets of points are simply sorted and combined.


Uhm can you better explain that? I don’t get it. D3 doesn’t get reset because it’s guaranteed to be 0 at the beginning of each scanline, and the code needs to go through all “scanline blocks” until it finds the one whose Y contains the one specified as argument. It seems to me that each scanline is still self contained and begins logically at X=0 in the “outside” state?


> D3 doesn’t get reset because it’s guaranteed to be 0 at the beginning of each scanline

There's no such guarantee. The NEXTHOR loop only inverts for points which are to the absolute left of the point being tested ("IS HORIZ <= PT.H ? \\ NO, IGNORE THIS POINT").

Imagine that, for every point, there's a line of inversion that goes all the way down to the bottom of the bounding box. For a typical rectangular region, there's going to be four inversion points - one for each corner of the rectangle. The ones on the bottom cancel out the ones on the top. To add a second disjoint rectangle to the region, you'd simply include its four points as well; so long as the regions don't actually overlap, there's no need to keep track of whether they share any scan lines.


There’s a lot of good advice here, and everyone I know is different about how to overcome executive functioning issues. But one bit I’ll add:

ADHD can be incredibly lonely. Not even in ways you are aware of until you are older. It’s easy to see the places you aren’t like others or adjusted for in school. There are minor imperceptible ways you might be reminded of this and in all likelihood, those closest to you don’t have it—e.g. teachers, parents. And often it’s framed as something to overcome.

So remind your nephew of what makes him different in amazing ways. And take time to value the things he cares about and excels in. I know that’s good advice for any child, but it’s so important when the world is telling you that you aren’t the same.


When I first used Rust, I was using failure and it just made sense to me. And then we got the 2nd (3rd?) wave of error libraries and nothing has ever made simple sense to me since. Never saw this link and it’s wonderful, it’s exactly how I think of errors. Thanks!


In all my undergrad and graduate level Physics, I don't think I ever used the value of R. The answer has nothing to do with the numerical value--that you can google. It has to do with knowing how to solve the problem.

Though having a grasp of the numbers can help with scale and the often forgotten "does that make any reasonable sense" check.


The occlusion would need scans form the phone which I can think of one company that can do it fast, then you need to figure out where in the world the user is if you want to occlude using buildings, etc. I know of one company doing that. Neither are working with Microsoft as far as I know.

(I work for the latter company and we do VPS: the thing you'd need to build the game I assume people will glean from the video but they are totally not releasing.)


One incredible use is actually in network training for things like AR and autonomous driving. You want a slightly fake world and you could easily try out various network approaches using a free fake world found in game engines. Microsoft has something for this but cannot find a link or the name right now.


Recently been working on a rails app and been forced to use nano for editing one a remote server and it's now that I really see the niceness of YAML. I always like YAML with ruby but I think a lot of the great features are subtle and hard to appreciate. Inheritance! What a great idea for a configuration language. Greatly missed in JSON.


Anything you can express in YAML, you can express in JSON. I'm not saying I would choose JSON over YAML for configuration... but it's definitely not lacking in equal flexibility in use for structure.


This is super fantastic. Well written and just the right amount of approachfulness and wit. Sometimes articles about things like this go too far into metaphor and lose the reader. I'd recommment going over

    fn mv_mutable(mut a : MyThing) {}
a little bit as in when you might want to do this and especially

    fn mutable_ref_mutable(mut a : &mut MyThing) {}
as I write a lot fo rust and still never understand how this works or why its useful. Lastly maybe an explainer of conforming to `Copy` and if you should do this because I believe currently the recommendation is conform to it for any type you can and I still have to stop and think how that's more performant. But again really great article, I bookmarked it for reference ;)


> fn mv_mutable(mut a : MyThing) {}

Compared to simply `a: MyThing`, there are two main reasons when you'd want to do this, namely a) when you want to reassign a different value to `a` or b) when you want to make a mutable reference to `a` (i.e. `&mut a`).

> fn mutable_ref_mutable(mut a : &mut MyThing) {}

Since you already have an `&mut MyThing`, reason "b" from above doesn't apply here, generally the only reason you'd need to do this is if you wanted to reassign a different value to `a`. Technically you would also need it if for some reason you needed an `&mut &mut MyThing`, but that isn't likely to be something you need very often.


Exactly.


I’m no airplane expert but I find the trend lines of the industry interesting and one trend has been how fuel prices and long lead times on fuel efficiency has lead to formerly continental planes now flying intercontinental. AirBus has really done this well and airlines love to be able to reuse resources. With the MAX there is a sense that airline execs are spooked by a new plane since it requires a ton of new training and maintenance outfitting. So Boeing, possibly smartly, tried to create what these airlines would pay for (a fuel efficient airplane) that would marketable be super similar to a very popular plane. But this lead to rushing the process and making too many affordances and hiding the differences from airlines and training material for fear of spooking business execs worried about cost.


I love all of Rust’s documentation it has really been great to see as I learn the language. I can pick up a language easy enough but to pick up a language’s specific idioms is really hard without examples and this resource is great for that. One issue I have had though is how often the resource is out-of-date in some sense. Rust 2018 switched how modules were included and I constantly was confused what the difference was until I learned one was just older (by like a month). Also error handling is very confusing for me. I used error-chain first and everything worked but then I heard failure was the way to go yet there are very few resources on using either idiomatically.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: