Compare commits

..

No commits in common. "main" and "jb/reworking-screen-memory-and-bun-drawing" have entirely different histories.

49 changed files with 2224 additions and 2132 deletions

View File

@ -1,2 +0,0 @@
AllCops:
TargetRubyVersion: 3.2

BIN
32x50

Binary file not shown.

View File

@ -1,90 +0,0 @@
/**
* What do we need
* * [ ] screen setup
*/
#include <hardware/custom.h>
#include <hardware/cia.h>
#include <clib/graphics_protos.h>
#include "system/system.h"
#include "system/copper.h"
#include "system/blitter.h"
#include "screen.h"
extern struct Custom far custom;
extern struct CIA far ciaa;
uint16_t custom_color = (uint16_t)offsetof(Custom, color);
uint16_t custom_sprite = (uint16_t)offsetof(Custom, sprpt);
uint16_t custom_sprite_control = (uint16_t)offsetof(Custom, spr);
extern unsigned char chip coolbun[];
int main(void) {
struct ScreenDefinition screenDefinition;
struct ActiveScreenBufferDetails activeScreenBufferDetails;
uint16_t *copperlist, *currentCopperlist;
void *copperlistBitplanePointers[8][2];
int i, plane;
allocateDoubleBufferedScreenMemory(
&screenDefinition,
&activeScreenBufferDetails,
320,
256,
2
);
copperlist = prepareNewCopperlist(300);
currentCopperlist = addDisplayToCopperlist(
copperlist,
&screenDefinition,
&activeScreenBufferDetails,
&copperlistBitplanePointers
);
COPPERLIST_MOVE(currentCopperlist, custom_color, 0x3a6);
COPPERLIST_MOVE(currentCopperlist, custom_color + 2, 0x000);
COPPERLIST_MOVE(currentCopperlist, custom_color + 4, 0xfff);
currentCopperlist = setUpEmptySpritesInCopperlist(currentCopperlist);
endCopperlist(currentCopperlist);
takeOverSystem();
setCopperlist(copperlist);
setUpDisplay((uint32_t)screenDefinition.bitplanes);
// Render a bun at 32x50
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, 0);
custom.bltcon1 = BLTCON1(BLITTER_ASCENDING, 0);
custom.bltapt = coolbun + (plane * 4 * 32);
custom.bltdpt = activeScreenBufferDetails.planes[plane] + (50 * 320 / 8) + 32 / 8;
custom.bltafwm = 0xffff;
custom.bltalwm = 0xffff;
custom.bltamod = 0;
custom.bltdmod = 40 - 4;
custom.bltsize = 2 + (32 << 6);
WaitBlit();
}
while (1) {
if ((ciaa.ciapra >> 6) != 3) break;
}
giveBackSystem();
freeCopperlist(copperlist);
teardownScreen(&screenDefinition);
}

BIN
33x50

Binary file not shown.

View File

@ -1,127 +0,0 @@
/**
* What do we need
* * [ ] screen setup
*/
#include <hardware/custom.h>
#include <hardware/cia.h>
#include <clib/graphics_protos.h>
#include "system/system.h"
#include "system/copper.h"
#include "system/blitter.h"
#include "screen.h"
extern struct Custom far custom;
extern struct CIA far ciaa;
uint16_t custom_color = (uint16_t)offsetof(Custom, color);
uint16_t custom_sprite = (uint16_t)offsetof(Custom, sprpt);
uint16_t custom_sprite_control = (uint16_t)offsetof(Custom, spr);
extern unsigned char chip coolbun[];
int main(void) {
struct ScreenDefinition screenDefinition;
struct ActiveScreenBufferDetails activeScreenBufferDetails;
uint16_t *copperlist, *currentCopperlist;
void *copperlistBitplanePointers[8][2];
int i, plane, x, y, dirX, dirY, shift, byteX;
allocateDoubleBufferedScreenMemory(
&screenDefinition,
&activeScreenBufferDetails,
320,
256,
2
);
copperlist = prepareNewCopperlist(300);
currentCopperlist = addDisplayToCopperlist(
copperlist,
&screenDefinition,
&activeScreenBufferDetails,
&copperlistBitplanePointers
);
COPPERLIST_MOVE(currentCopperlist, custom_color, 0x3a6);
COPPERLIST_MOVE(currentCopperlist, custom_color + 2, 0x000);
COPPERLIST_MOVE(currentCopperlist, custom_color + 4, 0xfff);
currentCopperlist = setUpEmptySpritesInCopperlist(currentCopperlist);
endCopperlist(currentCopperlist);
takeOverSystem();
setCopperlist(copperlist);
setUpDisplay((uint32_t)screenDefinition.bitplanes);
// Render a bun at 32x50
x = 32;
y = 50;
dirX = 1;
dirY = 1;
while (1) {
WaitTOF();
swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails);
shift = x & 15;
byteX = (x >> 4 * 2);
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, shift);
custom.bltcon1 = BLTCON1(BLITTER_ASCENDING, 0);
custom.bltapt = coolbun + (plane * 4 * 32);
custom.bltdpt = activeScreenBufferDetails.planes[plane] + (y * 320 / 8) + byteX;
custom.bltafwm = 0xffff;
if (shift == 0) {
custom.bltalwm = 0xffff;;
} else {
custom.bltalwm = 0x0000;
}
custom.bltamod = shift ? -2 : 0;
custom.bltdmod = 40 - (shift ? 6 : 4);
custom.bltsize = (shift ? 3 : 2) + (32 << 6);
WaitBlit();
}
x += dirX;
if (x == 320 - 32) {
x -= 1;
dirX = -dirX;
}
if (x < 0) {
x = 0;
dirX = -dirX;
}
y += dirY;
if (y == 256 - 32) {
y -= 1;
dirY = -dirY;
}
if (y > 0) {
y = 0;
dirY -= dirY;
}
if ((ciaa.ciapra >> 6) != 3) break;
}
giveBackSystem();
freeCopperlist(copperlist);
teardownScreen(&screenDefinition);
}

3
NOTES.md Normal file
View File

@ -0,0 +1,3 @@
Left off at implementing asm routine for injecting point in
copperlist ram where bitplane pointers are going for
easy replacement for double buffering.

View File

@ -1,50 +0,0 @@
## Cool Bun Demo
![demo](./demo.gif)
Built for [The Obligatory Amiga Blitter Video](https://makertube.net/w/eV545ku522sRq8CTcxDuFZ).
Uses a bunch of C and Assembler code to drive the blitter, sprites, and copper
to display high color Topaz art overtop of flying cool bun logos.
## Running
Click the mouse to escape any demo.
* `main`: Main demo
* `32x50`, `33x50`, `left_side`, `right_side`: Rendering Cool Bun in various
locations on screen.
* `any_position`: Cool Bun flies around like a DVD player pause screen.
* `keyboard_interrupt`: Tests using `input.device` to access the keyboard.
* `blitter_speed_test`: Get the speed of blitter vs. CPU memory operations
* `bun_test`: Run some unit tests (yes, really!)
This will get 50 fps on an 020, and 25 or lower on an 68EC020 and below.
## Building
### Vamos
You'll want [Vamos](https://github.com/cnvogelg/amitools/blob/master/docs/vamos.md),
and [SAS/C](https://www.amigaclub.be/blog/steffest/2/amiga-c%20compilers)
&amp; [GenAm from DevPac](https://archive.org/details/Devpac_v3.14_1994-12-16_HiSoft)
on Vamos's path:
```
# main
ruby ./image_converter.rb && touch images.s && vamos -- smake
# any others
vamos -- smake <other>
```
The image converter requires Ruby 3.2.4 and RMagick installed.
## Performance
The best way I can think of to make this way faster is for a script in
Ruby or Python to calculate every blitter register for every frame of data
for bun renders and clears, store that in a list of words, and rip through
those lists in Assembler, shotgunning the values directly into the registers
without the C code needing to track bun positions and bun clears. That's a
project for another day.

Binary file not shown.

View File

@ -1,144 +0,0 @@
/**
* What do we need
* * [ ] screen setup
*/
#include <hardware/custom.h>
#include <hardware/cia.h>
#include <clib/graphics_protos.h>
#include "system/system.h"
#include "system/copper.h"
#include "system/blitter.h"
#include "screen.h"
extern struct Custom far custom;
extern struct CIA far ciaa;
uint16_t custom_color = (uint16_t)offsetof(Custom, color);
uint16_t custom_sprite = (uint16_t)offsetof(Custom, sprpt);
uint16_t custom_sprite_control = (uint16_t)offsetof(Custom, spr);
extern unsigned char chip coolbun[];
int main(void) {
struct ScreenDefinition screenDefinition;
struct ActiveScreenBufferDetails activeScreenBufferDetails;
uint16_t *copperlist, *currentCopperlist;
void *copperlistBitplanePointers[8][2];
int i, plane, x, y, dirX, dirY, shift, byteX, clearY;
allocateDoubleBufferedScreenMemory(
&screenDefinition,
&activeScreenBufferDetails,
320,
256,
2
);
copperlist = prepareNewCopperlist(300);
currentCopperlist = addDisplayToCopperlist(
copperlist,
&screenDefinition,
&activeScreenBufferDetails,
&copperlistBitplanePointers
);
COPPERLIST_MOVE(currentCopperlist, custom_color, 0x3a6);
COPPERLIST_MOVE(currentCopperlist, custom_color + 2, 0x000);
COPPERLIST_MOVE(currentCopperlist, custom_color + 4, 0xfff);
currentCopperlist = setUpEmptySpritesInCopperlist(currentCopperlist);
endCopperlist(currentCopperlist);
takeOverSystem();
setCopperlist(copperlist);
setUpDisplay((uint32_t)screenDefinition.bitplanes);
// Render a bun at 32x50
x = 32;
y = 50;
dirX = 1;
dirY = 1;
while (1) {
WaitTOF();
swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails);
shift = x & 15;
byteX = ((x >> 4) * 2);
clearY = y - 4;
if (clearY < 0) clearY = 0;
if (clearY + 40 > 255) clearY = 255 - 40;
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = BLTCON0(0xc0, 0, 0, 0, 1, 0);
custom.bltcon1 = 0;
custom.bltadat = 0x0000;
custom.bltdpt = activeScreenBufferDetails.planes[plane] + (clearY * 320 / 8);
custom.bltafwm = 0xffff;
custom.bltalwm = 0xffff;
custom.bltsize = BLTSIZE(20, 40);
custom.bltdmod = 0;
WaitBlit();
}
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, shift);
custom.bltcon1 = BLTCON1(BLITTER_ASCENDING, 0);
custom.bltapt = coolbun + (plane * 4 * 32);
custom.bltdpt = activeScreenBufferDetails.planes[plane] + (y * 320 / 8) + byteX;
custom.bltafwm = 0xffff;
if (shift == 0) {
custom.bltalwm = 0xffff;;
} else {
custom.bltalwm = 0x0000;
}
custom.bltamod = shift ? -2 : 0;
custom.bltdmod = 40 - (shift ? 6 : 4);
custom.bltsize = (shift ? 3 : 2) + (32 << 6);
WaitBlit();
}
x += dirX;
if (x == 320 - 32) {
x -= 1;
dirX = -dirX;
}
if (x < 0) {
x = 0;
dirX = -dirX;
}
y += dirY;
if (y == 256 - 32) {
y -= 1;
dirY = -dirY;
}
if (y < 0) {
y = 0;
dirY = -dirY;
}
if ((ciaa.ciapra >> 6) != 3) break;
}
giveBackSystem();
freeCopperlist(copperlist);
teardownScreen(&screenDefinition);
}

BIN
basics Executable file

Binary file not shown.

172
basics.s Normal file
View File

