432 lines
11 KiB
C
432 lines
11 KiB
C
#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();
|
|
}
|