Slide 1

Slide 1 text

“RASTER SHADERS” on

Slide 2

Slide 2 text

I keep old computers alive mehowte Michał Taszycki on

Slide 3

Slide 3 text

I can teach you to program Commodore 64 one bite at a time h tt p:/ /64bites.com/

Slide 4

Slide 4 text

I have bad news for you…

Slide 5

Slide 5 text

Commodore 64 belongs to the past…

Slide 6

Slide 6 text

Today

Slide 7

Slide 7 text

Back then

Slide 8

Slide 8 text

Today

Slide 9

Slide 9 text

Back then

Slide 10

Slide 10 text

Back then

Slide 11

Slide 11 text

Back then?

Slide 12

Slide 12 text

Wait!

Slide 13

Slide 13 text

Today!

Slide 14

Slide 14 text

Today!

Slide 15

Slide 15 text

HOW?!

Slide 16

Slide 16 text

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; }

Slide 17

Slide 17 text

“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

Slide 18

Slide 18 text

Enough with theory!

Slide 19

Slide 19 text

Let’s code!

Slide 20

Slide 20 text

A minimal program :BasicUpstart2(main) main: rts

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

The most important instructions

Slide 23

Slide 23 text

LDA adress LDA #value RAM ➞ A register STA address A register ➞ RAM The most important instructions

Slide 24

Slide 24 text

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)

Slide 25

Slide 25 text

Macros rts main: lda # sta background_color lda # sta border_color GRAY DARK_GRAY

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

Meet Raster Bars

Slide 33

Slide 33 text

What’s the secret behind Raster Bars?

Slide 34

Slide 34 text

Doing nothing!

Slide 35

Slide 35 text

Raster Bars // long delay :background(BLACK) :background(DARK_GRAY)

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

:background(BLACK) :background(DARK_GRAY) .for (var i = 0; i < ; i++) { nop } 230 Delay

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

This will draw the bar… Somewhere :(

Slide 44

Slide 44 text

We need to start drawing at a specific Raster Line

Slide 45

Slide 45 text

We need to invoke a “Raster Shader”

Slide 46

Slide 46 text

We’ll get there but first…

Slide 47

Slide 47 text

Take a look at the cursor

Slide 48

Slide 48 text

Take a look at the cursor WHY DOES IT BLINK?

Slide 49

Slide 49 text

Meet Interrupts Small routines (let’s call them “shaders”) invoked by a signal (CIA TIMER, VIC CHIP)

Slide 50

Slide 50 text

Here’s our “Shader” raster_bars_irq: jmp irq_handler :nops( ) :background(BLACK) :background(DARK_GRAY) 230

Slide 51

Slide 51 text

// Disable IRQ handling sei // Enable IRQ handling cli Now we need to attach it to a signal

Slide 52

Slide 52 text

// Disable IRQ handling sei // Enable IRQ handling cli Disable interrupts while we do it

Slide 53

Slide 53 text

// Disable IRQ handling sei // inject the handler lda #raster_bars_irq sta irq_vector + 1 // Enable IRQ handling cli Inject interrupt handler

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

// inject the handler lda #raster_bars_irq sta irq_vector + 1 Let’s Use another type of IRQ cli sei

Slide 56

Slide 56 text

cli sei First delete the injection

Slide 57

Slide 57 text

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 Disable Timer IRQs

Slide 58

Slide 58 text

But Enable Raster IRQs 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

Slide 59

Slide 59 text

Let’s 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)

Slide 60

Slide 60 text

.macro request_raster_irq(line_number, handler) { } How to Choose Raster Line

Slide 61

Slide 61 text

.macro request_raster_irq(line_number, handler) { } lda #handler sta irq_vector + 1 Inject the adress of the handler

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

.macro request_raster_irq(line_number, handler) { } 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 It might not fit in a byte

Slide 64

Slide 64 text

.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 } Helper macros to toggle bits

Slide 65

Slide 65 text

Raster IRQs need to be Acknowledged jmp irq_handler raster_bars_irq: :background(BLACK) :nops(230) :background(DARK_GRAY)

Slide 66

Slide 66 text