@ -0,0 +1,172 @@
XREF _custom
; write this from scratch and get it working
; then plug it into C
FUNC_CNT SET -30
FUNCDEF MACRO
_LVO\1 EQU FUNC_CNT
FUNC_CNT SET FUNC_CNT-6
ENDM
INCDIR "include_i_39:"
INCDIR "extra_lvos_39:"
INCLUDE "exec/exec_lib.i"
INCLUDE "exec/types.i"
INCLUDE "exec/execbase.i"
INCLUDE "exec/libraries.i" # get the CALLLIB macro
INCLUDE "graphics/gfxbase.i"
INCLUDE "graphics_lvo.i"
INCLUDE "hardware/custom.i"
INCLUDE "hardware/dmabits.i"
START:
BSR _takeOverSystem
BSR _giveBackSystem
MOVE.L #0,D0
RTS
OpenGraphicsLibrary MACRO
LEA GraphicsLibrary,A1
MOVEQ #0,D0
CALLLIB _LVOOpenLibrary
MOVE.L D0,GraphicsBase
ENDM
TakeOverView MACRO
MOVE.L GraphicsBase,A6
MOVE.L gb_ActiView(A6),OldView
MOVEQ #0,D0
CALLLIB _LVOLoadView
CALLLIB _LVOWaitTOF
CALLLIB _LVOWaitTOF
ENDM
PreserveOldCopper MACRO
MOVE.L $26(A6),OldCopper1
MOVE.L $32(A6),OldCopper2
ENDM
GetVBRPointer MACRO
BSR getVBR
MOVE.L D0,VBRPtr
ENDM
PreserveOldRegisters MACRO
LEA _custom,A6
MOVE.W adkconr(A6),Oldadkcon
MOVE.W intenar(A6),Oldintena
MOVE.W dmaconr(A6),Olddmacon
ENDM
ClearRegisters MACRO
MOVE.W #$7FFF,D0
BSR waitRaster
MOVE.W D0,intena(A6)
MOVE.W D0,dmacon(A6)
MOVE.W D0,intreq(A6)
ENDM
SetRegisters MACRO
MOVE.W #$C000,intena(A6) ; enable master interrupt
MOVE.W #$3FFF,intena(A6) ; disable every other interrupt
MOVE.W #DMAF_SETCLR|DMAF_COPPER|DMAF_RASTER|DMAF_BLITTER,dmacon(A6)
MOVE.W #DMAF_AUDIO|DMAF_DISK|DMAF_SPRITE,dmacon(A6)
ENDM
_takeOverSystem:
MOVEM.L A6,-(SP)
CLR.W $100
MOVE.L $4,A6
CALLLIB _LVOForbid
OpenGraphicsLibrary
PreserveOldCopper
CALLLIB _LVOOwnBlitter
CALLLIB _LVOWaitBlit
PreserveOldRegisters
SetRegisters
TakeOverView
MOVEM.L (SP)+,A6
RTS
waitRaster:
MOVE.L D0,-(SP)
.loop:
MOVE.L $DFF004,D0
AND.L #$1FF00,D0
CMP.L #303<<8,D0
BNE .loop
MOVE.L (SP)+,D0
RTS
_giveBackSystem:
CLR.W $100
MOVEM.L A6,-(SP)
LEA _custom,A6
MOVE.W #$8000,d0
OR.W D0,Olddmacon
OR.W D0,Oldintena
OR.W D0,Oldadkcon
SUBQ #1,D0
;ClearRegisters
MOVE.L OldCopper1,cop1lc(A6)
MOVE.L OldCopper2,cop2lc(A6)
MOVE.W #1,copjmp1(A6)
MOVE.W Olddmacon,intena(A6)
MOVE.W Olddmacon,dmacon(A6)
MOVE.W Oldadkcon,adkcon(A6)
MOVE.L OldView,A1
MOVE.L GraphicsBase,A6
CALLLIB _LVOLoadView
CALLLIB _LVOWaitTOF
CALLLIB _LVOWaitTOF
MOVE.L $4,A6
MOVE.L GraphicsBase,D0
MOVE.L D0,A1
CALLLIB _LVOCloseLibrary
CALLLIB _LVOPermit
MOVEM.L (SP)+,A6
RTS
getVBR:
MOVE.L A5,-(SP)
MOVEQ #0,D0
MOVE.L $4,A6
BTST #0,AttnFlags+1(A6)
BEQ .is68K
LEA .get010VBR(pc),A5
CALLLIB _LVOSupervisor
.is68K:
MOVE.L (SP)+,A5
RTS
.get010VBR:
dc.l $4E7A0801 ; movec vcr,d0
RTE
CNOP 0,4
GraphicsLibrary dc.b 'graphics.library',0
CNOP 0,4
GraphicsBase dc.l 1
OldView dc.l 1
OldCopper1 dc.l 1
OldCopper2 dc.l 1
VBRPtr dc.l 1
Oldadkcon dc.w 0
Oldintena dc.w 0
Olddmacon dc.w 0

BIN
better_startup Executable file

Binary file not shown.

98
better_startup.c Normal file
View File

@ -0,0 +1,98 @@
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <exec/memory.h>
#include <graphics/gfxbase.h>
#include <hardware/custom.h>
#include <hardware/dmabits.h>
#include <exec/types.h>
extern struct GfxBase *GfxBase;
extern far struct Custom custom;
int main(void) {
UWORD OldDMACON,OldINTENA,OldINTREQ,OldADKCON;
struct View *OldView = ((struct GfxBase *)GfxBase)->ActiView;
ULONG OldCopper = custom.cop1lc;
ULONG OldCopper2 = custom.cop2lc;
UWORD *copperlist = AllocMem(10000, MEMF_CHIP | MEMF_CLEAR);
UWORD *currentCopperlist;
UBYTE *bitplanes = AllocMem(320 * 256, MEMF_CHIP | MEMF_CLEAR);
int i;
LoadView(0);
WaitTOF();
WaitTOF();
OwnBlitter();
WaitBlit();
Forbid();
OldDMACON = custom.dmaconr | 0x8000;
OldINTENA = custom.intenar | 0x8000;
//OldINTREQ = custom.intreqr | 0x8000;
OldADKCON = custom.adkconr | 0x8000;
custom.intreq = 0x7fff;
custom.cmacon = 0x7fff;
custom.cmacon = 0x7fff;
// enable
custom.dmacon = DMAF_SETCLR | DMAF_COPPER | DMAF_RASTER | DMAF_BLITTER;
// disable
custom.dmacon = DMAF_AUDIO | DMAF_DISK | DMAF_SPRITE;
custom.bplcon0 = (1 << 9) + (1 << 12);
custom.bplcon1 = 0;
custom.bplcon2 = 0;
custom.bpl1mod = 0;
custom.bpl2mod = 0;
custom.diwstrt = 0x2c21;
custom.diwstop = 0x2cc1;
custom.ddfstrt = 0x0038;
custom.ddfstop = 0x00d0;
currentCopperlist = copperlist;
*(currentCopperlist++) = 0x0050;
*(currentCopperlist++) = ((ULONG)bitplanes >> 16);
*(currentCopperlist++) = 0x0020;
*(currentCopperlist++) = ((ULONG)bitplanes && 16);
*(currentCopperlist++) = 0xffff;
*(currentCopperlist++) = 0xfffe;
custom.cop1lc = copperlist;
for (i = 0; i < 200; ++i) {
WaitTOF();
}
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;
custom.cop2lc = OldCopper1;
LoadView(OldView);
WaitTOF();
WaitTOF();
WaitBlit();
DisownBlitter();
Permit();
FreeMem(copperlist, 10000);
FreeMem(bitplanes, 320 * 256);
}

0
blitter_speed_test.q Normal file
View File

438
bun.c
View File

