From 59a65d757b4fe53bf5573bbcdf759f3d96af267f Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 4 Mar 2020 17:28:05 +0100 Subject: [PATCH] examples: use vcalloc --- .../modules/automaton/automaton.v | 4 +- examples/path_tracing.v | 156 +++++++++--------- 2 files changed, 80 insertions(+), 80 deletions(-) diff --git a/examples/game_of_life/modules/automaton/automaton.v b/examples/game_of_life/modules/automaton/automaton.v index d31a1381cb..af3fc88e37 100644 --- a/examples/game_of_life/modules/automaton/automaton.v +++ b/examples/game_of_life/modules/automaton/automaton.v @@ -46,8 +46,8 @@ fn new_automaton(f [][]int) Automaton { maxx = f[y].len } } - field := &A2D{ maxx: maxx maxy: maxy data: &int( calloc( sizeof(int) * maxy * maxx ) ) } - new_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( vcalloc( sizeof(int) * maxy * maxx ) ) } for y in 0..field.maxy { for x in 0..field.maxx { field.set( x, y, f[y][x] ) diff --git a/examples/path_tracing.v b/examples/path_tracing.v index 1ad3044fe1..d4ce38180c 100644 --- a/examples/path_tracing.v +++ b/examples/path_tracing.v @@ -8,7 +8,7 @@ * This file contains a path tracer example in less of 500 line of codes * 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 * - https://www.kevinbeason.com/smallpt/ * @@ -16,13 +16,13 @@ * - there are some approximation errors in the calculations * - to speed-up the code a cos/sin table is used * - 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 -* - 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 * in linux: ulimit -s byte_size_of_the_stack * example: ulimit -s 16000000 -* - No OpenMP support +* - No OpenMP support **********************************************************************/ import os import math @@ -34,10 +34,10 @@ const ( eps = f64(1e-4) f_0 = f64(0.0) ) - + /***************************** 3D Vector utility struct **********************/ -struct Vec { -mut: +struct Vec { +mut: x f64 = f64(0.0) y f64 = f64(0.0) z f64 = f64(0.0) @@ -94,7 +94,7 @@ fn new_image(w int, h int) Image { return Image{ width: w, 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() -enum Refl_t { - diff, - spec, - refr -} +enum Refl_t { + diff, + spec, + refr +} /********************************* Sphere ************************************/ struct Sphere { @@ -137,21 +137,21 @@ struct Sphere { } 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) mut det := b * b - op.dot(op) + sp.rad * sp.rad if det < 0 { return f64(0) } - + det = math.sqrt(det) - + mut t := b - det if t > eps { return t } - + t = b + det if t > eps { return t @@ -165,19 +165,19 @@ fn (sp Sphere) intersect (r Ray) f64 { * 2) Psychedelic * The sphere fileds are: Sphere{radius, position, emission, color, material} ******************************************************************************/ -const ( +const ( Cen = Vec{50, 40.8, -860} // used by scene 1 spheres = [ [// 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 +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 +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,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{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: 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{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, 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: 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: 600 , p: Vec{50,681.6-.27,81.6} , e: Vec{12,12,12}, c: Vec{}, refl: .diff} //Lite ], [// scene 1 sunset @@ -272,27 +272,27 @@ fn radiance(r Ray, depthi int, scene_id int) Vec { sin_tab := &f64( tabs.sin_tab ) cos_tab := &f64( tabs.cos_tab ) 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 res := false // result of intersect - + v_1 := f64(1.0) //v_2 := f64(2.0) - + scene := spheres[scene_id] //res, t, id = intersect(r, id, tb.scene) res, t, id = intersect(r, scene.data, scene.len) - if !res { return Vec{} } //if miss, return black - - obj := scene[id] // the hit object - + if !res { return Vec{} } //if miss, return black + + obj := scene[id] // the hit object + x := r.o + r.d.mult_s(t) n := (x - obj.p).norm() - + nl := if n.dot(r.d) < 0.0 { n } else { n.mult_s(-1) } - + mut f := obj.c - + // max reflection mut p := 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 { if f.y > f.z { p = f.y - } + } } - + depth++ - if depth > 5 { + if depth > 5 { if rand_f64() < p { f = f.mult_s(f64(1.0)/p) } else { return obj.e //R.R. } } - - if obj.refl == .diff { // Ideal DIFFUSE reflection + + if obj.refl == .diff { // Ideal DIFFUSE reflection // **Full Precision** //r1 := f64(2.0 * math.pi) * rand_f64() - + // tabbed speed-up r1 := C.rand() & cache_mask - + r2 := rand_f64() r2s := math.sqrt(r2) - + w := nl - + mut u := if math.abs(w.x) > f64(0.1) { Vec{0, 1, 0} } else { Vec{1, 0, 0} } u = u.cross(w).norm() - + v := w.cross(u) - + // **Full Precision** //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 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) } else { 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) } } - + 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) nt := f64(1.5) - + nnt := if into { nc / nt } else { nt / nc } - + ddn := r.d.dot(nl) cos2t := v_1 - nnt * nnt * (v_1 - ddn * ddn) if cos2t < 0.0 { // Total internal reflection return obj.e + f * radiance(refl_ray, depth, scene_id) } - + dirc := if into { f64(1) } else { f64(-1) } tdir := (r.d.mult_s(nnt) - n.mult_s(dirc * (ddn * nnt + math.sqrt(cos2t)))).norm() - + a := 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) } - + re := r0 + (v_1 - r0) * c * c * c * c * c tr := v_1 - re pp := f64(.25) + f64(.5) * re rp := re / pp tp := tr / (v_1 - pp) - + mut tmp := Vec{} if depth > 2 { // Russian roulette @@ -391,26 +391,26 @@ fn radiance(r Ray, depthi int, scene_id int) Vec { /************************ beam scan routine **********************************/ fn ray_trace(w int, h int, samps int, file_name string, scene_id int) Image { image := new_image(w, h) - + // inverse costants w1 := f64(1.0 / w) h1 := f64(1.0 / h) samps1 := f64(1.0 / samps) - + 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} cy := cx.cross(cam.d).norm().mult_s(0.5135) mut r := Vec{} - + // speed-up constants v_1 := f64(1.0) v_2 := f64(2.0) - + // OpenMP injection point! #pragma omp parallel for schedule(dynamic, 1) shared(c) for y:=0; y < h; y++ { eprint("\rRendering (${samps * 4} spp) ${(100.0 * f64(y)) / (f64(h) - 1.0):5.2f}%") for x in 0..w { - + i := (h - y - 1) * w + x mut ivec := &image.data[i] // 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 { r1 := v_2 * rand_f64() dx := if r1 < v_1 { math.sqrt(r1) - v_1 } else { v_1 - math.sqrt(v_2 - r1) } - + r2 := v_2 * rand_f64() 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 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 } } - } + } } return image } @@ -447,7 +447,7 @@ fn main() { 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 file_name := 'image.ppm' // name of the output file in .ppm format - + if os.args.len >= 2 { samples = os.args[1].int() / 4 } @@ -463,20 +463,20 @@ fn main() { if os.args.len == 6 { height = os.args[5].int() } - + // init the rand, using the same seed allows to obtain the same result in different runs // change the seed from 2020 for different results - rand.seed(2020) - + rand.seed(2020) + 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() - + eprintln('\nRendering finished. Took: ${t2-t1:5d}ms') - - image.save_as_ppm( file_name ) + + image.save_as_ppm( file_name ) t3:=time.ticks() - + eprintln('Image saved as [${file_name}]. Took: ${t3-t2:5d}ms') }