I started working through Pete Shirley's Ray Tracing in One Weekend and hit a snag on the first example. I wrote the PPM image example in C++, Go, Java, Python, Ruby, and Nim. Except for Nim, all the other languages output almost identical results.
What am I doing wrong to get a different output in Nim?
C++
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
bool outputFile(std::string const &fileName,
std::string const &header,
std::vector<std::string> const &pixels) {
std::ofstream output;
try {
output.open(fileName);
output << header;
for (auto rgb : pixels) {
output << rgb;
}
return true;
} catch (...) {
std::cout << "Any error occured writing image" << std::endl;
}
return false;
}
std::string generateHeader(int x, int y) {
std::string header = "P3\n" + std::to_string(x) + " " + std::to_string(y) + "\n255\n";
return header;
}
std::vector<std::string> generatePixels(int x, int y) {
std::vector<std::string> pixels;
pixels.reserve(x * y);
std::string rgb;
for (int j = y-1; j >= 0; j--) {
for (int i = 0; i < x; i++) {
float r = float(i) / float(x-1);
float g = float(j) / float(y-1);
float b = 0.2;
int ir = int(255.999 * r);
int ig = int(255.999 * g);
int ib = int(255.999 * b);
rgb = std::to_string(ir) + " " + std::to_string(ig) + " " + std::to_string(ib) + "\n";
pixels.push_back(rgb);
}
}
return pixels;
}
int main() {
int x = 200;
int y = 100;
auto header = generateHeader(x, y);
auto pixels = generatePixels(x, y);
outputFile("cppimage.ppm", header, pixels);
}
Python
def outputFile(filename, header, pixels):
ppmFile = open(filename, "w")
ppmFile.write(header)
ppmFile.writelines(pixels)
ppmFile.close()
def generateHeader(x, y):
header = "P3\n" + str(x) + " " + str(y) + "\n255\n"
return header
def generatePixels(x, y):
pixels = []
rgb = ""
for j in range(y-1, -1, -1):
for i in range(x):
r = float(i) / float(x-1)
g = float(j) / float(y-1)
b = 0.2
ir = int(255.999 * r)
ig = int(255.999 * g)
ib = int (255.999 * b)
rgb = str(ir) + " " + str(ig) + " " + str(ib) + "\n"
pixels.append(rgb)
return pixels
x = 200
y = 100
header = generateHeader(x, y)
pixels = generatePixels(x, y)
outputFile("pyimage.ppm", header, pixels)
C++ and Python
P3
200 100
255
0 255 51
1 255 51
2 255 51
3 255 51
5 255 51
6 255 51
7 255 51
9 255 51
10 255 51
Nim
proc outputFile(fileName: string, header: string, pixels: seq[string]): bool =
var output = open(fileName, fmWrite)
try:
output.writeLine(header)
for p in pixels:
output.writeLine(p)
return true
except:
echo "Any error occured writing image"
return false
proc generateHeader(x: int, y: int): string =
var header: string = "P3\r\n" & $x & " " & $y & "\r\n255"
return header
proc generatePixels(x: int, y: int): seq[string] =
var pixels = newSeq[string]()
var rgb: string
for j in countdown(y-1, 0):
for i in 0..<x:
let r = toFloat(i) / toFloat(x-1)
let g = toFloat(j) / toFloat(y-1)
let b = 0.2
let ir = toInt(255.999 * r)
let ig = toInt(255.999 * g)
let ib = toInt(255.999 * b)
rgb = $ir & " " & $ig & " " & $ib
pixels.add(rgb)
return pixels
# main
let x = 200
let y = 100
let header = generateHeader(x, y)
let pixels = generatePixels(x, y)
let image = outputFile("nimimage.ppm", header, pixels)
if image == false:
echo "Error writing image file"
Nim
P3
200 100
255
0 256 51
1 256 51
3 256 51
4 256 51
5 256 51
6 256 51
8 256 51
9 256 51
10 256 51
To be clear:
echo int(1.6) # 1
echo toInt(1.6) # 2
use int(x) ?
for a in [0.4, 0.5, 0.6, 1.4, 1.5, 1.6]:
echo (a, a.int, a.toInt)
let b = -a
echo (b, b.int, b.toInt)
(0.4, 0, 0)
(-0.4, 0, 0)
(0.5, 0, 1)
(-0.5, 0, -1)
(0.6, 0, 1)
(-0.6, 0, -1)
(1.4, 1, 1)
(-1.4, -1, -1)
(1.5, 1, 2)
(-1.5, -1, -2)
(1.6, 1, 2)
(-1.6, -1, -2)