@ -1,5 +1,3 @@
#include <math.h>
// Custom
#include <hardware/custom.h>
@ -13,127 +11,69 @@
#include "screen.h"
#include "bun.h"
#include "system/system.h"
#include "system/blitter.h"
#define COOL_BUN_WIDTH (32)
#define COOL_BUN_WIDTH_BYTES (COOL_BUN_WIDTH / 8)
#define COOL_BUN_HEIGHT (32)
#define COOL_BUN_PLANES (2)
#define COOL_BUN_LAST_ROW (COOL_BUN_HEIGHT - 1)
#define COOL_BUN_LAST_ROW_BYTES (COOL_BUN_LAST_ROW * COOL_BUN_WIDTH_BYTES)
#define COOL_BUN_PLANE_SIZE (COOL_BUN_WIDTH_BYTES * COOL_BUN_HEIGHT)
#define COOL_BUN_MEMORY_SIZE (COOL_BUN_PLANE_SIZE * COOL_BUN_PLANES)
#define BUN_MAX_RANGE (31 + 320)
#define BUN_SPEED (1)
#define BUN_HORIZ_DISTANCE_BETWEEN_BUNS ((BUN_MAX_RANGE / 4) - COOL_BUN_WIDTH)
#define BUN_TOTAL_HORIZ_DISTANCE (BUN_HORIZ_DISTANCE_BETWEEN_BUNS + COOL_BUN_WIDTH)
#define BUN_ROW_START (50)
#define BUN_VERT_DISTANCE_BETWEEN_BUNS (30)
#define BUN_TOTAL_VERT_DISTANCE (COOL_BUN_HEIGHT + BUN_VERT_DISTANCE_BETWEEN_BUNS)
#define FRAME_MAX (BUN_TOTAL_HORIZ_DISTANCE / BUN_SPEED)
#define BUN_WAVE_LENGTH (FRAMES_FOR_SCREEN / 2)
// linked as raw bytes in assembler
extern unsigned char chip coolbun[];
extern unsigned char far coolbun[];
unsigned char *coolbunArea;
#define BLTCON0( \
minterm, aChan, bChan, cChan, dChan, shift \
) (minterm + (aChan << 11) + (bChan << 10) + (cChan << 9) + (dChan << 8) + (shift << 12))
#define BLTCON1(descending, shift) ((descending << 1) + (shift << 12))
extern struct Custom far custom;
struct BunClear {
uint16_t memoryStartOffsetBytes;
uint16_t widthWords;
uint16_t heightRows;
uint8_t direction;
};
void setupBun() {
unsigned char *currentCoolBunArea, *currentCoolBun;
unsigned int x, y, plane;
#define BUN_OFF_RIGHT_SIDE (0)
#define BUN_OFF_LEFT_SIDE (1)
#define BUN_ANYWHERE (2)
coolbunArea = AllocMem(COOL_BUN_MEMORY_SIZE, MEMF_CHIP | MEMF_CLEAR);
currentCoolBunArea = coolbunArea;
currentCoolBun = coolbun;
uint8_t *coolbunPlaneStarts[3][2];
uint16_t bunRightSide_bltalwmPrecalc[16];
uint16_t bunLeftSide_bltalwmPrecalc[16];
void precalculateBunBLTALWM() {
int shift, j;
uint16_t bltalwm;
for (shift = 0; shift < 16; ++shift) {
// right
bltalwm = 0x0000;
for (j = 0; j < 15 - shift; ++j) {
bltalwm += (1 << (15 - j));
CopyMem(coolbun, coolbunArea, COOL_BUN_MEMORY_SIZE);
}
bunRightSide_bltalwmPrecalc[shift] = bltalwm;
//left
bltalwm = 0x0000;
for (j = 0; j <= 15 - shift; ++j) {
bltalwm += (1 << j);
}
bunLeftSide_bltalwmPrecalc[shift] = bltalwm;
}
void teardownBun() {
FreeMem(coolbunArea, COOL_BUN_MEMORY_SIZE);
}
void bun_offRightSide(
int plusXValue,
int y,
struct ScreenDefinition *screenDefinition,
struct ActiveScreenBufferDetails *activeScreenBufferDetails,
struct BunClear *bunClear
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen
) {
uint8_t i, plane = 0;
uint8_t shift = plusXValue & 15;
uint8_t wordShift = (plusXValue >> 4);
uint16_t bltalwm, bltcon0, bltcon1, bltdmod, bltsize;
uint16_t bltalwm;
bunClear->memoryStartOffsetBytes = (y * screenDefinition->byteWidth) +
screenDefinition->byteWidth - COOL_BUN_WIDTH_BYTES +
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = BLTCON0(0xc0, 0, 1, 0, 1, shift);
custom.bltcon1 = BLTCON1(0, shift);
custom.bltadat = 0xffff;
custom.bltbpt = coolbunArea +
plane * COOL_BUN_PLANE_SIZE;
custom.bltdpt = currentScreen->planes[plane] +
(y * screenSetup->byteWidth) +
screenSetup->byteWidth - COOL_BUN_WIDTH_BYTES +
wordShift * 2;
bunClear->heightRows = COOL_BUN_HEIGHT;
bunClear->widthWords = 2 - wordShift;
bunClear->direction = BLITTER_ASCENDING;
bltalwm = bunRightSide_bltalwmPrecalc[shift];
/*
custom.bltafwm = 0xffff;
bltalwm = 0x0000;
for (i = 0; i <= 15 - shift; ++i) {
bltalwm += (1 << (15 - i));
}
*/
bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, shift);
bltcon1 = BLTCON1(bunClear->direction, shift);
bltdmod = screenDefinition->byteWidth - COOL_BUN_WIDTH_BYTES +
wordShift * 2;
bltsize = bunClear->widthWords + (bunClear->heightRows << 6);
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = bltcon0;
custom.bltcon1 = bltcon1;
custom.bltapt = coolbunPlaneStarts[BUN_OFF_RIGHT_SIDE][plane];
custom.bltdpt = activeScreenBufferDetails->planes[plane] +
bunClear->memoryStartOffsetBytes;
custom.bltafwm = 0xffff;
custom.bltalwm = bltalwm;
custom.bltamod = wordShift * 2;
custom.bltdmod = bltdmod;
custom.bltbmod = wordShift * 2;
custom.bltdmod = screenSetup->byteWidth - COOL_BUN_WIDTH_BYTES +
wordShift * 2;
custom.bltsize = bltsize;
custom.bltsize = 2 - wordShift + (COOL_BUN_HEIGHT << 6);
WaitBlit();
}
@ -142,58 +82,47 @@ void bun_offRightSide(
void bun_offLeftSide(
int minusXValue,
int y,
struct ScreenDefinition *screenDefinition,
struct ActiveScreenBufferDetails *activeScreenBufferDetails,
struct BunClear *bunClear
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen
) {
unsigned char plane;
uint8_t shift = minusXValue & 15;
uint8_t wordShift = (minusXValue >> 4);
uint8_t i;
uint16_t bltalwm, bltcon0, bltcon1, bltdmod, bltsize;
uint16_t bltalwm;
// y can't be 0 otherwise we will corrupt memory for now
if (y == 0) return;
bunClear->memoryStartOffsetBytes = (screenDefinition->byteWidth * (y + COOL_BUN_LAST_ROW)) +
2 - wordShift * 2;
bunClear->heightRows = COOL_BUN_HEIGHT;
bunClear->widthWords = 2 - wordShift;
bunClear->direction = BLITTER_DESCENDING;
for (plane = 0; plane < 2; ++plane) {
// shift left, so descending
custom.bltcon0 = BLTCON0(0xc0, 0, 1, 0, 1, shift);
custom.bltcon1 = BLTCON1(1, shift);
bltalwm = bunLeftSide_bltalwmPrecalc[shift];
// a has a mask we're shifting
custom.bltadat = 0xffff;
// b has bun data
custom.bltbpt = coolbunArea + 2 +
COOL_BUN_LAST_ROW_BYTES +
plane * COOL_BUN_PLANE_SIZE;
/*
// d is the part on screen
custom.bltdpt = currentScreen->planes[plane] +
(screenSetup->byteWidth * (y + COOL_BUN_LAST_ROW)) +
2 -
wordShift * 2;
custom.bltafwm = 0xffff;
bltalwm = 0x0000;
for (i = 0; i <= 15 - shift; ++i) {
bltalwm += (1 << i);
}
*/
bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, shift);
bltcon1 = BLTCON1(bunClear->direction, shift);
bltdmod = screenDefinition->byteWidth - 4 + wordShift * 2;
bltsize = bunClear->widthWords + (bunClear->heightRows << 6);
for (plane = 0; plane < 2; ++plane) {
// shift left, so descending
custom.bltcon0 = bltcon0;
custom.bltcon1 = bltcon1;
// a has bun data
custom.bltapt = coolbunPlaneStarts[BUN_OFF_LEFT_SIDE][plane];
// d is the part on screen
custom.bltdpt = activeScreenBufferDetails->planes[plane] + bunClear->memoryStartOffsetBytes;
custom.bltafwm = 0xffff;
custom.bltalwm = bltalwm;
custom.bltamod = wordShift * 2;
custom.bltdmod = bltdmod;
custom.bltbmod = wordShift * 2;
custom.bltdmod = screenSetup->byteWidth - 4 + wordShift * 2;
custom.bltsize = bltsize;
custom.bltsize = 2 - wordShift + (COOL_BUN_HEIGHT << 6);
WaitBlit();
}
@ -202,256 +131,65 @@ void bun_offLeftSide(
void bun_anywhere(
int x,
int y,
struct ScreenDefinition *screenDefinition,
struct ActiveScreenBufferDetails *activeScreenBufferDetails,
struct BunClear *bunClear
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen
) {
uint8_t plane;
uint8_t shift = x & 15;
uint8_t needsExtraWord = shift != 0;
uint16_t bltcon0, bltcon1, bltalwm, bltamod, bltdmod, bltsize;
bunClear->memoryStartOffsetBytes = WORD_ALIGNED_BYTE_POSITION(screenDefinition->width, x, y);
bunClear->heightRows = COOL_BUN_HEIGHT;
bunClear->widthWords = 2 + needsExtraWord;
bunClear->direction = BLITTER_ASCENDING;
// buns will never interfere with a background so they don't need a mask
bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, shift);
bltcon1 = BLTCON1(bunClear->direction, shift);
if (needsExtraWord) {
bltalwm = 0x0000;
} else {
bltalwm = 0xffff;
}
bltamod = -(needsExtraWord * 2);
bltdmod = screenDefinition->byteWidth - COOL_BUN_WIDTH_BYTES - (needsExtraWord * 2);
bltsize = bunClear->widthWords + (bunClear->heightRows << 6);
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = bltcon0;
custom.bltcon1 = bltcon1;
// if we extend the bun area by a word, we only need one write
custom.bltapt = coolbunPlaneStarts[BUN_ANYWHERE][plane];
custom.bltdpt = activeScreenBufferDetails->planes[plane] +
bunClear->memoryStartOffsetBytes;
// buns will never interfere with a background so they don't need a mask
// they do need the scratch area though
custom.bltcon0 = BLTCON0(0xc0, 0, 1, 0, 1, shift);
custom.bltcon1 = BLTCON1(0, shift);
custom.bltadat = 0xffff;
custom.bltbpt = coolbunArea + plane * COOL_BUN_PLANE_SIZE;
custom.bltdpt = currentScreen->planes[plane] +
WORD_ALIGNED_BYTE_POSITION(screenSetup->width, x, y);
// custom.bltdpt = screenSetup.memoryStart;
custom.bltafwm = 0xffff;
custom.bltalwm = bltalwm;
if (needsExtraWord) {
custom.bltalwm = 0x0000;
} else {
custom.bltalwm = 0xffff;
}
custom.bltamod = bltamod;
custom.bltdmod = bltdmod;
custom.bltsize = bltsize;
custom.bltbmod = -(needsExtraWord * 2);
custom.bltdmod = screenSetup->byteWidth - COOL_BUN_WIDTH_BYTES - (needsExtraWord * 2);
custom.bltsize = (2 + needsExtraWord) + (COOL_BUN_HEIGHT << 6);
WaitBlit();
}
}
#define ENABLE_RENDER_BUN_CHECKING (0)
void renderBun(
int x,
int y,
struct ScreenDefinition *screenDefinition,
struct ActiveScreenBufferDetails *activeScreenBufferDetails,
struct BunClear *bunClear
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen
) {
/**
* Conditions that will cause the program to crash if met. If your bun
* isn't rendering, it's due to here. Turn off checking once you know
* everything is solid to save some CPU.
* isn't rendering, it's due to here.
*
* TODO: Handle top/bottom off-screen as well.
*/
if (ENABLE_RENDER_BUN_CHECKING) {
if (x < -31) return;
if (x > screenDefinition->width + 31) return;
if (x > screenSetup->width + 31) return;
if (y < 1) return;
if (y > screenDefinition->height - COOL_BUN_HEIGHT - 1) return;
}
if (y > screenSetup->height- COOL_BUN_HEIGHT - 1) return;
if (x < 0) {
bun_offLeftSide(
-x,
y,
screenDefinition,
activeScreenBufferDetails,
bunClear
);
} else if (x > screenDefinition->width - COOL_BUN_WIDTH) {
bun_offRightSide(
x - (screenDefinition->width - COOL_BUN_WIDTH),
y,
screenDefinition,
activeScreenBufferDetails,
bunClear
);
bun_offLeftSide(-x, y, screenSetup, currentScreen);
} else if (x > screenSetup->width - COOL_BUN_WIDTH) {
bun_offRightSide(x - (screenSetup->width - COOL_BUN_WIDTH), y, screenSetup, currentScreen);
} else {
bun_anywhere(
x,
y,
screenDefinition,
activeScreenBufferDetails,
bunClear
);
bun_anywhere(x, y, screenSetup, currentScreen);
}
}
#define MAX_SINE_WAVE_CHANGE (20)
int bunAngleAdjustments[BUN_COUNT];
void calculateBunPositions(
uint16_t frame,
short int bunPositions[BUN_COUNT][2],
struct ScreenDefinition *screenDefinition
) {
int x, y, row, column, current;
float angle, startAngle;
frame %= FRAMES_FOR_SCREEN;
startAngle = (float)(frame % BUN_WAVE_LENGTH) * 360 / BUN_WAVE_LENGTH;
for (current = 0; current < BUN_COUNT; ++current) {
row = current / 4;
column = current % 4;
angle = startAngle + bunAngleAdjustments[current];
x = column * BUN_TOTAL_HORIZ_DISTANCE + ((float)frame * BUN_MAX_RANGE / FRAMES_FOR_SCREEN);
if (row == 1) {
x += BUN_TOTAL_HORIZ_DISTANCE / 2;
}
x %= BUN_MAX_RANGE;
x -= 31;
angle = angle * PI / 180;
y = BUN_ROW_START +
row * BUN_TOTAL_VERT_DISTANCE +
sin(angle) * MAX_SINE_WAVE_CHANGE;
bunPositions[current][0] = x;
bunPositions[current][1] = y;
}
}
short int allBunPositionsByFrame[FRAMES_FOR_SCREEN][BUN_COUNT][2];
void calculateAllBunPositions(
struct ScreenDefinition *screenDefinition
) {
int frame;
for (frame = 0; frame < FRAMES_FOR_SCREEN; ++frame) {
calculateBunPositions(
frame,
allBunPositionsByFrame[frame],
screenDefinition
);
}
}
void buildBunAngleAdjustments(void) {
int current, angleAdjustment;
for (current = 0; current < BUN_COUNT; ++current) {
angleAdjustment = 0;
if (current % 2 == 1) angleAdjustment += 180;
if (current / 4 == 1) angleAdjustment += 90;
bunAngleAdjustments[current] = angleAdjustment;
}
}
void precalculateBunRenderInfo(void) {
int plane;
for (plane = 0; plane < 2; ++plane) {
coolbunPlaneStarts[BUN_OFF_RIGHT_SIDE][plane] = coolbun + plane * COOL_BUN_PLANE_SIZE;
coolbunPlaneStarts[BUN_ANYWHERE][plane] = coolbun + plane * COOL_BUN_PLANE_SIZE;
coolbunPlaneStarts[BUN_OFF_LEFT_SIDE][plane] = coolbun + 2 +
COOL_BUN_LAST_ROW_BYTES +
plane * COOL_BUN_PLANE_SIZE;
}
}
void setupBunRenderer(
struct BunRenderer *bunRenderer,
struct ScreenDefinition *screenDefinition,
struct ActiveScreenBufferDetails *activeScreenBufferDetails) {
bunRenderer->screenDefinition = screenDefinition;
bunRenderer->activeScreenBufferDetails = activeScreenBufferDetails;
buildBunAngleAdjustments();
calculateAllBunPositions(screenDefinition);
precalculateBunRenderInfo();
precalculateBunBLTALWM();
}
/**
* Is there bun clear information for this frame? This is not true for the
* first frame in the demo.
*/
int hasBunClear[2] = {0,0};
struct BunClear bunClearForScreen[2][BUN_COUNT];
void clearCurrentBuns(
struct BunRenderer *bunRenderer
) {
int bun, plane;
struct BunClear *currentBunClear;
uint16_t bltcon0, bltcon1, bltdmod, bltsize;
if (!hasBunClear[bunRenderer->activeScreenBufferDetails->currentBuffer]) return;
bltcon0 = BLTCON0(0xc0, 0, 0, 0, 1, 0);
for (bun = 0; bun < BUN_COUNT; ++bun) {
currentBunClear = &bunClearForScreen[bunRenderer->activeScreenBufferDetails->currentBuffer][bun];
bltcon1 = BLTCON1(currentBunClear->direction, 0);
bltdmod = bunRenderer->screenDefinition->byteWidth - (currentBunClear->widthWords * 2);
bltsize = currentBunClear->widthWords + (currentBunClear->heightRows << 6);
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = bltcon0;
custom.bltcon1 = bltcon1;
custom.bltadat = 0x0000;
custom.bltafwm = 0xffff;
custom.bltalwm = 0xffff;
custom.bltdpt = bunRenderer->activeScreenBufferDetails->planes[plane] +
currentBunClear->memoryStartOffsetBytes;
custom.bltdmod = bltdmod;
custom.bltsize = bltsize;
WaitBlit();
}
}
}
void renderBunFrame(
int frame,
struct BunRenderer *bunRenderer
) {
int bun;
frame %= FRAMES_FOR_SCREEN;
for (bun = 0; bun < BUN_COUNT; ++bun) {
renderBun(
allBunPositionsByFrame[frame][bun][0],
allBunPositionsByFrame[frame][bun][1],
bunRenderer->screenDefinition,
bunRenderer->activeScreenBufferDetails,
&bunClearForScreen[bunRenderer->activeScreenBufferDetails->currentBuffer][bun]
);
}
hasBunClear[bunRenderer->activeScreenBufferDetails->currentBuffer] = 1;
}
void teardownBunRenderer() {
}

38
bun.h
View File

@ -3,31 +3,23 @@
#include "screen.h"
#define FRAMES_FOR_SCREEN (60)
#define BUN_COUNT (12)
#define COOL_BUN_WIDTH (32)
#define COOL_BUN_WIDTH_BYTES (COOL_BUN_WIDTH / 8)
#define COOL_BUN_HEIGHT (32)
#define COOL_BUN_PLANES (2)
#define COOL_BUN_LAST_ROW (COOL_BUN_HEIGHT - 1)
#define COOL_BUN_LAST_ROW_BYTES (COOL_BUN_LAST_ROW * COOL_BUN_WIDTH_BYTES)
struct BunRenderer {
struct ScreenDefinition *screenDefinition;
struct ActiveScreenBufferDetails *activeScreenBufferDetails;
};
#define COOL_BUN_PLANE_SIZE (COOL_BUN_WIDTH_BYTES * COOL_BUN_HEIGHT)
#define COOL_BUN_MEMORY_SIZE (COOL_BUN_PLANE_SIZE * COOL_BUN_PLANES)
void setupBunRenderer(
struct BunRenderer *,
struct ScreenDefinition *,
struct ActiveScreenBufferDetails *
void setupBun(void);
void renderBun(
int x,
int y,
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen
);
void teardownBun(void);
void renderBunFrame(
int frame,
struct BunRenderer *
);
void clearCurrentBuns(
struct BunRenderer *
);
void teardownBunRenderer(void);
void calculateNeededRedrawRanges(
int frame,
uint16_t redrawRanges[BUN_COUNT][4]
);
#endif

BIN
bun_test

Binary file not shown.

View File

@ -1,30 +0,0 @@
#include <stdio.h>
#include "bun.h"
#include "cutest/CuTest.h"
void *coolbun;
void TBun_calculateBunPositions(CuTest *tc) {
printf("wow\n");
}
CuSuite *BunSuite() {
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, TBun_calculateBunPositions);
}
int main(void) {
CuString *output = CuStringNew();
CuSuite *suite = CuSuiteNew();
CuSuiteAddSuite(suite, BunSuite());
CuSuiteRun(suite);
CuSuiteSummary(suite, output);
CuSuiteDetails(suite, output);
printf("%s\n", output->buffer);
return 0;
}

Binary file not shown.

BIN
demo.gif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 892 KiB

View File

@ -1,435 +0,0 @@
#!/usr/bin/env ruby
require 'rmagick'
# [ ] load the image
# [ ] map each pixel to a 12 bit color, with pixels less than 25% transparent as mask
# [ ] sort the color counts
# [ ] transparent pixels become the mask
# [ ] turn the big color counts into three bitplames worth of data
# [ ] turn the little color counts into up to 8 sprites worth of data strips & color changes
image = Magick::Image.read('topaz-narrow.png').first
rows = []
class MaskPixel
def initialize; end
def color? = false
def ==(other)
other.is_a?(MaskPixel)
end
end
class Color
attr_reader :red, :green, :blue
def initialize(red:, green:, blue:)
@red = red
@green = green
@blue = blue
end
WHITE = new(red: 15, green: 15, blue: 15)
BLACK = new(red: 0, green: 0, blue: 0)
TRANSPARENT = new(red: -1, green: -1, blue: -1)
def ==(other)
red == other.red && green == other.green && blue == other.blue
end
def transparent?
red == -1 && green == -1 && blue == -1
end
def -(other)
red - other.red + green - other.green + blue - other.blue
end
def for_diff
2 * red * red + 4 * green * green + 3 * blue * blue
end
alias eql? ==
def hash
red * 256 + green * 16 + blue
end
end
class BitplanePixel
attr_reader :color
def initialize(color:)
@color = color
end
def color? = true
end
MAX_ALPHA = Magick::QuantumRange * 0.25
BIT_SHIFT = Math.log2(Magick::QuantumRange + 1) - 4
class PixelRow
include Enumerable
def initialize
@row = []
end
def add(pixel:, x:)
@row[x] = pixel
end
def each(&block)
@row.each(&block)
end
def prioritized_colors
colors_with_usage.sort_by(&:last).reverse.map(&:first)
end
private
def colors_with_usage
last = nil
count = 0
@row.find_all(&:color?).each_with_object({}) do |pixel, obj|
if last != pixel.color
last = pixel.color
count = 1
end
count += count
obj[pixel.color] ||= 0
obj[pixel.color] += count
end
end
end
class RowColors
def initialize; end
end
class RowColorCalculator
MAX_BITPLANE_COLORS = 8
MAX_SPRITE_COLORS = 8
def self.calculate(row:)
prioritized_colors = row.prioritized_colors
bitplane_pixels_by_color = {
Color::TRANSPARENT => 0,
Color::BLACK => 1,
Color::WHITE => 2
}
sprite_pixels_by_color = {}
colors_by_bitplane_pixel = {}
colors_by_sprite_pixel = {}
prioritized_colors.each do |color|
next if bitplane_pixels_by_color.keys.include?(color)
closest_matches = bitplane_pixels_by_color.keys.reject(&:transparent?).map do |bp_color|
[(bp_color.for_diff - color.for_diff).abs, bp_color]
end.compact
closest_match = closest_matches.min_by(&:first)
if bitplane_pixels_by_color.values.max == MAX_BITPLANE_COLORS - 1
bitplane_pixels_by_color[color] = bitplane_pixels_by_color[closest_match.last]
max_sprite_value = sprite_pixels_by_color.values.max
if !max_sprite_value || max_sprite_value < MAX_SPRITE_COLORS - 1
new_pixel_index = colors_by_sprite_pixel.count
sprite_pixels_by_color[color] = new_pixel_index
colors_by_sprite_pixel[new_pixel_index] = color
end
else
new_pixel_index = colors_by_bitplane_pixel.count + 3
bitplane_pixels_by_color[color] = new_pixel_index
colors_by_bitplane_pixel[new_pixel_index] = color
end
end
{
bitplane_pixels_by_color:,
sprite_pixels_by_color:,
colors_by_bitplane_pixel:,
colors_by_sprite_pixel:
}
end
end
class RowMaskBitplaneCalculator
def self.calculate(row:)
bits = row.map { |p| p.is_a?(MaskPixel) ? 0 : 1 }
bits.each_slice(8).map do |pixels|
byte = 0
pixels.each_with_index do |pixel, index|
bit = 7 - index
byte |= (pixel << bit)
end
byte
end
end
end
class RowBitplaneCalculator
def self.calculate(row:, bitplane_pixels_by_color:)
output_pixels = row.map do |pixel|
next 0 if pixel.is_a?(MaskPixel)
bitplane_pixels_by_color[pixel.color] || 0
end
bitplanes = [[], [], []]
output_pixels.each_slice(8) do |pixels|
bits = [0] * 3
pixels.each_with_index do |pixel, index|
bit = 7 - index
3.times do |i|
bits[i] |= (((pixel >> i) & 1) << bit)
end
end
3.times do |i|
bitplanes[i] << bits[i]
end
end
bitplanes
end
end
class Sprite
attr_reader :x, :y, :color, :pixels
# @!attribute color
# @return Color
def initialize(x:, y:, color:)
@x = x
@y = y
@color = color
@pixels = [0] * 16
end
def add_pixel(x:, index:)
return if x - @x >= 16
@pixels[x - @x] = index
end
end
class RowSpriteCalculator
def self.calculate(y:, row:, sprite_pixels_by_color:)
sprites_by_color = {}
row.each_with_index.map do |pixel, x|
next if pixel.is_a?(MaskPixel)
sprite_pixel = sprite_pixels_by_color[pixel.color]
next unless sprite_pixel
sprite = sprites_by_color[pixel.color]
unless sprite
sprite = Sprite.new(y:, x:, color: pixel.color)
sprites_by_color[pixel.color] = sprite
end
sprite.add_pixel(x:, index: 1)
end
sprites_by_color
end
end
module Amiga
class Util
TOTAL_HEIGHT = 256
TOP_OFFSET = 44
LEFT_OFFSET = 128 + 64
SPRITE_HEIGHT = TOTAL_HEIGHT + TOP_OFFSET
def self.color_to_amiga_word(color:)
(color.blue + (color.green << 4) + (color.red << 8))
end
def self.sprposctl(x:, y:)
y += TOP_OFFSET
x += LEFT_OFFSET
sprpos = ((y & 0xff) << 8) +
((x & 0x1fe) >> 1)
sprctl = (((y + TOTAL_HEIGHT) & 0xff) << 8) +
((y & 0x100) >> 6) +
(((y + TOTAL_HEIGHT) & 0x100) >> 7) +
(x & 1)
{ sprpos:, sprctl: }
end
end
class BitplaneCopperlistFactory
def self.build(colors_by_bitplane_pixel:)
5.times.map do |color_index|
color = colors_by_bitplane_pixel[color_index + 3] || Color::BLACK
Amiga::Util.color_to_amiga_word(color:)
end.pack('n*')
end
end
class BitplaneDataFactory
def self.build(bitplanes:)
bitplanes.map do |data|
data.pack('C*')
end
end
end
class BitplaneMaskDataFactory
def self.build(bitplane:)
bitplane.pack('C*')
end
end
class SpriteCopperlistFactory
# @param sprites [Array<Sprite>]
def self.build(sprites:, y_offset:)
obj = []
8.times do |sprite_index|
color = 0
sprpos = 0
sprctl = 0
sprite = sprites[sprite_index]
if sprite
result = Amiga::Util.sprposctl(x: sprite.x, y: sprite.y + y_offset)
color = Amiga::Util.color_to_amiga_word(color: sprite.color)
sprpos = result[:sprpos]
sprctl = result[:sprctl]
end
obj << color
obj << sprpos
obj << sprctl
end
obj.pack('n*')
end
end
class SpriteDataFactory
def self.build(sprites:)
sprite_out = [''] * 8
sprites_with_bitplane = sprites.zip([0, 1] * 4)
8.times do |sprite_index|
sprite, bitplane = sprites_with_bitplane[sprite_index]
2.times do |current_bitplane|
result = 0
if bitplane == current_bitplane
sprite.pixels.each_with_index do |pixel, bit|
result |= (pixel << (15 - bit))
end
end
sprite_out[sprite_index] += [result].pack('n*')
end
end
sprite_out
end
end
end
image.each_pixel do |px, x, y|
rows[y] ||= PixelRow.new
pixel = if px.alpha < MAX_ALPHA
MaskPixel.new
else
BitplanePixel.new(
color: Color.new(
red: px.red >> BIT_SHIFT,
green: px.green >> BIT_SHIFT,
blue: px.blue >> BIT_SHIFT
)
)
end
rows[y].add(pixel:, x:)
end
copper_colors = ''
topaz_bitplanes = [''] * 3
sprite_copperlist = ''
sprite_data = [''] * 8
mask_bitplane = ''
8.times do |i|
result = Amiga::Util.sprposctl(x: 319, y: 0)
sprite_data[i] = [result[:sprpos], result[:sprctl]].pack('n*')
end
rows.each_with_index do |row, y_offset|
result = RowColorCalculator.calculate(row:)
bitplane_pixels_by_color = result[:bitplane_pixels_by_color]
sprite_pixels_by_color = result[:sprite_pixels_by_color]
colors_by_bitplane_pixel = result[:colors_by_bitplane_pixel]
bitplanes = RowBitplaneCalculator.calculate(row:, bitplane_pixels_by_color:)
sprites = RowSpriteCalculator.calculate(y: y_offset, row:, sprite_pixels_by_color:).values
mask = RowMaskBitplaneCalculator.calculate(row:)
mask_bitplane += Amiga::BitplaneMaskDataFactory.build(bitplane: mask)
copper_colors += Amiga::BitplaneCopperlistFactory.build(colors_by_bitplane_pixel:)
raw_bitplanes = Amiga::BitplaneDataFactory.build(bitplanes:)
sprite_copperlist += Amiga::SpriteCopperlistFactory.build(sprites:, y_offset:)
raw_sprite_data = Amiga::SpriteDataFactory.build(sprites:)
raw_bitplanes.each_with_index do |raw, index|
topaz_bitplanes[index] += raw
end
raw_sprite_data.each_with_index do |raw, index|
sprite_data[index] += raw
end
end
8.times do |i|
sprite_data[i] += [0, 0].pack('n*')
end
File.open('copper-colors', 'wb') { |fh| fh.print copper_colors }
File.open('topaz-bitplane', 'wb') { |fh| fh.print topaz_bitplanes.join('') }
File.open('mask-bitplane', 'wb') { |fh| fh.print mask_bitplane }
File.open('sprite-copperlist', 'wb') { |fh| fh.print sprite_copperlist }
File.open('sprite-data', 'wb') { |fh| fh.print sprite_data.join('') }

View File

@ -1,30 +1,4 @@
XDEF _coolbun
XDEF _TopazBitplanes
XDEF _CopperColors
XDEF _SpriteCopperlist
XDEF _SpriteData
XDEF _MaskBitplane
SECTION Topaz,Data_C
_coolbun:
INCBIN "images/bun small.raw"
CNOP 0,4
_TopazBitplanes:
INCBIN "topaz-bitplane"
CNOP 0,4
_CopperColors:
INCBIN "copper-colors"
CNOP 0,4
_SpriteCopperlist:
INCBIN "sprite-copperlist"
CNOP 0,4
_SpriteData:
INCBIN "sprite-data"
CNOP 0,4
_MaskBitplane:
INCBIN "mask-bitplane"

Binary file not shown.

View File

@ -1,77 +0,0 @@
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <exec/exec.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <devices/input.h>
#include <intuition/intuition.h>
static struct MsgPort *keyboardMessagePort = NULL;
static struct IOStdReq *keyboardIO = NULL;
static struct Interrupt keyboardInterrupt;
extern far ULONG keyboardPressed;
extern struct InputEvent * __asm stupidKeyboardHandler(
register __a0 struct InputEvent *input,
register __a1 APTR id
);
void setupKeyboard(void) {
if (keyboardMessagePort = CreatePort(NULL, NULL)) {
if (keyboardIO = (struct IOStdReq *)CreateExtIO(
keyboardMessagePort,
sizeof(struct IOStdReq)
)) {
// OpenDevice returns 0 if successful
if (!OpenDevice(
"input.device",
0,
(struct IORequest *)keyboardIO,
0
)) {
keyboardInterrupt.is_Node.ln_Type = NT_INTERRUPT;
keyboardInterrupt.is_Node.ln_Pri = 100;
keyboardInterrupt.is_Node.ln_Name = (STRPTR)"cool bun";
keyboardInterrupt.is_Code = (void (*)())&stupidKeyboardHandler;
keyboardIO->io_Data = (void *)&keyboardInterrupt;
keyboardIO->io_Command = IND_ADDHANDLER;
DoIO((struct IORequest *)keyboardIO);
}
}
}
}
void teardownKeyboard(void) {
if (keyboardIO) {
keyboardIO->io_Data = (void *)&keyboardInterrupt;
keyboardIO->io_Command = IND_REMHANDLER;
DoIO((struct IORequest *)keyboardIO);
CloseDevice((struct IORequest *)keyboardIO);
DeleteIORequest((struct IORequest *)keyboardIO);
keyboardIO = NULL;
}
if (keyboardMessagePort) {
DeleteMsgPort(keyboardMessagePort);
keyboardMessagePort = NULL;
}
}
int main(void) {
setupKeyboard();
while (!keyboardPressed) {}
teardownKeyboard();
return 0;
}

BIN
left_side

Binary file not shown.

View File

@ -1,90 +0,0 @@
/**
* What do we need
* * [ ] screen setup
*/
#include <hardware/custom.h>
#include <hardware/cia.h>
#include <clib/graphics_protos.h>
#include "system/system.h"
#include "system/copper.h"
#include "system/blitter.h"
#include "screen.h"
extern struct Custom far custom;
extern struct CIA far ciaa;
uint16_t custom_color = (uint16_t)offsetof(Custom, color);
uint16_t custom_sprite = (uint16_t)offsetof(Custom, sprpt);
uint16_t custom_sprite_control = (uint16_t)offsetof(Custom, spr);
extern unsigned char chip coolbun[];
int main(void) {
struct ScreenDefinition screenDefinition;
struct ActiveScreenBufferDetails activeScreenBufferDetails;
uint16_t *copperlist, *currentCopperlist;
void *copperlistBitplanePointers[8][2];
int i, plane;
allocateDoubleBufferedScreenMemory(
&screenDefinition,
&activeScreenBufferDetails,
320,
256,
2
);
copperlist = prepareNewCopperlist(300);
currentCopperlist = addDisplayToCopperlist(
copperlist,
&screenDefinition,
&activeScreenBufferDetails,
&copperlistBitplanePointers
);
COPPERLIST_MOVE(currentCopperlist, custom_color, 0x3a6);
COPPERLIST_MOVE(currentCopperlist, custom_color + 2, 0x000);
COPPERLIST_MOVE(currentCopperlist, custom_color + 4, 0xfff);
currentCopperlist = setUpEmptySpritesInCopperlist(currentCopperlist);
endCopperlist(currentCopperlist);
takeOverSystem();
setCopperlist(copperlist);
setUpDisplay((uint32_t)screenDefinition.bitplanes);
// Render a cut off bun at -8x50
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, 8);
custom.bltcon1 = BLTCON1(BLITTER_DESCENDING, 8);
custom.bltapt = coolbun + (plane * 4 * 32) + (31 * 4) + 2;
custom.bltdpt = activeScreenBufferDetails.planes[plane] + ((50 + 31) * 320 / 8) + 2;
custom.bltafwm = 0xffff;
custom.bltalwm = 0x00ff;
custom.bltamod = 0;
custom.bltdmod = 40 - 4;
custom.bltsize = 2 + (32 << 6);
WaitBlit();
}
while (1) {
if ((ciaa.ciapra >> 6) != 3) break;
}
giveBackSystem();
freeCopperlist(copperlist);
teardownScreen(&screenDefinition);
}

