amiga-agnus-copperbars/intro.c

232 lines
5.9 KiB
C

/**
* Intro copperbars demo
* Copyright 2023 John Bintz
* Licensed under the MIT License
* https://theindustriousrabbit.com
*/
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/timer_protos.h>
#include <exec/memory.h>
#include <exec/io.h>
#include <devices/timer.h>
#include <graphics/GfxBase.h>
#include <hardware/cia.h>
#include <hardware/dmabits.h>
#include <stdio.h>
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(&currentSystemTime);
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();
}