#include #include #include #include #include #include #include #include #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" extern struct Custom far custom; extern struct CIA far ciaa; // change to 0 to not render sprites #define RENDER_SPRITES (1) struct ScreenDefinition screenDefinition; struct ActiveScreenBufferDetails activeScreenBufferDetails; /** * 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 */ void *copperlistBitplanePointers[8][2]; 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 TOPAZ_WIDTH_PIXELS (160) #define TOPAZ_WIDTH_BYTES (TOPAZ_WIDTH_PIXELS / 8) #define TOPAZ_WIDTH_WORDS (TOPAZ_WIDTH_PIXELS / 16) #define BLTSIZE(w, h) (w + (h << 6)) void renderTopaz(void) { int plane; uint16_t bltcon0, bltcmod; uint8_t *bltbpt; bltcon0 = 0xca + (1 << 8) + (1 << 9) + (1 << 10) + (1 << 11); bltcmod = screenDefinition.byteWidth - TOPAZ_WIDTH_BYTES; bltbpt = TopazBitplanes; for (plane = 0; plane < 3; ++plane) { custom.bltcon0 = bltcon0; 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); 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 { printf("Skipping render\n"); 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); } void renderTopazPartials( uint16_t redrawRanges[BUN_COUNT][4] ) { int plane, i, topazX; uint16_t bltcon0; uint16_t bltamod, bltbmod, bltcmod, bltdmod; uint16_t width, height, bltsize; uint8_t *bltapt, *bltbpt, *bltcpt, *bltdpt; bltcon0 = 0xca + (1 << 8) + (1 << 9) + (1 << 10) + (1 << 11); bltcmod = screenDefinition.byteWidth; bltbpt = TopazBitplanes; for (i = 0; i < BUN_COUNT; ++i) { if (redrawRanges[i][2] - redrawRanges[i][0] < TOPAZ_WIDTH_PIXELS) { if ( (redrawRanges[i][2] > 64 && redrawRanges[i][0] < (64 + TOPAZ_WIDTH_PIXELS)) || (redrawRanges[i][0] < (64 + TOPAZ_WIDTH_PIXELS) && redrawRanges[i][2] > 64) ) { width = redrawRanges[i][2] - redrawRanges[i][0]; height = redrawRanges[i][3] - redrawRanges[i][1]; topazX = redrawRanges[i][0] - 64; if (topazX < 0) { topazX += 16; width -= 16; } // always round up to the next word width += 16; bltapt = redrawRanges[i][1] * TOPAZ_WIDTH_BYTES + (topazX >> 4) * 2; bltbpt = bltapt; bltcpt = redrawRanges[i][1] * screenDefinition.byteWidth + (redrawRanges[i][0] >> 4) * 2; bltdpt = bltcpt; bltamod = TOPAZ_WIDTH_BYTES - (width >> 4) * 2; bltbmod = bltamod; bltcmod = screenDefinition.byteWidth - (width >> 4) * 2; bltdmod = bltcmod; bltsize = BLTSIZE((width >> 4), height); printf( "Coords: %d, %d -> %d, %d\n", redrawRanges[i][0], redrawRanges[i][1], redrawRanges[i][2], redrawRanges[i][3] ); printf("topazX: %d\n", topazX); printf("width: %d\n", width); printf("BLTAPT: %d\n", bltapt); printf("BLTBPT: %d\n", bltbpt); printf("BLTCPT: %d\n", bltcpt); printf("BLTDPT: %d\n", bltdpt); printf("BLTAMOD: %d\n", bltamod); printf("BLTBMOD: %d\n", bltbmod); printf("BLTCMOD: %d\n", bltcmod); printf("BLTDMOD: %d\n", bltdmod); printf("BLTSIZE: %d, %d\n", (width >> 4), height); /* for (plane = 0; plane < 3; ++plane) { custom.bltcon0 = bltcon0; 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); bltbpt += TOPAZ_WIDTH_BYTES * 256; WaitBlit(); } */ } } } } int main(void) { int i; struct BunRenderer bunRenderer; uint16_t redrawRanges[BUN_COUNT][4]; 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"); 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"); printf("\nEnjoy, and thanks for watching!\n"); printf("John (theindustriousrabbit.com)\n\n"); 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) ); } */ calculateNeededRedrawRanges(0, redrawRanges); renderTopazPartials(redrawRanges); /* takeOverSystem(); setCopperlist(copperlist); setUpDisplay((uint32_t)screenDefinition.bitplanes); renderTopaz(); swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails); renderTopaz(); swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails); i = 0; while (0) { swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails); clearCurrentBuns(&bunRenderer); renderBunFrame(i, &bunRenderer); updateDisplayInCopperList( &screenDefinition, &activeScreenBufferDetails, copperlistBitplanePointers ); WaitBOF(250); if ((ciaa.ciapra >> 6) != 3) break; i++; //i %= FRAMES_FOR_SCREEN; } giveBackSystem(); */ teardownScreen(&screenDefinition); freeCopperlist(copperlist); teardownBunRenderer(); return 0; }