rokicki@rocky.STANFORD.EDU (Tomas Rokicki) (04/17/87)
Part 1 of 2, blitlab. Play with the blitter. See the enclosed readme. #! /bin/sh : This is a shar archive. Extract with sh, not csh. echo x - makefile cat > makefile << '7514!Funky!Stuff!' OBJECTS = blitlab.o bits.o initialize.o render.o gadgets.o mem.o parse.o \ math.o doblit.o .c.o: cc -a +istructures.b $*.c as -ZAP $*.asm all: blit blit: $(OBJECTS) ln -o blitlab $(OBJECTS) -lc $(OBJECTS): structures.b structures.b: structures.h cc -a +hstructures.b structures.h delete structures.asm count: wc makefile readme structures.h bits.c blitlab.c initialize.c \ render.c gadgets.c mem.c parse.c math.c doblit.c 7514!Funky!Stuff! echo x - readme cat > readme << '7514!Funky!Stuff!' BlitLab 1.1 17 April 1987 BlitLab is a program which lets you experiment with the blitter to your hearts content, in relative safety. It opens up a workbench window with gadgets for all of the registers of the blitter, and allows you to manipulate individual registers and perform blits on a magnified bitmap. This documentation is sketchy, but it probably won't get much better. This program was written for a blitter presentation at the BADGE meeting of 16 April 1987, and it met with such approval that I decided to make it available over the net. I wrote it for Manx C using 16 bit ints. It should port to Lattice with a minimum of effort. The code itself may turn out to be interesting. I wrote the entire program in two days, but I tried to keep things clean and modular. Any comments on the code, either positive or constructive criticism, is welcome. On to the program. I'm going to describe operation of the program starting in the upper left hand corner and proceeding across and down. I will not describe the operation of the blitter. The large dark area in the upper left is the bit map we are going to play with. It has a width of 96 bits, or 12 bytes, or 6 words. It has a height of 32 rows. Remember these numbers well. You can draw in this area with the mouse and the two gadgets in the upper right. The topmost gadget is the Point/Box gadget. When set to point, you can draw individual pixels on the screen by clicking on the pixels with the select button. When set to box, you can draw a filled rectangle by clicking on the upper left hand pixel of the box you wish to draw with the select button, dragging the mouse and releasing the select button over the lower left hand pixel. The next gadget is the Clear/Set gadget, allowing you to clear or set points. Note that this is not a paint program, and the interaction speed may not be as fast as you are used to; no apologies. It was only intended to draw bits for the blitter. Below these two gadgets are two numbers. The adrs number holds the address of the word the cursor is currently pointing at, relative to the beginning of the bit array. (It is written as, for instance, M+382, which means the address of the array plus 382 bytes.) The shift value is the pixel, numbered from 0 at the left to 15 at the right. With these values, you can point at a pixel to get its address to enter into a string gadget below. The Calc gadget looks at the values you have entered for the blitter, and determines if any memory other than the bit array will be modified. If it will, it prints `Blit unsafe' on the title bar. This is a sanity check to keep you from crashing the system. Carefully check your values if this flag is on. The fact that this gadget writes `Blit unsafe' does not necessarily mean that the blit will destroy memory outside of the array; careful use of a source operand and mask bits might not pass this test but would be perfectly okay. I have allocated several extra rows above and below the bit array so minor errors shouldn't crash the system. Currently line mode is not checked, so use it with care. The GO gadget performs the blit you have indicated. After the blit, the results are updated in the magnified bit array rather slowly. It performs the same check performed by Calc before executing, and complains similarly. You can override the complaint by clicking on the GO gadget again. Underneath the magnified bit map, on the left, are four gadgets labeled SX, SY, EX, and EY. These bits get the starting and ending points for the line you wish to draw. The X values should range from 0 to 95; the Y values from 0 to 31. These are not checked. Be aware that these are not blitter registers; they are simply values that the program will use in calculating the actual blitter register contents necessary for the line draw. The (line)/LINE gadget turns on line mode. The Setup gadget takes the SX/SY/EX/EY values, and sets up most of the blitter registers to draw the line automatically. It does not set up the function register, because there are different ways to draw lines. For a solid line, use ~AC+A; for a textured line, use ~AC+AB; for an XOR line, use ~AC+A~C, for instance. It does not perform the blit, however. Note that if you want to draw a new line, you need to change the appropriate SX/SY/EX/EY values, then click Setup, then click GO. The next two gadgets, W and H, hold the size of the current blit. The W value is in words, and the H value is in bytes. Legal values range from 1-64 for W, and 1-1024 for H. (Of course, the useful range within this program is much smaller.) Next to the H gadget are gadgets for the DESC, FCI, IFE, and EFE bits of the gadget. These can get set or cleared by selecting them. Underneath these gadgets is the Function gadget. In this gadget you enter the function you want to perform. 0 is clear all, 255 is set all, and other combinations can be entered directly as minterms. For instance, the A~C+~CA presented earlier means exclusive or the A and C bits for the destination. The lower right hand corner contains the actual blitter registers and their values in hexadecimal. These are the values that are fed to the blitter when you select GO. As you enter new numbers into the string gadgets corresponding to blitter registers, these values will change to reflect the new values. (Actually, they will only change if you hit carriage return after entering the numbers into the string gadget; if you simply select another gadget after entering data into a string gadget, the old value will stay displayed until you select CALC or GO.) This can be used to calculate minterms, for instance. Entering ABC+A~B~C+~AB~C+~A~BC into the Function gadget hitting return will put 96 in the least significant eight bits of CON0; this is the hexadecimal value reflecting the above minterms. At the lower right is a table of string gadgets. Each row is for a single DMA channel. The first column is the USE bit; is that channel on or off? Y means on, N means off; selecting the gadget toggles it. The next column contains the start address for DMA. These numbers (as in the remaining string gadgets) can be entered in decimal, hexadecimal (preceded by a $), binary (preceded by a %), or as an offset from the start of the bit array (preceeded by M+). M alone represents the beginning of the blit array. The third column is the modulo value which is added to the DMA channel pointer at the end of each row; this value is in bytes and can be negative. The fourth column is the data register; if a channel is turned off, its data register can be preloaded with a value, and then it functions as a constant. For instance, to fill a block of memory with the value $E931, simply preload the A data register with this value, turn on only the D channel, and blit with the function A. Finally, the last column is the amount to shift the A and B operands, to the right, before using them. Finally, in the lower left corner of the DMA channel box are string gadgets for AFWM and ALWM. This program has been tested fairly carefully. Therefore, if the blitter appears to do something it shouldn't, you probably have set up the registers wrong. Remember, the Amiga blitter is a word blitter, not a bit blitter. It can be made to look like a bit blitter with some work. It is possible, however, that errant blits can muck up some system memory, or some internal variable memory, so if things really seem awry, reboot and go back into the program. Try the same values again, and see if they work this time. Blitter documentation is not included here currently. Sometime in the next week I will finish my blitter documentation; that documentation will tell you more than you ever wanted to know about the blitter. So, until then, I remain: Tomas Rokicki Box 2081 Stanford, CA 94305 723-1646 (office), 326-5312, -5681 (home) rokicki@sushi.stanford.edu ...lll-crg!decwrl!sushi.stanford.edu!rokicki 7514!Funky!Stuff! echo x - structures.h cat > structures.h << '7514!Funky!Stuff!' /* * The structures and include files used in BlitLab. */ #define BANNER "BlitLab 1.1, Copyright (C) 1987, Radical Eye Software" #include "exec/exec.h" #include "intuition/intuition.h" #include "functions.h" #include "graphics/display.h" #include "graphics/gfx.h" #include "graphics/gfxmacros.h" #include "graphics/gfxbase.h" #include "stdio.h" /* * This is the blitter register structure we use. */ struct blitregs { short con0, con1, size, afwm, alwm ; short pth[4] ; short ptl[4] ; short mod[4] ; short dat[4] ; } ; /* * Here we number the gadgets. */ #define GDGPNTREG (0) #define GDGCLRSET (1) #define GDGGO (2) #define GDGSX (3) #define GDGSY (4) #define GDGEX (5) #define GDGEY (6) #define GDGLINE (7) #define GDGH (8) #define GDGV (9) #define GDGDESC (10) #define GDGFCI (11) #define GDGIFE (12) #define GDGEFE (13) #define GDGSETUP (14) #define GDGFUNC (15) #define GDGUSEA (16) #define GDGUSEB (17) #define GDGUSEC (18) #define GDGUSED (19) #define GDGAPT (20) #define GDGBPT (21) #define GDGCPT (22) #define GDGDPT (23) #define GDGAMOD (24) #define GDGBMOD (25) #define GDGCMOD (26) #define GDGDMOD (27) #define GDGADAT (28) #define GDGBDAT (29) #define GDGCDAT (30) #define GDGASH (31) #define GDGBSH (32) #define GDGAFWM (33) #define GDGALWM (34) #define GDGCALC (35) #define MAXGADG (36) /* * These defines set the size of the screen and various subareas of * the screen, including most gadget locations. */ #define HWINSTART (0) #define VWINSTART (5) #define HWINSIZE (640) #define VWINSIZE (195) #define HBITSTART (4) #define VBITSTART (11) #define HBITSIZE (96 * 6) #define VBITSIZE (32 * 3 + 1) #define HLMGSTART (HBITSIZE + HBITSTART + 2) #define HLMGSIZE (HWINSIZE - HLMGSTART - 4) #define VLMGSIZE (12) #define VLMGINT (4) #define VLMG1 (VBITSTART + VLMGINT) #define VLMG2 (VLMG1 + VLMGSIZE + VLMGINT) #define VLMG3 (VLMG2 + VLMGSIZE + VLMGINT) #define VLMG4 (VLMG3 + VLMGSIZE + VLMGINT) #define VLMG5 (VLMG4 + VLMGSIZE + VLMGINT) #define VGOSTART (VLMG5 + VLMGSIZE + VLMGINT) #define HGOSTART (HLMGSTART + 2) #define HGOSIZE (HLMGSIZE - 4) #define VGOSIZE (VRVSTART - VGOSTART - VLMGINT) #define VSTRSIZE (11) #define HSTRSIZE(a) (8 * (a) + 4) #define HMGSIZE (63) #define VMGSIZE (11) #define HMGINT (1) #define VMGINT (0) #define HMG1START (HBITSTART) #define HMG2START (HMG1START + HMGSIZE + HMGINT) #define HMG3START (HMG2START + HMGSIZE + HMGINT) #define HMG4START (HMG3START + HMGSIZE + HMGINT) #define HMG5START (HMG4START + HMGSIZE + HMGINT) #define HMG6START (HMG5START + HMGSIZE + HMGINT) #define HMG7START (HMG6START + HMGSIZE + HMGINT) #define HMG8START (HMG7START + HMGSIZE + HMGINT) #define HMG9START (HMG8START + HMGSIZE + HMGINT) #define VMG1START (VBITSTART + VBITSIZE) #define VMG2START (VMG1START + VMGSIZE + VMGINT) #define VRVSTART (VMG2START + VMGSIZE) #define VRVL1 (VRVSTART + 2) #define VRVL2 (VRVL1 + 9) #define VRVL3 (VRVL2 + 9) #define VRVL4 (VRVL3 + 9) #define VRVL5 (VRVL4 + 9) #define VRVL6 (VRVL5 + 9) #define VRVLL2 (VRVL1 + 10) #define VRVLL3 (VRVLL2 + 11) #define VRVLL4 (VRVLL3 + 11) #define VRVLL5 (VRVLL4 + 11) #define VRVLL6 (VRVLL5 + 11) #define VRG1 (VRVL1 + 8) #define VRVSIZE (VWINSIZE - VRVSTART) #define HRVSIZE (HWINSIZE - HBITSTART - 3) #define HRVSTART (HBITSTART) #define HRVC1 (HRVSTART + 6) #define HRVC2 (HRVC1 + 5 * 8) #define HRVC3 (HRVC2 + 5 * 8) #define HRVC4 (HRVC3 + 2 * 8) #define HRVC5 (HRVC4 + 5 * 8) #define HRVC6 (HRVC5 + 5 * 8) #define HRVC6B (HRVC6 + 5 * 8) #define HMVSTART (HRVC6B + 35) #define HRVC7 (HRVC6B + 5 * 8) #define HRVC8 (HRVC7 + 2 * 8) #define HRVC9 (HRVC8 + 3 * 8 + 4) #define HRVC10 (HRVC9 + 9 * 8) #define HRVC11 (HRVC10 + 7 * 8) #define HRVC12 (HRVC11 + 19 * 8) #define VTEXTOFF (2) #define HTEXTOFF (2) /* * Colors. */ #define BLUE (0) #define WHITE (1) #define BLACK (2) #define ORANGE (3) 7514!Funky!Stuff! echo x - bits.c cat > bits.c << '7514!Funky!Stuff!' /* * This routine handles the display of the bit array in BlitLab. */ #include "structures.h" /* * This is the address of the real bits we operate on. */ extern short int *realbits ; static int safearr[192] ; allocbitmem() { extern void *allocmem() ; realbits = (short *)(allocmem(1000L, MEMF_CHIP | MEMF_CLEAR)) + 150 ; } pdot(x, y, on) int x, y, on ; { int off = (x >> 4) + y * 6 ; int bit = 1 << (15 - (x & 15)) ; if (on) { if ((realbits[off] & bit) == 0) { realbits[off] |= bit ; safearr[off] |= bit ; color(WHITE) ; fbox(x * 6 + HBITSTART, y * 3 + VBITSTART + 1, 4, 2) ; } } else { if (realbits[off] & bit) { realbits[off] &= ~bit ; safearr[off] &= ~bit ; color(BLACK) ; fbox(x * 6 + HBITSTART, y * 3 + VBITSTART + 1, 4, 2) ; } } } preg(x1, y1, x2, y2, on) int x1, y1, x2, y2, on ; { int i, j ; for (i=x1; i<=x2; i++) for (j=y1; j<=y2; j++) pdot(i, j, on) ; } /* * This routine writes out the new position to the screen. */ updatepos(x1, y1) int x1, y1 ; { char outbuf[4] ; sprintf(outbuf, "%3d", ((x1 >> 3) & ~1) + y1 * 12) ; drawtext(HLMGSTART+28, VLMG3+6, outbuf) ; sprintf(outbuf, "%2d", x1 & 15) ; drawtext(HLMGSTART+12, VLMG4+6, outbuf) ; } updatebits() { int x=HBITSTART, y=VBITSTART+1 ; register short *p1 = realbits, *p2 = safearr ; int i = 192 ; int rc = 6 ; int bit ; while (i-- > 0) { if (*p1 == *p2) { p1++ ; p2++ ; x += 6 * 16 ; } else { bit = 0x8000 ; while (bit != 0) { if ((*p2 & bit) != (*p1 & bit)) { color((*p1 & bit) ? WHITE : BLACK) ; fbox(x, y, 4, 2) ; } bit = (bit >> 1) & 0x7fff ; x += 6 ; } *p2++ = *p1++ ; } if (--rc == 0) { rc = 6 ; x = HBITSTART ; y += 3 ; } } } 7514!Funky!Stuff! echo x - blitlab.c cat > blitlab.c << '7514!Funky!Stuff!' /* * This is the main routine from BlitLab. */ #include "structures.h" /* * Here are all the globals we use. (Yuck! Globals!) */ struct Window *mywindow ; struct GfxBase *GfxBase ; struct IntuitionBase *IntuitionBase ; struct RastPort *myrp ; char strings[900] ; char *bufarr[MAXGADG] ; long gvals[MAXGADG] ; struct Gadget *gadgets[MAXGADG] ; char errorbuf[140] ; short *realbits ; struct blitregs blitregs ; int errortitle ; /* * Externals we use: */ extern int blitsafe() ; /* * Some statics to this module. */ static int updatethem ; /* * Errors go through here. Currently, we write to the CLI window. * Later, we will write to the title bar of the window. */ error(s) char *s ; { if (mywindow == NULL) printf("blitlab: %s\n", s) ; else { SetWindowTitles(mywindow, s, -1L) ; errortitle = 1 ; } if (*s == '!') cleanup() ; } /* * This routine handles a gadget selection. */ handlegadget(gp) register struct Gadget *gp ; { static int gocount = 0 ; if (errortitle == 1) { SetWindowTitles(mywindow, BANNER, -1L) ; errortitle = 0 ; } if (bufarr[gp->GadgetID] == NULL) switch(gp->GadgetID) { case GDGPNTREG: case GDGCLRSET: case GDGLINE: case GDGDESC: case GDGFCI: case GDGIFE: case GDGEFE: case GDGUSEA: case GDGUSEB: case GDGUSEC: case GDGUSED: flipgadg(gp->GadgetID) ; break ; case GDGCALC: parseall() ; updatethem = 0 ; if (!blitsafe()) { error("Blit unsafe.") ; } break ; case GDGSETUP: setupline() ; parseall() ; break ; case GDGGO: gocount += 2 ; parseall() ; updatethem = 0 ; if (!blitsafe()) { if (gocount < 3) error("Blit unsafe---hit again to override") ; else { doblit() ; updatebits() ; } } else { doblit() ; updatebits() ; } break ; default: error("! bad value in gadget switch") ; break ; } if (gocount > 0) gocount-- ; } /* * The main routine, no arguments. Sets things up, and then goes * through the standard Intuition message loop. * * It may look like I'm setting message to NULL and checking it and * everything all over, but that is so I can introduce interruptibility * into some operations later, if I choose. */ main() { struct IntuiMessage *message = NULL ; int x, y ; int mousemoved = 0 ; int getouttahere = 0 ; int selectdown = 0 ; int bam ; int ox, oy ; initialize() ; while (1) { mousemoved = 0 ; bam = 0 ; if (message == NULL) WaitPort(mywindow->UserPort) ; while (message || (message = (struct IntuiMessage *)GetMsg(mywindow->UserPort))) { x = message->MouseX ; y = message->MouseY ; if (message->Class == MOUSEMOVE) { ReplyMsg(message) ; message = NULL ; mousemoved = 1 ; } else { if (message->Class == MOUSEBUTTONS) { selectdown = (message->Code == SELECTDOWN) ; bam = 1 ; } else if (message->Class == GADGETDOWN || message->Class == GADGETUP) { updatethem = 1 ; handlegadget((struct Gadget *)(message->IAddress)) ; } else if (message->Class == CLOSEWINDOW) { getouttahere = 1 ; } else error("! undefined message class") ; ReplyMsg(message) ; message = NULL ; } } if (getouttahere) break ; if (updatethem) { parseall() ; updatethem = 0 ; } x = (x - HBITSTART) / 6 ; y = (y - VBITSTART) / 3 ; if (y < 32 && x < 96 && x >= 0 && y >= 0) { if (gvals[GDGPNTREG]) { if (bam) { if (selectdown) { ox = x ; oy = y ; } else { preg(ox, oy, x, y, (int)gvals[GDGCLRSET]) ; } } } else { if (selectdown) pdot(x, y, (int)gvals[GDGCLRSET]) ; } if (message != NULL || (message = (struct IntuiMessage *)GetMsg(mywindow->UserPort))) ; else updatepos(x, y) ; } } cleanup() ; } 7514!Funky!Stuff! echo x - initialize.c cat > initialize.c << '7514!Funky!Stuff!' /* * Initialization module of the blitlab program. */ #include "structures.h" /* * These are the externals we reference. */ extern struct Window *mywindow ; extern struct GfxBase *GfxBase ; extern struct IntuitionBase *IntuitionBase ; extern struct RastPort *myrp ; /* * This is the humongous window we open on the standard * workbench screen. */ static struct NewWindow mynewwindow = { HWINSTART, VWINSTART, HWINSIZE, VWINSIZE, -1, -1, MOUSEBUTTONS | MOUSEMOVE | GADGETDOWN | GADGETUP | CLOSEWINDOW, WINDOWDEPTH | WINDOWCLOSE | WINDOWDRAG | SMART_REFRESH | REPORTMOUSE | ACTIVATE, NULL, NULL, (UBYTE *)BANNER, NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN } ; /* * This is the main initialize routine, which gets everything started * up. */ initialize() { int i, j ; /* * First, we try and open libraries and windows. */ if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library",0L))==NULL || (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L)) ==NULL) error("! Couldn't open libraries") ; if ((mywindow=OpenWindow(&mynewwindow))==NULL) error("! Couldn't open window") ; myrp = mywindow -> RPort ; allocbitmem() ; buildgadgets() ; drawlabels() ; parseall() ; /* * Here we draw the bits array, hopefully for easy reference. */ color(BLACK) ; fbox(HBITSTART, VBITSTART, HBITSIZE, VBITSIZE) ; color(WHITE) ; box(HBITSTART, VBITSTART, HBITSIZE, VBITSIZE) ; color(ORANGE) ; for (i=1; i<24; i++) box(HBITSTART + i * 24 - 2, VBITSTART, 2, VBITSIZE) ; for (i=1; i<96; i++) for (j=1; j<32; j++) line(HBITSTART + i * 6 - 2, VBITSTART + j * 3, HBITSTART + i * 6 - 2, VBITSTART + j * 3) ; color(BLUE) ; box(HBITSTART, VBITSTART, HBITSIZE, VBITSIZE) ; for (i=1; i<7; i++) box(HBITSTART + i * 96 - 2, VBITSTART, 2, VBITSIZE) ; for (i=1; i<9; i++) line(HBITSTART, VBITSTART + i * 12, HBITSTART + HBITSIZE - 1, VBITSTART + i * 12) ; updatebits() ; /* * Now we draw boxes around the blitter register values and user * settable values. */ color(WHITE) ; box(HRVSTART, VRVSTART, HRVSIZE, VRVSIZE) ; line(HMVSTART, VRVSTART, HMVSTART, VRVSTART + VRVSIZE - 1) ; } /* * This routine cleans up for exit. */ cleanup() { if (mywindow != NULL) CloseWindow(mywindow) ; if (GfxBase != NULL) CloseLibrary(GfxBase) ; if (IntuitionBase != NULL) CloseLibrary(IntuitionBase) ; freemem() ; exit(0) ; } /* * drawlabels() draws several miscellaneous labels all over the * screen. */ drawlabels() { drawtext(HLMGSTART+4, VLMG3-2, "Adrs:") ; drawtext(HLMGSTART+4, VLMG3+6, " M+") ; drawtext(HLMGSTART+4, VLMG4-2, "Shift:") ; drawtext(HRVC1 + 12, VRVL6, "Blitter Register Values") ; drawtext(HRVC7 + 4, VRVLL6, "DMA Channels") ; drawtext(HRVC1, VRVL1, "CON0") ; drawtext(HRVC1, VRVL2, "CON1") ; drawtext(HRVC1, VRVL3, "SIZE") ; drawtext(HRVC1, VRVL4, "AFWM") ; drawtext(HRVC1, VRVL5, "ALWM") ; drawtext(HRVC3, VRVL2, "A") ; drawtext(HRVC3, VRVL3, "B") ; drawtext(HRVC3, VRVL4, "C") ; drawtext(HRVC3, VRVL5, "D") ; drawtext(HRVC4 + 4, VRVL1, "PTH PTL MOD DAT") ; drawtext(HRVC7, VRVLL2, "A") ; drawtext(HRVC7, VRVLL3, "B") ; drawtext(HRVC7, VRVLL4, "C") ; drawtext(HRVC7, VRVLL5, "D") ; drawtext(HRVC8, VRVL1, "USE PT MOD DAT SH") ; } 7514!Funky!Stuff!
rokicki@rocky.STANFORD.EDU (Tomas Rokicki) (04/17/87)
Part 2 of 2. #! /bin/sh : This is a shar archive. Extract with sh, not csh. echo x - render.c cat > render.c << '7544!Funky!Stuff!' /* * This file handles the graphics primitives for BlitLab. */ #include "structures.h" /* * External variables we use. */ extern struct RastPort *myrp ; /* * color sets the current foreground color to the appropriate value. */ color(c) int c ; { SetAPen(myrp, (long)c) ; SetDrMd(myrp, (long)JAM1) ; } /* * This routine draws a horizontal or vertical line. */ line(x1, y1, x2, y2) int x1, y1, x2, y2 ; { int t ; if (x1 > x2) { t = x1 ; x1 = x2 ; x2 = t ; } if (y1 > y2) { t = y1 ; y1 = y2 ; y2 = t ; } if (x1 != x2 && y1 != y2) error("! can only draw h/v lines currently") ; RectFill(myrp, (long)x1, (long)y1, (long)x2, (long)y2) ; } /* * This routine draws a box. */ box(x1, y1, xsize, ysize) int x1, y1, xsize, ysize ; { xsize = x1 + xsize - 1 ; ysize = y1 + ysize - 1 ; line(x1, y1, xsize, y1) ; line(xsize, y1, xsize, ysize) ; line(xsize, ysize, x1, ysize) ; line(x1, ysize, x1, y1) ; } /* * This routine draws a filled box. */ fbox(x1, y1, xsize, ysize) int x1, y1, xsize, ysize ; { RectFill(myrp, (long)x1, (long)y1, (long)(x1 + xsize - 1), (long)(y1 + ysize - 1)) ; } /* * This routine draws a text string at a particular location. It is * somewhat crude; we build an IntuiText structure, and tell it to * draw it. */ static struct IntuiText dmy = { WHITE, BLUE, JAM2, 0, 0, NULL, NULL, NULL } ; drawtext(x, y, s) int x, y ; char *s ; { dmy.IText = (UBYTE *)s ; PrintIText(myrp, &dmy, (long)(x), (long)(y)) ; } 7544!Funky!Stuff! echo x - gadgets.c cat > gadgets.c << '7544!Funky!Stuff!' /* * Gadgets for BlitLab. We have something like 40 gadgets here. */ #include "structures.h" /* * To make things nice, we build the gadgets up, one by one. First, * the externals we use. */ extern struct Window *mywindow ; extern char *bufarr[] ; extern char strings[] ; extern void *allocmem() ; extern struct Gadget *gadgets[] ; /* * This routine allocates a border description. */ static struct Border *givebox(xsize, ysize) int xsize, ysize ; { register struct Border *bp ; register short *r ; bp = allocmem((long)sizeof(struct Border), MEMF_CLEAR) ; r = allocmem(20L, MEMF_CLEAR) ; r[2] = xsize ; r[4] = xsize ; r[5] = ysize ; r[7] = ysize ; bp->FrontPen = WHITE ; bp->DrawMode = JAM2 ; bp->Count = 5 ; bp->XY = r ; return(bp) ; } /* * This routine allocates an intuitext structure, with a string * centered in it. */ static struct IntuiText *centertext(size, s) int size ; char *s ; { register struct IntuiText *itp ; itp = allocmem((long)sizeof(struct IntuiText), MEMF_CLEAR) ; itp->FrontPen = WHITE ; itp->DrawMode = JAM2 ; itp->TopEdge = 2 ; itp->LeftEdge = (size - strlen(s) * 8) / 2 ; itp->IText = (UBYTE *)s ; return(itp) ; } /* * This routine builds a simple hit gadget, given an id, x and * y locations, xsize and ysize, and a string label. */ static buildhit(id, x, y, xsize, ysize, s) int id ; int x, y, xsize, ysize ; char *s ; { register struct Gadget *gp ; gp = allocmem((long)sizeof(struct Gadget), MEMF_CLEAR) ; gp->LeftEdge = x ; gp->TopEdge = y ; gp->Width = xsize ; gp->Height = ysize ; gp->Flags = GADGHCOMP ; gp->Activation = RELVERIFY ; gp->GadgetType = BOOLGADGET ; gp->GadgetRender = (APTR)givebox(xsize, ysize) ; gp->GadgetText = centertext(xsize, s) ; gp->GadgetID = id ; gadgets[id] = gp ; AddGadget(mywindow, gp, 0) ; } /* * This routine builds a gadget with two possible strings. It is up * to the user to flip the strings when it is selected; this means * taking it off the list and putting it back on. */ static buildtoggle(id, x, y, xsize, ysize, s1, s2) int id ; int x, y, xsize, ysize ; char *s1, *s2 ; { register struct Gadget *gp ; gp = allocmem((long)sizeof(struct Gadget), MEMF_CLEAR) ; gp->LeftEdge = x ; gp->TopEdge = y ; gp->Width = xsize ; gp->Height = ysize ; gp->Flags = GADGHNONE ; gp->Activation = GADGIMMEDIATE ; gp->GadgetType = BOOLGADGET ; gp->GadgetRender = (APTR)givebox(xsize, ysize) ; gp->GadgetText = centertext(xsize, s1) ; gp->GadgetID = id ; gp->UserData = (APTR)centertext(xsize, s2) ; gadgets[id] = gp ; AddGadget(mywindow, gp, 0) ; } /* * This routine builds a simple string gadget. We allocate pieces * of the `strings' array as we do the gadgets. `p' holds a pointer * to the next available chunk; we have to be careful to initialize. * We also allow a label parameter which lives to the left of the * string gadget. */ static char undobuf[100] ; static char *p ; static buildstring(id, x, y, width, init, rmax, lab) int id ; int x, y ; int width ; char *init ; int rmax ; char *lab ; { register struct Gadget *gp ; register struct StringInfo *sip ; register struct Border *bp ; int ysize ; int xsize ; int chars ; if (lab != NULL) { drawtext(x + 4, y + 2, lab) ; x += 8 + strlen(lab) * 8 ; width -= 8 + strlen(lab) * 8 ; } chars = ( width - 4 ) / 8 ; ysize = VSTRSIZE ; xsize = HSTRSIZE(chars) ; bufarr[id] = p ; strcpy(p, init) ; gp = allocmem((long)sizeof(struct Gadget), MEMF_CLEAR) ; sip = allocmem((long)sizeof(struct StringInfo), MEMF_CLEAR) ; sip->Buffer = (UBYTE *)p ; p += rmax ; sip->UndoBuffer = (UBYTE *)undobuf ; sip->MaxChars = rmax ; gp->LeftEdge = x + 2 ; gp->TopEdge = y + 2 ; gp->Width = xsize ; gp->Height = ysize - 3 ; gp->Flags = GADGHCOMP ; gp->Activation = RELVERIFY ; gp->GadgetType = STRGADGET ; bp = givebox(xsize - 2, ysize - 2) ; bp->XY[0] = -2 ; bp->XY[1] = -2 ; bp->XY[3] = -2 ; bp->XY[6] = -2 ; bp->XY[8] = -2 ; bp->XY[9] = -2 ; gp->GadgetRender = (APTR)bp ; gp->GadgetText = NULL ; gp->SpecialInfo = (APTR)sip ; gp->GadgetID = id ; gadgets[id] = gp ; AddGadget(mywindow, gp, 0) ; } /* * This routine actually creates all of the gadgets. Wish * us luck placing all of these correctly! */ buildgadgets() { int i ; p = strings ; buildhit(GDGGO, HGOSTART, VGOSTART, HGOSIZE, VGOSIZE, "GO") ; buildhit(GDGSETUP, HMG3START, VMG2START, HMGSIZE, VMGSIZE, "Setup") ; buildhit(GDGCALC, HLMGSTART, VLMG5, HLMGSIZE, VLMGSIZE, "Calc") ; buildtoggle(GDGPNTREG, HLMGSTART, VLMG1, HLMGSIZE, VLMGSIZE, "Point", " Box ") ; buildtoggle(GDGCLRSET, HLMGSTART, VLMG2, HLMGSIZE, VLMGSIZE, "Clear", " Set ") ; buildtoggle(GDGLINE, HMG3START, VMG1START, HMGSIZE, VMGSIZE, "(line)", " LINE ") ; buildtoggle(GDGDESC, HMG6START, VMG1START, HMGSIZE, VMGSIZE, "(desc)", " DESC ") ; buildtoggle(GDGFCI, HMG7START, VMG1START, HMGSIZE, VMGSIZE, "(fci)", " FCI ") ; buildtoggle(GDGIFE, HMG8START, VMG1START, HMGSIZE, VMGSIZE, "(ife)", " IFE ") ; buildtoggle(GDGEFE, HMG9START, VMG1START, HMGSIZE, VMGSIZE, "(efe)", " EFE ") ; for (i=0; i<4; i++) buildtoggle(GDGUSEA+i, HRVC8, VRG1 + 11 * i, 24, VSTRSIZE, "N", "Y") ; buildstring(GDGSX, HMG1START, VMG1START, HMGSIZE, "0", 20, "SX") ; buildstring(GDGSY, HMG2START, VMG1START, HMGSIZE, "0", 20, "SY") ; buildstring(GDGEX, HMG1START, VMG2START, HMGSIZE, "0", 20, "EX") ; buildstring(GDGEY, HMG2START, VMG2START, HMGSIZE, "0", 20, "EY") ; buildstring(GDGH, HMG4START, VMG1START, HMGSIZE, "0", 20, "W") ; buildstring(GDGV, HMG5START, VMG1START, HMGSIZE, "0", 20, "H") ; buildstring(GDGFUNC, HMG4START, VMG2START, 6 * HMGSIZE, "0", 100, "Function") ; for (i=0; i<4; i++) buildstring(GDGAPT+i, HRVC9, VRG1 + 11 * i, HSTRSIZE(8), "0", 20, NULL) ; for (i=0; i<4; i++) buildstring(GDGAMOD+i, HRVC10, VRG1 + 11 * i, HSTRSIZE(6), "0", 20, NULL) ; for (i=0; i<3; i++) buildstring(GDGADAT+i, HRVC11, VRG1 + 11 * i, HSTRSIZE(18), "0", 20, NULL) ; for (i=0; i<2; i++) buildstring(GDGASH+i, HRVC12, VRG1 + 11 * i, HSTRSIZE(4), "0", 20, NULL) ; buildstring(GDGAFWM, HRVC11, VRG1 + 33, 180, "%1111111111111111", 20, "FWM") ; buildstring(GDGALWM, HRVC11, VRG1 + 44, 180, "%1111111111111111", 20, "LWM") ; RefreshGadgets(mywindow->FirstGadget, mywindow, NULL) ; } 7544!Funky!Stuff! echo x - mem.c cat > mem.c << '7544!Funky!Stuff!' /* * Memory allocation and deallocation for BlitLab. */ #include "structures.h" struct memnode { struct memnode * next ; long size ; } ; static struct memnode *head ; /* * Replacement for AllocMem. If not enough memory, we exit. */ void *allocmem(size, type) long size ; long type ; { struct memnode *p ; extern void *AllocMem() ; p = (struct memnode *)AllocMem(size + sizeof(struct memnode), type) ; if (p==NULL) error("! out of memory") ; p->size = size + sizeof(struct memnode) ; p->next = head ; head = p ; return(p + 1) ; } /* * Frees all allocated memory. */ freemem() { struct memnode *p ; while (head != NULL) { p = head->next ; FreeMem(head, head->size) ; head = p ; } } 7544!Funky!Stuff! echo x - parse.c cat > parse.c << '7544!Funky!Stuff!' /* * Parse.c of BlitLab software package. This routine handles * parsing the strings into integers, in any of the possible * formats. */ #include "structures.h" /* * Externals we use. */ extern short *realbits ; extern char *bufarr[] ; extern long gvals[] ; extern struct blitregs blitregs ; extern char errorbuf[] ; /* * This is the main parse routine. First, a static to indicate if * we saw a parse error or not. */ static int parseerr ; /* * We allow the following formats: * * (M+)?-?[$%]?[0-9a-f]+ * (~?[ABC])(+(~?[ABC]))* */ long parse(s) register char *s ; { int negative = 1 ; int c ; int radix = 10 ; long toadd = 0 ; long val ; static varr[] = { 0xf0, 0xcc, 0xaa } ; parseerr = 0 ; while (*s == ' ') s++ ; if (*s=='~' || *s=='A' || *s=='B' || *s=='C' || *s=='a' || *s=='b' || *s=='c') { val = 0 ; while (1) { toadd = 255 ; while (1) { if (*s == '~') { negative = 255 ; s++ ; } else negative = 0 ; c = *s++ ; if (c == 0 || c == '+') { if (toadd == 255) parseerr = 1 ; break ; } if (c >= 'a' && c <= 'z') c -= 'a' - 'A' ; if (c < 'A' || c > 'C') { parseerr = 1 ; break ; } toadd &= negative ^ varr[c-'A'] ; } val |= toadd ; if (c != '+') { if (c != 0) parseerr = 1 ; break ; } } return(val) ; } else { if (*s == 'm' || *s == 'M') { if (s[1]=='+') { s += 2 ; toadd = (long)realbits ; } else if (s[1]==0) return((long)realbits) ; else { parseerr = 1 ; return(0) ; } } if (*s == '-') { negative = -1 ; s++ ; } if (*s == '$') { radix = 16 ; s++ ; } else if (*s == '%') { radix = 2 ; s++ ; } val = 0 ; if (*s == 0) { parseerr = 1 ; return(val) ; } while (1) { c = *s ++ ; if (c == 0) break ; if (c >= 'a' && c <= 'z') c -= 'a' - 'A' ; if (c >= 'A' && c <= 'F') c -= 'A' - 10 ; else c -= '0' ; if (c < 0 || c >= radix) { parseerr = 1 ; break ; } val = val * radix + c ; } return(toadd + negative * val) ; } } /* * This routine parses all of the string gadgets. If it is successful, * it returns 1, otherwise it returns 0. */ int parseall() { int i ; for (i=0; i<MAXGADG; i++) if (bufarr[i] != NULL) { gvals[i] = parse(bufarr[i]) ; if (parseerr) { sprintf(errorbuf, "I can't parse %s", bufarr[i]) ; error(errorbuf) ; return(0) ; } } updateregs() ; return(1) ; } /* * This routine writes a four-digit hexadecimal value to the * screen. */ static char *hex = "0123456789abcdef" ; static char tmp[5] ; static writefour(x, y, val) int x, y, val ; { tmp[3] = hex[val & 15] ; val >>= 4 ; tmp[2] = hex[val & 15] ; val >>= 4 ; tmp[1] = hex[val & 15] ; val >>= 4 ; tmp[0] = hex[val & 15] ; drawtext(x, y, tmp) ; } /* * This routine calculates and writes out *all* of the blitter * register values. */ updateregs() { int i ; blitregs.con0 = ((gvals[GDGASH] & 15) << 12) + (gvals[GDGUSEA] << 11) + (gvals[GDGUSEB] << 10) + (gvals[GDGUSEC] << 9) + (gvals[GDGUSED] << 8) + (gvals[GDGFUNC] & 255) ; blitregs.con1 = ((gvals[GDGBSH] & 15) << 12) + (gvals[GDGEFE] << 4) + (gvals[GDGIFE] << 3) + (gvals[GDGFCI] << 2) + (gvals[GDGDESC] << 1) + gvals[GDGLINE] ; blitregs.size = ((gvals[GDGV] & 1023) << 6) + (gvals[GDGH] & 63) ; blitregs.afwm = (gvals[GDGAFWM] & 65535) ; blitregs.alwm = (gvals[GDGALWM] & 65535) ; for (i=0; i<4; i++) { blitregs.pth[i] = ((gvals[GDGAPT+i] >> 16) & 65535) ; blitregs.ptl[i] = (gvals[GDGAPT+i] & 65535) ; blitregs.mod[i] = (gvals[GDGAMOD+i] & 65535) ; } for (i=0; i<3; i++) blitregs.dat[i] = (gvals[GDGADAT+i] & 65535) ; /* * Now we write out the values. */ writefour(HRVC2, VRVL1, blitregs.con0) ; writefour(HRVC2, VRVL2, blitregs.con1) ; writefour(HRVC2, VRVL3, blitregs.size) ; writefour(HRVC2, VRVL4, blitregs.afwm) ; writefour(HRVC2, VRVL5, blitregs.alwm) ; for (i=0; i<4; i++) { writefour(HRVC4, VRVL2 + 9 * i, blitregs.pth[i]) ; writefour(HRVC5, VRVL2 + 9 * i, blitregs.ptl[i]) ; writefour(HRVC6, VRVL2 + 9 * i, blitregs.mod[i]) ; } for (i=0; i<3; i++) writefour(HRVC6B, VRVL2 + 9 * i, blitregs.dat[i]) ; } 7544!Funky!Stuff! echo x - math.c cat > math.c << '7544!Funky!Stuff!' /* * This is the math routines of BlitLab. It checks a possible blit to * insure that it is safe. It also handles the line calculations. */ #include "structures.h" /* * The externals we use. */ extern long gvals[] ; extern struct Gadget *gadgets[] ; extern short *realbits ; extern struct Window *mywindow ; extern char errorbuf[] ; /* * This routine insures that a blit is safe. It returns 1 if it is * okay, and 0 if it is not. */ int blitsafe() { long x1, x2, x3, x4 ; long lower, upper ; if (gvals[GDGUSED]==0) return(1) ; lower = (long)realbits ; upper = 382 + (long)realbits ; if (gvals[GDGH] < 1 || gvals[GDGV] < 1 || gvals[GDGH] > 64 || gvals[GDGV] > 1024) return(0) ; if (gvals[GDGLINE]) { } else { x1 = gvals[GDGDPT] ; if (gvals[GDGDESC]) { x2 = x1 - gvals[GDGH] * 2 + 2 ; x3 = x1 - (gvals[GDGV] - 1) * ((gvals[GDGH] * 2) + (gvals[GDGDMOD] & ~1)) ; x4 = x3 - gvals[GDGH] * 2 + 2 ; if (x1 < lower || x2 < lower || x3 < lower || x4 < lower || x1 > upper || x2 > upper || x3 > upper || x4 > upper) return(0) ; else return(1) ; } else { x2 = x1 + gvals[GDGH] * 2 - 2 ; x3 = x1 + (gvals[GDGV] - 1) * ((gvals[GDGH] * 2) + (gvals[GDGDMOD] & ~1)) ; x4 = x3 + gvals[GDGH] * 2 - 2 ; if (x1 < lower || x2 < lower || x3 < lower || x4 < lower || x1 > upper || x2 > upper || x3 > upper || x4 > upper) return(0) ; else return(1) ; } } } /* * This routine stuffs a value in a gadget. Could be dangerous, but * that's life. */ stuff(id, s) int id ; char *s ; { gvals[id] = parse(s) ; RemoveGadget(mywindow, gadgets[id]) ; strcpy(((struct StringInfo *)(gadgets[id]->SpecialInfo))->Buffer, s) ; AddGadget(mywindow, gadgets[id], -1) ; RefreshGadgets(gadgets[id], mywindow, NULL) ; } /* * This routine flips the state of a toggle gadget. */ flipgadg(id) int id ; { struct IntuiText *temp ; struct Gadget *gp = gadgets[id] ; RemoveGadget(mywindow, gp) ; temp = gp->GadgetText ; gp->GadgetText = (struct IntuiText *)gp->UserData ; gp->UserData = (APTR)temp ; gp->NextGadget = NULL ; AddGadget(mywindow, gp, -1) ; RefreshGadgets(gp, mywindow, NULL) ; gvals[id] = 1 - gvals[id] ; } /* * This routine sets up a line. */ setupline() { int x, y ; int i ; int X, Y ; int q = 0 ; parseall() ; stuff(GDGADAT, "$8000") ; stuff(GDGBDAT, "$ffff") ; x = gvals[GDGSX] ; y = gvals[GDGSY] ; sprintf(errorbuf, "%d", x & 15) ; stuff(GDGASH, errorbuf) ; i = ((x >> 3) & ~1) + y * 12 ; sprintf(errorbuf, "M+%d", i) ; stuff(GDGCPT, errorbuf) ; stuff(GDGDPT, errorbuf) ; stuff(GDGCMOD, "12") ; stuff(GDGDMOD, "12") ; stuff(GDGH, "2") ; x = (gvals[GDGEX] - gvals[GDGSX]) ; y = (gvals[GDGEY] - gvals[GDGSY]) ; if (x < 0) X = - x ; else X = x ; if (y < 0) Y = - y ; else Y = y ; if (x > 0) { if (y > 0) { q = (X > Y ? 1 : 0) ; } else { q = (X > Y ? 3 : 4) ; } } else { if (y > 0) { q = (X > Y ? 5 : 2) ; } else { q = (X > Y ? 7 : 6) ; } } if (Y > X) { i = X ; X = Y ; Y = i ; } sprintf(errorbuf, "%d", X+1) ; stuff(GDGV, errorbuf) ; sprintf(errorbuf, "%d", 2 * Y - X) ; stuff(GDGAPT, errorbuf) ; sprintf(errorbuf, "%d", 4 * (Y - X)) ; stuff(GDGAMOD, errorbuf) ; sprintf(errorbuf, "%d", 4 * Y) ; stuff(GDGBMOD, errorbuf) ; stuff(GDGAFWM, "%1111111111111111") ; stuff(GDGALWM, "%1111111111111111") ; if (! gvals[GDGLINE]) flipgadg(GDGLINE) ; if ((q & 1) != gvals[GDGEFE]) flipgadg(GDGEFE) ; if (((q >> 1) & 1) != gvals[GDGIFE]) flipgadg(GDGIFE) ; if (((q >> 2) & 1) != gvals[GDGFCI]) flipgadg(GDGFCI) ; if (! gvals[GDGUSEA]) flipgadg(GDGUSEA) ; if (gvals[GDGUSEB]) flipgadg(GDGUSEB) ; if (! gvals[GDGUSEC]) flipgadg(GDGUSEC) ; if (! gvals[GDGUSED]) flipgadg(GDGUSED) ; } 7544!Funky!Stuff! echo x - doblit.c cat > doblit.c << '7544!Funky!Stuff!' /* * This is the routine which actually does the hard blits. We just get * the blitter, stuff the values, wait for it to finish, disown the * blitter, and get out of there. */ #include "structures.h" /* * External values we use. */ extern struct blitregs blitregs ; /* * This include file includes the defines for all the blitter functions. * It only allows use of the `blit' operations; for area fills or line * drawing, it will need to be extended. * * Information gleaned from the Hardware Reference Manual. */ #define BLTADD (0xdff040L) /* * This structure contains everything we need to know. * Do not do a structure copy into this! Instead, assign * each field. The last field assigned must be bltsize; that * starts up the blitter. Also note that all of these are * write only, and you can't read them. */ struct bltstruct { short con0 ; short con1 ; short afwm ; short alwm ; short cpth, cptl, bpth, bptl, apth, aptl, dpth, dptl ; short bltsize ; short dmy1, dmy2, dmy3 ; short cmod, bmod, amod, dmod ; short dmy4, dmy5, dmy6, dmy7 ; short cdat, bdat, adat ; } *blitter = BLTADD ; /* * The actual routine. After we own the blitter, we need to wait for * it to finish. */ doblit() { OwnBlitter() ; WaitBlit() ; blitter->con0 = blitregs.con0 ; blitter->con1 = blitregs.con1 ; blitter->afwm = blitregs.afwm ; blitter->alwm = blitregs.alwm ; blitter->apth = blitregs.pth[0] ; blitter->bpth = blitregs.pth[1] ; blitter->cpth = blitregs.pth[2] ; blitter->dpth = blitregs.pth[3] ; blitter->aptl = blitregs.ptl[0] ; blitter->bptl = blitregs.ptl[1] ; blitter->cptl = blitregs.ptl[2] ; blitter->dptl = blitregs.ptl[3] ; blitter->amod = blitregs.mod[0] ; blitter->bmod = blitregs.mod[1] ; blitter->cmod = blitregs.mod[2] ; blitter->dmod = blitregs.mod[3] ; blitter->adat = blitregs.dat[0] ; blitter->bdat = blitregs.dat[1] ; blitter->cdat = blitregs.dat[2] ; /* * Wham! It is the following assignment that starts the blitter. */ blitter->bltsize = blitregs.size ; WaitBlit() ; DisownBlitter() ; } 7544!Funky!Stuff!