OOMA 2

1169 words ~ 5-10 mins

Rotozoom with tilt and experimental music in a valid 480bytes Atari bootsector.

This entry for Outline 2007 was really hard to pull, and I missed the deadline by one or two hours. On the other hand the result was beyond my expectations and the feedback was really positive.

Source code

;
;      ##
;     # #   #######
;     # #  ##     #
;     ######  ### #
;   ### #  # #### #
;  #  ###  # ### ##
;  ####  ##  ## # #
;     #  #  #  # #
;    ####  # ####
;   ##    # ##   #
;  ##  ### ##  ####
;  #  #### #  #   #
;  # #### ## #  ###
;  # ### # # # #  #
;  #    # # ## # ##
;  #######   ######
;
; Ooma 2   bootsector
;
; Mathieu 'P01' HENRI
; http://www.p01.org/
;
; released at
;       Outline  2oo7
;
; 
; 
; Commented source code for Alive.
; 
; Ooma2 was originally written in JavaScript.
; Therefore some parts, especially the precalc,
; could use more comments. Don't worry, the
; formulas are given in the C-like syntax.
; 
; Technical trivia: X+Z rotozoom with "sample" replay
; 
; Charly is still 16x16 2bpl => 16*4+4*2 = 72b
; The render area is 24x45 in 4x4 "chunky" = 96x180
; The channel A of YM21496 is updated 45 times per VBL
; 
;
;___init______________________________________________
  ;
  ;   clear interruptions
  ;
  move.w #$2700,sr
  ;
  ;   set the palette
  ;
  lea     sprite(pc),a2
  move.w  #$8240,a3
  move.l  (a2)+,(a3)+
  move.l  (a2)+,(a3)
  not.w   26(a3)
  ;
  ;   data start address
  ;       =   v_bas_ad
  ;           - extendedSprite    ( 16x16x16 )
  ;           - sinusLut          ( 1536*2 )
  ;           - precalcUVdUdV     ( 1024*45*2*4 )
  ;
  move.l  $44e.w,a1
  suba.l  #16*16*16+1536*2+1024*45*2*4,a1
  ;
  ;   extend sprite
  ;
  move.l  a1,a6
  moveq   #16-1,d0
  move.l  d0,a5
  extend_sprite:
    move.l  (a2)+,d2    ; pop a slice of Charly
    moveq   #16-1,d1
  extend_sprite_process:
      move.l  d2,d3
      andi.l  #$10001,d3  ; grab the pixel in the LSB
      move.l  d3,d4       ; extend 4x
      lsl.l   #4,d3
      sub.l   d4,d3
      move.l  d3,(a1)     ; push the 4x extended pixel
      adda.w  #16,a1
      lsr.l   #1,d2       ; right shift the slice
    dbf d1,extend_sprite_process
  dbf d0,extend_sprite
  ;
  ;   generate sinusLut ( kudos to Ray/TSCC )
  ;
  move.w  #$4000,a5
  move.w  #512-1,d0
  ;
gen_loop:
    move.w  d0,d1
    sub.w   #256,d1
    muls.w  d1,d1
    lsr.w   #2,d1
    sub.w   a5,d1
    move.w  d1,512*2(a1)
    neg.w   d1
    move.w  d1,1024*2(a1)
    move.w  d1,(a1)+
  dbf d0,gen_loop
  ;
  ;   display the title
  ;
  pea     title(pc)
  move.w  #9,-(sp)
  trap    #1
  addq.l  #6,sp
  ;
  ;       precalc UV & dUdV
  ;
  move.l  a1,a0
  adda.w  #1024*2,a0
  move.l  a0,a4
  suba.w  #512*2-128*2,a1
  move.w  #1024-1,d0
precalc_main:
    ;
    ;   a0 = precalcUVdUdV
    ;   a1 = sinusLut
    ;
    not.w   26(a3)
    moveq   #45-1,d1
precalc_inner:
      ;
      ;   the formula used for the U,V,dV,dV, with:
      ;        w = 24
      ;        h = 45
      ;        x in the range [ 0, w-1 ]
      ;        y in the range [ 0, h-1 ]
      ;
      ;   p   = h*(1-cos(an))/4/(h+y*cos(an+PI/4))
      ;   dU  = p*cos(an)
      ;   dV  = p*sin(an)
      ;   U   = -w/2*dU+(y-h/2)*dV-.5
      ;   V   = -w/2*dV-(y-h/2)*dU-.5
      ;
      move.w  256(a1),d7
      move.l  a5,d2
      sub.w   d7,d2
      moveq   #45,d3
      sub.w   d1,d3
      muls.w  768(a1),d3
      lsl.l   #2,d3
      swap    d3
      ext     d3
      addi.w  #45,d3
      divs.w  d3,d2
      muls.w  d2,d7       ; d7 = dV
      move.l  d7,d4
      swap    d4
      move.l  d2,d5
      muls.w  (a1),d5     ; d5 = dU
      swap    d5
      move.w  d5,d7
      move.l  d7,(a0)+    ; push dUdV
      moveq   #22,d2
      sub.l   d1,d2
      moveq   #11,d3
      muls.w  d4,d3
      move.l  d2,d6
      muls.w  d5,d6
      sub.l   d3,d6       ; d6 = U
      swap    d6
      moveq   #11,d7
      muls.w  d5,d7
      muls.w  d4,d2
      sub.w   d2,d7       ; d7 = V
      move.w  d7,d6
      addi.l  #$7f807f80,d6
      move.l  d6,(a0)+    ; push UV
    dbf     d1,precalc_inner
    addq.l  #2,a1
  dbf d0,precalc_main
  move.l  a4,d7
  ;
  ;   YM2149 init
  ;
  move.w  #$8800,a1
  ;
