Compare commits

...

36 Commits

Author SHA1 Message Date
John Bintz c9f1a55ebd Need genam too 2024-09-26 17:43:53 -04:00
John Bintz 457145f964 Ruby 2024-09-26 17:38:17 -04:00
John Bintz 98c05795fc More cleanup 2024-09-26 17:36:22 -04:00
John Bintz 623e51d164 More cleanups 2024-09-26 17:34:58 -04:00
John Bintz f2f699d2c9 Remove some files 2024-09-26 17:33:32 -04:00
John Bintz 38bf0dd0b2 prepping for release 2024-09-26 17:32:04 -04:00
John Bintz 9e8939089d reword 2024-09-22 08:21:25 -04:00
John Bintz e19f59246e how i'll make it fast eventually 2024-09-22 08:20:58 -04:00
John Bintz d1421929d8 Update README 2024-09-22 08:13:38 -04:00
John Bintz 7ba0c167cb finish up video stuff 2024-09-22 08:12:37 -04:00
John Bintz bd47027b4a OK this is CPU bound, much precalculating required 2024-09-22 07:36:27 -04:00
John Bintz f3913286eb binary 2024-09-22 07:32:44 -04:00
John Bintz 6b86be00d4 More performance stuff
Still can't get 50fps on an A500 but this is good enough for now.
2024-09-22 07:32:13 -04:00
John Bintz bd035eaea1 Move blitter commoon stuff to blitter header 2024-09-22 06:52:22 -04:00
John Bintz c76af7faf8 Cleanup startup code
I'm starting to understand this stuff better. This makes it possible to
use OS-level interrupts like the keyboard in the code.
2024-09-22 06:40:21 -04:00
John Bintz 634bdd884e Clean out that stab at targeted cleanups
I needed to write way more code to get that working right
2024-09-22 06:39:50 -04:00
John Bintz 1dfbec0252 Keyboard handling, just get this up to 50fps
The partial render approach was going to require more coordination than
I needed to just get this to 50fps.
2024-09-22 06:31:08 -04:00
John Bintz 3048754012 start on more precise topaz art replacement
this should hopefully speed things up a lot
2024-09-19 21:51:45 -04:00
John Bintz d89d68c115 More code cleanups 2024-09-19 13:03:46 -04:00
John Bintz c1d9f23026 More clarity work 2024-09-19 08:09:10 -04:00
John Bintz 1d7e327194 Improve clarity on screen definition functions 2024-09-19 07:47:48 -04:00
John Bintz 3a42da655b In which John learns about the playfield hardware and sprite priorities 2024-09-12 08:26:53 -04:00
John Bintz a73506a27b lol i reversed them 2024-07-17 07:40:48 -04:00
John Bintz 7656a6c653 Clean up names/signatures 2024-07-17 07:38:47 -04:00
John Bintz 777257b83d Simplify cool bun rendering code 2024-07-17 07:08:59 -04:00
John Bintz 6aed100cd2 I don't need two input channels for this 2024-07-16 08:02:38 -04:00
John Bintz 22a0359536 some text stuff, pending cleanup 2024-06-14 09:16:01 -04:00
John Bintz 048a1270bb 50 fps! 2024-06-13 12:30:39 -04:00
John Bintz 686125592a this is as optimized as the code will reasonably get
we just need to blit less stuff
2024-06-13 09:01:22 -04:00
John Bintz 331b76e798 start optimizing 2024-06-13 05:55:29 -04:00
John Bintz ecfdd53c5f it works 2024-06-10 22:04:40 -04:00
John Bintz 6febe83740 bitplane only color mapping works, let's make some bitplanes/copperlists 2024-06-04 12:44:12 -04:00
John Bintz 9ea3e5f8a6 start on image converter 2024-06-03 12:46:32 -04:00
John Bintz 2a420f6f4f starting on sprites 2024-06-02 16:03:16 -04:00
John Bintz eb5daa1684 code cleanups, on to sprites 2024-06-02 14:42:36 -04:00
John Bintz b06af2cb4a buns can march 2024-06-02 14:37:37 -04:00
49 changed files with 2131 additions and 2223 deletions

2
.rubocop.yml Normal file
View File

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

BIN
32x50 Executable file

Binary file not shown.

90
32x50_bun.c Normal file
View File

