Compare commits

...

4 Commits
master ... rust

Author SHA1 Message Date
64c5abd9b9 Start parsing command line arguments 2026-08-29 12:48:47 -04:00
d9dc0b7176 Add Cli struct 2026-08-21 23:15:42 -04:00
a567084398 Create cargo binary crate 2026-08-20 16:21:00 -04:00
789061b71f Remove old files 2026-08-20 16:16:46 -04:00
86 changed files with 88 additions and 16614 deletions

6
.gitignore vendored
View File

@ -1,5 +1 @@
fart
*.bmp
*.png
/.rscons*
/build/
/target/

7
Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "fart"
version = "0.1.0"

6
Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "fart"
version = "0.1.0"
edition = "2024"
[dependencies]

View File

@ -1,7 +0,0 @@
.PHONY: all
all:
@./rscons
.PHONY: clean
clean:
@./rscons clean

View File

@ -1,19 +0,0 @@
configure do
check_cxx_compiler
check_program "flex"
check_program "bison"
check_lib "pthread"
end
env do |env|
env["CCFLAGS"] += %w[-Wall -O2]
env["CPPPATH"] += glob("src/**")
env.CFile("^/parser/lexer.cc", "src/parser/parser.ll")
env.CFile("^/parser/parser.cc", "src/parser/parser.yy")
env["CPPPATH"] += ["#{env.build_root}/parser"]
sources = glob("src/**/*.cc")
sources += ["^/parser/lexer.cc", "^/parser/parser.cc"]
env.Program("fart", sources)
end

2
configure vendored
View File

@ -1,2 +0,0 @@
#!/bin/sh
exec ./rscons configure "$@"

1
fart Symbolic link
View File

@ -0,0 +1 @@
target/debug/fart

46
rscons

File diff suppressed because one or more lines are too long

View File

@ -1,41 +0,0 @@
scene
{
options
{
multisample 3
width 800
height 600
ambient_occlusion 5
}
camera
{
position <2, -3, 2>
look_at <0, 0, 1>
up <0, 0, 1>
}
light
{
position <200, -10, 50>
}
define material white
{
color <1, 1, 1>
}
sphere
{
radius 1
material white
translate <0, 0, 1>
}
plane
{
position <0, 0, 1>, 0
material white
}
}

View File

@ -1,228 +0,0 @@
scene
{
options
{
multisample 3
}
camera
{
position <3, -2.6, 2>
look_at <1.5, -1, 0>
up <0, 0, 1>
}
light
{
position <-2, -5, 6>
}
plane
{
position <1, -1, 1.5>, 3
material
{
color <1, 1, 0>
}
}
define material green
{
color <0, 1, 0>
shininess 3
}
subtract
{
intersect
{
box
{
size <1, 1, 1>
material
{
color <1, 0.4, 0.4>
}
}
sphere
{
radius 0.67
material
{
color <0, 0, 1>
shininess 3
}
}
}
union
{
cyl
{
size <0.35, 0.35, 1.2>
translate <0, 0, -0.6>
material green
}
union
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <1, 0, 0>
translate <0, 0, -0.6>
material green
}
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <0, 1, 0>
translate <0, 0, -0.6>
material green
}
}
}
}
scale <0.5, 0.5, 0.5>
{
translate <0, -3, -2>
{
intersect
{
box
{
size <1, 1, 1>
material
{
color <1, 0.4, 0.4>
}
}
sphere
{
radius 0.67
material
{
color <0, 0, 1>
shininess 3
}
}
}
translate <0, -1.5, -1>
{
box
{
size <1, 1, 1>
material
{
color <1, 0.4, 0.4>
}
}
}
translate <1.5, 0, -1>
{
sphere
{
radius 0.67
material
{
color <0, 0, 1>
shininess 3
}
}
}
}
translate <3, 0, -2>
{
union
{
cyl
{
size <0.35, 0.35, 1.2>
translate <0, 0, -0.6>
material green
}
union
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <1, 0, 0>
translate <0, 0, -0.6>
material green
}
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <0, 1, 0>
translate <0, 0, -0.6>
material green
}
}
}
translate <0, -1.5, -1>
{
cyl
{
size <0.35, 0.35, 1.2>
translate <0, 0, -0.6>
material green
}
}
translate <1.5, 0, -1>
{
union
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <1, 0, 0>
translate <0, 0, -0.6>
material green
}
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <0, 1, 0>
translate <0, 0, -0.6>
material green
}
}
translate <0, -1.5, -1>
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <1, 0, 0>
translate <0, 0, -0.6>
material green
}
}
translate <1.5, 0, -1>
{
cyl
{
size <0.35, 0.35, 1.2>
rotate 90, <0, 1, 0>
translate <0, 0, -0.6>
material green
}
}
}
}
}
}

View File

@ -1,84 +0,0 @@
scene
{
options
{
width 800
height 600
multisample 3
}
camera
{
position <1.0, -2, 1.2>
look_at <0, 0, 0.4>
up <0, 0, 1>
}
light
{
position <10, 0, 10>
}
define material cyan
{
color <0, 1, 1>
}
plane
{
position <0, 0, 1>, 0
material
{
color <1, 1, 0>
reflectance 0.6
}
}
translate <0, 0, 0.7>
{
box
{
size <0.4, 0.4, 0.4>
material
{
color <1.0, 0.6, 0>
}
}
cyl {
size <0.2, 0, 0.3>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate 90, <1, 0, 0>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate -90, <1, 0, 0>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate 180, <1, 0, 0>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate 90, <0, 1, 0>
translate <0, 0, 0.3>
material cyan
}
cyl {
size <0.2, 0, 0.3>
rotate -90, <0, 1, 0>
translate <0, 0, 0.3>
material cyan
}
}
}

View File

@ -1,152 +0,0 @@
scene
{
options
{
multisample 3
exposure 1.2
}
camera
{
position <1.2, -2, 1>
look_at <0, 0, 0>
}
light { position <10, -12, 8> }
plane
{
position <0, 0, 1>, 0.501
material
{
color <0.4, 1, 0.4>
reflectance 0.4
}
}
plane
{
position <1, 0, 0>, 1
material
{
color <1, 0.4, 0.4>
reflectance 0.4
}
}
plane
{
position <0, -1, 0>, 1
material
{
color <0.4, 0.4, 1>
reflectance 0.4
}
}
subtract
{
union
{
box { size <1, 0.8, 0.8> }
box { size <0.8, 1, 0.8> }
box { size <0.8, 0.8, 1> }
cyl { size <0.1, 0.1, 0.8> translate <0.4, 0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <0.4, -0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <-0.4, 0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <-0.4, -0.4, -0.4> }
cyl {
size <.1, .1, .8>
translate <.4, -.4, .4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, -.4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <-.4, -.4, .4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <-.4, -.4, -.4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, .4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, -.4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, .4, .4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, .4, -.4>
rotate -90, <0, 1, 0>
}
sphere { radius .1 translate <.4, .4, .4> }
sphere { radius .1 translate <.4, .4, -.4> }
sphere { radius .1 translate <.4, -.4, .4> }
sphere { radius .1 translate <.4, -.4, -.4> }
sphere { radius .1 translate <-.4, .4, .4> }
sphere { radius .1 translate <-.4, .4, -.4> }
sphere { radius .1 translate <-.4, -.4, .4> }
sphere { radius .1 translate <-.4, -.4, -.4> }
material
{
color <1, 0.4, 1>
transparency 0.4
}
}
union
{
sphere { radius .1 translate <0, -.5, 0> }
sphere { radius .1 translate <-.5, .25, -.25> }
sphere { radius .1 translate <-.5, -.25, .25> }
sphere { radius .1 translate <0, 0, -.5> }
sphere { radius .1 translate <.25, -.25, -.5> }
sphere { radius .1 translate <-.25, .25, -.5> }
sphere { radius .1 translate <-.25, -.25, .5> }
sphere { radius .1 translate <-.25, .25, .5> }
sphere { radius .1 translate <.25, -.25, .5> }
sphere { radius .1 translate <.25, .25, .5> }
sphere { radius .1 translate <.5, 0, 0> }
sphere { radius .1 translate <.5, .25, .25> }
sphere { radius .1 translate <.5, .25, -.25> }
sphere { radius .1 translate <.5, -.25, .25> }
sphere { radius .1 translate <.5, -.25, -.25> }
sphere { radius .1 translate <.25, .5, 0> }
sphere { radius .1 translate <.25, .5, -.25> }
sphere { radius .1 translate <.25, .5, .25> }
sphere { radius .1 translate <-.25, .5, 0> }
sphere { radius .1 translate <-.25, .5, -.25> }
sphere { radius .1 translate <-.25, .5, .25> }
material
{
color <1, 1, 1>
}
}
}
}

View File

@ -1,134 +0,0 @@
scene
{
options
{
ambient <0.2, 0.2, 0.2>
}
define material dw_blue {
color <0.000, 0.520, 0.546>
specular <0.5, 0.5, 0.5>
}
define material dw_brown {
color <0.634, 0.628, 0.126>
specular <0.5, 0.5, 0.5>
}
define material grey_ground {
color <0.3, 0.3, 0.3>
specular <0, 0, 0>
}
define shape dw_logo union {
subtract {
intersect {
cyl {
size <3.055, 3.055, 0.5>
translate <-4.454, 0.074, -0.25>
}
box {
size <6.01, 5.94, 1>
translate <-1.782, 0, 0>
}
}
cyl {
size <0.738, 0.738, 2>
translate <-3.645, 0.041, -1>
}
box {
size <1.96, 0.456, 2>
translate <-2.212, 0.048, 0>
}
material dw_blue
}
cyl {
size <0.307, 0.307, 0.5>
translate <-3.645, 0.041, -0.25>
material dw_brown
}
subtract {
extrude {
offset 0.5
polygon {
<4.787, -2.971>
<4.787, 1.565>
<4.196, 1.565>
<2.756, -2.375>
<1.367, 1.052>
<0.007, -2.40192>
<-0.891, -0.174>
<-3, -0.174>
<-3, -2.971>
}
translate <0, 0, -0.25>
}
cyl {
size <3.488, 3.488, 2>
translate <-4.454, 0.074, -1>
}
material dw_blue
}
subtract {
extrude {
offset 0.5
polygon {
<4.787, 2.025>
<4.787, 2.971>
<-3, 2.971>
<-3, 0.283>
<-0.588, 0.283>
<0.000, -1.179>
<1.368, 2.273>
<2.728, -1.083>
<3.877, 2.025>
}
translate <0, 0, -0.25>
}
cyl {
size <3.488, 3.488, 2>
translate <-4.454, 0.074, -1>
}
material dw_brown
}
scale 0.104
}
camera
{
position <0, 0, 10>
look_at <0, 0, 0>
up <0, 1, 0>
}
light
{
position <100, -100, 100>
}
plane
{
position <0, 0, 1>, 0
material grey_ground
}
for (local $i = 0; $i < 4; $i = $i + 1)
{
local $n_logos = 2 ^ ($i + 2)
for (local $j = 0; $j < $n_logos; $j = $j + 1)
{
shape dw_logo
{
rotate $j * 360 / $n_logos, <0, 0, 1>
translate <1.5 * ($i + 1), 0, 0.4 - 0.1 * $i>
if ($i > 0 && ($j + $i) % 2 == 1)
{
rotate 90, <0, 0, 1>
}
rotate -90, <0, 0, 1>
}
}
}
shape dw_logo { translate <0, 0, 0.5> }
}

View File

@ -1,123 +0,0 @@
scene {
define material dw_blue {
color <0.000, 0.520, 0.546>
specular <0.5, 0.5, 0.5>
}
define material dw_brown {
color <0.634, 0.628, 0.126>
specular <0.5, 0.5, 0.5>
}
define material grey_ground {
color <0.3, 0.3, 0.3>
shininess 30
}
define shape dw_logo union {
subtract {
intersect {
cyl {
size <3.055, 3.055, 0.5>
translate <-4.454, 0.074, -0.25>
}
box {
size <6.01, 5.94, 1>
translate <-1.782, 0, 0>
}
}
cyl {
size <0.738, 0.738, 2>
translate <-3.645, 0.041, -1>
}
box {
size <1.96, 0.456, 2>
translate <-2.212, 0.048, 0>
}
material dw_blue
}
cyl {
size <0.307, 0.307, 0.5>
translate <-3.645, 0.041, -0.25>
material dw_brown
}
subtract {
extrude {
offset 0.5
polygon {
<4.787, -2.971>
<4.787, 1.565>
<4.196, 1.565>
<2.756, -2.375>
<1.367, 1.052>
<0.007, -2.40192>
<-0.891, -0.174>
<-3, -0.174>
<-3, -2.971>
}
translate <0, 0, -0.25>
}
cyl {
size <3.488, 3.488, 2>
translate <-4.454, 0.074, -1>
}
material dw_blue
}
subtract {
extrude {
offset 0.5
polygon {
<4.787, 2.025>
<4.787, 2.971>
<-3, 2.971>
<-3, 0.283>
<-0.588, 0.283>
<0.000, -1.179>
<1.368, 2.273>
<2.728, -1.083>
<3.877, 2.025>
}
translate <0, 0, -0.25>
}
cyl {
size <3.488, 3.488, 2>
translate <-4.454, 0.074, -1>
}
material dw_brown
}
scale 0.104
}
shape dw_logo {
translate <0, 0.387, 0.309>
rotate 90, <1, 0, 0>
}
subtract {
plane {
position <0, 0, 1>, 0
}
shape dw_logo {
translate <0, 0, -0.025>
}
material grey_ground
}
camera {
position <-0.2, -0.8, 0.4>
look_at <-0.1, 0, 0.2>
up <0, 0, 1>
}
light {
position <10, -12, 5>
radius 0.2
jitter 3
}
options {
ambient_occlusion 5
multisample 3
}
}

View File

@ -1,53 +0,0 @@
scene
{
options
{
ambient_occlusion 2
multisample 2
exposure 1.2
}
camera
{
position <0, -10, 10>
look_at <0, 0, 2>
}
light { position <10, -12, 8> }
plane
{
position <0, 0, 1>, 0
material
{
color <0, 0.5, 0.1>
}
}
subtract
{
extrude { ngon 5, 6 offset 2 }
extrude { ngon 5, 5 offset 3 translate <0, 0, -0.5> }
material { color <1, 0.7, 0> }
}
union
{
extrude
{
ngon 6, 2
offset 3 { scale 0.5 position <4, 0> }
offset 3
offset 1 { scale 0 }
}
extrude
{
ngon 6, 2
offset 3 { scale 0.5 position <-4, 0> }
offset 3
offset 1 { scale 0 }
}
material { color <0, 0.9, 0.9> }
}
}

View File

@ -1,55 +0,0 @@
scene
{
camera
{
position <0, -40, 50>
look_at <0, 100, 0>
}
light
{
position <100, -100, 50>
}
define material mat
{
color <0, 0.8, 1>
}
define material glass
{
transparency 1
refraction 1.5
}
plane
{
position <0, 0, 1>, 0
material
{
color <0, 0.7, 0>
}
}
for (local $x = -200; $x <= 200; $x = $x + 40)
{
for (local $y = 0; $y <= 4000; $y = $y + 40)
{
sphere
{
radius 10
translate <$x, $y, 10>
if ($x == 0 && $y == 0)
{
material glass
translate <0, 0, 20>
}
else
{
material mat
}
}
}
}
}

View File

@ -1,57 +0,0 @@
scene
{
camera
{
position <0, -120, 80>
look_at <0, -40, 5>
}
light
{
position <100, -100, 100>
}
define material mat { color <0, 0.8, 1> }
define material mat2 { color <1, 0.7, 0> }
define material mat3 { transparency 0.5 reflectance 0.7 }
plane
{
position <0, 0, 1>, 0
material
{
color <0, 0.7, 0>
}
}
local $m = 0
for (local $x = -100; $x <= 100; $x = $x + 40)
{
for (local $y = -100; $y <= 100; $y = $y + 40)
{
sphere
{
radius 10
translate <$x, $y, 10>
if ($m % 3 == 0)
{
material mat
}
elsif ($m % 3 == 1)
{
material mat2
}
else
{
material
{
color <1, 0, 0>
transparency abs($x / 120)
}
}
}
$m = $m + 1
}
}
}

View File

@ -1,54 +0,0 @@
scene
{
options
{
multisample 4
width 1024
height 768
max_depth 15
}
camera
{
position <0.00001, -1.9, -0.000001>
look_at <0, 0, 0>
up <0, 0, 1>
}
define material mirror
{
color <0, 0, 0>
specular <0, 0, 0>
reflectance 1.0
}
plane { position <1, 0, 0>, 2 material mirror }
plane { position <-1, 0, 0>, 2 material mirror }
plane { position <0, 1, 0>, 2 material mirror }
plane { position <0, -1, 0>, 2 material mirror }
plane { position <0, 0, 1>, 2 material mirror }
plane { position <0, 0, -1>, 2 material mirror }
sphere
{
radius 0.5
material
{
reflectance 0.2
ambient <0.5, 0.5, 0.5>
diffuse <0.5, 0.5, 0.5>
shininess 80
}
}
light
{
position <1, -1, 1>
}
light
{
position <-1, 1, -1>
}
}

View File

@ -1,151 +0,0 @@
scene
{
options
{
ambient_occlusion 3
multisample 3
exposure 1.2
}
camera
{
position <5, -13, 9>
look_at <0, 0, 2>
}
light { position <10, -12, 8> radius 0.2 jitter 4 }
plane
{
position <0, 0, 1>, 0
material
{
color <0, 0.5, 0.1>
}
}
# define a reusable Die type
define shape Die subtract
{
union
{
box { size <1, 0.8, 0.8> }
box { size <0.8, 1, 0.8> }
box { size <0.8, 0.8, 1> }
cyl { size <0.1, 0.1, 0.8> translate <0.4, 0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <0.4, -0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <-0.4, 0.4, -0.4> }
cyl { size <0.1, 0.1, 0.8> translate <-0.4, -0.4, -0.4> }
cyl {
size <.1, .1, .8>
translate <.4, -.4, .4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, -.4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <-.4, -.4, .4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <-.4, -.4, -.4>
rotate -90, <1, 0, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, .4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, -.4, -.4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, .4, .4>
rotate -90, <0, 1, 0>
}
cyl {
size <.1, .1, .8>
translate <.4, .4, -.4>
rotate -90, <0, 1, 0>
}
define shape Corner sphere { radius 0.1 }
translate <.4, .4, .4> { shape Corner }
translate <.4, .4, -.4> { shape Corner }
translate <.4, -.4, .4> { shape Corner }
translate <.4, -.4, -.4> { shape Corner }
translate <-.4, .4, .4> { shape Corner }
translate <-.4, .4, -.4> { shape Corner }
translate <-.4, -.4, .4> { shape Corner }
translate <-.4, -.4, -.4> { shape Corner }
material
{
color <1, 0.4, 1>
transparency 0.4
}
}
union
{
define shape Pip sphere { radius 0.1 }
translate <0, -.5, 0> { shape Pip }
translate <-.5, .25, -.25> { shape Pip }
translate <-.5, -.25, .25> { shape Pip }
translate <0, 0, -.5> { shape Pip }
translate <.25, -.25, -.5> { shape Pip }
translate <-.25, .25, -.5> { shape Pip }
translate <-.25, -.25, .5> { shape Pip }
translate <-.25, .25, .5> { shape Pip }
translate <.25, -.25, .5> { shape Pip }
translate <.25, .25, .5> { shape Pip }
translate <.5, 0, 0> { shape Pip }
translate <.5, .25, .25> { shape Pip }
translate <.5, .25, -.25> { shape Pip }
translate <.5, -.25, .25> { shape Pip }
translate <.5, -.25, -.25> { shape Pip }
translate <.25, .5, 0> { shape Pip }
translate <.25, .5, -.25> { shape Pip }
translate <.25, .5, .25> { shape Pip }
translate <-.25, .5, 0> { shape Pip }
translate <-.25, .5, -.25> { shape Pip }
translate <-.25, .5, .25> { shape Pip }
material
{
color <1, 1, 1>
}
}
}
# Define an individual stack of dies
define shape DieStack union
{
translate <0, 0, 1.5> { scale 3 { shape Die } }
translate <0, 0, 4> { rotate 45, <0, 0, 1> { scale 2 { shape Die } } }
translate <0, 0, 5.5> { rotate 90, <0, 1, 0> { shape Die } }
}
# Instantiate various DieStack objects
translate <-5, 0, 0> { shape DieStack }
translate <5, 0, 0> { rotate 90, <0, 0, 1> { shape DieStack } }
translate <0, 5, 0> { rotate 180, <0, 0, 1> { shape DieStack } }
translate <0, -5, 0> { rotate 270, <0, 0, 1> { shape DieStack } }
}

View File

@ -1,27 +0,0 @@
scene {
options {
width 400
height 300
}
camera {
position <5, -5, 4>
look_at <0, 0, 1>
}
light {
position <10, -10, 50>
}
plane {
position <0, 0, 1>, 0
material {
color <0, 1, 0.2>
reflectance 0.4
}
}
sphere {
radius 1
translate <0, 0, 1>
material {
color <1, 1, 0>
}
}
}

View File

@ -1,55 +0,0 @@
scene
{
options
{
multisample 3
ambient <0.2, 0.2, 0.2>
}
camera
{
position <1, -2, 1>
look_at <0, 0, 0>
}
light
{
position <-5, -15, 20>
jitter 5
}
plane
{
position <0, 0, 1>, 1
material
{
color <0, 1, 1>
}
}
subtract
{
box
{
size <1, 1, 1>
material { color <0.2, 0.2, 1> }
}
subtract
{
sphere
{
radius 0.4
material { color <1, 0, 0> }
translate <0, -0.5, 0>
}
box
{
size <1, 1, 0.2>
material { color <0, 1, 0> }
translate <0, -0.5, 0>
}
}
}
}

View File

@ -1,46 +0,0 @@
scene
{
options
{
width 800
height 600
multisample 3
}
camera
{
position <2, -2.5, 3>
look_at <-0.5, 0, 0>
up <0, 0, 1>
}
light { position <5, 0, 5> }
plane
{
position <0, 0, 1>, 0
material { color <0.8, 0.8, 0.8> }
}
box
{
size <1, 1, 1>
translate <0, -1.5, 0.6>
material { color <0, 0, 1> transparency 0.8 }
}
box
{
size <1, 1, 1>
translate <0, 0, 0.6>
material { color <0, 0, 1> transparency 0.4 }
}
box
{
size <1, 1, 1>
translate <0, 1.5, 0.6>
material { color <0, 0, 1> transparency 0.1 }
}
}

57
src/cli.rs Normal file
View File

@ -0,0 +1,57 @@
macro_rules! options {
($($name:ident $sflag:literal $lflag:literal $hasarg:literal),* $(,)?) => {
enum Options {
$($name,)*
}
const SHORT_FLAGS: &[&str] = &[
$($sflag,)*
];
const LONG_FLAGS: &[&str] = &[
$($lflag,)*
];
const HAS_ARG: &[bool] = &[
$($hasarg,)*
];
};
}
options! {
Width "w" "width" true,
Height "h" "height" true,
}
#[derive(Default)]
pub struct Cli {
width: Option<usize>,
height: Option<usize>,
input_file: String,
}
impl Cli {
pub fn new() -> Self {
Cli::default()
}
pub fn run(&mut self) -> Option<()> {
let mut args = std::env::args();
/* Skip program name. */
args.next();
loop {
if let Some(arg) = args.next() {
if arg.starts_with("--") {
let flag = &arg[2..];
} else if arg.starts_with("-") {
let flag = &arg[1..2];
} else {
self.input_file = arg;
}
} else {
break;
}
}
Some(())
}
}

View File