BIN
main

Binary file not shown.

450
main.c
View File

@ -1,391 +1,195 @@
#include <stdio.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <exec/exec.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <devices/input.h>
#include <hardware/custom.h>
#include <hardware/dmabits.h>
#include <hardware/cia.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include "system/blitter.h"
#include "system/copper.h"
#include "system/system.h"
#include "system/sprite.h"
#include "screen.h"
#include "types.h"
#include "bun.h"
/**
* This barely gets 50fps on an 020 but I'm leaving it for now.
* The demo is definitely CPU bound.
*
* Potential improvements:
*
* [ ] Precalculate even more of bun.c. This may get 50fps on an A500 if I do this.
* It would require more significant caching of as much stuff as possible.
* The A500 is spending entirely too much time on CPU tasks.
* [ ] Topaz re-rendering is limited to squares or rows that changed in the last frame.
* I tried this once but I need a more precise way of redrawing those areas.
* [ ] Cool bun clears and re-renders happen in the same pass.
* This would likely mean extending the cool bun art to have a blank word on the left,
* and enough blank rows above and below to cover clearing areas above and below.
*/
extern struct Custom far custom;
extern struct CIA far ciaa;
// change to 0 to not render sprites
#define RENDER_SPRITES (1)
// this should be large enough to hold one bitplane of the largest object
// you are blitting, plus one additional word on each side
#define SCRATCH_AREA_WIDTH_BYTES (8)
#define SCRATCH_AREA_HEIGHT_ROWS (34)
#define SCRATCH_AREA_MEMORY_SIZE (SCRATCH_AREA_WIDTH_BYTES * SCRATCH_AREA_HEIGHT_ROWS)
struct ScreenDefinition screenDefinition;
struct ActiveScreenBufferDetails activeScreenBufferDetails;
volatile short *dbg = (volatile short *)0x100;
/**
* The locations within the copperlist data where the bitplanes are referenced.
* We change these areas of memory directly to implement double buffering.
* Addresses are to the high, then low, word of the plane memory address in the copperlist.
*
* @see addDisplayToCopperlist
*/
unsigned char *scratchArea;
struct ScreenSetup screenSetup;
struct CurrentScreen currentScreen;
void *copperlistBitplanePointers[8][2];
void *copperlistSpritePointers[8];
#define offsetof(s, m) &((struct s *)0)->m
uint16_t custom_color = (uint16_t)offsetof(Custom, color);
uint16_t custom_sprite = (uint16_t)offsetof(Custom, sprpt);
uint16_t custom_sprite_control = (uint16_t)offsetof(Custom, spr);
extern uint8_t chip TopazBitplanes[];
extern uint16_t chip CopperColors[];
extern uint16_t chip SpriteCopperlist[];
extern uint16_t chip SpriteData[];
extern uint8_t chip MaskBitplane[];
#define BUN_COUNT (12)
#define BUN_SPEED (2)
#define TOPAZ_WIDTH_PIXELS (160)
#define TOPAZ_WIDTH_BYTES (TOPAZ_WIDTH_PIXELS / 8)
#define TOPAZ_WIDTH_WORDS (TOPAZ_WIDTH_PIXELS / 16)
short int bunPositions[BUN_COUNT][2];
void renderTopaz(void) {
int plane;
#define BUN_MAX_RANGE (31 + 320 - 1)
uint16_t bltcmod;
uint8_t *bltbpt;
#define BUN_HORIZ_DISTANCE_BETWEEN_BUNS ((BUN_MAX_RANGE / 4) - COOL_BUN_WIDTH)
#define BUN_TOTAL_HORIZ_DISTANCE (BUN_HORIZ_DISTANCE_BETWEEN_BUNS + COOL_BUN_WIDTH)
#define BUN_ROW_START (10)
#define BUN_VERT_DISTANCE_BETWEEN_BUNS (20)
#define BUN_TOTAL_VERT_DISTANCE (COOL_BUN_HEIGHT + BUN_VERT_DISTANCE_BETWEEN_BUNS)
#define FRAME_MAX (BUN_TOTAL_HORIZ_DISTANCE / BUN_SPEED)
bltcmod = screenDefinition.byteWidth - TOPAZ_WIDTH_BYTES;
bltbpt = TopazBitplanes;
void calculateBunPositions(
uint16_t frame,
short int bunPositions[BUN_COUNT][2],
struct ScreenSetup *screenSetup
) {
int x, y, row, column, current;
for (plane = 0; plane < 3; ++plane) {
custom.bltcon0 = BLTCON0(0xca, 1, 1, 1, 1, 0);
custom.bltcon1 = 0;
custom.bltafwm = 0xffff;
custom.bltalwm = 0xffff;
custom.bltapt = MaskBitplane;
custom.bltbpt = bltbpt;
custom.bltcpt = activeScreenBufferDetails.planes[plane] + 8;
custom.bltdpt = activeScreenBufferDetails.planes[plane] + 8;
custom.bltamod = 0;
custom.bltbmod = 0;
custom.bltcmod = bltcmod;
custom.bltdmod = bltcmod;
custom.bltsize = BLTSIZE(TOPAZ_WIDTH_WORDS, 256);
frame %= FRAME_MAX;
bltbpt += TOPAZ_WIDTH_BYTES * 256;
for (current = 0; current < BUN_COUNT; ++current) {
row = current / 4;
column = current % 4;
WaitBlit();
}
x = column * BUN_TOTAL_HORIZ_DISTANCE + frame * BUN_SPEED;
if (row == 1) {
//x += BUN_TOTAL_HORIZ_DISTANCE / 2;
}
x %= BUN_MAX_RANGE;
x -= 31;
y = BUN_ROW_START + row * BUN_TOTAL_VERT_DISTANCE;
#define MOSTLY_TOPAZ_TOP_BOTTOM_CROP (30)
void renderMostlyTopaz(void) {
int plane;
uint16_t bltcmod;
uint8_t *bltbpt;
bltcmod = screenDefinition.byteWidth - TOPAZ_WIDTH_BYTES;
bltbpt = TopazBitplanes;
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = BLTCON0(0xca, 1, 1, 1, 1, 0);
custom.bltcon1 = 0;
custom.bltafwm = 0xffff;
custom.bltalwm = 0xffff;
custom.bltapt = MaskBitplane + (MOSTLY_TOPAZ_TOP_BOTTOM_CROP * TOPAZ_WIDTH_BYTES);
custom.bltbpt = bltbpt + (MOSTLY_TOPAZ_TOP_BOTTOM_CROP * TOPAZ_WIDTH_BYTES);
custom.bltcpt = MOSTLY_TOPAZ_TOP_BOTTOM_CROP * screenDefinition.byteWidth + activeScreenBufferDetails.planes[plane] + 8;
custom.bltdpt = MOSTLY_TOPAZ_TOP_BOTTOM_CROP * screenDefinition.byteWidth + activeScreenBufferDetails.planes[plane] + 8;
custom.bltamod = 0;
custom.bltbmod = 0;
custom.bltcmod = bltcmod;
custom.bltdmod = bltcmod;
custom.bltsize = BLTSIZE(TOPAZ_WIDTH_WORDS, 256 - MOSTLY_TOPAZ_TOP_BOTTOM_CROP * 2);
bltbpt += TOPAZ_WIDTH_BYTES * 256;
WaitBlit();
}
}
#define COPPERLIST_SIZE (10000)
uint16_t *copperlist;
void buildCopperlist(void) {
uint32_t spriteDataPointer;
uint16_t *currentCopperlist,
*currentCopperColors,
*currentSpriteCopperlist;
int i, j, y;
uint16_t spriteSetupRegisters[3];
copperlist = prepareNewCopperlist(COPPERLIST_SIZE);
currentCopperlist = addDisplayToCopperlist(
copperlist,
&screenDefinition,
&activeScreenBufferDetails,
&copperlistBitplanePointers
);
currentCopperColors = CopperColors;
currentSpriteCopperlist = SpriteCopperlist;
COPPERLIST_MOVE(currentCopperlist, custom_color, 0x3a6);
COPPERLIST_MOVE(currentCopperlist, custom_color + 2, 0x000);
COPPERLIST_MOVE(currentCopperlist, custom_color + 4, 0xfff);
if (RENDER_SPRITES) {
for (i = 0; i < 8; ++i) {
spriteDataPointer = (uint32_t)&SpriteData;
spriteDataPointer += ((256 + 2) * 4) * i;
COPPERLIST_MOVE_POINTER(
currentCopperlist,
custom_sprite + i * 4,
spriteDataPointer
);
}
} else {
currentCopperlist = setUpEmptySpritesInCopperlist(currentCopperlist);
}
for (y = 0; y < 256; ++y) {
if (RENDER_SPRITES) {
for (i = 0; i < 8; ++i) {
spriteSetupRegisters[0] = custom_color + 32 + (
// sprite color group
(i / 2) * 4 +
// 0 is transparent
1 +
i % 2
) * 2;
spriteSetupRegisters[1] = custom_sprite_control + i * 8;
spriteSetupRegisters[2] = custom_sprite_control + i * 8 + 2;
for (j = 0; j < 3; ++j) {
COPPERLIST_MOVE(
currentCopperlist,
spriteSetupRegisters[j],
*(currentSpriteCopperlist++)
);
}
}
} else {
//printf("Skipping render\n");
}
for (i = 3; i < 8; ++i) {
COPPERLIST_MOVE(
currentCopperlist,
custom_color + (i * 2),
*(currentCopperColors++)
);
}
COPPERLIST_WAIT(
currentCopperlist,
(31 + (256 / 4)),
(44 + y),
0xFFFE
);
}
endCopperlist(currentCopperlist);
}
static struct MsgPort *keyboardMessagePort = NULL;
static struct IOStdReq *keyboardIO = NULL;
static struct Interrupt keyboardInterrupt;
extern far ULONG keyboardPressed;
extern struct InputEvent * __asm KeyboardHandler(
register __a0 struct InputEvent *input,
register __a1 APTR id
);
void setupKeyboard(void) {
if (keyboardMessagePort = CreatePort(NULL, NULL)) {
if (keyboardIO = (struct IOStdReq *)CreateExtIO(
keyboardMessagePort,
sizeof(struct IOStdReq)
)) {
// OpenDevice returns 0 if successful
if (!OpenDevice(
"input.device",
0,
(struct IORequest *)keyboardIO,
0
)) {
keyboardInterrupt.is_Node.ln_Type = NT_INTERRUPT;
keyboardInterrupt.is_Node.ln_Pri = 100;
keyboardInterrupt.is_Node.ln_Name = (STRPTR)"cool bun";
keyboardInterrupt.is_Code = (void (*)())&KeyboardHandler;
keyboardIO->io_Data = (void *)&keyboardInterrupt;
keyboardIO->io_Command = IND_ADDHANDLER;
DoIO((struct IORequest *)keyboardIO);
}
}
}
}
void teardownKeyboard(void) {
if (keyboardIO) {
keyboardIO->io_Data = (void *)&keyboardInterrupt;
keyboardIO->io_Command = IND_REMHANDLER;
DoIO((struct IORequest *)keyboardIO);
CloseDevice((struct IORequest *)keyboardIO);
DeleteIORequest((struct IORequest *)keyboardIO);
keyboardIO = NULL;
}
if (keyboardMessagePort) {
DeleteMsgPort(keyboardMessagePort);
keyboardMessagePort = NULL;
bunPositions[current][0] = x;
bunPositions[current][1] = y;
}
}
int main(void) {
int i;
uint16_t *copperlist, *currentCopperlist, result;
int i, j, x, y, plane;
int blitShiftRight, memoryXOffset, blitWidth;
uint32_t wow, wow2;
struct BunRenderer bunRenderer;
uint16_t redrawRanges[BUN_COUNT][4];
color_t colors[8];
printf("\nCool bun blitter, copper, and sprite demo by John Bintz\n");
printf("\n");
printf("This is my first real go at writing graphics code for the Amiga.\n");
printf("It's a combination of C (SAS/C) and Assembler (DevPac), with a Ruby\n");
printf("script to do some image processing. The screen only uses three\n");
printf("bitplanes -- one color is the background, two colors are the flying\n");
printf("cool bun logo white and black, and the remaining 5 colors are used\n");
printf("by the Topaz smiling art. The Ruby script will process the PNG file\n");
printf("and figure out the best 5 colors (plus b&w) for that line of the\n");
printf("image, setting the colors via copperlist for that line.\n");
printf("It also builds the clipping mask for the blitter.\n\n");
colors[0] = 0x09b8;
colors[1] = 0x0000;
colors[2] = 0x0fff;
colors[3] = 0x000f;
printf("And, I'm also using sprites to add more colors to the Topaz art.\n");
printf("The Ruby script will figure out what small areas of each line weren't\n");
printf("covered by the bitplane colors and use the 8 available sprites,\n");
printf("changing the colors on each line via copper, to fill in the gaps.\n");
printf("Cool buns are animated via blitter rather than sprites, but I\n");
printf("managed to get it to run at a decent speed regardless.\n");
setupBun();
setupScreen(&screenSetup, SCREEN_WIDTH, SCREEN_HEIGHT, 3);
setupInitialCurrentScreen(&screenSetup, &currentScreen);
printf("\nEnjoy, and thanks for watching!\n");
printf("John (theindustriousrabbit.com)\n\n");
// blitter copy the first bitplane row down to the second
allocateDoubleBufferedScreenMemory(
&screenDefinition,
&activeScreenBufferDetails,
SCREEN_WIDTH,
SCREEN_HEIGHT,
3
);
copperlist = prepareNewCopperlist();
setupBunRenderer(
&bunRenderer,
&screenDefinition,
&activeScreenBufferDetails
);
buildCopperlist();
/*
copperlist debugging
for (i = 0; i < 20; ++i) {
printf(
"%x %x %x %x\n",
*(copperlist + (i * 4)),
*(copperlist + (i * 4) + 1),
*(copperlist + (i * 4) + 2),
*(copperlist + (i * 4) + 3)
);
}
*/
setupKeyboard();
takeOverSystem();
setCopperlist(copperlist);
setUpDisplay((uint32_t)screenDefinition.bitplanes);
setUpDisplay((uint32_t)screenSetup.bitplanes);
renderTopaz();
swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails);
renderTopaz();
swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails);
updateDisplayInCopperList(
&screenDefinition,
&activeScreenBufferDetails,
copperlistBitplanePointers
currentCopperlist = addDisplayToCopperlist(
copperlist,
&screenSetup,
&currentScreen,
&copperlistBitplanePointers
);
i = 0;
currentCopperlist = setUpEmptySpritesInCopperlist(currentCopperlist);
while (1) {
WaitTOF();
*(currentCopperlist++) = custom_color;
*(currentCopperlist++) = 0x000;
swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails);
*(currentCopperlist++) = custom_color + 2;
*(currentCopperlist++) = 0x000;
clearCurrentBuns(&bunRenderer);
renderBunFrame(i, &bunRenderer);
renderMostlyTopaz();
*(currentCopperlist++) = custom_color + 4;
*(currentCopperlist++) = 0xfff;
updateDisplayInCopperList(
&screenDefinition,
&activeScreenBufferDetails,
copperlistBitplanePointers
);
*(currentCopperlist++) = custom_color + 6;
*(currentCopperlist++) = 0x00F;
if (keyboardPressed) break;
if ((ciaa.ciapra >> 6) != 3) break;
for (y = 0; y < 256; ++y) {
*(currentCopperlist++) = 1 + (31 << 1) + ((44 + y) << 8);
*(currentCopperlist++) = 0xFFFE;
*(currentCopperlist++) = custom_color;
*(currentCopperlist++) = 0x9b8;
i++;
if (i > FRAMES_FOR_SCREEN) i = 0;
*(currentCopperlist++) = 1 + ((31 + (320 / 4)) << 1) + ((44 + y) << 8);
*(currentCopperlist++) = 0xFFFE;
*(currentCopperlist++) = custom_color;
*(currentCopperlist++) = 0x000;
}
// somthing in here causes an A500 in KS 1.3 to crash
giveBackSystem();
teardownKeyboard();
endCopperlist(currentCopperlist);
teardownScreen(&screenDefinition);
for (i = 0; i < FRAME_MAX * 6; ++i) {
calculateBunPositions(i, bunPositions, &screenSetup);
swapCurrentScreenBuffer(&screenSetup, &currentScreen);
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = 0xc0 + (1 << 8);
custom.bltcon1 = 0;
custom.bltadat = 0x0000;
custom.bltafwm = 0xffff;
custom.bltalwm = 0xffff;
custom.bltdpt = currentScreen.planes[plane];
custom.bltdmod = 0;
custom.bltsize = screenSetup.byteWidth / 2 + (screenSetup.height << 6);
WaitBlit();
}
for (j = 0; j < BUN_COUNT; ++j) {
renderBun(
bunPositions[j][0],
bunPositions[j][1],
&screenSetup,
&currentScreen
);
}
updateDisplayInCopperList(
&screenSetup,
&currentScreen,
copperlistBitplanePointers
);
WaitTOF();
}
/*
for (i = 0; i < 200; ++i) {
WaitTOF();
}
*/
giveBackSystem();
teardownScreen(&screenSetup);
freeCopperlist(copperlist);
teardownBunRenderer();
teardownBun();
for (i = 0; i < BUN_COUNT; ++i) {
printf("%d %d\n", bunPositions[i][0], bunPositions[i][1]);
}
return 0;
}