raster_bars_irq: :background(BLACK) :nops(230) :background(DARK_GRAY) lda #%00000001 sta vic2_interrupt_status_register jmp irq_handler By touching special register

Slide 67

Slide 67 text

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 Let’s put it in a macro

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

We need stabilization :exit_irq_handler() raster_bars_irq: :background(BLACK) :nops(230) :background(DARK_GRAY)

Slide 70

Slide 70 text

But stabilization is… complicated :exit_irq_handler() raster_bars_irq: :background(BLACK) :nops(230) :background(DARK_GRAY)

Slide 71

Slide 71 text

Let’s fake it ;) :exit_irq_handler() raster_bars_irq: :nops(14) :background(BLACK) :nops(230) :background(DARK_GRAY)

Slide 72

Slide 72 text

We’ll hide jittering under the border ;) :exit_irq_handler() raster_bars_irq: :nops(14) :background(BLACK) :nops(230) :background(DARK_GRAY)

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

Let’s make more bars! :exit_irq_handler() raster_bars_irq:

Slide 75

Slide 75 text

:nops(14) :background(BLACK) :nops(4) :background(DARK_GRAY) :nops(29) :background(GRAY) :nops(29) :background(LIGHT_GRAY) :nops(29) :background(WHITE) :exit_irq_handler() raster_bars_irq: Let’s make more bars!

Slide 76

Slide 76 text

:nops(14) :background(BLACK) :nops(4) :background(DARK_GRAY) :nops(29) :background(GRAY) :nops(29) :background(LIGHT_GRAY) :nops(29) :background(WHITE) :exit_irq_handler() raster_bars_irq: // ... Let’s make more bars!

Slide 77

Slide 77 text

:nops(14) :background(BLACK) :nops(4) :background(DARK_GRAY) :nops(29) :background(GRAY) :nops(29) :background(LIGHT_GRAY) :nops(29) :background(WHITE) :exit_irq_handler() raster_bars_irq: // ... // ... Let’s make more bars!

Slide 78

Slide 78 text

:nops(14) :background(BLACK) :nops(4) :background(DARK_GRAY) :nops(29) :background(GRAY) :nops(29) :background(LIGHT_GRAY) :nops(29) :background(WHITE) :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) // ... // ... Let’s make more bars!

Slide 79

Slide 79 text

No content

Slide 80

Slide 80 text

Meet Sprites Hardware-accelerated bitmaps

Slide 81

Slide 81 text

// Enable all 8 sprites lda #%11111111 sta sprites.enable_bits Sprites on/off

Slide 82

Slide 82 text

// 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) } Sprites’ positions

Slide 83

Slide 83 text

.macro set_sprite_position_x(index, position_x) { } Sprite position

Slide 84

Slide 84 text

.macro set_sprite_position_x(index, position_x) { } lda #position_x sta sprites.positions + index*2 + 0 Sprite position

Slide 85

Slide 85 text

.macro set_sprite_position_x(index, position_x) { } .if (position_x > 255) { :set_bits(sprites.position_x_high_bits,1<

Slide 86

Slide 86 text

Another “Shader”? raster_bars_irq: :exit_irq_handler() // ... :nops(14)

Slide 87

Slide 87 text

sprite_row_irq1: :exit_irq_handler() // ... raster_bars_irq: :exit_irq_handler() // ... :nops(14) Another Interrupt

Slide 88

Slide 88 text

sprite_row_irq1: :exit_irq_handler() // ... raster_bars_irq: :exit_irq_handler() // ... :request_raster_irq(60, sprite_row_irq1) :nops(14) Schedule 2nd from the 1st

Slide 89

Slide 89 text

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) Schedule 1st from the 2nd

Slide 90

Slide 90 text

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) Vertical Sprites’ positions

Slide 91

Slide 91 text

No content

Slide 92

Slide 92 text

By the way

Slide 93

Slide 93 text

WTH is Raster time?

Slide 94

Slide 94 text

A simple way to measure the complexity of a routine Raster time

Slide 95

Slide 95 text

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)

Slide 96

Slide 96 text

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)

Slide 97