@ -1,438 +0,0 @@
#include "distrib.h"
#include <fstream>
#include <string>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h> /* gethostbyname() */
#include <string.h> /* memset() */
#include <fcntl.h> /* fcntl(), F_GETFD, F_SETFD, FD_CLOEXEC */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/tcp.h> /* TCP_NODELAY */
using namespace std;
#define MSG_WANT_DATA 1
#define MSG_SEND_DATA 2
distrib::distrib()
{
pthread_cond_init(&m_listen_cond, NULL);
pthread_cond_init(&m_tasks_complete_cond, NULL);
pthread_mutex_init(&m_listen_mutex, NULL);
pthread_mutex_init(&m_task_mutex, NULL);
pthread_mutex_init(&m_tasks_in_progress_mutex, NULL);
pthread_mutex_init(&m_tasks_complete_mutex, NULL);
m_num_clients = 0;
m_data = NULL;
m_server = true;
m_next_task = 0;
m_client_socket = -1;
m_tasks_complete = 0;
}
distrib::~distrib()
{
if (m_client_socket != -1)
close(m_client_socket);
}
int distrib::readHostFile(const char * filename)
{
ifstream ifs(filename);
if ( ! ifs.is_open() )
return 1;
string host;
while ( ! ifs.eof() )
{
ifs >> host;
if ( ifs.eof() )
break;
m_hosts.push_back(host);
}
ifs.close();
return 0;
}
int distrib::startClients(const std::vector<std::string> & client_options)
{
int ret = 0;
for (int i = 0, sz = m_hosts.size(); i < sz; i++)
{
ret += clientConnect(m_hosts[i], client_options);
}
return ret;
}
int distrib::clientConnect(const string & host,
const std::vector<std::string> & client_options)
{
int id = fork();
if (id < 0) /* check for fork() error */
{
cerr << "Error forking: " << id << endl;
return 1;
}
else if (id > 0) /* in the parent */
{
m_children.push_back(id);
m_num_clients++;
}
else /* in the child */
{
char server_port_str[15];
sprintf(server_port_str, "%d", m_serverport);
vector<string> args;
args.push_back("ssh");
args.push_back(host);
args.push_back("fart");
args.push_back("--host");
args.push_back(m_servername);
args.push_back("--port");
args.push_back(server_port_str);
for (int i = 0, sz = client_options.size(); i < sz; i++)
args.push_back(client_options[i]);
const char * char_star_args[args.size() + 1];
for (int i = 0, sz = args.size(); i < sz; i++)
char_star_args[i] = args[i].c_str();
char_star_args[args.size()] = (char *) NULL;
#if 0
/* debug */
cout << "executing: 'ssh', ";
for (int i = 0, sz = args.size(); i < sz; i++)
cout << "'" << char_star_args[i] << "', ";
cout << endl;
#endif
execvp("ssh", (char * const *) char_star_args);
/* we should not get here */
cerr << "Error " << errno << " with execlp()!" << endl;
exit(33);
}
return 0;
}
void connection_thread(distrib::connection_thread_arg_t * arg)
{
distrib * the_distrib = arg->the_distrib;
int client_socket = arg->client_socket;
delete arg;
int flag = 1;
if (setsockopt(client_socket,
IPPROTO_TCP,
TCP_NODELAY,
(char *) &flag,
sizeof(flag)) < 0)
{
cerr << "Failed to set TCP_NODELAY on client socket in connection thread!" << endl;
}
bool done = false;
/* loop listening for messages from the client */
while (!done)
{
int msg_type;
size_t nread = read(client_socket, &msg_type, sizeof(msg_type));
if (nread == sizeof(msg_type))
{
switch (msg_type)
{
case MSG_WANT_DATA:
{
int task = the_distrib->getTask();
if (write(client_socket, &task, sizeof(task)) < 0)
done = true;
}
break;
case MSG_SEND_DATA:
{
unsigned char data[3 * UNIT_TASK_SIZE];
int task;
if (read(client_socket, &task, sizeof(task)) < 0)
done = true;
else if (read(client_socket, &data[0], sizeof(data)) < 0)
done = true;
else
the_distrib->send_data(task, &data[0], sizeof(data));
}
break;
default:
break;
}
}
else if (nread > 0 && nread < sizeof(msg_type))
{
cerr << "Error: nread = " << nread << "!" << endl;
}
else if (nread < 0)
{
break;
}
}
close(client_socket);
cerr << "Closing connection thread!" << endl;
pthread_exit(NULL);
}
void distrib_server(distrib * the_distrib)
{
char hostname[1000];
gethostname(&hostname[0], 1000);
the_distrib->m_servername = hostname;
int listen_socket = socket(PF_INET, SOCK_STREAM, 0);
if ( listen_socket == -1 )
{
cerr << "Error " << errno << " creating listen socket!" << endl;
exit(39);
}
int flags = fcntl(listen_socket, F_GETFD);
flags |= FD_CLOEXEC;
fcntl(listen_socket, F_SETFD, flags);
if ( listen(listen_socket, 5) == -1 )
{
cerr << "Error " << errno << " when trying to listen!" << endl;
exit(40);
}
struct sockaddr_in addr;
int addr_len = sizeof(struct sockaddr_in);
getsockname(listen_socket,
(struct sockaddr *) &addr,
(socklen_t *) &addr_len);
int ip_addr = ntohl(addr.sin_addr.s_addr);
the_distrib->m_serverport = ntohs(addr.sin_port);
cout << "Listening on "
<< (unsigned int) ((ip_addr >> 24) & 0xFF)
<< '.'
<< (unsigned int) ((ip_addr >> 16) & 0xFF)
<< '.'
<< (unsigned int) ((ip_addr >> 8) & 0xFF)
<< '.'
<< (unsigned int) (ip_addr & 0xFF)
<< ':'
<< the_distrib->m_serverport
<< endl;
/* signal readiness of the listen thread */
pthread_mutex_lock(&the_distrib->m_listen_mutex);
pthread_cond_signal(&the_distrib->m_listen_cond);
pthread_mutex_unlock(&the_distrib->m_listen_mutex);
for (;;)
{
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int client_socket = accept(listen_socket,
(struct sockaddr *) &client_addr,
&client_addr_len);
if (client_socket < 0)
break;
#if 0
int cip = ntohl(client_addr.sin_addr.s_addr);
cout << "Connection from "
<< (unsigned int) ((cip >> 24) & 0xFF)
<< '.'
<< (unsigned int) ((cip >> 16) & 0xFF)
<< '.'
<< (unsigned int) ((cip >> 8) & 0xFF)
<< '.'
<< (unsigned int) (cip & 0xFF)
<< ':'
<< client_addr.sin_port
<< endl;
#endif
distrib::connection_thread_arg_t * arg =
new distrib::connection_thread_arg_t;
arg->the_distrib = the_distrib;
arg->client_socket = client_socket;
pthread_t client_thread;
pthread_create(&client_thread,
NULL,
(void * (*)(void *)) &connection_thread,
arg);
}
cout << "Listen thread exiting!" << endl;
}
int distrib::startServer()
{
m_server = true;
pthread_mutex_lock(&m_listen_mutex);
/* start the listen thread */
int ret = pthread_create(&m_server_thread,
NULL,
(void * (*)(void *)) distrib_server,
this);
if (ret)
return ret;
/* wait for the listen thread to be running */
pthread_cond_wait(&m_listen_cond, &m_listen_mutex);
pthread_mutex_unlock(&m_listen_mutex);
return ret;
}
int distrib::startClient(const char * server, int port)
{
m_server = false;
m_client_socket = socket(PF_INET, SOCK_STREAM, 0);
if (m_client_socket < 0)
{
cerr << "Error creating client socket: " << errno << endl;
return 1;
}
int flag = 1;
if (setsockopt(m_client_socket,
IPPROTO_TCP,
TCP_NODELAY,
(char *) &flag,
sizeof(flag)) < 0)
{
cerr << "Failed to set TCP_NODELAY on client socket!" << endl;
return 2;
}
struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
struct addrinfo * res;
char portstr[15];
sprintf(portstr, "%d", port);
getaddrinfo(server, portstr, &hint, &res);
if (connect(m_client_socket, res->ai_addr, res->ai_addrlen) == -1)
{
cerr << "Error connecting from client socket: " << errno << endl;
return 2;
}
return 0;
}
int distrib::send_data(int task, unsigned char * data, int num_bytes)
{
if (m_server)
{
if (m_data != NULL)
{
int num_to_copy = num_bytes;
if (3 * task * UNIT_TASK_SIZE + num_to_copy > m_data_size)
num_to_copy = m_data_size - 3 * task * UNIT_TASK_SIZE;
if (num_to_copy > 0)
{
memcpy(m_data + 3 * task * UNIT_TASK_SIZE, data, num_to_copy);
}
taskDone(task);
}
}
else
{
int msg_header = MSG_SEND_DATA; /* send data */
if ( write(m_client_socket, &msg_header, sizeof(msg_header)) < 0
|| write(m_client_socket, &task, sizeof(task)) < 0
|| write(m_client_socket, data, num_bytes) < 0)
{
return -1;
}
}
return 0;
}
int distrib::getTask()
{
int task = -1;
if (m_server)
{
pthread_mutex_lock(&m_task_mutex);
if (m_next_task < m_num_tasks)
{
task = m_next_task;
m_next_task++;
}
pthread_mutex_unlock(&m_task_mutex);
if (task > -1)
startTask(task);
else
{
pthread_mutex_lock(&m_tasks_in_progress_mutex);
std::map<int, int>::const_iterator it = m_tasks_in_progress.begin();
if (it != m_tasks_in_progress.end())
{
task = it->first;
}
pthread_mutex_unlock(&m_tasks_in_progress_mutex);
}
}
else
{
int msg_header = MSG_WANT_DATA;
if (write(m_client_socket, &msg_header, sizeof(msg_header)) < 0)
return -1;
/* wait for a message back */
if (read(m_client_socket, &task, sizeof(task)) < 0)
return -1;
}
return task;
}
void distrib::startTask(int task)
{
pthread_mutex_lock(&m_tasks_in_progress_mutex);
m_tasks_in_progress[task] = 1;
pthread_mutex_unlock(&m_tasks_in_progress_mutex);
}
void distrib::taskDone(int task)
{
pthread_mutex_lock(&m_tasks_in_progress_mutex);
m_tasks_in_progress.erase(task);
m_tasks_complete++;
if (m_tasks_complete == m_num_tasks)
{
pthread_mutex_lock(&m_tasks_complete_mutex);
pthread_cond_signal(&m_tasks_complete_cond);
pthread_mutex_unlock(&m_tasks_complete_mutex);
}
pthread_mutex_unlock(&m_tasks_in_progress_mutex);
}
void distrib::waitAllTasks()
{
int done;
pthread_mutex_lock(&m_tasks_in_progress_mutex);
done = m_tasks_complete;
if (done < m_num_tasks)
pthread_mutex_lock(&m_tasks_complete_mutex);
pthread_mutex_unlock(&m_tasks_in_progress_mutex);
if (done < m_num_tasks)
{
pthread_cond_wait(&m_tasks_complete_cond, &m_tasks_complete_mutex);
pthread_mutex_unlock(&m_tasks_complete_mutex);
}
}

View File

@ -1,72 +0,0 @@
#ifndef DISTRIB_H
#define DISTRIB_H DISTRIB_H
#include <string>
#include <vector>
#include <map>
#include <pthread.h>
#define UNIT_TASK_SIZE 100
class distrib
{
public:
distrib();
~distrib();
int readHostFile(const char * filename);
int startServer();
int startClient(const char * server, int port);
int startClients(const std::vector<std::string> & client_options);
int getNumClients() { return m_num_clients; }
void set_data(unsigned char * data, int size)
{
m_data = data;
m_data_size = size;
}
void set_num_tasks(int num_tasks) { m_num_tasks = num_tasks; }
int getTask();
int send_data(int task, unsigned char * data, int num_bytes);
int getNumTasksInProgress() { return m_tasks_in_progress.size(); }
void waitAllTasks();
std::string & getServerName() { return m_servername; }
int getServerPort() { return m_serverport; }
typedef struct
{
distrib * the_distrib;
int client_socket;
} connection_thread_arg_t;
friend void distrib_server(distrib * the_distrib);
friend void connection_thread(connection_thread_arg_t * arg);
protected:
int clientConnect(const std::string & host,
const std::vector<std::string> & client_options);
void startTask(int task);
void taskDone(int task);
std::vector<std::string> m_hosts;
std::vector<int> m_children;
std::string m_servername;
int m_serverport;
int m_client_socket;
pthread_t m_server_thread;
pthread_cond_t m_listen_cond;
pthread_mutex_t m_listen_mutex;
int m_num_clients;
unsigned char * m_data;
int m_data_size;
int m_num_tasks;
int m_tasks_complete;
int m_next_task;
bool m_server;
pthread_mutex_t m_task_mutex;
std::map<int, int> m_tasks_in_progress;
pthread_mutex_t m_tasks_in_progress_mutex;
pthread_mutex_t m_tasks_complete_mutex;
pthread_cond_t m_tasks_complete_cond;
};
#endif

16
src/main.rs Normal file
View File

@ -0,0 +1,16 @@
mod cli;
use crate::cli::Cli;
use std::process::ExitCode;
fn main() -> ExitCode {
match run() {
Some(_) => ExitCode::SUCCESS,
None => ExitCode::FAILURE,
}
}
fn run() -> Option<()> {
let mut cli = Cli::new();
cli.run()
}

View File

@ -1,130 +0,0 @@
// BMP.cc
// extracts/inserts data from/into .bmp file
// Adapted by Josh Holtrop from the original access_bmp.c by gw
// Supports reading and creating 24-bit color BMP images
#include "BMP.h"
#include <stdio.h>
#include <iostream>
using namespace std;
BMP::BMP(const char * fileName)
{
open(fileName);
}
BMP::BMP(const char * fileName, int width, int height, unsigned char * data)
{
create(fileName, width, height, data);
}
BMP::~BMP()
{
if (m_fp != NULL)
close();
}
bool BMP::open(const char * fileName)
{
size_t bytes_read;
m_fp = fopen(fileName, "r+");
if (m_fp != NULL)
{
// read file header
bytes_read = fread(&m_header, sizeof(m_header), 1, m_fp);
if (m_header.id[0] != 'B' || m_header.id[1] != 'M')
{
cerr << fileName << " does not appear to be a BMP file." << endl;
fclose(m_fp);
m_fp = NULL;
}
// read image information
bytes_read = fread(&m_info, sizeof(m_info), 1, m_fp);
}
(void)bytes_read;
return (m_fp != NULL);
}
bool BMP::create(const char * fileName, int width, int height,
unsigned char * data)
{
size_t bytes_written;
m_fp = fopen(fileName, "w+");
if (m_fp != NULL)
{
/* Initialize the header structure */
m_header.id[0] = 'B';
m_header.id[1] = 'M';
int row_padding = (3 * width) & 0x3;
if (row_padding)
row_padding = 4 - row_padding;
int row_bytes = (3 * width) + row_padding;
m_header.file_size = sizeof(m_header) +
sizeof(m_info) +
row_bytes * height;
m_header.reserved = 0;
m_header.offset = sizeof(m_header) + sizeof(m_info);
/* Initialize the information structure */
m_info.header_size = 40;
m_info.width = width;
m_info.height = height;
m_info.color_planes = 1;
m_info.color_depth = 24;
m_info.compression = 0;
m_info.image_size = 0;
m_info.xresolution = 2835;
m_info.yresolution = 2835;
m_info.num_colors = 0;
m_info.num_important_colors = 0;
/* write them to the file */
bytes_written = fwrite(&m_header, sizeof(m_header), 1, m_fp);
bytes_written = fwrite(&m_info, sizeof(m_info), 1, m_fp);
unsigned int zero = 0;
unsigned char * data_ptr = data + (3 * width) * (height - 1);
for (int i = 0; i < height; i++)
{
bytes_written = fwrite(data_ptr, 3 * width, 1, m_fp);
if (row_padding)
bytes_written = fwrite(&zero, row_padding, 1, m_fp);
data_ptr -= 3 * width;
}
}
(void)bytes_written;
return (m_fp != NULL);
}
void BMP::read(unsigned char * buf)
{
size_t bytes_read;
if (m_fp != NULL)
{
int row_data_bytes = 3 * m_info.width;
int row_padding = row_data_bytes & 0x3;
if (row_padding)
row_padding = 4 - row_padding;
fseek(m_fp,
(m_header.offset != 0
? m_header.offset
: sizeof(m_header) + sizeof(m_info)),
SEEK_SET);
unsigned char * data_ptr = buf + row_data_bytes * (m_info.height - 1);
for (int i = 0; i < m_info.height; i++)
{
bytes_read = fread(data_ptr, row_data_bytes, 1, m_fp);
if (row_padding)
fseek(m_fp, row_padding, SEEK_CUR);
data_ptr -= row_data_bytes;
}
}
(void)bytes_read;
}
void BMP::close()
{
if (m_fp != NULL)
fclose(m_fp);
m_fp = NULL;
}

View File

@ -1,54 +0,0 @@
// BMP.h
// extracts/inserts data from/into .bmp file
// Adapted by Josh Holtrop from the original access_bmp.c by gw
// Supports reading and creating 24-bit color BMP images
#include <stdio.h>
#define BMP_RED 2
#define BMP_GREEN 1
#define BMP_BLUE 0
class BMP
{
public:
typedef struct
{
char id[2];
int file_size;
int reserved;
int offset;
} __attribute__ ((packed)) header_t;
typedef struct
{
int header_size;
int width;
int height;
unsigned short int color_planes;
unsigned short int color_depth;
unsigned int compression;
int image_size;
int xresolution;
int yresolution;
int num_colors;
int num_important_colors;
} __attribute__ ((packed)) info_t;
BMP(const char * fileName);
BMP(const char * fileName, int width, int height, unsigned char * data);
~BMP();
void read(unsigned char * buf);
int getWidth() { return m_info.width; }
int getHeight() { return m_info.height; }
protected:
FILE * m_fp;
header_t m_header;
info_t m_info;
bool open(const char * fileName);
bool create(const char * fileName, int width, int height,
unsigned char * data);
void close();
};

View File

@ -1,20 +0,0 @@
#include "Light.h"
#include "util/Vector.h"
#include "util/Ray.h"
Light::Light()
{
m_position = Vector(0, 0, 0);
m_diffuse_color = Color::white;
m_specular_color = Color::white;
m_jitter = 1;
m_radius = 1.0;
}
Vector Light::getJitterPosition(int index) const
{
if (index == 0)
return m_position;
return m_position + Vector::randomVector() * m_radius;
}

View File

@ -1,48 +0,0 @@
#ifndef LIGHT_H
#define LIGHT_H LIGHT_H
#include "util/Vector.h"
#include "util/Color.h"
class Light
{
public:
Light();
void setPosition(const Vector & position) { m_position = position; }
void setPosition(refptr<Vector> vec) { setPosition(*vec); }
const Vector & getPosition() const { return m_position; }
Vector getJitterPosition(int index) const;
void setDiffuseColor(const Color & diffuse)
{
m_diffuse_color = diffuse;
}
const Color & getDiffuseColor() const { return m_diffuse_color; }
void setSpecularColor(const Color & specular)
{
m_specular_color = specular;
}
const Color & getSpecularColor() const { return m_specular_color; }
void setJitter(int j) { m_jitter = j >= 1 ? j : 1; }
int getJitter() const { return m_jitter; }
void setRadius(double r) { m_radius = r; }
double getRadius() const { return m_radius; }
protected:
Vector m_position;
Color m_diffuse_color;
Color m_specular_color;
double m_radius;
int m_jitter;
};
#include "PointLight.h"
#endif

View File

@ -1,7 +0,0 @@
#include "PointLight.h"
PointLight::PointLight()
: Light()
{
}

View File

@ -1,17 +0,0 @@
#ifndef POINTLIGHT_H
#define POINTLIGHT_H POINTLIGHT_H
#include "Light.h"
#include "util/Color.h"
class PointLight : public Light
{
public:
PointLight();
protected:
};
#endif

View File

