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); }