Plan 9 from Bell Labs’s /usr/web/sources/contrib/maht/inferno/appl/cmd/MiniLight/MinilLight.b

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


implement Minilight;

include "sys.m";
	sys: Sys;

include "math.m";
	math : Math;

include "draw.m";
	draw: Draw;

include "bufio.m";
	bufio: Bufio;
	Iobuf: import bufio;

include "string.m";
	str: String;

Minilight: module
{
	init:	fn(nil: ref Draw->Context, nil: list of string);
	vfromstring : fn(txt : string) : ref Vector;
	vfromval : fn(v : real) : ref Vector;
	vfromvals : fn(x, y, z : real) : ref Vector;
	vfromvec : fn(v :ref Vector) : ref Vector;
	tfromstring : fn(txt : string) : ref Triangle;
};

Vector: adt {
	x, y, z : real;

	copy : fn(v: self ref Vector, o : ref Vector); 
	negate : fn(v: self ref Vector) : ref Vector;
	add : fn(v: self ref Vector, o : ref Vector) : ref Vector;
	sub : fn(v: self ref Vector, o : ref Vector) : ref Vector;
	mul : fn(v: self ref Vector, o : ref Vector) : ref Vector;
	scale : fn(v: self ref Vector, s : real) : ref Vector;
	is_zero : fn(v: self ref Vector) : int;
	dot : fn(v: self ref Vector, o : ref Vector) : real;
	unitize : fn(v: self ref Vector) : ref Vector;
	cross : fn(v: self ref Vector, o : ref Vector) : ref Vector;
	clamp: fn(v: self ref Vector, hi, lo : ref Vector);
	clamped: fn(v: self ref Vector, hi, lo : ref Vector) : ref Vector;
	tostring: fn(v: self ref Vector) : string;
};

ZERO, MAX, ONE : ref Vector;
TOLERANCE := 1.0 / 1024.0;
PI := 3.1415926535897932384626;
MAX_ITEMS := 8;
MAX_LEVELS := 44;

Triangle : adt {
	a, b, c, edge0, edge1, edge2, reflectivity, emitivity, tangent, normal  : ref Vector;
	area : real;
	tostring: fn(t: self ref Triangle) : string;
	get_bound: fn(t : self ref Triangle) : array of Vector;
};

SpatialIndex: adt {
	bound : array of ref Vector;
	is_branch : int;
	vector : array of real;
	fill_vector : fn(s : self ref SpatialIndex, items : list of (array of Vector, ref Triangle));
	get_intersection : fn(s : self ref SpatialIndex, origin, direction : ref Vector, last_hit : list of real) : list of real;
};

Camera : adt {
	position, direction, right, up : ref Vector;
	angle : real;
	tostring : fn(c : self ref Camera) : string;
};
	
Scene : adt {
	camera : ref Camera;
	iterations, width, height : int;
	skyemission, groundreflection : ref Vector;
	triangles : list of ref Triangle;
	emitters : list of ref Triangle;
	index : ref SpatialIndex;

	fprint : fn(s : self ref Scene, fd : ref Sys->FD);
	render : fn(s : self ref Scene, fd : ref Sys->FD);
};