@ -1,839 +0,0 @@
#include <math.h>
#include <typeinfo>
#include <iostream>
#include "Scene.h"
#include "Light.h"
#include "util/stb_image.h"
#include "parser/parser.h"
#include "parser/nodes.h"
#include "util/Polygon.h"
#include "util/Scope.h"
using namespace std;
typedef vector< refptr<Node> >::const_iterator Node_Iterator;
#ifdef NODE_TREE_DEBUG
static void dumpNodeTree(refptr<Node> node)
{
static int depth = 0;
for (int i = 0; i < depth; i++)
cerr << ' ';
cerr << typeid(*node).name() << endl;
depth++;
for (Node_Iterator it = node->getChildren().begin(); it != node->getChildren().end(); it++)
{
dumpNodeTree(*it);
}
depth--;
}
#endif
void Scene::load(const char * filename)
{
refptr<Scope> scope = new Scope();
refptr<Node> node = parse(filename, scope);
#ifdef NODE_TREE_DEBUG
dumpNodeTree(node);
#endif
if ( ! node.isNull() )
{
/* evaluate any scripting nodes in the node tree */
refptr<Node> processed_scene = node->evaluate();
node->evaluateChildren(processed_scene);
/* now we have a new node tree under 'dummy' with no scripting nodes */
processScene(processed_scene);
}
}
void Scene::processScene(refptr<Node> node)
{
/* first process any cameras present */
int cameras_found = 0;
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(CameraNode) )
{
cameras_found++;
if (cameras_found == 1)
processCamera(*it);
else
{
cerr << "Error: multiple camera definitions found!" << endl;
exit(5);
}
}
}
/* then any other scene-specific items */
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(LightNode) )
{
refptr<Light> light = processLight(*it);
if ( ! light.isNull() )
m_lights.push_back(light);
}
else if ( typeid(**it) == typeid(OptionsNode) )
{
processOptions(*it);
}
}
/* then any general items */
vector<ShapeRef> shapes = processGeneralItems(node);
for (vector<ShapeRef>::iterator it = shapes.begin();
it != shapes.end();
it++)
{
m_shapes.push_back(*it);
}
}
ShapeRef Scene::processShape(refptr<Node> node)
{
if ( typeid(*node) == typeid(BoxNode) )
{
return processBox(node);
}
else if ( typeid(*node) == typeid(PlaneNode) )
{
return processPlane(node);
}
else if ( typeid(*node) == typeid(SphereNode) )
{
return processSphere(node);
}
else if ( typeid(*node) == typeid(CylNode) )
{
return processCyl(node);
}
else if ( typeid(*node) == typeid(IntersectNode)
|| typeid(*node) == typeid(UnionNode)
|| typeid(*node) == typeid(SubtractNode) )
{
return processBool(node);
}
else if ( typeid(*node) == typeid(ExtrudeNode) )
{
return processExtrude(node);
}
else if ( typeid(*node) == typeid(ShapeRefNode) )
{
return processShapeRef(node);
}
else
{
cerr << "Error: Unknown shape!" << endl;
exit(3);
}
return ShapeRef(NULL);
}
void Scene::processCamera(refptr<Node> node)
{
Vector position(0, 0, 0);
Vector look_at(0, 1, 0);
Vector up(0, 0, 1);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(PositionNode) )
{
position = * (*it)->getVector();
}
else if ( typeid(**it) == typeid(LookAtNode) )
{
look_at = * (*it)->getVector();
}
else if ( typeid(**it) == typeid(UpNode) )
{
up = * (*it)->getVector();
}
else if ( typeid(**it) == typeid(VFOVNode) )
{
m_vfov = (*it)->getNumber();
}
}
m_transforms.top().lookAt(position, look_at, up);
}
void Scene::processOptions(refptr<Node> node)
{
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(WidthNode) )
{
m_width = (*it)->getInteger();
}
else if ( typeid(**it) == typeid(HeightNode) )
{
m_height = (*it)->getInteger();
}
else if ( typeid(**it) == typeid(ExposureNode) )
{
m_exposure = (*it)->getNumber();
if (m_exposure < 0.0)
m_exposure = 0.0;
}
else if ( typeid(**it) == typeid(MultisampleNode) )
{
m_multisample_level = (*it)->getInteger();
}
else if ( typeid(**it) == typeid(MaxDepthNode) )
{
m_max_depth = (*it)->getInteger();
}
else if ( typeid(**it) == typeid(AmbientNode) )
{
setAmbientLight(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(AmbientOcclusionNode) )
{
m_ambient_occlusion_level = (*it)->getInteger();
}
}
}
vector<ShapeRef> Scene::processTransformBlock(refptr<Node> node)
{
if ( typeid(*node) == typeid(TranslateBlockNode) )
{
m_transforms.push(m_transforms.top());
m_transforms.top().translate(node->getVector());
}
else if ( typeid(*node) == typeid(RotateBlockNode) )
{
m_transforms.push(m_transforms.top());
m_transforms.top().rotate(node->getNumber(),
node->getVector());
}
else if ( typeid(*node) == typeid(ScaleBlockNode) )
{
m_transforms.push(m_transforms.top());
m_transforms.top().scale(node->getVector());
}
else
{
cerr << "Unknown transformation block node type!" << endl;
exit(4);
}
vector<ShapeRef> shapes = processGeneralItems(node);
m_transforms.pop();
return shapes;
}
vector<ShapeRef> Scene::processGeneralItems(refptr<Node> node)
{
vector<ShapeRef> shapes, incoming;
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ((*it)->isTransformBlock())
{
incoming = processTransformBlock(*it);
}
else if ( typeid(**it) == typeid(MaterialDefinitionNode) )
{
processMaterialDefinition(*it);
}
else if ( typeid(**it) == typeid(ShapeDefinitionNode) )
{
processShapeDefinition(*it);
}
else if ( (*it)->isShape() )
{
shapes.push_back(processShape(*it));
}
while (incoming.size() > 0)
{
shapes.push_back(incoming[0]);
incoming.erase(incoming.begin());
}
}
return shapes;
}
void Scene::processMaterialDefinition(refptr<Node> node)
{
map< string, refptr<Material> >::iterator it =
m_materials.find(node->getString());
if ( it == m_materials.end() )
{
m_materials[node->getString()] = processMaterial(node);
}
else
{
cerr << "Error: duplicate material definition for material '"
<< node->getString() << "'" << endl;
exit(4);
}
}
refptr<Material> Scene::processMaterial(refptr<Node> node)
{
if ( typeid(*node) == typeid(MaterialRefNode) )
{
map< string, refptr<Material> >::iterator it =
m_materials.find(node->getString());
if ( it == m_materials.end() )
{
cerr << "Undefined material '" << node->getString()
<< "' requested!" << endl;
exit(4);
}
return m_materials[node->getString()];
}
refptr<Material> material = new Material();
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(ColorNode) )
{
material->setDiffuseColor(Color((*it)->getVector()));
material->setAmbientColor(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(AmbientNode) )
{
material->setAmbientColor(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(DiffuseNode) )
{
material->setDiffuseColor(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(SpecularNode) )
{
material->setSpecularColor(Color((*it)->getVector()));
}
else if ( typeid(**it) == typeid(ReflectanceNode) )
{
material->setReflectance((*it)->getNumber());
}
else if ( typeid(**it) == typeid(RefractionNode) )
{
material->setRefraction((*it)->getNumber());
}
else if ( typeid(**it) == typeid(ShininessNode) )
{
material->setShininess((*it)->getNumber());
}
else if ( typeid(**it) == typeid(TransparencyNode) )
{
material->setTransparency((*it)->getNumber());
}
else if ( typeid(**it) == typeid(TextureNode) )
{
string filename = (*it)->getString();
Texture * texture = NULL;
if (m_textures.find(filename) != m_textures.end())
{
/* texture already loaded */
texture = m_textures[filename];
}
else
{
texture = loadTexture(filename);
if (texture != NULL)
{
m_textures[filename] = texture;
}
}
if (texture != NULL)
{
material->setTexture(texture);
}
}
}
return material;
}
ShapeRef Scene::processBox(refptr<Node> node)
{
refptr<Vector> size = new Vector(1, 1, 1);
refptr<Material> material;
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(SizeNode) )
{
size = (*it)->getVector();
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
ShapeRef box = new Box(size);
if ( ! material.isNull() )
box->setMaterial(material);
box->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return box;
}
ShapeRef Scene::processCyl(refptr<Node> node)
{
double radius1 = 1.0;
double radius2 = 1.0;
double height = 1.0;
refptr<Material> material;
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(SizeNode) )
{
refptr<Vector> v = (*it)->getVector();
radius1 = (*v)[0];
radius2 = (*v)[1];
height = (*v)[2];
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
ShapeRef cyl = new Cyl(radius1, radius2, height);
if ( ! material.isNull() )
cyl->setMaterial(material);
cyl->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return cyl;
}
refptr<Light> Scene::processLight(refptr<Node> node)
{
refptr<Light> light = new PointLight();
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(PositionNode) )
{
refptr<Vector> v = (*it)->getVector();
light->setPosition(m_transforms.top().transform_point(*v));
}
else if ( typeid(**it) == typeid(DiffuseNode) )
{
Color c((*it)->getVector());
light->setDiffuseColor(c);
}
else if ( typeid(**it) == typeid(SpecularNode) )
{
Color c((*it)->getVector());
light->setSpecularColor(c);
}
else if ( typeid(**it) == typeid(ColorNode) )
{
Color c((*it)->getVector());
light->setDiffuseColor(c);
light->setSpecularColor(c);
}
else if ( typeid(**it) == typeid(RadiusNode) )
{
light->setRadius((*it)->getNumber());
}
else if ( typeid(**it) == typeid(JitterNode) )
{
light->setJitter((*it)->getInteger());
}
}
return light;
}
ShapeRef Scene::processPlane(refptr<Node> node)
{
Vector normal(0, 0, 1);
double dist = 0;
refptr<Material> material;
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(PlanePositionNode) )
{
normal = *(*it)->getVector();
dist = (*it)->getNumber();
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
ShapeRef plane = new Plane(normal[0],
normal[1],
normal[2],
dist);
if ( ! material.isNull() )
plane->setMaterial(material);
plane->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return plane;
}
ShapeRef Scene::processSphere(refptr<Node> node)
{
double radius = 1.0;
refptr<Material> material;
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(RadiusNode) )
{
radius = (*it)->getNumber();
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
ShapeRef sphere = new Sphere(radius);
if ( ! material.isNull() )
sphere->setMaterial(material);
sphere->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return sphere;
}
ShapeRef Scene::processBool(refptr<Node> node)
{
vector<ShapeRef> shapes;
refptr<Material> material;
bool restore_transform = processTransforms(node);
m_transforms.push(Transform());
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( (*it)->isShape() )
{
ShapeRef shape = processShape(*it);
if ( ! shape.isNull() )
shapes.push_back(shape);
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
else if ( (*it)->isTransformBlock() )
{
vector<ShapeRef> in = processTransformBlock(*it);
for (int i = 0, sz = in.size(); i < sz; i++)
{
shapes.push_back(in[i]);
}
}
else if ( typeid(**it) == typeid(ShapeDefinitionNode) )
{
processShapeDefinition(*it);
}
}
if (shapes.size() < 2)
{
cerr << "Error: boolean objects must have 2 or more sub-objects!"
<< endl;
exit(3);
}
ShapeRef shape;
if ( typeid(*node) == typeid(IntersectNode) )
shape = new Intersect(shapes);
else if ( typeid(*node) == typeid(UnionNode) )
shape = new Union(shapes);
else if ( typeid(*node) == typeid(SubtractNode) )
shape = new Subtract(shapes);
else
{
cerr << __FILE__ << ": " << __LINE__
<< ": error: bool object unrecognized" << endl;
exit(3);
}
if ( ! material.isNull() )
shape->setMaterial(material);
m_transforms.pop();
shape->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return shape;
}
ShapeRef Scene::processExtrude(refptr<Node> node)
{
refptr<Material> material;
Extrude * extrude = new Extrude();
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(PolygonNode) )
{
extrude->addPolygon(processPolygon(*it));
}
else if ( typeid(**it) == typeid(NGonNode) )
{
extrude->addPolygon(processNGon(*it));
}
else if ( typeid(**it) == typeid(OffsetNode) )
{
double distance = (*it)->getNumber();
if (distance <= 0.0)
{
cerr << "Error: extrude distance must be positive" << endl;
exit(3);
}
Vector scale(1, 1, 1);
Vector position(0, 0, 0);
for (Node_Iterator it2 = (*it)->getChildren().begin();
it2 != (*it)->getChildren().end();
it2++)
{
if ( typeid(**it2) == typeid(ScaleNode) )
{
scale = * (*it2)->getVector();
}
else if ( typeid(**it2) == typeid(PositionNode) )
{
position = * (*it2)->getVector();
}
}
if (scale[0] < 0.0 || scale[1] < 0.0)
{
cerr << "Error: extrude scale cannot be negative" << endl;
exit(3);
}
extrude->addOffset(distance, scale, position);
}
else if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
if ( ! material.isNull() )
extrude->setMaterial(material);
extrude->setTransform(m_transforms.top());
if (restore_transform)
m_transforms.pop();
return extrude;
}
refptr<Polygon> Scene::processPolygon(refptr<Node> node)
{
refptr<Polygon> p = new Polygon();
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(VectorNode) )
{
p->push_back((*it)->getVector());
}
else
{
cerr << "Error: Unknown polygon sub-object" << endl;
exit(3);
}
}
if (p->size() < 3)
{
cerr << "Error: Polygon with fewer than three points!" << endl;
exit(3);
}
return p;
}
refptr<Polygon> Scene::processNGon(refptr<Node> node)
{
refptr<Polygon> p = new Polygon();
double radius = node->getChildren()[0]->getNumber();
int n = node->getInteger();
int step = n < 0 ? -1 : 1;
n = abs(n);
if (n < 3)
n = 3;
int pos = 0;
double astep = 2.0 * M_PI / n;
for (int i = 0; i < n; i++)
{
p->push_back(new Vector(
radius * cos(pos * astep),
radius * sin(pos * astep),
0.0));
pos += step;
}
return p;
}
ShapeRef Scene::processShapeRef(refptr<Node> node)
{
if (m_shape_definitions.find(node->getString())
== m_shape_definitions.end())
{
cerr << "Error: no shape definition for '" << node->getString()
<< "' found!" << endl;
exit(3);
}
refptr<Material> material;
ShapeRef shape = m_shape_definitions[node->getString()]->clone();
bool restore_transform = processTransforms(node);
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( (*it)->isMaterial() )
{
material = processMaterial(*it);
}
}
if ( ! material.isNull() )
shape->setMaterial(material);
shape->setTransform(m_transforms.top() * shape->getTransform());
if (restore_transform)
m_transforms.pop();
return shape;
}
bool Scene::processTransforms(refptr<Node> node)
{
bool did_any = false;
for (Node_Iterator it = node->getChildren().begin();
it != node->getChildren().end();
it++)
{
if ( typeid(**it) == typeid(TranslateNode) )
{
if (did_any == false)
{
m_transforms.push(m_transforms.top());
did_any = true;
}
m_transforms.top().translate((*it)->getVector());
}
else if ( typeid(**it) == typeid(RotateNode) )
{
if (did_any == false)
{
m_transforms.push(m_transforms.top());
did_any = true;
}
m_transforms.top().rotate((*it)->getNumber(),
(*it)->getVector());
}
else if ( typeid(**it) == typeid(ScaleNode) )
{
if (did_any == false)
{
m_transforms.push(m_transforms.top());
did_any = true;
}
m_transforms.top().scale((*it)->getVector());
}
}
return did_any;
}
void Scene::processShapeDefinition(refptr<Node> node)
{
m_transforms.push(Transform());
m_shape_definitions[node->getString()]
= processShape(node->getChildren()[0]);
m_transforms.pop();
}
Texture * Scene::loadTexture(const std::string & filename)
{
int width = 0;
int height = 0;
int channels = 0;
/* request 4 channels so the data is always tightly packed RGBA */
unsigned char * data = stbi_load(filename.c_str(), &width, &height,
&channels, 4);
if (data == NULL)
{
cerr << "Error: image \"" << filename << "\" could not be loaded: "
<< stbi_failure_reason() << endl;
return NULL;
}
Texture * texture = new Texture;
texture->width = width;
texture->height = height;
texture->channels = 4;
texture->data = data;
return texture;
}

View File

@ -1,406 +0,0 @@
#include <math.h> /* exp(), pow(), M_PI */
#include <stdlib.h>
#include <string>
#include <vector>
#include <utility> /* pair */
#include <map>
#include <algorithm> /* sort() */
#include <typeinfo> /* typeid operator support */
#include "Scene.h"
#include "BMP.h"
#include "util/stb_image.h"
#include "util/Color.h"
#include "shapes/Shape.h"
#include "Light.h"
using namespace std;
#define MAX_AMBIENT_OCCLUSION_DISTANCE 50.0
Scene::Scene(const map<string, const char *> & options,
const char * filename)
{
m_width = 800;
m_height = 600;
m_multisample_level = 1;
m_vfov = 60.0;
m_ambient_light = Color(0.2, 0.2, 0.2);
m_max_depth = 10;
m_exposure = 1.0f;
m_ambient_occlusion_level = 0;
m_transforms.push(Transform());
load(filename);
/* after loading the scene file, apply any command-line render options */
for (map<const string, const char *>::const_iterator it = options.begin();
it != options.end();
it++)
{
if (it->first == "width")
{
m_width = atoi(it->second);
}
else if (it->first == "height")
{
m_height = atoi(it->second);
}
else if (it->first == "multisample")
{
m_multisample_level = atoi(it->second);
}
else if (it->first == "field-of-view")
{
m_vfov = atof(it->second);
}
else if (it->first == "max-depth")
{
m_max_depth = atoi(it->second);
}
else if (it->first == "ambient-occlusion")
{
m_ambient_occlusion_level = atoi(it->second);
}
}
/* view plane distance is calculated based on the field of view */
m_view_plane_dist = (m_height / 2.0) / tan(M_PI * m_vfov / 360.0);
m_sample_span = 1.0 / m_multisample_level;
m_half_sample_span = m_sample_span / 2.0;
m_multisample_level_squared = m_multisample_level * m_multisample_level;
}
Scene::~Scene()
{
/* clean up any textures loaded with stb_image */
for (std::map< std::string, Texture * >::iterator it = m_textures.begin();
it != m_textures.end();
it++)
{
stbi_image_free(it->second->data);
delete it->second;
}
}
void Scene::renderPixel(int x, int y, unsigned char * pixel)
{
/* calculate the ray going from the camera through this pixel */
Color finalColor;
for (int i = 0; i < m_multisample_level; i++)
{
for (int j = 0; j < m_multisample_level; j++)
{
double rx = (x + i * m_sample_span + m_half_sample_span)
- (m_width / 2.0);
double rz = (m_height / 2.0)
- (y + j * m_sample_span + m_half_sample_span);
Ray ray(Vector(0, 0, 0), Vector(rx, m_view_plane_dist, rz));
finalColor += traceRay(ray);
}
}
/* apply exposure formula so we aren't saturated */
finalColor.r = 1.0f -
exp(-m_exposure * finalColor.r / m_multisample_level_squared);
finalColor.g = 1.0f -
exp(-m_exposure * finalColor.g / m_multisample_level_squared);
finalColor.b = 1.0f -
exp(-m_exposure * finalColor.b / m_multisample_level_squared);
#if 0
/* gamma correct */
finalColor.r = pow(finalColor.r, 1 / 2.2);
finalColor.g = pow(finalColor.g, 1 / 2.2);
finalColor.b = pow(finalColor.b, 1 / 2.2);
#endif
/* take the average of all the samples as the final pixel value */
pixel[BMP_RED] = (unsigned char) (0xFF * finalColor.r);
pixel[BMP_GREEN] = (unsigned char) (0xFF * finalColor.g);
pixel[BMP_BLUE] = (unsigned char) (0xFF * finalColor.b);
}
Color Scene::traceRay(const Ray & ray)
{
return traceRayRecurse(ray, m_max_depth, 1.0, NULL);
}
/**
* factor: the proportion of the final color that this computation is worth
*/
Color Scene::traceRayRecurse(const Ray & ray, int depth, double factor,
refptr<Material> last_material)
{
static refptr<Material> air = new Material();
Color color(0, 0, 0);
if (last_material.isNull())
last_material = air;
Shape::Intersection hit = getRayClosestHit(ray);
if ( ! hit.shape.isNull() )
{
/* compute the Phong lighting for each hit */
refptr<Material> material = hit.shape->getMaterial();
/* check for backfaces */
bool frontface = ray.getDirection() % hit.normal < 0.0;
if (frontface)
{
color = computePhong(material,
ray,
hit.position,
hit.normal);
if (depth > 0 && factor > SCENE_FACTOR_THRESHOLD)
{
double reflectance = material->getReflectance();
if (factor * reflectance > SCENE_FACTOR_THRESHOLD)
{
color *= (1.0 - reflectance);
Vector reflected_direction =
ray.getDirection().reflect(hit.normal);
Ray newRay(hit.position, reflected_direction);
Vector jitter_surface_point = newRay[0.0001];
Ray jitterNewRay(jitter_surface_point, reflected_direction);
Color c = traceRayRecurse(jitterNewRay,
depth - 1,
factor * reflectance,
material);
color += c * reflectance;
}
double transparency = material->getTransparency();
if (factor * transparency > SCENE_FACTOR_THRESHOLD)
{
color *= (1.0 - transparency);
Vector jitter_surface_point = hit.position
+ ray.getDirection() * 0.0001;
Vector refracted_direction =
ray.getDirection().refract(hit.normal,
last_material->getRefraction(),
material->getRefraction());
Ray newRay(jitter_surface_point, refracted_direction);
Color c = traceRayRecurse(newRay,
depth - 1,
factor * transparency,
material);
color += c * transparency;
}
}
}
else
{
material = air;
Vector jitter_surface_point = hit.position
+ ray.getDirection() * 0.0001;
Vector refracted_direction =
ray.getDirection().refract(-hit.normal,
last_material->getRefraction(),
material->getRefraction());
Ray newRay(jitter_surface_point, refracted_direction);
color = traceRayRecurse(newRay, depth, factor, material);
}
}
return color;
}
Shape::Intersection Scene::getRayClosestHit(const Ray & ray)
{
Shape::Intersection hit;
double min_dist = 0.0;
bool foundOne = false;
/* loop through all shapes in the scene */
for (vector< refptr<Shape> >::iterator it = m_shapes.begin();
it != m_shapes.end();
it++)
{
Shape::IntersectionList intersections = (*it)->intersect(*it, ray);
for (int i = 0, num_results = intersections.size();
i < num_results;
i++)
{
refptr<Shape> shape = intersections[i].shape;
const Vector & isect_point = intersections[i].position;
double intersect_dist = ray.getOrigin().dist_to(isect_point);
if (foundOne == false || intersect_dist < min_dist)
{
hit = intersections[i];
min_dist = intersect_dist;
foundOne = true;
}
}
}
return hit;
}
Color Scene::computePhong(const refptr<Material> material,
const Ray & viewRay,
const Vector & surfacePoint,
const Vector & surfaceNormal)
{
Color result = m_ambient_light * material->getAmbientColor();
if (m_ambient_occlusion_level > 0)
{
result *= calculateAmbientOcclusion(
Ray(surfacePoint, surfaceNormal).shift(1e-7));
}
Vector viewDirection = -viewRay.getDirection();
double shininess = material->getShininess();
const Color & diffuseColor = material->getDiffuseColor();
const Color & specularColor = material->getSpecularColor();
for (std::vector< refptr<Light> >::const_iterator it = m_lights.begin();
it != m_lights.end();
it++)
{
Vector lightC = (*it)->getPosition();
double lightRadius = (*it)->getRadius();
Vector directionToLightC = lightC - surfacePoint;
Vector lightPlaneX = directionToLightC.getPerpendicular().normalize();
Vector lightPlaneY = (directionToLightC * lightPlaneX).normalize();
int jitter_samples = 0, jitter_level = (*it)->getJitter();;
Color jitterResult;
for (int jitter_index = 0; jitter_index < jitter_level; jitter_index++)
{
double jitterRadius = jitter_index * lightRadius
/ (jitter_level - 0.5);
for (int i = 0, num = (int) (M_PI * jitter_index) + 1; i < num; i++)
{
jitter_samples++;
double jitter_angle = i * 2.0 * M_PI / num;
Vector jitterPosition = lightC
+ lightPlaneX * jitterRadius * cos(jitter_angle)
+ lightPlaneY * jitterRadius * sin(jitter_angle);
Vector directionToLight = jitterPosition - surfacePoint;
directionToLight.normalize();
Vector reflectedLightDirection =
(-directionToLight).reflect(surfaceNormal);
Ray surfaceToLight(surfacePoint, directionToLight);
Color light_contribution =
calculateLightContribution(surfaceToLight.shift(0.0001),
jitterPosition);
if ( light_contribution.r > 0.0
|| light_contribution.g > 0.0
|| light_contribution.b > 0.0 )
{
/* calculate the diffuse term */
double diffuse_coef = directionToLight % surfaceNormal;
if (diffuse_coef > 0.0)
{
jitterResult += diffuseColor
* (*it)->getDiffuseColor()
* diffuse_coef
* light_contribution;
}
/* calculate the specular term */
double specular_coef = reflectedLightDirection % viewDirection;
if (specular_coef > 0.0)
{
jitterResult += specularColor
* (*it)->getSpecularColor()
* pow(specular_coef, shininess)
* light_contribution;
}
}
}
}
jitterResult /= jitter_samples;
result += jitterResult;
}
return result;
}
Color Scene::calculateLightContribution(const Ray & toLight,
const Vector & lightPosition)
{
Color contrib(1.0, 1.0, 1.0);
double dist_to_light = (lightPosition - toLight.getOrigin()).mag();
double dist_so_far = 0.0;
Ray currentRay = toLight;
for (;;)
{
Shape::Intersection hit = getRayClosestHit(currentRay);
if ( hit.shape.isNull() )
break;
double offset = currentRay.getOrigin().dist_to(hit.position) + 0.0001;
if ( dist_so_far + offset > dist_to_light )
break;
contrib *= hit.shape->getMaterial()->getTransparency();
contrib *= hit.shape->getMaterial()->getDiffuseColor();
if ( contrib.r < SCENE_FACTOR_THRESHOLD
&& contrib.g < SCENE_FACTOR_THRESHOLD
&& contrib.b < SCENE_FACTOR_THRESHOLD )
break;
dist_so_far += offset;
currentRay = currentRay.shift(offset);
}
return contrib;
}
Color Scene::calculateAmbientOcclusion(const Ray & surfaceNormal)
{
Color result(1, 1, 1);
const int nISteps = m_ambient_occlusion_level * 6;
const int nJSteps = nISteps / 2;
int nRays = 0;
Vector perpX = surfaceNormal.getDirection().getPerpendicular().normalize();
Vector perpY = (surfaceNormal.getDirection() * perpX).normalize();
double istep = 2.0 * M_PI / nISteps;
double jstep = M_PI_2 / nJSteps;
for (int i = 0; i < nISteps; i++)
{
int lim = i > 0 ? nJSteps : 1;
for (int j = 0; j < lim; j++)
{
Vector direction = cos(i * istep) * sin(j * jstep) * perpX
+ sin(i * istep) * sin(j * jstep) * perpY
+ cos(j * jstep) * surfaceNormal.getDirection();
Ray thisRay(surfaceNormal.getOrigin(), direction);
double dist = 0.0;
Color contrib(1, 1, 1);
while (contrib.r > 0.2 && contrib.g > 0.2 && contrib.b > 0.2)
{
Shape::Intersection hit = getRayClosestHit(thisRay);
if (hit.shape.isNull())
break;
double hitDist = (hit.position - thisRay.getOrigin()).mag();
dist += hitDist;
if (dist > MAX_AMBIENT_OCCLUSION_DISTANCE)
break;
contrib *= hit.shape->getMaterial()->getTransparency()
* hit.shape->getMaterial()->getDiffuseColor();
thisRay = thisRay.shift(hitDist + 1E-7);
}
result += contrib;
nRays++;
}
}
result /= nRays;
return result;
}

View File

@ -1,109 +0,0 @@
#ifndef SCENE_H
#define SCENE_H SCENE_H
#include <string>
#include <map>
#include <vector>
#include <utility>
#include <stack>
#include "util/refptr.h"
#include "util/Ray.h"
#include "util/Color.h"
#include "util/Material.h"
#include "util/Polygon.h"
#include "shapes/shapes.h"
#include "parser/parser.h"
#include "parser/nodes.h"
#include "Light.h"
#define SCENE_FACTOR_THRESHOLD 0.02
class Scene
{
public:
Scene(const std::map<std::string, const char *> & options,
const char * filename);
~Scene();
void setWidth(int width) { m_width = width; }
void setHeight(int height) { m_height = height; }
void setMultisampleLevel(int level) { m_multisample_level = level; }
void setVFOV(double vfov) { m_vfov = vfov; }
void setAmbientLight(const Color & al) { m_ambient_light = al; }
void renderPixel(int x, int y, unsigned char * pixel);
void setMaxDepth(int d) { m_max_depth = d; }
int getWidth() { return m_width; }
int getHeight() { return m_height; }
int getMultisampleLevel() { return m_multisample_level; }
int getAmbientOcclusionLevel() { return m_ambient_occlusion_level; }
double getVFOV() { return m_vfov; }
int getMaxDepth() { return m_max_depth; }
protected:
/* private methods */
Color traceRay(const Ray & ray);
Color traceRayRecurse(const Ray & ray, int depth, double factor,
refptr<Material> last_material);
Shape::Intersection getRayClosestHit(const Ray & ray);
Color computePhong(const refptr<Material> material,
const Ray & viewRay,
const Vector & surfacePoint,
const Vector & surfaceNormal);
Color calculateLightContribution(const Ray & toLight,
const Vector & lightPosition);
Color calculateAmbientOcclusion(const Ray & surfaceNormal);
/* In Scene-load.cc */
void load(const char * filename);
void processScene(refptr<Node> node);
refptr<Material> processMaterial(refptr<Node> node);
ShapeRef processBox(refptr<Node> node);
ShapeRef processCyl(refptr<Node> node);
refptr<Light> processLight(refptr<Node> node);
ShapeRef processPlane(refptr<Node> node);
ShapeRef processSphere(refptr<Node> node);
ShapeRef processShape(refptr<Node> node);
ShapeRef processBool(refptr<Node> node);
ShapeRef processExtrude(refptr<Node> node);
ShapeRef processShapeRef(refptr<Node> node);
refptr<Polygon> processPolygon(refptr<Node> node);
refptr<Polygon> processNGon(refptr<Node> node);
bool processTransforms(refptr<Node> node);
void processCamera(refptr<Node> node);
void processOptions(refptr<Node> node);
std::vector<ShapeRef> processTransformBlock(refptr<Node> node);
std::vector<ShapeRef> processGeneralItems(refptr<Node> node);
std::vector<ShapeRef> processForNode(refptr<Node> node);
void processMaterialDefinition(refptr<Node> node);
void processShapeDefinition(refptr<Node> node);
Texture * loadTexture(const std::string & filename);
/* rendering parameters */
int m_width;
int m_height;
int m_multisample_level;
double m_vfov;
Color m_ambient_light;
int m_max_depth;
double m_exposure;
int m_ambient_occlusion_level;
/* private data */
std::vector<ShapeRef> m_shapes;
std::map<std::string, ShapeRef> m_shape_definitions;
std::vector< refptr<Light> > m_lights;
std::stack<Transform> m_transforms;
double m_view_plane_dist;
int m_multisample_level_squared;
double m_sample_span;
double m_half_sample_span;
std::map< std::string, refptr<Material> > m_materials;
std::map< std::string, Texture * > m_textures;
};
#endif

View File

