• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

Getting started with application development for System 6/7

petteri

Well-known member
Thanks guys! I have one public question right away. If I want to draw single pixels on a 1bit depth area, what is the recommended way? MoveTo+Line(0,0) combo seems to be pretty slow.

 
Last edited by a moderator:

PotatoFi

Well-known member
I would love to see a tutorial on how to get a "Hello World" on System 6/System 7. If anyone ends up putting together a video, or is willing to jump on a Zoom and walk through it, I'd love to watch. My development experience is pretty thin... I've done a few Arduino projects, and would like to understand how much further I'd need to go to start writing basic applications for 68k Macs.

 

petteri

Well-known member
I would love to see a tutorial on how to get a "Hello World" on System 6/System 7. If anyone ends up putting together a video, or is willing to jump on a Zoom and walk through it, I'd love to watch. My development experience is pretty thin... I've done a few Arduino projects, and would like to understand how much further I'd need to go to start writing basic applications for 68k Macs.
I followed this guide: http://www.think-pascal.org/ and after that https://vintageapple.org/macprogramming/pdf/Macintosh_Pascal_Programming_Primer_1990.pdf

Pascal has already given me some head aches :-D  Usually (in modern world) one wouldn't do conditional with single =, as in some programming languages it does assignment inside if clause :sadmac:  Also, it took moment to figure out how to if/else syntax works without curly braces or Python like indentation...

 

Crutch

Well-known member
Thanks guys! I have one public question right away. If I want to draw single pixels on a 1bit depth area, what is the recommended way? MoveTo+Line(0,0) combo seems to be pretty slow.
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 did this from memory so check my math.  I will test it tonight to ensure I got it right!  It also assumes a screen that’s 512 pixels wide:

[SIZE=1.4rem]#define SET_PIXEL(x, y)[/SIZE]

[SIZE=1.4rem]    *(((short *) [/SIZE][SIZE=1.4rem]screenBits.baseAddr) [/SIZE][SIZE=1.4rem]+ ((y) << 5) + ((x) >> 4)) |= (0x8000 >> ((x) & 0x000F))[/SIZE]

Translation:

- grab start of screenBits bitmap, cast as a short* so we can do pointer arithmetic word-by-word

- advance by y<<5 == y*32, where 32 = #words in a 512-pixel row.  This gets us to the start of the right row

- then advance by x/16 to grab the right word in the row

- now we need to apply a bitwise OR to that word to set one of the bits...

- the thing we will OR it with is 0x8000 = 0b100000000000000, right-shifted by the low 4 bits of x (which tell us which bit to use in the word of interest)

For multiple invocations, faster if you put screenBits.baseAddr in a register first of course.  Or do this in an asm{...} and use a BSET instruction rather than the |=.

If you’re on a Mac that might have multiple monitors/varying bit depths, it’s just slightly tricker, you have to get the current gDevice first.

If you’re on a color screen, uncertain of the PixMap width and use rowBytes, be sure to remember the high 3 bits contain flags and should be stripped off.  This one gets me every time.

 
Last edited by a moderator:

Dog Cow

Well-known member
I would love to see a tutorial on how to get a "Hello World" on System 6/System 7. [...] and would like to understand how much further I'd need to go to start writing basic applications for 68k Macs.
I've posted a handful of development tutorials on the Mac 512K Blog. They're in assembly language, and will run on any Mac. Even if you don't end up using assembly language for your project, you can still see the Toolbox calls in action and how they're used.

Check out MacTutor, especially the first 3 volumes. There are "hello world" type application tutorials in several languages, including C.

 

Crutch

Well-known member
(I confirmed the code snippet above is correct, but check your rowBytes on any machine with color QuickDraw ... with my grayscale card, the main device Pixmap on my SE30 has rowBytes = 1024 even in 1 bit mode ... if this doesn’t make sense and you’re not running on a black and white compact, I can post a slower but more general code snippet that will work on any screen)

 

petteri

Well-known member
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?

 

Crutch

Well-known member
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

 
Last edited by a moderator:

Crutch

Well-known member
(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)

 

petteri

Well-known member
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...

 
Last edited by a moderator:

cheesestraws

Well-known member
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*.

 

Crutch

Well-known member
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.

 
Last edited by a moderator:

Crutch

Well-known member
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.)

 
Last edited by a moderator:

techknight

Well-known member
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. 

 
Last edited by a moderator:

cheesestraws

Well-known member
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™.

 
Last edited by a moderator:

techknight

Well-known member
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. 

 
Last edited by a moderator:
Top