Home
Admin | Edit

Bloom 612 - Dreamcast 256 bytes

link

A 256-byte procedural graphics program for the Sega Dreamcast video game console, released at Lovebyte 2025.

Tested in Redream with v1.004, v1.01c and v1.01d BIOS, does not seem to work on v1.022 though.

This is a SH-4 port of a processing sketch i originally made in June 2024, all integers (3x additive integer circle algorithm progressively scaled up), it render a blooming flower.

My journey on the Dreamcast began in mid-2024, mainly motivated by the RISC CPU (2-way Superscalar,), 640x480 resolution and 24-bit color depth.

I never owned a Dreamcast myself (i did have a Sega Saturn though !) but i was aware of its well-designed hardware (Sega last console breath !), it was pretty cool that Linux could run on it back in early 2000 !

I don't think i had much difficulty on the port except getting grips of the SH-4, it only use integers so doesn't really use the powerful bits of the SH-4 (such as FSCA and FSRRA instructions) but it was a good introduction, the original idea was to add a cursive logo signature (with the 'O' of "Orz" being a spiral; Dreamcast logo) but this sadly didn't fit. (wouldn't fit the anonymous compo theme anyways !)

The Dreamcast is a powerful beast and can probably deliver much more impressive graphics, it is a neat alternative to x86 or ARM.

Name is a reference to The Little Prince.

Chaos Rose was a similar albeit 3D looking flower (different algorithm) which was very cool to watch at previous Lovebyte.

Variants

Here are some more images produced by the same algorithm, it can produce many spiral looking graphics, the first ones were made in June, some of these may have been interesting to show but also added ~10 more instructions (especially the later ones) :

fractalesque

this one looked kinda cool

spiral and blobs

a quite rough sunflower (a try at additive blending also)

another type of flower

Dreamcast SH-4 sources

! assume r2, r3, r7 are 0
mov #19,r1
shll16 r1
mov #23,r4
shll16 r4
mov #14,r5
shll16 r5
neg r1,r6

! clear screen
mov.l VIDEO_BASE,r12
mov.l VIDEO_DRAW_OFFSET,r0
shll r0 ! ~640*480*4
clr:
    mov.l r2,@(r0,r12)
    add #-3,r0
    dt r0
    bf clr
mov #-16,r13

mov.l r2,@(r0,r12)

mov.l VIDEO_DRAW_OFFSET,r0
add r0,r12

mov #-6,r14
mov #-7,r15

main:
    mov r12,r8
    shlr16 r8
iter:
    mov r2,r11
    shad r14,r11
    add r11,r1
    mov r1,r11
    shad r14,r11
    sub r11,r2

    mov #12,r9
ia:
    mov r4,r11
    shad r14,r11
    add r11,r3
    mov r3,r11
    shad r14,r11
    sub r11,r4
    dt r9
    bf ia

    mov #7,r10
ib:
    mov r6,r11
    shad r15,r11
    add r11,r5
    mov r5,r11
    shad r15,r11
    sub r11,r6
    dt r10
    bf ib

    ! px
    mov r1,r9
    add r3,r9
    add r5,r9
    shad r13,r9

    ! py
    mov r2,r10
    add r4,r10
    add r6,r10
    shad r13,r10

    ! compute index
    mov #40,r11
    shll2 r11
    shll2 r11
    mul.l r11,r10
    sts macl,r10
    add r9,r10
    shll2 r10
    
    ! compute color
    mov r7,r11
    shll2 r11
    add r11,r11
    sub r7,r11 ! r11 * 7
    mov #-4,r0
    shad r0,r11
    mov r8,r9
    mov #-14,r0 ! -14 for a cleaner looks
    shad r0,r9
    add r9,r11
    add #-127,r11
    cmp/pz r11
    bt positive
    neg r11,r11
positive:
    mov #-3,r0
    mul.l r0,r11
    sts macl,r11 ! * -3
    mov #127,r9
    shll r9
    add #1,r9 ! 255
    add r11,r9 ! r
    add r11,r11 ! * 2
    mov #48,r0
    shll2 r0 ! 192
    add r0,r11 ! g

    cmp/pz r9
    subc r0,r0
    and r0,r9 ! max(r9, 0)

    cmp/pz r11
    subc r0,r0
    and r0,r11 ! max(r11, 0)

    add r12,r10
    mov r11,r0

    shll16 r9
    shll8 r11
    or r9,r11 ! RG

    mov.l r11,@r10

    add #4,r10
    or r0,r11 ! RGG
    mov.l r11,@r10

    dt r8
    bf iter

    mov r1,r0
    bsr scale
    nop
    add r0,r1

    mov r2,r0
    bsr scale

    mov #2,r8
    shll8 r8
    add #16,r8
    add #1,r7
    cmp/hi r8,r7
el:
    bt el
    add r0,r2
    bra main

scale:
    mov #-10,r9
    shad r9,r0
    mov #5,r11
    mul.l r11,r0
    sts macl,r0
    rts

.align 2
    VIDEO_BASE: .long 0xa5200000
    VIDEO_DRAW_OFFSET: .long (320 + (240 * 640)) * 4

p5.js prototype sources

let x0 = 19<<16
let y0 = 0
let x1 = 0
let y1 = 23<<16
let x2 = 14<<16
let y2 = -x0

function setup() {
  createCanvas(640, 480)
  background(0)
}

function draw() {
  if (frameCount > 512) return
 
  loadPixels()
  for (let i = 42281; i >= 0; i -= 1) {
    x0 += y0 >> 6
    y0 -= x0 >> 6

    for (let a = 0; a < 12; a += 1) {
      x1 += y1 >> 6
      y1 -= x1 >> 6
    }

    for (let a = 0; a < 7; a += 1) {
      x2 += y2 >> 7
      y2 -= x2 >> 7
    }

    let px = (x0 + x1 + x2) >> 16
    let py = (y0 + y1 + y2) >> 16
      
    let offset = (width / 2 + height / 2 * width) * 4
    let index = offset + (px + (py * width)) * 4

    let m = abs((((frameCount * 7) >> 4) + (i >> 14)) - 127) * -3
    let r = 255 + m
    let g = 192 + m * 2
    
    // only needed on HW
    //r = ~(r >> 31) & r
    //g = ~(g >> 31) & g

    pixels[index + 0] = r
    pixels[index + 1] = g
    pixels[index + 2] = 0

    // cover gaps (smoother) + blend colors
    pixels[index + 0 + 4] = r
    pixels[index + 1 + 4] = g
    pixels[index + 2 + 4] = g
  }

  x0 += 5 * (x0 >> 10)
  y0 += 5 * (y0 >> 10)

  updatePixels()
}

back to topLicence Creative Commons