@ -1,434 +0,0 @@
#include <string.h>
#include <unistd.h> /* sysconf() */
#include <stdlib.h> /* rand(), srand() */
#include <time.h> /* time() */
#include <getopt.h>
#include <sys/time.h> /* gettimeofday() */
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <pthread.h>
#include <atomic>
#include "Scene.h"
#include "distrib/distrib.h"
#include "BMP.h"
using namespace std;
/*
* Number of contiguous pixels each worker thread claims at a time. Pulling
* work in small chunks (rather than whole rows) keeps the load balanced even
* when individual rows vary wildly in render cost, while keeping the claimed
* pixels contiguous so cache locality and dispatch overhead stay close to the
* row-based baseline. See benchmarks: 64 was the sweet spot.
*/
#define RENDER_CHUNK_SIZE 64
/*
* State shared by the local multithreaded renderer. Worker threads pull
* fixed-size chunks of pixels off a lock-free atomic cursor until the image
* is complete.
*/
typedef struct
{
Scene * scene;
unsigned char * data;
int width;
int total_pixels;
std::atomic<int> next_pixel; /* dispatch cursor: next unclaimed pixel */
std::atomic<int> pixels_done; /* pixels finished, for progress */
std::atomic<int> last_permille; /* last tenth-of-a-percent printed */
} render_thread_state_t;
static void * render_thread(void * varg)
{
render_thread_state_t * state = (render_thread_state_t *) varg;
const int width = state->width;
const int total_pixels = state->total_pixels;
for (;;)
{
/* atomically claim the next chunk of contiguous pixels */
int start = state->next_pixel.fetch_add(RENDER_CHUNK_SIZE,
std::memory_order_relaxed);
if (start >= total_pixels)
break;
int end = start + RENDER_CHUNK_SIZE;
if (end > total_pixels)
end = total_pixels;
for (int pixel = start; pixel < end; pixel++)
{
int y = pixel / width;
int x = pixel % width;
state->scene->renderPixel(x, y, &state->data[3 * pixel]);
}
/* report progress without locking: of the threads that advance the
* tenth-of-a-percent counter, only the one that wins the update prints,
* so the display stays monotonic and free of interleaved output */
int done = state->pixels_done.fetch_add(end - start,
std::memory_order_relaxed)
+ (end - start);
int permille = (int) (1000L * done / total_pixels);
int prev = state->last_permille.load(std::memory_order_relaxed);
while (permille > prev)
{
if (state->last_permille.compare_exchange_weak(
prev, permille, std::memory_order_relaxed))
{
printf("\e[8D%2.1f%%", permille / 10.0);
fflush(stdout);
break;
}
/* prev reloaded by compare_exchange_weak; re-test permille > prev */
}
}
return NULL;
}
static void renderThreaded(Scene & scene,
unsigned char * data,
int width,
int height,
int num_threads)
{
/* a non-positive override means auto-detect the available cores */
if (num_threads < 1)
{
num_threads = sysconf(_SC_NPROCESSORS_ONLN);
if (num_threads < 1)
num_threads = 1;
}
render_thread_state_t state;
state.scene = &scene;
state.data = data;
state.width = width;
state.total_pixels = width * height;
state.next_pixel.store(0, std::memory_order_relaxed);
state.pixels_done.store(0, std::memory_order_relaxed);
state.last_permille.store(0, std::memory_order_relaxed);
vector<pthread_t> threads(num_threads);
for (int i = 0; i < num_threads; i++)
pthread_create(&threads[i], NULL, render_thread, &state);
for (int i = 0; i < num_threads; i++)
pthread_join(threads[i], NULL);
printf("\e[8D");
}
void usage(const char * progname)
{
cout << "Usage: " << progname << " [options] <scene-file>" << endl;
cout << " Options:" << endl;
cout << " -o|--output-file <output-file-name>" << endl;
cout << " -w|--width <image-width>" << endl;
cout << " -h|--height <image-height>" << endl;
cout << " -m|--multisample <level>" << endl;
cout << " -f|--field-of-view <vertical-fov>" << endl;
cout << " -d|--max-depth <max-recursion-depth>" << endl;
cout << " -a|--ambient-occlusion <ambient-occlusion-level>" << endl;
cout << " -p|--preview (means -w400 -h300 -m1 -d8 -a0)" << endl;
cout << " -j|--threads <num-threads> (default: number of cores)" << endl;
cout << " --hosts <hosts-file>" << endl;
exit(42);
}
void startChildren(const string & servername,
int serverport,
const vector<string> options)
{
char server_port_str[15];
sprintf(server_port_str, "%d", serverport);
vector<string> args;
args.push_back("fart");
args.push_back("--child");
args.push_back("--host");
args.push_back(servername);
args.push_back("--port");
args.push_back(server_port_str);
for (int i = 0, sz = options.size(); i < sz; i++)
args.push_back(options[i]);
const char * char_star_args[args.size() + 1];
for (int i = 0, sz = args.size(); i < sz; i++)
char_star_args[i] = args[i].c_str();
char_star_args[args.size()] = (char *) NULL;
int num_children = sysconf(_SC_NPROCESSORS_CONF);
num_children--;
#if 0
/* debug */
cout << "executing: 'fart', ";
for (int i = 0, sz = args.size(); i < sz; i++)
cout << "'" << char_star_args[i] << "', ";
cout << endl;
#endif
for (int i = 0; i < num_children; i++)
{
int id = fork();
if (id == 0)
{
/* child process */
execvp("fart", (char * const *) char_star_args);
}
}
}
int main(int argc, char * argv[])
{
int opt;
int option_index;
map<string, const char *> scene_options;
vector<string> client_options;
bool server = true;
bool distributed = false;
const char * hosts_file = NULL;
const char * server_name = NULL;
int server_port = 0;
unsigned char * data = NULL;
const char * output_file_name = "fart.bmp";
bool child = false;
int num_threads = 0; /* 0 means auto-detect available cores */
static const struct option long_options[] = {
{ "ambient-occlusion", required_argument, NULL, 'a' },
{ "output-file", required_argument, NULL, 'o' },
{ "width", required_argument, NULL, 'w' },
{ "height", required_argument, NULL, 'h' },
{ "multisample", required_argument, NULL, 'm' },
{ "field-of-view", required_argument, NULL, 'f' },
{ "max-depth", required_argument, NULL, 'd' },
{ "preview", no_argument, NULL, 'p' },
{ "threads", required_argument, NULL, 'j' },
{ "help", no_argument, NULL, 256 },
{ "host", required_argument, NULL, 257 },
{ "port", required_argument, NULL, 258 },
{ "hosts", required_argument, NULL, 259 },
{ "child", no_argument, NULL, 260 },
{ NULL, 0, NULL, 0 }
};
while ((opt = getopt_long(argc, argv, "a:o:w:h:m:f:d:pj:",
long_options, &option_index)) != -1)
{
switch (opt)
{
case 'a':
scene_options["ambient-occlusion"] = optarg;
client_options.push_back("--ambient-occlusion");
client_options.push_back(optarg);
break;
case 'o':
output_file_name = optarg;
break;
case 'w':
scene_options["width"] = optarg;
client_options.push_back("--width");
client_options.push_back(optarg);
break;
case 'h':
scene_options["height"] = optarg;
client_options.push_back("--height");
client_options.push_back(optarg);
break;
case 'm':
scene_options["multisample"] = optarg;
client_options.push_back("--multisample");
client_options.push_back(optarg);
break;
case 'f':
scene_options["field-of-view"] = optarg;
client_options.push_back("--field-of-view");
client_options.push_back(optarg);
break;
case 'd':
scene_options["max-depth"] = optarg;
client_options.push_back("--max-depth");
client_options.push_back(optarg);
break;
case 'p':
scene_options["ambient-occlusion"] = "0";
scene_options["width"] = "400";
scene_options["height"] = "300";
scene_options["multisample"] = "1";
scene_options["max-depth"] = "8";
client_options.push_back("--preview");
break;
case 'j':
num_threads = atoi(optarg);
break;
case 256:
usage(argv[0]);
break;
case 257:
server_name = optarg;
server = false;
distributed = true;
break;
case 258:
server_port = atoi(optarg);
distributed = true;
break;
case 259:
hosts_file = optarg;
distributed = true;
break;
case 260:
child = true;
break;
default:
usage(argv[0]);
break;
}
}
if (optind >= argc)
{
usage(argv[0]);
}
srand(time(NULL));
const char * filename = argv[optind];
client_options.push_back(filename);
Scene scene(scene_options, filename);
const int width = scene.getWidth();
const int height = scene.getHeight();
if (server)
{
/* allocate data for the image */
data = new unsigned char[3 * width * height];
cout << " *** Beginning scene render ***" << endl;
cout << "Parameters:" << endl;
cout << "----------------------------------------" << endl;
cout << " Width: " << width << endl;
cout << " Height: " << height << endl;
cout << " Multisample Level: " << scene.getMultisampleLevel() << endl;
cout << " Ambient Occlusion Level: " << scene.getAmbientOcclusionLevel() << endl;
cout << " Vertical Field of View: " << scene.getVFOV() << endl;
cout << " Max Depth: " << scene.getMaxDepth() << endl;
cout << "----------------------------------------" << endl;
}
distrib the_distrib;
struct timeval before, after;
gettimeofday(&before, NULL); /* start timing */
if (distributed)
{
/* start the distribution infrastructure */
if (server)
{
if (strcmp(hosts_file, ""))
the_distrib.readHostFile(hosts_file);
int num_tasks = (width * height + (UNIT_TASK_SIZE - 1))
/ UNIT_TASK_SIZE;
the_distrib.set_num_tasks(num_tasks);
the_distrib.set_data(data, 3 * width * height);
the_distrib.startServer();
the_distrib.startClients(client_options);
/* wait until all tasks are complete */
the_distrib.waitAllTasks();
}
else
{
if (!child)
{
startChildren(server_name, server_port, client_options);
}
the_distrib.startClient(server_name, server_port);
unsigned char data[3 * UNIT_TASK_SIZE];
for (;;)
{
int task_id = the_distrib.getTask();
if (task_id < 0)
break;
int pixel = task_id * UNIT_TASK_SIZE;
int i = pixel / width;
int j = pixel % width;
for (int t = 0; t < UNIT_TASK_SIZE; t++)
{
scene.renderPixel(j, i, &data[3 * t]);
j++;
if (j >= width)
{
j = 0;
i++;
if (i >= height)
break;
}
}
int ret = the_distrib.send_data(task_id,
&data[0],
3 * UNIT_TASK_SIZE);
if (ret != 0)
break;
}
}
}
else
{
/* local multithreaded render; num_threads of 0 auto-detects cores */
renderThreaded(scene, data, width, height, num_threads);
}
gettimeofday(&after, NULL); /* stop timing */
if (server)
{
cout << " *** Ending scene render ***" << endl;
cout << "Writing output file '" << output_file_name << '\'' << endl;
/* write the image */
BMP outputImage(output_file_name, width, height, data);
/* print how much time has elapsed */
double time_before = before.tv_sec + before.tv_usec / 1000000.0;
double time_after = after.tv_sec + after.tv_usec / 1000000.0;
double total_seconds = time_after - time_before;
cout << "Render time: " << total_seconds << " seconds";
double seconds = total_seconds;
int days = (int) (seconds / (60.0 * 60.0 * 24.0));
seconds -= days * 60.0 * 60.0 * 24.0;
int hours = (int) (seconds / (60.0 * 60.0));
seconds -= hours * 60.0 * 60.0;
int minutes = (int) (seconds / 60.0);
seconds -= minutes * 60.0;
if (days || hours || minutes)
{
cout << " (";
if (days)
cout << days << (days == 1 ? " day, " : " days, ");
if (days || hours)
cout << hours << (hours == 1 ? " hour, " : " hours, ");
cout << minutes << (minutes == 1 ? " minute, " : " minutes, ");
cout << seconds << (seconds == 1 ? " second)" : " seconds)");
}
cout << endl;
}
exit(0);
return 0;
}

View File

@ -1,283 +0,0 @@
#include <stdlib.h>
#include <math.h>
#include <vector>
#include <iostream>
#include <typeinfo>
#include <map>
#include "nodes.h"
using namespace std;
typedef NodeRef (*Function)(NodeRef args);
NodeRef CosFunction(NodeRef args);
NodeRef SinFunction(NodeRef args);
NodeRef SqrtFunction(NodeRef args);
NodeRef AbsFunction(NodeRef args);
static const struct {
const char * fn_name;
Function fn;
} functions[] = {
{"cos", CosFunction},
{"sin", SinFunction},
{"sqrt", SqrtFunction},
{"abs", AbsFunction}
};
class FunctionMap : public map<string, Function>
{
public:
FunctionMap()
{
for (unsigned int i = 0;
i < sizeof(functions)/sizeof(functions[0]);
i++)
{
(*this)[functions[i].fn_name] = functions[i].fn;
}
}
bool contains(const string & key)
{
return find(key) != end();
}
};
static FunctionMap function_map;
void Node::evaluateChildren(refptr<Node> parent)
{
/* recursively evaluate all children nodes */
for (std::vector< refptr<Node> >::iterator it = m_children.begin();
it != m_children.end();
it++)
{
refptr<Node> evaluated = (*it)->evaluate();
if ( ! evaluated.isNull() )
{
if (typeid(*evaluated) == typeid(EvaluatePropagateNode))
{
for (vector<NodeRef>::iterator it2
= evaluated->getChildren().begin();
it2 != evaluated->getChildren().end();
it2++)
{
parent->addChild(*it2);
}
}
else
{
(*it)->evaluateChildren(evaluated);
parent->addChild(evaluated);
}
}
}
}
void Node::addChildren(NodeRef other)
{
if (other.isNull())
return;
for (vector<NodeRef>::const_iterator it = other->m_children.begin();
it != other->m_children.end();
it++)
{
addChild(*it);
}
}
Node::~Node()
{
}
NodeRef BinOpNode::evaluate()
{
double o = one->evaluate()->getNumber();
double t = two->evaluate()->getNumber();
double r = 0.0;
switch (m_op)
{
case '*':
r = o * t;
break;
case '/':
r = o / t;
break;
case '+':
r = o + t;
break;
case '-':
r = o - t;
break;
case '%':
r = (int) o % (int) t;
break;
case '^':
r = pow(o, t);
break;
default:
cerr << "Error: BinOpNode created with op '" << m_op << "'" << endl;
exit(-3);
}
return new NumberNode(r);
}
NodeRef BoolExpressionNode::evaluate()
{
double o = 0, t = 0;
double r = 0;
if (m_op != '!' && m_op != '&' && m_op != '|')
{
o = one->evaluate()->getNumber();
t = two->evaluate()->getNumber();
}
switch (m_op)
{
case '<':
r = o < t ? 1 : 0;
break;
case 'l':
r = o <= t ? 1 : 0;
break;
case '>':
r = o > t ? 1 : 0;
break;
case 'g':
r = o >= t ? 1 : 0;
break;
case '=':
r = o == t ? 1 : 0;
break;
case 'n':
r = o != t ? 1 : 0;
break;
case '&':
r = one->evaluate()->getInteger();
if (r != 0)
{
r = two->evaluate()->getInteger();
}
break;
case '|':
r = one->evaluate()->getInteger();
if (r == 0)
{
r = two->evaluate()->getInteger();
}
break;
case '!':
r = ! one->evaluate()->getInteger();
break;
case 'T':
r = 1;
break;
}
return new NumberNode(r);
}
NodeRef ForNode::evaluate()
{
NodeRef eval = new EvaluatePropagateNode();
if (!m_nodes[0].isNull())
{
m_nodes[0]->evaluate();
}
while (m_nodes[1]->evaluate()->getInteger() != 0)
{
evaluateChildren(eval);
if (!m_nodes[2].isNull())
{
m_nodes[2]->evaluate();
}
}
return eval;
}
NodeRef IfNode::evaluate()
{
NodeRef eval = new EvaluatePropagateNode();
int if_val = m_test_expr->evaluate()->getInteger();
if (if_val != 0)
{
evaluateChildren(eval);
}
else if ( ! m_elses.isNull() )
{
return m_elses->evaluate();
}
return eval;
}
NodeRef ElseNode::evaluate()
{
NodeRef eval = new EvaluatePropagateNode();
evaluateChildren(eval);
return eval;
}
NodeRef FunctionCallNode::evaluate()
{
if (function_map.contains(m_name->getString()))
{
return function_map[m_name->getString()](m_parameters);
}
cerr << "Error: no function \"" << m_name->getString() << "\" defined!"
<< endl;
exit(4);
}
/**************************************************************************
* Scene file functions *
*************************************************************************/
NodeRef CosFunction(NodeRef args)
{
if (args->getChildren().size() != 1)
{
cerr << "Error: cos function requires 1 argument" << endl;
exit(4);
}
return new NumberNode(cos(args->getChildren()[0]->evaluate()->getNumber()));
}
NodeRef SinFunction(NodeRef args)
{
if (args->getChildren().size() != 1)
{
cerr << "Error: sin function requires 1 argument" << endl;
exit(4);
}
return new NumberNode(sin(args->getChildren()[0]->evaluate()->getNumber()));
}
NodeRef SqrtFunction(NodeRef args)
{
if (args->getChildren().size() != 1)
{
cerr << "Error: sqrt function requires 1 argument" << endl;
exit(4);
}
return new NumberNode(sqrt(args->getChildren()[0]->evaluate()->getNumber()));
}
NodeRef AbsFunction(NodeRef args)
{
if (args->getChildren().size() != 1)
{
cerr << "Error: abs function requires 1 argument" << endl;
exit(4);
}
return new NumberNode(fabs(args->getChildren()[0]->evaluate()->getNumber()));
}

View File

@ -1,791 +0,0 @@
#ifndef NODES_H
#define NODES_H NODES_H
#include <stdlib.h> /* exit() */
#include <vector>
#include <string>
#include <iostream>
#include "util/refptr.h"
#include "util/Vector.h"
#include "util/Scope.h"
extern refptr<Scope> parser_scope;
class Node
{
public:
virtual ~Node();
void addChild(refptr<Node> child) { m_children.push_back(child); }
void addChildren(refptr<Node> other);
std::vector< refptr<Node> > & getChildren() { return m_children; }
virtual int getInteger() { return getNumber(); }
virtual double getNumber()
{
std::cerr << "Warning: Node::getNumber() called!" << std::endl;
return 0.0;
}
virtual refptr<Vector> getVector()
{
std::cerr << "Warning: Node::getVector() called!" << std::endl;
return refptr<Vector>(NULL);
}
virtual std::string getString()
{
std::cerr << "Warning: Node::getString() called!" << std::endl;
return "";
}
virtual refptr<Node> evaluate()
{
std::cerr << "Warning: Node::evaluate() called!" << std::endl;
return NULL;
}
virtual void evaluateChildren(refptr<Node> parent);
virtual bool isShape() { return false; }
virtual bool isMaterial() { return false; }
virtual bool isTransformBlock() { return false; }
virtual bool isExpression() { return false; }
protected:
std::vector< refptr<Node> > m_children;
};
typedef refptr<Node> NodeRef;
class NumberNode : public Node
{
public:
NumberNode(double number)
: m_number(number), m_direct(true)
{
}
NumberNode(NodeRef expr)
: m_direct(false)
{
m_expr = expr;
}
virtual double getNumber()
{
return m_direct ? m_number : m_expr->getNumber();
}
virtual refptr<Node> evaluate()
{
return m_direct
? new NumberNode(m_number)
: new NumberNode(m_expr->evaluate());
}
protected:
double m_number;
bool m_direct;
NodeRef m_expr;
};
class VectorNode : public Node
{
public:
VectorNode(NodeRef a, NodeRef b, NodeRef c)
: m_a(a), m_b(b), m_c(c), m_direct(true)
{
}
VectorNode(NodeRef node)
: m_vector(node), m_direct(false)
{
}
refptr<Vector> getVector()
{
return m_direct
? new Vector(m_a->getNumber(),
m_b->getNumber(),
m_c->getNumber())
: m_vector->getVector();
}
virtual NodeRef evaluate()
{
return m_direct
? new VectorNode(m_a->evaluate(),
m_b->evaluate(),
m_c->evaluate())
: m_vector->evaluate();
}
protected:
NodeRef m_a, m_b, m_c, m_vector;
bool m_direct;
};
class AmbientNode : public VectorNode
{
public:
AmbientNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new AmbientNode(m_vector->evaluate());
}
};
class AmbientOcclusionNode : public NumberNode
{
public:
AmbientOcclusionNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new AmbientOcclusionNode(m_expr->evaluate());
}
};
class BoxNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate()
{
return new BoxNode();
}
};
class CameraNode : public Node
{
public:
virtual NodeRef evaluate()
{
return new CameraNode();
}
};
class ColorNode : public VectorNode
{
public:
ColorNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new ColorNode(m_vector->evaluate());
}
};
class CylNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate()
{
return new CylNode();
}
};
class DiffuseNode : public VectorNode
{
public:
DiffuseNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new DiffuseNode(m_vector->evaluate());
}
};
class ExposureNode : public NumberNode
{
public:
ExposureNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new ExposureNode(m_expr->evaluate());
}
};
class ExtrudeNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate()
{
return new ExtrudeNode();
}
};
class HeightNode : public NumberNode
{
public:
HeightNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new HeightNode(m_expr->evaluate());
}
};
class IdentifierNode : public Node
{
public:
IdentifierNode(const std::string & str) { m_string = str; }
std::string getString() { return m_string; }
virtual NodeRef evaluate()
{
return new IdentifierNode(m_string);
}
protected:
std::string m_string;
};
class IntersectNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate()
{
return new IntersectNode();
}
};
class ItemsNode : public Node
{
public:
virtual NodeRef evaluate()
{
return new ItemsNode();
}
};
class JitterNode : public NumberNode
{
public:
JitterNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new JitterNode(m_expr->evaluate());
}
};
class LightNode : public Node
{
public:
virtual NodeRef evaluate() { return new LightNode(); }
};
class LookAtNode : public VectorNode
{
public:
LookAtNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new LookAtNode(m_vector->evaluate());
}
};
class MaterialNode : public Node
{
public:
bool isMaterial() { return true; }
virtual NodeRef evaluate() { return new MaterialNode(); }
};
class MaterialDefinitionNode : public IdentifierNode
{
public:
MaterialDefinitionNode(const std::string & str) : IdentifierNode(str) {}
virtual NodeRef evaluate()
{
return new MaterialDefinitionNode(m_string);
}
};
class MaterialRefNode : public IdentifierNode
{
public:
MaterialRefNode(const std::string & str) : IdentifierNode(str) {}
bool isMaterial() { return true; }
virtual NodeRef evaluate() { return new MaterialRefNode(m_string); }
};
class MaxDepthNode : public NumberNode
{
public:
MaxDepthNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new MaxDepthNode(m_expr->evaluate());
}
};
class MultisampleNode : public NumberNode
{
public:
MultisampleNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new MultisampleNode(m_expr->evaluate());
}
};
class NGonNode : public NumberNode
{
public:
NGonNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new NGonNode(m_expr->evaluate());
}
};
class OffsetNode : public NumberNode
{
public:
OffsetNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new OffsetNode(m_expr->evaluate());
}
};
class OptionsNode : public Node
{
public:
virtual NodeRef evaluate() { return new OptionsNode(); }
};
class PlaneNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate() { return new PlaneNode(); }
};
class PlanePositionNode : public VectorNode
{
public:
PlanePositionNode(NodeRef vec_node, NodeRef dist)
: VectorNode(vec_node)
{
m_dist = dist;
}
double getNumber() { return m_dist->getNumber(); }
virtual NodeRef evaluate()
{
return new PlanePositionNode(m_vector->evaluate(),
m_dist->evaluate());
}
protected:
NodeRef m_dist;
};
class PolygonNode : public Node
{
public:
virtual NodeRef evaluate() { return new PolygonNode(); }
};
class PositionNode : public VectorNode
{
public:
PositionNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new PositionNode(m_vector->evaluate());
}
};
class RadiusNode : public NumberNode
{
public:
RadiusNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new RadiusNode(m_expr->evaluate());
}
};
class ReflectanceNode : public NumberNode
{
public:
ReflectanceNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new ReflectanceNode(m_expr->evaluate());
}
};
class RefractionNode : public NumberNode
{
public:
RefractionNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new RefractionNode(m_expr->evaluate());
}
};
class RotateNode : public VectorNode
{
public:
RotateNode(NodeRef angle, NodeRef vec_node)
: VectorNode(vec_node)
{
m_angle = angle;
}
double getNumber() { return m_angle->getNumber(); }
virtual NodeRef evaluate()
{
return new RotateNode(m_angle->evaluate(), m_vector->evaluate());
}
protected:
NodeRef m_angle;
};
class RotateBlockNode : public RotateNode
{
public:
RotateBlockNode(NodeRef angle, NodeRef vec_node)
: RotateNode(angle, vec_node) {}
bool isTransformBlock() { return true; }
virtual NodeRef evaluate()
{
return new RotateBlockNode(m_angle->evaluate(), m_vector->evaluate());
}
};
class ScaleNode : public VectorNode
{
public:
ScaleNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new ScaleNode(m_vector->evaluate());
}
};
class ScaleBlockNode : public ScaleNode
{
public:
ScaleBlockNode(NodeRef vector) : ScaleNode(vector) {}
bool isTransformBlock() { return true; }
virtual NodeRef evaluate()
{
return new ScaleBlockNode(m_vector->evaluate());
}
};
class ScaleScalarNode : public Node
{
public:
ScaleScalarNode(NodeRef expr)
: m_expr(expr)
{
}
virtual NodeRef evaluate()
{
NodeRef n = m_expr->evaluate();
return new VectorNode(n, n, n);
}
protected:
NodeRef m_expr;
};
class SceneNode : public Node
{
public:
virtual NodeRef evaluate() { return new SceneNode(); }
};
class ShapeDefinitionNode : public IdentifierNode
{
public:
ShapeDefinitionNode(const std::string & str) : IdentifierNode(str) {}
virtual NodeRef evaluate() { return new ShapeDefinitionNode(m_string); }
};
class ShapeRefNode : public IdentifierNode
{
public:
ShapeRefNode(const std::string & str) : IdentifierNode(str) {}
bool isShape() { return true; }
virtual NodeRef evaluate() { return new ShapeRefNode(m_string); }
};
class ShininessNode : public NumberNode
{
public:
ShininessNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new ShininessNode(m_expr->evaluate());
}
};
class SizeNode : public VectorNode
{
public:
SizeNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new SizeNode(m_vector->evaluate());
}
};
class SpecularNode : public VectorNode
{
public:
SpecularNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new SpecularNode(m_vector->evaluate());
}
};
class SphereNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate() { return new SphereNode(); }
};
class SubtractNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate() { return new SubtractNode(); }
};
class TextureNode : public IdentifierNode
{
public:
TextureNode(const std::string & str) : IdentifierNode(str) {}
virtual NodeRef evaluate() { return new TextureNode(m_string); }
};
class TranslateNode : public VectorNode
{
public:
TranslateNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new TranslateNode(m_vector->evaluate());
}
};
class TranslateBlockNode : public TranslateNode
{
public:
TranslateBlockNode(NodeRef vector) : TranslateNode(vector) {}
bool isTransformBlock() { return true; }
virtual NodeRef evaluate()
{
return new TranslateBlockNode(m_vector->evaluate());
}
};
class TransparencyNode : public NumberNode
{
public:
TransparencyNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new TransparencyNode(m_expr->evaluate());
}
};
class UnionNode : public Node
{
public:
bool isShape() { return true; }
virtual NodeRef evaluate() { return new UnionNode(); }
};
class UpNode : public VectorNode
{
public:
UpNode(NodeRef vector) : VectorNode(vector) {}
virtual NodeRef evaluate()
{
return new UpNode(m_vector->evaluate());
}
};
class VFOVNode : public NumberNode
{
public:
VFOVNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new VFOVNode(m_expr->evaluate());
}
};
class WidthNode : public NumberNode
{
public:
WidthNode(NodeRef e) : NumberNode(e) {}
virtual NodeRef evaluate()
{
return new WidthNode(m_expr->evaluate());
}
};
/******** scripting nodes ********/
class ExpressionNode : public Node
{
public:
bool isExpression() { return true; }
virtual NodeRef evaluate() = 0;
};
class AssignmentNode : public ExpressionNode
{
public:
AssignmentNode(NodeRef varref, NodeRef expr)
: m_varref(varref), m_expr(expr)
{
}
std::string getString() { return m_varref->getString(); }
virtual NodeRef evaluate()
{
double n = m_expr->evaluate()->getNumber();
parser_scope->putGlobal(getString(), n);
return new NumberNode(n);
}
protected:
NodeRef m_varref;
NodeRef m_expr;
};
class LocalAssignmentNode : public ExpressionNode
{
public:
LocalAssignmentNode(NodeRef varref, NodeRef expr)
: m_varref(varref), m_expr(expr)
{
}
std::string getString() { return m_varref->getString(); }
virtual NodeRef evaluate()
{
double n = m_expr->evaluate()->getNumber();
parser_scope->putLocal(getString(), n);
return new NumberNode(n);
}
protected:
NodeRef m_varref;
NodeRef m_expr;
};
class LocalDeclNode : public ExpressionNode
{
public:
LocalDeclNode(NodeRef varref) : m_varref(varref) { }
virtual NodeRef evaluate()
{
parser_scope->putLocal(m_varref->getString(), 0.0);
return NULL;
}
protected:
NodeRef m_varref;
};
class BinOpNode : public ExpressionNode
{
public:
BinOpNode(char op, NodeRef one, NodeRef two)
: m_op(op), one(one), two(two)
{
}
virtual NodeRef evaluate();
protected:
char m_op;
NodeRef one;
NodeRef two;
};
class BoolExpressionNode : public Node
{
public:
BoolExpressionNode(char op, NodeRef one, NodeRef two)
: m_op(op), one(one), two(two)
{
}
virtual NodeRef evaluate();
protected:
char m_op;
NodeRef one;
NodeRef two;
};
class VarRefNode : public Node
{
public:
VarRefNode(const std::string & str) { m_string = str; }
std::string getString() { return m_string; }
virtual NodeRef evaluate()
{
if (parser_scope->contains(m_string))
{
return new NumberNode(parser_scope->get(m_string));
}
std::cerr << "Error: No identifier '" << m_string << "' in scope"
<< std::endl;
exit(4);
}
protected:
std::string m_string;
};
class ForNode : public Node
{
public:
ForNode(NodeRef e1, NodeRef e2, NodeRef e3)
{
m_nodes[0] = e1;
m_nodes[1] = e2;
m_nodes[2] = e3;
}
virtual NodeRef evaluate();
protected:
NodeRef m_nodes[3];
};
class IfNode : public Node
{
public:
IfNode(NodeRef test_expr, NodeRef elses)
{
m_test_expr = test_expr;
m_elses = elses;
}
virtual NodeRef evaluate();
protected:
NodeRef m_test_expr, m_elses;
};
class ElseNode : public Node
{
public:
virtual NodeRef evaluate();
};
class FunctionCallNode : public Node
{
public:
FunctionCallNode(NodeRef name, NodeRef parameters)
{
m_name = name;
m_parameters = parameters;
}
virtual NodeRef evaluate();
protected:
NodeRef m_name, m_parameters;
};
/* this class is only used to hold a set of items coming out of a class's
* evaluate() from above. the evaluateChildren() top-level method will
* propagate children of this class up to the level of their parent */
class EvaluatePropagateNode : public Node
{
};
#endif

