ThinkC Mixing the text feedback immediacy of ANSI projects and toolbox graphics from MacTraps

Relating to ThinkC Development

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Doing timing benchmarks on graphical operations (DrawPicture, CopyBits, MoveBlock, etc) is stumping me right now.
I don't particularly like converting long values to Str255 and moving about the pen to DrawString all my result information across zillions of tiny Str255 fragments, alternating between regular text and converted-to-text values.

I like using the much simpler printf just to get a quick value on screen. Not to mention, I can query values with scanf far more simply than devoting a whole new dialog or textedit box. This is not for a full-fledged app, just a simple benchmarking tool.

However, the thing I'm not sure about is how an ANSI THINK C project deals with windows. I can't add both libraries to the same default Segment 2 (ANSI and MacTraps) because they're too big together. No problem, I put MacTraps in segment 3. The problem lies in that an ANSI project deals with its own GrafPtr in order to display stuff in the default window it creates under curtains for me. I can use FillRect to get some graphics going inside that window, without having to call my own MacTrap-like usual functions like InitGraf and stuff. That's all fine and dandy and expected.

Things start to turn sour when I try to simply DrawPicture on the given window I get. It doesn't work. I tried several things to circumvent this problem:

-define my own secondary window with or without InitWindows() at the start
-try GetPort SetPort to make both things stay in their lanes (text for the ANSI text output and graphics for my own defined windowptr port)

I get either of these:
-Mac bomb system 3
-freeze at start
-just the ANSI text output and freeze while attempting to return to shell

Is there an elegant way to get the cake and eat it as well?
 

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
The console window is just a window, you should be able to draw anything into it after a simple SetPort(FrontWindow());

You do of course need to call InitGraf() etc first. Can you post a minimal failing example of your code?
 
Last edited:

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
This worked for me?

C:
#include <stdio.h>

void main(void)
{
    InitGraf(&thePort);
    InitFonts();
    InitWindows();
    InitMenus();

    printf("foo\n");

    SetPort(FrontWindow());

    {
        const Rect r = {60, 30, 350, 250};
        const PicHandle pic = GetPicture(-16503);
        DrawPicture(pic, &r);
    }
    
    while (!Button()) ;
}
1689781667744.png
 

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Behavior under System 7 mini-vMac:
PICT won't show but FillRect and printf do
1689784386862.png


Behavior under Finder 4.1 mini-vMac:
System error 3
1689784466673.png


Behavior under System 7.5.3 Basilisk II:
everything works
1689784504545.png




Behavior under a real Mac Plus (system 6.0.8):
1689784670654.png
 

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Project window:
1689784726601.png


Resource:
1689784753300.png


Source code:
Code:
/* Barebones THINK C v6.0 project created by Michael Juneau
 *
 * on July 17th, 2022
 *
 * This is meant to run on real hardware, not emulators. It will do TickCount
 * timing measurements for some graphical operations and display the results in an ANSI
 * text window. In order to get semi-accurate measurements, 1000 copies of the operation is
 * performed and the average per is calculated and displayed.
 *
*/




// Insert your #include list here
#include <stdio.h>


// Insert your #define list here
#define kCloudImgRess    128


// Insert your global variables here


// Insert your function declarations here
void myInitStuff(void);


// Insert your function definitions here


void myInitStuff()
    {
    InitGraf(&qd.thePort); //qd is the quickdraw global, lets you access thePort (viewable area)
    InitFonts(); //Do this to mess with text and fonts
    InitWindows(); //A must if you plan on drawing on controlled window surfaces as opposed to the raw screen
    InitMenus(); //Do this to mess with menus
    TEInit(); //Text Editing (for inputs)
    InitDialogs(nil); //Dialog manager for alerts, dialogs, etc. nil = no return resumeProc
    InitCursor(); //Cursor manager, if you don't do this, you'll be stuck with the waiting cursor (watch icon or more modern ones)
    GetDateTime((unsigned long*)(&qd.randSeed)); //if you ever need random numbers, this will prep it with a unique time related seed that changes every launch
    //MoreMasters(); //useful at the very start, allows to have an additional block of master pointers. avoids fragmentation of memory if called at the start. uncomment if needed.
    FlushEvents(everyEvent,0); //Do this to prevent queued events from messing with your app right at launch.
    }
   


