#include #include #include #include #include #include #include #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(); } } void renderMostlyTopaz(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 < 2; ++plane) { custom.bltcon0 = bltcon0; custom.bltcon1 = 0; custom.bltafwm = 0xffff; custom.bltalwm = 0xffff; custom.bltapt = MaskBitplane + (30 * TOPAZ_WIDTH_BYTES); custom.bltbpt = bltbpt + (30 * TOPAZ_WIDTH_BYTES); custom.bltcpt = 30 * screenDefinition.byteWidth + activeScreenBufferDetails.planes[plane] + 8; custom.bltdpt = 30 * screenDefinition.byteWidth + activeScreenBufferDetails.planes[plane] + 8; custom.bltamod = 0; custom.bltbmod = 0; custom.bltcmod = bltcmod; custom.bltdmod = bltcmod; custom.bltsize = BLTSIZE(TOPAZ_WIDTH_WORDS, 196); 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); } uint16_t renderPartialAreas[BUN_COUNT][5]; void calculateTopazRenderPartialAreas( uint16_t redrawRanges[BUN_COUNT][4] ) { int topazX; uint16_t i, width, height, screenX; for (i = 0; i < BUN_COUNT; ++i) { renderPartialAreas[i][0] = 0; 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] + 16; height = redrawRanges[i][3] - redrawRanges[i][1]; topazX = redrawRanges[i][0] - 64; screenX = redrawRanges[i][0]; if (topazX < 0) { //printf("Too far left, adjusting...\n"); topazX += 16; screenX += 16; width -= 16; } if (topazX + width > 64 + TOPAZ_WIDTH_PIXELS) { //printf("Too far right, adjusting...\n"); width -= 16; } renderPartialAreas[i][0] = width; renderPartialAreas[i][1] = height; renderPartialAreas[i][2] = topazX; renderPartialAreas[i][3] = screenX; renderPartialAreas[i][4] = redrawRanges[i][1]; } } } } void calculateTopazRenderPartialBlitterSettings() { uint16_t bltapt, bltcpt, bltamod, bltcmod, bltsize; int i; for (i = 0; i < BUN_COUNT; ++i) { if (renderPartialAreas[i][0] == 0) continue; bltapt = renderPartialAreas[i][4] * TOPAZ_WIDTH_BYTES + (renderPartialAreas[i][2] >> 4) * 2; bltcpt = renderPartialAreas[i][4] * screenDefinition.byteWidth + (renderPartialAreas[i][3] >> 4) * 2; printf("%d, %d\n", screenDefinition.byteWidth, renderPartialAreas[i][0]); bltamod = TOPAZ_WIDTH_BYTES - (renderPartialAreas[i][0] >> 4) * 2; bltcmod = screenDefinition.byteWidth - (renderPartialAreas[i][0] >> 4) * 2; bltsize = BLTSIZE((renderPartialAreas[i][0] >> 4), renderPartialAreas[i][1]); renderPartialAreas[i][0] = bltapt; renderPartialAreas[i][1] = bltcpt; renderPartialAreas[i][2] = bltamod; renderPartialAreas[i][3] = bltcmod; renderPartialAreas[i][4] = bltsize; } } void renderTopazPartials( uint16_t redrawRanges[BUN_COUNT][4] ) { int plane, i, topazX, screenX; uint16_t bltcon0; uint16_t bltamod, bltbmod, bltcmod, bltdmod; uint16_t width, height, bltsize; uint32_t bltapt, bltbpt, bltcpt, bltdpt; bltcon0 = 0xca + (1 << 8) + (1 << 9) + (1 << 10) + (1 << 11); WaitTOF(); 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] + 16; height = redrawRanges[i][3] - redrawRanges[i][1]; topazX = redrawRanges[i][0] - 64; screenX = redrawRanges[i][0]; if (topazX < 0) { //printf("Too far left, adjusting...\n"); topazX += 16; screenX += 16; width -= 16; } if (topazX + width > 64 + TOPAZ_WIDTH_PIXELS) { //printf("Too far right, adjusting...\n"); width -= 16; } bltapt = redrawRanges[i][1] * TOPAZ_WIDTH_BYTES + (topazX >> 4) * 2; bltbpt = bltapt; bltcpt = redrawRanges[i][1] * screenDefinition.byteWidth + (screenX >> 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("MaskBitplane: %d\n", MaskBitplane); printf("TopazBitplanes: %d\n", TopazBitplanes); printf("ActiveScreenBuffer Plane 0: %d\n", activeScreenBufferDetails.planes[0]); printf("BLTAPT: %d\n", bltapt); printf("BLTAPT src: %d\n", bltapt + (uint32_t)MaskBitplane); printf("BLTBPT: %d\n", bltbpt); printf("BLTBPT src: %d\n", bltbpt + (uint32_t)TopazBitplanes); printf("BLTCPT: %d\n", bltcpt); printf("BLTCPT src: %d\n", bltcpt + (uint32_t)activeScreenBufferDetails.planes[0] + 8); printf("BLTDPT: %d\n", bltdpt); printf("BLTDPT src: %d\n", bltdpt + (uint32_t)activeScreenBufferDetails.planes[0] + 8); 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); */ bltapt += (uint32_t)MaskBitplane; bltbpt += (uint32_t)TopazBitplanes; for (plane = 0; plane < 2; ++plane) { custom.bltcon0 = bltcon0; custom.bltcon1 = 0; custom.bltafwm = 0xffff; custom.bltalwm = 0xffff; custom.bltapt = bltapt; custom.bltbpt = bltbpt + (plane * TOPAZ_WIDTH_BYTES * 256); custom.bltcpt = bltcpt + activeScreenBufferDetails.planes[plane]; custom.bltdpt = bltdpt + activeScreenBufferDetails.planes[plane]; custom.bltamod = bltamod; custom.bltbmod = bltbmod; custom.bltcmod = bltcmod; custom.bltdmod = bltdmod; custom.bltsize = bltsize; WaitBlit(); } break; } } } } 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) { int i; struct BunRenderer bunRenderer; uint16_t redrawRanges[BUN_COUNT][4]; /* allocateDoubleBufferedScreenMemory( &screenDefinition, &activeScreenBufferDetails, SCREEN_WIDTH, SCREEN_HEIGHT, 3 ); setupBunRenderer( &bunRenderer, &screenDefinition, &activeScreenBufferDetails ); calculateNeededRedrawRanges(i, redrawRanges); calculateTopazRenderPartialAreas(redrawRanges); printf("********\n"); for (i = 0; i < BUN_COUNT; ++i) { if (renderPartialAreas[i][0] == 0) continue; printf( "%d, %d, %d, %d, %d\n", renderPartialAreas[i][0], renderPartialAreas[i][1], renderPartialAreas[i][2], renderPartialAreas[i][3], renderPartialAreas[i][4] ); } calculateTopazRenderPartialBlitterSettings(); printf("********\n"); for (i = 0; i < BUN_COUNT; ++i) { if (renderPartialAreas[i][0] == 0) continue; printf( "%d, %d, %d, %d, %x\n", renderPartialAreas[i][0], renderPartialAreas[i][1], renderPartialAreas[i][2], renderPartialAreas[i][3], renderPartialAreas[i][4] ); } teardownScreen(&screenDefinition); return 0; */ 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) ); } */ setupKeyboard(); takeOverSystem(); setCopperlist(copperlist); setUpDisplay((uint32_t)screenDefinition.bitplanes); renderTopaz(); swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails); renderTopaz(); swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails); updateDisplayInCopperList( &screenDefinition, &activeScreenBufferDetails, copperlistBitplanePointers ); i = 0; while (1) { WaitTOF(); swapCurrentScreenBuffer(&screenDefinition, &activeScreenBufferDetails); clearCurrentBuns(&bunRenderer); renderBunFrame(i, &bunRenderer); /* calculateNeededRedrawRanges(i, redrawRanges); renderTopazPartials(redrawRanges); */ renderMostlyTopaz(); //WaitTOF(); updateDisplayInCopperList( &screenDefinition, &activeScreenBufferDetails, copperlistBitplanePointers ); //WaitBOF(100); //WaitTOF(); if (keyboardPressed) { i++; } if ((ciaa.ciapra >> 6) != 3) break; i++; i %= FRAMES_FOR_SCREEN; } giveBackSystem(); teardownKeyboard(); teardownScreen(&screenDefinition); freeCopperlist(copperlist); teardownBunRenderer(); return 0; }