Slide 97 text

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)

Slide 98

Slide 98 text

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) WATCH OUT! (SYNCHRONIZATION IS OFF)

Slide 99

Slide 99 text

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)

Slide 100

Slide 100 text

No content

Slide 101

Slide 101 text

Let’s display more sprites!

Slide 102

Slide 102 text

Wait, what?

Slide 103

Slide 103 text

More than 8?

Slide 104

Slide 104 text

More than 8?

Slide 105

Slide 105 text

Interrupt chain raster_bars_irq: :request_raster_irq( ) :exit_irq_handler() 60, sprite_row_irq1 sprite_row_irq1: // ... // ...

Slide 106

Slide 106 text

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: // ... // ... Another interrupt handler

Slide 107

Slide 107 text

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 Let’s add it to the chain

Slide 108

Slide 108 text

No content

Slide 109

Slide 109 text

Let’s open the border!

Slide 110

Slide 110 text

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()

Slide 111

Slide 111 text

No content

Slide 112

Slide 112 text

No content

Slide 113

Slide 113 text

Before reaching the line 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()

Slide 114

Slide 114 text

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) Make border thin

Slide 115

Slide 115 text

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) After we’ve passed that line

Slide 116

Slide 116 text

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) Make border wide

Slide 117

Slide 117 text

No content

Slide 118

Slide 118 text

What’s the point? You can’t draw any characters in this area :(

Slide 119

Slide 119 text

But you can draw a bar code ;) lda #%10110101 sta border_pattern

Slide 120

Slide 120 text

No content

Slide 121

Slide 121 text

And Sprites!

Slide 122

Slide 122 text

No content

Slide 123

Slide 123 text

Let’s play SID music

Slide 124

Slide 124 text

What’s a SID file?

Slide 125

Slide 125 text

It’s like an mp3 for C64…

Slide 126

Slide 126 text

But the player is included!

Slide 127

Slide 127 text

// Import music from a file .pc=$1000 music: .import binary "music.bin" Import SID file into the memory

Slide 128

Slide 128 text

main: // initialize music jsr music // Import music from a file .pc=$1000 music: .import binary "music.bin" Initialize the player

Slide 129

Slide 129 text

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() Play a tiny bit of music

Slide 130

Slide 130 text

No content

Slide 131

Slide 131 text

How did you like it?

Slide 132

Slide 132 text

Want more?

Slide 133

Slide 133 text

I can teach you to program Commodore 64 one bite at a time

Slide 134

Slide 134 text

Short & Sweet Commodore 64 programming lessons

Slide 135

Slide 135 text

Tons of Small Epiphanies

Slide 136

Slide 136 text

Short Focused Deep

Slide 137

Slide 137 text

BASIC to Assembly

Slide 138

Slide 138 text

Difficult Concepts Explained

Slide 139

Slide 139 text

Step By Step

Slide 140

Slide 140 text

Modern Programming Techniques

Slide 141

Slide 141 text

Useful For Games

Slide 142

Slide 142 text

Useful For Demos

Slide 143

Slide 143 text

1 episode • 5-10 minute video • 1 small epiphany • Full transcript • Source code • Exercises $3.99

Slide 144

Slide 144 text

Bundles of 9 episodes Seasons

Slide 145

Slide 145 text

No content

Slide 146

Slide 146 text

1 season • 9 videos • 9 small epiphanies • Lower price $19.99

Slide 147

Slide 147 text

but…

Slide 148

Slide 148 text

You can also…

Slide 149

Slide 149 text

Get them all!

Slide 150

Slide 150 text

Get them all!

Slide 151

Slide 151 text

of short video lessons Huge library

Slide 152

Slide 152 text

No content

Slide 153

Slide 153 text

Videos 108

Slide 154

Slide 154 text

Exercises 235

Slide 155

Slide 155 text

Lines of code 156 000

Slide 156

Slide 156 text

No content

Slide 157

Slide 157 text

Get everything • 108 videos • 235 exercises • 156 000 lines of code • Best price • less than $2 per episode $199

Slide 158

Slide 158 text

Get everything less than $2 per episode $199 64bites.com/all