[net.micro.amiga] gfxmem.c - graphical memory usage for your amiga

louie@trantor.UMD.EDU (10/28/85)

From: Louis A. Mamakos <louie@trantor.UMD.EDU>

Here's a program that I hacked together today to figure out how some of the
graphics primitives work.  It creates a window, and plots a bar graph in it
showing how much memory is free and how much is in use.  If you have so called
FAST memory external, then it's size is displayed too.  As you resize the
window, the bar graphs are rescaled.  This program shows you how to create
a window, and how to use the RectFill() function.  You'll also see how to
handle some of the Intuition messages about your window.  I wasn't able to
make the timer.device thingy work, so there's a bit of a kludge in there
to use AmigaDOS Delay() subroutine.  Oh well, it just a day's hack anyway.
The hack to find how much memory is in the system is from Amiga's AVAIL
program.  I don't clain to know how it works;  it's methods certainly
aren't documented.  Enjoy.


------------------------------- Feed this to your C compiler -----------------
/*
 *  gfxmem.c - display memory used graphically.  This program is a freebie; 
 *  give it to anyone you want, just don't sell it.  If you do, the software
 *  police will be out to get YOU! 
 *
 *  Copyright (C) 1985,  Louis A. Mamakos
 */

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/exec.h>
#include <exec/execbase.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <devices/timer.h>
#include <hardware/blit.h>
#include <graphics/copper.h>
#include <graphics/regions.h>
#include <graphics/rastport.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/gels.h>
#include <intuition/intuition.h>

extern struct ExecBase *SysBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct MsgPort *timerport, *CreatePort();
struct timerequest timereq;
struct NewWindow NewWindow = {
   10, 10, 400, 50,           /* sizes */
   0, 1,                      /* pens */
   CLOSEWINDOW | SIZEVERIFY | NEWSIZE | REFRESHWINDOW,/* IDCMP flags */
   WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | WINDOWSIZING | SIMPLE_REFRESH,
   NULL, NULL,                /*gadget, checkmark */
   "GfxMem",                  /* title */
   NULL, NULL,                /* screen, bitmap */
   100, 30, 640, 60,          /* min and max sizing */
   WBENCHSCREEN               /* on the workbench screen */
};

ULONG   AvailMem ();
ULONG   ChipMax, FastMax, ChipFree, FastFree;
ULONG   ChipLargest, FastLargest;
int   dont_draw;

/*
 *  maxsize -- determine the total maximum size for all regions
 *   of the given type.  This code must be executed while
 *   FORBIDDEN (it accesses shared system structures).
 */
ULONG
maxsize (t)
    unsigned long t;
{
    /* THIS CODE MUST ALWAYS BE CALLED WHILE FORBIDDEN */
    ULONG size = 0;
    struct MemHeader *mem;
    struct ExecBase *eb = SysBase;

    for (mem = (struct MemHeader *) eb -> MemList.lh_Head;
                        mem -> mh_Node.ln_Succ; mem = mem -> mh_Node.ln_Succ)
       if (mem -> mh_Attributes & t)
          size += ((ULONG) mem -> mh_Upper - (ULONG) mem -> mh_Lower);
    return size;
}

getsizes()
{
   if (ChipMax == 0) {  /* only do this once */
      Forbid ();
      ChipMax = maxsize (MEMF_CHIP);
      FastMax = maxsize (MEMF_FAST);
      Permit();
   }
   ChipFree = AvailMem (MEMF_CHIP);
   ChipLargest = AvailMem (MEMF_CHIP | MEMF_LARGEST);
   FastFree = AvailMem (MEMF_FAST);
   FastLargest = AvailMem (MEMF_FAST | MEMF_LARGEST);
}

starttimer()
{
   timereq.tr_time.tv_secs = 1;
   timereq.tr_time.tv_micro = 0;
   timereq.tr_node.io_Command = TR_ADDREQUEST;
   timereq.tr_node.io_Flags = 0;
   timereq.tr_node.io_Error = 0;
   DoIO((char *) &timereq.tr_node);
}

/*
 *  Main function.  Call intution to create a new window for us on the
 *  screen.  Go from there.
 */
