Home
Admin | Edit

Isopolis - Atari ST 256 bytes

link

A 256 bytes Atari ST (1985) cityscape attempt for Outline 2025 which came after some iterative Dimetric cube experiment using the HAKMEM 149 algorithm.

The original idea was way more ambitious / real-time with palette rotation and building details but i couldn't pull it off, the end result is still okay anyway even if a bit dull and not animated, this algorithm wasn't really suited for this platform perhaps, it is too fancy, ARM would be best due to heavy use of shifts !

Buildings could perhaps be done better with simple x,y iterations or specific Line A calls. (using fill patterns for details ?)

First implementation was all grayscale but it was a tad boring so the gradient / shades were added up, trails were a quick cheap addition which ended up okay.

This use Line A putpixel heavily.

The initial prototype wasn't particularly optimized and i departed heavily from it, had to look at some issues :
Biggest issue after optimizations was to get around crashes on specific RAM amount (>= 4MB) due to unchecked putpixel calls, this was concerning as it was the compo machine...

The crash fix was to check every putpixel calls for coordinates that goes outside the screen, this ended up too heavy so i had another go at optimizations.

The speed improved by a factor of two with the fix so ~1m5s vs +2 minutes to render the screenshot above, not instant yet... but way more acceptable ! Many speed optimization may be left over. (especially on the use of word vs long)

Actual binary size is 288 bytes (300 bytes with clean exit) due to the 32 bytes program header but the party didn't count the header.

Versions

very early version, different seed / gradient, kinda liked this due to density and colors

early version with the palette

different geom, no bytes change

a mix of both geom; heavier

shading variations, too dim

"CGA" like

fancier gradient (inspiration was C64 They are spraying by Gordian) : (y >> 5) & (y >> 3)

messy if run for too long... (~2 minutes)

Sources

; vasmm68k_mot -m68000 -Fbin isopolis.s -o isopolis.tos
    dc.w $601a ; ph_branch
    dc.l end-start ; ph_tlen
    dc.l $0 ; ph_dlen
    dc.l $0 ; ph_blen
    dc.l $0 ; ph_slen
    dc.l $0 ; ph_res1
    dc.l $0 ; ph_prgflags
    dc.w $1 ; ph_absflag
start
    dc.w $a000 ; Line A init call
    movem.l (a0),a1-a4
    sf -6(a0) ; disable cursor / blinking

    ; supervisor mode for mem. access
    move.w #$20,-(sp)
    trap #1

    ; palette setup
    lea pal(pc),a2
    movem.l (a2),d0-d5
    movem.l d0-d5,$ff8240

    ; vertical gradient
    move.w #199,d7; d0,d7 shorter but seems to crash with different RAM setup (>= 4MB)
    y:
        move.w d7,d5
        asr.w #5,d5
        move.w #319,d6 ; d3 save 2 bytes but way too slow...
        x:
            move.w d5,(a3)
            move.w d6,(a4)
            move.w d7,2(a4)
            dc.w $a001
            dbra d6,x
        dbra d7,y

    loop:
        ; trails
        move.w #9,(a3)
        move.w d7,(a4)
        move.w d3,2(a4)
        cmp.w #199,d3
        bgt skipTrail
        dc.w $a001
skipTrail

        addq.w #1,d7 ; framecount

        ; building setup
        move.w d7,d2
        and.w #63,d2 ; very fast when using d3 but has shading issues
        bne.s skipNext
            move.w (a2),d0
            mulu #47989,d0 ; rng, seed at pal(pc)
            move.w d0,(a2)
            asr.l #7,d0 ; higher bits for better small range values

            move.l d0,d4
            and.w #7,d4
            bne.s skip
            moveq #2,d4
skip
            subq.w #1,d4 ; s

            moveq #1,d3
            lsl.l d4,d3
            subq.w #1,d3 ; r
            move.l d0,d2
            and.w #511,d2 ; can be removed with move.w below for 4 bytes gains but meh result (may works with different seed though)
            move.l d2,a5 ; x offset
            swap d0
            and.w #127,d0
            add.w #52,d0
            move.l d0,a6 ; y offset
skipNext
        move.l d3,d6 ; x
        and.w d7,d6
        clr.l d5 ; y

        swap d7
        ; iterate & draw
        move.w #1276,d7
        i:
            move.l d6,d0
            asr.l d4,d0
            add.l d0,d5 ; y += x >> rs1

            move.l d5,d0
            asr.l #8,d0
            sub.l d0,d6 ; x -= y >> 8

            ; y -= i & 1
            btst.l #0,d7
            beq skipAdjust
            subq.l #1,d5
skipAdjust
            ;move.w d7,d0
            ;and.l #1,d0
            ;sub.l d0,d5 ; y -= i & 1
            
            ; top color
            move.l #11,a1
            sub.l d4,a1

            ; geom variation but inconsistent (note : use d1 as shift value for asr.w #1,.. below)
            ;clr.l d1
            ;tst.w (a2)
            ;blt s
            ;moveq #1,d1
s
            move.l d3,d2
            asr.w #1,d2
            sub.l d5,d2 ; (r >> 1) - y

            move.l d3,d0
            sub.l d6,d0
            asr.w #1,d0 ; (r - x) >> 1
        
            ; face color
            move.l d0,d1
            bpl skipNegate
            neg.l d0
skipNegate
            cmp.l d2,d0
            blt draw
            tst.w d1
            bmi skipLeft
            subq.w #1,a1
            bra.s draw
skipLeft
            subq.w #2,a1
draw
            move.w a1,(a3) ; color
            move.w d6,d2
            add.w a5,d2
            swap d2
            move.w d5,d2
            add.w a6,d2
            cmp.w #199,d2
            bgt skipDraw
            move.l d2,(a4)
            ; slower ->
            ;move.w a5,(a4) ; offset
            ;add.w d6,(a4) ; + x
            ;move.w a6,2(a4) ; offset
            ;add.w d5,2(a4) ; + y
            dc.w $a001 ; plot
skipDraw
        dbra d7,i
        swap d7

        bra loop
; clean exit support (+12 bytes)
;        cmp.b #$39,$fffc02
;        bne loop
;    clr.l -(a7)
;    trap #1

pal
    dc.w $036,$136,$236,$336,$436,$546,$656
    dc.w $666,$444,$777
end

back to topLicence Creative Commons