@ -0,0 +1,90 @@
/**
* 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 Executable file

Binary file not shown.

127
33x50_bun.c Normal file
View File

@ -0,0 +1,127 @@
/**
* 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);
}

View File

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

50
README.md Normal file
View File

@ -0,0 +1,50 @@
## 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.

BIN
any_position Executable file

Binary file not shown.

144
any_position.c Normal file
View File

@ -0,0 +1,144 @@
/**
* 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

Binary file not shown.

172
basics.s
View File

@ -1,172 +0,0 @@
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

Binary file not shown.

View File

@ -1,98 +0,0 @@
#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);
}

View File

434
bun.c
View File

@ -1,3 +1,5 @@
#include <math.h>
// Custom // Custom
#include <hardware/custom.h> #include <hardware/custom.h>
@ -11,69 +13,127 @@
#include "screen.h" #include "screen.h"
#include "bun.h" #include "bun.h"
#include "system/system.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 // linked as raw bytes in assembler
extern unsigned char far coolbun[]; extern unsigned char chip 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; extern struct Custom far custom;
void setupBun() { struct BunClear {
unsigned char *currentCoolBunArea, *currentCoolBun; uint16_t memoryStartOffsetBytes;
unsigned int x, y, plane; uint16_t widthWords;
uint16_t heightRows;
uint8_t direction;
};
coolbunArea = AllocMem(COOL_BUN_MEMORY_SIZE, MEMF_CHIP | MEMF_CLEAR); #define BUN_OFF_RIGHT_SIDE (0)
currentCoolBunArea = coolbunArea; #define BUN_OFF_LEFT_SIDE (1)
currentCoolBun = coolbun; #define BUN_ANYWHERE (2)
CopyMem(coolbun, coolbunArea, COOL_BUN_MEMORY_SIZE); 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));
} }
void teardownBun() { bunRightSide_bltalwmPrecalc[shift] = bltalwm;
FreeMem(coolbunArea, COOL_BUN_MEMORY_SIZE);
//left
bltalwm = 0x0000;
for (j = 0; j <= 15 - shift; ++j) {
bltalwm += (1 << j);
}
bunLeftSide_bltalwmPrecalc[shift] = bltalwm;
}
} }
void bun_offRightSide( void bun_offRightSide(
int plusXValue, int plusXValue,
int y, int y,
struct ScreenSetup *screenSetup, struct ScreenDefinition *screenDefinition,
struct CurrentScreen *currentScreen struct ActiveScreenBufferDetails *activeScreenBufferDetails,
struct BunClear *bunClear
) { ) {
uint8_t i, plane = 0; uint8_t i, plane = 0;
uint8_t shift = plusXValue & 15; uint8_t shift = plusXValue & 15;
uint8_t wordShift = (plusXValue >> 4); uint8_t wordShift = (plusXValue >> 4);
uint16_t bltalwm; uint16_t bltalwm, bltcon0, bltcon1, bltdmod, bltsize;
for (plane = 0; plane < 2; ++plane) { bunClear->memoryStartOffsetBytes = (y * screenDefinition->byteWidth) +
custom.bltcon0 = BLTCON0(0xc0, 0, 1, 0, 1, shift); screenDefinition->byteWidth - COOL_BUN_WIDTH_BYTES +
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; wordShift * 2;
bunClear->heightRows = COOL_BUN_HEIGHT;
bunClear->widthWords = 2 - wordShift;
bunClear->direction = BLITTER_ASCENDING;
custom.bltafwm = 0xffff; bltalwm = bunRightSide_bltalwmPrecalc[shift];
/*
bltalwm = 0x0000; bltalwm = 0x0000;
for (i = 0; i <= 15 - shift; ++i) { for (i = 0; i <= 15 - shift; ++i) {
bltalwm += (1 << (15 - i)); bltalwm += (1 << (15 - i));
} }
custom.bltalwm = bltalwm; */
custom.bltbmod = wordShift * 2; bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, shift);
custom.bltdmod = screenSetup->byteWidth - COOL_BUN_WIDTH_BYTES + bltcon1 = BLTCON1(bunClear->direction, shift);
bltdmod = screenDefinition->byteWidth - COOL_BUN_WIDTH_BYTES +
wordShift * 2; wordShift * 2;
custom.bltsize = 2 - wordShift + (COOL_BUN_HEIGHT << 6); 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.bltsize = bltsize;
WaitBlit(); WaitBlit();
} }
@ -82,47 +142,58 @@ void bun_offRightSide(
void bun_offLeftSide( void bun_offLeftSide(
int minusXValue, int minusXValue,
int y, int y,
struct ScreenSetup *screenSetup, struct ScreenDefinition *screenDefinition,
struct CurrentScreen *currentScreen struct ActiveScreenBufferDetails *activeScreenBufferDetails,
struct BunClear *bunClear
) { ) {
unsigned char plane; unsigned char plane;
uint8_t shift = minusXValue & 15; uint8_t shift = minusXValue & 15;
uint8_t wordShift = (minusXValue >> 4); uint8_t wordShift = (minusXValue >> 4);
uint8_t i; uint8_t i;
uint16_t bltalwm; uint16_t bltalwm, bltcon0, bltcon1, bltdmod, bltsize;
// y can't be 0 otherwise we will corrupt memory for now // y can't be 0 otherwise we will corrupt memory for now
if (y == 0) return; if (y == 0) return;
for (plane = 0; plane < 2; ++plane) { bunClear->memoryStartOffsetBytes = (screenDefinition->byteWidth * (y + COOL_BUN_LAST_ROW)) +
// shift left, so descending 2 - wordShift * 2;
custom.bltcon0 = BLTCON0(0xc0, 0, 1, 0, 1, shift); bunClear->heightRows = COOL_BUN_HEIGHT;
custom.bltcon1 = BLTCON1(1, shift); bunClear->widthWords = 2 - wordShift;
bunClear->direction = BLITTER_DESCENDING;
// a has a mask we're shifting bltalwm = bunLeftSide_bltalwmPrecalc[shift];
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; bltalwm = 0x0000;
for (i = 0; i <= 15 - shift; ++i) { for (i = 0; i <= 15 - shift; ++i) {
bltalwm += (1 << 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.bltalwm = bltalwm;
custom.bltbmod = wordShift * 2; custom.bltamod = wordShift * 2;
custom.bltdmod = screenSetup->byteWidth - 4 + wordShift * 2; custom.bltdmod = bltdmod;
custom.bltsize = 2 - wordShift + (COOL_BUN_HEIGHT << 6); custom.bltsize = bltsize;
WaitBlit(); WaitBlit();
} }
@ -131,65 +202,256 @@ void bun_offLeftSide(
void bun_anywhere( void bun_anywhere(
int x, int x,
int y, int y,
struct ScreenSetup *screenSetup, struct ScreenDefinition *screenDefinition,
struct CurrentScreen *currentScreen struct ActiveScreenBufferDetails *activeScreenBufferDetails,
struct BunClear *bunClear
) { ) {
uint8_t plane; uint8_t plane;
uint8_t shift = x & 15; uint8_t shift = x & 15;
uint8_t needsExtraWord = shift != 0; uint8_t needsExtraWord = shift != 0;
uint16_t bltcon0, bltcon1, bltalwm, bltamod, bltdmod, bltsize;
for (plane = 0; plane < 2; ++plane) { bunClear->memoryStartOffsetBytes = WORD_ALIGNED_BYTE_POSITION(screenDefinition->width, x, y);
// if we extend the bun area by a word, we only need one write
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 // buns will never interfere with a background so they don't need a mask
// they do need the scratch area though bltcon0 = BLTCON0(0xf0, 1, 0, 0, 1, shift);
custom.bltcon0 = BLTCON0(0xc0, 0, 1, 0, 1, shift); bltcon1 = BLTCON1(bunClear->direction, 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;
if (needsExtraWord) { if (needsExtraWord) {
custom.bltalwm = 0x0000; bltalwm = 0x0000;
} else { } else {
custom.bltalwm = 0xffff; bltalwm = 0xffff;
} }
custom.bltbmod = -(needsExtraWord * 2); bltamod = -(needsExtraWord * 2);
custom.bltdmod = screenSetup->byteWidth - COOL_BUN_WIDTH_BYTES - (needsExtraWord * 2); bltdmod = screenDefinition->byteWidth - COOL_BUN_WIDTH_BYTES - (needsExtraWord * 2);
custom.bltsize = (2 + needsExtraWord) + (COOL_BUN_HEIGHT << 6); bltsize = bunClear->widthWords + (bunClear->heightRows << 6);
for (plane = 0; plane < 2; ++plane) {
custom.bltcon0 = bltcon0;
custom.bltcon1 = bltcon1;
custom.bltapt = coolbunPlaneStarts[BUN_ANYWHERE][plane];
custom.bltdpt = activeScreenBufferDetails->planes[plane] +
bunClear->memoryStartOffsetBytes;
custom.bltafwm = 0xffff;
custom.bltalwm = bltalwm;
custom.bltamod = bltamod;
custom.bltdmod = bltdmod;
custom.bltsize = bltsize;
WaitBlit(); WaitBlit();
} }
} }
#define ENABLE_RENDER_BUN_CHECKING (0)
void renderBun( void renderBun(
int x, int x,
int y, int y,
struct ScreenSetup *screenSetup, struct ScreenDefinition *screenDefinition,
struct CurrentScreen *currentScreen struct ActiveScreenBufferDetails *activeScreenBufferDetails,
struct BunClear *bunClear
) { ) {
/** /**
* Conditions that will cause the program to crash if met. If your bun * Conditions that will cause the program to crash if met. If your bun
* isn't rendering, it's due to here. * isn't rendering, it's due to here. Turn off checking once you know
* everything is solid to save some CPU.
* *
* TODO: Handle top/bottom off-screen as well. * TODO: Handle top/bottom off-screen as well.
*/ */
if (ENABLE_RENDER_BUN_CHECKING) {
if (x < -31) return; if (x < -31) return;
if (x > screenSetup->width + 31) return; if (x > screenDefinition->width + 31) return;
if (y < 1) return; if (y < 1) return;
if (y > screenSetup->height- COOL_BUN_HEIGHT - 1) return; if (y > screenDefinition->height - COOL_BUN_HEIGHT - 1) return;
}
if (x < 0) { if (x < 0) {
bun_offLeftSide(-x, y, screenSetup, currentScreen); bun_offLeftSide(
} else if (x > screenSetup->width - COOL_BUN_WIDTH) { -x,
bun_offRightSide(x - (screenSetup->width - COOL_BUN_WIDTH), y, screenSetup, currentScreen); y,
screenDefinition,
activeScreenBufferDetails,
bunClear
);
} else if (x > screenDefinition->width - COOL_BUN_WIDTH) {
bun_offRightSide(
x - (screenDefinition->width - COOL_BUN_WIDTH),
y,
screenDefinition,
activeScreenBufferDetails,
bunClear
);
} else { } else {
bun_anywhere(x, y, screenSetup, currentScreen); bun_anywhere(
x,
y,
screenDefinition,
activeScreenBufferDetails,
bunClear
);
} }
} }
#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,23 +3,31 @@
#include "screen.h" #include "screen.h"
#define COOL_BUN_WIDTH (32) #define FRAMES_FOR_SCREEN (60)
#define COOL_BUN_WIDTH_BYTES (COOL_BUN_WIDTH / 8) #define BUN_COUNT (12)
#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) struct BunRenderer {
#define COOL_BUN_MEMORY_SIZE (COOL_BUN_PLANE_SIZE * COOL_BUN_PLANES) struct ScreenDefinition *screenDefinition;
struct ActiveScreenBufferDetails *activeScreenBufferDetails;
};
void setupBun(void); void setupBunRenderer(
void renderBun( struct BunRenderer *,
int x, struct ScreenDefinition *,
int y, struct ActiveScreenBufferDetails *
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 #endif

BIN
bun_test Executable file

Binary file not shown.

30
bun_test.c Normal file
View File

@ -0,0 +1,30 @@
#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;
}

BIN
copper-colors Normal file

Binary file not shown.

BIN
demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 KiB

435
image_converter.rb Executable file
View File

@ -0,0 +1,435 @@
#!/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,4 +1,30 @@
XDEF _coolbun XDEF _coolbun
XDEF _TopazBitplanes
XDEF _CopperColors
XDEF _SpriteCopperlist
XDEF _SpriteData
XDEF _MaskBitplane
SECTION Topaz,Data_C
_coolbun: _coolbun:
INCBIN "images/bun small.raw" 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"

BIN
keyboard_interrupt Executable file

Binary file not shown.

77
keyboard_interrupt.c Normal file
View File

@ -0,0 +1,77 @@
#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 Executable file

Binary file not shown.

90
left_side.c Normal file
View File

@ -0,0 +1,90 @@
/**
* 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.

452
main.c
View File

@ -1,195 +1,391 @@
#include <stdio.h> #include <stdio.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h> #include <clib/exec_protos.h>
#include <clib/graphics_protos.h> #include <clib/graphics_protos.h>
#include <exec/exec.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/custom.h>
#include <hardware/dmabits.h> #include <hardware/dmabits.h>
#include <hardware/cia.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h> #include <graphics/gfx.h>
#include "system/blitter.h" #include "system/blitter.h"
#include "system/copper.h" #include "system/copper.h"
#include "system/system.h" #include "system/system.h"
#include "system/sprite.h"
#include "screen.h" #include "screen.h"
#include "types.h" #include "types.h"
#include "bun.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 Custom far custom;
extern struct CIA far ciaa;
// this should be large enough to hold one bitplane of the largest object // change to 0 to not render sprites
// you are blitting, plus one additional word on each side #define RENDER_SPRITES (1)
#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)
volatile short *dbg = (volatile short *)0x100; struct ScreenDefinition screenDefinition;
struct ActiveScreenBufferDetails activeScreenBufferDetails;
unsigned char *scratchArea; /**
struct ScreenSetup screenSetup; * The locations within the copperlist data where the bitplanes are referenced.
struct CurrentScreen currentScreen; * 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
*/
void *copperlistBitplanePointers[8][2]; 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_color = (uint16_t)offsetof(Custom, color);
uint16_t custom_sprite = (uint16_t)offsetof(Custom, sprpt); uint16_t custom_sprite = (uint16_t)offsetof(Custom, sprpt);
uint16_t custom_sprite_control = (uint16_t)offsetof(Custom, spr);
#define BUN_COUNT (12) extern uint8_t chip TopazBitplanes[];
#define BUN_SPEED (2) extern uint16_t chip CopperColors[];
extern uint16_t chip SpriteCopperlist[];
extern uint16_t chip SpriteData[];
extern uint8_t chip MaskBitplane[];
short int bunPositions[BUN_COUNT][2]; #define TOPAZ_WIDTH_PIXELS (160)
#define TOPAZ_WIDTH_BYTES (TOPAZ_WIDTH_PIXELS / 8)
#define TOPAZ_WIDTH_WORDS (TOPAZ_WIDTH_PIXELS / 16)
#define BUN_MAX_RANGE (31 + 320 - 1) void renderTopaz(void) {
int plane;
#define BUN_HORIZ_DISTANCE_BETWEEN_BUNS ((BUN_MAX_RANGE / 4) - COOL_BUN_WIDTH) uint16_t bltcmod;
#define BUN_TOTAL_HORIZ_DISTANCE (BUN_HORIZ_DISTANCE_BETWEEN_BUNS + COOL_BUN_WIDTH) uint8_t *bltbpt;
#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)
void calculateBunPositions( bltcmod = screenDefinition.byteWidth - TOPAZ_WIDTH_BYTES;
uint16_t frame, bltbpt = TopazBitplanes;
short int bunPositions[BUN_COUNT][2],
struct ScreenSetup *screenSetup
) {
int x, y, row, column, current;
frame %= FRAME_MAX; 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);
for (current = 0; current < BUN_COUNT; ++current) { bltbpt += TOPAZ_WIDTH_BYTES * 256;
row = current / 4;
column = current % 4;
x = column * BUN_TOTAL_HORIZ_DISTANCE + frame * BUN_SPEED; WaitBlit();
if (row == 1) { }
//x += BUN_TOTAL_HORIZ_DISTANCE / 2;
} }
x %= BUN_MAX_RANGE;
x -= 31;
y = BUN_ROW_START + row * BUN_TOTAL_VERT_DISTANCE;
bunPositions[current][0] = x; #define MOSTLY_TOPAZ_TOP_BOTTOM_CROP (30)
bunPositions[current][1] = y;
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;
} }
} }
int main(void) { int main(void) {
uint16_t *copperlist, *currentCopperlist, result; int i;
int i, j, x, y, plane;
int blitShiftRight, memoryXOffset, blitWidth;
uint32_t wow, wow2;
color_t colors[8]; struct BunRenderer bunRenderer;
uint16_t redrawRanges[BUN_COUNT][4];
colors[0] = 0x09b8; printf("\nCool bun blitter, copper, and sprite demo by John Bintz\n");
colors[1] = 0x0000; printf("\n");
colors[2] = 0x0fff; printf("This is my first real go at writing graphics code for the Amiga.\n");
colors[3] = 0x000f; 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");
setupBun(); printf("And, I'm also using sprites to add more colors to the Topaz art.\n");
setupScreen(&screenSetup, SCREEN_WIDTH, SCREEN_HEIGHT, 3); printf("The Ruby script will figure out what small areas of each line weren't\n");
setupInitialCurrentScreen(&screenSetup, &currentScreen); 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");
// blitter copy the first bitplane row down to the second printf("\nEnjoy, and thanks for watching!\n");
printf("John (theindustriousrabbit.com)\n\n");
copperlist = prepareNewCopperlist(); allocateDoubleBufferedScreenMemory(
&screenDefinition,
&activeScreenBufferDetails,
SCREEN_WIDTH,
SCREEN_HEIGHT,
3
);
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(); takeOverSystem();
setCopperlist(copperlist); setCopperlist(copperlist);
setUpDisplay((uint32_t)screenSetup.bitplanes); setUpDisplay((uint32_t)screenDefinition.bitplanes);
currentCopperlist = addDisplayToCopperlist( renderTopaz();
copperlist, swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails);
&screenSetup, renderTopaz();
&currentScreen, swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails);
&copperlistBitplanePointers
);
currentCopperlist = setUpEmptySpritesInCopperlist(currentCopperlist);
*(currentCopperlist++) = custom_color;
*(currentCopperlist++) = 0x000;
*(currentCopperlist++) = custom_color + 2;
*(currentCopperlist++) = 0x000;
*(currentCopperlist++) = custom_color + 4;
*(currentCopperlist++) = 0xfff;
*(currentCopperlist++) = custom_color + 6;
*(currentCopperlist++) = 0x00F;
for (y = 0; y < 256; ++y) {
*(currentCopperlist++) = 1 + (31 << 1) + ((44 + y) << 8);
*(currentCopperlist++) = 0xFFFE;
*(currentCopperlist++) = custom_color;
*(currentCopperlist++) = 0x9b8;
*(currentCopperlist++) = 1 + ((31 + (320 / 4)) << 1) + ((44 + y) << 8);
*(currentCopperlist++) = 0xFFFE;
*(currentCopperlist++) = custom_color;
*(currentCopperlist++) = 0x000;
}
endCopperlist(currentCopperlist);
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( updateDisplayInCopperList(
&screenSetup, &screenDefinition,
&currentScreen, &activeScreenBufferDetails,
copperlistBitplanePointers copperlistBitplanePointers
); );
i = 0;
while (1) {
WaitTOF(); WaitTOF();
swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails);
clearCurrentBuns(&bunRenderer);
renderBunFrame(i, &bunRenderer);
renderMostlyTopaz();
updateDisplayInCopperList(
&screenDefinition,
&activeScreenBufferDetails,
copperlistBitplanePointers
);
if (keyboardPressed) break;
if ((ciaa.ciapra >> 6) != 3) break;
i++;
if (i > FRAMES_FOR_SCREEN) i = 0;
} }
/* // somthing in here causes an A500 in KS 1.3 to crash
for (i = 0; i < 200; ++i) {
WaitTOF();
}
*/
giveBackSystem(); giveBackSystem();
teardownKeyboard();
teardownScreen(&screenSetup); teardownScreen(&screenDefinition);
freeCopperlist(copperlist); freeCopperlist(copperlist);
teardownBun(); teardownBunRenderer();
for (i = 0; i < BUN_COUNT; ++i) {
printf("%d %d\n", bunPositions[i][0], bunPositions[i][1]);
}
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 62 KiB

