Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ba0ebfe71 | ||
|
|
a3684b20b6 | ||
|
|
c1c8c46ac7 | ||
|
|
0a979c487c | ||
|
|
88bfc29323 | ||
|
|
e964908e46 | ||
|
|
bf09c094e1 | ||
|
|
1475434c4c | ||
|
|
e13608b287 | ||
|
|
c8f6d36bdc | ||
|
|
6b77b1a666 | ||
|
|
d7394027b1 | ||
|
|
68d5b39cfd | ||
|
|
0d36f13b17 | ||
|
|
88d482dcb3 | ||
|
|
d71be68fae | ||
|
|
1947ea553c | ||
|
|
7eaf5f9555 | ||
|
|
d761433382 | ||
|
|
e3d4c88f66 | ||
|
|
94105a883f | ||
|
|
c05f2b1b59 | ||
|
|
cc041168a1 | ||
|
|
05dfa4f977 | ||
|
|
8edec7e28a | ||
|
|
0319619724 | ||
|
|
d764740b54 | ||
|
|
a233b746c2 | ||
|
|
917bfe4821 | ||
|
|
6849d583ae | ||
|
|
6d102b8de9 |
No files matched your search
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
fart
|
|
||||||
*.bmp
|
*.bmp
|
||||||
*.png
|
*.png
|
||||||
|
/.propane*
|
||||||
/.rscons*
|
/.rscons*
|
||||||
/build/
|
/build/
|
||||||
|
/fart
|
||||||
+20
-12
@@ -1,19 +1,27 @@
|
|||||||
configure do
|
configure do
|
||||||
check_cxx_compiler
|
check_cxx_compiler "clang++"
|
||||||
check_program "flex"
|
check_cfg package: "libpng"
|
||||||
check_program "bison"
|
end
|
||||||
check_lib "pthread"
|
|
||||||
|
class Propane < Builder
|
||||||
|
def run(options)
|
||||||
|
@sources += ["propane"] unless @sources.include?("propane")
|
||||||
|
if @command
|
||||||
|
finalize_command
|
||||||
|
else
|
||||||
|
command = %W[./propane -w --log #{@target}.log #{@sources.first} #{@target}]
|
||||||
|
standard_command("Propane <target>#{@target}<reset>", command, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
env do |env|
|
env do |env|
|
||||||
env["CCFLAGS"] += %w[-Wall -O2]
|
env.add_builder(Propane)
|
||||||
env["CPPPATH"] += glob("src/**")
|
env["CCFLAGS"] += %w[-Wall -O2 -std=c++23 -include fart/common.h]
|
||||||
|
env["CPPPATH"] += %W[src #{env.build_root}/src]
|
||||||
|
|
||||||
env.CFile("^/parser/lexer.cc", "src/parser/parser.ll")
|
env.Propane("^/src/fart/propane.cpp", "src/fart.propane")
|
||||||
env.CFile("^/parser/parser.cc", "src/parser/parser.yy")
|
env.barrier
|
||||||
env["CPPPATH"] += ["#{env.build_root}/parser"]
|
sources = glob("src/**/*.cpp") + ["#{env.build_root}/src/fart/propane.cpp"]
|
||||||
|
|
||||||
sources = glob("src/**/*.cc")
|
|
||||||
sources += ["^/parser/lexer.cc", "^/parser/parser.cc"]
|
|
||||||
env.Program("fart", sources)
|
env.Program("fart", sources)
|
||||||
end
|
end
|
||||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
# The MIT License (MIT)
|
||||||
|
#
|
||||||
|
# Copyright (c) 2010-2026 Josh Holtrop
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
script = File.join(File.dirname(__FILE__), ".propane-5.2.0-58c963344c9bc893689cbae5e4c49b1b.rb")
|
||||||
|
unless File.exist?(script)
|
||||||
|
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
|
||||||
|
require "zlib"
|
||||||
|
require "base64"
|
||||||
|
encoded_compressed = $1
|
||||||
|
unescaped_compressed = Base64.decode64(encoded_compressed)
|
||||||
|
inflated = Zlib::Inflate.inflate(unescaped_compressed)
|
||||||
|
File.open(script, "wb") do |fh|
|
||||||
|
fh.write(inflated)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise "Could not decompress."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
load script
|
||||||
|
if __FILE__ == $0
|
||||||
|
Propane::CLI.new.run(ARGV)
|
||||||
|
end
|
||||||
|
#==>eJzsvX1zG8eROPz/fYqVksiABEKSncu5SNGOSpbuVI9jqSz5clUkC7UEluRaABaHBSgrFn+f/Zl+mZmet30BwVxyZ9RdLO7u9PTM9HT39PTL7+493tbrx+fl8nGxvM7W2/NP/7Iu/ntbrovsfrE+v2//qouN/GuzLpeXZXX/X6bzvK6zt+tqlS+Lf8myRTXbzovsea0a1OrvLKMvnj3L6mJ+gU+ybFZcZJfFZrDMF8WQn6kv87rI4JF58vGqWGb3V/m6Ltbj6RhRyszv/u/K5XS+nRXZ6f1nfzjOXpXzYnyugACMQbXdrLabyYV6OBzX2/PBH9a/np6OT/KDv509+v3NSDU6vT/M/vDN+Er9a2lgPas3s/Oqmo+vvvGezsvz4CHMAz48XT5+uLff6TJ7mL3dns/LaTbLNzn8va/fY8Y1e199ULMLc1WPM3g8rZb1Jpte5WvVO0zony/X+WKRr8erdXFR/qLmagNtJtjm5Cw7zn49XT77g/0OX9fjIp9eTT6Wm6tJuZwVv2SzKvuMr0YZPvisIKkhqR8tHL4bA1R4cX+EQIvlDD+7ObqLyf1JUVQ2rdQins+r6Yd67zPszB90NKGOxhfFZno1AOKzJHgn5LMur/NNkW0+rYq7GF5WXvgEMt6ucA/fO1Yjezs5vY9De/ww+7Got/MNzjfT2u8UCyiXRfZ28u6nFy9evnuXPdnKp9+9fPHmu5eTlz/++ObH7Knz6qcfXv7X25cv3r/8bvL6h7c/vc++TL1+/+b/e/lD9pUL+Mc3b7M/Oo9evnmV/asL493LHyfvX/74l9c/PFeAsj9tHZLEMT1fKmK+zuflLHv9Xab+sS3cob3+4T+ff/9aIfldNhjU5d+KyWZ48HR4F2v9bgMrXS7LTakQ+lu+KavlXfAM7Oz5XBEy9Jer6TB9Ftm8+KVYPyZmrZZ6uSl+2WSKQ26nm+26GENbbP9dIRoBjFmRa5DANBKshyFOZsW82BSDoQX4Z9VnvlCoKH6PD7LsPfSND8bBJ5N5sbzcXAVfZvRcwF0XCvNl9sIfS3ZRrZ3hYpvH3qYPMN8k2ar+Yll8HGzL5ebrCWwW4MYPCbdRRgTkjECR0q9mJ05XK8NV29HQy3OcqS7bvh8Mj4j853WxUx+D1o+HUySBwVMaaHXR1mSocTJbEpBS2/J7WBZvK9C+RBWD2h98Qyt+TPN5FHvJk6y/4T/9TxGbVVWX2M+6+qi+f7pt/mpazaNfLUAcHdPMInWN4cmknClpoXhKrlgoiYujgP9u1kXhzoNiucX6WulTAFSxoCdZXmebK/VgO59n+D28GjPdqkY+FRm8EqqAAjFZIkdfF7Bog6e8JplLKZ3hTKb5Kp+Wm08wO38KpqeteZrQ4PUE9CgktQWT2p+2ikgbqU20Q3oDdBbFQqm2gwed0Tp5cjbKnrTQdayn7vNmKBVpilaA90WwRZinMXD1+Y3k7U28uSt/f6WY44tHj0aqLb2t1rVi7IrqzosM9nkxQwaaLz8ZMFuAeVEW85nSD/6j+lhcF2ulLF4gwFWlWGKhgOSK9aovZ0phVB1X6i+N3EyNq66262lRj5DKEWB9VW3nqjMgdvVwgdDOiwtoCYgo3V09L+vsYruc4tb0ZQrjx7Li+8YZEMh0EGPA6odablxXSovoJPY6s11HODhs4sED+wCmZsJKPTAK1NxYb4syBVi4gZZFiuKebI/Uf5/1YBbIKoaq1aNHwxi7uHUPmlM7PfAegA5+pf9kNLpB941cno3LmmZraGEIcGm56HAgOu9MDGQ1yB7spDw7IkWj+EWduWcTUKoHqQUdZRe5mtxRtizn+D9DMw3wu6F/3jh8IqJQEPEJpiG1AUMngTDC5VR/dJ9jzfs6t5pelfPZWi2Iz/h8KJ6+cHMXavh3BSzG+s40b4Kf5dlP718dfE3HV2SOHXVh4JszhNGmFb+mz6Gl0Iq5wUm13Zxl6n+Q9iaIge5LsV7qYSbQyxSLRX49y64KxSgVsQCPZlGERyf4xJwF2zrzNHhUahbniidXF9n5p01Bio7oH4VGOxIMMEDFnAbUV+LEWi3VUtTbqRI69cV2LjukOfDaOWdaNG3lS0WQ6ksQRMV6rTif6rs6R81t5rWGUyo2AqyBjCsawMYur2q8BtsLtVWkw2w0vn8IRzGtPY4eo+ZDgFkogOKu3SjTvfhvnFON5s6uKg7SYBhwcV5CnKIjw9FQhQJb1lSr8EoTO+qMt/2D29jJ8RA+stgOptmD7MkvXyssU8ja5gqt6VHshafPifEAzw0gasQuKqV/fFSkNME9IEAL1F5q1H55YbCLSDEXS2z59NX2yP3I61DiK3DWeEssXhksXvbE4kkHLL7sisXXGotXfbH4t3YsvuqKxQuDxdc9sfiqHYs/dsXipcHiRU8snrZj8a8NWCT7Mtta8s04nIBTPDv2sUiPqUc/sT2queZw4I/7kdoPQwEopdn6G5cV19QSAE87NzytxG7OvCXAlT3H9YF9Dno9sSX3Mw90l9nwZsSdFZgO8dezZ9mfVOefM0blq1fOfFjtE/7z0JUGQF8+C34YFRjOly5PNoNhkX10R4ofHgzvQu1jc1aN9t3X36Exn0w28C+4RgNRdlkoiaX+nigKG7DpCJtMNvn5vMAjFyj+dISf0KtyNtnoqxWl75Ele+50F7dnf//yv17+OHn3/vn7l2DbFuYqv0/V5dYdyNZcuziDUYo5vKG1LeFMsyViskI632yK9bIeL/LV4MEhfzgcT6vFKp9u1ONfss+fsydD2A6o4ScnKOxJzI3zMjU/chTxOcILBNw/PEOR4dnJsTSUbdb5ksyEGc6j0vQ2609WC8VbBzVo0BiFvrnIN+okhOYMpdLmy0uyUecSHkIiQ8w039akncL3NCh1Nlitq8u1Umbh3xvU5OtNuUQTKtGEtlfouSXbh1HYYKZelet64+j+Sw8ptLhYvKxxtoNWdgHQj6yZU01bfofdzXOvt+/EjLh7pbkvf+PJqaXHwJr4MwtAUKBkBJIy2tbjNd7A8oIG1GWQpuV15ibGVSRqdpsfZE9xC/lv6frXmcAfzEEtSumlEpt9cZJcR3GH7NfP9ab4rFoXJ4dLMZn12Q2wCcTUee7SE28GuBtXnSzUcTHfJPFJ3ZBvCEIEsssBq0w9nG7hMi3eSYwrZfwvB/pfrwq1wnLmiCmoCc2ZVJmHWuDg5pDl6vy62tSC/nhCPdLD24k+lPfm4qIuzIaUlKuGfc6WXLPYC3MZAe1Bp/rqy8kmE4s7qRCgQBSvRwyegoviyFXPF1XMQP2epkibba+q+azOyF2E7ACKBtfVQvDG7co/6/NcIjzsrQNr/MEzUqh/lNbOog3bBM3MBOuLRq2RO9u01VdLYKjb5EhWbCBAz4oWktWtVTeq2QRhmNuq7l0u4bHgxPnFxuwkBbcHFg0YPEdqBUkn2a9ZLm/yHHo2Zo1cwwg4LzafAN0E5O+zK+oEAJTTCN+OPIJW0mkmwVHBgEMeMz43xW1nfWd+RdeZ6Ecnhygoz0DHGGVN34GE6/CZEFf49U3CRycUU5F50uvh/BWfHcnbzcRInhCbk+D9yWFcMomBR9q4sqPxUyTyM1BAT+9rFRCdT5T6h7cpyZbMyr22Un1sbs/cG9BrWRPLvyNLQpzU+SO+IPadXQ/7LLoc/uuTw5CpN+GPPPYli0krPvO6rqalvW7zpZxvEu9zlTd2G+ISCWuzktxsfN26bmRCoDsgiK+I7v+ConlGrNTIQIm629QxeDuNQ/M8mlVJDQFOJgfM3BgFo5LLWt8PXV7IN1CNhuhrlIFpms9ADMOfgFlFbmaqr2W1gdupeTktN/NP+hSeszTStmmiv2YtylN/ul9/jtrVp1Hm27vtMo0c4SvXYNSIMYkONm3bR9amXStaVdtmoA+wxpor3SjNYddsMX7y2blw0+TCsKzDBfjgAZbhB9tD6su9PZTfuTeG/MbeGt5k5+si/9DgZgBfsbfKofmY7TyOVcZnlL4vwourQu0oorM1XhA5x1kj86fb9VoxFkchAMpVVHhFVpkMnIJncF8D31+W17gHQJVpuEJjsCSfmLBfhF2FrELeh71O98Kz8L2LtVQzKtx2CbOLmpdltSy83RScM6cwiRNfGRkY/doZ5cjq3XYklnbNy7g0VaIilOgO/LNA2zEnRICP9lHTibSQtsJ1z3PCgOpd9g8SalliRI+y8myMqhRYlMWcZA8euDZQx+x5nNL+mroBTWzYaqXeAXDM1KChuiZYb2O6FOdvz1eqCzoiVctL1YUrfvkIhqdau0WNC9y+hLO9HbaquxDUGjV7HlwvyHjT6UaaIYkb37VnGI/jslVHoVUxVarJJOZxCmLTfOH4nvZEy/eEdriLc1fNTZ6z8P6Y1+Iwq0Q0rN1s7DaV4xSo07XxGi+ut+CXhWNg1QAWSt9oe+B8ZB0OiQ1Bg0DdgWln+Smi0rk34gKv+JU4jJTvxD1WybL9QpHxhOmEiGhHJUOeHVkBsI/MJfrDJgKxrDYC0sHRc0Z03klvQ+eF8SyMQIcZXqzi0J13ErrzwkB/6A4dxEIE9bgEMjJEnEEc/9izcXh4kOLj6Chk/Dz1pOXRfGuB5bn8aq7pDGzsXClp3AM/CceLi+/mLFB5QRfxpwhR4ecHEmEBYxcPBhf1+I2ZwG9NQRvHnd1H2F3E8ROBObGuHw+CbuV9oNaNqeO4KETd1rC1Q1dGeiIzUIaElNTUltCPPLVISP7IRWsA9t5xQoa2X7/GKC97lL7hTLcNTXlquO4ngZ3Nh0j+kfZK9jj74vR0+cUw/DIylBAltz/wln/0KNJra0PPgV7+bsJHrpPBbRBW/UYRjnTqczWfRhKT3arosr1n1xXwTJ/As9q6TCyQw9N9ymqfI+9P447igNX0/032pH3ndBM78hfxDmhBsRsSCekebD+9uzttboOsr0c1Y+39qc/jAUNVupTHTB8/zP5aZFflJlPvrEld/263WAw8vwZvVtYLine truncated
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
# Copyright (c) 2013-2022 Josh Holtrop
|
# Copyright (c) 2013-2025 Josh Holtrop
|
||||||
#
|
#
|
||||||
# MIT License
|
# MIT License
|
||||||
#
|
#
|
||||||
@@ -24,23 +24,515 @@
|
|||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
script = File.join(File.dirname(__FILE__), ".rscons-3.1.0-4892f95d56c30bbe9aa0c9964062ec5b.rb")
|
BASE64CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
|
||||||
|
def base64_decode(s)
|
||||||
|
out = ""
|
||||||
|
v = 0
|
||||||
|
bits = 0
|
||||||
|
s.each_char do |c|
|
||||||
|
if cv = BASE64CHARS.index(c)
|
||||||
|
v = (v << 6) | cv
|
||||||
|
bits += 6
|
||||||
|
elsif c == "="
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if bits >= 8
|
||||||
|
out += (v >> (bits - 8)).chr
|
||||||
|
v &= 0xFFFFFFFF >> (32 - (bits - 8))
|
||||||
|
bits -= 8
|
||||||
|
end
|
||||||
|
end
|
||||||
|
out
|
||||||
|
end
|
||||||
|
|
||||||
|
script = File.join(File.dirname(__FILE__), ".rscons-3.4.2-b1e276fdbe6b603498fe893d904fe368.rb")
|
||||||
unless File.exist?(script)
|
unless File.exist?(script)
|
||||||
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/
|
if File.read(__FILE__, mode: "rb") =~ /^#==>(.*)/m
|
||||||
require "zlib"
|
require "zlib"
|
||||||
require "base64"
|
|
||||||
encoded_compressed = $1
|
encoded_compressed = $1
|
||||||
unescaped_compressed = Base64.decode64(encoded_compressed)
|
compressed = base64_decode(encoded_compressed)
|
||||||
inflated = Zlib::Inflate.inflate(unescaped_compressed)
|
if ENV["rscons_dist_specs"]
|
||||||
|
require "digest/md5"
|
||||||
|
if Digest::MD5.hexdigest(compressed) != "b1e276fdbe6b603498fe893d904fe368"
|
||||||
|
raise "Hash mismatch when decompressing rscons executable"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
inflated = Zlib::Inflate.inflate(compressed)
|
||||||
File.open(script, "wb") do |fh|
|
File.open(script, "wb") do |fh|
|
||||||
fh.write(inflated)
|
fh.write(inflated)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise "Could not decompress."
|
raise "Error expanding rscons executable"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
load script
|
load script
|
||||||
if __FILE__ == $0
|
if __FILE__ == $0
|
||||||
Rscons::Cli.new.run(ARGV)
|
Rscons::Cli.new.run(ARGV)
|
||||||
end
|
end
|
||||||
#==>eJztff13GzeS4O/5K9ptJyZlirIzN7PvMVYkW5IT7cmWT5KznqUZDkU2pR6T3dxuUrJW5v7thyp8VQHoJiXbuey+87yJ2PgoAIVCoVAoVD18sLUoi63zNNtKsquoWJzffFck/7FIiySKs2S+dTmfz2KbNEovknIefzfNR4tJEp2Uwzwrv4si9f0iK1PxFUXDyaAso+fPozKZjDElik4OTg/Oou0o/pB0n05jlTpKxtF1kc6TRpq3oo1pUpaDi6SpckV+3h/mk7wQFWVr7cFsNkmHg3maZ22ROxBtyiKmTjo21dpZOtkxGQycqrsjGrbNJdnI/M4Xc+huHIJLQA4XRZFkc9tNGCdtMikF7kaV+WrI7WQwvBTwo8/TzyQXW52207I/2Gmczos0u2iy7CiapFlSCsDTdikwM2/EH7K4FW0+C5bDZvrX6fyyn2aj5BO2CDmtKP3sVMC2IS96wPDA8vnwRUE23kAdidgn6xR0UbuqBp09rzkYiJcbqiEGlUbPFbrK9D+TaDN6tubg3cn1elFdYBUdrTVImPs1BummJJPSxc1wUCbR1Em8vkyyqCOm4Cea6lI4rvCf/vJs6nZFVr8okiT7aWX1Hyuq3ySTSX7906rqf6mofj5ZJLT3FdX/V0X1qViq2Xzw04rqf62oPrwZZGu0/reK6teXglOuRt2/VI09n4zo5IWqP6ueOKhOJ6+ietXEQXU6eRXVKydOVKeTV1G9auKgOp28iupVEwfV6eRVVK+aOKhOJ6+iet3ErSKbqlkrkjKZ19BMiM94/IF986/12GAF+6OgHCb0xfuianK65kjo7zRvS6FEwNBgbf6sSK8Gc91XkGCCsoTo4Mm7l3/vvz16cfbq+OR1tP1f0dZUdPT687S8KbdIPxoHb37rxmcHJ6/jXrQt5vPTPCmmcTP64Yfo++vuOB3n0fByUAyGIv10lgzTwaTXTrPhZDFKoNV2OR/M2+P5zYzITg5CRan5/GYnMGD9S/6F/8L/jdQn6McX+aSI98IKYwhhMJ8X/SIZjJIi6ojepldJ/2pQpINsXtoCg+FQTK4glc75Ip2M+qO0CGX60p1TIOvPL6Gx0m+7HBbpbB6qVKYTSavZOL1YFEmozFVSnOcKeTC/QlZK5wLnQhhQKNt1wYiVNC8WJtsMTKTj5J6c7h2/Oe2/fHd4tN/fPzwRE/35cxRjOb1wRcH2KJkkgvD88nped82oBeh383QiqgC1CHGlzxEiyirc9y+KfDGDCt0emWk5uPmg/NhPPiXDBUxjf3Ypdn5NJbuhTA9CscgaBRIGYr2FIMXKzEb9mSDaadmKysv8uo/JrWgwmeifSTY4nwhmpGlED3JPLPpEELgg62yYdOPxIJ0gz5pOBdQSVokeiuokbQ7mwknSRd0GRVE36TuzfP3CIAfDonzgwreLMTYkETNeMIQh9QPtu2PV9XFV9UeD+SDudWO3YtwjSzs0rHB7NasfiBrnT1Q+xR/tLLm22BBTuBA0PckHoz5ZXqRiG/IoJdCDFfTD7YZtWsJXJGJqYZIEJXMahnYs6CKZL4oseurBhJPiDZZWk9QYDwRLbNbRNl/G6dgjpHYynVEuKpA8FPCLHHiHQPdVWuTZNKGoFlDOBJQ2gurGYsUMFpM5m0DIJzltCVX2LQnNGWXtfhf1lokjzAZTcbqTWZ/dNk2JNdo0v556HCA8vYtsIpAS7Zp0TY4UNT7tuqfN5JPYScTEPGgE6Fzsqb83Pjz5vNncogJAYEF4lfV5uRXTmiVsr+OU171d1sC2+OZo4PIKz6Md32m0N5qPtkKlR2kJf1uRZuQwVaI/j561okc/shp+v7u0Us9wOg0U8bzJEM2FI9AU6O7C6ILDgoXrtWy5oUrpdrAProhmchVKoZPV41BAehxRkxI4NZDIGsCRAdxDIPRJmDMKW1atohDbpQsGORvsaloCiSJnjwvsDN4uGK4Z1PGoTKbmAX2dEnQflfOREHZbeLpvRfErBBmpWlHj4W0aPYmeLbce3rqtgYpk2ezELXXWaKEWwk61At2eLcRSQoFFVe3P837ZUB+umE2RNZwkg0zjF3Di4YZmCj5bXCRzze0pN4R0O3xZukimuZBSZWZD/rGdfyXGCn0u28W0P3ayyawjKCHuJcN5XqSJaVyIk/Po9vOgFZ1/js6lOun59s/RQKLNdk7Xvanon8lvmF+2l1nyaa65LfTY9ORmJ1RcLJjGflq0xS6FfbVFos2o+7j9uBU9brcf95ruZhdFUK2Yigq0kpj24SKJsnRSu23I8SC9eVMseNJ8/Wl2C7YhRWsE2ZQV44aVxZs+ZeFq5WeBkOAAS93Oes1et54wZxocESkA9kIlRw0W8xzKEMS7faw+v9GR1cglZnNWZcSSDkovBzax26Nb3RXdCMRnWwGqYKDhZsJslA3EGbjpt0UiacUmcsiAQCAnnX08A+G2sevKqefJRZqRcekZMXAFv6KiJxK+PBQfFAUoVH6OEjZtgjbFUZKLnlh3kApxMzSd/vFn3SNBSMr5zusKJ2Yf44sMW57o1XwHlougv4zjerws+SR4w45XDreT+ARgpdlF9PBWFljGsJDoAR7+3ZuNywH9T+PiHu5M3TD6vh3fV1TakIeUfAYELgVuPVBgiyFNEvx78MDNao+FyCOmSsuqEZcd4QQPP7Q4z85R0BJXmPiYY/nBtWvHoH61R6SkSjPdwd74uURk1VDGyXx42eioM2IroquY1PyY3ARqidQWNmVruEOdDEqBJY3HHtzeKiA1rELDUP018n6ftrX6IJGOA/NEQVG+KY/7nnRfS4JW7g/1HjHQ2BBMoWxFP5xP8uFHQn2QLMiqKOcV6mZ1JsNy5SQdJg8aT33eYunCAgQVoDlauso6OwHtaSL4Fa6RTiRXip6nTtTtkb5i3+1mBl9GTRaaPzwkaFgNb+iVC09uXjGrLtZ5luVzsYWKXxM4PUB2mkUDkXqZFLwx2bnYQ9PqRbh+21GWG0TBcNMsGQVanCdF/+oCZmYymJ6PBkijMlVVZpTKcuReIKjV7XRpdcU4uQ4mRWMcjjgGzfgZls9eBRDGe/nZ1ulR1+93j6x3u4dVHfOrVxzHI29InBr1+d09ua9x8vZnqdvtcRU2vY2xgm+FFOSRljNomf6Z9ESCGeYL0NlwjkGxJwtUoG8dXsUUzqq5baPUhH/qQgyu+94Qutb6iLEQPjWTxe5RzU46druObJbNh4YPZgRCJAiVB+FvJnb/ZbXWSK5OIhGjnO3Z9dQfXuiOcc+Zq5ypOjq/SZPJKOINr+rrGjpqKW6BvrXsaMyh9rWHkmVQXws/GduBhPYokS2JXQH2DtOSK9t9343EFJZibWTzcSP+fvPHfyljCVRuzUsUmDnEJaUHzHT1yfhNFcqcSYiNrT8HIRYUi5sPb23xJb+bFsPBPHFu+JiIPbW4cHiJgQTEuE0htRczME1xALoX1gYJLhr+CmiIH97qBpYxokL2pgoXq3iTPpLW71t3pWBNNx+y3+iyDq/MaEcs2sfhvOXjOOpEcbzsUKTda4HoPkWWQehGSIKRXqFTDfXVVJ2oYh31q8xXyeSZSDDHcnaps/IyhMCxo1OzyOHCZZ+piBpze73nrBavQW+1CJY2WSTexop5Ys24FzISXteCcXdct0KZzPukoUZFB7gWPmD7Febh8bvsY5ZfZxIU3DlHbGHqvQF3IuiVYjGKATRrFuz6dFB5CamOBXAqQhmy/t7OKX1vrZ2Cg8cLPJD77YqjVykO5N9fd42OUyowrZ7FPaIbvRU3yAibYLwclOmQKOkMqqzNQiN0rgZ2JAhGpAn2cprgZW9Dwu509g9evXh3dNYHG4Szk3d7Z4fHb/q/vTg5fPHy6OBUg8BZ8HH1QLfHytklInd2wRPKB978dnsNgTCnj1041HpFLwS1i/xA+baXxZvYbuB5WCyGUEMo5k1CHEh8NnAFlW6DgUwmz3yaAUWIwkUybsg/LZE6LwaQqAR5DVSmMLnQlHQNmlUH6s4A0D95gLRgQoKYPPzAZoyGIkl21UH7bTxsioMm/LdHutgOj4qA4YgQpDgo+4JxXOYjbfljbqU6DJhB3Ay63x9PBhdlA/9LDqf4Le9RHzg3qCpLcItkMmk8euafxosreqt7nRd44XYK5fFD3Q2zNsuP6cy5Q5RlQ/dtkMMu2+CiVAAgkxOAB/9ADRg8IEgi48dUgS8kZLqpFFdw4gL7ImIkQzOeWAp327gUkzBJVreBB4oJUmOEB4+JrysDMpkIUIikLt4f8h1MIYCp6QPmhQAFLiHhgF/RkERNF3sq/jvprRbfEDR0Da16NgfF8NI7MdX2XrUZ7+29Onrxy6mQK7sKDGKrFy59tL+6NMdACEvy1lv2HhbAw1vN8uK9t28F9357cvDq8L0Qbj3bAjnDXVXu8M0B9OURGRuFDZhRd/lfATka0peOGHtV3pRFns+/Rrc0qLXnrabGF83d4Zu9tSbu7YuzX2tmzYF6dPjy6PDN/14NWRSsIwYf7P7hyVpQV/QX5nOa5ZvDm4vrlD1gCMwXVGEYD8yQU8ZrS7Qyyq/LUEvrQ5lJW8tv213A+ea/DVoedjWYF6cazKNnxKCpDtqkGprt1NrQZtXQBKWuDQ4smIs57qI7jXiTHRdWo7UKzpM7wllzepJQBbl4vNIBfUFx5UmIRNB5wKUOLctUikIo24Uy8MNrqb64lGVmg7TArV/LyVyMEUIhE7HVvciLohjcNHGrhm2aJlKWKGpLOdsVQzhebbkqaSV0PhwtplrEkqJv/3JQXkbbRhKe5/1LvwCe0lAZ1z+/afzQAcukJtOEMM1iv5wXUhusr4Rupuf5pBntyDR5Eo5QZjb1gtZW8KakpUESCyqwI0CNiu4hSm7mjE0MrEJYWPdgJtXC6xshQ2FusaKuI/UpBv50475OjZ2VRTQrtFcUSPgtpmjJ3HAuSqYIQQJrsFwyc+LT07eINNZfB2B9X3Xlr6POqG6HtpHqVcuwjEkLine truncated
|
#==>
|
||||||
|
#eJztvWt7GzmOKPy9f0WlkulIji0nPTu776NO2k5spzt7nMuxnT6Zo3g0slSya6Lb
|
||||||
|
#Vkl2fBztbz8AeANIVkl2knl79zmZ6UTFCwiCIAiCIHj/3vaiLLbP8sl2NrlMisXZ
|
||||||
|
#9Q9F9h+LvMiSdJLNty/m81nqkgb5eVbO0x/G08FilCVHZX86KX9IEv39fFLm8JUk
|
||||||
|
#/VGvLJOnT5MyGw0pJUmODo4PTpJnSfox6zwepzp1kA2TqyKfZ418uplsjLOy7J1n
|
||||||
|
#TZ0L+dNufzqaFlBRtdbqzWajvN+b59NJC3J70KYqYuvkQ1utNclHOzZDgNN1d6Bh
|
||||||
|
#11w2Gdjf08Uc0U1jcBnI/qIossncoYn95E1mJdBuUJmvu9zKev0LgJ98GX9hudTq
|
||||||
|
#uJWX3d5O43he5JPzpshOklE+yUoAPG6VQJl5I/04STeTrSfRctRM9yqfX3TzySD7
|
||||||
|
#TC1izmaSf/EqUNuYl9wTdBD5svtQUPQ3UkcR9tE6BX3SrqrBRy9oDjsS5MZqQKfy
|
||||||
|
#5KkmV5n/nyzZSp6s2Xl/cAMsqgus4qO1Ooljv0Yn/ZRsVPq06ffKLBl7iVcX2SRp
|
||||||
|
#wxD8zFN9DqcZ/vOfn4x9VFT18yLLJj+vrP5TRfXrbDSaXv28qvqfK6qfjRYZx76i
|
||||||
|
#+r9UVB/DVJ3Mez+vqP6Xiur9695kjdb/taL61QVIytWk+7eqvk9HAz54sepPqgcO
|
||||||
|
#q/PBq6heNXBYnQ9eRfXKgYPqfPAqqlcNHFbng1dRvWrgsDofvIrqVQOH1fngVVSv
|
||||||
|
#G7hVbFM1akVWZvManonJmUA+iG/5tZ4YrBB/HJQnhL56XdRNjtfsCf+dT1tKKQEY
|
||||||
|
#BqzLnxX5ZW9ucEUNJqpLAIJH71/8tfvu8PnJy7dHr5Nn/5lsjwHRqy/j8rrcZng0
|
||||||
|
#Dt783klPDo5ep6fJMxjPz/OsGKfN5Mcfkz9ddYb5cJr0L3pFrw/px7Osn/dGp618
|
||||||
|
#0h8tBhm22irnvXlrOL+eMd3JIyiUms+vdyIdNr/Uv/g3/me1PuCfUOVTKt5zp4wR
|
||||||
|
#hN58XnSLrDfIiqQN2OaXWfeyV+S9ybx0BXr9PgwusEr7bJGPBt1BXsQyQ+3OKzDp
|
||||||
|
#zi+wsTJsu+wX+Wweq1TmI8Wrk2F+viiyWJnLrDibauLh+IKulM+B5qAMaJLt+mBg
|
||||||
|
#Js2Lhc22HYN0Gtyj4723b467L96/Otzv7r86goH+8iVJqZyZuFCwNchGGTBeWN6M
|
||||||
|
#667tNYB+P89HUAW5BdSVriQIlNW0754X08UMK3RO2Uirzs175adu9jnrL3AYu7ML
|
||||||
|
#WPkNl+zGMgMIxWLSKIgxiOqbBBJm5mTQnQHTjsvNpLyYXnUpeTPpjUbmZzbpnY1A
|
||||||
|
#GBkeMZ3cg0mfAYMDW0/6WScd9vIRyazxGKCWOEtMVzSSvDkcCy/JFPUbhKJ+0g92
|
||||||
|
#+oaFUQ/GSXnPh+8mY2pZIhWyoI9d6kba9/tq6tOs6g5681562kn9iukpm9qxbsXb
|
||||||
|
#q5n9yNQ0flD5mH60JtmVowYM4QJ4ejTtDbpserGKLczjnMA3VoiHj4ZrWsHXLGJr
|
||||||
|
#UZICpXIalncc6CKbL4pJ8jiAiTvFayqtB6kx7IFIbNbxtpzG+TBgpFY2nnEpCkTu
|
||||||
|
#A/xiirIDyH2ZF9PJOOOkBignAKVFoDopzJjeYjQXA4j5LKeloCrcstiYcdEeomiW
|
||||||
|
#TOrhpDeG3Z3K+uK3aUus0ab99TiQAPHhXUxGQJRk16YbduSkCXnX321mn2ElgYG5
|
||||||
|
#14jwOaypf2t8fPRlq7nNFYDIhAgqm/3yZsprlri8DnNZ92ZZA9vRW5JB6isyjyO+
|
||||||
|
#02htNB9sx0oP8hL/3UyMIMehAnwePNlMHvwkaoR4d3ilUyvpDFCi85YgtFSO0FJg
|
||||||
|
#0MXeRbuFEzdo2UlDndJpEw6+imZzNUkRyep+aCCnklCjEiU1ssgawEkA3EEhDFlY
|
||||||
|
#CgpXVs+imNjlE4YkG65qRgNJEm+Ni6wMwSoYrxm18ehMYeZBe51WdB+U8wEou5u0
|
||||||
|
#u99M0pcEMtG1ksb9mzx5lDxZbt+/8VtDE8my2U439V5jk6wQbqg16NZsAVOJFBZd
|
||||||
|
#tTufdsuG/vDVbE6s/ijrTQx9kSYBbXgmyNniPJsbac+lIaa77qvSRTaegpaqMhvq
|
||||||
|
#H4f8S+gr4ly2inF36GWzUSdQoO5l/fm0yDPbOKiT8+TmS28zOfuSnClz0tNnvyQ9
|
||||||
|
#RTaHnKl7XYGfzW/YXw7LSfZ5bqQtYmwxud6JFYcJ09jPixasUoSrK5JsJZ2HrYeb
|
||||||
|
#ycNW6+Fp01/skgSrFWOowCvBsPcXWTLJR7XLhuoP8VswxCCT5usPs1+whSnGIiiG
|
||||||
|
#rBg2nC7eDDmLZqvcC8QUB5zqbtRr1rr1lDnb4IBpAbgWaj2qt5hPsQwjvI9j9f6N
|
||||||
|
#96xGL7GLsy4DUzqqvRy4xM4pX+ou+UIAny0NqEKAxpuJi1HREa/jFm9HRNaKS5SQ
|
||||||
|
#kYDITib77QyV28aur6eeZef5hPXLjIiFC/KKq57E+GpTfFAUaFD5JcnEsAFvwlZS
|
||||||
|
#qp5Ut5eDuhkbznD7s+6WIKbl/BCgIpk5pPhiQi2PzGy+hcgl0F8ncQNZln0G2bAT
|
||||||
|
#lKPlJD1CWPnkPLl/owosU5xIfAOPf+4sxlWH/rtJ8YB2tm6cfN9P7msubahNynSG
|
||||||
|
#DK4UbtNRFIsxSxL+uXfPz2oNQeWBoTK6aiJ1R9zB4w+jzot9FLYkDSYh5UR+dO66
|
||||||
|
#PuhfrQErqdMsOoRNmMtUVgNlmM37F4223iNuJnwWs5qfsutILUjdpKZcDb+ro14J
|
||||||
|
#VDJ0PMXTWw2kRlQYGBpfq+93eVurNxL5MDJOHBSXm2q7H2j3tSzo9P4Y9kSBxgYI
|
||||||
|
#hXIz+fFsNO1/YtyHycBWRTmvMDfrPRmVK0d5P7vXeBzKFscXDiCaAO3W0jfWuQFo
|
||||||
|
#jTOQVzRH2omaKWac2knnlOFKuLvFDL+smSw2frRJMLAaQdcrJ55avFJRHeb5ZDKd
|
||||||
|
#wxIKv0a4e8DsfJL0IPUiK2RjCrk0INPqSbh+28lkagmF3c0n2SDS4jwrupfnODKj
|
||||||
|
#3vhs0CMeVam6suBUkaPWAuBWH+nS2YppcD1KQmMSDmyDZnIPK0evAoiQvXJv62HU
|
||||||
|
#CfE+ZfPdrWFV2/zqGSfpKBuCXaPZv/s79zV23uEodTqn0oTNT2Oc4luhBQWs5XVa
|
||||||
|
#pX9hmCgw/ekCbTZSYnDqqQIV5FtHVgmDs27umTVq4h99IIbHfW8YXxt7xBCUTyNk
|
||||||
|
#CT1u2cmHPuokZsV4GPjoRgAqQaw8Kn8zWP2X1VYjNTuZRkx6duDXU7954SvGHUeu
|
||||||
|
#cqTq+Pw6z0aDRDa8Ctc1bNRK3UJ7a9k2lCPr6ylpllF7Lf4UYgcTWoNMtQSrAq4d
|
||||||
|
#tiVft/tTJ4EhLGFuTObDRvqnrZ/+rUwVULU0L0lhlhCXnB8o07cn0zc3KEshAQtb
|
||||||
|
#d45KLBoWt+7fuOJLeTYN3aE82Dd8ymBNLc49WWIhITM+45Baixm6pngA/QNrSwSf
|
||||||
|
#DH9BMqT3b0wDy5RIobCposUq2WS2pPXr1m052PDNx8nvfFrHZ2ayA5P2YTxv+TBN
|
||||||
|
#2kmaLtucaHeaIAanxAkI0whLsNorItXQX02NRJXoqJ9loUlmOoEEuy0XhzorD0MY
|
||||||
|
#HNc7PYoSLh722YpkMXfHe95sCRoMZguItNEiCxZWyoM54x/IKHgdB8Zfcf0KZTbv
|
||||||
|
#soYaFQhIK3zE9ysuw9P3k0+T6dVEgcIz50RMTLM20EqEWGkRowVAs2bCrs8HlYeQ
|
||||||
|
#eluAuyLSIevP7bzSd7baaTi0vaANedgubL1K2JD/6apjbZzKgOnsLP4W3dqtpENG
|
||||||
|
#3AXjRa/M+8xIZ0nlfBYasX01iiNgGEgD8XKc0WFvQ8Fut/cPXj5/f3jSRR+Ek6P3
|
||||||
|
#eyev3r7p/v786NXzF4cHxwYEjUJIq3umPVHOTRG1soNMKO8F49s5bQDBPBw7uKkN
|
||||||
|
#ip4Dt0N+pHwryJJNPGvQfhgmQ6whUvNGMQkEnw2aQaXfYCRT6DOfZ8gRULjIhg31
|
||||||
|
#zyakzoseJmpF3gBVKUIvtCV9h2aNQN0eAPFTG0gHJqaIqc0PLsbkKJJNLtvkv02b
|
||||||
|
#Tdho4t+nDMVWvFcMjCQEsGKv7ILguJgOjOePPZVqC2CWcDNEvzsc9c7LBv3NNqf0
|
||||||
|
#rc5R73knqDoLpEU2GjUePAl348UlP9W9mhZ04HaM5elDnw2LNstP+cw7Q1RlY+dt
|
||||||
|
#mCMO2/CgFACwwYnAwz9oBoxuEBSTyW0q0IsYmS8qxSXuuNC/iDnJ8IxHjsP9Ni5g
|
||||||
|
#EEbZ6jZoQzEibkxo4zEKbWXIJiMARUTq0PmhXME0AYSZPuJeiFDwEBI3+BUNKdJ0
|
||||||
|
#CFP4e3S6Wn0j0IgaefVs9Yr+RbBjqsVet5nu7b08fP7rMeiVHQ2GqHUaL324v7q0
|
||||||
|
#pECMSurUW2GPE+D+jRF56d67dyC93x0dvHz1AZTbwLdAjXBHl3v15gBxecD6xmEj
|
||||||
|
#ZfRZ/jcgjoH0tT0mrMrrsphO598CLQNq7XGrqfFVY/fqzd5aA/fu+clvNaPmQT18
|
||||||
|
#9eLw1Zv/sRoyFKxjhhDs/qujtaCuwBfHczyZbvWvz69ycYEhMl5YRVA8MkJemaAt
|
||||||
|
#aGUwvSpjLa0PZaZ8Lb8vukjzrf/V2wyoa8A8PzZgHjxhDk110EbV0BxSa0ObVUMD
|
||||||
|
#Tl0bHHowF3NaRXca6ZbYLqwmaxWcR7eEs+bwZLEKavIEpSP2guIy0BCZonNPah1G
|
||||||
|
#l6lUhUi3i2XQR9BSfXGly8x6eUFLv9GTpRoDSqFQsfW5yPOi6F03aanGZZoncpEI
|
||||||
|
#tZWe7ashkq6uXJW2EtsfDhZjo2Ip1bd70SsvkmdWE55PuxdhAdqlkTGue3bd+LGN
|
||||||
|
#nklNYQkRlsVuOS+UNdgcCV2Pz6ajZrKj0tROOCGd2daLelvhnZJNA5J5UKEfAVlU
|
||||||
|
#DIakudk9NnOwilFh3Y2ZMguv74SMhaXHij6ONLsY/KeTdk1q6s0sZlnhWHEg8buY
|
||||||
|
#0JI94VyUwhBCDNYQuWzk4DOwt0CawNcDWI+rqfxtzBnV7fA2cjNrBZUpiVFY70Fd
|
||||||
|
#yXDXk5ttrISk0hgoLiNYhShAJZcEPEpi4FwRYRyDtJKOUoXNkwtCXmjdswO15/O8
|
||||||
|
#Cimx2x8P5L6akgFtq9Mc/3ZweCjWDMQkKIFLQ9pEC3xDg0DD4HiQosVzu0+Wzq2+
|
||||||
|
#gNOhgpsEr3It0VecsTHQMOfZuEu1Ij1/9bY1m8LANDobtm+bxl3ztKmOMKdMbE9b
|
||||||
|
#qKyskhnVRhp7YrH6sMIdHSh74+1MoiT3U306QabDtjxJOFWLoam7ki2M+czeZxrm
|
||||||
|
#o2yBzkCVF9lfoHEiK8qfNQhtaVOpBDp2w11ZetDEMuvNL4K5gtnCl6FczLLCqEXt
|
||||||
|
#tEkuGBUjJC43KfelML13VlZlldNF0c8iF6WgTmUeOe6Eydnk0iWyS1MwWSMN54Os
|
||||||
|
#mw2HsGrV3AADXp9ZTgwNl8y6j91z/i0dTQt7FciSwFyOgoTpaDHPaEwau9Lza1d3
|
||||||
|
#HQp7y4jOsL4Vu45OqEzon61xb0Z8rb4dG0eaVkVCEbpr3Ots25Rge4SBGZ5xz6BL
|
||||||
|
#m6WFrs3jFrpdTng0bWXuOg+f9owjSa8jxm7ZVKFbZbgSlI0NWAMLWONnblzQ/dNk
|
||||||
|
#axpvJn45oe8WMNOAgo0NjqcV1yzNCQ+W6ijNErvKhkiun7GxRyRVkQar1WQuUVii
|
||||||
|
#yM7zEp0NWJlGrBVWT9AahUKkeI3oxftzHqdrJ5eTi7xMtMl0vCjJwWV6mRVFPhhk
|
||||||
|
#kwSda0CMnNGgpREi55N5F6B39fk7rFao4rJzTrtmiKFUFc+UvJMAyCC8CozonKGn
|
||||||
|
#LlGDQ9wB0NwW4HlO/XAzllRqt7R61aCAWlH1N64iN1ChHUBYBlN0LTrueoS86uXz
|
||||||
|
#7nBaNPZUOp2v2I4qOno4NkPqoT4+6BWDO1PPoIU3AtUvM8esNAuEHio2u3xVUG5Z
|
||||||
|
#yo9zMcN7G6CkZjtuqu+6jqlqm8RIbopwJ2+u8+hDV634zC6mk2vtGLzjC2vVG8Jh
|
||||||
|
#/GmQF91Zw3jJoriyxXl5z+83gMg19XUYddendd0ubJhPaBWzAGPjc7th2DXexBpV
|
||||||
|
#mqJrD4N3rqhdAA2foq+eswao9ZCnrXUYqUQG15S8Fd0IFSoPa4T5Ns6X+lN4Iu6K
|
||||||
|
#SkAq8e0X0gdY/NMvQtBZGec2KZZGmLAb7hzLx4Mm9Mau7IBxIt2NdOQWBITVOnma
|
||||||
|
#/Ab7/koadtV6m036OY5zdBlFBbMhsRfVDAlEYoUCEShynFRPn5qBtW2jGq/TWlYr
|
||||||
|
#8w6lqgrBEnrGWIi35PTFEnTMcQ/IMjln4GBuoGLReKz2QEVWkrd0w0wRDbdsOhVC
|
||||||
|
#lUke2TztzXfz5exLcu9Mm3jM0bjZG8CvHqzD0GN/wfAPqfFAzy6mIDtxudcXJqAj
|
||||||
|
#OWzeKJPtcaEQJSHZsU/k1O4uVLheuE6gmuU42jgsM631UdKIcEDHjQt6EqN5rCdg
|
||||||
|
#tnqj0Y6625AJ56R7FX1wdz+hAu6RWR09RLUlBN/JonUmAOUjp+nGtqKSXkChjaCQ
|
||||||
|
#zgyo5zbPQ5dD/r6/iIBQLs9z/o7aNE2Eh/qliNxK+BzwekqKmEHmsTK6VoxH3H16
|
||||||
|
#D/1o6EiVmKuHSig5aplWW8m7aVnmmNLPi/5i1CsSyznX5ORz/0ZzJxCr8+RU85y5
|
||||||
|
#h7PeZlyFlNseD/6SRnfoNu0f5XSSrghK8vvB0fGrt2/Q//DPrX9p/ZTWSNo9u7l9
|
||||||
|
#99vbN3/tqoMsrNqmBO0sV7XR965BAd+aFBJxyp7q4ifEZEMQVMQlhI4xKpwDEkYX
|
||||||
|
#Jt3nH9N80ogExrNXHjeTtKUDMiCANOYOIzxoqFjc4YY7zjgvMlZDWeojOkbl9cxh
|
||||||
|
#w/WruQ4VEFCXXLzLxbhLlY19anc0nX4C7dTksp2C0HfsPSQ7z7QSSpep1GUzoVgy
|
||||||
|
#FL1Op7AVK4HeZJPSzMeHhyx0rjoMxlWq1qXhhZN6wwu6G9349+O3b1p4gNFQ4Jt1
|
||||||
|
#yiVXw/XEZzsBlNwYXeUyvinQiwXJdzRh3JBwj22aUeya9U2rhKqxmlt+K2wwvuBT
|
||||||
|
#9AH+0WZW+92wgFzhuv1CpHgSu0kYLSc3k4PsbHFOiyIP3rP3fO+3g+7+wYv3v6b+
|
||||||
|
#iYHyi6Vp305OVPftnURQJbNBCexmhDLs4/u9BfoM4qUBWJ1REBN6yXSCl6E/1fs3
|
||||||
|
#c7/DH+LF+G/joKy5Vg9hetq66JVI6Z2GJTqnyddQRNCDMettiIO3hoBESB3FJQO1
|
||||||
|
#OIGIgOVnTKKOFqJ8XnMhIUaqCHFuzVIBNTuWiOgsqqWQCujliaY/GgsCG8BnNsEg
|
||||||
|
#Y5NzILNmQlD6cUE7y6g8VJwnaKP+p/CmpKYSbIqY+6QytNuv9//Susg+Kw3CmFbM
|
||||||
|
#EekfjI9tJA34Bk1tahhZ0V6T/SuYWE2Prhbs9cTEQqnW+GMAukNc9mwMKZWo1gnY
|
||||||
|
#BfS/JIN+J6UyAMUFxpHGuCLvz6niaThzFJbPIm1+r9nwFQPH+6LxQZF0nl9mE6V2
|
||||||
|
#QyF0pJ4OE7G3tnIdBBWslFhsVmSX+XRRxsp//aSSWZrWDePaTXb4ZMscBDRC4jcj
|
||||||
|
#N8X/IKMAy0AP/gO8vzHNuCAypxUUKemSTmFtGpPY8YnDa9dPP1uyag7aAsFEtDmr
|
||||||
|
#Z6MefoZWCCWcdH8ESannBmK5ZYNBia0n6HLlN5KbfBokjwIKMS0XPpVq+iUq0Lp6
|
||||||
|
#zOvXfVZQD9l3UwDuOAIenTE2RIDzsor4Xz0Hb9EDkMGLGa6kWICiVqwik2soagj3
|
||||||
|
#jOq33lStuz26zd5IfVv+Yd4r3nrrbGan6I8fVWZjGqcMtOdfBev3Rmj4AewsB4dA
|
||||||
|
#+Pj5G8uI3bBik8nZobWY5P/hDCuBNJW7RI0RHeixdqzOiK5066mMm6K6mchY3xsH
|
||||||
|
#UZBEORaq63UicKN6ajLpipt+rmg+IkaasoaMTzgQCLoFB2E1wrVNLGzNP2IX9EU5
|
||||||
|
#gnTvnmV7c3/Ola2zxZsgRbqWszfRJwaYvCcDH4X75TIboWOndY2Nz+2OxZcWAQkU
|
||||||
|
#+Rso3PixTebS0CBnDjdxasQlzaxXzJVL8PxC+w9tdz5+/Lh9ui2KKGdedyeJ3Uai
|
||||||
|
#WEPKe29ednIVddrJgnJxhsChDWdm3FBlH28m6mJFYJThNhYNIH4Wa3oYKWRIzmIw
|
||||||
|
#wYTXBU9pjILRj6wkUddgFtbp1iwg8AnYYNDVtdh5TNcCvTUH1AXICnkycp4QAVYT
|
||||||
|
#eSreRw3WK20g+1E3YiJZBAHCaOjVi5Io6lnkHyWsDB5Q2YBEMgiuLVPDA75tmblf
|
||||||
|
#kfWVAhgTH6P/mrD8mmhX1vlEGC70ISGe2LpuoJt3VhQtodVc9Qo8smyDKuPALyEZ
|
||||||
|
#NKppUSxm8xaGqZtjdLz2x8n9G9NAEHrDon4TuqwEbEKnEi7WUGzI40VinuBeyfUM
|
||||||
|
#7/4KwG3+pGpGNSJeStDRB3f/hgjZXEsVDFDuYGVStiM6j8NBnsjUFFy3S30kVlw7
|
||||||
|
#cWyozg7G0wF0Oy3OUseMVmQL0kQwM9SB1oDvyuVXUQl2ktwFoN6jYY95HQnPUH66
|
||||||
|
#Kd1O/RoseP+8N1/EvEyVb5fwTPXyeDAz6U17YT2jPT8Lq/lrVG/pYbUbHCybDIeu
|
||||||
|
#8PuxqadewSCmXODNFor9xcQKhUvjE8Mb3kk67PM0aTtLhAbq1zJYsJrWmY7V1lnm
|
||||||
|
#HvmGaX8z2dArgHF707HGga4bznNpg7fuQvzTIGGQDPrRIkvQ1Okr1GZjg7UdPzyr
|
||||||
|
#cwa3aXhs9+dVZ82Gu21A0RgHyfCiu3OY1yp08gyaLYQv4+7VtPikX4xI79/UHeou
|
||||||
|
#t12AEiMAQu3KAmy66XxOq42JIg7N2ELLbQUSlsDzVFSwWiCdZkogeKJ5Zu85rA4U
|
||||||
|
#uuIlh7ol51mw8kZIFH3cA//k5HL8D3TI1Z3XgV15KtNDY5e1UjPYaC9J7eUtDoHd
|
||||||
|
#4Gq1WiIMtre5FlGxBWQND+q7pT7m76LeDHCMcBqEa4oGaroD8SrIcZzN5yp8KF3M
|
||||||
|
#AISJKvRElG62Rf4AVZHB6/V1Fay2XJDwlzx8oSLZBmzqouGtw4qro7wgm6j216mp
|
||||||
|
#yE+1KsZG34fhwCriourA1FZUNDb6/b4hguEdNSDpHpbFgcCj0L3EVKHxMFXiztMA
|
||||||
|
#ky6dRLVXVwWLad+mrUgsDQ3Ifxij34eqf7rqnMMPEJaT89AOR0WwrnVw6/fZZhqk
|
||||||
|
#JSdBv1/pdquRcKqxL2lhMLTayi9C1BR9+tTBYwhDIdoWAeY7yWNY9p5YnHSQFbaH
|
||||||
|
#Js4xPuOglvWdnQLFoMtJyQ9rusBI+zTy2QDVNCAM7bwxZFkTNNuIf7jmk8+f78Ap
|
||||||
|
#jx798XgFcUJeefTobtzCCfGV/PL58y04hgr/l+KZAeeYwVocs38rfhmsxy+Dlfwy
|
||||||
|
#CPllYPgFfowG/Z/wr5BhqBRWtwwz8BmGUWGwgl0GtewyWJ9ZBopVBjWsMrgDqwxu
|
||||||
|
#yyqDtcXL8Dx6d4Hsh/1PKiip3ZnoJGeWi+tSnLEMlIdMq1JJTHV4KJhORXwAXelc
|
||||||
|
#Bc9zzaukdZt/KBQ5rFndpB0nrUPpCrYlh006+3S+pZZ/p8TpWmQRQI7U+x90um3o
|
||||||
|
#qtwUWhGFj362E1cXwz7q6suHiR3qWj2LImyK/STtttD+AbNqa6uvok5sbY3yM7sJ
|
||||||
|
#c/vcjiWVvu9gxtwLY2zI3d1M1M4dA0uBskaPv5C81jdjvLtT+dCW5zFwy/m0QBtK
|
||||||
|
#gXqhBl05Y+1cUpC8kjFd64IMAg31T7c6Ir0uP5tpE3kH1M5T9K93Nzh5CeNb/8O6
|
||||||
|
#s2EvUShw3hRIVfCn26R5G7vhORK71U/1dq3KAxWk0tbB25eMB+9r/3vcKjIURBDP
|
||||||
|
#fIIuLiBH8AewA4hRfKsy2cCPS+i4d25k3mv7maW6sx/XvhtKfc/VgUkP9+koKH1w
|
||||||
|
#s7e3TJ3cS7vHb98f7R0cq+wqMrDyJ8+Pfj04qSk+FcX3D969fHV4UFN+PLQVlnYa
|
||||||
|
#aN5/EuMgt1/TCTz8NBqI/AiPYn3BBVJVY+SEei5OFAVaUYfTumT80oGb3nhCKOLz
|
||||||
|
#NYjQe6/3l6mKBuggdG8/uyvnd0VvzMTXAS5ubM9wEGTHloFA8HuZJGdF1vsUocBX
|
||||||
|
#iA7QOv8wwgM06O8kPkDH/e8oQD58uLUEQUr8PxliC64vQz58+H9CpHI/lo9n02Le
|
||||||
|
#MD/q5Icp010hRUS5W8uS/UTV5pLEYXdHMTK4vRDRWNy/MY0v+dS34uP7yon9Wysa
|
||||||
|
#gz+KkBBcwDwaefJtBYao7IuN/e6r1+/eHp10feEhat1JhOz/k9SQqv4FckT21UkT
|
||||||
|
#2dX/f2QK7N4a8F+dJIHsFTJEl7i19IB6Ra+45sKDcKmQGxS0PWYrcds/usnc1Qfr
|
||||||
|
#VXPOFneCiFWskj010qdGwsRljHRl48DYmPLToHU61v+uHVtT8/qK/tpfdKtdb9x0
|
||||||
|
#EsbGT0CpSvosvBhagRe9c+ZuHeUQU4z7QlMTNUW9693rzLzKlWHEHBVVDFBM7QCn
|
||||||
|
#n1atFnzUbrNAZJ+zdSW+nrOMmirhtlJeV/PluwnpyyS7LnknmX64/8+R6WFvAmlu
|
||||||
|
#eubkuOnYt5HgtZYtjgXjo7Dlu68I2nDXsAa8qCf7aoOttnTewnqqV5l1rJ+2U1Sn
|
||||||
|
#whAe2L9plMJ+17FNvPvyDVhz4kxXtFPtzUTee9p7XNnQ0YTOTK6GbMoDkHHxW/Qt
|
||||||
|
#afV7M5Cj2Z8bGy5iz3yQq7NkGZIqnzBPW4nMwed8riEjQuoXekjmHBVTRw2oQqwm
|
||||||
|
#F9B1uZ14P9zzJ+SFdlAUk2m7ffDm7cGbE1c3RU0f/nvy07/VvUGoeF8NKgqA+KCo
|
||||||
|
#UloMqw8k3TSInOYK2hCp0l3RxiENwxzzSJQROGGQg7oe2TdBvmmXTKzWO/UpH0Zh
|
||||||
|
#Ub+iQZwXWWUY5yo4OqyzDHifrVUzqFjrH8JPA+i44htSWUew9aIVRQo8fVoRZrte
|
||||||
|
#MAfHd8K1T2aR4p2qMx1dmR/v8Zo8XVVzx0H1C1A0OLX25AFtxENpKdx4xEWkDG/K
|
||||||
|
#4kubp8GQ6wnBX56gNS5W+TSmSEilWb0EhV2uuBblohsQYeTFJ0Ez8YCDfwnq3orO
|
||||||
|
#SUVnhG+AC+R2cEUcwBLWvs5Go+lVLc0JAJGcj2U1vacTauS04mla6WfWCKoJ97Qa
|
||||||
|
#uO+KaZ9DDcv1e9E4xTrMsqUGg1FxvrnHfasS5S74M67iyqMa6TXPJnjxD5Rk4Yy4
|
||||||
|
#XMu1zL+5sIaX0Xc4WMMN13ChNl74DlXcdIWvmWwkP61vwHKK9p/+Vwe9QZbJVj/Z
|
||||||
|
#IlpFLE7xZOtJQcseCtN0b4+mKsDTWXfQzWtVX7X8098RPZtHj4xd7FrH9ee7HG/M
|
||||||
|
#M5DywE1P59cAGR1LT35h2Sc0xid/vBH+/Dkyxh8+/OEHud5d5/uZnvuAfmsMGwzf
|
||||||
|
#8Izj+/V25077HLvTRlemU+6tRLR2aOLLp4lOtYlXFyAOEQBrzuOSwZ24RLzw7Phk
|
||||||
|
#X8mCQX/poYDYsxrw2Z2e/aNcDIf5Z6h59P7FX7vvDp+fvHx79JpejxnDWnX1ZVxe
|
||||||
|
#l9sYOL8FpSl0fmuartGXYRTr+zei3eUaXVvDFML6L4baEWPTT29vTZUtBzBNvdzj
|
||||||
|
#3+rzD/fra9fni4eZVKHDrcNIKfYqlCk28ovt7x+8+/XgjdLU0i28L/zswY05nlim
|
||||||
|
#p5tRLnd+5jWj/kU9+LQtWiRCd5BE717pd3rojkC6tVVko6nyVd/Cy1CjZ7O8n1ap
|
||||||
|
#YhbS2xf/fvz+JXaS4Aj2iN0d/daGp3VkX+I9EbbGxie+ifEfSkFkZPAFd1lQxGEu
|
||||||
|
#1fJVFWAgeCNF5PBbmQFo/MOehKnSnOsc9lc43qtnaeSOeK0qHd1tr278ypB/AQig
|
||||||
|
#6XfEVgg3xubAsF3zoBOrvwObTBB86Ho3BK5HSte/wGoFUfr8SM3dXqFnLqTsvVa2
|
||||||
|
#aYD34Ob50TLBv2kq4U9taKaf2iy9PLV11YzTtYt+aXOOQ48rSJRNHZtlRrTy/FjJ
|
||||||
|
#EPxtX7hbYro6gldl9Fth6sMhG2CITbbVvVWv5W/YrH79S2CAyUyyLunTABLSVGVx
|
||||||
|
#nJkQxUF+/Xo/2Xr9MmGC1JV1I9BxieYlNTMGBu2UlbCGa1WAUHP5WgZqFFrHBrZW
|
||||||
|
#7dPzvnGMS8nVyxEXBjw2rHt7cfruOfLuMeruuV971cNLTQfDSxh8h+a/7TAbjNYZ
|
||||||
|
#ZvMEnRjmaJpnLJHpYvXeT12emMZECVt6aT4R6JLBs/zDG+kKVsA7+e+O3gKdjrs0
|
||||||
|
#KAeJTDRj4o/WGiMU8oLHsn2boXcq6fmjR6lLk0z74UOcaz98uB3ffPiwHuNS+yHn
|
||||||
|
#EhrfB4dvzL0GqbXYV2PkscuHD/6Q9ZNWfzZLcMeZtPZMwX0jcwZW5giF2CWKMd1X
|
||||||
|
#ggh/QGFvLduPk1S4Z1C56jHcjwofbPVbNflth2x//QHT32x4UudAlO5HBnP/1fHz
|
||||||
|
#49dy+oMqvf/+9Tvqk8quISYrYDHcGuRlryyzMd5b2NpSJ+G2xrs9bA73kd6Y/wb/
|
||||||
|
#H3Lab023vmacdUPnazQ0LK8n897nrelkdP01TXoTY2AzAvchOwLuNWA1LV6Z4dKu
|
||||||
|
#B5N8ZBMik4dO1V3/DvcVA4Zs/G2Z8jDGTIcHuhPDUfY5dYmSvSCBwEO6xsiXnAFd
|
||||||
|
#bVmvvcgWOHV5wcZ3xDLDgXDH8TyFT6WerX/4+2ujKtNFRpnh9ZfSosuULl7NUA5e
|
||||||
|
#ILAs2BUwv/G4M+gesVSOINjIUlzLFJUOG3MMgM7yvHkzNUBB4fiV5YnNVEquMmhJ
|
||||||
|
#MoCOfzNqrti/YLIYEUz4FsouwOG/a/QGjUIwiBqT74QGmpC+5eBb4FxnVw2gS6Hd
|
||||||
|
#9rrifmld2BUwOp7w0FcZ/pB9I1WPIK0/bHGFz6Dz/XD5DmPHtTmjtvoDsm8n0D6f
|
||||||
|
#QExvM0oSz/SGympwuuIdFSqoXTc0cT1Otf4tm/72I7HvjQNvy9pDeXlrI8Uq4TQL
|
||||||
|
#NAVhOzbqQMoyvQFTWoOu5ZGssvuQUUkAyqsjwaFPA9vIVnnRK7IBK1qzynvt+Os8
|
||||||
|
#ZbMsuX7Q2jHKz0Tp6tVmgJEp8dyitMrX8av/rX338Y0enioJDAlEFfi3hqNNrlxX
|
||||||
|
#//rcLGpnOT6Ow5KlnoEpCJhy1tWsXGGrvSvSL1cHUKKASe4LHyi+mhaDyIO7KooS
|
||||||
|
#O3ZJngYnMYRP7B0eLzgYvmCUT84xnJWoasLJAIAuxmayFuJdVrLsnl2b0EDMiCyK
|
||||||
|
#8FBFLMqADn+YO2P2bj4gi/JjkfLoGXs2ajf3TfwyCnFDPJ8o0QAqmEhn+Ccfklut
|
||||||
|
#F8Eo2rmOKXiqfHFt+Zivqn4dSBNlwj1ocu8p46rmqCnXiDwWEFVqMDH/xqLHReK5
|
||||||
|
#DbozEPzqmJjfwYg+P5z1L6YVwLvFdDqP1Zl0VTSySNuWKF4cMPMsoHzWMLcPvKkH
|
||||||
|
#BQUX0fvbkzk6MCHjxV556vXn+WXW1SVLP36vTnfHxzqh07bPOxFxvUv7+Eg8YKtf
|
||||||
|
#84r7FZ31ShtFjAqHT5/t6uyOLbuZbPBOnWrP2S3uq+oov04YtPs3u+I2qWAw6Adv
|
||||||
|
#zj6WxjiwPsRCbyIE01U+v0gUyRNLcvMor34OgmZF1A3J71tdx4KZ6Pwa3cjgaPsR
|
||||||
|
#0eTh2ToRrn6QpEjfqeBjtl+uLHwNpyDO+8DrFPZLksd/7s28Phm84K2mjoh8Z2Re
|
||||||
|
#NuhG36h0JWsetWbPc8LyI2S1pryOhSoA8mcbXCp7LtBL7F5Mp58oHYQMBj3cTGbT
|
||||||
|
#co6/vLFwL3Z/phvQ5gVI9iCKOeN78f7V4f7B0bG7riEeGqXJw2/0+M+hmicpW8hS
|
||||||
|
#8y4GDQ4BNCsBgEyLPwpo4leqYvdvQqDiHndvMDCdlO3XRyLZRRnMDp75sTNm8XPn
|
||||||
|
#igzlvBiZUpdZcTYVi46ILqrrinx69TeC8K4V+/HZK1cFyy/0UmniVIHdyuWJMxtb
|
||||||
|
#FKxCgGnsmN+9WYt/uONKRA/S64yT31i5g0mntwDhwutVxOubVKx06ywpdavJLSRh
|
||||||
|
#ECq1NVjMdB5hyP2lKYEcpdvOfdWUAuHSaZOgPxvhC7tW5TA/lSw4pfvmqs6zKjhe
|
||||||
|
#oQn8CEupZ3nwu2mLx9zvVYaOz22xasqJUyF05AQiJXXX6kAYFv7KBG6l8dhJlArH
|
||||||
|
#47vaMqCGyis5fqNt8mpxg3gp1R16P9lAY6yiO25efnU99JbSrChDiakUDf3FhSZq
|
||||||
|
#vhEJVS+bqJJyW99FlxF8JSGCoeWSVb1QLBPoO5SKoauyU69HlKUeka7sDJVp/OiX
|
||||||
|
#r9VCTIuwdt2ySaxy63YlRY2C0jV0wxW70XYSdpNJ228r8lhw5btJvMRum7jsq1z6
|
||||||
|
#QBKiyjid8G6IV8SFNMS1OJp9PT6bjgJhKYsKJ6wKHUH/Q3MvfNH6OMdLKy9MtGs1
|
||||||
|
#l7wOiPUyikckBj+bsh2z/QwfcY9S1HBZ+CA8nzb0ZHj0Ffc4z9ZAwylRDQ73aKo8
|
||||||
|
#PX5ir2ArWimvwk3ZNzb02ed50TNBOyTVXJabP7x0CrsdlxA8r+xukZv4xuyzdV4u
|
||||||
|
#zhrpx4/oAL2dRhFqAa/vJD/+KCvio2fzLm59dsip2u1hlttsn4NXhFi1Jd4YIvfb
|
||||||
|
#6M7MBzQVPYN+0iXRce9TBhvrUY82uRQ5v7qZZsV7027QZn2zucjRuDIQISh8jGb9
|
||||||
|
#GixsZd0mb2lWTFm4YLkfa9W+Xqxr0i0Z2G/JDYzJJJ5EMXXVy1E+cddOW8jE1qZC
|
||||||
|
#WFi9OR8HqHkQi8rtjleijEFxKi7XcKXiK3ZloM0OFv0MNDtab6Cbi5F7nh2LuCVH
|
||||||
|
#ZSaPeG6LwYZRwdgF0MFgKsgbvFcXeHFI4mGMAShwzZ5UJq6gZsycYKogeiwZ4xbE
|
||||||
|
#G0e3dpmlNGQV7lRlG+R42ircYmW9cYw99ehhGZh0fAdr8wKKz7qrYfMHwdfj3qAK
|
||||||
|
#R4UvziWPXO5NQP72dxDNc2U3xuU58nNQTJmx/Ct6vi0mCHwf4yBs4tEzDJP+Hvbj
|
||||||
|
#f9cyyLyXAJTQTyZ0QfglWy//jtfgLvPsih5OVC3Y+xJ0Za6YjuXLo+rd2eksU0ah
|
||||||
|
#WIj5KrsYIOdvyOT+D6WbNrJ4q74/6rzeOJtfTAfdcV6WMNwN9akji/LgMFbnt9c6
|
||||||
|
#VVHSe9g1IkJgUy9jpQoqAeBgpOZ622jL0q1gz21ccwPdqGahi1EmsLTfe8WxfAZP
|
||||||
|
#m1DeT7LP+E4PDQQMfrEg7Skxqi4+b4mX9RWs4E0fPgr2oUCAiFcO/Kf3dA8TE4JD
|
||||||
|
#fzsDsErgSrxKsdpBSzeBdxdUgurdC39vlBgcVDGh4reGsDjOMydv3bMnTuljQ3VK
|
||||||
|
#zMRAKyTaZuQCdGEfaQaT5fXVWzdymm0KAXHZpi0AT0Syt704I4F8DsSXtCyibkjL
|
||||||
|
#EEut2WsZqBgM29bNCq+UXi/xjMiwoC6oxyTU1l/0iiLnoyTtnB1T3z5dy7Ruf7Bi
|
||||||
|
#ahoZcGsmvLLSmucDYYq5Z1PdtFWZVXxlWVwXU/+EEppZaeUbuMjmi4GIcLAYVHPx
|
||||||
|
#Ak9coIBox1tLFKMvBr6sq3+5U85Ru7Ww2HbMEIiQAqIz95Ib7EsMOmCzDKrYbTsn
|
||||||
|
#QN1r9gAFbV0hUs5MsRhwckXQBwZexBdeq3wRE/aGaLM0rOFxBueisDjGky4yOj4u
|
||||||
|
#Yb223OTs9/KpVZ0t6thCdZDu9kZrfKRXHWOI8feDxAskHVY8mUtxCnzusqrZXUKG
|
||||||
|
#7ohq3iTwtTuvajUleMGmYJ/1KAIsxUHUMJe308KtBBM//HDIoGFl361mrbdluQRx
|
||||||
|
#m4WmRrFbcXadkm3toUjHiV9GGqvM0BMJti/RPuAfdae4dt7Fz3B6iRsErfzN5VPK
|
||||||
|
#nhbCaWyfRGZoNdhvSzBxLgfjGSF1UM3foAfv0a4hdb23MQNxVd0j9861eO/Z6I3O
|
||||||
|
#lKPUx6hBZ33Mpov5bDG3tpm4EWmF+Wi3y6YTQ9+IxVCwmI1NfUUn/DmWTM1Ei30X
|
||||||
|
#WBl2IF1p3WzpONesniOgVLJWYY+HCQxMwN13lq7rC6HIKMYoEqDJ+UsJFFWZG5iq
|
||||||
|
#nj+VMfOY9U+/b4GGuWgEJsoxGpAM7ZdUYlEZTEe9JLw4a/ypuPnbR/hfY+dZBx8U
|
||||||
|
#xrB3da4KTVaL12HWtGaF9TEm1LU8hn/sOsb7on8DZxXZUJUKZcmsyCdzq5sXi4mJ
|
||||||
|
#omN4dzOhM17gA/UGHHTIvvJuz9gw0gI/GVMhDvzD43xoKlbFyXJRmvytfBneIVeD
|
||||||
|
#LiGGIX0cyMhZtgq3I3u3BqSgToRjFAnk+XgNhCSGSjCv86GB4ZSv6bw36sasiOpT
|
||||||
|
#HnTML/KSFUZMiAOGjfRPsMT5sMjqssRIIGZ75DLZ7MKAhBkdnKQdgCLbQBN1AHh5
|
||||||
|
#6nbxschOG3r8R9MCMOiOe8WnxQwt2qYtDFVh4j2lTflWXmyuGA4fTou7r5hyx1i1
|
||||||
|
#ap6pnWZMPareDYuQBaC+zJjjg7VVGN1FhUzRC5bOVIFQbr6UXxJQimHS6GOI1iC1
|
||||||
|
#u6GB70JBq5WUE6nvxu1iUjpPDFPfbs0kZKf9RWNme4D0Ei+OHKKBrwMElC7M02xZ
|
||||||
|
#xT+jrDfpCh8SJeXl92YSba7a+aQj4sQ/q0CCbfIUR3Qtq+lF4jybdPkKp4vTqGh7
|
||||||
|
#RUPWtQHx9KBbQvvWK3qyXnCIzxTRosrj2DgrEhFxbFhyYNTi1WWcfRe9lKXjDIQh
|
||||||
|
#UVBk3O/SqUOswcrxR0G33hA5CH07BCRLBDwUVKxdvRC39Dq8bA1y9po4b7dap2Ra
|
||||||
|
#ZVjeqZIGLREyEpngnZMBpoyhkdg6xrDBydGvMd1QA8YqJblsM/ExquJlIbv8YHFV
|
||||||
|
#dj+99zZOPPU656bcL8V3Q8iDbHmR8poWOutOLvY3oO5UeLjc1aoYrpPEFtVIsmBl
|
||||||
|
#qEXpczy7KUZXi4aLz0laBalNtkVVw0kCOgmaZ2Ou4sZPMI3NM25mWV0LOMw0xmpR
|
||||||
|
#NyLphPqJez7ctqLP7DqmTszwqqvveSqcwLLqJDeOJsF7ETQTBOOxJxU4w84noI0M
|
||||||
|
#nHMnbemW1oavF2ZsCU8tTKuRk4uqEznCSoYgCs+6oUPpS3V8NZ9qM4VDSU3MpX0P
|
||||||
|
#mUCKgEmmJJ9XbCVxqZyFvMNBaxpQ9gBWaZMuUJGzL50nJCxP+rhR7wQS2k0vYjSR
|
||||||
|
#BLvr7PwKjy5jqnW5FMUz9IyrGlp34l1k4+llRmzqVxfsdwfWo5DAyHtaKvicV2Eb
|
||||||
|
#DNAyrGtV36gowL1FLzD1bdJ0K4W1TxW3C54PnviUimgOCAt4UVJV6fDsKY6nhhoZ
|
||||||
|
#q0rPjcjZ00oTq+/PoCQbep6gEgR/5eUFLHIqucGnAp79UKpyLMIT6YbnafEscT7V
|
||||||
|
#3OVCeLmww6LatknENEMZU+cyI7ahcynIYzykijTZpCXomVUJmOkXlUJDFq+aiQ1t
|
||||||
|
#vQFQ7zNrhvrXKXiWZnrEfWD5MISnxceeb1+I9yqoziuEsG1cPD28Mma3lWRVFYUA
|
||||||
|
#WukkQW8qB5B8u4cY8BWLSjBmwfKi/ngW92qHE8ZCkr+fMvZey20ncAhh7LGybngB
|
||||||
|
#y3CUoRoUO40YjURHq71iVvgPaWnN9c/KqhbXqiNWFDn5SJtX8K6Rmx/Ggwwfp+Eu
|
||||||
|
#ZHpebCbTs380AycyJ/oi89IdkEfHNOq6xadf6O9AZTuPT1tSScY9BlGgEe9m5IpO
|
||||||
|
#Sweu197n2tGeZzbDqXcHJeLurugW2XX0CP+MUX5FeCiAsdbM4wNUuRCsiDccXWQm
|
||||||
|
#04l/scUkhQKbbh3aYL4qlVPunhagvVF+me3EeshVJzI9IOqcgzdEY2taC+PLEiOi
|
||||||
|
#WYOqlpGgXI0TScW6JlFUf3N3fHZbO4vE3lRe7cdkVSY4KuHX0fSsN9ovjdO+dwtX
|
||||||
|
#WaFZP1QCWg0dJD4AbsvvbmUmt7u6Sft5QKuxMUMvqYJHfVXGqGimBDCYXk1GUxiy
|
||||||
|
#RQH7kEFWVjwOye73gJik+BfdUT7O9cHYX/zdRlA6E4GRgSUopHb2GTZGOw1st4ke
|
||||||
|
#4u5BhIveT3/513Ix5rWo3n5+DqXb7ePfnv/Uusg+D+i7QeDO8gnxH8Fr4oWoVQAj
|
||||||
|
#q3GdJBH7qiJHu93RK6Qd09zKrFuWI/QGKkbSy/1iPp+V7W3u3g6ryAzwy8SNEDRZ
|
||||||
|
#gh4Bw1bAnHIHIanTI1SvIU2Qg5skpKdykrzJoNRvJyfvFE6AdN66mOJ44y/18KbG
|
||||||
|
#vW1+qIUQ0ZZy2YVDVxxT9UCc10MEhAsXtY1eGRj2GH6rqniJ2K9M8dPVcQdmN4Ns
|
||||||
|
#TQdYhTHfy848Ra56XPVzQ8dEdvJLxcgUXPesu9BtZxEqFPdvkCZL3FdmLXfqUrU3
|
||||||
|
#M+TREtGO0pGeN+x+jK5RORG96NCVOBvQCdUDDFBVHijbR6QnKW8/NPmoldXKEdOf
|
||||||
|
#TmoiaqennmDRqoZEv13dry18osvJEW0XWceIoIVRFY2P1dszoa/t+sNcPbARyVMh
|
||||||
|
#4ZJ7zzQfO3m2GiXuDqzvfSTTSS1eUvRnk8v4ndroOqQfhTaX9h10mNdebPsqqPGL
|
||||||
|
#1PNe+Uk7n2MogdlFr8y4lSJryZsv3mhHuzbr4Ut0ymmENpGboP5/ykq8D0rMaA6N
|
||||||
|
#HXIngEa7/Q4rUh9uUdlve35Bb0lMJyL6yMGb3zupetuwVUL31ZIFTUJS9/jg3fOj
|
||||||
|
#5ydvj2pgguJM10VDxw665NjRC6rnn0FB0iRKNW3oG6kVTXhwAHJVozVNICC8mivb
|
||||||
|
#QHVXJ1b5O5h8XCpNUbogUUdHyS1sDBiUKK4FcWpDHXmKGwOJzjPIBCR48FjSLlYm
|
||||||
|
#6D2VUCJuWlz77jt8w94hbLgaA9XwYFVc8JNymtVOt4bpZsL6FUIyuNARZvXbm54S
|
||||||
|
#l4LowdApijpi1ZAE8wpGYTOEWWVkZt/IoJxyFOL4NwjTtJWiqNVfAe3386I1u2K7
|
||||||
|
#DnqgJVXttEGageKFIt6ORvJQYfwwVQ6yukHfFADK/nU5z8bs6cX+BZRrI6Sq1g6z
|
||||||
|
#3uWtGnNrGrS5epl4Ka7utJPUkdC9L7l6sSgvbK+CLYGMa8XcjMgDld10Ydi6qtaG
|
||||||
|
#p0w3W0/izAbdmueTBQuyYOMUmCzfcqnA4q79Gd59AI7QiWg/qRAyju9c2SrmXysq
|
||||||
|
#iI/KLyxSl+WGNRy4IqoXVY2gWa0P+XuCgF+DqAsZJQQql9GX51CrVwyiGjPbt6Aq
|
||||||
|
#fNbrf5oXvX7W+enU1459eqnxFJ31HJ/oyVDUFDdNO+x5WHFhrvKYMriEpuCs1ivl
|
||||||
|
#zED9pUrjoXGtLiAB6chPWvOIb8JjLBerVttCN5vgfbHBTsMkSNeR6kbqa8YbOy+m
|
||||||
|
#i9ktFM016smGcHNtI5U11mhBdcJWqStaB9th0bEg2n32aHe7fzGeBt/dI5ECWwr/
|
||||||
|
#W5aYiY/uqJDf/JNOO0YjljKaiI9u6X2yG2zt8SdYZvzvLm9+fMk+YAVlX8VYfHSH
|
||||||
|
#8rPwPmW2bHc+XfQvzDczFauLfs5CoN7L7KpkfWNTWRI002xsfLri7MONC6gU4Ows
|
||||||
|
#nf+5uB4a1q5bI82/ylZ4Mp0dZpcZWguTp1HL4UzFQlM+YvwjsCC2eC55z7nP6Gzo
|
||||||
|
#LeZT3KU1zI8QpMnBO6v6Zy1Lo2MgG58BaHt+mt0X8nLqXaZa/lxMvLRgvL0QZbFB
|
||||||
|
#V5TjIx+ONwlhVpw8fe1Y33aEzUuiWfUQB8bhTRfxrjtlDsEqmF1gQOaFSRtxn7WD
|
||||||
|
#pbbp9jHDzSCLPWYZZA5q6g3Pw7TuBUWnjDZSkWWcGIOMUX4WpJmX378hcwhPL05V
|
||||||
|
#XxCYwJJy61elBfQX5Xw6VhE4GlYj8fnKPJmr9BijID2CDQt/z95EFBLoVb1z7kUQ
|
||||||
|
#DeSDly8mvORT3cAuEw/sIIsJNdKWKGaci7eU4XOjg6ntAc23lMSE9+4fWVBgH3JE
|
||||||
|
#fgL68LxXzPNhD694Nc4Wc7pjJiJMNn0gBsm28rpo8rbj9itEJaoUa1QNrSvQtVNe
|
||||||
|
#Bz0gMq/AysslqxRs+TrKPJXOCuBXehp2e1EW22gvHcEXEh3SjvH2vBKO6sFiVTxp
|
||||||
|
#aLnaTlytZtpkDy6rDlkxvQ793e4TNz+C9F9NeYtIDfV1RytQfaVyDdXR54JFD40Q
|
||||||
|
#KfWJYdeZihbem/w1R3Z1r22LaywqOA/JeM5tLRGYJUjmydwZYeUMVUsI5s51SGmy
|
||||||
|
#fNCBmDL34NOW0NnizNJnjVnd8OAa29GT0LvYItaILXX9AZ2K8bXTthlfHF0ajiLU
|
||||||
|
#RSMtizJrg8zKgi0VVoy5aaoE9totoMJ6+TnrNySITR8kTdkumYPDyGvhkXP1yTJ2
|
||||||
|
#gWkSMuz4reJi52rvSSEOyk+lFxHb8D5LWHMfnCKKaIUip8mH6sLvdDEZpJVbYwmY
|
||||||
|
#0Fm5Ytroo1hczle8LgQ0N+HcWDfCrbdraJc+697bNEQnK78uEQ+y7Qf+Dq6ZiWx7
|
||||||
|
#PMAz3ZrL3dg81fBWRxQm7rXgg12qDKnSWW7XAiMCSvzwug67Tfcsqb5GJ9QM0189
|
||||||
|
#vyIZXLuopWCc7CJVLZcV6XoqRtQYaQgJIqPHtZtdLy60C0QmCeXO6CODsaswlrHO
|
||||||
|
#GLIiQ9OQt4XzLh6UF0RJPrxuRPvEBTDIDtUg30tSCjn6EXodV8LGClEm5RmbFpXC
|
||||||
|
#wQsCQHXQUwEFhoO8fBhcMPSIEaAhL+tSLCpTT38O5JihW5G3f73VyWVlUePWFXlE
|
||||||
|
#gHWGc4xbadz9c7fa0KrlMk51M7KT0udMMdezhK11dXhHFAN5LyLWV48g0rdq5RKa
|
||||||
|
#JCqlo5ZvPrQxg3lM5YmRQbOiGXHmuxalVoRpbB3LNkHJuunEz+5ZjN2INYVJEnuo
|
||||||
|
#b9LCtzyiUFG48DuUQtZYoJi8NkC6oiZgMsH2yMSuYbCpQuTANgpfiRAH3oOmsk+b
|
||||||
|
#LNAMpsjbVUwK2SVeih68b4e3ES1LNVxpzWrKN3yl86b0n1TPmXgOC9Vvu6hR1nKa
|
||||||
|
#rs9O+1LvNzt1qXZhIGLfZ6FWYeKNSIzrJ1CUSl1Gpa6gUj5cYy1IOH3NyHS5crGG
|
||||||
|
#QI/Uq9eN9TdaZGuVY3Hj3D8kxyO5msfStxnF1Un0fyYYXqKx0/541W7uUISJZdUY
|
||||||
|
#qTgW3Jtvew0fG3lDPkCXuTuEIRRW+AxE8FuJTuUd737d3W7yI8UrwH199XdjY3sD
|
||||||
|
#b/iyeT7IvXvr1LQ58de5HdMQHYU+etJstU6DQcHTQoYGXjQ2kJYpxQTZ/giNP9je
|
||||||
|
#TOTVbLt4cKcE342CW/7xmKKhUbvtqZ8fbSE4PHTRJ4gN/9Zobew0G087f/vl9NEv
|
||||||
|
#TfhqPhAMSXYL3HYObLQeoMWDJ5vJg5/gvz+zsnRpFAuyNHLeS58q7/9f5H0TLAqw
|
||||||
|
#2mNAZiKcJHUtdUm6olb/ujcJq9BRa0UNyqugZ5J0ZFc3fEqqvjdP9fF+Fwh58+Xy
|
||||||
|
#S3JJ+lBaOUE7mtx12ocZu7qDdnNajxFwbpIv/S9Jv5Mm6Sm+xwY6bl9fdX+IdruH
|
||||||
|
#H+HPQ9B10VujnfSTpfOpiDY9QFV5jEZq/1EP4hjyTzo63nv75rj75uS3o4Pn+8fo
|
||||||
|
#qkQM9HHwSPKMdr188AQPM/JIt8MDf2KdozNlg2m3oaGXr37tpOgH3J2W6ak/0Nuj
|
||||||
|
#fLL4vC2GWTfrjEvpNq522/3ZIp8MpyAVyn5v0tj+m14Dp8XHcqO93aRJHzQwLq/y
|
||||||
|
#yZe4lCaa/P1qnPcTAI73wpM3i/FZVrwdHk7PQZEdvTNNlMkWrTV/J2JVlnpGVJRt
|
||||||
|
#VBLSJ6ZBedArAOcQUcC+Px8lW5Pk4qo1AYwVMl/XZOilHB3oJ1F2U0FyhtNi3NOh
|
||||||
|
#HkgglsEiVDo/GU8g68DRVbMOlwVXapk0HpkEAriVPFk2Yx5eEk+6EaPUdTyab8ij
|
||||||
|
#UG366sCKe4q3OdXHx49p7EYBPhq4owCQLVsvBgb0jgebjYVnXqvR18iPEURpoYwF
|
||||||
|
#t/Ps9AG4ezw29fqLz1t6aZyjw7wNDMII5qqqtxV8R3ndRaEk+J1cb+GrD1FyiwAl
|
||||||
|
#fsDgeCgvoxoaTaI65ggdow0cr90ixk6N6sFaB+2jCkc2RqY/MQ5jsFdSPYm+EEIj
|
||||||
|
#oKZzNurNSrw/lo+zhv5wGF0AEvS4n85JtpPGvz5ONpJ/fdxseuuFLrH1TNfCQvSX
|
||||||
|
#GwNYBVToUwYPIFUCMhUElBKUzgk9cqVLtvoZu/NivSjZNRcgq8LJe11PB/CnEaMC
|
||||||
|
#y4sk7kjKIWCIWoNZDUBdZDmuACkK604tmR+rcM2UYxePDxT6QnMVNlrGlTJ3nngx
|
||||||
|
#pTHAsqva+lg2Ph5vNH+OruMPnlTwon2DRTUDmkOAslXHSRv3J4SqTphcPXoQbbxO
|
||||||
|
#5lYIoKorb/ZRWMSMHku0WaZw1Q1fne8HwlWpPBQU7HxSKVp1IWKG7aqQJZxl0PmY
|
||||||
|
#uqBrNitDLSbJO90TsrzSvskTQE11rE1ZInRdQMpW6WLrSXpGniEJ2LF2282En95Q
|
||||||
|
#f7xqtmmHsxTdSbv3bx48WcJfP8noLv65FBZUEnf99Xgl38zwmjOPD4qaQmM89IOS
|
||||||
|
#6mDgzKZDR+QL9MJ5+NAmOvXXgqBVpgsac0bjiT88lqI8sx1swt6h3PDmhWkLOOUh
|
||||||
|
#/O+RNz19SgXFsQVfebD4Y8Odv7VPH30EefDoYxP1ctiWtnUaJjY/BqoqEeTpU4lJ
|
||||||
|
#oiNCCtitjXYS7GzxD5BIk9UDoqED+rqIVqCgMzQxGj+2S9CSZnLSyblVMUDVCyu2
|
||||||
|
#E2UR8hUI3W+jN5nqLPR3s9F7qxY78m7FD3jpkLTelh09mzVQ3TWn6toSp/pO50Pp
|
||||||
|
#OdK152HrvR6riqfhGbY4fVe+6fcasabWuRNYeZoc3ID3noljoVwiwXR0/KE3U1ME
|
||||||
|
#vVQoHgCAjOsR/7HIyMT6P/FfcXfXtmKjyAdX/E90BJzsKjBJe3t+B5CME95MEo/a
|
||||||
|
#MLxas0V5EYSE8btQTWYNJOKt6Jlg3Lsztq67hCFWwNhFq2ZLLF1dfJbGXvCRa6KD
|
||||||
|
#mrZAs9efy5SFlaGbFLjN9CsFneDh+7TwWGdv5pIZV5WsNGA36o3PBr2oSsB2uErP
|
||||||
|
#i+5wa29s1Rh/lL2c7DHw32B6VXK7DDdSVNxXU730uIV3zX208C4tWqNEYXQ4d/tq
|
||||||
|
#HEb9VQme1XAb6cgemm/xHCxlXMYfqVeaUhFj/DeOLJGh0dAleefwSR+vKP5xRfFC
|
||||||
|
#jC29xMFLb1sHGPPWdc56c9AZiWkE03Vk4E/zp8poEC7ANSIh1NSig+Cw5CPBMEBi
|
||||||
|
#1yFddVJW742lHlui4p4XiY6O4y7f7I6vuzbRpPWnPZNoFUZ9h9ZF0PE8ND5llofx
|
||||||
|
#qF+DdYesLN+12oFUewYsTuoNCm6xMCme8mkLxlsKWiO/oGzWBc2qYepSRtR6FkM0
|
||||||
|
#YIZa6wYnE+6TAdofmVa634IyX93vzukzbIlcwnzGM4MCWUG9GJqrCcbjFMXpZEVq
|
||||||
|
#jE4riFR/dm1nCep0zuGzd89hr/W9+LNoOhNd9vEGaO9eM0TfeMWVkXeBz+ldYFMS
|
||||||
|
#rYf2I0oSN/vtpJC4u+7aM2vhc0I3KqfzCwrn5cQK67IKxJX4L1mL3MoXjg3ym2z0
|
||||||
|
#AMmmrK2pTmhI4QRSr1fqqxOJer58M2kT1rYPMvi5+mdT6yviqW06ZlL5OoVOTtQZ
|
||||||
|
#N9dGVBm2JX7w8abR+dvyFDaiy8pDUqjFH8WtOifVDvPPPLwNFI63dYGjvFC7h6p4
|
||||||
|
#wcEHZcSURqgZJQYniJm7jCgyQLGmi8aj4pKyw0idUn65vPxiqqiE2RdaY5f3by4v
|
||||||
|
#2Vu2y2XwpF7A6RXgVQhwhOLDrNEE2KhvJuqlaXO/QV2QEEGP1u57VVcJ52rUwl6K
|
||||||
|
#Tvm16zScysDHnyagKla8zzi/nmX6gUakLU3wZdKglzQplXY6JgotXqe+f+NzmM1u
|
||||||
|
#rmkbE7OQl4wwnyprDZKgnUWefjFPpEzmFdyeBQ83KjZYNfyhvMBz2x/izat/OhsM
|
||||||
|
#g9MoPvEgwWsOE1LDDJNNCEYgtrzBztMozfZcwy4cZjGxK7yV2NpArapII3W4Agtt
|
||||||
|
#BraeeUEVjP6wENZHETaiVq3BAoEC6LnbVes30cMPqaoQ+XQJpFOLJ/GiaoHt9uaN
|
||||||
|
#DR6EkKIfGiaFD9dNXDiF9ue17wfdZ4uvCUpqNCZvCXBDtJiUF/lwHgxifIcQo4Al
|
||||||
|
#KgYU5SsmfNcsl5CLK3r19MUC2msFBLYbumay5JUwFIeoo5kOdBIZ9/QTsFGT85Dh
|
||||||
|
#DckZzaBETAXk09D1c7292v7By+fvD0+6L96/Otw/ODrG3RZVM/FG1WWttg4nab9m
|
||||||
|
#1/rnvrFT2O8SJnU2humuU17xa8jmy692mH02v/KzomfT357hlTH94Z6hcAnaE8Ym
|
||||||
|
#sFut7eOLHgyABKjSBNhj2JTqn3/t9fv4E7lcbWOZl37yNDlaTPBQmD5/1qQNHSq1
|
||||||
|
#Em7s0940CHMSkQhD8JwZt7nxkhdrdYP7pcx91G+ETxL5mFnsFSLjOEnrSrjTrngv
|
||||||
|
#ppHOMQSOe8np8f+HVzALfBzsSffx48f4X6v1L+Yn/tdUR+bl9TjSyryroqh0y4vM
|
||||||
|
#3vbbpQ+8i2TJ4ptlyV6oigmbX3BLOW7RTUsVvC5FO8+rt2hpzSaNjr7QnuL7Yokp
|
||||||
|
#oo8782kYXjGf0iFWi05ZvFzfyuO5H6k/8gwjrCa/jI/b8W8Hh4fpKZmiRAJGb0op
|
||||||
|
#2dGnw0tA37b63hnBigLqpErNphat+bT7S4WzcNqscRdWpn+HUFpepDFEAJWqrIj2
|
||||||
|
#2Un74wGd5AaF67XNikZiSzLnVWN01xZ3++iWny7Y9isppwacBSy+oRUb13Cq9fr4
|
||||||
|
#r8fby5XcDmAcj6fZ5DLVPI7/Mja/QSaXTL0kQ6gpE0wABc0fxjVYv/YYBD1NOuG9
|
||||||
|
#Jp/SzxrczhOMg2/rqVof9bcJw001dNrr/HM+MRYNnbafzfAMweKr3bpISJso8OTx
|
||||||
|
#gCeyoqQ9Hd/Vb2rJkeZeKxRWvJN29w/evXx1eJB6VkNz7EsRkuJH87UQJPV36cl2
|
||||||
|
#/52VXfNA066Nb0VHzItJ/h+QCOPOIYpXX+5mTeYv5Mgri7BvyAp8s2lkoNx61NQs
|
||||||
|
#dPNSafDBYMZuTphB1nUGjU/89Vf1h5JcDIx29hn2b0CxPUx/TWahtY5XNba8mocF
|
||||||
|
#KEOXue2xHUKbLN8xDwdbXB4Oz30T1wBd2nG3SOsR9+z/IWD+aD3+UZG57Rk3M9pZ
|
||||||
|
#BJz9lBeWq/Cue5OwKOfM22gDOdR7cJCD6bSVpQJWPJoqlRFxZfT+bkCRYF+cT2YL
|
||||||
|
#vN/JNsMelqseaWLSDFSj2aiHD337C6qa4G11iOhLYNlTHRBYw1y5ssrK8VoS2/CN
|
||||||
|
#0WcelKAERj7HuCCo68Pax0mxyyd8AIlnxoML6vfWIkyIZIu9UbKu/A6IZaTsyfOj
|
||||||
|
#Xw9OKC7qbvB8uyt2/Pb90d7BsSoXLgIk2LFJa5mNMDG+mqlk+vH7ly9ffVim/pPO
|
||||||
|
#vEUr/j0GirAQDsg9jb28qwUMjHi4p4OX26lvVUwUrv4L2nYVET3bZPPdBxRhSDI1
|
||||||
|
#akhLDNHMQEXOngcxSoiXRtUAxGnrvUhqTSUVvs+GlAis8olIZzGKXhEzfzr1UMRD
|
||||||
|
#k+K2WaCAxWgY95+OkSy0QWpSKkVBh7ZriEC3ob4h+8eezHG8pBMbgbgzQlmAIJ6B
|
||||||
|
#1QHtLeUqFWmVhBTxNUMBttw+zCf4Kkli7nfdvyFtK3IpxMzk5lJf7ELjs7lM5hg3
|
||||||
|
#eusrMlKrMLsLRnXmeCCsDkRqx8OG4IoFUq31Mv6mqrZS2vadw6FUX7pTyifPR/Mg
|
||||||
|
#TTeQKUpMkEtMZMZ3YMq/ffHvTpTC9+GrF+b7NMKIwRO7BDZ4SXnXe0oZ/1g9wAgV
|
||||||
|
#/y1dzbnBM7obphe+0Ihcl4iwlCbUkL9ni0hbSrLdg6f9m1soBgGlwmiy2Me6Q7Lr
|
||||||
|
#nkTecOV/lMDTL8P6WG4m8ReJQ+6r6uf6W87vycbaYhnoJ160WU2xtRQU8053O9lV
|
||||||
|
#fZa7C58DRoPK9e7+zYg+l8j8EaGLftcDdXnUI7Zp2anpKiFiJhNvcVnxr99IV7XC
|
||||||
|
#1dC2bd/N8jaC4R+xC2X0CBglllbvlqWxUY8mgqZUQRTCV8eY87Gs0EzupDxq2scK
|
||||||
|
#2hGlkh4OtcswZ4e91/sVHBGsFqldKivXPLuSGIFSxbnfeFZqy4ISI8lT7xXeyolY
|
||||||
|
#+QTZ7dvWpyrrtx0XAb4AcFTygmGsw1NrbkdW8UoVi/THA1JYkmemJSgJetrxXmp3
|
||||||
|
#fQiDz51oMHymxRGI45P9t+9PPHOjexKGooNWa/YOQhRrOTtDJr9/Y/q1XI/Rg5Fd
|
||||||
|
#xdCRO1i34bPZdZTJmFXGi8YqTTK7OuIiezKVe1KZuwv6cM8/va+bTEShbl7qZyas
|
||||||
|
#ZtQaZZNzUEZ+SZ40gS+iEh3/kCeztosKQ8ratXz9AfhE4SJx2zFzJWnLVzwCAKRh
|
||||||
|
#oBLnP94gAMY0P/f4ddEP9D6HcwLZXtfs3Te8N1n0VSARYDh1Xfrlm9fd/bcnr5+f
|
||||||
|
#7P3WBG10hKE+6U2xkETMEX4YUaoYjoszLBZCgAytR4o7Brp89FqBLFj0m03/0p0k
|
||||||
|
#bUcDO1UbITVk6O2s21658Y/owQ520Q/gehc1AcN6L6ZqIeya4dx6avktIhH0Syyg
|
||||||
|
#2rjtnzwcNEAFB6m3wSKeKnqrDlsSIPIAdtQ7+rE5dbCfEAVCM76LZiexqduiqtfB
|
||||||
|
#v+822TxUg0+Q6sbdJlVE+qwiZqAaBtpYjXGDXkTcNLFy24GsrI+Rg5UrCvRnDTuK
|
||||||
|
#m3TSUWbFZYaU8Z+vX+fMpmqI10KdN9DwBWNEmhoh6SU3oTTinrSjT3qbf9WqZWIT
|
||||||
|
#P6X16+c7a1nW1+SfuATaNm+xFkau/gRri3+YRufvMUqzGtXvu6jH99rJ390Me5j0
|
||||||
|
#Rni2dp0QwFJfaaGwlD0XzDqtfhPGu3rp3VIJZmq6B83N5TtNdSqUN6G9mWlNE2tN
|
||||||
|
#x7UOJj125Nxkf38Nc1p/qX/2NuArNfz9V8fPj193qxT9UEl2Xf0mptOaXSQp++0k
|
||||||
|
#mAvfbtd4mH3+77hrOzz4cIsB/TWbZIWau6PsM4hEHXiG3K6/+ZofMTh/w/FUToLB
|
||||||
|
#mBpfAGW6a7cDq7O3hARjr94gCZKNfQNGImqxfivsXustHmvwWL1p0F9avg0Xhtao
|
||||||
|
#VVz4/Gh9HqThQg6ErHneT0Z6IHtF/wL2GF9tdvp2LKaGdE0O+6qWnJ/sP0tGYW23
|
||||||
|
#nyFftPJLUq5wucBFxB2uaE8L6bE26/erT2P3lt5JM15xwQr/mWyPBv0g2sas3+2P
|
||||||
|
#6ZY6VH63h5KuDeX8nVy4NYzWPA9rfkMbbswBoHbeaBzXtMpyFrnDieFXH/5Zcxbu
|
||||||
|
#XBe43bmNPcv5fa+cTtKJ6yvZP+768a3mwt6HD6tmw6xL80EV9rgP0DrPJjZ3/+Dd
|
||||||
|
#rwdv6qMBcXh7deD2YtDknlMz8bujg3dHb4GNj7t7e8TK1Eh9SQU9VZcfsNnvpP5E
|
||||||
|
#HF/QSGGdR27hUCNIsdIY/u5dtVq1vuNCdBrrifBdvBG+q8qlTz5vr3L5BeQRatxL
|
||||||
|
#Eyc+2hZtOJ6N8bQQJhQe4dga+uz5gSLMabOTtqqOGHQRdL21acANpyFHAdv/6tjJ
|
||||||
|
#Fsahr/HE5Q/fU9G494p2Ka/vbCAJfA/Meln+T1d7w5gwkWNUKcUkrurg0hU93I9f
|
||||||
|
#Mbw9G4tLRn8UZgYt2F7RXsGMx78dvnoBsnglN643QYRzoEWjWT9lngVJGP7wXoNC
|
||||||
|
#3rU2tps7jc7ftk8fNR8s0d708cn9Gwt6+fHjT5XPJ/1TpzVR8rvNa35x7b/o7OZd
|
||||||
|
#uPscP/5t7VkOI/KN5/ntN3F1kzj7PC96vjNS2i2pqbrYznfuRD6ejTKdEfSi6sGu
|
||||||
|
#Fa9AoTUXtRDGCLHntKqYxlRHrtE/o4OLertnoZfvzJkXZ3d9hL6eav/nv5px9vjV
|
||||||
|
#/z5Y34iiOvjdtMd/ikUWr+7+dzTJ/vX53t7dbLJ09+uPZ5RVY9lumzE00tK9z6ZB
|
||||||
|
#tlHaPz/WfZf3VFyeXiyxiHJD1VluIQ68pKHEc3sQAbpDiJFYbP9AeNVhtLdXjRHl
|
||||||
|
#xTHaMwjdjQ64Gle3q3Pv0HJtTz98qOkqZVa0yC0s3GHU5H4FFepwMtl3wYrq3p5G
|
||||||
|
#+zWjsl89Jvs1mCh7693IU4eOzr09QlhxPcr8YOUsVTw8/P3182MtVX9IYki5Ig6v
|
||||||
|
#HxKOmS5h8cPcbyVp/ij4mlfVy+tJ3/jJWNMtLKq0xISWW+11OMpJ/JsYI+r1nb2j
|
||||||
|
#V+9OMM7In646qgI1nrDfreJM7X3M8g1rjvVEwt9QG/9hMVvkzfbscz4nZXI+BXX3
|
||||||
|
#MhsJCOrGefKWevyOFsl2+9XkEpb+wVt9Q/GXJHehf7XXRGu2gL1NPm35fk8ifyGy
|
||||||
|
#CJOfouthGDNHXdbGKMr6QmNDPZjMkWe53L/w6gJN+UQUeh2Gv8GAUeYho/NYP3e0
|
||||||
|
#tYXhyHeajZ32MwwE19yRoeDiT93ZUHBBUZWNV4s9PyqG64on7NzQtspR3s/uNR4z
|
||||||
|
#hUIqX2ewQ6l7xk+0K+gtaVx2exNzc7Thk5hnrktnHQBcZWIgI5HDIdIjzJoOK0dc
|
||||||
|
#9ouDCTpXzfJsovGndkEAXClieC6F6DATS88mGMhroEIkqqfQ7TUHPqF09OzkCwgJ
|
||||||
|
#disbv1rTSSPdek5RNrbQW9h78Z03XeGgwwGdKUCkNyf7r47SJrsVDqKQ+z9GYsfb
|
||||||
|
#cvYuMffNjTeZqSYtDX4/1o2aFPlWX0Ax83NFM8OEjgCaoaeuHM5YCDoO56VCF8d6
|
||||||
|
#a9jLRxhb3qN5LKg+soYuzptWsVkfr2hTBVHZushGM7+tiJRcG+w/Evt2myKLfett
|
||||||
|
#xTDbcsj+5nf1426uxUJ1hJ7SS16/3TfjQQn44IxwgNbvB5oslqMe95sOh/KULYLq
|
||||||
|
#YApTvMy7qknf09dAgk1bP7s1LE9Ax+2AvPsnqvs0H/2BFMJjjZl6qadNVpxNy3VY
|
||||||
|
#UJdcDzrCLaFWlN1SBT3RZZL7N0YT+/3g6PjV2zex2NgxZkQP+GkBq/29VUvGGgsN
|
||||||
|
#LMxsJtvWIm9tsmJ8+y8Uj3SvN0EvTWRt6CCrEuvck1jnREBHIWNiOpy72zcMIulr
|
||||||
|
#vId1ZgEXOTFCBK9r8mn0+UXG9UV8D0JH9mmlFRAOp9NP2QBfjMCYG9HuqPclgUf5
|
||||||
|
#4a5HLoe71Dgj3IuKK+vZZsAkm2wGbbplbzNYMjzFlYekA0XVDVm1o2/Wsg7xcbdd
|
||||||
|
#v39cq+Cy+unTg7cvf3iPKUjHB4+XSQfvnfRGxiB8mnS0ekP/uOQWPkn7w6+icBvA
|
||||||
|
#bj3fTEgRoCaOgSRIC0WtpAGqzATGG8UAninBZiRh+5WymeQTpXiNgOFayXsop4cF
|
||||||
|
#iPSPxURFIMWqxDVbJ6hbLeh56h+w8bOEQh8iCrT8P6NPhUo2VyoB80xu6DOJtspp
|
||||||
|
#KiAZqAAIwQzYs9+PCcIBDSQ+rDjIS/ppSrSgBrpV99Q+b6vMkCfmwKHYj2Q6NCX1
|
||||||
|
#aKhnGJJXQ+qFeoWAOLBUfUu3UsrRtRC0bnJAVnKUCVMTOpuSLbDhAqhNrQqAj1LE
|
||||||
|
#W8OdJLCNofdw8P0ISCBIVqWZX/TmQNfMwE7Ors3hDf6cTkbXKgvNkpYa+GFAYftQ
|
||||||
|
#z5HnLcbRvsoxkq3qsQKMUbwdcUoiYZmc58glxmDbm1y7AigzNHBE0BCllZwAVA3N
|
||||||
|
#AGdQf1DzbZzha6coN9B6SisvYjMrpnQMlJf2WR4ASayglDaqjryIH4gh391SuZfI
|
||||||
|
#L1wlc9yPCdCkMQyPpueq+VmRXebThQ42RI75tL1sDKaZ7ugUhplyCZpeMFSDF9gg
|
||||||
|
#6mOuISWdEkyshyYhgRKGsCZai3r2xs6WCT0OiyQ12lZjNO3DdLezxiy8ceVsqVso
|
||||||
|
#kr23h2+PsBXSXJ7Rp21GaTOoYCUN0KhAdi7m082EVCIN4QTrkghx3bVigjpLMhjf
|
||||||
|
#DC5Z37HLpdfn5IVlZoJF3KykE82UHhdIxGSK35Qw2np+gstTKcUacBLyN8GDH9fJ
|
||||||
|
#Re8y8yDhc6xTzS2XJF2UOkSVjhaTRH+PrpGZkRV7izIzrIaN0mULN8dVtwxbLUqa
|
||||||
|
#p0ok4K0xc5GeGjTaVMAsRoNak19wtXDriTkCAMWn28Wp0e3ipZkHqGkZhWxvlOPm
|
||||||
|
#kZbP50e//t6kGv8X0VCbvw==
|
||||||
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-228
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-152
@@ -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>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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> }
|
|
||||||
}
|
|
||||||
-123
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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> }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 } }
|
|
||||||
}
|
|
||||||
@@ -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>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
tree;
|
||||||
|
tree_prefix P;
|
||||||
|
ptype double;
|
||||||
|
|
||||||
|
<<header
|
||||||
|
/* User terminate codes. */
|
||||||
|
#define PARSER_TERMINATE_NUMBER_RANGE 1u
|
||||||
|
>>
|
||||||
|
|
||||||
|
<<
|
||||||
|
#include <charconv>
|
||||||
|
|
||||||
|
/* Store the numeric value of the matched text in *out. Returns false if the
|
||||||
|
* value cannot be represented. */
|
||||||
|
static bool parse_number(uint8_t const * match_text, size_t match_length, double * out)
|
||||||
|
{
|
||||||
|
const char * first = (const char *)match_text;
|
||||||
|
const char * last = first + match_length;
|
||||||
|
std::from_chars_result r = std::from_chars(first, last, *out);
|
||||||
|
return (r.ec == std::errc()) && (r.ptr == last);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
drop /\s+/;
|
||||||
|
|
||||||
|
token background;
|
||||||
|
token comma /,/;
|
||||||
|
token gt />/;
|
||||||
|
token height;
|
||||||
|
token lcurly /\{/;
|
||||||
|
token lt /</;
|
||||||
|
token options;
|
||||||
|
token rcurly /\}/;
|
||||||
|
token scene;
|
||||||
|
token width;
|
||||||
|
|
||||||
|
token uint /\d+/ <<
|
||||||
|
if (!parse_number(match_text, match_length, &$$))
|
||||||
|
{
|
||||||
|
$terminate(PARSER_TERMINATE_NUMBER_RANGE);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
token number /-?\d+(\.\d+)?/ <<
|
||||||
|
if (!parse_number(match_text, match_length, &$$))
|
||||||
|
{
|
||||||
|
$terminate(PARSER_TERMINATE_NUMBER_RANGE);
|
||||||
|
}
|
||||||
|
>>
|
||||||
|
|
||||||
|
Start -> RenderParams Scene;
|
||||||
|
|
||||||
|
Background -> background Vector;
|
||||||
|
|
||||||
|
Height -> height uint;
|
||||||
|
|
||||||
|
Number -> uint;
|
||||||
|
Number -> number;
|
||||||
|
|
||||||
|
RenderParams -> ;
|
||||||
|
RenderParams -> RenderParam RenderParams;
|
||||||
|
|
||||||
|
RenderParam -> Background;
|
||||||
|
RenderParam -> Height;
|
||||||
|
RenderParam -> Width;
|
||||||
|
|
||||||
|
Scene -> scene lcurly SceneItems rcurly;
|
||||||
|
|
||||||
|
SceneItems -> ;
|
||||||
|
|
||||||
|
Vector -> lt Number comma Number comma Number gt;
|
||||||
|
Vector -> lt Number comma Number comma Number comma Number gt;
|
||||||
|
|
||||||
|
Width -> width uint;
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
#include <fart/Cli.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define FLAGS \
|
||||||
|
FLAG(height, "h", true) \
|
||||||
|
FLAG(height_l, "height", true) \
|
||||||
|
FLAG(help, "help", false) \
|
||||||
|
FLAG(output, "o", true) \
|
||||||
|
FLAG(output_l, "output", true) \
|
||||||
|
FLAG(threads, "t", true) \
|
||||||
|
FLAG(threads_l, "threads", true) \
|
||||||
|
FLAG(version, "version", false) \
|
||||||
|
FLAG(width, "w", true) \
|
||||||
|
FLAG(width_l, "width", true) \
|
||||||
|
|
||||||
|
#define FLAG(name, flag, arg) flag_##name,
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
FLAGS
|
||||||
|
flag__count
|
||||||
|
} flag_id_t;
|
||||||
|
#undef FLAG
|
||||||
|
|
||||||
|
#define FLAG(name, flag, arg) static const char flag_##name##_str[] = flag;
|
||||||
|
FLAGS
|
||||||
|
#undef FLAG
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char * flag;
|
||||||
|
size_t flag_length;
|
||||||
|
bool arg;
|
||||||
|
} flag_def_t;
|
||||||
|
|
||||||
|
#define FLAG(name, flag, arg) { \
|
||||||
|
flag_##name##_str, \
|
||||||
|
sizeof(flag_##name##_str) - 1u, \
|
||||||
|
arg},
|
||||||
|
static const flag_def_t flag_defs[] = {
|
||||||
|
FLAGS
|
||||||
|
};
|
||||||
|
#undef FLAG
|
||||||
|
|
||||||
|
int Cli::run(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
for (size_t i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
size_t dashes = 0u;
|
||||||
|
if (strncmp(argv[i], "--", 2) == 0)
|
||||||
|
{
|
||||||
|
dashes = 2u;
|
||||||
|
}
|
||||||
|
else if (strncmp(argv[i], "-", 1) == 0)
|
||||||
|
{
|
||||||
|
dashes = 1u;
|
||||||
|
}
|
||||||
|
if (dashes > 0u)
|
||||||
|
{
|
||||||
|
const char * flag = &argv[i][dashes];
|
||||||
|
size_t flag_idx;
|
||||||
|
for (flag_idx = 0u; flag_idx < flag__count; flag_idx++)
|
||||||
|
{
|
||||||
|
size_t flag_length = flag_defs[flag_idx].flag_length;
|
||||||
|
size_t flag_dashes = flag_length == 1u ? 1u : 2u;
|
||||||
|
if (flag_dashes != dashes)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(flag, flag_defs[flag_idx].flag, flag_length) != 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dashes == 2 && flag[flag_length] != '\0' && flag[flag_length] != '=')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool arg = flag_defs[flag_idx].arg;
|
||||||
|
const char * arg_value = nullptr;
|
||||||
|
if (arg)
|
||||||
|
{
|
||||||
|
if (flag[flag_length] == '\0')
|
||||||
|
{
|
||||||
|
if (i >= (argc - 1))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: option %s requires an argument\n", flag_defs[flag_idx].flag);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
arg_value = argv[i];
|
||||||
|
}
|
||||||
|
else if (dashes == 1u)
|
||||||
|
{
|
||||||
|
arg_value = &flag[flag_length];
|
||||||
|
}
|
||||||
|
else if (flag[flag_length + 1] != '\0')
|
||||||
|
{
|
||||||
|
arg_value = &flag[flag_length + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: option %s requires an argument\n", flag_defs[flag_idx].flag);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dashes == 2u && flag[flag_length] == '=')
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: option %s does not take an argument\n", flag_defs[flag_idx].flag);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TODO: support combining short flags, e.g. -cofoo */
|
||||||
|
}
|
||||||
|
int r = handle_option(flag_idx, arg_value);
|
||||||
|
if (r != 0)
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (flag_idx == flag__count)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unknown flag: %s\n", flag);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!this->input_file.empty())
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Extraneous argument: %s\n", argv[i]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
this->input_file = argv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parse_size(const char * flag, const char * value, opt<size_t> * out)
|
||||||
|
{
|
||||||
|
bool valid = value[0] != '\0';
|
||||||
|
for (const char * c = value; *c != '\0'; c++)
|
||||||
|
{
|
||||||
|
if (*c < '0' || *c > '9')
|
||||||
|
{
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
unsigned long long v = strtoull(value, nullptr, 10);
|
||||||
|
if (errno == 0 && v <= SIZE_MAX)
|
||||||
|
{
|
||||||
|
*out = (size_t)v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Error: invalid value for option %s: '%s'\n", flag, value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Cli::handle_option(size_t flag_idx, const char * arg_value)
|
||||||
|
{
|
||||||
|
switch (flag_idx)
|
||||||
|
{
|
||||||
|
case flag_height:
|
||||||
|
case flag_height_l:
|
||||||
|
if (!parse_size(flag_defs[flag_idx].flag, arg_value, &this->params.height))
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case flag_help:
|
||||||
|
printf("Usage: fart [options] input-file\n");
|
||||||
|
printf("\n");
|
||||||
|
printf(" Options:\n");
|
||||||
|
printf("\n");
|
||||||
|
printf(" -h, --height H Set render height to H\n");
|
||||||
|
printf(" --help Show this help and exit\n");
|
||||||
|
printf(" -o, --output F Write rendered image to file F\n");
|
||||||
|
printf(" -t, --threads N Use N render threads (default: number of CPUs)\n");
|
||||||
|
printf(" -w, --width W Set render width to W\n");
|
||||||
|
printf(" --version Show fart version and exit\n");
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case flag_output:
|
||||||
|
case flag_output_l:
|
||||||
|
this->output_file = arg_value;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case flag_threads:
|
||||||
|
case flag_threads_l:
|
||||||
|
if (!parse_size(flag_defs[flag_idx].flag, arg_value, &this->params.threads))
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (*this->params.threads == 0u)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: option %s must be at least 1\n", flag_defs[flag_idx].flag);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case flag_width:
|
||||||
|
case flag_width_l:
|
||||||
|
if (!parse_size(flag_defs[flag_idx].flag, arg_value, &this->params.width))
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case flag_version:
|
||||||
|
printf("fart, version 0.0.0.0.0.1\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Internal error: unhandled flag_idx=%zu\n", flag_idx);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fart/RenderParams.h>
|
||||||
|
|
||||||
|
class Cli
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RenderParams params;
|
||||||
|
string_view input_file;
|
||||||
|
opt<string_view> output_file;
|
||||||
|
|
||||||
|
int run(int argc, char * argv[]);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int handle_option(size_t option_idx, const char * arg_value);
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct Color
|
||||||
|
{
|
||||||
|
double r;
|
||||||
|
double g;
|
||||||
|
double b;
|
||||||
|
double a;
|
||||||
|
|
||||||
|
Color(double r = 0.0, double g = 0.0, double b = 0.0, double a = 1.0)
|
||||||
|
: r(r), g(g), b(b), a(a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#include <fart/Engine.h>
|
||||||
|
#include <fart/Parser.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
Engine::Engine(const RenderParams & params)
|
||||||
|
: params(params)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine::~Engine()
|
||||||
|
{
|
||||||
|
delete scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Engine::run(string_view input_file, opt<string_view> output_file)
|
||||||
|
{
|
||||||
|
string output_path;
|
||||||
|
if (output_file)
|
||||||
|
{
|
||||||
|
output_path = *output_file;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string_view base = input_file;
|
||||||
|
if (base.ends_with(".fart"))
|
||||||
|
{
|
||||||
|
base.remove_suffix(5u);
|
||||||
|
}
|
||||||
|
output_path = string(base) + ".png";
|
||||||
|
}
|
||||||
|
|
||||||
|
image_writer.reset(ImageWriter::build(output_path));
|
||||||
|
if (!image_writer)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify the output file can be written before rendering. */
|
||||||
|
FILE * fh = fopen(output_path.c_str(), "wb");
|
||||||
|
if (fh == nullptr)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error opening output file '%s': %s\n", output_path.c_str(), strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (fclose(fh) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error closing output file '%s': %s\n", output_path.c_str(), strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (remove(output_path.c_str()) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error removing output file '%s': %s\n", output_path.c_str(), strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete scene;
|
||||||
|
scene = Parser::load_scene(input_file);
|
||||||
|
if (!scene)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLI params take precedence over scene params; defaults fill the rest. */
|
||||||
|
params.merge(scene->params);
|
||||||
|
params.apply_defaults();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fart/ImageWriter.h>
|
||||||
|
#include <fart/RenderParams.h>
|
||||||
|
#include <fart/Scene.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Engine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Engine(const RenderParams & params);
|
||||||
|
~Engine();
|
||||||
|
int run(string_view input_file, opt<string_view> output_file);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RenderParams params;
|
||||||
|
std::unique_ptr<ImageWriter> image_writer;
|
||||||
|
Scene * scene = nullptr;
|
||||||
|
};
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include <fart/Image.h>
|
||||||
|
|
||||||
|
Image::Image(size_t width, size_t height)
|
||||||
|
: width(width), height(height), pixels(width * height)
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fart/Color.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct Image
|
||||||
|
{
|
||||||
|
size_t width;
|
||||||
|
size_t height;
|
||||||
|
vector<Color> pixels;
|
||||||
|
Image(size_t width, size_t height);
|
||||||
|
|
||||||
|
Color & operator[](size_t x, size_t y)
|
||||||
|
{
|
||||||
|
return this->pixels[this->width * y + x];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#include <fart/ImageWriter.h>
|
||||||
|
#include <fart/PngImageWriter.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
ImageWriter * ImageWriter::build(const string & fname)
|
||||||
|
{
|
||||||
|
string ext = std::filesystem::path(fname).extension().string();
|
||||||
|
if (ext == ".png")
|
||||||
|
{
|
||||||
|
return new PngImageWriter(fname);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Unsupported output image format: '%s'\n", fname.c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <fart/Image.h>
|
||||||
|
|
||||||
|
class ImageWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static ImageWriter * build(const string & fname);
|
||||||
|
virtual ~ImageWriter() = default;
|
||||||
|
virtual bool write(const Image & image) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ImageWriter(const string & fname) : fname(fname) {}
|
||||||
|
string fname;
|
||||||
|
};
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
#include <fart/Parser.h>
|
||||||
|
#include <fart/propane.h>
|
||||||
|
#include <fart/read_file.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
Scene * Parser::load_scene(const string_view & input_file)
|
||||||
|
{
|
||||||
|
opt<vector<uint8_t>> input = read_file(input_file);
|
||||||
|
if (!input)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_context_t * context = p_context_new(input->data(), input->size());
|
||||||
|
size_t result = p_parse(context);
|
||||||
|
p_position_t pos = p_position(context);
|
||||||
|
int fname_len = (int)input_file.size();
|
||||||
|
const char * fname = input_file.data();
|
||||||
|
bool success = false;
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case P_SUCCESS:
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case P_DECODE_ERROR:
|
||||||
|
fprintf(stderr, "%.*s:%u:%u: error: invalid UTF-8 encoding\n",
|
||||||
|
fname_len, fname, pos.row, pos.col);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case P_UNEXPECTED_INPUT:
|
||||||
|
fprintf(stderr, "%.*s:%u:%u: error: unexpected input\n",
|
||||||
|
fname_len, fname, pos.row, pos.col);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case P_UNEXPECTED_TOKEN:
|
||||||
|
{
|
||||||
|
p_token_t token = p_token(context);
|
||||||
|
if (token == TOKEN___EOF)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%.*s:%u:%u: error: unexpected end of input\n",
|
||||||
|
fname_len, fname, pos.row, pos.col);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%.*s:%u:%u: error: unexpected token '%s'\n",
|
||||||
|
fname_len, fname, pos.row, pos.col, p_token_names[token]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case P_USER_TERMINATED:
|
||||||
|
if (p_user_terminate_code(context) == PARSER_TERMINATE_NUMBER_RANGE)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%.*s:%u:%u: error: number out of range\n",
|
||||||
|
fname_len, fname, pos.row, pos.col);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%.*s:%u:%u: internal error: unknown terminate code %zu\n",
|
||||||
|
fname_len, fname, pos.row, pos.col, p_user_terminate_code(context));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%.*s:%u:%u: internal error: unknown parser result %zu\n",
|
||||||
|
fname_len, fname, pos.row, pos.col, result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
p_context_delete(context);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene * scene = build_scene(input_file, p_result(context));
|
||||||
|
p_context_delete(context);
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert a uint token value to a size_t, reporting an error if it does not
|
||||||
|
* fit. */
|
||||||
|
static bool token_to_size(const string_view & input_file, PToken token, opt<size_t> * out)
|
||||||
|
{
|
||||||
|
/* SIZE_MAX + 1, computed so that it is exactly representable as a double. */
|
||||||
|
const double size_limit = (double)(SIZE_MAX / 2u + 1u) * 2.0;
|
||||||
|
double value = token.pvalue();
|
||||||
|
if (value >= size_limit)
|
||||||
|
{
|
||||||
|
p_position_t pos = token.position();
|
||||||
|
fprintf(stderr, "%.*s:%u:%u: error: value out of range\n",
|
||||||
|
(int)input_file.size(), input_file.data(), pos.row, pos.col);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*out = (size_t)value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Color vector_to_color(PVector vector)
|
||||||
|
{
|
||||||
|
Color color{
|
||||||
|
vector.pNumber2().pToken().pvalue(),
|
||||||
|
vector.pNumber4().pToken().pvalue(),
|
||||||
|
vector.pNumber6().pToken().pvalue(),
|
||||||
|
};
|
||||||
|
if (PNumber a = vector.pNumber8(); p_node_valid(a))
|
||||||
|
{
|
||||||
|
color.a = a.pToken().pvalue();
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene * Parser::build_scene(const string_view & input_file, PStart start)
|
||||||
|
{
|
||||||
|
Scene * scene = new Scene();
|
||||||
|
|
||||||
|
for (PRenderParams rps = start.pRenderParams(); p_node_valid(rps); rps = rps.pRenderParams())
|
||||||
|
{
|
||||||
|
PRenderParam rp = rps.pRenderParam();
|
||||||
|
bool ok = true;
|
||||||
|
if (PBackground background = rp.pBackground(); p_node_valid(background))
|
||||||
|
{
|
||||||
|
scene->params.background = vector_to_color(background.pVector());
|
||||||
|
}
|
||||||
|
else if (PHeight height = rp.pHeight(); p_node_valid(height))
|
||||||
|
{
|
||||||
|
ok = token_to_size(input_file, height.pToken2(), &scene->params.height);
|
||||||
|
}
|
||||||
|
else if (PWidth width = rp.pWidth(); p_node_valid(width))
|
||||||
|
{
|
||||||
|
ok = token_to_size(input_file, width.pToken2(), &scene->params.width);
|
||||||
|
}
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
delete scene;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fart/Scene.h>
|
||||||
|
|
||||||
|
struct PStart;
|
||||||
|
|
||||||
|
class Parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Scene * load_scene(const string_view & input_file);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Scene * build_scene(const string_view & input_file, PStart start);
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#include <fart/PngImageWriter.h>
|
||||||
|
#include <png.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
static uint8_t to_byte(double v)
|
||||||
|
{
|
||||||
|
return (uint8_t)std::lround(std::clamp(v, 0.0, 1.0) * 255.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PngImageWriter::write(const Image & image)
|
||||||
|
{
|
||||||
|
vector<uint8_t> buffer(image.width * image.height * 4u);
|
||||||
|
for (size_t i = 0u; i < image.pixels.size(); i++)
|
||||||
|
{
|
||||||
|
const Color & c = image.pixels[i];
|
||||||
|
buffer[i * 4u + 0u] = to_byte(c.r);
|
||||||
|
buffer[i * 4u + 1u] = to_byte(c.g);
|
||||||
|
buffer[i * 4u + 2u] = to_byte(c.b);
|
||||||
|
buffer[i * 4u + 3u] = to_byte(c.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_image png = {};
|
||||||
|
png.version = PNG_IMAGE_VERSION;
|
||||||
|
png.width = image.width;
|
||||||
|
png.height = image.height;
|
||||||
|
png.format = PNG_FORMAT_RGBA;
|
||||||
|
|
||||||
|
if (!png_image_write_to_file(&png, fname.c_str(), 0, buffer.data(), 0, nullptr))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error writing PNG file '%s': %s\n", fname.c_str(), png.message);
|
||||||
|
png_image_free(&png);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fart/ImageWriter.h>
|
||||||
|
|
||||||
|
class PngImageWriter : public ImageWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PngImageWriter(const string & fname) : ImageWriter(fname) {}
|
||||||
|
bool write(const Image & image) override;
|
||||||
|
};
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#include <fart/RenderParams.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
void RenderParams::merge(const RenderParams & other)
|
||||||
|
{
|
||||||
|
if (!width)
|
||||||
|
{
|
||||||
|
width = other.width;
|
||||||
|
}
|
||||||
|
if (!height)
|
||||||
|
{
|
||||||
|
height = other.height;
|
||||||
|
}
|
||||||
|
if (!threads)
|
||||||
|
{
|
||||||
|
threads = other.threads;
|
||||||
|
}
|
||||||
|
if (!background)
|
||||||
|
{
|
||||||
|
background = other.background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderParams::apply_defaults()
|
||||||
|
{
|
||||||
|
if (!width)
|
||||||
|
{
|
||||||
|
width = 800u;
|
||||||
|
}
|
||||||
|
if (!height)
|
||||||
|
{
|
||||||
|
height = 600u;
|
||||||
|
}
|
||||||
|
if (!threads)
|
||||||
|
{
|
||||||
|
/* hardware_concurrency() may return 0 if it cannot be determined. */
|
||||||
|
size_t n = std::thread::hardware_concurrency();
|
||||||
|
threads = n > 0u ? n : 1u;
|
||||||
|
}
|
||||||
|
if (!background)
|
||||||
|
{
|
||||||
|
background = Color{0.0, 0.0, 0.0, 1.0};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fart/Color.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct RenderParams
|
||||||
|
{
|
||||||
|
opt<size_t> width;
|
||||||
|
opt<size_t> height;
|
||||||
|
opt<size_t> threads;
|
||||||
|
opt<Color> background;
|
||||||
|
|
||||||
|
/* Set each field that is not already set to the value from other. */
|
||||||
|
void merge(const RenderParams & other);
|
||||||
|
|
||||||
|
/* Fill in any unset fields with default values. */
|
||||||
|
void apply_defaults();
|
||||||
|
};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fart/RenderParams.h>
|
||||||
|
|
||||||
|
class Scene
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RenderParams params;
|
||||||
|
};
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using string = std::string;
|
||||||
|
using string_view = std::string_view;
|
||||||
|
template <typename T> using opt = std::optional<T>;
|
||||||
|
template <typename T> using vector = std::vector<T>;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#include <fart/Cli.h>
|
||||||
|
#include <fart/Engine.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
Cli cli;
|
||||||
|
int rc = cli.run(argc, argv);
|
||||||
|
if (rc > 0)
|
||||||
|
{
|
||||||
|
return rc - 1;
|
||||||
|
}
|
||||||
|
if (cli.input_file.empty())
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: no input file specified\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Engine engine(cli.params);
|
||||||
|
return engine.run(cli.input_file, cli.output_file);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#include <fart/read_file.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
opt<vector<uint8_t>> read_file(string_view fname)
|
||||||
|
{
|
||||||
|
string path(fname);
|
||||||
|
FILE * fh = fopen(path.c_str(), "rb");
|
||||||
|
if (fh == nullptr)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error opening input file '%s': %s\n", path.c_str(), strerror(errno));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<uint8_t> buffer;
|
||||||
|
uint8_t chunk[4096];
|
||||||
|
size_t n;
|
||||||
|
while ((n = fread(chunk, 1u, sizeof(chunk), fh)) > 0u)
|
||||||
|
{
|
||||||
|
buffer.insert(buffer.end(), chunk, chunk + n);
|
||||||
|
}
|
||||||
|
if (ferror(fh))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error reading input file '%s': %s\n", path.c_str(), strerror(errno));
|
||||||
|
fclose(fh);
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
fclose(fh);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
opt<vector<uint8_t>> read_file(string_view fname);
|
||||||
-130
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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();
|
|
||||||
};
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
#include "PointLight.h"
|
|
||||||
|
|
||||||
PointLight::PointLight()
|
|
||||||
: Light()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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];
|
|
||||||
|
|
||||||
%%
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
#include "BoolShape.h"
|
|
||||||
|
|
||||||
void BoolShape::setMaterial(refptr<Material> material)
|
|
||||||
{
|
|
||||||
m_material = material;
|
|
||||||
m_shape1->setMaterial(material);
|
|
||||||
m_shape2->setMaterial(material);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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"
|
|
||||||
@@ -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 */
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
|
|
||||||
/* Single translation unit that compiles the stb_image implementation. */
|
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
|
||||||
#include "stb_image.h"
|
|
||||||
Loaded 100 of 101 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user