************************************************ * 256 Color demo for Color Computer 3 * Copyright Chris Lomont 2007 www.lomont.org ************************************************ * Theory - although there are several programs showing how to get * many simultaneous colors onscreen for the CoCo3, none (I have seen) * are suitable for animation, since they involve many pages of data * and long preprocessing times. I wanted to see if I could get many * colors with as little overhead as possible for animation, games, * and my Mandelbrot generator. Here are some ways to get many colors: * 1. Palette flipping - this works well, except it introduces flicker * unless you are careful, and has the overhead of writing palette * registers a lot. You can do it per line, per screen, or any mix. * 2. Page swapping - the idea is to draw on different images with * different colors, and flip the images back and forth. Since the * CoCo3 is hardware limited to 60 frames per second (fps), a 2 page * flip will result in 30 fps, which is ok visually. * 3. Dithering - totally unacceptable for realtime animation, due to * the computational overhead. * * I initially wrote a two page flip, two palette version, but * mathematically it is very difficult to get good colors. The reason * is that for two colors A and B, the resulting color is (A+B)/2, and * you get many different ways to hit the same result color. For * example, if you have RGB palette color (2,0,0) in the first palette, * color (1,0,0) in both palettes, and color (0,0,0) in the second * palette, you end up with two ways to get * (1,0,0) = ((2,0,0)+(0,0,0))/2 = ((1,0,0)+(1,0,0))/2. * * This effectively loses a color. This coupled with the fact you want * nice colors like pure white and pure black leads to a host of * problems trying to pick a palette. * * Next solution is to do two page cycle, but let one page last twice * as long as the other, leading to an effective 20 fps, which is * about as slow as you can visually go (and even 20 fps is sorta * flickery). This time the color mixing is effectively (2A+B)/3, which * leads to an easier solution to the palette choice. Furthermore, you * can find a single palette which behaves nicely, removing the * requirement that you change palettes to get a wide range of colors. * * In this case a nice palette I hand constructed leads to 240 unique * colors, with a nice mix of colors. Computer perturbing this over * many iterations led to several palettes which have 256 unique * colors. In the code below Palette240 is the one leading to 240 * colors, and Palette256 is the one leading to 256 colors. However, * so far I have not found a palette leading to 256 colors that also * includes pure white and pure black. The palette included here gets * close. * * So, in short, the best idea so far is a 2 page flip, with a single * palette for all pages, where one page is shown 2 frames and then * the other once, and then repeat. * * This is just a proof of concept for fun, and it could be enhanced in * many ways. The first thing to do is pick a nice palette mapping, and * see if the palette can be improved, so you can write some call like * SetPixel(x,y,r,g,b) in a nice manner. * * Finally, this palette is chosen for a RGB demo, but you can convert * it to get an equivalent one for composite. * * to be continued ...... perhaps...... Next time draw bouncing lines? * * * * How this program works: * 1. Disable interrupts, high speed poke * 2. Display 320x192x16 graphics mode at GIME page $30(=$60000 address) * 3. Set 16 palette colors * 4. Load GIME pages $30-33 into CPU RAM $8000-$FFFF, draw horiz lines image * 5. Load GIME pages $34-37 into CPU RAM $8000-$FFFF, draw vert lines image * 6. Install interrupt handler to fire on vertical blank to toggle images * 7. Infinite loop INIT0 equ $FF90 * GIME Initialization register 0 IRQENR equ $FF92 * IRQ interrupt source FIRQENR equ $FF93 * FIRQ interrupt source VMODE equ $FF98 * Video mode - sets lines per row, text/graphics VRES equ $FF99 * Video resolution - sets size VIDSTART equ $FF9D * video memory start register FIRQADDR equ $FEF4 * where FIRQ jumps org 16384 * program start start * 1. Disable interrupts, high speed poke orcc #$50 * disable interrupts sta $FFD9 * high speed poke * 2. Display 320x192x16 graphics mode at GIME page $30(=$60000 address) lda #%01001100 * Coco3, MMU on, DRAM constant, standard SCS 16K internal 16K external ROM sta INIT0 lda #%10000000 sta VMODE * graphics mode, 60 hz, normal burst lda #%00011110 * width 320, height 192 sta VRES ldd #$C000 * first block of graphics screen at $60000 / 8 std VIDSTART * vidstart offset * 3. Set 16 palette colors ldx #$FFB0 * set palette entries leay Palette256,pcr ldb 16 * 16 entries ! lda ,y+ sta ,x+ decb bne < * 4. Load GIME pages $30-33 into CPU RAM $8000-$FFFF, draw horiz line image lda #$30 * this page default bsr SetGraphicsMem * set the memory pages ldx #$8000 * screen start clra * color 00 horiz ldy #1920 * bytes per 1/16 of screen ! sta ,x+ leay -1,y * decrement counter bne < adda #$11 * increment both pixel colors cmpx #$F800 * end of graphics blt horiz bsr SetFIRQ * set interrupt jump in the page $37 * 5. Load GIME pages $34-37 into CPU RAM $8000-$FFFF, draw vert line image lda #$34 * next pages bsr SetGraphicsMem * draw 16 vertical stripes ldx #$8000 * screen start clra * color 00, each strip = 320/16=20 pixels = 10 bytes vert ldb #10 ! sta ,x+ decb bne < adda #$11 * increment both pixel colors bcc > * if carry, zero a clra ! cmpx #$F800 * end of graphics? blt vert bsr SetFIRQ * set interrupt jump in the page $37 * 6. Install interrupt handler to fire on VSYNC to toggle images lda #$08 * enable vertical blank interrupt sta FIRQENR * set the interrupt register clr IRQENR * disable these to be safe lda INIT0 * get this ora #$10 * enable GIME FIRQ interrupts sta INIT0 * and save it andcc #$BF * enable FIRQ interrupts * 7. Infinite loop ! bra < ************************************************ * SetFIRQ * Sets the FIRQ handler to jump to intV * REG: modifies REGD,REGY ************************************************ SetFIRQ lda #$7E * opcode for JMP sta FIRQADDR * save it leay intV,pcr * address to jump to sty FIRQADDR+1 rts ************************************************ * Set graphics memory - sets 32K in 0x8000-0xFFFF * from MMU pages 0x60000 on up * interrupts should be disabled to use this * REGA - first page to load (nice start pages are $30 and $34) * Registers changed: REGX,REGD ************************************************ SetGraphicsMem ldx #$FFA4 * mapped to $8000-$9FFF, then more ldb #4 * 4 pages to load ! sta ,x+ inca * next page decb bne < rts * palette leading to 240 colors Palette240 * fcb 32,36,16,18,8,9,25,44,50,54,45,27,43,0,56,63 * palette leading to 256 colors Palette256 fcb 44,45,32,39,3,2,8,9,25,50,54,19,43,4,56,63 vidPos fcb 1 * frame 0,1... to draw ************************************************ * vertical interrupt - draw frame at GIME $C000, * then $D000, and then repeat * NOTE: set this to change as fast as possible - todo * REGS: All registers must be saved ************************************************ intV pshs d,x * save these - we use FIRQ leax vidPos,pcr * what frame? lda ,x cmpa #2 bne showC showD ldd #$D000 std VIDSTART * show it clr ,x * reset bra vidOut showC ldd #$C000 std VIDSTART * show it inc ,x * next frame vidOut ldd FIRQENR * read (and clears) the interrupt source puls d,x rti final end start * set BASIC exec address * end of file - Color256.asm