next_real(v: chan of ref Vector, b : ref Iobuf)
{
	r, x, y, z : real;
	t : string;
	digits := 0;
	invector := 0;
	for(t = b.gett(")	(
 \n"); t != nil; t = b.gett(")	(
 \n")) { 
		case t[0] {
		'#' =>
			if(t[len(t)-1] != '\n')
				t = b.gett("\n");
		'
' or '\n'  or '	' or ' ' =>
			;
		')' =>
			invector = 0;
		'(' =>
			invector = 1;
			digits = 0;
		* =>
			if(invector) {
				case digits {
				0 =>
					x = real(t);
				1 =>
					y = real(t);
				2 =>
					z = real(t);
					v <-= ref Vector(x, y, z);
					digits = 0;
				}
				digits++;
				if(t[len(t)-1] == ')')
					invector = 0;
			} else {
				r = real(t);
				v <-= ref Vector(r, r, r);
			}
		}
	}
	v <-= nil;
}

vfromstring(txt : string) : ref Vector
{
	return ref Vector(0.0, 0.0, 0.0);
}

tfromstring(txt : string) : ref Triangle
{
	return nil;
}

vfromval(v : real) : ref Vector
{
	return ref Vector(v, v, v);
}

vfromvals(x, y, z : real) : ref Vector
{
	return ref Vector(x, y, z);
}
vfromvec(v :ref Vector) : ref Vector
{
	return ref Vector(v.x, v.y, v.z);
}

min(a, b : real) : real
{
	if(a > b)
		return b;
	return a;
}

max(a, b : real) : real
{
	if(a > b)
		return a;
	return b;
}

loadmods()
{
	sys = load Sys Sys->PATH;
	math = load Math Math->PATH;
	draw = load Draw Draw->PATH;
	bufio = load Bufio Bufio->PATH;
	str = load String String->PATH;
}

init(nil: ref Draw->Context, nil: list of string)
{
	loadmods();
	ZERO = ref Vector(0.0, 0.0, 0.0);
	ONE = ref Vector(1.0, 1.0, 1.0);
	MAX = ref Vector(2.0**1023, 2.0**1023, 2.0**1023);

	b := bufio->open("/usr/maht/MiniLight/minilight/python/cornellbox.txt", bufio->OREAD);
	if(b != nil)
		scene := new_scene(b);
	if(scene == nil)
		sys->print("failed\n");
	else {
		scene.render(nil);
		scene.fprint(sys->fildes(1));
	}
}

Vector.tostring(v: self ref Vector) : string
{
	return sys->sprint("(%0.3f %0.3f %0.3f)", v.x, v.y, v.z);
}

Vector.copy(v: self ref Vector, o : ref Vector) 
{
	if(o!= nil) {
		v.x = o.x;
		v.y = o.y;
		v.z = o.z;
	}
}

Vector.negate(v: self ref Vector) : ref Vector
{
	return ref Vector(-v.x, -v.y, -v.z);
}

Vector.add(v: self ref Vector, o : ref Vector) : ref Vector
{
	return ref Vector(v.x + o.x, v.y + o.y, v.z + o.z);
}

Vector.sub(v: self ref Vector, o : ref Vector) : ref Vector
{
	return ref Vector(v.x - o.x, v.y - o.y, v.z - o.z);
}

Vector.mul(v: self ref Vector, o : ref Vector) : ref Vector
{
	return ref Vector(v.x * o.x, v.y * o.y, v.z * o.z);
}

Vector.scale(v: self ref Vector, s : real) : ref Vector
{
	return ref Vector(v.x * s, v.y * s, v.z * s);
}

Vector.is_zero(v: self ref Vector) : int 
{
	return v.x == 0.0 && v.y == 0.0 && v.z == 0.0;
}

Vector.dot(v: self ref Vector, o : ref Vector) : real
{
	return v.x * o.x + v.y * o.y + v.z * o.z;
}

Vector.unitize(v: self ref Vector) : ref Vector
{
	length := math->sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
	rlength : real;
	if(length == 0.0)
		rlength = 0.0;
	else
		rlength = 1.0 / length;
	return ref Vector(v.x * rlength, v.y * rlength, v.z * rlength);
}

Vector.cross(v: self ref Vector, o : ref Vector) : ref Vector
{
	return ref Vector(v.y * o.z - v.z * o.y, v.z * o.x - v.x * o.z, v.x * o.y - v.y - o.x);
}

Vector.clamp(v: self ref Vector, lo, hi : ref Vector)
{
	v.x = min(max(v.x, lo.x), hi.x);
	v.y = min(max(v.y, lo.y), hi.y);
	v.z = min(max(v.z, lo.z), hi.z);
}

Vector.clamped(v: self ref Vector, lo, hi : ref Vector) : ref Vector
{
	return ref Vector(min(max(v.x, lo.x), hi.x), min(max(v.y, lo.y), hi.y), min(max(v.z, lo.z), hi.z));
}

new_triangle(vecs : chan of ref Vector) : ref Triangle
{
	t : Triangle;
	t.a =<- vecs;
	if(t.a==nil) return nil;
	t.b =<- vecs;
	if(t.b==nil) return nil;
	t.c =<- vecs;
	if(t.c==nil) return nil;
	t.reflectivity =<- vecs;
	if(t.reflectivity==nil) return nil;
	t.emitivity =<- vecs;
	if(t.emitivity==nil) return nil;

	t.edge0 = t.b.sub(t.a);
	t.edge1 = t.c.sub(t.b);
	t.edge2 = t.c.sub(t.a);

	t.tangent = t.edge0.unitize();
	t.normal = t.tangent.cross(t.edge1).unitize();

	pa2 := t.edge0.cross(t.edge1);
	t.area = math->sqrt(pa2.dot(pa2)) * 0.5;

	t.reflectivity.clamp(ZERO, ONE);
	t.emitivity.clamp(ZERO, MAX);

	return ref t;
}

collect_triangles(v : chan of ref Vector, t : chan of ref Triangle)
{
	tri : ref Triangle;
	for(tri = new_triangle(v); t != nil; tri = new_triangle(v))
		t <-= tri;
	t <-= nil;
}

new_scene(b : ref Iobuf) : ref Scene
{
	if(b == nil) return nil;
	vecs := chan of ref Vector;
	spawn next_real(vecs, b);
	S : Scene;
	s := ref S;
	v :=<- vecs;
	if(v==nil) return nil;
	s.iterations = int(v.x);

	v =<- vecs;
	if(v==nil) return nil;
	s.width = int(v.x);
	
	v =<- vecs;
	if(v==nil) return nil;
	s.height = int(v.x);
	
	s.camera = new_camera(vecs);
	if(s.camera == nil) return nil;

	s.skyemission =<- vecs;
	if(s.skyemission==nil) return nil;

	s.groundreflection =<- vecs;
	if(s.groundreflection==nil) return nil;

	t := chan of ref Triangle;
	spawn collect_triangles(vecs, t);
	i := 0;
	tri : ref Triangle;
	for(tri =<- t; tri != nil; tri =<- t) {
		s.triangles = tri :: s.triangles;
		i++;
	}

	if(s.triangles != nil) {
		tris : list of ref Triangle;
		for(tris = s.triangles; tris != nil && hd tris != nil; tris = tl tris)
			if(!(hd tris).emitivity.is_zero() && (hd tris).area > 0.0)
				s.emitters = (hd tris) :: s.emitters;
		s.index = new_spatial_index(s.camera.position, nil, s.triangles, 0);
	}
	return s;
}

Scene.fprint(s : self ref Scene, fd : ref Sys->FD)
{
	sys->fprint(fd, "%d\n%d %d\n%s\n", s.iterations, s.width, s.height, s.camera.tostring());
	if(s.triangles == nil)
		sys->fprint(fd, "No triangles\n");
	else {
		tris : list of ref Triangle;
		for(tris = s.triangles; tris != nil && hd tris != nil; tris = tl tris)
			sys->fprint(fd, "%s\n", (hd tris).tostring());
	}
}

new_camera(vecs : chan of ref Vector) : ref Camera
{
	C : Camera;
	c := ref C;
	c.position = <- vecs;
	if(c.position==nil) return nil;

	c.direction = <- vecs;
	if(c.position==nil) return nil;
	c.direction = c.direction.unitize();

	if(c.direction.is_zero())
		c.direction = ref Vector(0.0, 0.0, 1.0);

	v := <- vecs;
	if(v==nil) return nil;
	c.angle = min(max(10.0, v.x), 160.0) * PI / 180.0;

	c.right = (ref Vector(0.0, 1.0, 0.0)).cross(c.direction).unitize();
	if(c.right.is_zero()) {
		if(c.direction.y == 0.0)
			c.up = ref Vector(0.0, 0.0, -1.0);
		else
			c.up = ref Vector(0.0, 0.0, c.direction.y);
		c.right = c.up.cross(c.direction).unitize();
	} else {
		c.up = c.direction.cross(c.right).unitize();
	}

	return c;
}

Camera.tostring(c : self ref Camera) : string
{
	return sys->sprint("%s %s %f", c.position.tostring(), c.direction.tostring(), c.angle);
}

Triangle.tostring(t : self ref Triangle) : string
{
	return sys->sprint("%s %s %s %s %s", t.a.tostring(), t.b.tostring(), t.c.tostring(), t.reflectivity.tostring(), t.emitivity.tostring());
}

abs(x : real) : real
{
	if(x < 0.0) return -x;
	return x;
}

bound(a, b, c: real) : (real, real)
{
	lo, hi : real;
	lo = hi = c;

	if(a < b) {
		if(a < lo)
			lo = a;
		if(b > hi)
			hi = b;
	} else {
		if(b < lo)
			lo = b;
		if(a > hi)
			hi = a;
	}
	lo -= (abs(lo) + 1.0) * TOLERANCE;
	hi +=  (abs(hi) + 1.0) * TOLERANCE;
	return (lo, hi);
}

Triangle.get_bound(t : self ref Triangle) : array of Vector
{
	r := array[2] of Vector;
	(r[0].x, r[1].x) = bound(t.a.x, t.b.x, t.c.x);
	(r[0].y, r[1].y) = bound(t.a.y, t.b.y, t.c.y);
	(r[0].z, r[1].z) = bound(t.a.z, t.b.z, t.c.z);
	return r;
}


SpatialIndex.get_intersection(s : self ref SpatialIndex, origin, direction : ref Vector, last_hit : list of real) : list of real
{

}

mesh_boundary(items : list of (array of Vector, ref Triangle)) : ref Vector
{
	itemh : list of (array of Vector, ref Triangle);
	bound := ref Vector;
	v : array of Vector;
	for(itemh = items; itemh != nil; itemh = tl itemh) {
		(v, nil) = (hd itemh);
		if(bound.x > v[0].x)
			bound.x = v[0].x;
		if(bound.y > v[0].y)
			bound.y = v[0].y;
		if(bound.y > v[0].x)
			bound.z = v[0].z;
	}
	return bound;
}

new_spatial_index(p : ref Vector, r : list of real, mesh : list of ref Triangle, level : int) : ref SpatialIndex
{
	S : SpatialIndex;
	s := ref S;
	s.bound = array[2] of ref Vector;
	s.bound[0] = ref Vector(0.0, 0.0, 0.0);
	s.bound[1] = ref Vector(0.0, 0.0, 0.0);
	items : list of (array of Vector, ref Triangle);

	if(p != nil) {
		tris : list of ref Triangle;
		for(tris = mesh; tris != nil && hd tris != nil; tris = tl tris)
			items = ((hd tris).get_bound(), (hd tris)) :: items;
		b := mesh_boundary(items);
		a := p.sub(b);
		size := max(a.x, max(a.y, a.z));
		s.bound[0].copy(b);
		s.bound[1] = p.clamped(b.add(ref Vector(size, size, size)), MAX);
	} else if(r != nil && len(r) == 6) {
		s.bound[0].x = hd r;
		s.bound[0].y = hd tl r;
		s.bound[0].z = hd tl tl r;
		s.bound[1].x = hd tl tl tl r;
		s.bound[1].y = hd tl tl tl tl r;
		s.bound[1].z = hd tl tl tl tl tl r;
	} else {
		return nil;
	}
	
	s.is_branch = len(mesh) > MAX_ITEMS && level < MAX_LEVELS -1;
	s.fill_vector(items);

	return s;
}

SpatialIndex.fill_vector(s : self ref SpatialIndex, items : list of (array of Vector, ref Triangle))
{
	if(s.is_branch) {
		q1 := 0;
		s.vector = array[8] of real;
	} else {
		s.vector = array[len(items)] of real;
	}
}


Scene.render(s : self ref Scene, fd : ref Sys->FD)
{
	
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].