# Drawing shapes on the screen

[Courses](https://asm-editor.specy.app/learn/courses.md) › [MIPS assembly](https://asm-editor.specy.app/learn/courses/mips.md) › Examples

Web page: https://asm-editor.specy.app/learn/courses/mips/examples/drawing-on-the-screen

> A house, a sun and a sky drawn onto the bitmap display with sw and nothing else, by two subroutines that work out which word each pixel is.

The same program in: [M68K](https://asm-editor.specy.app/learn/courses/m68k/examples/drawing-on-the-screen.md), [RISC-V](https://asm-editor.specy.app/learn/courses/risc-v/examples/drawing-on-the-screen.md), [Z80](https://asm-editor.specy.app/learn/courses/z80/examples/drawing-on-the-screen.md), [x86-64](https://asm-editor.specy.app/learn/courses/x86/examples/drawing-on-the-screen.md)

This program draws a sky, ground, sun and house on a 32 by 32 word grid. Select **Build**, then
**Run**, and look at the Screen panel. Each word is one coloured cell. The program draws shapes by
calculating which words to change and storing colours with `sw`.

The grid starts at `display`. `x` counts columns from the left and `y` counts rows from the top;
both start at 0. A row has `SIDE = 32` words, and each word takes four bytes. For example, the
house's upper-left cell is `(x, y) = (10, 16)`: 16 complete rows and 10 more words give word index
`16 * 32 + 10 = 522`, or byte offset `522 * 4 = 2088` from `display`.

Two drawing helpers reuse that address calculation. `fill_rect` takes its left column, top row,
width and height in `$a0`–`$a3`. `fill_disc` takes a centre column, centre row and radius in
`$a0`–`$a2`. Both also read the current colour from `$s0` and the grid's base address from `$s1`.
`main` sets those shared values before each call. The helpers change only `$t` registers, so the
colour, base address and roof counter in `$s3` survive their calls. The coordinates used here keep
every stored cell inside the grid.

```mips
# @screen unit=8 width=256 height=256 base=display
.eqv SIDE 32                # words across and down
.eqv SKY 0x0070B0E0
.eqv GRASS 0x003C9648
.eqv SUN 0x00FFD200
.eqv WALL 0x00C07040
.eqv ROOF 0x00A02020
.eqv DOOR 0x00704020

.data
display: .space 4096        # SIDE * SIDE words, four bytes each

.text
.globl main

# fill_rect(x, y, w, h): $a0-$a3 hold the dimensions;
# $s0 holds the colour and $s1 holds the grid base
fill_rect:
    blez $a2, rect_done     # nothing to draw when width or height is nonpositive
    blez $a3, rect_done
    move $t0, $a1           # row = y
    add $t1, $a1, $a3       # one past the last row
rect_rows:
    sll $t2, $t0, 5         # row * SIDE
    add $t2, $t2, $a0       # + x
    sll $t2, $t2, 2         # four bytes per word
    add $t2, $t2, $s1       # the first pixel of this run
    move $t3, $a2           # how many still to draw across
rect_cols:
    sw $s0, 0($t2)
    addi $t2, $t2, 4
    addi $t3, $t3, -1
    bnez $t3, rect_cols
    addi $t0, $t0, 1
    blt $t0, $t1, rect_rows
rect_done:
    jr $ra

# fill_disc(cx, cy, r): $a0-$a2 hold centre and radius;
# $s0 holds the colour and $s1 holds the grid base
fill_disc:
    mul $t7, $a2, $a2       # r * r
    sub $t0, $a1, $a2       # y = cy - r
    add $t1, $a1, $a2       # the last row
disc_rows:
    sub $t2, $a0, $a2       # x = cx - r
    add $t3, $a0, $a2
disc_cols:
    sub $t4, $t2, $a0       # dx
    sub $t5, $t0, $a1       # dy
    mul $t4, $t4, $t4
    mul $t5, $t5, $t5
    add $t4, $t4, $t5       # dx*dx + dy*dy
    bge $t4, $t7, disc_next
    sll $t6, $t0, 5         # the same address arithmetic again
    add $t6, $t6, $t2
    sll $t6, $t6, 2
    add $t6, $t6, $s1
    sw $s0, 0($t6)
disc_next:
    addi $t2, $t2, 1
    ble $t2, $t3, disc_cols
    addi $t0, $t0, 1
    ble $t0, $t1, disc_rows
    jr $ra

main:
    la $s1, display         # shared grid base for both helpers

    li $s0, SKY             # the sky, the top twenty rows
    li $a0, 0
    li $a1, 0
    li $a2, SIDE
    li $a3, 20
    jal fill_rect

    li $s0, GRASS           # the ground under it
    li $a0, 0
    li $a1, 20
    li $a2, SIDE
    li $a3, 12
    jal fill_rect

    li $s0, SUN             # a disc of radius 4, up in the corner
    li $a0, 26
    li $a1, 6
    li $a2, 4
    jal fill_disc

    li $s0, WALL            # the house
    li $a0, 10
    li $a1, 16
    li $a2, 12
    li $a3, 10
    jal fill_rect

    li $s0, ROOF            # six rows up from the wall, each two cells narrower
    li $s3, 0
roof:
    li $a0, 10
    add $a0, $a0, $s3
    li $a1, 15
    sub $a1, $a1, $s3
    li $a2, 12
    sll $t7, $s3, 1
    sub $a2, $a2, $t7
    li $a3, 1
    jal fill_rect
    addi $s3, $s3, 1
    blt $s3, 6, roof

    li $s0, DOOR            # and a door in the wall
    li $a0, 14
    li $a1, 21
    li $a2, 4
    li $a3, 5
    jal fill_rect

    li $v0, 10
    syscall
```

The `# @screen` line sets the Screen on every Build. `unit=8` draws each word as an 8 by 8 block;
`width=256 height=256` sets the display area. Thus 256 divided by 8 gives 32 cells across and
down. `base=display` connects the Screen to the reserved memory labelled `display`. The
`32 * 32` words need `32 * 32 * 4 = 4096` bytes, the amount reserved by `.space 4096`.

A colour is the low 24 bits of a word, red in bits 23 to 16, green in 15 to 8 and blue in 7 to 0.
So `0x0070B0E0` is a pale blue made of 112 red, 176 green and 224 blue, and the order is the
`#RRGGBB` you write in CSS with a `0x` on the front.

The address of the cell at `(x, y)` is `base + (y * SIDE + x) * 4`, the same calculation used for
a 2D array of words. Both helpers use `sll` by 5 for `y * 32`, add `x`, use `sll` by 2 for four
bytes per word, then add the base address.

`fill_rect` computes the first address in each row, then advances by four bytes for every cell
across. The roof loop calls it six times with height 1: each call moves one row upward, starts one
column farther right and draws two fewer cells. The wall and door are rectangles drawn in the same
way.

`fill_disc` checks each cell in the square from `cx - r` to `cx + r` and from `cy - r` to
`cy + r`. Only cells satisfying `dx * dx + dy * dy < r * r` receive a store. For this sun,
`r = 4`, so a cell three columns from the centre on the same row passes (`3 * 3 < 16`), while
one four columns away fails (`4 * 4` is not less than 16). The `bge` skips the store when the
distance squared is equal to or greater than 16. That includes the square's outer edge.

Try adding a window to the house. Select **Open in editor** and copy the door call, from
`li $s0, DOOR` through `jal fill_rect`. Paste the copy just before the original door call.
In the copy, set `$s0` to `SUN`, then pass `x = 12`, `y = 18`, `w = 3` and `h = 3` in
`$a0`–`$a3`. Build and run. You should see a yellow 3 by 3 window near the upper-left of the wall.

Now move the sun's centre three cells right by changing its `li $a0, 26` to `li $a0, 29`.
Build and run again. Part of the sun appears at the left edge one row lower: column 32 of a row
has the same memory address as column 0 of the next row. These helpers do not check whether a
coordinate is inside the 32 by 32 grid. Return the centre to 26 when finished.

## Instructions in this Lecture

- MIPS: [`blez`](https://asm-editor.specy.app/documentation/mips/instruction/blez.md), [`move`](https://asm-editor.specy.app/documentation/mips/instruction/move.md), [`add`](https://asm-editor.specy.app/documentation/mips/instruction/add.md), [`sll`](https://asm-editor.specy.app/documentation/mips/instruction/sll.md), [`sw`](https://asm-editor.specy.app/documentation/mips/instruction/sw.md), [`addi`](https://asm-editor.specy.app/documentation/mips/instruction/addi.md), [`bnez`](https://asm-editor.specy.app/documentation/mips/instruction/bnez.md), [`blt`](https://asm-editor.specy.app/documentation/mips/instruction/blt.md), [`jr`](https://asm-editor.specy.app/documentation/mips/instruction/jr.md), [`mul`](https://asm-editor.specy.app/documentation/mips/instruction/mul.md), [`sub`](https://asm-editor.specy.app/documentation/mips/instruction/sub.md), [`bge`](https://asm-editor.specy.app/documentation/mips/instruction/bge.md), [`ble`](https://asm-editor.specy.app/documentation/mips/instruction/ble.md), [`la`](https://asm-editor.specy.app/documentation/mips/instruction/la.md), [`li`](https://asm-editor.specy.app/documentation/mips/instruction/li.md), [`jal`](https://asm-editor.specy.app/documentation/mips/instruction/jal.md), [`syscall`](https://asm-editor.specy.app/documentation/mips/instruction/syscall.md)

Previous: [Print a number in any base without help](https://asm-editor.specy.app/learn/courses/mips/examples/number-to-string.md)

Next: [A bouncing ball](https://asm-editor.specy.app/learn/courses/mips/examples/bouncing-ball.md)
