diff --git a/agnus.png b/agnus.png new file mode 100644 index 0000000..c359964 Binary files /dev/null and b/agnus.png differ diff --git a/bun.c b/bun.c index 028bfb3..c64c74a 100644 --- a/bun.c +++ b/bun.c @@ -31,12 +31,11 @@ #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 (30) -#define BUN_VERT_DISTANCE_BETWEEN_BUNS (20) +#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 FRAMES_FOR_SCREEN (90) #define BUN_WAVE_LENGTH (FRAMES_FOR_SCREEN / 2) // linked as raw bytes in assembler diff --git a/bun.h b/bun.h index b10af54..b780f92 100644 --- a/bun.h +++ b/bun.h @@ -3,6 +3,8 @@ #include "screen.h" +#define FRAMES_FOR_SCREEN (60) + struct BunRenderer { struct ScreenSetup *screenSetup; struct CurrentScreen *currentScreen; diff --git a/copper-colors b/copper-colors new file mode 100644 index 0000000..5b4ed90 Binary files /dev/null and b/copper-colors differ diff --git a/image_converter.rb b/image_converter.rb index dff49e3..f1594d0 100755 --- a/image_converter.rb +++ b/image_converter.rb @@ -17,6 +17,10 @@ class MaskPixel def initialize; end def color? = false + + def ==(other) + other.is_a?(MaskPixel) + end end class Color @@ -30,15 +34,24 @@ class Color 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 @@ -60,6 +73,8 @@ MAX_ALPHA = Magick::QuantumRange * 0.25 BIT_SHIFT = Math.log2(Magick::QuantumRange + 1) - 4 class PixelRow + include Enumerable + def initialize @row = [] end @@ -68,10 +83,284 @@ class PixelRow @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] += 1 + 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 + + 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] + 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 @@ -94,63 +383,53 @@ image.each_pixel do |px, x, y| rows[y].add(pixel:, x:) end -prioritized_colors = rows[50].colors_with_usage.to_a.sort { |a, b| b.last <=> a.last } +copper_colors = '' +topaz_bitplanes = [''] * 3 +sprite_copperlist = '' +sprite_data = [''] * 8 -presets_by_pixel_color = [ - nil, Color::BLACK, Color::WHITE -] +mask_bitplane = '' -unavailable_bitplane_colors = { - 0 => true, - 1 => true, - 2 => true -} +8.times do |i| + result = Amiga::Util.sprposctl(x: 319, y: 0) + sprite_data[i] = [result[:sprpos], result[:sprctl]].pack('n*') +end -MAX_BITPLANE_COLORS = 8 +rows.each_with_index do |row, y_offset| + result = RowColorCalculator.calculate(row:) -bitplane_colors = [ - nil, - Color::BLACK, - Color::WHITE -] + 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] -color_to_pixel_map = {} + bitplanes = RowBitplaneCalculator.calculate(row:, bitplane_pixels_by_color:) + sprites = RowSpriteCalculator.calculate(y: y_offset, row:, sprite_pixels_by_color:).values -# take 5 + BLACK + WHITE colors into bitplane_colors + mask = RowMaskBitplaneCalculator.calculate(row:) -prioritized_colors.map(&:first).each do |color| - maybe_preset_index = presets_by_pixel_color.find_index { |c| c && color == c } + mask_bitplane += Amiga::BitplaneMaskDataFactory.build(bitplane: mask) - if !maybe_preset_index.nil? - bitplane_colors[maybe_preset_index] = color - color_to_pixel_map[color] = maybe_preset_index + copper_colors += Amiga::BitplaneCopperlistFactory.build(colors_by_bitplane_pixel:) + raw_bitplanes = Amiga::BitplaneDataFactory.build(bitplanes:) - unavailable_bitplane_colors[maybe_preset_index] = true - elsif bitplane_colors.count < MAX_BITPLANE_COLORS - next_available_bitplane_color = 8.times.find { |i| !unavailable_bitplane_colors[i] } + sprite_copperlist += Amiga::SpriteCopperlistFactory.build(sprites:, y_offset:) + raw_sprite_data = Amiga::SpriteDataFactory.build(sprites:) - bitplane_colors[next_available_bitplane_color] = color - color_to_pixel_map[color] = next_available_bitplane_color + raw_bitplanes.each_with_index do |raw, index| + topaz_bitplanes[index] += raw + end - unavailable_bitplane_colors[next_available_bitplane_color] = true - else - closest_match = bitplane_colors.each_with_index.map do |bp_color, index| - next unless bp_color - - [(bp_color - color).abs, index] - end.compact.min_by(&:first) - - pp color - pp closest_match - pp bitplane_colors[closest_match.last] - puts '************************' - - color_to_pixel_map[color] = closest_match.last + raw_sprite_data.each_with_index do |raw, index| + sprite_data[index] += raw end end -pp prioritized_colors -pp bitplane_colors -pp color_to_pixel_map +8.times do |i| + sprite_data[i] += [0, 0].pack('n*') +end -# .to_a.sort(&:last).reverse +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('') } diff --git a/images.s b/images.s index cf0c8c5..ffbad83 100644 --- a/images.s +++ b/images.s @@ -1,4 +1,31 @@ XDEF _coolbun + XDEF _TopazBitplanes + XDEF _CopperColors + XDEF _SpriteCopperlist + XDEF _SpriteData + XDEF _MaskBitplane _coolbun: INCBIN "images/bun small.raw" + + CNOP 0,4 + + SECTION Topaz,Data_C +_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" diff --git a/main b/main index 19363d4..6f276b9 100755 Binary files a/main and b/main differ diff --git a/main.c b/main.c index ba22e1b..bfa9ee9 100644 --- a/main.c +++ b/main.c @@ -6,6 +6,7 @@ #include #include +#include #include @@ -18,6 +19,7 @@ #include "bun.h" extern struct Custom far custom; +extern struct CIA far ciaa; // this should be large enough to hold one bitplane of the largest object // you are blitting, plus one additional word on each side @@ -38,9 +40,6 @@ 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); -uint16_t chip spriteData[200]; -uint16_t chip spriteData2[20]; - uint16_t spritePositionsEachLine[256][2]; void calculageSpritePositionsEachLine() { @@ -59,8 +58,15 @@ void calculageSpritePositionsEachLine() { (x & 1) \ ) +extern uint8_t chip TopazBitplanes[]; +extern uint16_t chip CopperColors[]; +extern uint16_t chip SpriteCopperlist[]; +extern uint16_t chip SpriteData[]; +extern uint16_t chip MaskBitplane[]; + int main(void) { - uint16_t *copperlist, *currentCopperlist, result; + uint16_t *copperlist, *currentCopperlist, *currentCopperColors, result, *currentSpriteCopperlist; + uint32_t spriteDataPointer; int i, x, y, height, plane; struct BunRenderer bunRenderer; @@ -72,51 +78,13 @@ int main(void) { colors[2] = 0x0fff; colors[3] = 0x000f; - printf("%p\n", &spriteData); + printf("%x\n", &SpriteData); printf("setting up, i haven't crashed...yet.\n"); - x = 150; - y = 47; - height = y + 98; - - printf("%d, %d, %d\n", x, y, height); - - spriteData[0] = SPRPOS(x, y); - spriteData[1] = SPRCTL(x, y, height); - - printf("%0x %0x\n", spriteData[0], spriteData[1]); - - for (i = 2; i < 198; i += 2) { - spriteData[i] = 0x0f + i % 16; - spriteData[i + 1] = 0xf0f0; - } - - spriteData[198] = 0x0000; - spriteData[199] = 0x0000; - - spriteData2[0] = SPRPOS(220, 70); - spriteData2[1] = SPRCTL(220, 70, 72); - /* - spriteData2[2] = 0x0345; - spriteData2[3] = 0x5678; - spriteData2[4] = 0x9abc; - spriteData2[5] = 0xdef0; - */ - spriteData2[2] = 0xffff; - spriteData2[3] = 0xffff; - spriteData2[4] = 0xffff; - spriteData2[5] = 0xffff; - spriteData2[6] = SPRPOS(230, 150); - spriteData2[7] = SPRCTL(230, 150, 151); - spriteData2[8] = 0xffff; - spriteData2[9] = 0xffff; - spriteData2[10] = 0; - spriteData2[11] = 0; - setupScreen(&screenSetup, SCREEN_WIDTH, SCREEN_HEIGHT, 3); setupInitialCurrentScreen(&screenSetup, ¤tScreen); - //setupBunRenderer(&bunRenderer, &screenSetup, ¤tScreen); + setupBunRenderer(&bunRenderer, &screenSetup, ¤tScreen); // blitter copy the first bitplane row down to the second @@ -133,11 +101,10 @@ int main(void) { ¤tScreen, &copperlistBitplanePointers ); - currentCopperlist = setUpEmptySpritesInCopperlist(currentCopperlist); - *(currentCopperlist++) = custom_color; - *(currentCopperlist++) = 0x000; + currentCopperColors = CopperColors; + currentSpriteCopperlist = SpriteCopperlist; *(currentCopperlist++) = custom_color + 2; *(currentCopperlist++) = 0x000; @@ -145,77 +112,72 @@ int main(void) { *(currentCopperlist++) = custom_color + 4; *(currentCopperlist++) = 0xfff; - *(currentCopperlist++) = custom_color + 6; - *(currentCopperlist++) = 0x00F; + for (i = 0; i < 8; ++i) { + spriteDataPointer = (uint32_t)&SpriteData; + spriteDataPointer += ((256 + 2) * 4) * i; - // sprites - *(currentCopperlist++) = custom_color + 34; - *(currentCopperlist++) = 0xF0F; + *(currentCopperlist++) = custom_sprite + i * 4; + *(currentCopperlist++) = (spriteDataPointer >> 16); - *(currentCopperlist++) = custom_color + 36; - *(currentCopperlist++) = 0xFF0; + *(currentCopperlist++) = custom_sprite + 2 + i * 4; + *(currentCopperlist++) = (spriteDataPointer & 0xffff); + } - *(currentCopperlist++) = custom_color + 38; - *(currentCopperlist++) = 0x00F; - - *(currentCopperlist++) = custom_sprite; - *(currentCopperlist++) = ((uint32_t)&spriteData2 >> 16); - - *(currentCopperlist++) = custom_sprite + 2; - *(currentCopperlist++) = ((uint32_t)&spriteData2 & 0xffff); + *(currentCopperlist++) = custom_color; + *(currentCopperlist++) = 0x3a6; for (y = 0; y < 256; ++y) { + for (i = 0; i < 8; ++i) { + *(currentCopperlist++) = custom_color + 32 + ( + // sprite color group + (i / 2) * 4 + + // 0 is transparent + 1 + + i % 2 + ) * 2; + + *(currentCopperlist++) = *(currentSpriteCopperlist++); + //*(currentCopperlist++) = 0xf0f; + + //currentSpriteCopperlist++; + + *(currentCopperlist++) = custom_sprite_control + i * 8; + *(currentCopperlist++) = *(currentSpriteCopperlist++); + + *(currentCopperlist++) = custom_sprite_control + i * 8 + 2; + *(currentCopperlist++) = *(currentSpriteCopperlist++); + } + + for (i = 3; i < 8; ++i) { + *(currentCopperlist++) = custom_color + (i * 2); + *(currentCopperlist++) = *(currentCopperColors++); + } + + *(currentCopperlist++) = 1 + ((31 + (256 / 4)) << 1) + ((44 + y) << 8); + *(currentCopperlist++) = 0xFFFE; /* - if (y > 100 && y < 135) { - *(currentCopperlist++) = custom_sprite_control; - *(currentCopperlist++) = SPRPOS(60 + y, y); - - *(currentCopperlist++) = custom_sprite_control + 2; - *(currentCopperlist++) = SPRCTL(60 + y, y, 0); - } - */ - - *(currentCopperlist++) = 1 + (1 << 1) + ((44 + y) << 8); - *(currentCopperlist++) = 0xFFFE; - - if (y == 27) { - /* - *(currentCopperlist++) = custom_sprite_control; - *(currentCopperlist++) = 0; - - *(currentCopperlist++) = custom_sprite_control + 2; - *(currentCopperlist++) = 0; - */ - - *(currentCopperlist++) = custom_sprite; - *(currentCopperlist++) = ((uint32_t)&spriteData >> 16); - - *(currentCopperlist++) = custom_sprite + 2; - *(currentCopperlist++) = ((uint32_t)&spriteData & 0xffff); - - *(currentCopperlist++) = custom_sprite_control; - *(currentCopperlist++) = SPRPOS(60, 100); - - *(currentCopperlist++) = custom_sprite_control + 2; - *(currentCopperlist++) = SPRCTL(60, 100, 198); - } - - *(currentCopperlist++) = 1 + (31 << 1) + ((44 + y) << 8); - *(currentCopperlist++) = 0xFFFE; *(currentCopperlist++) = custom_color; *(currentCopperlist++) = 0x9b8; + */ + /* + *(currentCopperlist++) = 1 + (1 << 1) + ((44 + y) << 8); + *(currentCopperlist++) = 0xFFFE; + */ + + /* *(currentCopperlist++) = 1 + ((31 + (320 / 4)) << 1) + ((44 + y) << 8); *(currentCopperlist++) = 0xFFFE; *(currentCopperlist++) = custom_color; *(currentCopperlist++) = 0x000; - + */ } endCopperlist(currentCopperlist); - for (i = 0; i < 200; ++i) { - /* + i = 0; + + while (1) { swapCurrentScreenBuffer(&screenSetup, ¤tScreen); for (plane = 0; plane < 2; ++plane) { @@ -230,16 +192,48 @@ int main(void) { WaitBlit(); } - //renderBunFrame(i, &bunRenderer); + renderBunFrame(i, &bunRenderer); + + /* + */ + + for (plane = 0; plane < 3; ++plane) { + custom.bltcon0 = 0xca + (1 << 8) + (1 << 9) + (1 << 10) + (1 << 11); + custom.bltcon1 = 0; + custom.bltafwm = 0xffff; + custom.bltalwm = 0xffff; + custom.bltapt = MaskBitplane; + custom.bltbpt = TopazBitplanes + (plane * 32 * 256); + custom.bltcpt = currentScreen.planes[plane]; + custom.bltdpt = currentScreen.planes[plane]; + custom.bltamod = 0; + custom.bltbmod = 0; + custom.bltcmod = screenSetup.byteWidth - 32; + custom.bltdmod = screenSetup.byteWidth - 32; + custom.bltsize = 16 + (256 << 6); + + WaitBlit(); + } + + /* + *(SpriteData) = SPRPOS(250, 44); + *(SpriteData + 1) = SPRCTL(250, 44, 44 + 257); + */ updateDisplayInCopperList( &screenSetup, ¤tScreen, copperlistBitplanePointers ); - */ + WaitTOF(); + //WaitTOF(); + + if ((ciaa.ciapra >> 6) != 3) break; + + i++; + i %= FRAMES_FOR_SCREEN; } /* @@ -250,12 +244,16 @@ int main(void) { giveBackSystem(); - for (i = 10; i < 50; ++i) { - printf("%x ", copperlist[i]); - } - teardownScreen(&screenSetup); + /* + for (i = 0; i < 50; ++i) { + printf("%x %x\n", copperlist[i * 2], copperlist[i * 2 + 1]); + } +*/ + + printf("%x %x", SPRPOS(250, 44), SPRCTL(250, 44, 44 + 256)); + freeCopperlist(copperlist); teardownBunRenderer(); diff --git a/mask-bitplane b/mask-bitplane new file mode 100644 index 0000000..042d777 Binary files /dev/null and b/mask-bitplane differ diff --git a/sprite-copperlist b/sprite-copperlist new file mode 100644 index 0000000..ece03cb Binary files /dev/null and b/sprite-copperlist differ diff --git a/sprite-data b/sprite-data new file mode 100644 index 0000000..7ae3830 Binary files /dev/null and b/sprite-data differ diff --git a/system/system.s b/system/system.s index c5f6e66..078b8c7 100644 --- a/system/system.s +++ b/system/system.s @@ -365,8 +365,9 @@ _setUpDisplay: MOVE.W #0,bpl2mod(A1) MOVE.W #$2c81,diwstrt(A1) ; pal trick - MOVE.W #$f4c1,diwstop(A1) - MOVE.W #$38c1,diwstop(A1) + ;MOVE.W #$f4c1,diwstop(A1) + ;MOVE.W #$38c1,diwstop(A1) + MOVE.W #$2cc1,diwstop(A1) MOVE.W #$0038,ddfstrt(A1) MOVE.W #$00d0,ddfstop(A1) MOVE.L (SP)+,D2 diff --git a/topaz-bitplane b/topaz-bitplane new file mode 100644 index 0000000..e5a7848 Binary files /dev/null and b/topaz-bitplane differ diff --git a/topaz2.png b/topaz2.png new file mode 100644 index 0000000..64e8984 Binary files /dev/null and b/topaz2.png differ