void main()
    {
    Rect r, cloudRect;  
    int i, howMany;
    long firstCount,lastCount, diff, result;
    PicHandle cloudPicH;
    WindowPtr myWinPtr;
   
    //myInitStuff(); //do this at startup
    InitGraf(&thePort);
    InitFonts();
    //InitWindows();
    InitMenus();
   
    printf("test");
    SetPort(FrontWindow());
   
    SetRect(&r,5,5,230,120);
   
    howMany = 200;
    firstCount=TickCount();


    TextSize(10);
    printf("Starting %d rect fills = %lu ticks.\n",howMany, firstCount);
   
    for(i = 0;i< howMany;i++)
        {
        FillRect(&r,ltGray);  
        }
    lastCount=TickCount();
    diff=lastCount-firstCount;
   
    printf("Ending %d rect fills = %lu ticks.\n",howMany, lastCount);
    printf("Tick Diff=  %lu ticks.\n",diff);
   
    result = (long)(16667*diff/(1.0f*howMany));
    printf("microseconds per fill= %lu \n",result);


    cloudPicH = (PicHandle)NewHandle(sizeof(Picture));
    cloudPicH = GetPicture(kCloudImgRess);
   
    HLock((Handle)cloudPicH);
    cloudRect = (*cloudPicH)->picFrame;
    OffsetRect(&cloudRect,300,30);
   
    firstCount=TickCount();
    printf("Starting %d rect fills = %lu draws.\n",howMany, firstCount);


    for(i = 0;i< howMany;i++)
        {
        DrawPicture(cloudPicH,&cloudRect);  
        }
    lastCount=TickCount();
    diff=lastCount-firstCount;
    HUnlock((Handle)cloudPicH);


    printf("Ending %d rect draws = %lu ticks.\n",howMany, lastCount);
    printf("Tick Diff=  %lu ticks.\n",diff);
    result = (long)(16667*diff/(1.0f*howMany));
    printf("microseconds per fill= %lu \n",result);






        FillRect(&r,ltGray);
       
        DrawPicture(cloudPicH,&cloudRect);  
    }
 

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Incredibly strange behavior.
I only see a blank PICT resource under system 6 or earlier.

1689789190340.png


shows up fine in system 7. Shows as 866 bytes, so I doubt it's a colored PICT.
 

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
ok,

launching under System 7.5.3
Opening Superpaint v2
copying from Resedit to superpaint
copying it back to Resedit under PICT id=129

it now properly gets compiled and seen under mini-vMac, but now this (no text. ignore the slightly vertically displaced copy of the pict, that's normal)

1689789616540.png
 

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Mini-vMac: System 4.2 is too ancient for this I guess (my go to small boot disk for small programs usually).

Mini-vMac: System 6.0.3 yields this:
1689790260619.png



edit - and I'm gettting a Mac bomb on my real Plus (memory management error)

SIGH
 
Last edited:

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
You only need to lock a handle if the Memory Manager might be invoked while it is dereferenced (normally because you call a trap listed as possibly moving or purging memory). Just copying the bounds doesn’t move any memory, so no locking is needed.
 

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
Your code works fine for me (Mini vMac, 7.5.5), I again set the resource ID to -16503 which is the MacOS logo in the System file under 7.5.5. I think you are doing almost* everything right. The resource not showing up in ResEdit in System 6 is a bit weird, any chance there is something goofy or corrupt in that particular PICT? Otherwise you should be good, though I would personally call InitWindows() myself.

*except that you shouldn’t call NewHandle before GetPicture. GetPicture automatically allocates memory for the returned picture. Your code has a small memory leak, because the handle returned by NewHandle is just replaced by GetPicture. In general all the Get…() ToolBox calls do your memory allocation for you, you shouldn’t ever need to call NewHandle yourself first.
 

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
Oh, I do see a weird thing.

In the THINK standard library C file console.c, you can see that in the InitConsole() routine, ANSI calls InitGraf() and gives it a random pointer that doesn’t get saved anywhere. The result is that when you call InitGraf, you are setting up a separate set of QuickDraw globals for the same port. It’s kind of weird but probably won’t cause any problems as long as you call your own InitGraf basically right away after InitConsole gets called (which should be at the time of the first printf) and before you do any drawing.

BUT if you wanted to be really rigorous, the “right” answer would be to recompile the ANSI library after having deleted the various Toolbox Init… routines from console.c. Call your new library “ANSIWithoutToolBoxInit” and use it in projects where you want to do your own drawing in the console window, only after calling InitGraf etc yourself of course.

1689800970922.png
 
  • Like
Reactions: eric

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Screenshot 2023-07-21 07-29-43.png


Works on my real machine with a modded ANSI library!
The hardware Plus really didn't like 2 simultaneous GrafPtr despite my earlier attempts to switch back and forth between them.

Do you think these benchmark numbers are realistic?
 

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
Cool, glad that worked! I wonder why THINK didn’t do that from the start.

Yes I think those numbers look reasonable. (And of course you could draw that picture faster by coping it to a bitmap first, but that’s not your point here I gather.)

How do you get these gorgeous screendumps from your hardware plus again? I recall you did something fancy for that, I’m sure you talked about it somewhere. (I recall it‘s not just Cmd-Shift-3.)
 

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
Man, printf works without issue, but scanf...execution blows past it. It must require something that was set up tight in console.c
 
Last edited:

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
THINK’s console innards are incredibly complex and hard to read. I will play around with this too, I agree with your desired use case.
 

Mu0n

Active Tinkerer
Oct 29, 2021
609
560
93
Quebec
www.youtube.com
yeah, check that out under Basilisk II:
1689963930220.png


this is the image I'm using for fullscreen images (source: MidJourney)
1689964494728.png



Benchmarks so far
1689966530579.png



CopyBits vs BlockMove for a fullscreen copy:
1689968179445.png
 
Last edited:

Crutch

Tinkerer
Jul 10, 2022
293
228
43
Chicago
Nice.

Also, great image - does that mean you found out how to get MindJourney to generate 512x342 black and white pixel art? If so, I would love to know how!