Jump to content
petteri

Getting started with application development for System 6/7

Recommended Posts

15 hours ago, Crutch said:

Yeah it’s slow if you’re doing it a lot.

 

If you’re on a compact Mac (no graphics card), write directly to screenBits:  (qd.screenBits in some later compilers)

 

I was filling 200x200px window with random noise and it seemed slow on my beige G3. I was expecting near instant without "scanline". Maybe I should create it offscreen first?

Share this post


Link to post
Share on other sites

Well ... I guess you could do that.  :)  It will still be slow to set up though, you are making Toolbox calls tens of thousands of times.

 

The way to efficiently generate random noise on the screen is to write directly to the screen.  It’s pretty simple once you know where to pull in the screen’s bitmap/pixmap.

 

I tried it this morning.  This generates a 300x300 square of 8-bit grayscale noise on the fly on my SE/30 in under 0.25 seconds.  (I do have an accelerator ... but still, it’s very quick.  In 1-bit mode it would be probably 8x faster and run in the blink of an eye).  I write directly to the screen, one long at a time.  I generate the random longs (r) using a textbook one-line PRNG.  Prior to this code, I set gdh = GetMainDevice() and seeded r with a random constant.  Second screenshot shows the output.

 

To avoid worry about edge cases, I didn’t check whether the bounding rect sides are aligned with longs — you should do this if you might change the size of the rectangle.

 

(and yes, if you really need this to appear instantly, you can use this code to write directly to an offscreen pixmap, then CopyBits that to the screen!)

 

 

61F0BED2-D87B-4574-AEF3-4AB28832DB14.jpeg

C9C13117-8CBD-4E7E-9410-103B73E52E78.jpeg

Edited by Crutch

Share this post


Link to post
Share on other sites

(Semi-related side note:  one of the coolest bits of classic Mac code ever is the “DissBits” assembly routine article in MacTutor vol 1 no 13 that randomly and very quickly dissolves a black & white bitmap onto the screen, one random pixel at a time, using a maximum-length sequence generator to efficiently generate a nonrepeating sequence of random numbers of the required length ... I haven’t tried running it yet because it looks like a pain to type in the code [anyone have the old MacTutor disks??], but it’s definitely a brilliant piece of tight and tricky 68k assembly)

Share this post


Link to post
Share on other sites

Is it possible to prepare sort of a raw bitmap of the noise in the memory and then copy that to a window? Sorry about lack of the correct lingo, just studying GrafPort and BitMaps...

Edited by petteri

Share this post


Link to post
Share on other sites

I mean, it depends what you want.  If you just want to display an image that happens to contain random noise (but the same random noise each time), you could always just store it as a PICT resource and load and display *that*.

Share this post


Link to post
Share on other sites
9 hours ago, petteri said:

Is it possible to prepare sort of a raw bitmap of the noise in the memory and then copy that to a window? Sorry about lack of the correct lingo, just studying GrafPort and BitMaps...

Yes, this is what I was suggesting above.

 

A PixMap is a BitMap that supports >= 2 colors (instead of just black/white).

 

Above, I did:

 

    GDHandle gdh = GetMainDevice();

    PixMapHandle pix = (**gdh).gdPMap;

 

This gets a handle to the main screen's PixMap in pix.

 

Instead, you could allocate an offscreen PixMap, and stick a handle to it in pix.  Then use exactly the same code I wrote above to (quickly!) fill it with random noise.  Then, use the QuickDraw call CopyBits() to transfer it to the screen.

 

However, the code above is fast enough (I'm sure it's imperceptibly fast on your G3) that you probably don't need to bother with that, you can just plot the noise directly on-screen, unless you really need the image to appear crazy fast.

 

Of course you could also just run the noise-generating code once and save the result to disk.  But then you have to mess with saving and grabbing a PICT resource or whatever.

 

Edited by Crutch

Share this post


Link to post
Share on other sites
12 hours ago, Andy said:

