Initial commit
This commit is contained in:
commit
6d58dd3fe9
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*.uaem
|
||||
*.o
|
||||
*.lnk
|
||||
*.info
|
37
README.md
Normal file
37
README.md
Normal file
@ -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.
|
BIN
actual complex demo
Normal file
BIN
actual complex demo
Normal file
Binary file not shown.
431
actual complex demo.c
Normal file
431
actual complex demo.c
Normal file
@ -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();
|
||||
}
|
BIN
chunky vertical
Normal file
BIN
chunky vertical
Normal file
Binary file not shown.
160
chunky vertical.c
Normal file
160
chunky vertical.c
Normal file
@ -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();
|
||||
}
|
231
intro.c
Normal file
231
intro.c
Normal file
@ -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();
|
||||
}
|
BIN
two columns of lines
Normal file
BIN
two columns of lines
Normal file
Binary file not shown.
159
two columns of lines.c
Normal file
159
two columns of lines.c
Normal file
@ -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
Block a user