Initial commit
commit
ad9dc1eaa9
|
@ -0,0 +1,4 @@
|
|||
*.uaem
|
||||
*.o
|
||||
*.lnk
|
||||
*.info
|
|
@ -0,0 +1,37 @@
|
|||
# Amiga Copperbars Examples from "Amiga rasterbar are cool"
|
||||
|
||||
These are the code files used to generate the rasterbars effects on the
|
||||
Agnus/Copper Industrious Rabbit video. I built them to compile in SAS/C
|
||||
6.58:
|
||||
|
||||
`sc <filename> link`
|
||||
|
||||
They're written in C and, except for `actual complex demo.c`, are left
|
||||
pretty unoptimized so they're more readable. Writing them in assembler
|
||||
and with more tricks can get them to perform faster, at the expense of
|
||||
a lot of readability for a beginner.
|
||||
|
||||
`actual complex demo.c` will not run at full 50FPS on a stock Amiga 500, but
|
||||
`intro.c` will (or at least should).
|
||||
|
||||
They also don't work on NTSC Amigas! I wait for a position well below
|
||||
the max NTSC Copper vertical position to detect the end of the vertical
|
||||
blank. If you want to modify these for NTSC, please send patches
|
||||
to me via the contact instructions on the
|
||||
[About page](https://theindustriousrabbit.com/about).
|
||||
|
||||
## Intro
|
||||
|
||||
The three horizontal bars moving up and down at the beginning of the video.
|
||||
|
||||
## Chunky Vertical, Two Columns of Lines, and Actual Complex Demo
|
||||
|
||||
The three different demos at the end of the video.
|
||||
|
||||
## Random numbers
|
||||
|
||||
Intro and Actual Complex Demo both use [`FastRand`](http://amiga.nvg.org/amiga/reference/Includes_and_Autodocs_2._guide/node015A.html)
|
||||
to generate pseudo-random results in the demo, using the microseconds since
|
||||
the machine was turned on as the initial seed
|
||||
(using [timer.device](http://www.amigadev.elowar.com/read/ADCD_2.1/Devices_Manual_guide/node00C1.html)).
|
||||
This required enabling audio DMA for some reason that I don't understand.
|
Binary file not shown.
|
@ -0,0 +1,431 @@
|
|||
#include <clib/exec_protos.h>
|
||||
#include <clib/dos_protos.h>
|
||||
#include <clib/alib_protos.h>
|
||||
#include <exec/memory.h>
|
||||
#include <exec/io.h>
|
||||
#include <clib/intuition_protos.h>
|
||||
#include <clib/graphics_protos.h>
|
||||
#include <devices/timer.h>
|
||||
#include <clib/timer_protos.h>
|
||||
#include <graphics/GfxBase.h>
|
||||
#include <hardware/cia.h>
|
||||
#include <hardware/dmabits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* Complex copper demo
|
||||
* * 20 colors on a 4 color display
|
||||
* * Single buffered bitplane updating
|
||||
*
|
||||
* Leave the slow speed on A500 for another video to solve
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
#define offsetof(s, m) &((struct s *)0)->m
|
||||
|
||||
#define BPLCON0_COLOR (0x200)
|
||||
#define BPLCON0_BPU_2 (0x2000)
|
||||
|
||||
#define COPPERLIST_SIZE (20000)
|
||||
#define DISPLAY_TOP (44)
|
||||
|
||||
#define SAWTOOTH_STEPS (8)
|
||||
#define TOTAL_SAWTOOTH_STEPS (SAWTOOTH_STEPS * 2 - 2)
|
||||
#define BITPLANE_SIZE (320/8)*(256+TOTAL_SAWTOOTH_STEPS)
|
||||
|
||||
#define BAR_HEIGHT (20)
|
||||
|
||||
#define COP_WAIT(x,y) ((y & 0xff) << 8) | x | 0x01
|
||||
#define COP_WAITMASK (0xfffe)
|
||||
#define CPTR *(copperlist_ptr++)
|
||||
|
||||
#define COLOR00 0x180
|
||||
#define COLOR01 0x182
|
||||
#define COLOR02 0x184
|
||||
#define COLOR03 0x186
|
||||
|
||||
void buildSawtoothSlice(ULONG *dest, int i) {
|
||||
ULONG base;
|
||||
|
||||
// left side bpl 1
|
||||
base = 0x1fffffff;
|
||||
base = base >> i;
|
||||
|
||||
dest[0] = base;
|
||||
|
||||
// right side bpl 1
|
||||
base = 0xfffffff0;
|
||||
base = base << (8 - i);
|
||||
|
||||
dest[1] = base;
|
||||
|
||||
// left side bpl 2
|
||||
base = 0x0fffffff;
|
||||
base = base >> i;
|
||||
|
||||
dest[2] = base;
|
||||
|
||||
// right side bpl 2
|
||||
base = 0xfffffff8;
|
||||
base = base << (8 - i);
|
||||
|
||||
dest[3] = base;
|
||||
}
|
||||
|
||||
long getRandomSeed(void) {
|
||||
long randomSeed = 0;
|
||||
struct MsgPort *TimerMP;
|
||||
struct timerequest *TimerIO;
|
||||
struct timeval currentSystemTime;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
return randomSeed;
|
||||
}
|
||||
|
||||
void buildSawtooth(ULONG verticalBarSlices[]) {
|
||||
int i, j;
|
||||
|
||||
// create the sawtooth pattern
|
||||
for (i = 0; i < SAWTOOTH_STEPS; ++i) {
|
||||
buildSawtoothSlice(&verticalBarSlices[i * 4], i);
|
||||
}
|
||||
for (i = 0; i < SAWTOOTH_STEPS - 2; ++i) {
|
||||
j = SAWTOOTH_STEPS - 2 - i;
|
||||
buildSawtoothSlice(&verticalBarSlices[(SAWTOOTH_STEPS * 4) + (i * 4)], j);
|
||||
}
|
||||
}
|
||||
|
||||
#define BITPLANE_ADVANCE ((320/32) - 6)
|
||||
#define BITPLANE_WORD_SIZE ((320/32)*(256+TOTAL_SAWTOOTH_STEPS))
|
||||
|
||||
/**
|
||||
* Write sawtooth pattern to provided bitplanes.
|
||||
*/
|
||||
void writeSawtoothToBitplanes(APTR *bitplanes, ULONG verticalBarSlices[]) {
|
||||
ULONG *bitplane_1 = (ULONG *)bitplanes + 1;
|
||||
ULONG *bitplane_2 = (ULONG *)bitplanes + BITPLANE_WORD_SIZE + 1;
|
||||
|
||||
int currentSlice = 0, currentY, sliceOffset;
|
||||
|
||||
for (currentY = 0; currentY < (255 + TOTAL_SAWTOOTH_STEPS); ++currentY) {
|
||||
sliceOffset = currentSlice * 4;
|
||||
// left
|
||||
*(bitplane_1++) = verticalBarSlices[sliceOffset++];
|
||||
*(bitplane_1) = verticalBarSlices[sliceOffset++];
|
||||
*(bitplane_2++) = verticalBarSlices[sliceOffset++];
|
||||
*(bitplane_2) = verticalBarSlices[sliceOffset++];
|
||||
|
||||
bitplane_1 += 4;
|
||||
bitplane_2 += 4;
|
||||
|
||||
sliceOffset = currentSlice * 4;
|
||||
|
||||
// right
|
||||
*(bitplane_1++) = verticalBarSlices[sliceOffset++];
|
||||
*(bitplane_1) = verticalBarSlices[sliceOffset++];
|
||||
*(bitplane_2++) = verticalBarSlices[sliceOffset++];
|
||||
*(bitplane_2) = verticalBarSlices[sliceOffset++];
|
||||
|
||||
bitplane_1 += BITPLANE_ADVANCE;
|
||||
bitplane_2 += BITPLANE_ADVANCE;
|
||||
|
||||
currentSlice += 1;
|
||||
if (currentSlice == TOTAL_SAWTOOTH_STEPS) currentSlice = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int BAR_COLORS[2][20] = {
|
||||
{
|
||||
0x300,
|
||||
0x500, 0x500,
|
||||
0x700, 0x700,
|
||||
0xa00, 0xa00, 0xa00,
|
||||
0xf00, 0xf00, 0xfdd, 0xf00,
|
||||
0xa00, 0xa00, 0xa00,
|
||||
0x700, 0x700,
|
||||
0x500, 0x500,
|
||||
0x300
|
||||
}, {
|
||||
0x003,
|
||||
0x005, 0x005,
|
||||
0x007, 0x007,
|
||||
0x00a, 0x00a, 0x00a,
|
||||
0x00f, 0x00f, 0xddf, 0x00f,
|
||||
0x00a, 0x00a, 0x00a,
|
||||
0x007, 0x007,
|
||||
0x005, 0x005,
|
||||
0x003
|
||||
}
|
||||
};
|
||||
|
||||
int main(void) {
|
||||
struct View *OldView = ((struct GfxBase *)GfxBase)->ActiView;
|
||||
ULONG OldCopper = (ULONG)((struct GfxBase *)GfxBase)->copinit;
|
||||
ULONG OldDMACON, OldINTENA, OldINTREQ, OldADKCON;
|
||||
|
||||
int currentY, frame = 0;
|
||||
int currentHighlight = 0, currentBar;
|
||||
|
||||
int barPosition[2] = {150, 250};
|
||||
int barBottomPosition[2] = { 150 + BAR_HEIGHT, 250 + BAR_HEIGHT };
|
||||
int barDestination[2] = {230, 40};
|
||||
int barSpeed[2] = {1, -2};
|
||||
int firstInFront = 0, actualBar;
|
||||
int barsDrawn[2];
|
||||
|
||||
UWORD barColor, lastBarColor, lastHighlightColor, highlightColor, shadowColor;
|
||||
|
||||
long randomSeed;
|
||||
|
||||
// 2 per slice * 8 different slices * 2 bitplanes * replicate for sawtooth
|
||||
ULONG verticalBarSlices[TOTAL_SAWTOOTH_STEPS * 4 * 2];
|
||||
|
||||
void *copperlist;
|
||||
UWORD *copperlist_ptr;
|
||||
APTR *bitplanes;
|
||||
|
||||
// how much can we avoid hard coding into our code?
|
||||
UWORD custom_bplpt = (UWORD)offsetof(Custom, bplpt);
|
||||
//UWORD custom_color = (UWORD)offsetof(Custom, color);
|
||||
|
||||
randomSeed = getRandomSeed();
|
||||
buildSawtooth(verticalBarSlices);
|
||||
|
||||
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 | DMAF_DISK;
|
||||
custom.dmacon = DMAF_SPRITE | DMAF_BLITTER;
|
||||
|
||||
// TODO: determine optimal size
|
||||
copperlist = AllocMem(COPPERLIST_SIZE, MEMF_CHIP | MEMF_CLEAR);
|
||||
|
||||
// bitplanes are always same size regardless of anim size
|
||||
bitplanes = (APTR *)AllocMem(BITPLANE_SIZE * 2, MEMF_PUBLIC|MEMF_CHIP|MEMF_CLEAR);
|
||||
|
||||
// default copperlist has just STOP
|
||||
((ULONG *)copperlist)[0] = 0xfffffffe;
|
||||
|
||||
// set up 2 bitplane pal display
|
||||
custom.bplcon0 = BPLCON0_COLOR | BPLCON0_BPU_2;
|
||||
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;
|
||||
|
||||
writeSawtoothToBitplanes(
|
||||
bitplanes,
|
||||
verticalBarSlices
|
||||
);
|
||||
|
||||
lastBarColor = 0xffff;
|
||||
lastHighlightColor = 0xffff;
|
||||
|
||||
// neither HID button 0 is down
|
||||
while ((ciaa.ciapra >> 6) == 3) {
|
||||
// rebuild copperlist
|
||||
copperlist_ptr = (UWORD *)copperlist;
|
||||
|
||||
currentHighlight = ((frame + TOTAL_SAWTOOTH_STEPS) % TOTAL_SAWTOOTH_STEPS);
|
||||
actualBar = firstInFront;
|
||||
|
||||
barsDrawn[0] = 0;
|
||||
barsDrawn[1] = 0;
|
||||
|
||||
// bpl1pth
|
||||
*(copperlist_ptr++) = custom_bplpt;
|
||||
*(copperlist_ptr++) = (((ULONG)bitplanes + (frame * (320/8)) >> 16)) & 0xffff;
|
||||
// bpl1ptl
|
||||
*(copperlist_ptr++) = custom_bplpt + 2;
|
||||
*(copperlist_ptr++) = ((ULONG)bitplanes + (frame * (320/8))) & 0xffff;
|
||||
|
||||
// bpl2pth
|
||||
*(copperlist_ptr++) = custom_bplpt + 4;
|
||||
*(copperlist_ptr++) = ((((ULONG)bitplanes) + BITPLANE_SIZE + (frame * (320/8))) >> 16) & 0xffff;
|
||||
// bpl2ptl
|
||||
*(copperlist_ptr++) = custom_bplpt + 6;
|
||||
*(copperlist_ptr++) = (((ULONG)bitplanes) + BITPLANE_SIZE + (frame * (320/8))) & 0xffff;
|
||||
|
||||
*(copperlist_ptr++) = COLOR00;
|
||||
*(copperlist_ptr++) = 0x0000;
|
||||
|
||||
for (currentY = DISPLAY_TOP; currentY < DISPLAY_TOP + 256; currentY++) {
|
||||
// 8 of highlight on color02, then 6 of shadow on color03
|
||||
// 8 of lesser shadow on color01, then 6 of lesser highlight on color02
|
||||
// color01 for now stays the same
|
||||
|
||||
CPTR = COP_WAIT(0x10, currentY);
|
||||
CPTR = COP_WAITMASK;
|
||||
|
||||
CPTR = COLOR03;
|
||||
CPTR = 0x779;
|
||||
|
||||
if (currentHighlight < SAWTOOTH_STEPS) {
|
||||
highlightColor = 0xfff;
|
||||
shadowColor = 0x777;
|
||||
} else {
|
||||
highlightColor = 0x444;
|
||||
shadowColor = 0xaaa;
|
||||
}
|
||||
|
||||
// only write shading to copperlist if it changes
|
||||
if (highlightColor != lastHighlightColor) {
|
||||
CPTR = COLOR02;
|
||||
CPTR = highlightColor;
|
||||
CPTR = COLOR01;
|
||||
CPTR = shadowColor;
|
||||
|
||||
lastHighlightColor = highlightColor;
|
||||
}
|
||||
|
||||
if (!barsDrawn[0] || !barsDrawn[1]) {
|
||||
barColor = 0x000;
|
||||
for (currentBar = 0; currentBar < 2; currentBar++) {
|
||||
if (!barsDrawn[actualBar]) {
|
||||
if (currentY >= barPosition[actualBar]) {
|
||||
if (currentY < barBottomPosition[actualBar]) {
|
||||
barColor = BAR_COLORS[actualBar][currentY - barPosition[actualBar]];
|
||||
} else {
|
||||
barsDrawn[actualBar] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
actualBar = 1 - actualBar;
|
||||
}
|
||||
|
||||
if (barColor != lastBarColor) {
|
||||
CPTR = COLOR00;
|
||||
CPTR = barColor;
|
||||
|
||||
lastBarColor = barColor;
|
||||
}
|
||||
}
|
||||
|
||||
CPTR = COP_WAIT(0x70, currentY);
|
||||
CPTR = COP_WAITMASK;
|
||||
|
||||
CPTR = COLOR03;
|
||||
CPTR = 0x977;
|
||||
|
||||
// PAL workaround
|
||||
if (currentY == 255) {
|
||||
*(copperlist_ptr++) = 0xffdf;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
}
|
||||
|
||||
currentHighlight += 1;
|
||||
if (currentHighlight == TOTAL_SAWTOOTH_STEPS) currentHighlight = 0;
|
||||
}
|
||||
|
||||
// reset color 0
|
||||
CPTR = COP_WAIT(0x10, DISPLAY_TOP + 256);
|
||||
CPTR = COP_WAITMASK;
|
||||
|
||||
CPTR = COLOR00;
|
||||
CPTR = 0x0000;
|
||||
|
||||
// end the copperlist
|
||||
*(copperlist_ptr++) = 0xffff;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
|
||||
// vbl wait
|
||||
// this will not work on NTSC!
|
||||
while ((*custom_vposr & 0x1FF00) != ((256 + DISPLAY_TOP) << 8)) {}
|
||||
|
||||
for (currentBar = 0; currentBar < 2; currentBar++) {
|
||||
barPosition[currentBar] += barSpeed[currentBar];
|
||||
barBottomPosition[currentBar] += barSpeed[currentBar];
|
||||
if (barSpeed[currentBar] > 0) {
|
||||
if (barPosition[currentBar] > barDestination[currentBar]) {
|
||||
barSpeed[currentBar] = -(FastRand(randomSeed) % 3 + 2);
|
||||
barDestination[currentBar] = FastRand(randomSeed) % 128 + DISPLAY_TOP;
|
||||
}
|
||||
} else {
|
||||
if (barPosition[currentBar] < barDestination[currentBar]) {
|
||||
barSpeed[currentBar] = FastRand(randomSeed) % 3 + 2;
|
||||
barDestination[currentBar] = FastRand(randomSeed) % 128 + 128 + DISPLAY_TOP - BAR_HEIGHT;
|
||||
|
||||
firstInFront = 1 - firstInFront;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
randomSeed += frame;
|
||||
if (randomSeed > 0xffffffff) randomSeed -= 0xffffffff;
|
||||
|
||||
frame += 1;
|
||||
if (frame == TOTAL_SAWTOOTH_STEPS) frame = 0;
|
||||
}
|
||||
|
||||
FreeMem(bitplanes, BITPLANE_SIZE);
|
||||
FreeMem(copperlist, COPPERLIST_SIZE);
|
||||
|
||||
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();
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
* Chunky vertical 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 <graphics/GfxBase.h>
|
||||
|
||||
#include <exec/memory.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;
|
||||
|
||||
#define offsetof(s, m) &((struct s *)0)->m
|
||||
#define BITPLANE_SIZE (320/8)*256
|
||||
|
||||
#define BPLCON0_COLOR (0x200)
|
||||
#define BPLCON0_BPU_1 (0x1000)
|
||||
|
||||
static UWORD colors[] = {0xf00,0x0f0,0xff0,0x0ff};
|
||||
|
||||
int main(void) {
|
||||
struct View *OldView = ((struct GfxBase *)GfxBase)->ActiView;
|
||||
ULONG OldCopper = (ULONG)((struct GfxBase *)GfxBase)->copinit;
|
||||
ULONG OldDMACON, OldINTENA, OldINTREQ, OldADKCON;
|
||||
|
||||
int currentY, colorBar, xPos;
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
custom.dmacon = DMAF_SETCLR | DMAF_COPPER | DMAF_RASTER;
|
||||
custom.dmacon = DMAF_AUDIO | DMAF_DISK | DMAF_SPRITE | DMAF_BLITTER;
|
||||
|
||||
// 4 bars = WAIT + MOVE (8 bytes) 8 times * 312 + ~100 for setup = 21000 should do it
|
||||
|
||||
copperlist = AllocMem(21000, 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;
|
||||
|
||||
for (currentY = 0; currentY < 312; currentY++) {
|
||||
for (colorBar = 0; colorBar < 4; colorBar++) {
|
||||
xPos = 0x68 + (colorBar * 24);
|
||||
|
||||
*(copperlist_ptr++) = ((currentY & 0xff) << 8) | xPos | 0x1;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
|
||||
*(copperlist_ptr++) = custom_color;
|
||||
*(copperlist_ptr++) = colors[colorBar];
|
||||
|
||||
*(copperlist_ptr++) = ((currentY & 0xff) << 8) | xPos + 2 | 0x1;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
|
||||
*(copperlist_ptr++) = custom_color;
|
||||
*(copperlist_ptr++) = 0x000;
|
||||
}
|
||||
|
||||
// PAL workaround
|
||||
if (currentY == 255) {
|
||||
*(copperlist_ptr++) = 0xffdf;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
}
|
||||
}
|
||||
|
||||
// end the copperlist
|
||||
*(copperlist_ptr++) = 0xffff;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
|
||||
// vbl wait
|
||||
// this will not work on NTSC!
|
||||
while ((*custom_vposr & 0x1FF00) != (300 << 8)) {}
|
||||
}
|
||||
|
||||
FreeMem(bitplane, BITPLANE_SIZE);
|
||||
FreeMem(copperlist, 21000);
|
||||
|
||||
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();
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
/**
|
||||
* 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(¤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();
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,159 @@
|
|||
/**
|
||||
* Two columns of lines 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 <exec/memory.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;
|
||||
|
||||
#define offsetof(s, m) &((struct s *)0)->m
|
||||
#define BITPLANE_SIZE (320/8)*256
|
||||
|
||||
#define BPLCON0_COLOR (0x200)
|
||||
#define BPLCON0_BPU_1 (0x1000)
|
||||
|
||||
static UWORD leftColors[] = {0xf00,0xd00,0xb00,0x900};
|
||||
static UWORD rightColors[] = {0x00f,0x00d,0x00b,0x009};
|
||||
|
||||
int main(void) {
|
||||
struct View *OldView = ((struct GfxBase *)GfxBase)->ActiView;
|
||||
ULONG OldCopper = (ULONG)((struct GfxBase *)GfxBase)->copinit;
|
||||
ULONG OldDMACON, OldINTENA, OldINTREQ, OldADKCON;
|
||||
|
||||
int currentY, colorIndex;
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
custom.dmacon = DMAF_SETCLR | DMAF_COPPER | DMAF_RASTER;
|
||||
custom.dmacon = DMAF_AUDIO | DMAF_DISK | DMAF_SPRITE | DMAF_BLITTER;
|
||||
|
||||
// 4 bars = WAIT + MOVE (8 bytes) 8 times * 312 + ~100 for setup = 21000 should do it
|
||||
|
||||
copperlist = AllocMem(21000, 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++) = leftColors[0];
|
||||
|
||||
for (currentY = 0; currentY < 312; currentY++) {
|
||||
colorIndex = (currentY / 4) % 4;
|
||||
|
||||
*(copperlist_ptr++) = ((currentY & 0xff) << 8) | 0x06 | 0x1;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
|
||||
*(copperlist_ptr++) = custom_color;
|
||||
*(copperlist_ptr++) = leftColors[colorIndex];
|
||||
|
||||
*(copperlist_ptr++) = ((currentY & 0xff) << 8) | 0x90 | 0x1;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
|
||||
*(copperlist_ptr++) = custom_color;
|
||||
*(copperlist_ptr++) = rightColors[colorIndex];
|
||||
|
||||
// PAL workaround
|
||||
if (currentY == 255) {
|
||||
*(copperlist_ptr++) = 0xffdf;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
}
|
||||
}
|
||||
|
||||
// end the copperlist
|
||||
*(copperlist_ptr++) = 0xffff;
|
||||
*(copperlist_ptr++) = 0xfffe;
|
||||
|
||||
// vbl wait
|
||||
// this will not work on NTSC!
|
||||
while ((*custom_vposr & 0x1FF00) != (300 << 8)) {}
|
||||
}
|
||||
|
||||
FreeMem(bitplane, BITPLANE_SIZE);
|
||||
FreeMem(copperlist, 21000);
|
||||
|
||||
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();
|
||||
}
|
Loading…
Reference in New Issue