ThinkC [Study Group 1] Drawing on the Macintosh

Relating to ThinkC Development

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
On Page 84, where it talks about changing the font:

C:
GetFNum("\pMonaco", &fontNum);

if (fontNum != 0) {
    TextFont(fontNum);
}

I’m noticing that only two fonts work – the system font (Chicago), and the application font (Geneva). Any other number I pass into TextFont() seems to result in Geneva.

Any idea why that’s not working? Is it a System 7 thing? (I’m running System 6).
Did you install those fonts when System 6 was installed? At System install, you can optionally bring a bunch more fonts or keep it light deliberately.
 
  • Like
Reactions: pretzelFTW

pretzelFTW

New Tinkerer
Sep 5, 2022
26
8
3
Did you install those fonts when System 6 was installed? At System install, you can optionally bring a bunch more fonts or keep it light deliberately.
I don’t remember, so that definitely might be the problem.
 

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
On Page 84, where it talks about changing the font:

C:
GetFNum("\pMonaco", &fontNum);

if (fontNum != 0) {
    TextFont(fontNum);
}

By the way you don’t need GetFNum here. The font manager defines constants for all the classic Apple fonts. Just TextFont(monaco) will do. If not available it will indeed fail over to Geneva.
 
Last edited:
  • Like
Reactions: pretzelFTW

pfuentes69

Active Tinkerer
Oct 27, 2021
380
293
63
Switzerland
As for my SE/30 running 7.5.3, the default window almost creates a weird single line that goes from edge of window to center, or is just a small segment to the left edge of the window. If I futz around by resizing the window, moving it and reclicking, I can get a recognizeable shape such as this. It seems to struggle between local and global coordinates, is my guess?

View attachment 8511
Thanks for your tests!

I think I managed to find the issue, which was initially because the variable initialisation was not working as I expected, and I also caught a couple of typos I made. Now I have it quite stable. I'll share all the code later, when it's cleaner.

I'm curious about the issue with the Plus, because I think I was compiling for 68000, but maybe there's some dependency with the System version. I need to dig more into that. When I'm back home I'll move to real hardware to keep with it.
 

pretzelFTW

New Tinkerer
Sep 5, 2022
26
8
3
Well, this is strange. Page 92, at the end of the Randomize function:
C:
return ( (randomNumber * range) / kRandomUpperLimit );


This line crashes with an "Illegal instruction" error for me.

Apparently you can't multiply a long and a short?

This crashes also:
C:
main()
{
   long x = 3;
   short y = 5;
   printf("x * y = %ld", x * y);
}
 

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Well, this is strange. Page 92, at the end of the Randomize function:
C:
return ( (randomNumber * range) / kRandomUpperLimit );


This line crashes with an "Illegal instruction" error for me.

Apparently you can't multiply a long and a short?

This crashes also:
C:
main()
{
   long x = 3;
   short y = 5;
   printf("x * y = %ld", x * y);
}
Try casting the short into a long inside the formula that uses the short.

C:
 x + (long) y
 

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
Apparently you can't multiply a long and a short?

This crashes also:
C:
main()
{
   long x = 3;
   short y = 5;
   printf("x * y = %ld", x * y);
}
You can absolutely multiply a long and a short. No casting is required.

Something fishy is happening there. Would you mind running Source—>Disassemble on this code and posting the result for that small main() function?
 
Last edited:

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Well, this is strange. Page 92, at the end of the Randomize function:
C:
return ( (randomNumber * range) / kRandomUpperLimit );


This line crashes with an "Illegal instruction" error for me.

Apparently you can't multiply a long and a short?

This crashes also:
C:
main()
{
   long x = 3;
   short y = 5;
   printf("x * y = %ld", x * y);
}
I also assumed you added the ANSI library to your project in order to use printf, as well as put #include <stdio.h> at the top (I assume nothing of your experience, I'm just writing about common failpoints and not claiming that you're doing them )
 
  • Like
Reactions: pretzelFTW

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
Yeah but not including ANSI would generate a link error, not an illegal instruction.

Theory: @pretzelFTW you have “generate 68020 code” checked in your project settings dialog but are running on a Plus. So you are getting a MULS.L instruction in your generated code, which is a valid 68020 instruction but not a 68000 instruction. (On a 68000, multiplying by a long requires multiple instructions.). If you want to run on a Plus, ensure you have “generate 68020/68030 code” or similar settings turned off in project settings.
 
  • Like
Reactions: pretzelFTW

pretzelFTW

New Tinkerer
Sep 5, 2022
26
8
3
Yeah but not including ANSI would generate a link error, not an illegal instruction.