View File

@ -1,13 +0,0 @@
#ifndef PARSER_H
#define PARSER_H PARSER_H
#include "nodes.h"
#include "util/refptr.h"
#include "util/Scope.h"
#define YYSTYPE refptr<Node>
refptr<Node> parse(const char * fileName, refptr<Scope> scope);
#endif

View File

@ -1,157 +0,0 @@
%option nounput
%option noyywrap
%option bison-locations
%{
#include <string>
#include "nodes.h"
#include "parser.h"
#include "parser.hh"
#define YY_USER_ACTION yylloc->first_column += yyleng;
static std::string build_string;
%}
%x str
%%
\+ return PLUS;
- return MINUS;
\* return TIMES;
\/ return DIVIDE;
% return MOD;
\^ return POW;
= return ASSIGN;
== return EQUALS;
!= return NOTEQUALS;
\< return LESS;
\<= return LESSEQ;
\> return GREATER;
\>= return GREATEREQ;
&& return AND;
\|\| return OR;
! return NOT;
; return SEMICOLON;
: return COLON;
\? return QUESTION;
\$ return DOLLAR;
\. return DOT;
, return COMMA;
\{ return LCURLY;
\} return RCURLY;
\[ return LBRACKET;
\] return RBRACKET;
\( return LPAREN;
\) return RPAREN;
[0-9]+ *yylval = new NumberNode(atof(yytext)); return REAL_NUMBER;
[0-9]*\.[0-9]+ *yylval = new NumberNode(atof(yytext)); return REAL_NUMBER;
ambient return AMBIENT;
ambient_occlusion return AMBIENT_OCCLUSION;
box return BOX;
camera return CAMERA;
color return COLOR;
cyl return CYL;
define return DEFINE;
diffuse return DIFFUSE;
exposure return EXPOSURE;
extrude return EXTRUDE;
height return HEIGHT;
intersect return INTERSECT;
jitter return JITTER;
light return LIGHT;
look_at return LOOKAT;
material return MATERIAL;
max_depth return MAXDEPTH;
multisample return MULTISAMPLE;
ngon return NGON;
offset return OFFSET;
options return OPTIONS;
plane return PLANE;
polygon return POLYGON;
position return POSITION;
radius return RADIUS;
reflectance return REFLECTANCE;
refraction return REFRACTION;
rotate return ROTATE;
scale return SCALE;
scene return SCENE;
shape return SHAPE;
shininess return SHININESS;
size return SIZE;
specular return SPECULAR;
sphere return SPHERE;
subtract return SUBTRACT;
texture return TEXTURE;
translate return TRANSLATE;
transparency return TRANSPARENCY;
union return UNION;
up return UP;
vfov return VFOV;
width return WIDTH;
else return ELSE;
elsif return ELSIF;
for return FOR;
if return IF;
while return WHILE;
local return LOCAL;
[a-zA-Z_][a-zA-Z_0-9]* {
*yylval = new IdentifierNode(yytext);
return IDENTIFIER;
}
\$[a-zA-Z_][a-zA-Z_0-9]* {
*yylval = new VarRefNode(yytext+1);
return VARREF;
}
#.*\n {
yylloc->first_line++; yylloc->last_line++;
yylloc->first_column = yylloc->last_column = 0;
}
\n {
yylloc->first_line++; yylloc->last_line++;
yylloc->first_column = yylloc->last_column = 0;
}
[ \t\v] /* ignore whitespace */
/* strings */
\" build_string = ""; BEGIN(str);
<str>{
\" {
/* end of the string literal */
BEGIN(INITIAL);
*yylval = new IdentifierNode(build_string);
return STRING;
}
\\x[0-9A-Fa-f]{2} {
/* hexadecimal escape code */
unsigned int val;
(void) sscanf(yytext + 2, "%x", &val);
build_string += (char) val;
}
\\n build_string += '\n';
\\t build_string += '\t';
\\r build_string += '\r';
\\b build_string += '\b';
\\f build_string += '\f';
\\(.|\n) build_string += yytext[1];
[^\\\"]+ build_string += yytext;
}
. return yytext[0];
%%

View File

@ -1,511 +0,0 @@
%{
#include <stdio.h>
#include <iostream>
#include "util/Vector.h"
#include "util/refptr.h"
#include "util/Scope.h"
#include "nodes.h"
#include "parser.h"
#include "parser.hh" /* bison-generated header with YY[SL]TYPE */
using namespace std;
#define yyerror(msg) errFunc(msg, &yylloc)
int yylex(YYSTYPE *, YYLTYPE *);
extern FILE * yyin;
void errFunc(const char * str, YYLTYPE * yyllocp);
static refptr<Node> parsed_scene_node;
refptr<Scope> parser_scope;
%}
%define api.pure
%locations
%define parse.error verbose
%initial-action {
/* Reference yynerrs so the generated parser does not warn that it is
set but never used; this grammar has no error-recovery rules. */
(void) yynerrs;
}
%token PLUS;
%token MINUS;
%token TIMES;
%token DIVIDE;
%token MOD;
%token POW;
%token ASSIGN;
%token EQUALS;
%token NOTEQUALS;
%token LESS;
%token LESSEQ;
%token GREATER;
%token GREATEREQ;
%token AND
%token OR
%token NOT;
%token SEMICOLON;
%token COLON;
%token QUESTION;
%token DOLLAR;
%token DOT;
%token COMMA;
%token LCURLY;
%token RCURLY;
%token LBRACKET;
%token RBRACKET;
%token LPAREN;
%token RPAREN;
%token REAL_NUMBER;
%token STRING;
%token AMBIENT;
%token AMBIENT_OCCLUSION;
%token BOX;
%token CAMERA;
%token COLOR;
%token CYL;
%token DEFINE;
%token DIFFUSE;
%token EXPOSURE;
%token EXTRUDE;
%token HEIGHT;
%token INTERSECT;
%token JITTER;
%token LIGHT;
%token LOOKAT;
%token MATERIAL;
%token MAXDEPTH;
%token MULTISAMPLE;
%token NGON;
%token OFFSET;
%token OPTIONS;
%token PLANE;
%token POLYGON;
%token POSITION;
%token RADIUS;
%token REFLECTANCE;
%token REFRACTION;
%token ROTATE;
%token SCALE;
%token SCENE;
%token SHAPE;
%token SHININESS;
%token SIZE;
%token SPECULAR;
%token SPHERE;
%token SUBTRACT;
%token TEXTURE;
%token TRANSLATE;
%token TRANSPARENCY;
%token UNION;
%token UP;
%token VFOV;
%token WIDTH;
%token IDENTIFIER;
%token VARREF;
%token ELSE;
%token ELSIF;
%token FOR;
%token IF;
%token WHILE;
%token LOCAL;
%right ASSIGN
%left AND OR NOT
%left PLUS MINUS
%left TIMES DIVIDE MOD
%right POW
%left UMINUS
%%
scene: SCENE LCURLY general_items RCURLY {
$$ = new SceneNode();
$$->addChildren($3);
parsed_scene_node = $$;
}
;
box: BOX LCURLY general_items RCURLY {
$$ = new BoxNode();
$$->addChildren($3);
}
;
camera: CAMERA LCURLY general_items RCURLY {
$$ = new CameraNode();
$$->addChildren($3);
}
;
cyl: CYL LCURLY general_items RCURLY {
$$ = new CylNode();
$$->addChildren($3);
}
;
extrude: EXTRUDE LCURLY general_items RCURLY {
$$ = new ExtrudeNode();
$$->addChildren($3);
}
;
general_items: /* empty */ { $$ = NULL; }
| general_item general_items {
$$ = new ItemsNode();
$$->addChild($1);
$$->addChildren($2);
}
;
general_item: AMBIENT vector3 { $$ = new AmbientNode($2); }
| AMBIENT_OCCLUSION expression {
$$ = new AmbientOcclusionNode($2);
}
| camera { $$ = $1; }
| COLOR vector3 { $$ = new ColorNode($2); }
| DIFFUSE vector3 { $$ = new DiffuseNode($2); }
| EXPOSURE expression { $$ = new ExposureNode($2); }
| for { $$ = $1; }
| HEIGHT expression { $$ = new HeightNode($2); }
| if { $$ = $1; }
| JITTER expression { $$ = new JitterNode($2); }
| light { $$ = $1; }
| LOOKAT vector3 { $$ = new LookAtNode($2); }
| material { $$ = $1; }
| material_definition { $$ = $1; }
| material_ref { $$ = $1; }
| MAXDEPTH expression { $$ = new MaxDepthNode($2); }
| MULTISAMPLE expression { $$ = new MultisampleNode($2); }
| ngon { $$ = $1; }
| offset { $$ = $1; }
| options { $$ = $1; }
| polygon { $$ = $1; }
| POSITION vector3 { $$ = new PositionNode($2); }
| POSITION vector3 COMMA expression {
$$ = new PlanePositionNode($2, $4);
}
| RADIUS expression { $$ = new RadiusNode($2); }
| REFLECTANCE expression { $$ = new ReflectanceNode($2); }
| REFRACTION expression { $$ = new RefractionNode($2); }
| ROTATE expression COMMA vector3 { $$ = new RotateNode($2, $4); }
| SCALE expression { $$ = new ScaleNode(new ScaleScalarNode($2)); }
| SCALE vector2 { $$ = new ScaleNode($2); }
| SCALE vector3 { $$ = new ScaleNode($2); }
| shape { $$ = $1; }
| shape_definition { $$ = $1; }
| SHININESS expression { $$ = new ShininessNode($2); }
| SIZE vector3 { $$ = new SizeNode($2); }
| SPECULAR vector3 { $$ = new SpecularNode($2); }
| stmt_expression { $$ = $1; }
| TEXTURE STRING { $$ = new TextureNode($2->getString()); }
| transform_block { $$ = $1; }
| TRANSLATE vector3 { $$ = new TranslateNode($2); }
| TRANSPARENCY expression { $$ = new TransparencyNode($2); }
| UP vector3 { $$ = new UpNode($2); }
| vector2 { $$ = $1; }
| VFOV expression { $$ = new VFOVNode($2); }
| while { $$ = $1; }
| WIDTH expression { $$ = new WidthNode($2); }
;
intersect: INTERSECT LCURLY general_items RCURLY {
$$ = new IntersectNode();
$$->addChildren($3);
}
;
light: LIGHT LCURLY general_items RCURLY {
$$ = new LightNode();
$$->addChildren($3);
}
;
material: MATERIAL LCURLY general_items RCURLY {
$$ = new MaterialNode();
$$->addChildren($3);
}
;
material_definition: DEFINE MATERIAL IDENTIFIER LCURLY general_items RCURLY {
$$ = new MaterialDefinitionNode($3->getString());
$$->addChildren($5);
}
;
material_ref: MATERIAL IDENTIFIER {
$$ = new MaterialRefNode($2->getString());
}
;
number: REAL_NUMBER { $$ = $1; }
;
ngon: NGON expression COMMA expression {
$$ = new NGonNode($2);
$$->addChild(new RadiusNode($4));
}
;
offset: OFFSET expression {
$$ = new OffsetNode($2);
}
| OFFSET expression LCURLY general_items RCURLY {
$$ = new OffsetNode($2);
$$->addChildren($4);
}
;
options: OPTIONS LCURLY general_items RCURLY {
$$ = new OptionsNode();
$$->addChildren($3);
}
;
plane: PLANE LCURLY general_items RCURLY {
$$ = new PlaneNode();
$$->addChildren($3);
}
;
polygon: POLYGON LCURLY general_items RCURLY {
$$ = new PolygonNode();
$$->addChildren($3);
}
;
shape: plane { $$ = $1; }
| sphere { $$ = $1; }
| box { $$ = $1; }
| cyl { $$ = $1; }
| union { $$ = $1; }
| intersect { $$ = $1; }
| subtract { $$ = $1; }
| extrude { $$ = $1; }
| shape_ref { $$ = $1; }
;
shape_definition: DEFINE SHAPE IDENTIFIER shape {
$$ = new ShapeDefinitionNode($3->getString());
$$->addChild($4);
}
;
shape_ref: SHAPE IDENTIFIER shape_ref_more {
$$ = new ShapeRefNode($2->getString());
$$->addChildren($3);
}
;
shape_ref_more: /* empty */ { $$ = NULL; }
| LCURLY general_items RCURLY { $$ = $2; }
;
sphere: SPHERE LCURLY general_items RCURLY {
$$ = new SphereNode();
$$->addChildren($3);
}
;
subtract: SUBTRACT LCURLY general_items RCURLY {
$$ = new SubtractNode();
$$->addChildren($3);
}
;
transform_block: TRANSLATE vector3 LCURLY general_items RCURLY {
$$ = new TranslateBlockNode($2);
$$->addChildren($4);
}
| ROTATE expression COMMA vector3 LCURLY general_items RCURLY {
$$ = new RotateBlockNode($2, $4);
$$->addChildren($6);
}
| SCALE vector3 LCURLY general_items RCURLY {
$$ = new ScaleBlockNode($2);
$$->addChildren($4);
}
| SCALE expression LCURLY general_items RCURLY {
$$ = new ScaleBlockNode(new ScaleScalarNode($2));
$$->addChildren($4);
}
;
union: UNION LCURLY general_items RCURLY {
$$ = new UnionNode();
$$->addChildren($3);
}
;
vector2: LESS expression COMMA expression GREATER {
$$ = new VectorNode($2, $4, new NumberNode(0.0));
}
;
vector3: LESS expression COMMA expression COMMA expression GREATER {
$$ = new VectorNode($2, $4, $6);
}
;
expression: expression TIMES expression { $$ = new BinOpNode('*', $1, $3); }
| expression DIVIDE expression { $$ = new BinOpNode('/', $1, $3); }
| expression PLUS expression { $$ = new BinOpNode('+', $1, $3); }
| expression MINUS expression { $$ = new BinOpNode('-', $1, $3); }
| expression MOD expression { $$ = new BinOpNode('%', $1, $3); }
| expression POW expression { $$ = new BinOpNode('^', $1, $3); }
| MINUS expression %prec UMINUS {
$$ = new BinOpNode('-', new NumberNode(0.0), $2);
}
| stmt_expression { $$ = $1; }
| function_call { $$ = $1; }
| number { $$ = $1; }
| VARREF { $$ = $1; }
| LPAREN expression RPAREN { $$ = $2; }
;
maybe_expression: /* empty */ { $$ = NULL; }
| expression { $$ = $1; }
;
stmt_expression: assignment { $$ = $1; }
| local_assignment { $$ = $1; }
| local_decl { $$ = $1; }
;
bool_expression: expression LESS expression {
$$ = new BoolExpressionNode('<', $1, $3);
}
| expression LESSEQ expression {
$$ = new BoolExpressionNode('l', $1, $3);
}
| expression GREATER expression {
$$ = new BoolExpressionNode('>', $1, $3);
}
| expression GREATEREQ expression {
$$ = new BoolExpressionNode('g', $1, $3);
}
| expression EQUALS expression {
$$ = new BoolExpressionNode('=', $1, $3);
}
| expression NOTEQUALS expression {
$$ = new BoolExpressionNode('n', $1, $3);
}
| bool_expression AND bool_expression {
$$ = new BoolExpressionNode('&', $1, $3);
}
| bool_expression OR bool_expression {
$$ = new BoolExpressionNode('|', $1, $3);
}
| NOT bool_expression {
$$ = new BoolExpressionNode('!', $2, NULL);
}
| LPAREN bool_expression RPAREN {
$$ = $2;
}
;
assignment: VARREF ASSIGN expression {
$$ = new AssignmentNode($1, $3);
}
;
local_assignment: LOCAL VARREF ASSIGN expression {
$$ = new LocalAssignmentNode($2, $4);
}
;
local_decl: LOCAL VARREF {
$$ = new LocalDeclNode($2);
}
;
for: FOR LPAREN maybe_expression SEMICOLON bool_expression SEMICOLON maybe_expression RPAREN LCURLY general_items RCURLY {
$$ = new ForNode($3, $5, $7);
$$->addChildren($10);
}
;
while: WHILE LPAREN bool_expression RPAREN LCURLY general_items RCURLY {
$$ = new ForNode(NULL, $3, NULL);
$$->addChildren($6);
}
;
if: IF LPAREN bool_expression RPAREN LCURLY general_items RCURLY if_more {
$$ = new IfNode($3, $8);
$$->addChildren($6);
}
;
if_more: /* empty */ { $$ = NULL; }
| ELSIF LPAREN bool_expression RPAREN LCURLY general_items RCURLY if_more {
$$ = new IfNode($3, $8);
$$->addChildren($6);
}
| ELSE LCURLY general_items RCURLY {
$$ = new ElseNode();
$$->addChildren($3);
}
;
function_call: IDENTIFIER LPAREN function_call_parameters RPAREN {
$$ = new FunctionCallNode($1, $3);
}
;
function_call_parameters: /* empty */ { $$ = NULL; }
| expression function_call_more_parameters {
$$ = new ItemsNode();
$$->addChild($1);
$$->addChildren($2);
}
;
function_call_more_parameters: /* empty */ { $$ = NULL; }
| COMMA expression function_call_more_parameters {
$$ = new ItemsNode();
$$->addChild($2);
$$->addChildren($3);
}
;
%%
refptr<Node> parse(const char * fileName, refptr<Scope> scope)
{
parser_scope = scope;
yyin = fopen(fileName, "r");
if (yyin == NULL)
{
cerr << "Failed to open file '" << fileName << "'" << endl;
return refptr<Node>(NULL);
}
if (yyparse())
{
cerr << "Aborting." << endl;
exit(1);
}
return parsed_scene_node;
}
void errFunc(const char * str, YYLTYPE * yyllocp)
{
fprintf(stderr, "error: %s: line %d, column %d\n",
str,
yyllocp->first_line,
yyllocp->first_column);
}

View File

@ -1,34 +0,0 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
using namespace std;
int preprocess(const char * fileName)
{
struct stat st;
if (stat(fileName, &st))
{
cerr << "Error accessing " << fileName << endl;
return -1;
}
ifstream ifs(fileName);
if ( ! ifs.is_open() )
{
cerr << "Error opening " << fileName << endl;
return -2;
}
char * buff = new char[st.st_size];
while ( ! ifs.eof() )
{
ifs.getline(buff, st.st_size);
}
delete[] buff;
return 0;
}

View File

@ -1,9 +0,0 @@
#include "BoolShape.h"
void BoolShape::setMaterial(refptr<Material> material)
{
m_material = material;
m_shape1->setMaterial(material);
m_shape2->setMaterial(material);
}

View File

@ -1,19 +0,0 @@
#ifndef BOOLSHAPE_H
#define BOOLSHAPE_H BOOLSHAPE_H
#include "Shape.h"
class BoolShape : public Shape
{
public:
virtual IntersectionList intersect(refptr<Shape> _this, const Ray & ray) = 0;
virtual void setMaterial(refptr<Material> material);
virtual refptr<Shape> clone() = 0;
protected:
refptr<Shape> m_shape1;
refptr<Shape> m_shape2;
};
#endif

View File

