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)
{
}
|