/** * Intro copperbars demo * Copyright 2023 John Bintz * Licensed under the MIT License * https://theindustriousrabbit.com */ #include #include #include #include #include #include #include #include #include #include #include #include #include extern struct GfxBase *GfxBase; extern struct Custom far custom; extern struct CIA far ciaa, ciab; // this is faster than // custom.vhposr + (custom.vposr << 16) static volatile ULONG *custom_vposr = (volatile ULONG *)0xdff004; struct Library *TimerBase; struct MsgPort *TimerMP; struct timerequest *TimerIO; #define offsetof(s, m) &((struct s *)0)->m #define BITPLANE_SIZE (320/8)*256 #define BAR_HEIGHT (50) #define BPLCON0_COLOR (0x200) #define BPLCON0_BPU_1 (0x1000) int main(void) { struct View *OldView = ((struct GfxBase *)GfxBase)->ActiView; ULONG OldCopper = (ULONG)((struct GfxBase *)GfxBase)->copinit; ULONG OldDMACON, OldINTENA, OldINTREQ, OldADKCON; unsigned short redY = 0, greenY = 10, blueY = 20; unsigned short redSpeed = 1, greenSpeed = 2, blueSpeed = 3; unsigned short currentY = 0, currentColor, newColor; long randomSeed = 0; struct timeval currentSystemTime; void *copperlist; UWORD *copperlist_ptr; APTR *bitplane; // how much can we avoid hard coding into our code? UWORD custom_bplpt = (UWORD)offsetof(Custom, bplpt); UWORD custom_color = (UWORD)offsetof(Custom, color); // get a random seed by using the amount of microseconds the machine's // been on, modulo 1000000. // // if for some weird reaon timer.device is not available, // we can continue. if (TimerMP = CreatePort(NULL, NULL)) { if (TimerIO = (struct timerequest *)CreateExtIO(TimerMP, sizeof(struct timerequest))) { if (!(OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0))) { TimerBase = (struct Library *)TimerIO->tr_node.io_Device; GetSysTime(¤tSystemTime); randomSeed = currentSystemTime.tv_micro; CloseDevice((struct IORequest *)TimerIO); } DeleteExtIO((struct IORequest *)TimerIO); } DeletePort(TimerMP); } LoadView(NULL); WaitTOF(); WaitTOF(); OwnBlitter(); WaitBlit(); Forbid(); OldDMACON = custom.dmaconr | 0x8000; OldINTENA = custom.intenar | 0x8000; OldINTREQ = custom.intreqr | 0x8000; OldADKCON = custom.adkconr | 0x8000; // disable interrupts custom.intena = 0xc000; custom.intena = 0x3fff; // set up dma // weirdly i need DMAF_AUDIO enabled in order for FastRand() to work... custom.dmacon = DMAF_SETCLR | DMAF_COPPER | DMAF_RASTER | DMAF_AUDIO; custom.dmacon = DMAF_DISK | DMAF_SPRITE | DMAF_BLITTER; copperlist = AllocMem(100, MEMF_CHIP | MEMF_CLEAR); bitplane = (APTR *)AllocMem(BITPLANE_SIZE, MEMF_PUBLIC|MEMF_CHIP|MEMF_CLEAR); // default copperlist has just STOP ((ULONG *)copperlist)[0] = 0xfffffffe; // set up 1 bitplane pal display custom.bplcon0 = BPLCON0_COLOR | BPLCON0_BPU_1; custom.bplcon1 = 0; custom.bpl1mod = 0; custom.diwstrt = 0x2c21; custom.diwstop = 0x2cc1; custom.ddfstrt = 0x0038; custom.ddfstop = 0x00d0; // substitute our minimal copperlist now custom.cop1lc = (ULONG)copperlist; // neither HID button 0 is down while ((ciaa.ciapra >> 6) == 3) { // rebuild copperlist copperlist_ptr = (UWORD *)copperlist; // bpl1pth *(copperlist_ptr++) = custom_bplpt; *(copperlist_ptr++) = ((ULONG)bitplane >> 16) & 0xffff; // bpl1ptl *(copperlist_ptr++) = custom_bplpt + 2; *(copperlist_ptr++) = (ULONG)bitplane & 0xffff; *(copperlist_ptr++) = custom_color; *(copperlist_ptr++) = 0x0f00; // impossible color currentColor = 0xFFFF; for (currentY = 0; currentY < 300; currentY++) { newColor = 0x000; if (currentY >= redY && currentY < (redY + BAR_HEIGHT)) { newColor = newColor | 0xf00; } if (currentY >= greenY && currentY < (greenY + BAR_HEIGHT)) { newColor = newColor | 0x0f0; } if (currentY >= blueY && currentY < (blueY + BAR_HEIGHT)) { newColor = newColor | 0x00f; } if (newColor != currentColor) { //printf("Color change at %d: %x to %x\n", currentY, currentColor, newColor); *(copperlist_ptr++) = ((currentY & 0xff) << 8) | 0x26 | 0x1; *(copperlist_ptr++) = 0xfffe; *(copperlist_ptr++) = custom_color; *(copperlist_ptr++) = newColor; currentColor = newColor; } // PAL workaround if (currentY == 255) { *(copperlist_ptr++) = 0xffdf; *(copperlist_ptr++) = 0xfffe; } } // end the copperlist *(copperlist_ptr++) = 0xffff; *(copperlist_ptr++) = 0xfffe; // advance the bars and loop them around, changing // speed randomly on every loop redY += redSpeed; if (redY > 300) { redSpeed = (FastRand(randomSeed) + 1) % 5; randomSeed += redSpeed; redY %= 300; } greenY += greenSpeed; if (greenY > 300) { greenSpeed = (FastRand(randomSeed) + 1) % 5; randomSeed += greenSpeed; greenY %= 300; } blueY += blueSpeed; if (blueY > 300) { blueSpeed = (FastRand(randomSeed) + 1) % 5; randomSeed += blueSpeed; blueY %= 300; } randomSeed %= 0xffffff; // vbl wait // this will not work on NTSC! while ((*custom_vposr & 0x1FF00) != (300 << 8)) {} } FreeMem(bitplane, BITPLANE_SIZE); FreeMem(copperlist, 100); custom.dmacon = 0x7FFF; custom.dmacon = OldDMACON; custom.intena = 0x7FFF; custom.intena = OldINTENA; custom.intreq = 0x7FFF; custom.intreq = OldINTREQ; custom.adkcon = 0x7FFF; custom.adkcon = OldADKCON; custom.cop1lc = OldCopper; LoadView(OldView); WaitTOF(); WaitTOF(); WaitBlit(); DisownBlitter(); Permit(); }