@ -1,111 +0,0 @@
#include "Box.h"
#include "util/Solver.h"
#include <math.h>
#include <iostream>
using namespace std;
#define FP_EQUAL(x,y) (fabs((x)-(y)) < 0.000001)
Box::Box(refptr<Vector> size)
{
m_size = *size;
m_size[0] = fabs(m_size[0]) / 2.0;
m_size[1] = fabs(m_size[1]) / 2.0;
m_size[2] = fabs(m_size[2]) / 2.0;
}
Shape::IntersectionList Box::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
/*** optimization ***/
if (ray_inv.getOrigin()[0] > m_size[0])
{
if (ray_inv.getDirection() % Vector::X > 0)
return res;
}
else if (ray_inv.getOrigin()[0] < -m_size[0])
{
if (ray_inv.getDirection() % Vector::X < 0)
return res;
}
if (ray_inv.getOrigin()[1] > m_size[1])
{
if (ray_inv.getDirection() % Vector::Y > 0)
return res;
}
else if (ray_inv.getOrigin()[1] < -m_size[1])
{
if (ray_inv.getDirection() % Vector::Y < 0)
return res;
}
if (ray_inv.getOrigin()[2] > m_size[2])
{
if (ray_inv.getDirection() % Vector::Z > 0)
return res;
}
else if (ray_inv.getOrigin()[2] < -m_size[2])
{
if (ray_inv.getDirection() % Vector::Z < 0)
return res;
}
/*** end optimization ***/
/*
* Ray equation: R = R0 + tRd
* x = R0x + tRdx
* y = R0y + tRdy
* z = R0z + tRdz
* Side equation: x - size_x = 0
* Combined: R0x + (t)Rdx - size_x = 0
*/
for (int dim = 0; dim < 3; dim++)
{
for (int side = -1; side <= 1; side += 2)
{
LinearSolver solver(ray_inv.getDirection()[dim],
ray_inv.getOrigin()[dim]
+ side * m_size[dim]);
Solver::Result solutions = solver.solve();
for (int i = 0; i < solutions.numResults; i++)
{
if (solutions.results[i] >= 0.0)
{
Vector isect_point = ray_inv[solutions.results[i]];
if ( (dim == 0 || fabs(isect_point[0]) <= m_size[0])
&& (dim == 1 || fabs(isect_point[1]) <= m_size[1])
&& (dim == 2 || fabs(isect_point[2]) <= m_size[2]) )
{
Vector normal(0, 0, -1);
if ( FP_EQUAL(isect_point[0], m_size[0]) )
normal = Vector(1, 0, 0);
else if ( FP_EQUAL(isect_point[0], -m_size[0]) )
normal = Vector(-1, 0, 0);
else if ( FP_EQUAL(isect_point[1], m_size[1]) )
normal = Vector(0, 1, 0);
else if ( FP_EQUAL(isect_point[1], -m_size[1]) )
normal = Vector(0, -1, 0);
else if ( FP_EQUAL(isect_point[2], m_size[2]) )
normal = Vector(0, 0, 1);
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(normal))
);
}
}
}
}
}
return res;
}
refptr<Shape> Box::clone()
{
return new Box(*this);
}

View File

@ -1,19 +0,0 @@
#ifndef BOX_H
#define BOX_H BOX_H
#include "Shape.h"
class Box : public Shape
{
public:
Box(refptr<Vector> size);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
virtual refptr<Shape> clone();
protected:
Vector m_size;
};
#endif

View File

@ -1,141 +0,0 @@
#include "Cyl.h"
#include "util/Solver.h"
#include <math.h>
#include <iostream>
using namespace std;
#define FP_EQUAL(x,y) (fabs((x)-(y)) < 0.000001)
Cyl::Cyl(double bottom_radius, double top_radius, double height)
{
m_bottom_radius = fabs(bottom_radius);
m_bottom_radius_2 = bottom_radius * bottom_radius;
m_top_radius = fabs(top_radius);
m_top_radius_2 = top_radius * top_radius;
m_height = fabs(height);
if (m_height == 0.0)
m_height = 1.0;
m_slope = (m_top_radius - m_bottom_radius) / m_height; /* rise over run */
if ( ! FP_EQUAL(m_slope, 0.0) )
m_inv_slope = -1.0 / m_slope;
}
Shape::IntersectionList Cyl::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
/* First intersect with the bottom plane, if it has positive area */
if (m_bottom_radius > 0.0)
{
LinearSolver solver(-ray_inv.getDirection()[2],
-ray_inv.getOrigin()[2]);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector isect_point = ray_inv[solutions.results[0]];
if (isect_point[0]*isect_point[0] + isect_point[1]*isect_point[1]
<= m_bottom_radius_2)
{
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(Vector(0, 0, -1))));
}
}
}
/* Same for the top plane */
if (m_top_radius > 0.0)
{
LinearSolver solver(ray_inv.getDirection()[2],
ray_inv.getOrigin()[2] - m_height);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector isect_point = ray_inv[solutions.results[0]];
if (isect_point[0]*isect_point[0] + isect_point[1]*isect_point[1]
<= m_top_radius_2)
{
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(Vector(0, 0, 1))));
}
}
}
/*
* Now see if the ray hit the side of the cylinder/cone thingy
* Ray equation: R = R0 + tRd
* x = R0x + tRdx
* y = R0y + tRdy
* z = R0z + tRdz
* Side equation: x^2 + y^2 = (m*z + b)^2
* Combined: (R0x+t*Rdx)^2 + (R0y+t*Rdy)^2 = (m*(R0z+t*Rdz) + b)^2
* Expanded: (R0x*R0x + (t*t)*Rdx*Rdx + 2*R0x*t*Rdx)
* + (R0y*R0y + (t*t)*Rdy*Rdy + 2*R0y*t*Rdy)
* = ((m*R0z+m*t*Rdz)^2 + b*b + 2*m*(R0z+t*Rdz)*b)
* = ((m*R0z*m*R0z + m*m*t*t*Rdz*Rdz + 2*m*R0z*m*t*Rdz)
* + b*b + 2*m*R0z*b + 2*m*t*Rdz*b)
* Quadratic form: (t*t)(Rdx*Rdx + Rdy*Rdy - m*m*Rdz*Rdz)
* + (t)(2*R0x*Rdx + 2*R0y*Rdy - 2*m*R0z*m*Rdz - 2*m*Rdz*b)
* + (R0x*R0x + R0y*R0y - m*m*R0z*R0z - b*b - 2*m*R0z*b)
* = 0
*/
double Rdx = ray_inv.getDirection()[0];
double Rdy = ray_inv.getDirection()[1];
double Rdz = ray_inv.getDirection()[2];
double R0x = ray_inv.getOrigin()[0];
double R0y = ray_inv.getOrigin()[1];
double R0z = ray_inv.getOrigin()[2];
double m = m_slope;
double m2 = m*m;
double b = m_bottom_radius;
QuadraticSolver solver(Rdx * Rdx + Rdy * Rdy - m2 * Rdz * Rdz,
2.0 * (R0x*Rdx + R0y*Rdy - m2*R0z*Rdz - m*Rdz*b),
R0x*R0x + R0y*R0y - m2*R0z*R0z - b*b - 2*m*R0z*b);
Solver::Result solutions = solver.solve();
for (int i = 0; i < solutions.numResults; i++)
{
if (solutions.results[i] >= 0.0)
{
Vector isect_point = ray_inv[solutions.results[i]];
if (isect_point[2] > 0.0 && isect_point[2] < m_height)
{
Vector normal;
if ( FP_EQUAL(m_slope, 0.0) )
{
normal = Vector(isect_point[0], isect_point[1], 0.0);
}
else
{
double x = isect_point[0];
double y = isect_point[1];
double dist = sqrt( isect_point[0] * isect_point[0]
+ isect_point[1] * isect_point[1] );
if (dist > 0.0)
{
double scale = 1.0 / dist;
x *= scale;
y *= scale;
}
normal = Vector(x, y, m_inv_slope);
}
normal.normalize();
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(normal)));
}
}
}
return res;
}
refptr<Shape> Cyl::clone()
{
return new Cyl(*this);
}

View File

@ -1,25 +0,0 @@
#ifndef CYL_H
#define CYL_H CYL_H
#include "Shape.h"
class Cyl : public Shape
{
public:
Cyl(double bottom_radius, double top_radius, double height);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
virtual refptr<Shape> clone();
protected:
double m_bottom_radius;
double m_bottom_radius_2;
double m_top_radius;
double m_top_radius_2;
double m_height;
double m_slope;
double m_inv_slope;
};
#endif

View File

@ -1,267 +0,0 @@
#include <math.h>
#include <iostream>
#include <algorithm> /* sort() */
#include "Extrude.h"
#include "util/Polygon.h"
#include "util/Solver.h"
using namespace std;
#define FP_EQUAL(x,y) (fabs((x)-(y)) < 0.000001)
Extrude::Extrude()
{
}
class IntersectListComparator
{
public:
IntersectListComparator(Vector start) : m_start(start) {}
bool operator()(const Shape::Intersection & i1,
const Shape::Intersection & i2) const
{
double d1 = (i1.position - m_start).mag2();
double d2 = (i2.position - m_start).mag2();
return d1 < d2;
}
protected:
Vector m_start;
};
Shape::IntersectionList Extrude::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
/*** optimization ***/
if (ray_inv.getOrigin()[0] > m_aabb.max[0])
{
if (ray_inv.getDirection() % Vector::X > 0)
return res;
}
else if (ray_inv.getOrigin()[0] < m_aabb.min[0])
{
if (ray_inv.getDirection() % Vector::X < 0)
return res;
}
if (ray_inv.getOrigin()[1] > m_aabb.max[1])
{
if (ray_inv.getDirection() % Vector::Y > 0)
return res;
}
else if (ray_inv.getOrigin()[1] < m_aabb.min[1])
{
if (ray_inv.getDirection() % Vector::Y < 0)
return res;
}
if (ray_inv.getOrigin()[2] > m_aabb.max[2])
{
if (ray_inv.getDirection() % Vector::Z > 0)
return res;
}
else if (ray_inv.getOrigin()[2] < m_aabb.min[2])
{
if (ray_inv.getDirection() % Vector::Z < 0)
return res;
}
/*** end optimization ***/
int n_polygons = m_polygons.size();
int n_offsets = m_offsets.size();
double distance = 0.0;
Vector scale(1.0, 1.0, 1.0);
Vector shift(0.0, 0.0, 0.0);
for (int p = 0; p < n_polygons; p++)
{
refptr<Polygon> polygon = m_polygons[p];
for (int o = 0; o < n_offsets; o++)
{
Offset & offset = m_offsets[o];
for (int pt = 0, n_pts = polygon->size(); pt < n_pts; pt++)
{
Vector p1 = scale.mult(*(*polygon)[pt]) + shift;
Vector p2 = scale.mult(*(*polygon)[(pt+1) % n_pts]) + shift;
Vector p3 = scale.mult(offset.scale)
.mult(*(*polygon)[(pt+1) % n_pts])
+ shift + offset.shift;
Vector p4 = scale.mult(offset.scale).mult(*(*polygon)[pt])
+ shift + offset.shift;
p1[2] += distance;
p2[2] += distance;
p3[2] += distance + offset.distance;
p4[2] += distance + offset.distance;
Vector e1 = p2 - p1;
Vector e2 = p3 - p2;
Vector normal = (e1 * e2).normalize();
double a = normal[0], b = normal[1], c = normal[2];
double d = -(a * p1[0] + b * p1[1] + c * p1[2]);
LinearSolver solver( a * ray_inv.getDirection()[0]
+ b * ray_inv.getDirection()[1]
+ c * ray_inv.getDirection()[2],
a * ray_inv.getOrigin()[0]
+ b * ray_inv.getOrigin()[1]
+ c * ray_inv.getOrigin()[2]
+ d);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector ipoint = ray_inv[solutions.results[0]];
Polygon quad;
quad.add(p1).add(p2).add(p3).add(p4);
if (quad.containsPointConvex(ipoint))
{
res.add(Intersection(_this,
m_transform.transform_point(ipoint),
m_transform.transform_normal(normal)));
}
}
}
distance += offset.distance;
scale = scale.mult(offset.scale);
shift += offset.shift;
}
}
double a = 0, b = 0, c = -1.0, d = 0.0;
LinearSolver solver( a * ray_inv.getDirection()[0]
+ b * ray_inv.getDirection()[1]
+ c * ray_inv.getDirection()[2],
a * ray_inv.getOrigin()[0]
+ b * ray_inv.getOrigin()[1]
+ c * ray_inv.getOrigin()[2]
+ d);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector ipoint = ray_inv[solutions.results[0]];
for (int p = 0; p < n_polygons; p++)
{
refptr<Polygon> polygon = m_polygons[p];
if (polygon->containsPoint2D(ipoint))
{
res.add(Intersection(_this,
m_transform.transform_point(ipoint),
m_transform.transform_normal(Vector(a, b, c))));
}
}
}
if (scale[0] > 0.0 && scale[1] > 0.0)
{
a = 0, b = 0, c = 1.0, d = -distance;
LinearSolver solver( a * ray_inv.getDirection()[0]
+ b * ray_inv.getDirection()[1]
+ c * ray_inv.getDirection()[2],
a * ray_inv.getOrigin()[0]
+ b * ray_inv.getOrigin()[1]
+ c * ray_inv.getOrigin()[2]
+ d);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0 && solutions.results[0] > 0.0)
{
Vector ipoint = ray_inv[solutions.results[0]];
for (int p = 0; p < n_polygons; p++)
{
Polygon tp = *m_polygons[p];
for (int i = 0, sz = tp.size(); i < sz; i++)
{
tp[i] = new Vector(tp[i]->mult(scale) + shift);
(*tp[i])[2] += distance;
}
if (tp.containsPoint2D(ipoint))
{
res.add(Intersection(_this,
m_transform.transform_point(ipoint),
m_transform.transform_normal(Vector(a, b, c))));
break;
}
}
}
}
sort(res.begin(), res.end(), IntersectListComparator(ray.getOrigin()));
return res;
}
void Extrude::addPolygon(refptr<Polygon> polygon)
{
m_polygons.push_back(polygon);
updateAABB();
}
void Extrude::addOffset(double distance,
const Vector & scale, const Vector & shift)
{
m_offsets.push_back(Offset(distance, scale, shift));
updateAABB();
}
void Extrude::updateAABB()
{
int n_polygons = m_polygons.size();
int n_offsets = m_offsets.size();
bool first = true;
double distance = 0.0;
Vector scale(1.0, 1.0, 1.0);
Vector shift(0.0, 0.0, 0.0);
for (int p = 0; p < n_polygons; p++)
{
refptr<Polygon> polygon = m_polygons[p];
for (int o = 0; o < n_offsets; o++)
{
Offset & offset = m_offsets[o];
for (int pt = 0, n_pts = polygon->size(); pt < n_pts; pt++)
{
Vector p1 = scale.mult(*(*polygon)[pt]) + shift;
Vector p2 = scale.mult(*(*polygon)[(pt+1) % n_pts]) + shift;
Vector p3 = scale.mult(offset.scale)
.mult(*(*polygon)[(pt+1) % n_pts])
+ shift + offset.shift;
Vector p4 = scale.mult(offset.scale).mult(*(*polygon)[pt])
+ shift + offset.shift;
p1[2] += distance;
p2[2] += distance;
p3[2] += distance + offset.distance;
p4[2] += distance + offset.distance;
if (first)
{
m_aabb.min = p1;
m_aabb.max = p1;
first = false;
}
expandAABB(p1);
expandAABB(p2);
expandAABB(p3);
expandAABB(p4);
}
distance += offset.distance;
scale = scale.mult(offset.scale);
shift += offset.shift;
}
}
}
void Extrude::expandAABB(const Vector & v)
{
if (v[0] < m_aabb.min[0])
m_aabb.min[0] = v[0];
if (v[0] > m_aabb.max[0])
m_aabb.max[0] = v[0];
if (v[1] < m_aabb.min[1])
m_aabb.min[1] = v[1];
if (v[1] > m_aabb.max[1])
m_aabb.max[1] = v[1];
if (v[2] < m_aabb.min[2])
m_aabb.min[2] = v[2];
if (v[2] > m_aabb.max[2])
m_aabb.max[2] = v[2];
}
refptr<Shape> Extrude::clone()
{
return new Extrude(*this);
}

View File

@ -1,43 +0,0 @@
#ifndef EXTRUDE_H
#define EXTRUDE_H EXTRUDE_H
#include <vector>
#include "util/Polygon.h"
#include "util/AABB.h"
#include "Shape.h"
class Extrude : public Shape
{
public:
Extrude();
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
void addPolygon(refptr<Polygon> polygon);
void addOffset(double distance,
const Vector & scale, const Vector & shift);
class Offset
{
public:
Offset(double d, const Vector & s, const Vector & p)
: distance(d), scale(s), shift(p)
{
}
double distance;
Vector scale;
Vector shift;
};
virtual refptr<Shape> clone();
protected:
std::vector< refptr<Polygon> > m_polygons;
std::vector<Offset> m_offsets;
AABB m_aabb;
void updateAABB();
void expandAABB(const Vector & v);
};
#endif

View File

@ -1,115 +0,0 @@
#include "Intersect.h"
#include <iostream>
using namespace std;
Intersect::Intersect(const vector< refptr<Shape> > & shapes)
{
int num_shapes = shapes.size();
if (num_shapes > 2)
{
m_shape2 = shapes[num_shapes - 1];
vector< refptr<Shape> > rest = shapes;
rest.pop_back();
m_shape1 = new Intersect(rest);
}
else if (num_shapes == 2)
{
m_shape1 = shapes[0];
m_shape2 = shapes[1];
}
else
{
cerr << __FILE__ << ": " << __LINE__
<< ": error: Intersect::Intersect() called with only "
<< num_shapes
<< " sub-shapes!"
<< endl;
exit(4);
}
}
Shape::IntersectionList Intersect::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res1 = m_shape1->intersect(m_shape1, ray_inv);
/*** optimization ***/
if (res1.size() == 0)
return res1;
/*** end optimization ***/
IntersectionList res2 = m_shape2->intersect(m_shape2, ray_inv);
BoolIntersectionList merged(res1, res2, ray_inv.getOrigin());
IntersectionList res;
bool in1 = false, in2 = false;
/* initially go through the merged intersections to see whether
* the ray started inside one of the sub-objects */
for (int i = 0, sz = merged.size(), saw1 = 0, saw2 = 0;
i < sz && (!saw1 || !saw2);
i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool back = dot < 0.0;
bool left = merged[i].left;
if (back)
{
if (left && !saw1)
in1 = true;
else if (!left && !saw2)
in2 = true;
}
if (left)
saw1 = 1;
else
saw2 = 1;
}
bool in_bool = in1 && in2;
for (int i = 0, sz = merged.size(); i < sz; i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool front = dot > 0.0;
bool left = merged[i].left;
if (front)
{
if (left)
in1 = true;
else
in2 = true;
if (!in_bool && in1 && in2)
{
/* we found an intersection point with the boolean object */
in_bool = true;
res.add( merged[i].intersection.transform(m_transform) );
}
}
else
{
if (in_bool && in1 && in2)
{
/* we found an intersection point with the boolean object */
res.add( merged[i].intersection.transform(m_transform) );
}
if (left)
in1 = false;
else
in2 = false;
in_bool = false;
}
}
return res;
}
refptr<Shape> Intersect::clone()
{
Intersect * s = new Intersect(*this);
s->m_shape1 = m_shape1->clone();
s->m_shape2 = m_shape2->clone();
return refptr<Shape>(s);
}

View File

@ -1,17 +0,0 @@
#ifndef INTERSECT_H
#define INTERSECT_H INTERSECT_H
#include "BoolShape.h"
#include <vector>
class Intersect : public BoolShape
{
public:
Intersect(const std::vector< refptr<Shape> > & shapes);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
refptr<Shape> clone();
};
#endif

View File

@ -1,57 +0,0 @@
#include "Plane.h"
#include "util/Solver.h"
#include <math.h>
#include <iostream>
using namespace std;
Plane::Plane(double a, double b, double c, double d)
{
m_a = a;
m_b = b;
m_c = c;
m_d = d;
m_normal = Vector(m_a, m_b, m_c);
m_normal.normalize();
}
Shape::IntersectionList Plane::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
/*
* Plane equation: ax + by + cz + d = 0
* Ray equation: R = R0 + tRd
* x = R0x + tRdx
* y = R0y + tRdy
* z = R0z + tRdz
* Combined: a(R0x + tRdx) + b(R0y + tRdy) + c(R0z + tRdz) + d = 0
* aR0x + (t)aRdx + bR0y + (t)bRdy + cR0z + (t)cRdz + d = 0
* (t)(aRdx + bRdy + cRdz) + aR0x + bR0y + cR0z + d = 0
*/
LinearSolver solver( m_a * ray_inv.getDirection()[0]
+ m_b * ray_inv.getDirection()[1]
+ m_c * ray_inv.getDirection()[2],
m_a * ray_inv.getOrigin()[0]
+ m_b * ray_inv.getOrigin()[1]
+ m_c * ray_inv.getOrigin()[2]
+ m_d);
Solver::Result solutions = solver.solve();
if (solutions.numResults > 0)
{
if (solutions.results[0] > 0.0)
{
Vector isect_point = ray_inv[solutions.results[0]];
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(m_normal)));
}
}
return res;
}
refptr<Shape> Plane::clone()
{
return new Plane(*this);
}

View File

@ -1,20 +0,0 @@
#ifndef PLANE_H
#define PLANE_H PLANE_H
#include "Shape.h"
class Plane : public Shape
{
public:
Plane(double a, double b, double c, double d);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
virtual refptr<Shape> clone();
protected:
double m_a, m_b, m_c, m_d;
Vector m_normal;
};
#endif

View File

@ -1,66 +0,0 @@
#include "Shape.h"
#include <algorithm> /* sort() */
#include <utility>
using namespace std;
static refptr<Material> default_material;
static bool default_material_initialized = false;
Shape::Shape()
{
if (default_material_initialized == false)
{
default_material = new Material();
default_material_initialized = true;
}
m_material = default_material;
}
Shape::~Shape()
{
}
void Shape::setMaterial(refptr<Material> material)
{
m_material = material;
}
class BoolIntersectionComparator
{
public:
BoolIntersectionComparator(const Vector & refPoint)
{
m_refPoint = refPoint;
}
bool operator()(const Shape::BoolIntersection & i1,
const Shape::BoolIntersection & i2) const
{
return ( m_refPoint.dist_to(i1.intersection.position)
< m_refPoint.dist_to(i2.intersection.position) );
}
protected:
Vector m_refPoint;
};
Shape::BoolIntersectionList::BoolIntersectionList(const IntersectionList & l1,
const IntersectionList & l2,
const Vector & startPoint)
{
for (size_t i = 0, sz = l1.size();
i < sz;
i++)
{
m_intersections.push_back( BoolIntersection(l1[i], true) );
}
for (size_t i = 0, sz = l2.size();
i < sz;
i++)
{
m_intersections.push_back( BoolIntersection(l2[i], false) );
}
sort(m_intersections.begin(),
m_intersections.end(),
BoolIntersectionComparator(startPoint));
}

View File

@ -1,131 +0,0 @@
#ifndef SHAPE_H
#define SHAPE_H SHAPE_H
#include "util/Solver.h"
#include "util/Ray.h"
#include "util/Vector.h"
#include "util/Transform.h"
#include "util/Material.h"
#include "util/refptr.h"
#include <vector>
#include <utility>
class Shape
{
public:
class Intersection
{
public:
Intersection() {};
Intersection(refptr<Shape> shape,
const Vector & position,
const Vector & normal)
{
this->shape = shape;
this->position = position;
this->normal = normal;
}
refptr<Shape> shape;
Vector position;
Vector normal;
Intersection transform(Transform & t)
{
return Intersection(shape,
t.transform_point(position),
t.transform_normal(normal));
}
};
class BoolIntersection
{
public:
BoolIntersection() {};
BoolIntersection(const Intersection & intersection, bool left)
{
this->intersection = intersection;
this->left = left;
}
Intersection intersection;
bool left;
};
class IntersectionList
{
public:
void add(const Intersection & i)
{
m_intersections.push_back(i);
}
Intersection & operator[](int i)
{
return m_intersections[i];
}
const Intersection & operator[](int i) const
{
return m_intersections[i];
}
size_t size() const { return m_intersections.size(); }
std::vector<Intersection>::iterator begin()
{
return m_intersections.begin();
}
std::vector<Intersection>::iterator end()
{
return m_intersections.end();
}
protected:
std::vector< Intersection > m_intersections;
};
class BoolIntersectionList
{
public:
BoolIntersectionList(const IntersectionList & l1,
const IntersectionList & l2,
const Vector & startPoint);
BoolIntersection & operator[](int i)
{
return m_intersections[i];
}
const BoolIntersection & operator[](int i) const
{
return m_intersections[i];
}
size_t size() const { return m_intersections.size(); }
std::vector<BoolIntersection>::iterator begin()
{
return m_intersections.begin();
}
std::vector<BoolIntersection>::iterator end()
{
return m_intersections.end();
}
protected:
std::vector< BoolIntersection > m_intersections;
};
Shape();
virtual ~Shape();
virtual IntersectionList intersect(refptr<Shape> _this,
const Ray & ray) = 0;
virtual refptr<Shape> clone() = 0;
void setTransform(const Transform & t)
{
m_transform = t;
m_inverse = m_transform.getInverse();
}
Transform & getTransform() { return m_transform; }
virtual void setMaterial(refptr<Material> material);
refptr<Material> getMaterial() const { return m_material; }
protected:
Transform m_transform;
Transform m_inverse;
refptr<Material> m_material;
};
typedef refptr<Shape> ShapeRef;
#endif

