examples: use vcalloc

pull/3937/head
Alexander Medvednikov 2020-03-04 17:28:05 +01:00
parent c203a744fe
commit 59a65d757b
2 changed files with 80 additions and 80 deletions

View File

@ -46,8 +46,8 @@ fn new_automaton(f [][]int) Automaton {
maxx = f[y].len maxx = f[y].len
} }
} }
field := &A2D{ maxx: maxx maxy: maxy data: &int( calloc( sizeof(int) * maxy * maxx ) ) } field := &A2D{ maxx: maxx maxy: maxy data: &int( vcalloc( sizeof(int) * maxy * maxx ) ) }
new_field := &A2D{ maxx: maxx maxy: maxy data: &int( calloc( sizeof(int) * maxy * maxx ) ) } new_field := &A2D{ maxx: maxx maxy: maxy data: &int( vcalloc( sizeof(int) * maxy * maxx ) ) }
for y in 0..field.maxy { for y in 0..field.maxy {
for x in 0..field.maxx { for x in 0..field.maxx {
field.set( x, y, f[y][x] ) field.set( x, y, f[y][x] )

View File

@ -8,7 +8,7 @@
* This file contains a path tracer example in less of 500 line of codes * This file contains a path tracer example in less of 500 line of codes
* 3 demo scenes included * 3 demo scenes included
* *
* This code is inspired by: * This code is inspired by:
* - "Realistic Ray Tracing" by Peter Shirley 2000 ISBN-13: 978-1568814612 * - "Realistic Ray Tracing" by Peter Shirley 2000 ISBN-13: 978-1568814612
* - https://www.kevinbeason.com/smallpt/ * - https://www.kevinbeason.com/smallpt/
* *
@ -16,13 +16,13 @@
* - there are some approximation errors in the calculations * - there are some approximation errors in the calculations
* - to speed-up the code a cos/sin table is used * - to speed-up the code a cos/sin table is used
* - the full precision code is present but commented, can be restored very easily * - the full precision code is present but commented, can be restored very easily
* - an higher number of samples ( > 60) can block the program on higher resolutions * - an higher number of samples ( > 60) can block the program on higher resolutions
* without a stack size increase * without a stack size increase
* - as a recursive program this code depend on the stack size, * - as a recursive program this code depend on the stack size,
* for higher number of samples increase the stack size * for higher number of samples increase the stack size
* in linux: ulimit -s byte_size_of_the_stack * in linux: ulimit -s byte_size_of_the_stack
* example: ulimit -s 16000000 * example: ulimit -s 16000000
* - No OpenMP support * - No OpenMP support
**********************************************************************/ **********************************************************************/
import os import os
import math import math
@ -34,10 +34,10 @@ const (
eps = f64(1e-4) eps = f64(1e-4)
f_0 = f64(0.0) f_0 = f64(0.0)
) )
/***************************** 3D Vector utility struct **********************/ /***************************** 3D Vector utility struct **********************/
struct Vec { struct Vec {
mut: mut:
x f64 = f64(0.0) x f64 = f64(0.0)
y f64 = f64(0.0) y f64 = f64(0.0)
z f64 = f64(0.0) z f64 = f64(0.0)
@ -94,7 +94,7 @@ fn new_image(w int, h int) Image {
return Image{ return Image{
width: w, width: w,
height: h, height: h,
data: &Vec(calloc(sizeof(Vec)*w*h)) data: &Vec(vcalloc(sizeof(Vec)*w*h))
} }
} }
@ -121,11 +121,11 @@ struct Ray {
} }
// material types, used in radiance() // material types, used in radiance()
enum Refl_t { enum Refl_t {
diff, diff,
spec, spec,
refr refr
} }
/********************************* Sphere ************************************/ /********************************* Sphere ************************************/
struct Sphere { struct Sphere {
@ -137,21 +137,21 @@ struct Sphere {
} }
fn (sp Sphere) intersect (r Ray) f64 { fn (sp Sphere) intersect (r Ray) f64 {
op := sp.p - r.o // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0 op := sp.p - r.o // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0
b := op.dot(r.d) b := op.dot(r.d)
mut det := b * b - op.dot(op) + sp.rad * sp.rad mut det := b * b - op.dot(op) + sp.rad * sp.rad
if det < 0 { if det < 0 {
return f64(0) return f64(0)
} }
det = math.sqrt(det) det = math.sqrt(det)
mut t := b - det mut t := b - det
if t > eps { if t > eps {
return t return t
} }
t = b + det t = b + det
if t > eps { if t > eps {
return t return t
@ -165,19 +165,19 @@ fn (sp Sphere) intersect (r Ray) f64 {
* 2) Psychedelic * 2) Psychedelic
* The sphere fileds are: Sphere{radius, position, emission, color, material} * The sphere fileds are: Sphere{radius, position, emission, color, material}
******************************************************************************/ ******************************************************************************/
const ( const (
Cen = Vec{50, 40.8, -860} // used by scene 1 Cen = Vec{50, 40.8, -860} // used by scene 1
spheres = [ spheres = [
[// scene 0 cornnel box [// scene 0 cornnel box
Sphere{rad: 1e+5, p: Vec{ 1e+5 +1,40.8,81.6} , e: Vec{} , c: Vec{.75,.25,.25} , refl: .diff},//Left Sphere{rad: 1e+5, p: Vec{ 1e+5 +1,40.8,81.6} , e: Vec{} , c: Vec{.75,.25,.25} , refl: .diff},//Left
Sphere{rad: 1e+5, p: Vec{-1e+5 +99,40.8,81.6}, e: Vec{} , c: Vec{.25,.25,.75} , refl: .diff},//Rght Sphere{rad: 1e+5, p: Vec{-1e+5 +99,40.8,81.6}, e: Vec{} , c: Vec{.25,.25,.75} , refl: .diff},//Rght
Sphere{rad: 1e+5, p: Vec{50,40.8, 1e+5} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Back Sphere{rad: 1e+5, p: Vec{50,40.8, 1e+5} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Back
Sphere{rad: 1e+5, p: Vec{50,40.8,-1e+5 +170} , e: Vec{} , c: Vec{} , refl: .diff},//Frnt Sphere{rad: 1e+5, p: Vec{50,40.8,-1e+5 +170} , e: Vec{} , c: Vec{} , refl: .diff},//Frnt
Sphere{rad: 1e+5, p: Vec{50, 1e+5, 81.6} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Botm Sphere{rad: 1e+5, p: Vec{50, 1e+5, 81.6} , e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Botm
Sphere{rad: 1e+5, p: Vec{50,-1e+5 +81.6,81.6}, e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Top Sphere{rad: 1e+5, p: Vec{50,-1e+5 +81.6,81.6}, e: Vec{} , c: Vec{.75,.75,.75} , refl: .diff},//Top
Sphere{rad: 16.5, p: Vec{27,16.5,47} , e: Vec{} , c: Vec{1,1,1}.mult_s(.999) , refl: .spec},//Mirr Sphere{rad: 16.5, p: Vec{27,16.5,47} , e: Vec{} , c: Vec{1,1,1}.mult_s(.999) , refl: .spec},//Mirr
Sphere{rad: 16.5, p: Vec{73,16.5,78} , e: Vec{} , c: Vec{1,1,1}.mult_s(.999) , refl: .refr},//Glas Sphere{rad: 16.5, p: Vec{73,16.5,78} , e: Vec{} , c: Vec{1,1,1}.mult_s(.999) , refl: .refr},//Glas
Sphere{rad: 600 , p: Vec{50,681.6-.27,81.6} , e: Vec{12,12,12}, c: Vec{}, refl: .diff} //Lite Sphere{rad: 600 , p: Vec{50,681.6-.27,81.6} , e: Vec{12,12,12}, c: Vec{}, refl: .diff} //Lite
], ],
[// scene 1 sunset [// scene 1 sunset
@ -272,27 +272,27 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
sin_tab := &f64( tabs.sin_tab ) sin_tab := &f64( tabs.sin_tab )
cos_tab := &f64( tabs.cos_tab ) cos_tab := &f64( tabs.cos_tab )
mut depth := depthi // actual depth in the reflection tree mut depth := depthi // actual depth in the reflection tree
mut t := f64(0) // distance to intersection mut t := f64(0) // distance to intersection
mut id := 0 // id of intersected object mut id := 0 // id of intersected object
mut res := false // result of intersect mut res := false // result of intersect
v_1 := f64(1.0) v_1 := f64(1.0)
//v_2 := f64(2.0) //v_2 := f64(2.0)
scene := spheres[scene_id] scene := spheres[scene_id]
//res, t, id = intersect(r, id, tb.scene) //res, t, id = intersect(r, id, tb.scene)
res, t, id = intersect(r, scene.data, scene.len) res, t, id = intersect(r, scene.data, scene.len)
if !res { return Vec{} } //if miss, return black if !res { return Vec{} } //if miss, return black
obj := scene[id] // the hit object obj := scene[id] // the hit object
x := r.o + r.d.mult_s(t) x := r.o + r.d.mult_s(t)
n := (x - obj.p).norm() n := (x - obj.p).norm()
nl := if n.dot(r.d) < 0.0 { n } else { n.mult_s(-1) } nl := if n.dot(r.d) < 0.0 { n } else { n.mult_s(-1) }
mut f := obj.c mut f := obj.c
// max reflection // max reflection
mut p := f.z mut p := f.z
if f.x > f.y && f.x > f.z { if f.x > f.y && f.x > f.z {
@ -300,80 +300,80 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
} else { } else {
if f.y > f.z { if f.y > f.z {
p = f.y p = f.y
} }
} }
depth++ depth++
if depth > 5 { if depth > 5 {
if rand_f64() < p { if rand_f64() < p {
f = f.mult_s(f64(1.0)/p) f = f.mult_s(f64(1.0)/p)
} else { } else {
return obj.e //R.R. return obj.e //R.R.
} }
} }
if obj.refl == .diff { // Ideal DIFFUSE reflection if obj.refl == .diff { // Ideal DIFFUSE reflection
// **Full Precision** // **Full Precision**
//r1 := f64(2.0 * math.pi) * rand_f64() //r1 := f64(2.0 * math.pi) * rand_f64()
// tabbed speed-up // tabbed speed-up
r1 := C.rand() & cache_mask r1 := C.rand() & cache_mask
r2 := rand_f64() r2 := rand_f64()
r2s := math.sqrt(r2) r2s := math.sqrt(r2)
w := nl w := nl
mut u := if math.abs(w.x) > f64(0.1) { mut u := if math.abs(w.x) > f64(0.1) {
Vec{0, 1, 0} Vec{0, 1, 0}
} else { } else {
Vec{1, 0, 0} Vec{1, 0, 0}
} }
u = u.cross(w).norm() u = u.cross(w).norm()
v := w.cross(u) v := w.cross(u)
// **Full Precision** // **Full Precision**
//d := (u.mult_s(math.cos(r1) * r2s) + v.mult_s(math.sin(r1) * r2s) + w.mult_s(1.0 - r2)).norm() //d := (u.mult_s(math.cos(r1) * r2s) + v.mult_s(math.sin(r1) * r2s) + w.mult_s(1.0 - r2)).norm()
// tabbed speed-up // tabbed speed-up
d := (u.mult_s(cos_tab[r1] * r2s) + v.mult_s(sin_tab[r1] * r2s) + w.mult_s(math.sqrt(f64(1.0) - r2))).norm() d := (u.mult_s(cos_tab[r1] * r2s) + v.mult_s(sin_tab[r1] * r2s) + w.mult_s(math.sqrt(f64(1.0) - r2))).norm()
return obj.e + f * radiance(Ray{x, d}, depth, scene_id) return obj.e + f * radiance(Ray{x, d}, depth, scene_id)
} else { } else {
if obj.refl == .spec { // Ideal SPECULAR reflection if obj.refl == .spec { // Ideal SPECULAR reflection
return obj.e + f * radiance(Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d)) }, depth, scene_id) return obj.e + f * radiance(Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d)) }, depth, scene_id)
} }
} }
refl_ray := Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d))} // Ideal dielectric REFRACTION refl_ray := Ray{x, r.d - n.mult_s(2.0 * n.dot(r.d))} // Ideal dielectric REFRACTION
into := n.dot(nl) > 0 // Ray from outside going in? into := n.dot(nl) > 0 // Ray from outside going in?
nc := f64(1.0) nc := f64(1.0)
nt := f64(1.5) nt := f64(1.5)
nnt := if into { nc / nt } else { nt / nc } nnt := if into { nc / nt } else { nt / nc }
ddn := r.d.dot(nl) ddn := r.d.dot(nl)
cos2t := v_1 - nnt * nnt * (v_1 - ddn * ddn) cos2t := v_1 - nnt * nnt * (v_1 - ddn * ddn)
if cos2t < 0.0 { // Total internal reflection if cos2t < 0.0 { // Total internal reflection
return obj.e + f * radiance(refl_ray, depth, scene_id) return obj.e + f * radiance(refl_ray, depth, scene_id)
} }
dirc := if into { f64(1) } else { f64(-1) } dirc := if into { f64(1) } else { f64(-1) }
tdir := (r.d.mult_s(nnt) - n.mult_s(dirc * (ddn * nnt + math.sqrt(cos2t)))).norm() tdir := (r.d.mult_s(nnt) - n.mult_s(dirc * (ddn * nnt + math.sqrt(cos2t)))).norm()
a := nt - nc a := nt - nc
b := nt + nc b := nt + nc
r0 := a * a / (b * b) r0 := a * a / (b * b)
c := if into { v_1 + ddn } else { v_1 - tdir.dot(n) } c := if into { v_1 + ddn } else { v_1 - tdir.dot(n) }
re := r0 + (v_1 - r0) * c * c * c * c * c re := r0 + (v_1 - r0) * c * c * c * c * c
tr := v_1 - re tr := v_1 - re
pp := f64(.25) + f64(.5) * re pp := f64(.25) + f64(.5) * re
rp := re / pp rp := re / pp
tp := tr / (v_1 - pp) tp := tr / (v_1 - pp)
mut tmp := Vec{} mut tmp := Vec{}
if depth > 2 { if depth > 2 {
// Russian roulette // Russian roulette
@ -391,26 +391,26 @@ fn radiance(r Ray, depthi int, scene_id int) Vec {
/************************ beam scan routine **********************************/ /************************ beam scan routine **********************************/
fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image { fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
image := new_image(w, h) image := new_image(w, h)
// inverse costants // inverse costants
w1 := f64(1.0 / w) w1 := f64(1.0 / w)
h1 := f64(1.0 / h) h1 := f64(1.0 / h)
samps1 := f64(1.0 / samps) samps1 := f64(1.0 / samps)
cam := Ray{Vec{50, 52, 295.6}, Vec{0, -0.042612, -1}.norm()} // cam position, direction cam := Ray{Vec{50, 52, 295.6}, Vec{0, -0.042612, -1}.norm()} // cam position, direction
cx := Vec{ f64(w) * 0.5135 / f64(h), 0, 0} cx := Vec{ f64(w) * 0.5135 / f64(h), 0, 0}
cy := cx.cross(cam.d).norm().mult_s(0.5135) cy := cx.cross(cam.d).norm().mult_s(0.5135)
mut r := Vec{} mut r := Vec{}
// speed-up constants // speed-up constants
v_1 := f64(1.0) v_1 := f64(1.0)
v_2 := f64(2.0) v_2 := f64(2.0)
// OpenMP injection point! #pragma omp parallel for schedule(dynamic, 1) shared(c) // OpenMP injection point! #pragma omp parallel for schedule(dynamic, 1) shared(c)
for y:=0; y < h; y++ { for y:=0; y < h; y++ {
eprint("\rRendering (${samps * 4} spp) ${(100.0 * f64(y)) / (f64(h) - 1.0):5.2f}%") eprint("\rRendering (${samps * 4} spp) ${(100.0 * f64(y)) / (f64(h) - 1.0):5.2f}%")
for x in 0..w { for x in 0..w {
i := (h - y - 1) * w + x i := (h - y - 1) * w + x
mut ivec := &image.data[i] mut ivec := &image.data[i]
// we use sx and sy to perform a square subsampling of 4 samples // we use sx and sy to perform a square subsampling of 4 samples
@ -420,11 +420,11 @@ fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
for s in 0..samps { for s in 0..samps {
r1 := v_2 * rand_f64() r1 := v_2 * rand_f64()
dx := if r1 < v_1 { math.sqrt(r1) - v_1 } else { v_1 - math.sqrt(v_2 - r1) } dx := if r1 < v_1 { math.sqrt(r1) - v_1 } else { v_1 - math.sqrt(v_2 - r1) }
r2 := v_2 * rand_f64() r2 := v_2 * rand_f64()
dy := if r2 < v_1 { math.sqrt(r2) - v_1 } else { v_1 - math.sqrt(v_2 - r2) } dy := if r2 < v_1 { math.sqrt(r2) - v_1 } else { v_1 - math.sqrt(v_2 - r2) }
d := cx.mult_s( ( (f64(sx) + 0.5 + dx)*0.5 + f64(x))*w1 - .5) + d := cx.mult_s( ( (f64(sx) + 0.5 + dx)*0.5 + f64(x))*w1 - .5) +
cy.mult_s( ( (f64(sy) + 0.5 + dy)*0.5 + f64(y))*h1 - .5) + cam.d cy.mult_s( ( (f64(sy) + 0.5 + dy)*0.5 + f64(y))*h1 - .5) + cam.d
r = r + radiance(Ray{cam.o+d.mult_s(140.0), d.norm()}, 0, scene_id).mult_s(samps1) r = r + radiance(Ray{cam.o+d.mult_s(140.0), d.norm()}, 0, scene_id).mult_s(samps1)
} }
@ -432,7 +432,7 @@ fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image {
*ivec = *ivec + tmp_vec *ivec = *ivec + tmp_vec
} }
} }
} }
} }
return image return image
} }
@ -447,7 +447,7 @@ fn main() {
mut samples := 4 // number of samples per pixel, increase for better quality mut samples := 4 // number of samples per pixel, increase for better quality
mut scene_id := 0 // scene to render [0 cornell box,1 sunset,2 psyco] mut scene_id := 0 // scene to render [0 cornell box,1 sunset,2 psyco]
mut file_name := 'image.ppm' // name of the output file in .ppm format mut file_name := 'image.ppm' // name of the output file in .ppm format
if os.args.len >= 2 { if os.args.len >= 2 {
samples = os.args[1].int() / 4 samples = os.args[1].int() / 4
} }
@ -463,20 +463,20 @@ fn main() {
if os.args.len == 6 { if os.args.len == 6 {
height = os.args[5].int() height = os.args[5].int()
} }
// init the rand, using the same seed allows to obtain the same result in different runs // init the rand, using the same seed allows to obtain the same result in different runs
// change the seed from 2020 for different results // change the seed from 2020 for different results
rand.seed(2020) rand.seed(2020)
t1:=time.ticks() t1:=time.ticks()
image := ray_trace(width, height, samples, file_name, scene_id) image := ray_trace(width, height, samples, file_name, scene_id)
t2:=time.ticks() t2:=time.ticks()
eprintln('\nRendering finished. Took: ${t2-t1:5d}ms') eprintln('\nRendering finished. Took: ${t2-t1:5d}ms')
image.save_as_ppm( file_name ) image.save_as_ppm( file_name )
t3:=time.ticks() t3:=time.ticks()
eprintln('Image saved as [${file_name}]. Took: ${t3-t2:5d}ms') eprintln('Image saved as [${file_name}]. Took: ${t3-t2:5d}ms')
} }