1
0

Added canvas + colour implementations

This commit is contained in:
neviyn 2020-07-21 19:10:29 +01:00
parent a26131ab6e
commit 8404e2b025

128
src/canvas.nim Normal file
View File

@ -0,0 +1,128 @@
import "./tuple"
import strformat, strutils
type Colour* = Tuple4
proc colour*(red: float, green: float, blue: float): Colour = Colour(x: red, y: green, z: blue, w: 0)
proc red*(c: Colour): float = c.x
proc green*(c: Colour): float = c.y
proc blue*(c: Colour): float = c.z
proc `*`*(lhs, rhs: Colour): Colour = colour(lhs.red * rhs.red, lhs.green * rhs.green, lhs.blue * rhs.blue)
type
Canvas* = object
pixels: seq[seq[Colour]]
width*: int
height*: int
proc canvas*(width, height: int): Canvas =
result.width = width
result.height = height
result.pixels = newSeq[seq[Colour]](height)
for i in 0..<height:
result.pixels[i] = newSeq[Colour](width)
for j in 0..<width:
result.pixels[i][j] = colour(0,0,0)
proc writePixel*(canvas: var Canvas, x, y: int, colour: Colour) = canvas.pixels[y][x] = colour
proc writePixel*(canvas: var Canvas, x, y: float, colour: Colour) = writePixel(canvas, toInt(x), toInt(y), colour)
proc pixelAt*(canvas: Canvas, x, y: int): Colour = canvas.pixels[y][x]
proc toPPM*(canvas: Canvas): string =
result = &"P3\n{canvas.width} {canvas.height}\n255\n"
var length = 0
for y in 0..<canvas.height:
for x in 0..<canvas.width:
let redValue = intToStr(toInt(canvas.pixelAt(x, y).red.clamp(0.0, 1.0) * 255))
if(len(redValue) + length > 69):
result[high(result)] = '\n'
length = 0
result.add(redValue & " ")
length += len(redValue) + 1
let greenValue = intToStr(toInt(canvas.pixelAt(x, y).green.clamp(0.0, 1.0) * 255))
if(len(greenValue) + length > 69):
result[high(result)] = '\n'
length = 0
result.add(greenValue & " ")
length += len(greenValue) + 1
let blueValue = intToStr(toInt(canvas.pixelAt(x, y).blue.clamp(0.0, 1.0) * 255))
if(len(blueValue) + length > 69):
result[high(result)] = '\n'
length = 0
result.add(blueValue & " ")
length += len(blueValue) + 1
result[high(result)] = '\n'
length = 0
when isMainModule:
import unittest
suite "canvas":
test "Colour creation":
let t1 = colour(-0.5, 0.4, 1.7)
check(t1.red == -0.5)
check(t1.green == 0.4)
check(t1.blue == 1.7)
test "Colour addition":
let t1 = colour(0.9, 0.6, 0.75)
let t2 = colour(0.7, 0.1, 0.25)
check(t1 + t2 == colour(1.6, 0.7, 1.0))
test "Colour subtraction":
let t1 = colour(0.9, 0.6, 0.75)
let t2 = colour(0.7, 0.1, 0.25)
check(t1 - t2 == colour(0.2, 0.5, 0.5))
test "Multiply colour by scalar":
check(colour(0.2, 0.3, 0.4) * 2 == colour(0.4, 0.6, 0.8))
test "Multiply colours":
let t1 = colour(1, 0.2, 0.4)
let t2 = colour(0.9, 1, 0.1)
check(t1 * t2 == colour(0.9, 0.2, 0.04))
test "Create canvas":
var canvas = canvas(10, 20)
check(canvas.width == 10)
check(canvas.height == 20)
let black = colour(0,0,0)
for i in 0..<canvas.width:
for j in 0..<canvas.height:
check(canvas.pixelAt(i, j) == black)
test "Write and read pixel":
var canvas = canvas(10, 20)
let red = colour(1, 0, 0)
canvas.writePixel(2, 3, red)
check(canvas.pixelAt(2, 3) == red)
test "PPM Header":
let canvas = canvas(5, 3)
let ppmData = canvas.toPPM().splitLines()
check(ppmData[0] == "P3")
check(ppmData[1] == "5 3")
check(ppmData[2] == "255")
test "PPM Data":
var canvas = canvas(5, 3)
canvas.writePixel(0, 0, colour(1.5, 0, 0))
canvas.writePixel(2, 1, colour(0, 0.5, 0))
canvas.writePixel(4, 2, colour(-0.5, 0, 1))
let ppmData = canvas.toPPM().splitLines()
check(ppmData[3] == "255 0 0 0 0 0 0 0 0 0 0 0 0 0 0")
check(ppmData[4] == "0 0 0 0 0 0 0 128 0 0 0 0 0 0 0")
check(ppmData[5] == "0 0 0 0 0 0 0 0 0 0 0 0 0 0 255")
test "PPM Data, Variable length lines":
var canvas = canvas(10, 2)
for y in 0..<canvas.height:
for x in 0..<canvas.width:
canvas.writePixel(x, y, colour(1, 0.8, 0.6))
let ppmData = canvas.toPPM().splitLines()
check(ppmData[3] == "255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204")
check(ppmData[4] == "153 255 204 153 255 204 153 255 204 153 255 204 153")
check(ppmData[5] == "255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204")
check(ppmData[6] == "153 255 204 153 255 204 153 255 204 153 255 204 153")