View File

@ -1,49 +0,0 @@
#include "Sphere.h"
#include "util/Solver.h"
#include <math.h>
#include <iostream>
using namespace std;
Sphere::Sphere(double radius)
{
m_radius = radius;
m_radius2 = radius * radius;
}
Shape::IntersectionList Sphere::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res;
QuadraticSolver solver(1.0,
2 * ( ray_inv.getOrigin()[0] * ray_inv.getDirection()[0]
+ ray_inv.getOrigin()[1] * ray_inv.getDirection()[1]
+ ray_inv.getOrigin()[2] * ray_inv.getDirection()[2] ),
ray_inv.getOrigin()[0] * ray_inv.getOrigin()[0]
+ ray_inv.getOrigin()[1] * ray_inv.getOrigin()[1]
+ ray_inv.getOrigin()[2] * ray_inv.getOrigin()[2]
- m_radius2);
Solver::Result quadSolutions = solver.solve();
for (int i = 0; i < quadSolutions.numResults; i++)
{
if (quadSolutions.results[i] >= 0.0)
{
Vector isect_point = ray_inv[quadSolutions.results[i]];
Vector normal = isect_point;
normal.normalize();
res.add(
Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(normal))
);
}
}
return res;
}
refptr<Shape> Sphere::clone()
{
return new Sphere(*this);
}

View File

@ -1,20 +0,0 @@
#ifndef SPHERE_H
#define SPHERE_H SPHERE_H
#include "Shape.h"
class Sphere : public Shape
{
public:
Sphere(double radius);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
virtual refptr<Shape> clone();
protected:
double m_radius;
double m_radius2;
};
#endif

View File

@ -1,115 +0,0 @@
#include "Subtract.h"
#include <iostream>
using namespace std;
Subtract::Subtract(const vector< refptr<Shape> > & shapes)
{
int num_shapes = shapes.size();
if (num_shapes > 2)
{
m_shape2 = shapes[num_shapes - 1];
vector< refptr<Shape> > rest = shapes;
rest.pop_back();
m_shape1 = new Subtract(rest);
}
else if (num_shapes == 2)
{
m_shape1 = shapes[0];
m_shape2 = shapes[1];
}
else
{
cerr << __FILE__ << ": " << __LINE__
<< ": error: Subtract::Subtract() called with only "
<< num_shapes
<< " sub-shapes!"
<< endl;
exit(4);
}
}
Shape::IntersectionList Subtract::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res1 = m_shape1->intersect(m_shape1, ray_inv);
/*** optimization ***/
if (res1.size() == 0)
return res1;
/*** end optimization ***/
IntersectionList res2 = m_shape2->intersect(m_shape2, ray_inv);
BoolIntersectionList merged(res1, res2, ray_inv.getOrigin());
IntersectionList res;
bool in1 = false, in2 = false;
/* initially go through the merged intersections to see whether
* the ray started inside one of the sub-objects */
for (int i = 0, sz = merged.size(), saw1 = 0, saw2 = 0;
i < sz && (!saw1 || !saw2);
i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool back = dot < 0.0;
bool left = merged[i].left;
if (back)
{
if (left && !saw1)
in1 = true;
else if (!left && !saw2)
in2 = true;
}
if (left)
saw1 = 1;
else
saw2 = 1;
}
bool in_bool = in1 && !in2;
for (int i = 0, sz = merged.size(); i < sz; i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool front = dot > 0.0;
bool left = merged[i].left;
if (left)
in1 = front;
else
in2 = front;
if (!in_bool && in1 && !in2)
{
/* we found an intersection point
* to get into the boolean object */
in_bool = true;
BoolIntersection bi = merged[i];
Intersection i = bi.intersection;
if ( ! left ) /* if this point came from object B (A - B) */
i.normal = - i.normal;
res.add(i.transform(m_transform));
}
else if (in_bool && !(in1 && !in2))
{
/* we found an intersection point
* to get out of the boolean object */
BoolIntersection bi = merged[i];
Intersection i = bi.intersection;
if ( ! left ) /* if this point came from object B (A - B) */
i.normal = - i.normal;
res.add(i.transform(m_transform));
in_bool = false;
}
}
return res;
}
refptr<Shape> Subtract::clone()
{
Subtract * s = new Subtract(*this);
s->m_shape1 = m_shape1->clone();
s->m_shape2 = m_shape2->clone();
return refptr<Shape>(s);
}

View File

@ -1,17 +0,0 @@
#ifndef SUBTRACT_H
#define SUBTRACT_H SUBTRACT_H
#include "BoolShape.h"
#include <vector>
class Subtract : public BoolShape
{
public:
Subtract(const std::vector< refptr<Shape> > & shapes);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
refptr<Shape> clone();
};
#endif

View File

@ -1,110 +0,0 @@
#include "Union.h"
#include <iostream>
#include <vector>
using namespace std;
Union::Union(const vector< refptr<Shape> > & shapes)
{
int num_shapes = shapes.size();
if (num_shapes > 2)
{
m_shape2 = shapes[num_shapes - 1];
vector< refptr<Shape> > rest = shapes;
rest.pop_back();
m_shape1 = new Union(rest);
}
else if (num_shapes == 2)
{
m_shape1 = shapes[0];
m_shape2 = shapes[1];
}
else
{
cerr << __FILE__ << ": " << __LINE__
<< ": error: Union::Union() called with only "
<< num_shapes
<< " sub-shapes!"
<< endl;
exit(4);
}
}
Shape::IntersectionList Union::intersect(refptr<Shape> _this, const Ray & ray)
{
Ray ray_inv = m_inverse.transform_ray(ray);
IntersectionList res1 = m_shape1->intersect(m_shape1, ray_inv);
IntersectionList res2 = m_shape2->intersect(m_shape2, ray_inv);
BoolIntersectionList merged(res1, res2, ray_inv.getOrigin());
IntersectionList res;
bool in1 = false, in2 = false;
/* initially go through the merged intersections to see whether
* the ray started inside one of the sub-objects */
for (int i = 0, sz = merged.size(), saw1 = 0, saw2 = 0;
i < sz && (!saw1 || !saw2);
i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool back = dot < 0.0;
bool left = merged[i].left;
if (back)
{
if (left && !saw1)
in1 = true;
else if (!left && !saw2)
in2 = true;
}
if (left)
saw1 = 1;
else
saw2 = 1;
}
bool in_bool = in1 || in2;
for (int i = 0, sz = merged.size(); i < sz; i++)
{
Vector normal = merged[i].intersection.normal;
double dot = - (ray_inv.getDirection() % normal);
bool front = dot > 0.0;
bool left = merged[i].left;
if (front)
{
if (left)
in1 = true;
else
in2 = true;
if (!in_bool && (in1 || in2))
{
/* we found an intersection point with the boolean object */
in_bool = true;
res.add( merged[i].intersection.transform(m_transform) );
}
}
else
{
if (left)
in1 = false;
else
in2 = false;
if (in_bool && !(in1 || in2))
{
/* we found an intersection point with the boolean object */
res.add( merged[i].intersection.transform(m_transform) );
in_bool = false;
}
}
}
return res;
}
refptr<Shape> Union::clone()
{
Union * s = new Union(*this);
s->m_shape1 = m_shape1->clone();
s->m_shape2 = m_shape2->clone();
return refptr<Shape>(s);
}

View File

@ -1,17 +0,0 @@
#ifndef UNION_H
#define UNION_H UNION_H
#include "BoolShape.h"
#include <vector>
class Union : public BoolShape
{
public:
Union(const std::vector< refptr<Shape> > & shapes);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
refptr<Shape> clone();
};
#endif

View File

@ -1,10 +0,0 @@
#include "BoolShape.h"
#include "Box.h"
#include "Cyl.h"
#include "Extrude.h"
#include "Intersect.h"
#include "Plane.h"
#include "Sphere.h"
#include "Subtract.h"
#include "Union.h"

View File

@ -1,21 +0,0 @@
#ifndef AABB_H
#define AABB_H
class AABB
{
public:
Vector min;
Vector max;
AABB()
{
}
AABB(const Vector & min, const Vector & max)
: min(min), max(max)
{
}
};
#endif /* AABB_H */

View File

@ -1,17 +0,0 @@
#include "Color.h"
const Color Color::black = Color(0, 0, 0);
const Color Color::white = Color(1, 1, 1);
const Color Color::red = Color(1, 0, 0);
const Color Color::green = Color(0, 1, 0);
const Color Color::blue = Color(0, 0, 1);
const Color Color::yellow = Color(1, 1, 0);
const Color Color::cyan = Color(0, 1, 1);
const Color Color::magenta = Color(1, 0, 1);
std::ostream & operator<<(std::ostream & out, const Color & color)
{
out << "[" << color.r << ", " << color.g << ", " << color.b << "]";
return out;
}

View File

@ -1,132 +0,0 @@
#ifndef COLOR_H
#define COLOR_H COLOR_H
#include "refptr.h"
#include <iostream>
#include "util/Vector.h"
class Color
{
public:
double r, g, b;
Color()
{
r = g = b = 0.0;
}
Color(double r, double g, double b)
{
this->r = r;
this->g = g;
this->b = b;
}
Color(const Vector & v)
{
r = v[0];
g = v[1];
b = v[2];
}
Color(refptr<Vector> v)
{
r = (*v)[0];
g = (*v)[1];
b = (*v)[2];
}
Color operator*(const Color & other) const
{
Color result;
result.r = r * other.r;
result.g = g * other.g;
result.b = b * other.b;
return result;
}
Color operator*(double scale) const
{
return Color(r * scale, g * scale, b * scale);
}
Color operator/(double scale) const
{
return Color(r / scale, g / scale, b / scale);
}
Color & operator+=(const Color & other)
{
r += other.r;
g += other.g;
b += other.b;
return *this;
}
Color & operator-=(const Color & other)
{
r += other.r;
g += other.g;
b += other.b;
return *this;
}
Color & operator*=(double scale)
{
r *= scale;
g *= scale;
b *= scale;
return *this;
}
Color & operator*=(const Color & other)
{
r *= other.r;
g *= other.g;
b *= other.b;
return *this;
}
Color & operator/=(double scale)
{
r /= scale;
g /= scale;
b /= scale;
return *this;
}
Color & operator/=(const Color & other)
{
r /= other.r;
g /= other.g;
b /= other.b;
return *this;
}
Color operator+(const Color & c2)
{
return Color(r + c2.r, g + c2.g, b + c2.b);
}
Color operator-(const Color & c2)
{
return Color(r - c2.r, g - c2.g, b - c2.b);
}
static const Color black;
static const Color white;
static const Color red;
static const Color green;
static const Color blue;
static const Color yellow;
static const Color cyan;
static const Color magenta;
};
static inline Color operator*(double d, const Color & c) { return c * d; }
static inline Color operator/(double d, const Color & c) { return c / d; }
std::ostream & operator<<(std::ostream & out, const Color & color);
#endif

View File

@ -1,72 +0,0 @@
#ifndef MATERIAL_H
#define MATERIAL_H MATERIAL_H
#include "Texture.h"
#include "Color.h"
class Material
{
public:
Material()
{
m_ambient_color = Color::white;
m_diffuse_color = Color::white;
m_specular_color = Color::white;
m_shininess = 50.0;
m_reflectance = 0.0;
m_transparency = 0.0;
m_refraction = 1.0;
m_texture = NULL;
}
void setAmbientColor(const Color & ambient)
{
m_ambient_color = ambient;
}
const Color & getAmbientColor() const { return m_ambient_color; }
void setDiffuseColor(const Color & diffuse)
{
m_diffuse_color = diffuse;
}
const Color & getDiffuseColor() const { return m_diffuse_color; }
void setSpecularColor(const Color & specular)
{
m_specular_color = specular;
}
const Color & getSpecularColor() const { return m_specular_color; }
void setShininess(double shininess) { m_shininess = shininess; }
double getShininess() const { return m_shininess; }
void setReflectance(double reflectance) { m_reflectance = reflectance; }
double getReflectance() const { return m_reflectance; }
void setRefraction(double refraction)
{
if (refraction > 0.0)
m_refraction = refraction;
}
double getRefraction() const { return m_refraction; }
void setTransparency(double t) { m_transparency = t; }
double getTransparency() const { return m_transparency; }
void setTexture(Texture * texture) { m_texture = texture; }
Texture * getTexture() const { return m_texture; }
protected:
Color m_ambient_color;
Color m_diffuse_color;
Color m_specular_color;
double m_shininess;
double m_reflectance;
double m_refraction;
double m_transparency;
Texture * m_texture;
};
#endif

View File

@ -1,241 +0,0 @@
#include "Matrix.h"
#include <math.h> /* fabs() */
#include <iostream>
#include <iomanip> /* setprecision() */
#define FP_EQ(x,y) (fabs((x)-(y)) < 0.00001)
Matrix::Matrix()
{
/* set matrix to the identity matrix */
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m_matrix[i][j] = i == j ? 1.0 : 0.0;
}
}
m_inverse_calculated = false;
}
Matrix Matrix::identity()
{
Matrix res;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
res[i][j] = i == j ? 1.0 : 0.0;
}
}
return res;
}
/* Formulas from http://www.cvl.iis.u-tokyo.ac.jp/~miyazaki/tech/teche23.html */
double Matrix::determinant()
{
return m_matrix[0][0] * m_matrix[1][1] * m_matrix[2][2] * m_matrix[3][3]
+ m_matrix[0][0] * m_matrix[1][2] * m_matrix[2][3] * m_matrix[3][1]
+ m_matrix[0][0] * m_matrix[1][3] * m_matrix[2][1] * m_matrix[3][2]
+ m_matrix[0][1] * m_matrix[1][0] * m_matrix[2][3] * m_matrix[3][2]
+ m_matrix[0][1] * m_matrix[1][2] * m_matrix[2][0] * m_matrix[3][3]
+ m_matrix[0][1] * m_matrix[1][3] * m_matrix[2][2] * m_matrix[3][0]
+ m_matrix[0][2] * m_matrix[1][0] * m_matrix[2][1] * m_matrix[3][3]
+ m_matrix[0][2] * m_matrix[1][1] * m_matrix[2][3] * m_matrix[3][0]
+ m_matrix[0][2] * m_matrix[1][3] * m_matrix[2][0] * m_matrix[3][1]
+ m_matrix[0][3] * m_matrix[1][0] * m_matrix[2][2] * m_matrix[3][1]
+ m_matrix[0][3] * m_matrix[1][1] * m_matrix[2][0] * m_matrix[3][2]
+ m_matrix[0][3] * m_matrix[1][2] * m_matrix[2][1] * m_matrix[3][0]
- m_matrix[0][0] * m_matrix[1][1] * m_matrix[2][3] * m_matrix[3][2]
- m_matrix[0][0] * m_matrix[1][2] * m_matrix[2][1] * m_matrix[3][3]
- m_matrix[0][0] * m_matrix[1][3] * m_matrix[2][2] * m_matrix[3][1]
- m_matrix[0][1] * m_matrix[1][0] * m_matrix[2][2] * m_matrix[3][3]
- m_matrix[0][1] * m_matrix[1][2] * m_matrix[2][3] * m_matrix[3][0]
- m_matrix[0][1] * m_matrix[1][3] * m_matrix[2][0] * m_matrix[3][2]
- m_matrix[0][2] * m_matrix[1][0] * m_matrix[2][3] * m_matrix[3][1]
- m_matrix[0][2] * m_matrix[1][1] * m_matrix[2][0] * m_matrix[3][3]
- m_matrix[0][2] * m_matrix[1][3] * m_matrix[2][1] * m_matrix[3][0]
- m_matrix[0][3] * m_matrix[1][0] * m_matrix[2][1] * m_matrix[3][2]
- m_matrix[0][3] * m_matrix[1][1] * m_matrix[2][2] * m_matrix[3][0]
- m_matrix[0][3] * m_matrix[1][2] * m_matrix[2][0] * m_matrix[3][1];
}
/* Formulas from http://www.cvl.iis.u-tokyo.ac.jp/~miyazaki/tech/teche23.html */
void Matrix::calculateInverse()
{
if (m_inverse_calculated)
return;
m_inverse_calculated = true;
m_inverse_valid = false;
double det = determinant();
if (det == 0.0)
return;
m_inverse[0][0] = m_matrix[1][1] * m_matrix[2][2] * m_matrix[3][3]
+ m_matrix[1][2] * m_matrix[2][3] * m_matrix[3][1]
+ m_matrix[1][3] * m_matrix[2][1] * m_matrix[3][2]
- m_matrix[1][1] * m_matrix[2][3] * m_matrix[3][2]
- m_matrix[1][2] * m_matrix[2][1] * m_matrix[3][3]
- m_matrix[1][3] * m_matrix[2][2] * m_matrix[3][1];
m_inverse[0][1] = m_matrix[0][1] * m_matrix[2][3] * m_matrix[3][2]
+ m_matrix[0][2] * m_matrix[2][1] * m_matrix[3][3]
+ m_matrix[0][3] * m_matrix[2][2] * m_matrix[3][1]
- m_matrix[0][1] * m_matrix[2][2] * m_matrix[3][3]
- m_matrix[0][2] * m_matrix[2][3] * m_matrix[3][1]
- m_matrix[0][3] * m_matrix[2][1] * m_matrix[3][2];
m_inverse[0][2] = m_matrix[0][1] * m_matrix[1][2] * m_matrix[3][3]
+ m_matrix[0][2] * m_matrix[1][3] * m_matrix[3][1]
+ m_matrix[0][3] * m_matrix[1][1] * m_matrix[3][2]
- m_matrix[0][1] * m_matrix[1][3] * m_matrix[3][2]
- m_matrix[0][2] * m_matrix[1][1] * m_matrix[3][3]
- m_matrix[0][3] * m_matrix[1][2] * m_matrix[3][1];
m_inverse[0][3] = m_matrix[0][1] * m_matrix[1][3] * m_matrix[2][2]
+ m_matrix[0][2] * m_matrix[1][1] * m_matrix[2][3]
+ m_matrix[0][3] * m_matrix[1][2] * m_matrix[2][1]
- m_matrix[0][1] * m_matrix[1][2] * m_matrix[2][3]
- m_matrix[0][2] * m_matrix[1][3] * m_matrix[2][1]
- m_matrix[0][3] * m_matrix[1][1] * m_matrix[2][2];
m_inverse[1][0] = m_matrix[1][0] * m_matrix[2][3] * m_matrix[3][2]
+ m_matrix[1][2] * m_matrix[2][0] * m_matrix[3][3]
+ m_matrix[1][3] * m_matrix[2][2] * m_matrix[3][0]
- m_matrix[1][0] * m_matrix[2][2] * m_matrix[3][3]
- m_matrix[1][2] * m_matrix[2][3] * m_matrix[3][0]
- m_matrix[1][3] * m_matrix[2][0] * m_matrix[3][2];
m_inverse[1][1] = m_matrix[0][0] * m_matrix[2][2] * m_matrix[3][3]
+ m_matrix[0][2] * m_matrix[2][3] * m_matrix[3][0]
+ m_matrix[0][3] * m_matrix[2][0] * m_matrix[3][2]
- m_matrix[0][0] * m_matrix[2][3] * m_matrix[3][2]
- m_matrix[0][2] * m_matrix[2][0] * m_matrix[3][3]
- m_matrix[0][3] * m_matrix[2][2] * m_matrix[3][0];
m_inverse[1][2] = m_matrix[0][0] * m_matrix[1][3] * m_matrix[3][2]
+ m_matrix[0][2] * m_matrix[1][0] * m_matrix[3][3]
+ m_matrix[0][3] * m_matrix[1][2] * m_matrix[3][0]
- m_matrix[0][0] * m_matrix[1][2] * m_matrix[3][3]
- m_matrix[0][2] * m_matrix[1][3] * m_matrix[3][0]
- m_matrix[0][3] * m_matrix[1][0] * m_matrix[3][2];
m_inverse[1][3] = m_matrix[0][0] * m_matrix[1][2] * m_matrix[2][3]
+ m_matrix[0][2] * m_matrix[1][3] * m_matrix[2][0]
+ m_matrix[0][3] * m_matrix[1][0] * m_matrix[2][2]
- m_matrix[0][0] * m_matrix[1][3] * m_matrix[2][2]
- m_matrix[0][2] * m_matrix[1][0] * m_matrix[2][3]
- m_matrix[0][3] * m_matrix[1][2] * m_matrix[2][0];
m_inverse[2][0] = m_matrix[1][0] * m_matrix[2][1] * m_matrix[3][3]
+ m_matrix[1][1] * m_matrix[2][3] * m_matrix[3][0]
+ m_matrix[1][3] * m_matrix[2][0] * m_matrix[3][1]
- m_matrix[1][0] * m_matrix[2][3] * m_matrix[3][1]
- m_matrix[1][1] * m_matrix[2][0] * m_matrix[3][3]
- m_matrix[1][3] * m_matrix[2][1] * m_matrix[3][0];
m_inverse[2][1] = m_matrix[0][0] * m_matrix[2][3] * m_matrix[3][1]
+ m_matrix[0][1] * m_matrix[2][0] * m_matrix[3][3]
+ m_matrix[0][3] * m_matrix[2][1] * m_matrix[3][0]
- m_matrix[0][0] * m_matrix[2][1] * m_matrix[3][3]
- m_matrix[0][1] * m_matrix[2][3] * m_matrix[3][0]
- m_matrix[0][3] * m_matrix[2][0] * m_matrix[3][1];
m_inverse[2][2] = m_matrix[0][0] * m_matrix[1][1] * m_matrix[3][3]
+ m_matrix[0][1] * m_matrix[1][3] * m_matrix[3][0]
+ m_matrix[0][3] * m_matrix[1][0] * m_matrix[3][1]
- m_matrix[0][0] * m_matrix[1][3] * m_matrix[3][1]
- m_matrix[0][1] * m_matrix[1][0] * m_matrix[3][3]
- m_matrix[0][3] * m_matrix[1][1] * m_matrix[3][0];
m_inverse[2][3] = m_matrix[0][0] * m_matrix[1][3] * m_matrix[2][1]
+ m_matrix[0][1] * m_matrix[1][0] * m_matrix[2][3]
+ m_matrix[0][3] * m_matrix[1][1] * m_matrix[2][0]
- m_matrix[0][0] * m_matrix[1][1] * m_matrix[2][3]
- m_matrix[0][1] * m_matrix[1][3] * m_matrix[2][0]
- m_matrix[0][3] * m_matrix[1][0] * m_matrix[2][1];
m_inverse[3][0] = m_matrix[1][0] * m_matrix[2][2] * m_matrix[3][1]
+ m_matrix[1][1] * m_matrix[2][0] * m_matrix[3][2]
+ m_matrix[1][2] * m_matrix[2][1] * m_matrix[3][0]
- m_matrix[1][0] * m_matrix[2][1] * m_matrix[3][2]
- m_matrix[1][1] * m_matrix[2][2] * m_matrix[3][0]
- m_matrix[1][2] * m_matrix[2][0] * m_matrix[3][1];
m_inverse[3][1] = m_matrix[0][0] * m_matrix[2][1] * m_matrix[3][2]
+ m_matrix[0][1] * m_matrix[2][2] * m_matrix[3][0]
+ m_matrix[0][2] * m_matrix[2][0] * m_matrix[3][1]
- m_matrix[0][0] * m_matrix[2][2] * m_matrix[3][1]
- m_matrix[0][1] * m_matrix[2][0] * m_matrix[3][2]
- m_matrix[0][2] * m_matrix[2][1] * m_matrix[3][0];
m_inverse[3][2] = m_matrix[0][0] * m_matrix[1][2] * m_matrix[3][1]
+ m_matrix[0][1] * m_matrix[1][0] * m_matrix[3][2]
+ m_matrix[0][2] * m_matrix[1][1] * m_matrix[3][0]
- m_matrix[0][0] * m_matrix[1][1] * m_matrix[3][2]
- m_matrix[0][1] * m_matrix[1][2] * m_matrix[3][0]
- m_matrix[0][2] * m_matrix[1][0] * m_matrix[3][1];
m_inverse[3][3] = m_matrix[0][0] * m_matrix[1][1] * m_matrix[2][2]
+ m_matrix[0][1] * m_matrix[1][2] * m_matrix[2][0]
+ m_matrix[0][2] * m_matrix[1][0] * m_matrix[2][1]
- m_matrix[0][0] * m_matrix[1][2] * m_matrix[2][1]
- m_matrix[0][1] * m_matrix[1][0] * m_matrix[2][2]
- m_matrix[0][2] * m_matrix[1][1] * m_matrix[2][0];
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m_inverse[i][j] /= det;
}
}
m_inverse_valid = true;
}
Matrix Matrix::getInverse()
{
calculateInverse();
Matrix m;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m.m_matrix[i][j] = m_inverse[i][j];
m.m_inverse[i][j] = m_matrix[i][j];
}
}
m.m_inverse_calculated = true;
m.m_inverse_valid = m_inverse_valid;
return m;
}
Matrix & Matrix::operator*=(const Matrix & other)
{
Matrix temp = (*this) * other;
(*this) = temp;
return (*this);
}
bool operator==(const Matrix & m1, const Matrix & m2)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (! FP_EQ(m1[i][j], m2[i][j]))
return false;
}
}
return true;
}
std::ostream & operator<<(std::ostream & out, const Matrix & m)
{
out << std::setprecision(3);
for (int i = 0; i < 4; i++)
{
out << (i == 0 ? "[ " : " ");
out << "[ ";
for (int j = 0; j < 4; j++)
{
out << m[i][j];
if (j < 3)
out << ", ";
}
out << " ]";
if (i == 3)
out << " ]";
out << std::endl;
}
return out;
}