1604
marquee.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Binary file not shown.

View File

@ -1,90 +0,0 @@
/**
* What do we need
* * [ ] screen setup
*/
#include <hardware/custom.h>
#include <hardware/cia.h>
#include <clib/graphics_protos.h>
#include "system/system.h"
#include "system/copper.h"
#include "system/blitter.h"
#include "screen.h"
extern struct Custom far custom;
extern struct CIA far ciaa;
uint16_t custom_color = (uint16_t)offsetof(Custom, color);
uint16_t custom_sprite = (uint16_t)offsetof(Custom, sprpt);
uint16_t custom_sprite_control = (uint16_t)offsetof(Custom, spr);
extern unsigned char chip coolbun[];
int main(void) {
struct ScreenDefinition screenDefinition;
struct ActiveScreenBufferDetails activeScreenBufferDetails;
uint16_t *copperlist, *currentCopperlist;
void *copperlistBitplanePointers[8][2];
int i, plane;
allocateDoubleBufferedScreenMemory(
&screenDefinition,
&activeScreenBufferDetails,
320,
256,
2
);
copperlist = prepareNewCopperlist(300);
currentCopperlist = addDisplayToCopperlist(
copperlist,
&screenDefinition,
&activeScreenBufferDetails,
&copperlistBitplanePointers
);
COPPERLIST_MOVE(currentCopperlist, custom_color, 0x3a6);
COPPERLIST_MOVE(currentCopperlist, custom_color + 2, 0x000);
COPPERLIST_MOVE(currentCopperlist, custom_color + 4, 0xfff);
currentCopperlist = setUpEmptySpritesInCopperlist(currentCopperlist);
endCopperlist(currentCopperlist);
takeOverSystem();
setCopperlist(copperlist);
setUpDisplay((uint32_t)screenDefinition.bitplanes);
// Render a cut off bun at -8x50
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, 8);
custom.bltcon1 = BLTCON1(BLITTER_ASCENDING, 8);
custom.bltapt = coolbun + (plane * 4 * 32);
custom.bltdpt = activeScreenBufferDetails.planes[plane] + (50 * 320 / 8) + (40 - 4);
custom.bltafwm = 0xffff;
custom.bltalwm = 0xff00;
custom.bltamod = 0;
custom.bltdmod = 40 - 4;
custom.bltsize = 2 + (32 << 6);
WaitBlit();
}
while (1) {
if ((ciaa.ciapra >> 6) != 3) break;
}
giveBackSystem();
freeCopperlist(copperlist);
teardownScreen(&screenDefinition);
}