Macintosh Garden does! https://macintoshgarden.org/apps/mactech-vol-1-12

 

DissBits fade sounds a lot like the one the Wolfenstein 3D does when you get a game over. There's a nice write up about how it works with some simple sample code here https://fabiensanglard.net/fizzlefade/index.php

Woo thanks!  And yes that Fizzlefade thing is exactly what MacTutor wrote up, 7 years before Wolf3D.  (Your linked site indeed has a better explanation than MacTutor though - thanks for sharing it.)

Edited by Crutch

Share this post


Link to post
Share on other sites

Double pointers always confused me in C, so I have always avoided the use of them.

 

What is it used for in this instance? Just curious. 

Edited by techknight

Share this post


Link to post
Share on other sites
8 hours ago, techknight said:

What is it used for in this instance? Just curious. 

Assuming you're referring to @Crutch's example: In a lot of cases, the toolbox returns pointers to pointers instead of straight pointers. This is so that the memory manager can move memory "underneath" the application if it needs to.  The handle (pointer-to-pointer) points into a table maintained by the memory manager, so it can update things as it moves memory around.  This enables all kinds of useful tricks, but does mean that if you dereference a handle once and store the result, Bad Things may happen.

 

Clarity edit: So, because the application holds a pointer into the table of pointers, the memory manager can move memory around and the application doesn't need to know or be notified of that.  It ought, if the application plays by the rules, Just Work™.

Edited by cheesestraws

Share this post


Link to post
Share on other sites

So the pointer to the pointer is simply just a table of addresses that are managed by the OS? So when getting the address to where your gonna place something, you have to refer to that table, basically? 

 

I see.... Pointers are just locations for system resources basically. 

 

Ive written bare-metal C, so its hard to sometimes fathom how an OS can complicate things sometimes. 

Edited by techknight

Share this post


Link to post
Share on other sites

The pointer-to-pointer is to an entry in that table, yes.  And by doing it this way it stops the application itself having to worry about things like heap fragmentation, because the actual locations of dynamically-allocated things in memory are the memory manager's problem, not the application's.

 

I tried to throw together a diagram that may (or may not) help (more for anyone stumbling across this thread later than you, as you seem to have worked it out):

 

memorymanager.png.776f030157383ee42f6285b35d5b2622.png

 

 

Share this post


Link to post
Share on other sites

That’s right.

 

In classic Mac parlance, a “Handle” is a pointer to an entry in a table of “Master Pointers” managed by the Memory Manager.  As cheesestraws says, this lets the Memory Manager move around the underlying blocks of memory (so-called “relocatable” blocks) or even nuke them (if they’re “purgeable” resources) entirely.  

 

(Edit:)  This last point is particularly nifty, so as an app developer if you’re (say) reading a bunch of data from a huge file, you can store it in a relocatable block (accessed via a Handle) and mark it purgeable.  Then, the Memory Manger is allowed to trash it whenever it needs more space.  Before using it each time, just double check that the Master Pointer hasn’t been set to NULL.  If it has, no big deal, just call your file-reading routine again to restore the data to RAM.  (And you only have to do this check at certain times — unless you call routines on a certain magic list, the Memory Manager guarantees it won’t move anything around or purge anything.)

 

As long as the application plays by the rules (don’t save a copy of the master pointer assuming it won’t change - and check purgeable things to ensure they haven’t been purged before using them!), this is a terrific model.

Edited by Crutch

Share this post


Link to post
Share on other sites

hmm maybe I need to read books on this, but how does the application cope if the memory manager decides if something needs moved? it just moves it halfway in the middle of your loop while your using it? 

 

I guess this stems from my bad idea of defining a new local pointer with the data from the other pointer. That would be bad, I see.... But then if the pointer address is moving around in a loop inside your application, how does the memory manager know not to reset that pointer back to the beginning again, crashing your app? (if it needs to move data)

 

Because it would seem to me if your using a pointer to a pointer you would be incrementing the address thats stored in the pointer table. If Memory manager changes this address to a new location, it screws the loop. 