BIN
mask-bitplane Normal file

Binary file not shown.

BIN
right_side Executable file

Binary file not shown.

90
right_side.c Normal file
View File

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

View File

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

View File

@ -1,4 +1,9 @@
MAIN_OBJS = main.o images.o system.lib screen.o bun.o 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 all: main
@ -8,12 +13,27 @@ all: main
.s.o: .s.o:
genam -l $*.s genam -l $*.s
system.lib: system/system.o system/copper.o system/blitter.o 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 sc objectlibrary=system.lib system/system.o system/copper.o system/blitter.o system/debug.o
main: $(MAIN_OBJS) main: $(MAIN_OBJS)
sc link to main $(MAIN_OBJS) sc link to main math=standard $(MAIN_OBJS)
test: blitter_test.o blitter.o system.o 32x50: $(32_objs)
sc link to blitter_test identifierlength=32 math=standard blitter_test.o blitter.o cutest/CuTest.c system.o 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

BIN
sprite-copperlist Normal file

Binary file not shown.

BIN
sprite-data Normal file

Binary file not shown.

View File

@ -1,8 +1,14 @@
#ifndef __BLITTER_H__ #ifndef __BLITTER_H__
#define __BLITTER_H__ #define __BLITTER_H__
#include "types.h" #define BLTSIZE(w, h) (w + (h << 6))
#include "screen.h" #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)
/* /*

View File

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

View File

@ -1,11 +1,31 @@
#ifndef __COPPER_H__ #ifndef __COPPER_H__
#define __COPPER_H__ #define __COPPER_H__
#define COPPERLIST_SIZE (10000)
#include "../types.h" #include "../types.h"
uint16_t * prepareNewCopperlist(void); /**
* 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);
void setCopperlist(uint16_t *copperlist); void setCopperlist(uint16_t *copperlist);
void freeCopperlist(uint16_t *copperlist); void freeCopperlist(uint16_t *copperlist);

11
system/debug.c Normal file
View File

@ -0,0 +1,11 @@
#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;
}

6
system/debug.h Normal file
View File

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

7
system/sprite.h Normal file
View File

@ -0,0 +1,7 @@
#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,15 +12,20 @@
// copperlist // copperlist
extern void initializeCopperlist(void *copperlist); extern void initializeCopperlist(void *copperlist);
extern uint16_t* endCopperlist(uint16_t *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( extern uint16_t* addDisplayToCopperlist(
uint16_t *copperlist, uint16_t *copperlist,
struct ScreenSetup *, struct ScreenDefinition *,
struct CurrentScreen *, struct ActiveScreenBufferDetails *,
void *copperlistBitplanePointers void *copperlistBitplanePointers
); );
extern void updateDisplayInCopperList( extern void updateDisplayInCopperList(
struct ScreenSetup *, struct ScreenDefinition *,
struct CurrentScreen *, struct ActiveScreenBufferDetails *,
void *copperlistBitplanePointers void *copperlistBitplanePointers
); );
extern uint16_t* addColorsToCopperlist(uint16_t *copperlist, color_t[], int count); extern uint16_t* addColorsToCopperlist(uint16_t *copperlist, color_t[], int count);

View File

@ -9,6 +9,9 @@
XDEF _endCopperlist XDEF _endCopperlist
XDEF _myWaitBlit XDEF _myWaitBlit
XDEF _WaitBOF XDEF _WaitBOF
XDEF _KeyboardHandler
XDEF _keyboardPressed
XREF _custom XREF _custom
@ -29,6 +32,8 @@ FUNC_CNT SET FUNC_CNT-6
INCLUDE "hardware/custom.i" INCLUDE "hardware/custom.i"
INCLUDE "hardware/dmabits.i" INCLUDE "hardware/dmabits.i"
INCLUDE "hardware/intbits.i" INCLUDE "hardware/intbits.i"
INCLUDE "exec/io.i"
INCLUDE "devices/inputevent.i"
; @param 1 Pointer to null terminated name of library ; @param 1 Pointer to null terminated name of library
; @param 2 Minimum version of library, 0 for any ; @param 2 Minimum version of library, 0 for any
@ -56,24 +61,69 @@ RestoreRegister MACRO
MOVE.W Old\1,\1(A0) MOVE.W Old\1,\1(A0)
ENDM ENDM
STRUCTURE ScreenSetup,0 STRUCTURE ScreenDefinition,0
UWORD ScreenSetup_width UWORD ScreenDefinition_width
UWORD ScreenSetup_height UWORD ScreenDefinition_height
UWORD ScreenSetup_bitplanes UWORD ScreenDefinition_bitplanes
ULONG ScreenSetup_memoryStart ULONG ScreenDefinition_memoryStart
UWORD ScreenSetup_byteWidth UWORD ScreenDefinition_byteWidth
UWORD ScreenSetup_nextBitplaneAdvance UWORD ScreenDefinition_nextBitplaneAdvance
UWORD ScreenSetup_nextBufferAdvance UWORD ScreenDefinition_nextBufferAdvance
ULONG ScreenSetup_copperlistBitplanePointers ULONG ScreenDefinition_copperlistBitplanePointers
LABEL ScreenSetup_SIZEOF LABEL ScreenDefinition_SIZEOF
STRUCTURE CurrentScreen,0 STRUCTURE ActiveScreenBufferDetails,0
UWORD CurrentScreen_currentBuffer UWORD ActiveScreenBufferDetails_currentBuffer
CurrentScreen_planes EQU SOFFSET ActiveScreenBufferDetails_planes EQU SOFFSET
SOFFSET SET SOFFSET+(8*4) SOFFSET SET SOFFSET+(8*4)
LABEL CurrentScreen_SIZEOF LABEL ActiveScreenBufferDetails_SIZEOF
BPLCON0_COLOR EQU $200 ; @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
M68K_LEVEL3_INTERRUPT_AUTOVECTOR EQU $6C M68K_LEVEL3_INTERRUPT_AUTOVECTOR EQU $6C
_takeOverSystem: _takeOverSystem:
@ -81,13 +131,15 @@ _takeOverSystem:
OpenLibrary #GraphicsLibrary,#0 OpenLibrary #GraphicsLibrary,#0
MOVE.L D0,GraphicsBase MOVE.L D0,GraphicsBase
MOVE.L $4,A6
CALLLIB _LVOForbid
MOVE.L D0,A6 MOVE.L D0,A6
MOVE.L gb_ActiView(A6),OldView MOVE.L gb_ActiView(A6),OldView
MOVE.L gb_copinit(A6),OldCopper MOVE.L gb_copinit(A6),OldCopper
MOVE.L #0,A1
CALLLIB _LVOLoadView
CALLLIB _LVOWaitTOF
CALLLIB _LVOWaitTOF
CALLLIB _LVOOwnBlitter CALLLIB _LVOOwnBlitter
CALLLIB _LVOWaitBlit CALLLIB _LVOWaitBlit
@ -98,20 +150,14 @@ _takeOverSystem:
PreserveRegister intreq PreserveRegister intreq
PreserveRegister adkcon 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 ; http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node0036.html
MOVE.W #$7FFF,intena(A0) ; disable all interrupts MOVE.W #$7FFF,intena(A0) ; disable all interrupts
; we need VERTB to use WaitTOF ; we need VERTB to use WaitTOF
MOVE.W #INTF_SETCLR|INTF_INTEN|INTF_COPER|INTF_VERTB,intena(A0) ; enable master interrupt, copper, and VBR ; 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 #$7FFF,dmacon(a0) MOVE.W #$7FFF,dmacon(a0)
MOVE.W #DMAF_SETCLR|DMAF_MASTER|DMAF_COPPER|DMAF_RASTER|DMAF_BLITTER,dmacon(A0) MOVE.W #DMAF_SETCLR|DMAF_MASTER|DMAF_COPPER|DMAF_RASTER|DMAF_BLITTER|DMAF_SPRITE,dmacon(A0)
MOVEM.L (SP)+,A2/A6 MOVEM.L (SP)+,A2/A6
RTS RTS
@ -147,7 +193,6 @@ NewLevel3VBI:
MOVEM.L (SP)+,D0-A6 MOVEM.L (SP)+,D0-A6
RTE RTE
_giveBackSystem: _giveBackSystem:
MOVE.L A6,-(SP) MOVE.L A6,-(SP)
LEA _custom,A0 LEA _custom,A0
@ -165,9 +210,6 @@ _giveBackSystem:
CALLLIB _LVOWaitTOF CALLLIB _LVOWaitTOF
CALLLIB _LVOWaitBlit CALLLIB _LVOWaitBlit
CALLLIB _LVODisownBlitter CALLLIB _LVODisownBlitter
MOVE.L $4,A6
CALLLIB _LVOPermit
MOVE.L (SP)+,A6 MOVE.L (SP)+,A6
RTS RTS
@ -179,8 +221,8 @@ _initializeCopperlist:
RTS RTS
; @stack *copperlist Pointer to copperlist ; @stack *copperlist Pointer to copperlist
; @stack ScreenSetup Pointer to screenSetup struct ; @stack ScreenDefinition Pointer to screenSetup struct
; @stack CurrentScreen Pointer to currentScreen struct ; @stack ActiveScreenBufferDetails Pointer to currentScreen struct
; @stack copperlistBitplanePointers Pointer to bitplane pointers within the copper list [[high, low], ...] ; @stack copperlistBitplanePointers Pointer to bitplane pointers within the copper list [[high, low], ...]
STRUCTURE updateDisplayInCopperList,4 STRUCTURE updateDisplayInCopperList,4
ULONG updateDisplayInCopperList_screenSetup ULONG updateDisplayInCopperList_screenSetup
@ -195,9 +237,9 @@ _updateDisplayInCopperList:
MOVE.L D0,A2 MOVE.L D0,A2
; a2 has copperlistBitplanePointers ; a2 has copperlistBitplanePointers
MOVE.W ScreenSetup_bitplanes(A0),D1 MOVE.W ScreenDefinition_bitplanes(A0),D1
SUBQ #1,D1 SUBQ #1,D1
LEA CurrentScreen_planes(A1),A1 LEA ActiveScreenBufferDetails_planes(A1),A1
; a1 has planes ; a1 has planes
.continue: .continue:
@ -248,13 +290,13 @@ _setUpEmptySpritesInCopperlist:
RTS RTS
; @stack *copperlist Pointer to copperlist ; @stack *copperlist Pointer to copperlist
; @stack ScreenSetup Pointer to screenSetup struct ; @stack ScreenDefinition Pointer to screenDefinition struct
; @stack CurrentScreen Pointer to currentScreen struct ; @stack ActiveScreenBufferDetails Pointer to activeScreenBufferDetails struct
; @stack copperlistBitplanePointers Pointer to currentScreen struct ; @stack copperlistBitplanePointers Pointer to copperlistBitplanePointers struct
STRUCTURE AddDisplayToCopperListParams,4 STRUCTURE AddDisplayToCopperListParams,4
ULONG AddDisplayToCopperListParams_copperlistPtr ULONG AddDisplayToCopperListParams_copperlistPtr
ULONG AddDisplayToCopperListParams_screenSetupPtr ULONG AddDisplayToCopperListParams_screenDefinitionPtr
ULONG AddDisplayToCopperListParams_currentScreenPtr ULONG AddDisplayToCopperListParams_activeScreenBufferDetailsPtr
ULONG AddDisplayToCopperListParams_copperlistBitplanePointersPtr ULONG AddDisplayToCopperListParams_copperlistBitplanePointersPtr
_addDisplayToCopperlist: _addDisplayToCopperlist:
MOVE.L A7,A0 MOVE.L A7,A0
@ -262,16 +304,15 @@ _addDisplayToCopperlist:
; A2,D2,D3 ; A2,D2,D3
MOVEM.L A2-A4/D2-D4,-(SP) MOVEM.L A2-A4/D2-D4,-(SP)
MOVE.L AddDisplayToCopperListParams_copperlistPtr(A0),A1 ; copperlist MOVE.L AddDisplayToCopperListParams_copperlistPtr(A0),A1 ; copperlist
MOVE.L AddDisplayToCopperListParams_screenSetupPtr(A0),A2 ; screenSetup MOVE.L AddDisplayToCopperListParams_screenDefinitionPtr(A0),A2 ; screenDefinition
MOVE.L AddDisplayToCopperListParams_currentScreenPtr(A0),A3 ; currentScreen MOVE.L AddDisplayToCopperListParams_activeScreenBufferDetailsPtr(A0),A3 ; currentScreen
MOVE.L AddDisplayToCopperListParams_copperlistBitplanePointersPtr(A0),A4 ; copperlistBitplanePointers MOVE.L AddDisplayToCopperListParams_copperlistBitplanePointersPtr(A0),A4 ; copperlistBitplanePointers
LEA CurrentScreen_planes(A3),A3 LEA ActiveScreenBufferDetails_planes(A3),A3
; a3 contains address to planes ; a3 contains address to planes
MOVEQ #0,D0 MOVEQ #0,D0
MOVE.W ScreenSetup_bitplanes(A2),D0 MOVE.W ScreenDefinition_bitplanes(A2),D0
; d0 is num of bitplanes ; d0 is num of bitplanes
; set up bplpt ; set up bplpt
@ -290,9 +331,10 @@ _addDisplayToCopperlist:
; get this position for later updating ; get this position for later updating
MOVE.L A1,(A4)+ MOVE.L A1,(A4)+
MOVE.W D3,(A1)+ MOVE.W D3,(A1)+
ADDQ #2,D1
; low byte ; low byte
SWAP D3 SWAP D3
ADDQ #2,D1
MOVE.W D1,(A1)+ MOVE.W D1,(A1)+
; get this position for later updating ; get this position for later updating
MOVE.L A1,(A4)+ MOVE.L A1,(A4)+
@ -307,7 +349,6 @@ _addDisplayToCopperlist:
MOVE.L A1,D0 MOVE.L A1,D0
MOVEM.L (SP)+,A2-A4/D2-D4 MOVEM.L (SP)+,A2-A4/D2-D4
RTS RTS
; @stack *copperlist ; @stack *copperlist
@ -342,33 +383,45 @@ _endCopperlist:
RTS 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 ; @stack bitplaneCount
_setUpDisplay: _setUpDisplay:
MOVE.L D2,-(SP) MOVE.L D2,-(SP)
MOVE.L 8(A7),D2 MOVE.L 8(A7),D2 ; bitplaneCount
LEA _custom,A1 LEA _custom,A1
MOVEQ #0,D0 MOVEQ #0,D0
MOVE.W #BPLCON0_COLOR,D0 MOVE.W #BPLCON0_ENABLE_COMPOSITE_COLOR,D0
; move bitplane count to bits 12-14
MOVEQ #0,D1 MOVEQ #0,D1
MOVE.W D2,D1 MOVE.W D2,D1
AND.W #$7,D1 AND.W #$7,D1
ROL.W #8,D1 ROL.W #8,D1
ROL.W #4,D1 ROL.W #4,D1
ADD.W D1,D0 ADD.W D1,D0
MOVE.W D0,bplcon0(A1) 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) MOVE.W #0,bplcon1(A1)
MOVE.W #0,bplcon2(A1)
; sprites always on top for this demo
MOVE.W #$0020,bplcon2(A1)
; no modulos needed
MOVE.W #0,bpl1mod(A1) MOVE.W #0,bpl1mod(A1)
MOVE.W #0,bpl2mod(A1) MOVE.W #0,bpl2mod(A1)
; pal default
MOVE.W #$2c81,diwstrt(A1) MOVE.W #$2c81,diwstrt(A1)
; pal trick MOVE.W #$2cc1,diwstop(A1)
MOVE.W #$f4c1,diwstop(A1)
MOVE.W #$38c1,diwstop(A1)
MOVE.W #$0038,ddfstrt(A1) MOVE.W #$0038,ddfstrt(A1)
MOVE.W #$00d0,ddfstop(A1) MOVE.W #$00d0,ddfstop(A1)
MOVE.L (SP)+,D2 MOVE.L (SP)+,D2
@ -429,5 +482,8 @@ VBIPtr dc.l 0
CNOP 0,4 CNOP 0,4
GraphicsLibrary GRAPHICSNAME GraphicsLibrary GRAPHICSNAME
CNOP 0,4
_keyboardPressed dc.l 0
SECTION Sprite,Data_C SECTION Sprite,Data_C
EmptySprite dc.w 0,0 EmptySprite dc.w 0,0

BIN
topaz-bitplane Normal file

Binary file not shown.

BIN
topaz-narrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
topaz.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -3,6 +3,14 @@
#include <exec/types.h> #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 short color_t;
typedef unsigned long uint32_t; typedef unsigned long uint32_t;
typedef unsigned short uint16_t; typedef unsigned short uint16_t;