main(argc, argv)
   int argc;
   char **argv;
{
   struct Window *w;
   struct IntuiMessage *msg, *GetMsg();
   struct MsgPort *timerport, *CreatePort();
   static struct timerequest timereq;

   timerport = NULL;
   IntuitionBase = (struct IntuitionBase *)
                   OpenLibrary("intuition.library", 0);
   if (IntuitionBase == NULL)
      exit(1);
   GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0);
   if (GfxBase == NULL) {
      CloseLibrary(IntuitionBase);
      exit(2);
   }

   if ((w = (struct Window *) OpenWindow(&NewWindow)) == NULL) {
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      exit(3);
   }
   if ((timerport = CreatePort("Timer Port", 0)) == NULL) {
      CloseWindow(w);
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      exit(5);
   }
   timereq.tr_node.io_Message.mn_ReplyPort = timerport;
   timereq.tr_node.io_Message.mn_Length = sizeof (timereq);
   timereq.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
   timereq.tr_node.io_Message.mn_Node.ln_Pri = 0;
   timereq.tr_node.io_Message.mn_Node.ln_Succ = NULL;
   timereq.tr_node.io_Message.mn_Node.ln_Pred = NULL;
   timereq.tr_node.io_Error = 0;
   timereq.tr_node.io_Flags = 0;

   if (OpenDevice(TIMERNAME, UNIT_VBLANK, (char *) &timereq, 0) != 0) {
      DeletePort(timerport);
      CloseWindow(w);
      CloseLibrary(GfxBase);
      CloseLibrary(IntuitionBase);
      exit(4);
   }

   redraw(w, TRUE);
   /* starttimer();  */
   for(;;) {
#ifdef   notdef
   Wait((1 << w->UserPort->mp_SigBit) |
           (1 << timerport->mp_SigBit));
#endif
/*
 *  Next two lines are a kludge;  if I can figure out how to make the timer
 *  device work, than that's the right way to do it.  Oh well...
 */
      Delay(25);
      redraw(w, FALSE);
      while (msg = GetMsg(w->UserPort)) {
         switch (msg->Class) {
         case CLOSEWINDOW:
            ReplyMsg(msg);
            CloseDevice(&timereq);
            DeletePort(timerport);
            CloseWindow(w);
            CloseLibrary(GfxBase);
            CloseLibrary(IntuitionBase);
            exit(0);

         case REFRESHWINDOW:
            BeginRefresh(w);
            dont_draw = 0;
            redraw(w, TRUE);
            EndRefresh(w, TRUE);

         case NEWSIZE:
            dont_draw = 0;
            redraw(w, FALSE);
            break;

         case SIZEVERIFY:
            dont_draw = 1;
            break;
         }
         ReplyMsg(msg);
      } /* while */
      if (GetMsg(timerport)) {
         redraw(w, FALSE);
         starttimer();
      }
   } /* for */
}

#define TOP w->BorderTop
#define BOTTOM w->Height - w->BorderBottom
#define LEFT w->BorderLeft
#define RIGHT w->Width - w->BorderRight
#define GUTTER 3        /* pixels of veritical spacing between bars */

/*
 *  Redraw all of the stuff in the window.
 */
redraw(w, refresh)
   struct Window *w;
   int refresh;
{
   register struct RastPort *rp = w->RPort;
   register short x_min, y_min, x_max, y_max;
   static short AvailWidth, AvailHeight, HorizSpace, Thickness, Scale;

   if (dont_draw)
      return 0;
   getsizes();
   if (refresh) {
      SetAPen(rp, 2);
      SetBPen(rp, 2);
      SetOPen(rp, 2);
      RectFill(rp, LEFT, TOP, RIGHT, BOTTOM);
      /*  recalculate the spacing paramters for this sized window */
      AvailWidth = w->Width - w->BorderRight - w->BorderLeft;
      AvailHeight = w->Height - w->BorderTop - w->BorderBottom;
      HorizSpace = AvailWidth/20; /* use 5% of available space as margin */
      AvailWidth -= HorizSpace * 2;
      Thickness = (AvailHeight - GUTTER*3) / 2;
      if (ChipMax > FastMax)
         Scale = ChipMax/AvailWidth;
      else
         Scale = FastMax/AvailWidth;
   }
   SetAPen(rp, 3);
   SetOPen(rp, 1);
   SetBPen(rp, 2);
   x_min = HorizSpace;
   y_min = TOP + GUTTER;
   x_max = x_min + (ChipMax - ChipFree)/Scale;
   y_max = y_min + Thickness;
   RectFill(rp, x_min, y_min, x_max, y_max);
   x_min = x_max;
   x_max = x_min + ChipFree/Scale;
   SetAPen(rp, 0);
   RectFill(rp, x_min, y_min, x_max, y_max);
   x_min = HorizSpace;
   x_max = x_min + (FastMax - FastFree)/Scale;
   y_min = y_max + GUTTER;
   y_max = y_min + Thickness;
   SetAPen(rp, 3);
   RectFill(rp, x_min, y_min, x_max, y_max);
   x_min = x_max;
   x_max = x_min + FastFree/Scale;
   SetAPen(rp, 0);
   RectFill(rp, x_min, y_min, x_max, y_max);
}