View File

@ -9,77 +9,66 @@
*/
#define TOTAL_SCREEN_SETUP_SIZE(s) ((s->width / 8) * s->height * s->bitplanes * 2)
/**
* Stores internal allocation details in screenSetup.
* Sets current
*/
void allocateDoubleBufferedScreenMemory(
struct ScreenDefinition *screenDefinition,
struct ActiveScreenBufferDetails *activeScreenBufferDetails,
void setupScreen(
struct ScreenSetup *screenSetup,
uint16_t width,
uint16_t height,
uint8_t bitplanes
) {
unsigned char *memory;
int buffer, plane;
screenDefinition->width = width;
screenDefinition->height = height;
screenDefinition->bitplanes = bitplanes;
screenSetup->width = width;
screenSetup->height = height;
screenSetup->bitplanes = bitplanes;
memory = (unsigned char *)AllocMem(
TOTAL_SCREEN_SETUP_SIZE(screenDefinition),
TOTAL_SCREEN_SETUP_SIZE(screenSetup),
MEMF_CLEAR | MEMF_CHIP
);
screenDefinition->memoryStart = memory;
screenDefinition->byteWidth = width / 8;
screenSetup->memoryStart = memory;
screenSetup->byteWidth = width / 8;
// memory is not interleaved
screenDefinition->nextBitplaneAdvance = screenDefinition->byteWidth * height;
screenDefinition->nextBufferAdvance = screenDefinition->nextBitplaneAdvance * bitplanes;
for (buffer = 0; buffer < 2; ++buffer) {
for (plane = 0; plane < bitplanes; ++plane) {
screenDefinition->bufferPlanes[buffer][plane] = screenDefinition->memoryStart +
buffer * screenDefinition->nextBufferAdvance +
plane * screenDefinition->nextBitplaneAdvance;
}
}
setActiveScreenBuffer(screenDefinition, activeScreenBufferDetails, 0);
screenSetup->nextBitplaneAdvance = screenSetup->byteWidth * height;
screenSetup->nextBufferAdvance = screenSetup->nextBitplaneAdvance * bitplanes;
}
void teardownScreen(
struct ScreenDefinition *screenDefinition
struct ScreenSetup *screenSetup
) {
FreeMem(
screenDefinition->memoryStart,
TOTAL_SCREEN_SETUP_SIZE(screenDefinition)
screenSetup->memoryStart,
TOTAL_SCREEN_SETUP_SIZE(screenSetup)
);
}
void setActiveScreenBuffer(
struct ScreenDefinition *screenDefinition,
struct ActiveScreenBufferDetails *currentScreen,
void setCurrentScreen(
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen,
short int buffer
) {
int plane;
currentScreen->currentBuffer = buffer;
for (plane = 0; plane < screenDefinition->bitplanes; ++plane) {
currentScreen->planes[plane] = screenDefinition->bufferPlanes[buffer][plane];
for (plane = 0; plane < screenSetup->bitplanes; ++plane) {
currentScreen->planes[plane] = screenSetup->memoryStart +
buffer * screenSetup->nextBufferAdvance +
plane * screenSetup->nextBitplaneAdvance;
}
}
void swapCurrentScreenBuffer(
struct ScreenDefinition *screenDefinition,
struct ActiveScreenBufferDetails *currentScreen
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen
) {
setActiveScreenBuffer(
screenDefinition,
currentScreen,
1 - currentScreen->currentBuffer
);
setCurrentScreen(screenSetup, currentScreen, 1 - currentScreen->currentBuffer);
}
void setupInitialCurrentScreen(
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen
) {
setCurrentScreen(screenSetup, currentScreen, 0);
}

View File

@ -6,7 +6,7 @@
#define SCREEN_WIDTH (320)
#define SCREEN_HEIGHT (256)
struct ScreenDefinition {
struct ScreenSetup {
// human entered
uint16_t width;
uint16_t height;
@ -17,36 +17,34 @@ struct ScreenDefinition {
uint16_t byteWidth;
uint16_t nextBitplaneAdvance;
uint16_t nextBufferAdvance;
unsigned char *bufferPlanes[2][8];
};
struct ActiveScreenBufferDetails {
struct CurrentScreen {
uint16_t currentBuffer;
unsigned char *planes[8];
};
void allocateDoubleBufferedScreenMemory(
struct ScreenDefinition *screenSetup,
struct ActiveScreenBufferDetails *currentScreen,
void setupScreen(
struct ScreenSetup *screenSetup,
uint16_t width,
uint16_t height,
uint8_t bitplanes
);
void teardownScreen(struct ScreenDefinition *screenSetup);
void teardownScreen(struct ScreenSetup *screenSetup);
void setActiveScreenBuffer(
struct ScreenDefinition *screenSetup,
struct ActiveScreenBufferDetails *currentScreen,
void setCurrentScreen(
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen,
short int buffer
);
void swapCurrentScreenBuffer(
struct ScreenDefinition *screenSetup,
struct ActiveScreenBufferDetails *currentScreen
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen
);
void setupInitialCurrentScreen(
struct ScreenDefinition *screenSetup,
struct ActiveScreenBufferDetails *currentScreen
struct ScreenSetup *screenSetup,
struct CurrentScreen *currentScreen
);
#endif

View File

@ -1,9 +1,4 @@
MAIN_OBJS = main.o images.o system.lib screen.o bun.o
32_objs = 32x50_bun.o system.lib screen.o images.o
33_objs = 33x50_bun.o system.lib screen.o images.o
left_side_objs = left_side.o system.lib screen.o images.o
right_side_objs = right_side.o system.lib screen.o images.o
any_position = any_position.o system.lib screen.o images.o
all: main
@ -13,27 +8,12 @@ all: main
.s.o:
genam -l $*.s
system.lib: system/system.o system/copper.o system/blitter.o system/debug.o
sc objectlibrary=system.lib system/system.o system/copper.o system/blitter.o system/debug.o
system.lib: system/system.o system/copper.o system/blitter.o
sc objectlibrary=system.lib system/system.o system/copper.o system/blitter.o
main: $(MAIN_OBJS)
sc link to main math=standard $(MAIN_OBJS)
sc link to main $(MAIN_OBJS)
32x50: $(32_objs)
sc link to 32x50 $(32_objs)
33x50: $(33_objs)
sc link to 33x50 $(33_objs)
left_side: $(left_side_objs)
sc link to left_side $(left_side_objs)
right_side: $(right_side_objs)
sc link to right_side $(right_side_objs)
any_position: $(any_position)
sc link to any_position $(any_position)
test: bun_test.o bun.o
sc link to bun_test identifierlength=32 math=standard bun_test.o bun.o cutest/CuTest.c
test: blitter_test.o blitter.o system.o
sc link to blitter_test identifierlength=32 math=standard blitter_test.o blitter.o cutest/CuTest.c system.o

Binary file not shown.

Binary file not shown.

View File

@ -1,14 +1,8 @@
#ifndef __BLITTER_H__
#define __BLITTER_H__
#define BLTSIZE(w, h) (w + (h << 6))
#define BLTCON0( \
minterm, aChan, bChan, cChan, dChan, shift \
) (minterm + (aChan << 11) + (bChan << 10) + (cChan << 9) + (dChan << 8) + (shift << 12))
#define BLTCON1(descending, shift) ((descending << 1) + (shift << 12))
#define BLITTER_ASCENDING (0)
#define BLITTER_DESCENDING (1)
#include "types.h"
#include "screen.h"
/*

View File

@ -7,15 +7,9 @@
extern struct Custom far custom;
uint16_t copperlistSize;
uint16_t * prepareNewCopperlist(uint16_t size_b) {
uint16_t *copperlist;
copperlistSize = size_b;
copperlist = AllocMem(
copperlistSize,
uint16_t * prepareNewCopperlist(void) {
uint16_t *copperlist = AllocMem(
COPPERLIST_SIZE,
MEMF_CHIP | MEMF_CLEAR
);
@ -26,9 +20,9 @@ uint16_t * prepareNewCopperlist(uint16_t size_b) {
void setCopperlist(uint16_t *copperlist) {
custom.cop1lc = copperlist;
custom.copjmp1 = 1;
//custom.copjmp1 = 1;
}
void freeCopperlist(uint16_t *copperlist) {
FreeMem(copperlist, copperlistSize);
FreeMem(copperlist, COPPERLIST_SIZE);
}

View File

@ -1,31 +1,11 @@
#ifndef __COPPER_H__
#define __COPPER_H__
#define COPPERLIST_SIZE (10000)
#include "../types.h"
/**
* Sets register to value over two Copper words.
* Side-effect: Advances ptr by 4.
*/
#define COPPERLIST_MOVE(ptr,register,value) \
*(ptr++) = register; \
*(ptr++) = value;
#define COPPERLIST_WAIT(ptr,x,y,mask) \
*(ptr++) = 1 + (x << 1) + (y << 8); \
*(ptr++) = mask;
/**
* Sets high/low registers to pointer value over four Copper words.
* Side-effect: Advances ptr by 8.
*/
#define COPPERLIST_MOVE_POINTER(ptr,register,pointerValue) \
*(ptr++) = register; \
*(ptr++) = (pointerValue >> 16); \
*(ptr++) = register + 2; \
*(ptr++) = (pointerValue & 0xffff);
uint16_t * prepareNewCopperlist(uint16_t size_b);
uint16_t * prepareNewCopperlist(void);
void setCopperlist(uint16_t *copperlist);
void freeCopperlist(uint16_t *copperlist);

View File

@ -1,11 +0,0 @@
#include "debug.h"
volatile short *dbg = (volatile short *)0x100;
/**
* Create a two-word write watch in the UAE debugger at memory location 0x100
* and call this function.
*/
void triggerUAEDebugger() {
*(dbg) = 0;
}

View File

@ -1,6 +0,0 @@
#ifndef __SYSTEM_DEBUG__
#define __SYSTEM_DEBUG__
void triggerUAEDebugger(void);
#endif

View File

@ -1,7 +0,0 @@
#define SPRPOS(x, y) (((y & 0xff) << 8) + ((x & 0x1fe) >> 1))
#define SPRCTL(x, y, height) ( \
((height & 0xff) << 8) + \
((y & 0x100) >> 6) + \
((height & 0x100) >> 7) + \
(x & 1) \
)

View File

@ -12,20 +12,15 @@
// copperlist
extern void initializeCopperlist(void *copperlist);
extern uint16_t* endCopperlist(uint16_t *copperlist);
/**
* This only adds bitplane pointers to the copperlist
* and sets it up for double buffering.
* You still need to configure the playfield hardware.
*/
extern uint16_t* addDisplayToCopperlist(
uint16_t *copperlist,
struct ScreenDefinition *,
struct ActiveScreenBufferDetails *,
struct ScreenSetup *,
struct CurrentScreen *,
void *copperlistBitplanePointers
);
extern void updateDisplayInCopperList(
struct ScreenDefinition *,
struct ActiveScreenBufferDetails *,
struct ScreenSetup *,
struct CurrentScreen *,
void *copperlistBitplanePointers
);
extern uint16_t* addColorsToCopperlist(uint16_t *copperlist, color_t[], int count);

View File

@ -9,9 +9,6 @@
XDEF _endCopperlist
XDEF _myWaitBlit
XDEF _WaitBOF
XDEF _KeyboardHandler
XDEF _keyboardPressed
XREF _custom
@ -32,8 +29,6 @@ FUNC_CNT SET FUNC_CNT-6
INCLUDE "hardware/custom.i"
INCLUDE "hardware/dmabits.i"
INCLUDE "hardware/intbits.i"
INCLUDE "exec/io.i"
INCLUDE "devices/inputevent.i"
; @param 1 Pointer to null terminated name of library
; @param 2 Minimum version of library, 0 for any
@ -61,69 +56,24 @@ RestoreRegister MACRO
MOVE.W Old\1,\1(A0)
ENDM
STRUCTURE ScreenDefinition,0
UWORD ScreenDefinition_width
UWORD ScreenDefinition_height
UWORD ScreenDefinition_bitplanes
ULONG ScreenDefinition_memoryStart
UWORD ScreenDefinition_byteWidth
UWORD ScreenDefinition_nextBitplaneAdvance
UWORD ScreenDefinition_nextBufferAdvance
ULONG ScreenDefinition_copperlistBitplanePointers
LABEL ScreenDefinition_SIZEOF
STRUCTURE ScreenSetup,0
UWORD ScreenSetup_width
UWORD ScreenSetup_height
UWORD ScreenSetup_bitplanes
ULONG ScreenSetup_memoryStart
UWORD ScreenSetup_byteWidth
UWORD ScreenSetup_nextBitplaneAdvance
UWORD ScreenSetup_nextBufferAdvance
ULONG ScreenSetup_copperlistBitplanePointers
LABEL ScreenSetup_SIZEOF
STRUCTURE ActiveScreenBufferDetails,0
UWORD ActiveScreenBufferDetails_currentBuffer
ActiveScreenBufferDetails_planes EQU SOFFSET
STRUCTURE CurrentScreen,0
UWORD CurrentScreen_currentBuffer
CurrentScreen_planes EQU SOFFSET
SOFFSET SET SOFFSET+(8*4)
LABEL ActiveScreenBufferDetails_SIZEOF
LABEL CurrentScreen_SIZEOF
; @see https://amigadev.elowar.com/read/ADCD_2.1/Devices_Manual_guide/node019A.html
; @register A0 struct InputEvent *
; @register A1 extra data about the event
; @output D0 The value of A0
_KeyboardHandler:
; @stack [RA,A0,current node]
MOVE.L A0,-(SP)
MOVE.L #0,-(SP)
_KeyboardHandler_CheckLoop:
CMP.B #IECLASS_RAWKEY,ie_Class(A0)
BNE.S _KeyboardHandler_NextEvent
MOVE.W ie_Code(A0),D0
AND.W #IECODE_UP_PREFIX,D0
SEQ _keyboardPressed
; if next_event:
; do the stack swap thing below
; else:
; change the A0 in the stack above it
TST.L (SP)
BNE.S _KeyboardHandler_hasLastEvent
MOVE.L (A0),4(SP)
BRA.S _KeyboardHandler_NextEvent
_KeyboardHandler_hasLastEvent:
; put the next event in the first pointer of the
; last event
MOVE.L A1,-(SP)
MOVE.L 4(SP),A1
MOVE.L (A0),(A1)
MOVE.L (SP)+,A1
_KeyboardHandler_NextEvent:
; next event is in first long of struct
MOVE.L (A0),D0
; store current node in stack
MOVE.L A0,(SP)
MOVE.L D0,A0
BNE.S _KeyboardHandler_CheckLoop
MOVE.L (SP)+,D0
MOVE.L (SP)+,D0
RTS
BPLCON0_COLOR EQU $200
M68K_LEVEL3_INTERRUPT_AUTOVECTOR EQU $6C
_takeOverSystem:
@ -131,15 +81,13 @@ _takeOverSystem:
OpenLibrary #GraphicsLibrary,#0
MOVE.L D0,GraphicsBase
MOVE.L $4,A6
CALLLIB _LVOForbid
MOVE.L D0,A6
MOVE.L gb_ActiView(A6),OldView
MOVE.L gb_copinit(A6),OldCopper
MOVE.L #0,A1
CALLLIB _LVOLoadView
CALLLIB _LVOWaitTOF
CALLLIB _LVOWaitTOF
CALLLIB _LVOOwnBlitter
CALLLIB _LVOWaitBlit
@ -150,14 +98,20 @@ _takeOverSystem:
PreserveRegister intreq
PreserveRegister adkcon
MOVE.L #0,A1
CALLLIB _LVOLoadView
CALLLIB _LVOWaitTOF
CALLLIB _LVOWaitTOF
LEA _custom,A0
; http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node0036.html
MOVE.W #$7FFF,intena(A0) ; disable all interrupts
; we need VERTB to use WaitTOF
; PORTS and EXTER give me access to the keyboard and mouse via OS interrupts
MOVE.W #INTF_SETCLR|INTF_INTEN|INTF_COPER|INTF_PORTS|INTF_EXTER|INTF_VERTB,intena(A0) ; enable master interrupt, copper, and VBR
MOVE.W #INTF_SETCLR|INTF_INTEN|INTF_COPER|INTF_VERTB,intena(A0) ; enable master interrupt, copper, and VBR
MOVE.W #$7FFF,dmacon(a0)
MOVE.W #DMAF_SETCLR|DMAF_MASTER|DMAF_COPPER|DMAF_RASTER|DMAF_BLITTER|DMAF_SPRITE,dmacon(A0)
MOVE.W #DMAF_SETCLR|DMAF_MASTER|DMAF_COPPER|DMAF_RASTER|DMAF_BLITTER,dmacon(A0)
MOVEM.L (SP)+,A2/A6
RTS
@ -193,6 +147,7 @@ NewLevel3VBI:
MOVEM.L (SP)+,D0-A6
RTE
_giveBackSystem:
MOVE.L A6,-(SP)
LEA _custom,A0
@ -210,6 +165,9 @@ _giveBackSystem:
CALLLIB _LVOWaitTOF
CALLLIB _LVOWaitBlit
CALLLIB _LVODisownBlitter
MOVE.L $4,A6
CALLLIB _LVOPermit
MOVE.L (SP)+,A6
RTS
@ -221,8 +179,8 @@ _initializeCopperlist:
RTS
; @stack *copperlist Pointer to copperlist
; @stack ScreenDefinition Pointer to screenSetup struct
; @stack ActiveScreenBufferDetails Pointer to currentScreen struct
; @stack ScreenSetup Pointer to screenSetup struct
; @stack CurrentScreen Pointer to currentScreen struct
; @stack copperlistBitplanePointers Pointer to bitplane pointers within the copper list [[high, low], ...]
STRUCTURE updateDisplayInCopperList,4
ULONG updateDisplayInCopperList_screenSetup
@ -237,9 +195,9 @@ _updateDisplayInCopperList:
MOVE.L D0,A2
; a2 has copperlistBitplanePointers
MOVE.W ScreenDefinition_bitplanes(A0),D1
MOVE.W ScreenSetup_bitplanes(A0),D1
SUBQ #1,D1
LEA ActiveScreenBufferDetails_planes(A1),A1
LEA CurrentScreen_planes(A1),A1
; a1 has planes
.continue:
@ -290,13 +248,13 @@ _setUpEmptySpritesInCopperlist:
RTS
; @stack *copperlist Pointer to copperlist
; @stack ScreenDefinition Pointer to screenDefinition struct
; @stack ActiveScreenBufferDetails Pointer to activeScreenBufferDetails struct
; @stack copperlistBitplanePointers Pointer to copperlistBitplanePointers struct
; @stack ScreenSetup Pointer to screenSetup struct
; @stack CurrentScreen Pointer to currentScreen struct
; @stack copperlistBitplanePointers Pointer to currentScreen struct
STRUCTURE AddDisplayToCopperListParams,4
ULONG AddDisplayToCopperListParams_copperlistPtr
ULONG AddDisplayToCopperListParams_screenDefinitionPtr
ULONG AddDisplayToCopperListParams_activeScreenBufferDetailsPtr
ULONG AddDisplayToCopperListParams_screenSetupPtr
ULONG AddDisplayToCopperListParams_currentScreenPtr
ULONG AddDisplayToCopperListParams_copperlistBitplanePointersPtr
_addDisplayToCopperlist:
MOVE.L A7,A0
@ -304,15 +262,16 @@ _addDisplayToCopperlist:
; A2,D2,D3
MOVEM.L A2-A4/D2-D4,-(SP)
MOVE.L AddDisplayToCopperListParams_copperlistPtr(A0),A1 ; copperlist
MOVE.L AddDisplayToCopperListParams_screenDefinitionPtr(A0),A2 ; screenDefinition
MOVE.L AddDisplayToCopperListParams_activeScreenBufferDetailsPtr(A0),A3 ; currentScreen
MOVE.L AddDisplayToCopperListParams_screenSetupPtr(A0),A2 ; screenSetup
MOVE.L AddDisplayToCopperListParams_currentScreenPtr(A0),A3 ; currentScreen
MOVE.L AddDisplayToCopperListParams_copperlistBitplanePointersPtr(A0),A4 ; copperlistBitplanePointers
LEA ActiveScreenBufferDetails_planes(A3),A3
LEA CurrentScreen_planes(A3),A3
; a3 contains address to planes
MOVEQ #0,D0
MOVE.W ScreenDefinition_bitplanes(A2),D0
MOVE.W ScreenSetup_bitplanes(A2),D0
; d0 is num of bitplanes
; set up bplpt
@ -331,10 +290,9 @@ _addDisplayToCopperlist:
; get this position for later updating
MOVE.L A1,(A4)+
MOVE.W D3,(A1)+
ADDQ #2,D1
; low byte
SWAP D3
ADDQ #2,D1
MOVE.W D1,(A1)+
; get this position for later updating
MOVE.L A1,(A4)+
@ -349,6 +307,7 @@ _addDisplayToCopperlist:
MOVE.L A1,D0
MOVEM.L (SP)+,A2-A4/D2-D4
RTS
; @stack *copperlist
@ -383,45 +342,33 @@ _endCopperlist:
RTS
BPLCON0_ENABLE_COMPOSITE_COLOR EQU $200
; TODO: [ ] Create a stock display structure w/ all the default values in it
; that can be overridden, with guides/help on how to do so, then
; have this accept that structure
; @stack bitplaneCount
_setUpDisplay:
MOVE.L D2,-(SP)
MOVE.L 8(A7),D2 ; bitplaneCount
MOVE.L 8(A7),D2
LEA _custom,A1
MOVEQ #0,D0
MOVE.W #BPLCON0_ENABLE_COMPOSITE_COLOR,D0
MOVE.W #BPLCON0_COLOR,D0
; move bitplane count to bits 12-14
MOVEQ #0,D1
MOVE.W D2,D1
AND.W #$7,D1
ROL.W #8,D1
ROL.W #4,D1
ADD.W D1,D0
MOVE.W D0,bplcon0(A1)
; this controls horizontal scroll. I'm not good enough
; yet to provide opinions on this.
MOVE.W #0,bplcon1(A1)
; sprites always on top for this demo
MOVE.W #$0020,bplcon2(A1)
; no modulos needed
MOVE.W #0,bplcon2(A1)
MOVE.W #0,bpl1mod(A1)
MOVE.W #0,bpl2mod(A1)
; pal default
MOVE.W #$2c81,diwstrt(A1)
MOVE.W #$2cc1,diwstop(A1)
; pal trick
MOVE.W #$f4c1,diwstop(A1)
MOVE.W #$38c1,diwstop(A1)
MOVE.W #$0038,ddfstrt(A1)
MOVE.W #$00d0,ddfstop(A1)
MOVE.L (SP)+,D2
@ -482,8 +429,5 @@ VBIPtr dc.l 0
CNOP 0,4
GraphicsLibrary GRAPHICSNAME
CNOP 0,4
_keyboardPressed dc.l 0
SECTION Sprite,Data_C
EmptySprite dc.w 0,0

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

BIN
topaz.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

View File

@ -3,14 +3,6 @@
#include <exec/types.h>
/**
* Get the offset from the beginning of a struct. Useful for building
* references to custom chip registers dynamically for copperlists.
*
* @see Custom
*/
#define offsetof(s, m) &((struct s *)0)->m
typedef unsigned short color_t;
typedef unsigned long uint32_t;
typedef unsigned short uint16_t;