Procedural landscape demo on OUYA/Android

A glitchy procedural, infinite-ish landscape demo running on Android and OUYA. Use the left joystick to move around on OUYA, or swiping on Android devices with touchscreens. Here’s the apk, and the source is here.

It’s great to be able to have a single binary that works across all these devices – from OUYA’s TV screen sizes to phones, and using the standard gesture interface at the same time as the OUYA controller.

The graphics are programmed in Jellyfish Lisp, using Perlin noise to create the landscape. The language is probably still a bit too close to the underlying bytecode in places, but the function calling is working and it’s getting easier to write and experiment with the code.

```(define terrain
'(let ((vertex positions-start)
(flingdamp (vector 0 0 0))
(world (vector 0 0 0)))

;; recycle a triangle which is off the screen
(define recycle
(lambda (dir)
;; shift along x and y coordinates:
;; set z to zero for each vertex
(write! vertex
(vector 1 1 0)) dir))
(write! (+ vertex 1)
(+ (*v (read (+ vertex 1))
(vector 1 1 0)) dir))
(write! (+ vertex 2)
(+ (*v (read (+ vertex 2))
(vector 1 1 0)) dir))

;; get the perlin noise values for each vertex
(let ((a (noise (* (- (read vertex) world) 0.2)))
(b (noise (* (- (read (+ vertex 1))
world) 0.2)))
(c (noise (* (- (read (+ vertex 2))
world) 0.2))))

;; set the z coordinate for height
(write! vertex
(+ (*v a (vector 0 0 8))
(vector 0 0 -4))))
(write! (+ vertex 1)
(+ (*v b (vector 0 0 8))
(vector 0 0 -4))))
(write! (+ vertex 2)
(+ (*v c (vector 0 0 8))
(vector 0 0 -4))))

;; recalculate normals
(define n (normalise

;; write to normal data
(write! (+ vertex 512) n)
(write! (+ vertex 513) n)
(write! (+ vertex 514) n)

;; write the z height as texture coordinates
(write! (+ vertex 1536)
(*v (swizzle zzz a) (vector 0 5 0)))
(write! (+ vertex 1537)
(*v (swizzle zzz b) (vector 0 5 0)))
(write! (+ vertex 1538)
(*v (swizzle zzz c) (vector 0 5 0))))))

;; forever
(loop 1
(set! flingdamp (+ (* flingdamp 0.99)
(*v
(vector 0.01 -0.01 0))))

(define vel (* flingdamp 0.002))
;; update the world coordinates
(set! world (+ world vel))

;; for each vertex
(loop (< vertex positions-end)

;; update the vertex position
(write! vertex (+ (read vertex) vel))
(write! (+ vertex 1) (+ (read (+ vertex 1)) vel))
(write! (+ vertex 2) (+ (read (+ vertex 2)) vel))

;; check for out of area polygons to recycle
(cond
(recycle (vector -10 0 0)))
(recycle (vector 10 0 0))))

(cond
((> (swizzle yzz (read vertex)) 4.0)
(recycle (vector 0 -8 0)))
((< (swizzle yzz (read vertex)) -4.0)
(recycle (vector 0 8 0))))

(set! vertex (+ vertex 3)))
(set! vertex positions-start))))
```

This lisp program compiles to 362 vectors of bytecode at startup, and runs well even on my cheap Android tablet. The speed seems close enough to native C++ to be worth the effort, and it’s much more flexible (i.e. future livecoding/JIT compilation possibilities). The memory layout is shown below, it’s packing executable instructions and model data into the same address space and doesn’t use any memory allocation while it’s running (no garbage collection and not even any C mallocs). The memory size is configurable but the nature of the system is such that it would be possible to put executable data into unused graphics sections (eg. normals or vertex colours), if appropriate.

Ouya development experiments

The Ouya is a tiny game console which is designed for promoting indy games rather than traditional high budget productions. It’s cheap compared to standard games hardware, and all the games are free to play at least in demo form. It’s very easy to start making games with as it’s based on Android – you can just plug in a USB cable and treat it just the same as any other Android device. You also don’t need to sign anything to start building stuff – it’s just a case of adding one line to your AndroidManifest.xml to tell the Ouya that the program is a game:

``` ```

`` <category android:name="tv.ouya.intent.category.GAME"/>``
``` ```

and adding a 732×412 icon in “res/drawable-xhdpi/ouya_icon.png” so it shows up on the menu.

There is a lot to like about the Ouya’s philosophy, so I tried out some graphics experiments with it to get better acquainted:

This program was made using Jellyfish, part of my increasingly odd rendering stack which started out as a port of Fluxus to PS2. It’s a type of microcode written inside TinyScheme and running in a separate virtual machine that makes it possible to process a lot of geometry without garbage collection overheads. At some point I might write a compiler for this, but writing the code longhand at the moment means I can tweak the instruction set and get a better understanding of how to use it. Here is the microcode for the ribbons above, they run at 20,000 cycles per frame each (so about 1.2MHz):

```;; register section
8 20000 0 ;; control (pc, cycles, stack)
mdl-size prim-tristrip 1 ;; graphics (size, primtype, renderhints)
0 0 0 ;; pos
0 0 0 ;; sensor addr

;; program data section
mdl-start 0 0     ;; 4 address of current vertex
mdl-start 0 0     ;; 5 address of accum vertex (loop)
0 0 0             ;; 6 influence
0 0 0             ;; temp

;; code section
;; add up differences with every other vertex
ldi  4  0         ;; load current vertex
ldi  5  0         ;; load accum vertex
sub  0  0         ;; get the difference
lda  6  0         ;; load the accumulation
nrm  0  0         ;; normalise
sta  6  0         ;; store accumulation

;; accumulation iteration
jlt  2  0         ;; exit if greater than model end (relative address)

;; end accum loop
;; push away from other verts
lda  6  0         ;; load accum
ldl -0.1 0        ;; reverse & make smaller
mul 0 0

;; attract to next vertex
ldi 4 0           ;; load current
ldi 4 1           ;; load next
sub 0 0           ;; get the difference
ldl 0.4 0
mul 0 0           ;; make smaller

;; do the animation
ldi 4 0           ;; load current vertex
sti 4 0           ;; write to model data

;; reset the outer loop
ldl 0 0           ;; load zero
sta 6 0           ;; reset accum
ldl mdl-start 0
sta 5 0           ;; reset accum address

jlt 2  0          ;; if greater than model (relative address)
jmp 8  0          ;; do next vertex

;; end: reset current vertex back to start
ldl mdl-start 0
sta 4 0

;; waggle around the last point a bit
lda mdl-end 0     ;; load vertex pos
rnd 0 0           ;; load random vert
ldl 0.5 0
mul 0 0           ;; make it smaller