Edited by techknight

Share this post


Link to post
Share on other sites

You use HLock to lock the handle managing your pointer, so you can't lose access to it. You HUnlock it after. 

 

Your question was spot on, and highlights the cost (small) of using this strategy in memory management. 

 

If I recall correctly, the most frequent use of those pairs of traps I did back 15 years ago was when I was prepping and blitting my offscreen memory block to the video RAM. 

Edited by Mu0n

Share this post


Link to post
Share on other sites
8 hours ago, techknight said:

how does the application cope if the memory manager decides if something needs moved

The memory manager only moves memory when you make a call to allocate a pointer or handle, or when you call a (toolbox) routine which does the same. Memory never gets moved at interrupt time, so it’s not like you can be going through the code and all of a sudden the memory you were using has moved. And like Mu0n said, if you wanna make a call to allocate memory but don’t want something moved, you lock it with HLock and then the memory manager won’t move it.

Edited by ZaneKaminski

Share this post


Link to post
Share on other sites

Addendum to both posts above: the toolbox documentation tells you what functions move memory, and you can't use those in interrupt handlers.  But yes, it's not like it does it at arbitrary times, and if you absolutely need something *not* to move then you can tell the memory manager not to move it.

 

It sounds kind of clumsy to describe, but it actually works really well; it's one of those tiny abstractions that reaps quite a lot of benefits.

Share this post


Link to post
Share on other sites

Ahh see this is all good information. I've never written a mac application before in my life in C so its neat knowing these things. I have wrntten mac apps in Abstracted languages such as RealBASIC. 

 

The only C programming I have done was Bare Metal, and surprisingly enough, was on a 68K. actually, juggling between two 68Ks, with 1 having paged memory access to the RAM of the other. But, thats a cluster**** for another day/time. 

 

Thanks for the tips. :-)

Edited by techknight

Share this post


Link to post
Share on other sites
8 hours ago, techknight said:

The only C programming I have done was Bare Metal, and surprisingly enough, was on a 68K. actually, juggling between two 68Ks, with 1 having paged memory access to the RAM of the other. But, thats a cluster**** for another day/time. 

I'd really like to hear about this sometime in some other thread, if you ever feel like talking about it.  That sounds a bit mad...

Share this post


Link to post
Share on other sites
9 hours ago, cheesestraws said:

I'd really like to hear about this sometime in some other thread, if you ever feel like talking about it.  That sounds a bit mad...

I should. it's just a bit off-topic for this forum so I dont know where I would put it. 

 

I need to have someone more seasoned in C code take a look at my program at some point. It works fine, but im sure there room for improvement to make things faster. When it comes to the 68010 running at 8Mhz, you need to squeeze every ounce of performance you can get out of it. 

 

Edited by techknight

Share this post


Link to post
Share on other sites

 

On 7/26/2020 at 10:52 PM, Mu0n said:

as well as Popfunc, so you can add a leftmost corner pop-up menu to your window editing a source file, allowing you to go directly to any function from a pull-down menu, if you're a barbarian like me and write too many functions in an individual source file sometimes (I'm trying to break the habit) 


Do you have a link for Popfunc?  I can’t find it anywhere.  Indeed Googling “popfunc” “think c” brings up only this one forum post on the whole wide web!  @Mu0n

Share this post


Link to post
Share on other sites
17 hours ago, Crutch said:

 


Do you have a link for Popfunc?  I can’t find it anywhere.  Indeed Googling “popfunc” “think c” brings up only this one forum post on the whole wide web!  @Mu0n

image.png.03dbb399d5583f346dc588d74aaaaa6e.png

 

PopupFuncs is the correct name.

 

I have no recollection where I got it, but I have a vivid memory of having installed it a few weeks/months after I started using THINK C for my millions of little projects back in 2004-5.

 

Perhaps I got it from the hotline server that was up back then, Retromac68k (what a treasure trove, long gone, before I could manually back up it all - I got a good chunk of it though).

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×