Upgrade to Pro — share decks privately, control downloads, hide ads and more …

'Raster Shaders' on Commodore 64

'Raster Shaders' on Commodore 64

Video cards can execute small programs whenever a pixel is displayed on screen.
Commodore 64 can execute small programs whenever a raster line is displayed on TV.

Pixel shaders can be used to create realistic lighting, special effects and even compute physics!
‘Raster shaders’ can be used to split screen, display more sprites and even play sound!

85977ebfe59c2ee669f2196930f1a701?s=128

Michał Taszycki

June 02, 2016
Tweet

Transcript

  1. “Raster Shaders” on

  2. I keep old computers alive mehowte  Michał Taszycki on

  3. I’m making a weekly video course about programming Commodore 64

    h/p:/ /64bites.com/
  4. Commodore 64 belongs to the past…

  5. Today

  6. Back then

  7. Today

  8. Back then

  9. Back then

  10. Back then?

  11. Today!

  12. Pixel Shader varying vec3 N; varying vec3 v; void main(void)

    { vec3 L = normalize(gl_LightSource[0].position.xyz - v); vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0); Idiff = clamp(Idiff, 0.0, 1.0); gl_FragColor = Idiff; }
  13. “Raster Shader” irq: lda #$ff sta $d019 ldx #$05 d:

    dex bne d ldx #$00 c: ldy #$08 a: lda colors,x sta $d020 sta $d021 inx dey beq c txa ldx #$07 b: dex bne b tax cpx #$8c bcc a
  14. Enough talking!

  15. Let’s code!

  16. A minimal program :BasicUpstart2(main) main: rts

  17. None
  18. LDA adress LDA #value RAM ➞ A register STA address

    A register ➞ RAM Most important instructions
  19. rts main: lda # sta background_color lda # sta border_color

    GRAY DARK_GRAY Border & Backgound Colors .label border_color = $d020 .label background_color = $d021 :BasicUpstart2(main)
  20. Macros rts main: lda # sta background_color lda # sta

    border_color GRAY DARK_GRAY
  21. rts main: lda # sta background_color lda # sta border_color

    GRAY DARK_GRAY .macro background(color) { } Macros
  22. lda # sta background_color rts main: :background( ) color lda

    # sta border_color GRAY DARK_GRAY .macro background(color) { } Macros
  23. lda # sta background_color rts main: :background( ) color lda

    # sta border_color GRAY DARK_GRAY .macro background(color) { } Macros
  24. lda # sta background_color rts main: .macro border(color) { }

    :background( ) color lda # sta border_color GRAY DARK_GRAY .macro background(color) { } Macros
  25. :border( ) .macro background(color) { } lda # sta background_color

    rts main: .macro border(color) { } :background( ) color lda # sta border_color GRAY DARK_GRAY color Macros
  26. None
  27. Raster Bar // long delay :background(BLACK) :background(DARK_GRAY)

  28. Delay :background(BLACK) :background(DARK_GRAY) nop

  29. :background(BLACK) :background(DARK_GRAY) nop nop Delay

  30. :background(BLACK) :background(DARK_GRAY) nop nop nop Delay

  31. :background(BLACK) :background(DARK_GRAY) nop // ... many more nops nop nop

    Delay
  32. :background(BLACK) :background(DARK_GRAY) .for (var i = 0; i < ;

    i++) { nop } 230 Delay
  33. .macro nops( ) { } .for (var i = 0;

    i < ; i++) { nop } :background(BLACK) :background(DARK_GRAY) 230 count Delay
  34. :nops( ) .macro nops( ) { } .for (var i

    = 0; i < ; i++) { nop } :background(BLACK) :background(DARK_GRAY) 230 count count Delay
  35. Interrupts raster_bars_irq: jmp irq_handler :nops( ) :background(BLACK) :background(DARK_GRAY) 230

  36. // Disable IRQ handling sei // inject the handler lda

    #<raster_bars_irq sta irq_vector lda #>raster_bars_irq sta irq_vector + 1 // Enable IRQ handling cli Interrupts
  37. None
  38. // inject the handler lda #<raster_bars_irq sta irq_vector lda #>raster_bars_irq

    sta irq_vector + 1 Let’s Disable Timer cli sei
  39. cli sei Let’s Disable Timer

  40. cli sei // Disable the interrupt generated by timers lda

    #%01111111 sta cia1_interrupt_control_register sta cia2_interrupt_control_register // Negate already scheduled interrupts lda cia1_interrupt_control_register lda cia2_interrupt_control_register Let’s Disable Timer
  41. Let’s Enable Raster cli sei // Disable the interrupt generated

    by timers lda #%01111111 sta cia1_interrupt_control_register sta cia2_interrupt_control_register // Negate already scheduled interrupts lda cia1_interrupt_control_register lda cia2_interrupt_control_register // Enable raster interrupts lda #%00000001 sta vic2_interrupt_control_register
  42. Choose Raster Line cli sei // Disable the interrupt generated

    by timers lda #%01111111 sta cia1_interrupt_control_register sta cia2_interrupt_control_register // Negate already scheduled interrupts lda cia1_interrupt_control_register lda cia2_interrupt_control_register // Enable raster interrupts lda #%00000001 sta vic2_interrupt_control_register :request_raster_irq(106, raster_bars_irq)
  43. .macro request_raster_irq(line_number, handler) { } Choose Raster Line

  44. .macro request_raster_irq(line_number, handler) { } lda #<handler sta irq_vector lda

    #>handler sta irq_vector + 1 Choose Raster Line
  45. .macro request_raster_irq(line_number, handler) { } lda #<handler sta irq_vector lda

    #>handler sta irq_vector + 1 lda #line_number sta vic2_rasterline_register Choose Raster Line
  46. .macro request_raster_irq(line_number, handler) { } lda #<handler sta irq_vector lda

    #>handler sta irq_vector + 1 .if (line_number > 255) { :set_bits(screen_control_register, %10000000) } else { :clear_bits(screen_control_register, %10000000) } lda #line_number sta vic2_rasterline_register Choose Raster Line
  47. .macro set_bits(address, bit_mask) { lda address ora #bit_mask sta address

    } .macro clear_bits(address, bit_mask) { lda address and #255 - bit_mask sta address } Choose Raster Line
  48. IRQ Acknowledged? jmp irq_handler raster_bars_irq: :background(BLACK) :nops(230) :background(DARK_GRAY)

  49. Przerwanie obsłużone? raster_bars_irq: :background(BLACK) :nops(230) :background(DARK_GRAY) lda #%00000001 sta vic2_interrupt_status_register

    jmp irq_handler
  50. Przerwanie obsłużone? raster_bars_irq: :background(BLACK) :nops(230) :background(DARK_GRAY) :exit_irq_handler() .macro exit_irq_handler() {

    } lda #%00000001 sta vic2_interrupt_status_register jmp irq_handler
  51. None
  52. Stabilization :exit_irq_handler() raster_bars_irq: :nops(14) :background(BLACK) :nops(230) :background(DARK_GRAY)

  53. None
  54. Raster Bars! :exit_irq_handler() raster_bars_irq:

  55. :nops(14) :background(BLACK) :nops(4) :background(DARK_GRAY) :nops(29) :background(GRAY) :nops(29) :background(LIGHT_GRAY) :nops(29) :background(WHITE)

    Raster Bars! :exit_irq_handler() raster_bars_irq:
  56. :nops(14) :background(BLACK) :nops(4) :background(DARK_GRAY) :nops(29) :background(GRAY) :nops(29) :background(LIGHT_GRAY) :nops(29) :background(WHITE)

    Raster Bars! :exit_irq_handler() raster_bars_irq: // ...
  57. :nops(14) :background(BLACK) :nops(4) :background(DARK_GRAY) :nops(29) :background(GRAY) :nops(29) :background(LIGHT_GRAY) :nops(29) :background(WHITE)

    Raster Bars! :exit_irq_handler() raster_bars_irq: // ... // ...
  58. :nops(14) :background(BLACK) :nops(4) :background(DARK_GRAY) :nops(29) :background(GRAY) :nops(29) :background(LIGHT_GRAY) :nops(29) :background(WHITE)

    Raster Bars! :exit_irq_handler() raster_bars_irq: :nops(29) :background(LIGHT_GRAY) :nops(29) :background(GRAY) :nops(29) :background(DARK_GRAY) :nops(29) :background(BLACK) :nops(4) :background(DARK_GRAY) // ... // ...
  59. None
  60. Hardware Sprites

  61. // Enable all 8 sprites lda #%11111111 sta sprites.enable_bits Hardware

    Sprites
  62. // Enable all 8 sprites lda #%11111111 sta sprites.enable_bits .for

    (var i = 0; i < 8; i++) { :set_sprite_position_x(i, 60 + 32 * i) } Hardware Sprites
  63. .macro set_sprite_position_x(index, position_x) { } Hardware Sprites

  64. .macro set_sprite_position_x(index, position_x) { } lda #position_x sta sprites.positions +

    index*2 + 0 Hardware Sprites
  65. .macro set_sprite_position_x(index, position_x) { } .if (position_x > 255) {

    :set_bits(sprites.position_x_high_bits,1<<index) } else { :clear_bits(sprites.position_x_high_bits,1<<index) } lda #position_x sta sprites.positions + index*2 + 0 Hardware Sprites
  66. More Interrupts raster_bars_irq: :exit_irq_handler() // ... :nops(14)

  67. sprite_row_irq1: :exit_irq_handler() // ... raster_bars_irq: :exit_irq_handler() // ... :nops(14) More

    Interrupts
  68. sprite_row_irq1: :exit_irq_handler() // ... raster_bars_irq: :exit_irq_handler() // ... :request_raster_irq(60, sprite_row_irq1)

    :nops(14) More Interrupts
  69. sprite_row_irq1: :exit_irq_handler() // ... :request_raster_irq(106, raster_bars_irq) raster_bars_irq: :exit_irq_handler() // ...

    :request_raster_irq(60, sprite_row_irq1) :nops(14) More Interrupts
  70. sprite_row_irq1: :exit_irq_handler() // Set the y-position, bitmaps and colors :sprites_row(70,

    0, 3) raster_bars_irq: :exit_irq_handler() // ... :request_raster_irq(60, sprite_row_irq1) :request_raster_irq(106, raster_bars_irq) :nops(14) More Interrupts
  71. None
  72. sprite_row_irq1: :exit_irq_handler() // Set the y-position, bitmaps and colors :sprites_row(70,

    0, 3) Raster time raster_bars_irq: :exit_irq_handler() // ... :request_raster_irq(60, sprite_row_irq1) :request_raster_irq(106, raster_bars_irq) :nops(14)
  73. sprite_row_irq1: :exit_irq_handler() // Set the y-position, bitmaps and colors :sprites_row(70,

    0, 3) Raster time raster_bars_irq: :exit_irq_handler() // ... :request_raster_irq(60, sprite_row_irq1) :request_raster_irq(106, raster_bars_irq) :border(RED) :border(GRAY) :nops(14)
  74. sprite_row_irq1: :exit_irq_handler() // Set the y-position, bitmaps and colors :sprites_row(70,

    0, 3) Raster time raster_bars_irq: :exit_irq_handler() // ... :request_raster_irq(60, sprite_row_irq1) :request_raster_irq(106, raster_bars_irq) :nops(14) :border(RED) :border(GRAY) :border(GRAY) :border(ORANGE)
  75. sprite_row_irq1: :exit_irq_handler() // Set the y-position, bitmaps and colors :sprites_row(70,

    0, 3) Raster time raster_bars_irq: :exit_irq_handler() // ... :request_raster_irq(60, sprite_row_irq1) :request_raster_irq(106, raster_bars_irq) :nops(7) :border(RED) :border(GRAY) :border(GRAY) :border(ORANGE)
  76. None
  77. More Sprites raster_bars_irq: :request_raster_irq( ) :exit_irq_handler() 60, sprite_row_irq1 sprite_row_irq1: //

    ... // ...
  78. raster_bars_irq: :request_raster_irq( ) :exit_irq_handler() sprite_row_irq2: :border(CYAN) :sprites_row(160, 8, 12) :border(GRAY)

    :request_raster_irq( ) :exit_irq_handler() 60, sprite_row_irq1 sprite_row_irq1: // ... // ... More Sprites
  79. raster_bars_irq: :request_raster_irq( ) :exit_irq_handler() sprite_row_irq2: :border(CYAN) :sprites_row(160, 8, 12) :border(GRAY)

    :request_raster_irq( ) :exit_irq_handler() 60, sprite_row_irq1 sprite_row_irq1: // ... // ... 150, sprite_row_irq2 More Sprites
  80. None
  81. Thin Green Line… :request_raster_irq(248, open_border_irq) open_border_irq: :border(GREEN) :nops(14) :border(GRAY) :request_raster_irq(60,

    sprite_row_irq1) :exit_irq_handler()
  82. None
  83. None
  84. Opening the Border sprite_row_irq2: :request_raster_irq(248, open_border_irq) :exit_irq_handler() open_border_irq: :request_raster_irq(60, sprite_row_irq1)

    :exit_irq_handler()
  85. sprite_row_irq2: :request_raster_irq(248, open_border_irq) :exit_irq_handler() open_border_irq: :request_raster_irq(60, sprite_row_irq1) :exit_irq_handler() // Enable

    25 lines mode :set_bits(screen_control_register, %00001000) Opening the Border
  86. sprite_row_irq2: :request_raster_irq(248, open_border_irq) :exit_irq_handler() open_border_irq: :request_raster_irq(60, sprite_row_irq1) :exit_irq_handler() // Enable

    24 lines mode :clear_bits(screen_control_register, %00001000) // Enable 25 lines mode :set_bits(screen_control_register, %00001000) Opening the Border
  87. None
  88. Draw Under The Border lda #%10110101 sta border_pattern

  89. None
  90. None
  91. Music

  92. // Import music from a file .pc=$1000 music: .import binary

    "music.bin" Music
  93. main: // initialize music jsr music // Import music from

    a file .pc=$1000 music: .import binary "music.bin" Music
  94. main: // initialize music jsr music // Import music from

    a file .pc=$1000 music: .import binary "music.bin" play_music: :border(YELLOW) jsr $music + 3 :border(GRAY) :request_raster_irq(248, open_border_irq) :exit_irq_handler() Music
  95. None
  96. Try It Youself! h/p:/ /64bites.com/raster-shaders/ Don’t Let Old Computers Die