Theory: @pretzelFTW you have “generate 68020 code” checked in your project settings dialog but are running on a Plus. So you are getting a MULS.L instruction in your generated code, which is a valid 68020 instruction but not a 68000 instruction. (On a 68000, multiplying by a long requires multiple instructions.). If you want to run on a Plus, ensure you have “generate 68020/68030 code” or similar settings turned off in project settings.
Yep! You called it. That's what it was. I unchecked that box and now it works. Thanks!

I'm rather surprised that's the default for new projects. I imagine there were plenty of Macintosh Plus machines still in use in the early nineties.
 

pfuentes69

Active Tinkerer
Oct 27, 2021
380
293
63
Switzerland
Well... I had some advance... I used the QuickDraw primitives to paint polygons, and used it for my 3d render project.
I have lots of issues related to memory management... I need to see how can I solve it, but with very big models I have crashes. But happy so far.
Screenshot 2022-09-09 at 12.35.18.png

Now I need to learn how to use mouse events and manage the menus. Also how to use the file management dialogs... I'm anxious to keep going with the next chapters.
 

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
I made an offshoot program that goes a bit beyond this QuickDraw chapter with some light event detection and a 1-item File menu. One thing that's immediately apparent is the lack of mouse-over-in-a-region pre-programmed event. There's none, contrary to modern environments/OSes and you have to do it all yourself.

If you're curious, head on over here, complete with video, source code and all the files in case you want to help me solve a few light problems:

1662838959913.png
 

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
I posted in the other thread an easier way to find out if the user mouses over a window (of course, taking action when the user just mouses over a window without clicking would be nonstandard behavior).

WaitNextEvent() also lets you pass in a ‘mouseRgn’ parameter which will toss you back a mouse-moved event if the mouse moves out of it. You could use this to get an event if the mouse leaves the current window, then check where it is at that time. See Inside Mac Volume VI.
 

jenna32bit

New Tinkerer
Aug 19, 2022
13
7
3
United States
Regarding the last of the four exercises. Not sure if I’m missing something here, but I’m getting the same set of lines drawn on repeat. Is that a program limit, or did I skip a line on accident? I tried calling init in the main loop but boy does that make a mess. Maybe that and some cleanup are the way to go.

I was surprised realizing that unlike modern language implementations we have a harder time doing things like abs(). Seeing that <0…*=-1 really surprised me 🤣
 

Attachments

  • 6250698D-2CD3-4615-B1AA-066759C2477F.jpeg
    6250698D-2CD3-4615-B1AA-066759C2477F.jpeg
    1.1 MB · Views: 73

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Regarding the last of the four exercises. Not sure if I’m missing something here, but I’m getting the same set of lines drawn on repeat. Is that a program limit, or did I skip a line on accident? I tried calling init in the main loop but boy does that make a mess. Maybe that and some cleanup are the way to go.

I was surprised realizing that unlike modern language implementations we have a harder time doing things like abs(). Seeing that <0…*=-1 really surprised me 🤣
Can you post the code in a CODE block in a reply here and set its language to C, we'll be able to spot a missing part of the code if it's that.
 

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
I was surprised realizing that unlike modern language implementations we have a harder time doing things like abs(). Seeing that <0…*=-1 really surprised me 🤣
You can of course include math.h (or is it stdlib.h?) and call abs() as long as you have included the ANSI library in your project. Not including/calling abs() is not because it’s difficult, it’s just an optimization to save memory and skip function call overhead.

I would typically just do this

#define ABS(x) ((x) >= 0 ? (x) : -(x))

There is no reason to incur function call overhead just to get an absolute value, and certainly no reason to do a multiply!
 
  • Like
Reactions: jenna32bit

jenna32bit

New Tinkerer
Aug 19, 2022
13
7
3
United States
This is a frigging enormous code block, so I apologize in advance. I formatted a bit differently from the book, but functionally this should match. Not sure if indentation will carry.

C:
#define kNumLines            50 // Can be higher for more linearity!
#define kMoveToFront        (WindowPtr)-1L
#define kRandomUpperLimit    32768
#define kEmptyString        "\p"
#define kEmptyTitle            kEmptyString
#define kVisible            true
#define kNoGoAway            false
#define kNilRefCon            (long)nil

/*** Globals ***/

Rect    gLines[kNumLines];
short    gDeltaTop=3;
short    gDeltaBottom=3;
short    gDeltaLeft=2;
short    gDeltaRight=6;
short    gOldMBarHeight;

/*** Functions ***/

void    ToolBoxInit(void);
void    WindowInit(void);
void    LinesInit(void);
void    MainLoop(void);
void    RandomRect(Rect *rectPtr);
short    Randomize(short range);
void    RecalcLine(short i);
void    DrawLine(short i);

/*** Main ***/

void    main(void)
{
    ToolBoxInit();
    WindowInit();
    LinesInit();
    MainLoop();
}