View File

@ -1,75 +0,0 @@
#ifndef MATRIX_H
#define MATRIX_H MATRIX_H
#include "Vector.h"
#include <iostream>
class Matrix
{
public:
Matrix();
typedef double Matrix_row_t[4];
Matrix_row_t & operator[](int idx) { return m_matrix[idx]; }
const Matrix_row_t & operator[](int idx) const { return m_matrix[idx]; }
static Matrix identity();
double determinant();
Matrix getInverse();
Matrix & operator*=(const Matrix & other);
Matrix operator*(const Matrix & m2) const
{
Matrix res;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
res[i][j] = m_matrix[i][0] * m2.m_matrix[0][j]
+ m_matrix[i][1] * m2.m_matrix[1][j]
+ m_matrix[i][2] * m2.m_matrix[2][j]
+ m_matrix[i][3] * m2.m_matrix[3][j];
}
}
return res;
}
/* transform a point */
Vector operator*(const Vector & v)
{
Vector res;
for (int i = 0; i < 3; i++)
{
res[i] = m_matrix[i][0] * v[0]
+ m_matrix[i][1] * v[1]
+ m_matrix[i][2] * v[2]
+ m_matrix[i][3]; /* v[3] is implicitly 1.0 */
}
return res;
}
/* transform a direction */
Vector operator%(const Vector & v)
{
Vector res;
for (int i = 0; i < 3; i++)
{
res[i] = m_matrix[i][0] * v[0]
+ m_matrix[i][1] * v[1]
+ m_matrix[i][2] * v[2];
}
return res;
}
protected:
double m_matrix[4][4];
double m_inverse[4][4];
bool m_inverse_calculated;
bool m_inverse_valid;
void calculateInverse();
};
bool operator==(const Matrix & m1, const Matrix & m2);
std::ostream & operator<<(std::ostream & out, const Matrix & m);
#endif

View File

@ -1,95 +0,0 @@
#include <math.h> /* acos(), M_PI */
#include "Polygon.h"
#define FP_EQUAL(x,y) (fabs((x)-(y)) < 1E-3)
/*
* from http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/
* Return the angle between two vectors on a plane
* The angle is from vector 1 to vector 2, positive anticlockwise
* The result is between -pi -> pi
*/
static double angle2D(double x1, double y1, double x2, double y2)
{
double dtheta, theta1, theta2;
theta1 = atan2(y1,x1);
theta2 = atan2(y2,x2);
dtheta = theta2 - theta1;
while (dtheta > M_PI)
dtheta -= 2.0 * M_PI;
while (dtheta < -M_PI)
dtheta += 2.0 * M_PI;
return dtheta;
}
static bool similarPoint(const Vector & v, const Vector & w)
{
return FP_EQUAL(v[0], w[0]) && FP_EQUAL(v[1], w[1]) && FP_EQUAL(v[2], w[2]);
}
Polygon & Polygon::add(const Vector & v)
{
int sz = size();
if (sz < 1 || !similarPoint(v, *(*this)[sz-1]))
{
push_back(new Vector(v));
}
return *this;
}
Polygon & Polygon::add(refptr<Vector> v)
{
int sz = size();
if (sz < 1 || !similarPoint(*v, *(*this)[sz-1]))
{
push_back(v);
}
return *this;
}
bool Polygon::containsPoint2D(const Vector & v)
{
if (size() < 3)
{
return false;
}
if (similarPoint(*(*this)[0], *(*this)[size()-1]))
{
pop_back();
}
double angle_sum = 0.0;
for (int i = 0, sz = size(); i < sz; i++)
{
Vector v1 = *(*this)[i] - v;
Vector v2 = *(*this)[(i+1) % sz] - v;
double angle = angle2D(v1[0], v1[1], v2[0], v2[1]);
angle_sum += angle;
}
return FP_EQUAL(angle_sum, 2.0 * M_PI);
}
bool Polygon::containsPointConvex(const Vector & v)
{
if (size() < 3)
{
return false;
}
if (similarPoint(*(*this)[0], *(*this)[size()-1]))
{
pop_back();
}
double angle_sum = 0.0;
for (int i = 0, sz = size(); i < sz; i++)
{
Vector v1 = *(*this)[i] - v;
Vector v2 = *(*this)[(i+1) % sz] - v;
double cosine = (v1 % v2) / (v1.mag() * v2.mag());
double angle = acos(cosine);
angle_sum += angle;
}
return FP_EQUAL(angle_sum, 2.0 * M_PI);
}

View File

@ -1,19 +0,0 @@
#ifndef POLYGON_H
#define POLYGON_H
#include <vector>
#include "refptr.h"
#include "Vector.h"
class Polygon : public std::vector< refptr<Vector> >
{
public:
Polygon & add(const Vector & v);
Polygon & add(refptr<Vector> v);
bool containsPoint2D(const Vector & v);
bool containsPointConvex(const Vector & v);
};
#endif

View File

@ -1,17 +0,0 @@
#include <stdlib.h> /* rand() */
#include <iostream>
#include "Ray.h"
Ray Ray::randomRay()
{
return Ray(Vector(0, 0, 0), Vector::randomVector());
}
std::ostream & operator<<(std::ostream & out, const Ray & r)
{
out << "(" << r.getOrigin() << " -> " << r.getDirection() << ")";
return out;
}

View File

@ -1,58 +0,0 @@
#ifndef RAY_H
#define RAY_H RAY_H
#include "Vector.h"
#include <iostream>
class Ray
{
public:
Ray()
{
}
Ray(const Vector & origin, const Vector & direction)
: m_origin(origin), m_direction(direction)
{
m_direction.normalize();
}
/*
* return a vector for the point at distance dist
* from the ray's origin point, along its direction.
*/
Vector getPositionAt(double dist) const
{
return Vector(
m_origin[0] + dist * m_direction[0],
m_origin[1] + dist * m_direction[1],
m_origin[2] + dist * m_direction[2]);
}
Ray shift(double amt)
{
return Ray(getPositionAt(amt), m_direction, false);
}
const Vector & getOrigin() const { return m_origin; }
const Vector & getDirection() const { return m_direction; }
static Ray randomRay();
Vector operator[](double dist) const { return getPositionAt(dist); }
protected:
Ray(const Vector & origin, const Vector & direction, bool no_norm)
: m_origin(origin), m_direction(direction)
{
/* no normalize version */
}
Vector m_origin;
Vector m_direction;
};
std::ostream & operator<<(std::ostream & out, const Ray & r);
#endif

View File

@ -1,73 +0,0 @@
#ifndef SCOPE_H
#define SCOPE_H
#include <list>
#include <map>
#include <string>
class Scope
{
public:
Scope() { push(); }
bool contains(const std::string & key)
{
for (m_list_type::const_reverse_iterator it = m_list.rbegin();
it != m_list.rend();
it++)
{
if (it->find(key) != it->end())
{
return true;
}
}
return false;
}
double get(const std::string & key)
{
for (m_list_type::reverse_iterator it = m_list.rbegin();
it != m_list.rend();
it++)
{
if (it->find(key) != it->end())
{
return (*it)[key];
}
}
return 0.0;
}
void putLocal(const std::string & key, double val)
{
(*m_list.rbegin())[key] = val;
}
void putGlobal(const std::string & key, double val)
{
for (m_list_type::reverse_iterator it = m_list.rbegin();
it != m_list.rend();
it++)
{
if (it->find(key) != it->end())
{
(*it)[key] = val;
return;
}
}
putLocal(key, val);
}
void push()
{
m_list.push_back(std::map< std::string, double >());
}
void pop()
{
if (m_list.size() > 1)
{
m_list.pop_back();
}
}
protected:
typedef std::list< std::map< std::string, double > > m_list_type;
m_list_type m_list;
};
#endif

View File

@ -1,127 +0,0 @@
#include "Solver.h"
#include <math.h>
/* Generic Solver constructor */
Solver::Solver(double a, double b, double c, double d, double e)
{
this->a = a;
this->b = b;
this->c = c;
this->d = d;
this->e = e;
}
Solver::~Solver()
{
}
Solver::Result::Result()
{
numResults = 0;
}
/**************************************************************************
* LinearSolver methods *
*************************************************************************/
LinearSolver::LinearSolver(double a, double b)
: Solver(a, b)
{
}
/* solve a linear equation */
Solver::Result LinearSolver::solve()
{
/* equation ax + b = 0 */
Result res;
if (a == 0.0)
{
if (b == 0.0)
{
res.numResults = 1;
res.results[0] = 0.0;
}
else
{
res.numResults = 0;
}
}
else
{
res.numResults = 1;
res.results[0] = -b / a;
}
return res;
}
/**************************************************************************
* QuadraticSolver methods *
*************************************************************************/
QuadraticSolver::QuadraticSolver(double a, double b, double c)
: Solver(a, b, c)
{
}
/* solve a quadratic equation */
Solver::Result QuadraticSolver::solve()
{
Result res;
double discriminant = b * b - 4 * a * c;
if (discriminant < 0.0)
{
res.numResults = 0;
}
else
{
double sqrt_discriminant = sqrt(discriminant);
double two_a = 2.0 * a;
if (sqrt_discriminant == 0.0)
{
res.numResults = 1;
res.results[0] = (-b) / two_a;
}
else
{
res.numResults = 2;
res.results[0] = (-b - sqrt_discriminant) / two_a;
res.results[1] = (-b + sqrt_discriminant) / two_a;
}
}
return res;
}
/**************************************************************************
* CubicSolver methods *
*************************************************************************/
CubicSolver::CubicSolver(double a, double b, double c, double d)
: Solver(a, b, c, d)
{
}
Solver::Result CubicSolver::solve()
{
Result res;
/* TODO: fill in */
return res;
}
/**************************************************************************
* QuarticSolver methods *
*************************************************************************/
QuarticSolver::QuarticSolver(double a, double b, double c, double d, double e)
: Solver(a, b, c, d, e)
{
}
Solver::Result QuarticSolver::solve()
{
Result res;
/* TODO: fill in */
return res;
}

View File

@ -1,57 +0,0 @@
#ifndef SOLVER_H
#define SOLVER_H SOLVER_H
class Solver
{
public:
class Result
{
public:
Result();
int numResults;
double results[4];
};
Solver(double a = 0.0,
double b = 0.0,
double c = 0.0,
double d = 0.0,
double e = 0.0);
virtual ~Solver();
virtual Result solve() = 0;
protected:
double a, b, c, d, e;
};
class LinearSolver : public Solver
{
public:
LinearSolver(double a, double b);
Result solve();
};
class QuadraticSolver : public Solver
{
public:
QuadraticSolver(double a, double b, double c);
Result solve();
};
class CubicSolver : public Solver
{
public:
CubicSolver(double a, double b, double c, double d);
Result solve();
};
class QuarticSolver : public Solver
{
public:
QuarticSolver(double a, double b, double c, double d, double e);
Result solve();
};
#endif

View File

@ -1,16 +0,0 @@
#ifndef TEXTURE_H
#define TEXTURE_H TEXTURE_H
/* A loaded image texture. Pixel data is stored as tightly packed RGBA
* bytes (4 channels) and is owned by this struct -- free it with
* stbi_image_free(). */
struct Texture
{
int width;
int height;
int channels;
unsigned char * data;
};
#endif

View File

@ -1,72 +0,0 @@
#include "Transform.h"
#include <math.h>
void Transform::lookAt(const Vector & eye,
const Vector & focus,
const Vector & up)
{
Vector forward = focus - eye;
forward.normalize();
Vector perpendicular_up = (up - up.proj(forward)).normalize();
Vector right = forward * perpendicular_up;
Matrix mult;
mult[0][0] = right[0];
mult[0][1] = right[1];
mult[0][2] = right[2];
mult[1][0] = forward[0];
mult[1][1] = forward[1];
mult[1][2] = forward[2];
mult[2][0] = perpendicular_up[0];
mult[2][1] = perpendicular_up[1];
mult[2][2] = perpendicular_up[2];
m_matrix *= mult;
translate(-eye[0], -eye[1], -eye[2]);
}
void Transform::translate(double x, double y, double z)
{
Matrix t = Matrix::identity();
t[0][3] = x;
t[1][3] = y;
t[2][3] = z;
m_matrix *= t;
}
void Transform::rotate(double angle, double xv, double yv, double zv)
{
/* formula from http://en.wikipedia.org/wiki/Rotation_matrix */
Vector l(xv, yv, zv);
l.normalize();
double c = cos(M_PI * angle / 180.0);
double s = sin(M_PI * angle / 180.0);
double lx2 = l[0] * l[0];
double ly2 = l[1] * l[1];
double lz2 = l[2] * l[2];
Matrix t = Matrix::identity();
t[0][0] = lx2 + (1 - lx2) * c;
t[0][1] = l[0] * l[1] * (1 - c) - l[2] * s;
t[0][2] = l[0] * l[2] * (1 - c) + l[1] * s;
t[1][0] = l[0] * l[1] * (1 - c) + l[2] * s;
t[1][1] = ly2 + (1 - ly2) * c;
t[1][2] = l[1] * l[2] * (1 - c) - l[0] * s;
t[2][0] = l[0] * l[2] * (1 - c) - l[1] * s;
t[2][1] = l[1] * l[2] * (1 - c) + l[0] * s;
t[2][2] = lz2 + (1 - lz2) * c;
m_matrix *= t;
}
void Transform::scale(double xs, double ys, double zs)
{
Matrix t = Matrix::identity();
t[0][0] = xs;
t[1][1] = ys;
t[2][2] = zs;
m_matrix *= t;
}

View File

@ -1,72 +0,0 @@
#ifndef TRANSFORM_H
#define TRANSFORM_H TRANSFORM_H
#include "refptr.h"
#include "Matrix.h"
#include "Ray.h"
#include "Vector.h"
#include <stack>
class Transform
{
public:
Transform getInverse()
{
Transform inv;
inv.m_matrix = m_matrix.getInverse();
return inv;
}
void lookAt(const Vector & eye,
const Vector & focus,
const Vector & up);
void translate(double x, double y, double z);
void translate(refptr<Vector> vec)
{
translate((*vec)[0], (*vec)[1], (*vec)[2]);
}
void rotate(double angle, double xv, double yv, double zv);
void rotate(double angle, refptr<Vector> vec)
{
rotate(angle, (*vec)[0], (*vec)[1], (*vec)[2]);
}
void scale(double xs, double ys, double zs);
void scale(refptr<Vector> vec)
{
scale((*vec)[0], (*vec)[1], (*vec)[2]);
}
Matrix & getMatrix() { return m_matrix; }
Vector transform_point(const Vector & v)
{
return m_matrix * v;
}
Vector transform_direction(const Vector & v)
{
return m_matrix % v;
}
Vector transform_normal(const Vector & v)
{
return (m_matrix % v).normalize();
}
Ray transform_ray(const Ray & r)
{
return Ray(m_matrix * r.getOrigin(), m_matrix % r.getDirection());
}
Transform operator*(const Transform & other) const
{
Transform t;
t.m_matrix = m_matrix * other.m_matrix;
return t;
}
protected:
Matrix m_matrix;
};
#endif

View File

@ -1,29 +0,0 @@
#include <stdlib.h> /* rand() */
#include <math.h>
#include <iostream>
#include "Vector.h"
const Vector Vector::X(1, 0, 0);
const Vector Vector::Y(0, 1, 0);
const Vector Vector::Z(0, 0, 1);
Vector Vector::randomVector()
{
double x, y, z;
do
{
x = 2.0 * rand() / RAND_MAX - 1.0;
y = 2.0 * rand() / RAND_MAX - 1.0;
z = 2.0 * rand() / RAND_MAX - 1.0;
} while (x*x + y*y + z*z > 1.0);
return Vector(x, y, z).normalize();
}
std::ostream & operator<<(std::ostream & out, const Vector & v)
{
out << "[" << v[0] << ", " << v[1] << ", " << v[2] << "]";
return out;
}

View File

@ -1,203 +0,0 @@
#ifndef VECTOR_H
#define VECTOR_H VECTOR_H
#include <math.h> /* sqrt() */
#include <iostream>
class Vector
{
public:
Vector()
{
m_array[0] = 0.0;
m_array[1] = 0.0;
m_array[2] = 0.0;
}
Vector(double x, double y, double z)
{
m_array[0] = x;
m_array[1] = y;
m_array[2] = z;
}
Vector & normalize()
{
double length = mag();
m_array[0] /= length;
m_array[1] /= length;
m_array[2] /= length;
return *this;
}
double mag() const
{
return sqrt(m_array[0] * m_array[0]
+ m_array[1] * m_array[1]
+ m_array[2] * m_array[2]);
}
double mag2() const
{
return m_array[0] * m_array[0]
+ m_array[1] * m_array[1]
+ m_array[2] * m_array[2];
}
double dist_to(const Vector & other) const
{
return (other - *this).mag();
}
Vector proj(const Vector & target) const
{
Vector target_normalized = target;
target_normalized.normalize();
return target_normalized * ((*this) % target_normalized);
}
Vector reflect(const Vector & target) const
{
return (*this) - target * (2 * dot(target));
}
/*
* from http://www.flipcode.com/archives/
* Reflections_and_Refraction_in_Raytracing.shtml
* target: normal vector of surface
* n1: refraction index of object we're coming from
* n2: refraction index of object we're going into
*/
Vector refract(const Vector & target, double n1, double n2) const
{
const double n = n1 / n2;
const double cosI = -dot(target);
const double sinT2 = n * n * (1.0 - cosI * cosI);
if (sinT2 > 1.0)
return Vector(0.0, 0.0, 0.0);
return (*this) * n + target * (n * cosI - sqrt(1.0 - sinT2));
}
Vector getPerpendicular() const
{
Vector t = *this;
t.normalize();
Vector p = t * Vector(0, 0, 1);
if (p.mag() <= 0.1)
{
p = t * Vector(1, 0, 0);
}
return p;
}
Vector mult(const Vector & v2) const
{
return Vector(
m_array[0] * v2.m_array[0],
m_array[1] * v2.m_array[1],
m_array[2] * v2.m_array[2]);
}
Vector div(const Vector & v2) const
{
return Vector(
m_array[0] / v2.m_array[0],
m_array[1] / v2.m_array[1],
m_array[2] / v2.m_array[2]);
}
Vector operator-() const
{
return Vector(
-m_array[0],
-m_array[1],
-m_array[2]);
}
/* Compute the dot-product of two vectors */
double dot(const Vector & v2) const
{
return m_array[0] * v2.m_array[0]
+ m_array[1] * v2.m_array[1]
+ m_array[2] * v2.m_array[2];
}
double operator%(const Vector & v2) const { return dot(v2); }
/* Compute the cross-product of two vectors */
Vector cross(const Vector & v2) const
{
return Vector(
m_array[1] * v2.m_array[2] - m_array[2] * v2.m_array[1],
m_array[2] * v2.m_array[0] - m_array[0] * v2.m_array[2],
m_array[0] * v2.m_array[1] - m_array[1] * v2.m_array[0]);
}
Vector operator*(const Vector & v2) const { return cross(v2); }
Vector operator+(const Vector & v2) const
{
return Vector(
m_array[0] + v2.m_array[0],
m_array[1] + v2.m_array[1],
m_array[2] + v2.m_array[2]);
}
Vector operator-(const Vector & v2) const
{
return Vector(
m_array[0] - v2.m_array[0],
m_array[1] - v2.m_array[1],
m_array[2] - v2.m_array[2]);
}
Vector operator*(double scale) const
{
return Vector(
m_array[0] * scale,
m_array[1] * scale,
m_array[2] * scale);
}
Vector operator/(double scale) const
{
return Vector(
m_array[0] / scale,
m_array[1] / scale,
m_array[2] / scale);
}
Vector & operator+=(const Vector & v2)
{
m_array[0] += v2.m_array[0];
m_array[1] += v2.m_array[1];
m_array[2] += v2.m_array[2];
return *this;
}
Vector & operator-=(const Vector & v2)
{
m_array[0] -= v2.m_array[0];
m_array[1] -= v2.m_array[1];
m_array[2] -= v2.m_array[2];
return *this;
}
double & operator[](int idx) { return m_array[idx]; }
double operator[](int idx) const { return m_array[idx]; }
static Vector randomVector();
static const Vector X;
static const Vector Y;
static const Vector Z;
protected:
double m_array[3];
};
std::ostream & operator<<(std::ostream & out, const Vector & v);
static inline Vector operator*(double d, const Vector & v) { return v * d; }
static inline Vector operator/(double d, const Vector & v) { return v / d; }
#endif

View File

@ -1,115 +0,0 @@
#ifndef REFPTR_H
#define REFPTR_H REFPTR_H
#include <stdlib.h> /* NULL */
#include <atomic> /* std::atomic */
template <typename T>
class refptr
{
public:
refptr();
refptr(T * ptr);
refptr(const refptr<T> & orig);
refptr & operator=(const refptr<T> & orig);
refptr & operator=(T * ptr);
~refptr();
T & operator*() const;
T * operator->() const;
bool isNull() const { return m_ptr == NULL; }
bool operator==(const refptr<T> & right) const;
bool operator!=(const refptr<T> & right) const;
private:
void cloneFrom(const refptr<T> & orig);
void destroy();
T * m_ptr;
/* reference count is atomic so that refptr copies may be made
* concurrently from multiple threads (e.g. the multithreaded
* renderer) without corrupting the count */
std::atomic<int> * m_refCount;
};
template <typename T> refptr<T>::refptr()
{
m_ptr = NULL;
m_refCount = NULL;
}
template <typename T> refptr<T>::refptr(T * ptr)
{
m_ptr = ptr;
m_refCount = new std::atomic<int>(1);
}
template <typename T> refptr<T>::refptr(const refptr<T> & orig)
{
cloneFrom(orig);
}
template <typename T> refptr<T> & refptr<T>::operator=(const refptr<T> & orig)
{
destroy();
cloneFrom(orig);
return *this;
}
template <typename T> refptr<T> & refptr<T>::operator=(T * ptr)
{
destroy();
m_ptr = ptr;
m_refCount = new std::atomic<int>(1);
return *this;
}
template <typename T> void refptr<T>::cloneFrom(const refptr<T> & orig)
{
this->m_ptr = orig.m_ptr;
this->m_refCount = orig.m_refCount;
if (m_refCount != NULL)
m_refCount->fetch_add(1, std::memory_order_relaxed);
}
template <typename T> refptr<T>::~refptr()
{
destroy();
}
template <typename T> void refptr<T>::destroy()
{
if (m_refCount != NULL)
{
/* fetch_sub returns the value prior to the decrement; if it was 1
* then this was the last reference and we own the cleanup */
if (m_refCount->fetch_sub(1, std::memory_order_acq_rel) == 1)
{
delete m_ptr;
delete m_refCount;
}
}
}
template <typename T> T & refptr<T>::operator*() const
{
return *m_ptr;
}
template <typename T> T * refptr<T>::operator->() const
{
return m_ptr;
}
template <typename T> bool refptr<T>::operator==(const refptr<T> & right) const
{
return m_ptr == right.m_ptr;
}
template <typename T> bool refptr<T>::operator!=(const refptr<T> & right) const
{
return m_ptr != right.m_ptr;
}
#endif

View File

@ -1,5 +0,0 @@
/* Single translation unit that compiles the stb_image implementation. */
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
" Vim syntax file
" Setup
if version >= 600
" Quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
endif
syn case match
syn keyword fartKeywords ambient ambient_occlusion color define diffuse exposure height jitter look_at material max_depth multisample ngon offset polygon position radius reflectance refraction rotate scale shininess size specular texture translate transparency union up vfov width
syn keyword fartObjects box camera cyl extrude intersect light options plane scene shape sphere subtract union
syn keyword fartControl for while if else elsif local
syn match fartNumber "\(^\|\W\)\@<=[+-]\=\(\d\+\)\=\.\=\d\+\([eE][+-]\=\d\+\)\="
syn match fartComment "#.*"
syn match fartIdentifier "\$[a-zA-Z_][a-zA-Z_0-9]*"
hi def link fartKeywords Operator
hi def link fartObjects Type
hi def link fartNumber Number
hi def link fartComment Comment
hi def link fartControl Special
hi def link fartIdentifier Identifier
let b:current_syntax = "fart"

View File

@ -1,3 +0,0 @@
if has("autocmd")
autocmd BufRead *.fart set syntax=fart
endif " has("autocmd")