;__main_______________________________________________
ooma2_main:
    ;
    ;   a0 = precalcUVdUdV
    ;   a1 = YM2149
    ;   a2 = screen
    ;   a6 = extendedSprite
    ;
    ; stabilize low enough for the render loop to
    ; not cross the beam
    ;
    cmp.b   #$d0,$ffff8207.w
    bne.s   *-6
    ;
    move.l  $44e.w,a2
    ;
    ;   effect loop ?
    ;
    cmpa.l  d7,a0
    bne.s   *+4
        move.l  a2,a0
    ;
    ;   render!
    ;
    moveq   #45-1,d0
render_y:
      ;   a5 = this row's UV
      ;   a4 = this row's dUdV
      move.l  -(a0),a5
      move.l  -(a0),a4
      moveq   #6-1,d1
render_x:
        ;   music
        ; Channel A rough|volume
        move.w  a5,d3
        andi.w  #$90d,d3
        movep.w d3,(a1)
          moveq   #0,d3
          moveq   #4-1,d2
render_process_16px:
          ;
          ;   mangle UV to point correctly in the
          ;   extended sprite
          ;
          move.l  a5,d5
          move.w  d5,d4
          andi.w  #$0f00,d4
          swap    d5
          lsr.w   #4,d5
          andi.b  #$f0,d5
          move.b  d5,d4
          ;
          ;   shift the 16px and push Charly's UV
          ;   extended pixel
          ;
          asl.l   #4,d3
          add.l   (a6,d4),d3
          ;   UV += dUdV
          add.l   a4,a5
        dbf d2,render_process_16px
        ;
        ;   output 16x4 pixels to the screen
        ;
        move.l  d3,160*10+80+160*0(a2)
        move.l  d3,160*10+80+160*1(a2)
        move.l  d3,160*10+80+160*2(a2)
        move.l  d3,160*10+80+160*3(a2)
        addq.w  #8,a2
      dbf d1,render_x
      adda.w  #160*4-96/2,a2
    dbf d0,render_y
    ;
    ;   press [space] ?
    ;
    cmpi.b  #57,$fffffc02.w
  bne ooma2_main
;__exit_______________________________________________
  ;
  ;   mute all YM2149 channels
  ;
  move.w  #$7ff,d5
  movep   d5,(a1)
  ;
  ;   reset the 4 first and the 15th colors and spare
  ;   your retina by replacing the burning green by a
  ;   gentle blue
  ;
  clr.w   26(a3)
  move.l  #$03450770,-(a3)
  move.l  #$07770700,(a3)
  ;
  ;   restore interruptions
  ;
  move.w #$2300,sr
  rts
  ;
;__data_______________________________________________
sprite
  ;   Charly's sexy skin tones
  dc.l    $01010420,$06410762
  ;
  ;   Hello Charly! long time no see
  dc.l    %00001000100001111110000001111000
  dc.l    %11011110100010100000000001110100
  dc.l    %00101000110101000110000000100100
  dc.l    %10001011011101010000001000000100
  dc.l    %11111001000010010000001001000100
  dc.l    %11111000100000110000000000011000
  dc.l    %11111111110101110000000000010000
  dc.l    %11101011111011110101110000000000
  dc.l    %11111111111111110101010000000000
  dc.l    %11101111111111110111010000000000
  dc.l    %11111111111110010000000000000001
  dc.l    %11011111001101010010000000000100
  dc.l    %01110010010101100000000011000010
  dc.l    %10110100000010110000010000000001
  dc.l    %11010001111000101100011101110001
  dc.l    %01010110100011100100000111110011
  ;
title
  ;   title text + VT52 codes to position it
  dc.b    27,"Y",32,52,"Ooma 2   p01"
  dc.b    27,"Y",56,52,"Outline 2oo7",0
  even

Feeback

Of course you can find Ooma 2 on Pouet


Other recent experiments

There are many experiments and projects like OOMA 2 to discover other here.


Let's talk

Don't be shy; get in touch by mail, twitter, github, linkedin or pouet if you have any questions, feedback, speaking or performance opportunity.