/*** ToolBoxInit ***/

void    ToolBoxInit(void)
{
    InitGraf(&thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();
}

/*** WindowInit ***/

void    WindowInit(void)
{
    Rect        totalRect;
    Rect        mBarRect;
    RgnHandle    mBarRgn;
    WindowPtr    window;
   
    gOldMBarHeight = MBarHeight;
    MBarHeight = 0;
   
    window = NewWindow(nil, &(screenBits.bounds),
                       kEmptyTitle, kVisible, plainDBox, kMoveToFront,
                       kNoGoAway, kNilRefCon);
   
    SetRect(&mBarRect, screenBits.bounds.left,
            screenBits.bounds.top, screenBits.bounds.right,
            screenBits.bounds.top+gOldMBarHeight);
   
    mBarRgn = NewRgn();
    RectRgn(mBarRgn, &mBarRect);
    UnionRgn(window->visRgn, mBarRgn, window->visRgn);
    DisposeRgn(mBarRgn);
    SetPort(window);
    FillRect(&(window->portRect), black);
    PenMode(patXor);
}

/*** LinesInit ***/

void    LinesInit(void)
{
    short i;
   
    HideCursor();
    GetDateTime((unsigned long *)(&randSeed));
    RandomRect(&(gLines[0]));
    DrawLine(0);
   
    for (i=1; i<kNumLines; i++)
    {
        gLines[i] = gLines[i-1];
        RecalcLine(i);
        DrawLine(i);
    }
}

/*** MainLoop ***/

void    MainLoop(void)
{
    short    i;
   
    while (!Button())
    {
        DrawLine(kNumLines - 1);
        for (i=kNumLines-1; i>0; i--)
            gLines[i] = gLines[i-1];
        RecalcLine(0);
        DrawLine(0);
    }
    MBarHeight = gOldMBarHeight;
}

/*** RandomRect ***/

void    RandomRect(Rect *rectPtr)
{
    WindowPtr    window;
   
    window = FrontWindow();
    rectPtr->left    = Randomize(window->portRect.right - window->portRect.left);
    rectPtr->right    = Randomize(window->portRect.right - window->portRect.left);
    rectPtr->top    = Randomize(window->portRect.bottom - window->portRect.top);
    rectPtr->bottom    = Randomize(window->portRect.bottom - window->portRect.top);
}

/*** Randomize ***/

short    Randomize(short range)
{
    long randomNumber;
    randomNumber = Random();

    if (randomNumber<0)
        randomNumber *= -1;
   
    return((randomNumber * range)/kRandomUpperLimit);
}

/*** RecalcLine ***/

void    RecalcLine(short i)
{
    WindowPtr    window;
    window = FrontWindow();
   
    gLines[i].top += gDeltaTop;
    if ((gLines[i].top < window->portRect.top) ||
        (gLines[i].top > window->portRect.bottom))
    {
        gDeltaTop *= -1;
        gLines[i].top += 2*gDeltaTop;
    }
   
    gLines[i].bottom += gDeltaBottom;
    if ((gLines[i].bottom < window->portRect.top) ||
        (gLines[i].bottom > window->portRect.bottom))
    {
        gDeltaBottom *= -1;
        gLines[i].bottom += 2*gDeltaBottom;
    }

    gLines[i].left += gDeltaBottom;
    if ((gLines[i].left < window->portRect.left) ||
        (gLines[i].left > window->portRect.right))
    {
        gDeltaLeft *= -1;
        gLines[i].left += 2*gDeltaLeft;
    }

    gLines[i].bottom += gDeltaBottom;
    if ((gLines[i].right < window->portRect.left) ||
        (gLines[i].right > window->portRect.right))
    {
        gDeltaRight *= -1;
        gLines[i].right += 2*gDeltaRight;
    }
}

/*** DrawLine ***/

void    DrawLine(short i)
{
    MoveTo(gLines[i].left, gLines[i].top);
    LineTo(gLines[i].right, gLines[i].bottom);
}

Edit: Indentation did not survive
 

pretzelFTW

New Tinkerer
Sep 5, 2022
26
8
3
@jenna32bit Check your RecalcLine() implementation. I had some errors there too and it gave odd results.

C:
gLines[i].left += gDeltaBottom;
…should be
C:
gLines[i].left += gDeltaLeft;

and
C:
gLines[i].right += gDeltaBottom;
…should be
C:
gLines[i].right += gDeltaRight;
 
Last edited:

jenna32bit

New Tinkerer
Aug 19, 2022
13
7
3
United States
Aha, well that fixed the bounding box issues, still seems to redraw the same pattern. My fault for copy/pasting and editing the repetitive parts. Can you blame me?